#define	 D3D_OVERLOADS
#include "particle.h"

#define rnd() (((FLOAT)rand()-(FLOAT)rand())/(2L*RAND_MAX))
#define RND() (((FLOAT)rand())/RAND_MAX)

ParticleSystem::ParticleSystem( DWORD _size, DWORD gNbr, LPDIRECTDRAWSURFACE7 txt ) : prtclBufferSize( _size ) 
{
	prtclBuffer = new PARTICLE[_size];

	texture		= txt;		
	gravity		= gem_Vector( 0, -9.8f, 0 );
	curNbr		= 0;
	genNbr		= gNbr;
	curParticle = 0;
}


VOID ParticleSystem::Move( FLOAT Time )
{
	gem_Vector		a0 = gravity;
    FLOAT			k  = 1.8f;
	LPPARTICLE		prtcl = prtclBuffer;

	for( DWORD i = 0; i<curNbr; i++, prtcl++ )
	{	
		if( prtcl->intensity <= 0 )
			continue;

		gem_Vector v0 = prtcl->vVelocity;
		gem_Vector r0 = prtcl->vInitialPos;

		FLOAT t = Time - prtcl->bornTime;
		FLOAT fDamping = (1.0f-(FLOAT)exp(-k*t))/(k*k);

		prtcl->vPosition = r0 + a0*t + t*(v0+t*a0)*fDamping;

		if( t>prtcl->lifeTime )
			prtcl->intensity = (prtcl->lifeTime + 1.0f - t);
	}
}

VOID ParticleSystem::Generate( FLOAT Time, gem_Vector& pos )
{	
	curNbr+=genNbr;
	if( curNbr>prtclBufferSize )
		curNbr = prtclBufferSize;

	for( DWORD i = 0 ; i<genNbr ; curParticle = (curParticle + 1) % prtclBufferSize, i++ )
	{
		prtclBuffer[curParticle].vVelocity = Normalize( gem_Vector( 2*rnd(), rnd(), rnd() ) )*RND();
		prtclBuffer[curParticle].vInitialPos = pos;
		prtclBuffer[curParticle].bornTime = Time;
		prtclBuffer[curParticle].intensity = 1.0f;
		
		FLOAT		lifeTime = 3.0f*RND()+5;
		FLOAT		coeff	 = 0.5f + 0.3f*RND();

		prtclBuffer[curParticle].lifeTime = coeff*lifeTime;
		prtclBuffer[curParticle].Falloff  = (1-coeff)*lifeTime;
		prtclBuffer[curParticle].coeff    = 1/(prtclBuffer[curParticle].Falloff);
	}
}

VOID ParticleSystem::Render( gem_Matrix& invCam, LPDIRECT3DDEVICE7 pd3dDevice )
{
	D3DMATRIX		mat;
	D3DLVERTEX		p[4];
	DWORD			alpha;
	FLOAT			size;

	p[0] = D3DLVERTEX( D3DVECTOR(-0.2f, 0.2f, 0 ), 0x00ffffff, 0, 0, 0 );
	p[1] = D3DLVERTEX( D3DVECTOR( 0.2f, 0.2f, 0 ), 0x00ffffff, 0, 1, 0 );
	p[2] = D3DLVERTEX( D3DVECTOR(-0.2f,-0.2f, 0 ), 0x00ffffff, 0, 0, 1 );
	p[3] = D3DLVERTEX( D3DVECTOR( 0.2f,-0.2f, 0 ), 0x00ffffff, 0, 1, 1 );

	pd3dDevice->SetTexture(	0, texture );			
	pd3dDevice->SetTextureStageState( 0, D3DTSS_ALPHAOP, D3DTOP_SELECTARG2 );

	for( DWORD i = 0; i<curNbr; i++ )
	{
		if( prtclBuffer[i].intensity < 0 )
			continue;

		alpha = (DWORD)(prtclBuffer[i].intensity*255.0f);
		alpha <<= 24;

		size = prtclBuffer[i].intensity*0.2;

		p[0].x = -size; p[0].y =  size;
		p[1].x =  size; p[1].y =  size;
		p[2].x = -size; p[2].y = -size;
		p[3].x =  size; p[3].y = -size;

		p[0].dcColor = (p[0].dcColor&0x00ffffff) | alpha ;
		p[1].dcColor = (p[1].dcColor&0x00ffffff) | alpha ;
		p[2].dcColor = (p[2].dcColor&0x00ffffff) | alpha ;
		p[3].dcColor = (p[3].dcColor&0x00ffffff) | alpha ;
		
		mat = (D3DMATRIX)(invCam*TranslationMtx( prtclBuffer[i].vPosition ) );
		pd3dDevice->SetTransform( D3DTRANSFORMSTATE_WORLD, &mat );
		pd3dDevice->DrawPrimitive( D3DPT_TRIANGLESTRIP, D3DFVF_LVERTEX, p, 4, NULL );
	}

	p[0] = D3DLVERTEX( D3DVECTOR(-0.4f, 0.4f, 0 ), 0xffffffff, 0, 0, 0 );
	p[1] = D3DLVERTEX( D3DVECTOR( 0.4f, 0.4f, 0 ), 0xffffffff, 0, 1, 0 );
	p[2] = D3DLVERTEX( D3DVECTOR(-0.4f,-0.4f, 0 ), 0xffffffff, 0, 0, 1 );
	p[3] = D3DLVERTEX( D3DVECTOR( 0.4f,-0.4f, 0 ), 0xffffffff, 0, 1, 1 );

	pd3dDevice->SetTextureStageState( 0, D3DTSS_ALPHAOP, D3DTOP_SELECTARG1 );
}
