/** 
 * \file Particles.cpp
 * \brief Defines the particle class functions.
 *
 * Particle class CGun takes care of rendering and animating gun bullets that come out of turtle.
 * CGun inherits PSystem, which can easilly be used to render snow or other particle systems
 * 
 * \author Petar Bajic, MPE (C) All Rights Reserved, Homepage: www.mystic-peanut.com
 * \date January, 16 2007.
 */

#include "Particles.h"

//Some usefull functions:

DWORD FtoDw(float f)
{
	return *((DWORD*)&f);
}

/**
 * \brief Returns random float between given bounds.
 * \author Petar Bajic 
 * \date January, 16 2007.
 */
float GetRandomFloat(float lowBound, float highBound)
{
	if( lowBound >= highBound ) // bad input
		return lowBound;
	// get random float in [0, 1] interval
	float f = (rand() % 10000) * 0.0001f;
	// return float in [lowBound, highBound] interval.
	return (f * (highBound - lowBound)) + lowBound;
}

/**
 * \brief Returns random 3D vector between given vector bounds.
 * \author Petar Bajic 
 * \date January, 16 2007.
 */
void GetRandomVector( D3DXVECTOR3* out,	D3DXVECTOR3* min, D3DXVECTOR3* max)
{
		out->x = GetRandomFloat(min->x, max->x);
		out->y = GetRandomFloat(min->y, max->y);
		out->z = GetRandomFloat(min->z, max->z);
}

/**
 * \brief Returns random 3D vector in the circle on the floor with given radius.
 * \author Petar Bajic 
 * \date January, 16 2007.
 */
void GetRandomVectorCircle( D3DXVECTOR3* out, float radius)
{
		out->x = GetRandomFloat(-radius, radius);
		out->y = GetRandomFloat(0.1f, 0.3f);
		out->z = GetRandomFloat(-radius, radius);
		if((out->x*out->x)+(out->z*out->z)>(radius*radius))
			GetRandomVectorCircle(out, radius);

}

/**
 * \brief Returns random 3D vector in the ring on the floor within min and max radius.
 * \author Petar Bajic 
 * \date January, 16 2007.
 */
void GetRandomVectorRing( D3DXVECTOR3* out, float min_radius, float max_radius)
{
		out->x = GetRandomFloat(-max_radius, max_radius);
		out->y = GetRandomFloat(0.0f, 0.3f);
		out->z = GetRandomFloat(-max_radius, max_radius);
		if(((out->x*out->x)+(out->z*out->z)>(max_radius*max_radius))||((out->x*out->x)+(out->z*out->z)<(min_radius*min_radius)))
			GetRandomVectorRing(out, min_radius, max_radius);

}

/**
 * \brief Returns random 3D vector in the ring on the floor within min and max radius.
 * This baby is recursive until random value in given bounds is drawn.
 * \param ringpart 1 represent upper ring part, other valued represent lower ring part.
 * \author Petar Bajic 
 * \date January, 16 2007.
 */
void GetRandomVectorRingPart( D3DXVECTOR3* out, float min_radius, float max_radius, int ringpart)
{
	if(ringpart == 1)
	{
		out->x = GetRandomFloat(-max_radius, max_radius);
		out->y = GetRandomFloat(0.1f, 0.3f);
		out->z = GetRandomFloat(max_radius/2, max_radius);
	}
	else
	{
		out->x = GetRandomFloat(-max_radius, max_radius);
		out->y = GetRandomFloat(0.1f, 0.3f);
		out->z = GetRandomFloat(-max_radius, max_radius);
	}
	if(((out->x*out->x)+(out->z*out->z)>(max_radius*max_radius))||((out->x*out->x)+(out->z*out->z)<(min_radius*min_radius)))
		GetRandomVectorRingPart(out, min_radius, max_radius, 1);

}

/////////////////////////  PSystem  ////////////////////


const DWORD Particle::FVF = D3DFVF_XYZ | D3DFVF_DIFFUSE;

/**
 * \brief Standard constructor.
 * \author Petar Bajic 
 * \date January, 16 2007.
 */
PSystem::PSystem(void): _emitRate(10), _size(0.03f), _maxParticles(20000)
{
	_device = NULL;
	_vb = NULL;
	_tex = NULL;
}

/**
 * \brief Standard destructor.
 * \author Petar Bajic 
 * \date January, 16 2007.
 */
PSystem::~PSystem(void)
{
	SAFE_RELEASE(_tex);
	SAFE_RELEASE(_vb);
}

/**
 * \brief Resets every particle to initial values. 
 * \author Petar Bajic 
 * \date January, 16 2007.
 */
void PSystem::reset()
{
	std::list<Attribute>::iterator i;
	for(i = _particles.begin(); i != _particles.end(); i++)
	{
		resetParticle( &(*i) );
	}
}

/**
 * \brief Adds new particle.
 * \author Petar Bajic 
 * \date January, 16 2007.
 */
void PSystem::addParticle()
{
	Attribute attribute;
	resetParticle(&attribute);
	_particles.push_back(attribute);
}

/**
 * \brief preRender sets particle rendering states and postRender returns them to previous state.
 * \author Petar Bajic 
 * \date January, 16 2007.
 */
void PSystem::preRender()
{
	_device->SetRenderState(D3DRS_LIGHTING, false);
	_device->SetRenderState(D3DRS_POINTSPRITEENABLE, true);
	_device->SetRenderState(D3DRS_POINTSCALEENABLE, true);
	_device->SetRenderState(D3DRS_POINTSIZE, FtoDw(_size));
	_device->SetRenderState(D3DRS_POINTSIZE_MIN, FtoDw(0.0f));
	// control the size of the particle relative to distance
	_device->SetRenderState(D3DRS_POINTSCALE_A, FtoDw(0.0f));
	_device->SetRenderState(D3DRS_POINTSCALE_B, FtoDw(0.0f));
	_device->SetRenderState(D3DRS_POINTSCALE_C, FtoDw(1.0f));
	// use alpha from texture
	_device->SetTextureStageState(0, D3DTSS_ALPHAARG1, D3DTA_TEXTURE);
	_device->SetTextureStageState(0, D3DTSS_ALPHAOP, D3DTOP_SELECTARG1);
	_device->SetRenderState(D3DRS_ALPHABLENDENABLE, true);
	_device->SetRenderState(D3DRS_SRCBLEND, D3DBLEND_SRCALPHA);
	_device->SetRenderState(D3DRS_DESTBLEND, D3DBLEND_INVSRCALPHA);
}

/**
 * \brief preRender sets particle rendering states and postRender returns them to previous state.
 * \author Petar Bajic 
 * \date January, 16 2007.
 */
void PSystem::postRender()
{
	_device->SetRenderState(D3DRS_LIGHTING, true);
	_device->SetRenderState(D3DRS_POINTSPRITEENABLE, false);
	_device->SetRenderState(D3DRS_POINTSCALEENABLE, false);
	_device->SetRenderState(D3DRS_ALPHABLENDENABLE, false);
}

/**
 * \brief This function removes or RENEWS dead particles
 * \author Petar Bajic 
 * \date January, 16 2007.
 */
void PSystem::removeDeadParticles()
{
	std::list<Attribute>::iterator i;
	i = _particles.begin();
	while( i != _particles.end() )
	{
		if( i->isAlive == false )
		{
			// erase returns the next iterator, so no need
			// to incrememnt to the next one ourselves.
			i = _particles.erase(i);
		}
		else
		{
			i++; // next in list
		}
	}
}

/**
 * \brief Inits particle system.
 * \param texFileName texture of particles.
 * \author Petar Bajic 
 * \date January, 16 2007.
 */
bool PSystem::init(LPDIRECT3DDEVICE9 device, const WCHAR* texFileName)
{
	HRESULT hr;

	//assign device
	_device = device;

	//Create texture (_tex) from jpg file (filename)
	D3DXCreateTextureFromFile(_device, texFileName, &_tex);

	hr = device->CreateVertexBuffer( _vbSize * sizeof(Particle), D3DUSAGE_DYNAMIC | D3DUSAGE_POINTS | D3DUSAGE_WRITEONLY, 
									Particle::FVF, D3DPOOL_DEFAULT, &_vb, 0);
	//return hr;
	if (hr == S_OK)
		return true;
	
	return false;
}

/**
 * \brief Renders particles vertex buffer on 3d device.
 * \author Petar Bajic 
 * \date January, 16 2007.
 */
void PSystem::Render()
{
	if( !_particles.empty() )
	{
		// set render states
		preRender();
		_device->SetTexture(0, _tex);
		_device->SetFVF(Particle::FVF);
		_device->SetStreamSource(0, _vb, 0, sizeof(Particle));
		// start at beginning if we're at the end of the vb
		if(_vbOffset >= _vbSize)
			_vbOffset = 0;
	
		Particle* v = 0;

		_vb->Lock(_vbOffset * sizeof( Particle ),_vbBatchSize * sizeof( Particle ),
					(void**)&v,_vbOffset ? D3DLOCK_NOOVERWRITE : D3DLOCK_DISCARD);
		
		DWORD numParticlesInBatch = 0;

		//
		// Until all particles have been rendered.
		//
		std::list<Attribute>::iterator i;
		for(i = _particles.begin(); i != _particles.end(); i++)
		{
			if( i->isAlive )
			{
				//
				// Copy a batch of the living particles to the
				// next vertex buffer segment
				//
				if (!m_double)
				{
					v->position = i->position;
					v->color = (D3DCOLOR)i->color;
					v++; // next element;
					numParticlesInBatch++; //increase batch counter

					// is this batch full?
					if(numParticlesInBatch == _vbBatchSize)
					{
						//
						// Draw the last batch of particles that was
						// copied to the vertex buffer.
						//
						_vb->Unlock();
						_device->DrawPrimitive(	D3DPT_POINTLIST, _vbOffset, _vbBatchSize);		
						//
						// While that batch is drawing, start filling the
						// next batch with particles.
						//
					
						// move the offset to the start of the next batch
						_vbOffset += _vbBatchSize;
						// don't offset into memory thats outside the vb's
						// range. If we're at the end, start at the beginning.
						if(_vbOffset >= _vbSize)
						_vbOffset = 0;
						_vb->Lock(_vbOffset * sizeof( Particle ),_vbBatchSize * sizeof( Particle ),(void**)&v,_vbOffset ? D3DLOCK_NOOVERWRITE :D3DLOCK_DISCARD);
			
						numParticlesInBatch = 0; // reset for new batch
					}//end if
				}
				else //double gun render double particles
				{
					v->position = i->left;
					v->color = (D3DCOLOR)i->color;
					v++; // next element;
					numParticlesInBatch++; //increase batch counter

					// is this batch full?
					if(numParticlesInBatch == _vbBatchSize)
					{
						//
						// Draw the last batch of particles that was
						// copied to the vertex buffer.
						//
						_vb->Unlock();
						_device->DrawPrimitive(	D3DPT_POINTLIST, _vbOffset, _vbBatchSize);		
						//
						// While that batch is drawing, start filling the
						// next batch with particles.
						//
					
						// move the offset to the start of the next batch
						_vbOffset += _vbBatchSize;
						// don't offset into memory thats outside the vb's
						// range. If we're at the end, start at the beginning.
						if(_vbOffset >= _vbSize)
						_vbOffset = 0;
						_vb->Lock(_vbOffset * sizeof( Particle ),_vbBatchSize * sizeof( Particle ),(void**)&v,_vbOffset ? D3DLOCK_NOOVERWRITE :D3DLOCK_DISCARD);
			
						numParticlesInBatch = 0; // reset for new batch
					}
					else
					{
						v->position = i->right;
						v->color = (D3DCOLOR)i->color;
						v++; // next element;
						numParticlesInBatch++; //increase batch counter

						// is this batch full?
						if(numParticlesInBatch == _vbBatchSize)
						{
							//
							// Draw the last batch of particles that was
							// copied to the vertex buffer.
							//
							_vb->Unlock();
							_device->DrawPrimitive(	D3DPT_POINTLIST, _vbOffset, _vbBatchSize);		
							//
							// While that batch is drawing, start filling the
							// next batch with particles.
							//
						
							// move the offset to the start of the next batch
							_vbOffset += _vbBatchSize;
							// don't offset into memory thats outside the vb's
							// range. If we're at the end, start at the beginning.
							if(_vbOffset >= _vbSize)
							_vbOffset = 0;
							_vb->Lock(_vbOffset * sizeof( Particle ),_vbBatchSize * sizeof( Particle ),(void**)&v,_vbOffset ? D3DLOCK_NOOVERWRITE :D3DLOCK_DISCARD);
				
							numParticlesInBatch = 0; // reset for new batch
						}
					}
				}
			}//end if
		}//end for

		_vb->Unlock();

		// it’s possible that the LAST batch being filled never
		// got rendered because the condition
		// (numParticlesInBatch == _vbBatchSize) would not have
		// been satisfied. We draw the last partially filled batch now.
		if( numParticlesInBatch )
		{
			_device->DrawPrimitive(	D3DPT_POINTLIST, _vbOffset,	numParticlesInBatch);
		}

		// next block
		_vbOffset += _vbBatchSize;
		postRender();

	}//end if

}// end render()

/**
 * \brief CGun standard constructor.
 * \param numParticles total number of particles in the system.
 * \author Petar Bajic 
 * \date January, 16 2007.
 */
CGun::CGun(int numParticles)
{
	_size = 0.8f;
	_vbSize = 2048;
	_vbOffset = 0;
	_vbBatchSize = 512;
	m_double = false;
	m_harmless = false;

	for(int i = 0; i < numParticles; i++)
		addParticle();
}

/**
 * \brief Change color of particles.
 * \param color new particle color.
 * \author Petar Bajic 
 * \date January, 16 2007.
 */
void CGun::SetParticleColor(D3DCOLOR color)
{
	std::list<Attribute>::iterator i;

	for(i = _particles.begin(); i != _particles.end(); i++)
	{
		i->color = color;
	}
}

/**
 * \brief resets gun particles. 
 * \author Petar Bajic 
 * \date January, 16 2007.
 */
void CGun::resetParticle(Attribute* attribute)
{
	attribute->isAlive = false;
	// get random x, z coordinate for the position of the gunflake.
	D3DXVECTOR3 min = D3DXVECTOR3(-.1f, 2.0f, -.1f);
	D3DXVECTOR3 max = D3DXVECTOR3(.1f, 2.2f, .1f);
	GetRandomVector(&attribute->position,&min,&max);
	//zero speed
	attribute->velocity.x = 0.0f;
	attribute->velocity.y = 0.0f;
	attribute->velocity.z = 0.0f;
	// green gunflake
	attribute->color = D3DCOLOR_XRGB(55, 155, 55);
}

/**
 * \brief shoots particles from turtles mouth.
 * \param facing where turtle is pointing to.
 * \author Petar Bajic 
 * \date January, 16 2007.
 */
void CGun::shootParticle(D3DXVECTOR3 position, float facing)
{
	std::list<Attribute>::iterator i;
	D3DXVECTOR3 velocity;
	velocity.x = sin(facing);
	velocity.y = 0.0f;
	velocity.z = cos(facing);
	//Single Shooter
	if (!m_double)
	{
		for(i = _particles.begin(); i != _particles.end(); i++)
		{
			if (!(i->isAlive))
			{
				i->isAlive = true;
				i->position.x = position.x + GetRandomFloat(-.3f, .3f);
				i->position.z = position.z + GetRandomFloat(-.3f, .3f);
				i->position.y = 2; //lift up a little bit
				i->velocity = velocity * 70;
				break;
			}
		}
	}
	//Double Shooter
	else
	{
		// If turtle has double gun we want rays to come out symetricaly
		// little to the left and right of her, like airplane guns on wings
		float xLeft = position.x + cos(facing + D3DX_PI);
		float xRight = position.x - cos(facing + D3DX_PI);
		float zLeft = position.z - sin(facing + D3DX_PI);
		float zRight = position.z + sin(facing + D3DX_PI);

		D3DXVECTOR3 left = D3DXVECTOR3(xLeft, 0.5, zLeft);
		D3DXVECTOR3 right = D3DXVECTOR3(xRight, 0.5, zRight);

		for(i = _particles.begin(); i != _particles.end(); i++)
		{
			if (!(i->isAlive))
			{
				i->isAlive = true;
				i->left.x = left.x + GetRandomFloat(-.3f, .3f);
				i->left.z = left.z + GetRandomFloat(-.3f, .3f);
				i->left.y = 2; //lift up a little bit
				i->right.x = right.x + GetRandomFloat(-.3f, .3f);
				i->right.z = right.z + GetRandomFloat(-.3f, .3f);
				i->right.y = 2; //lift up a little bit
				i->position.x = position.x + GetRandomFloat(-.3f, .3f);
				i->position.z = position.z + GetRandomFloat(-.3f, .3f);
				i->position.y = 2; //lift up a little bit
				i->velocity = velocity * 70;
				break;
			}
		}
	}
}

/**
 * \brief check if particle has hit the dwarf! (Or whatever in that position)
 * \param position position of target to be hit.
 * \param radius radius from position that is considered a hit.
 * \author Petar Bajic 
 * \date January, 16 2007.
 */
bool CGun::checkHit(D3DXVECTOR3 position, float radius)
{
	std::list<Attribute>::iterator i;

	//Single Shooter
	if (!m_double)
	{
		for(i = _particles.begin(); i != _particles.end(); i++)
		{
			if (i->isAlive)
			{
				if ((i->position.x > position.x - radius)&&(i->position.x < position.x + radius)&&(i->position.z > position.z - radius)&&(i->position.z < position.z + radius))
				{
					i->isAlive = false; //bullet dissappears so it can't kill enemies behind
					return true;
				}
			}
		}
	}
	//Double Shooter
	else
	{
		for(i = _particles.begin(); i != _particles.end(); i++)
		{
			if (i->isAlive)
			{
				if ((i->left.x > position.x - radius)&&(i->left.x < position.x + radius)&&(i->left.z > position.z - radius)&&(i->left.z < position.z + radius))
				{
					i->isAlive = false; //bullet dissappears so it can't kill enemies behind
					return true;
				}
				else if ((i->right.x > position.x - radius)&&(i->right.x < position.x + radius)&&(i->right.z > position.z - radius)&&(i->right.z < position.z + radius))
				{
					i->isAlive = false; //bullet dissappears so it can't kill enemies behind
					return true;
				}
			}
		}
	}
	return false;
}

/**
 * \brief Updates position of gun particles (moves bit forward every frame)
 * \author Petar Bajic 
 * \date January, 16 2007.
 */
void CGun::Update(float timeDelta, bool slow, bool follow)
{
	std::list<Attribute>::iterator i;
	D3DXVECTOR3 velocity;

	for(i = _particles.begin(); i != _particles.end(); i++)
	{
		//Speed of falling can be slowed down with timeDelta divided by larger number
		if (slow)
		{
			i->position += i->velocity * timeDelta/3;
			i->left += i->velocity * timeDelta/3;
			i->right += i->velocity * timeDelta/3;
		}
		else
		{
			i->position += i->velocity * timeDelta;
			i->left += i->velocity * timeDelta;
			i->right += i->velocity * timeDelta;
		}

		if (follow)
		{
			float sina = i->velocity.x/70;
			float angle = asin(sina);

			if (i->velocity.z < 0)
				angle =  D3DX_PI - angle;

			angle = angle + 0.01f;

			i->velocity.x = sin(angle) * 70;
			i->velocity.z = cos(angle) * 70;
		}

		// is the point outside bounds?
		if((i->position.x < -150 )||(i->position.z < -150)||(i->position.z > 150)||(i->position.x > 150))
			i->isAlive = false;
	}
}

/**
 * \brief Standard constructor.
 * \author Petar Bajic 
 * \date January, 16 2007.
 */
CSmoke::CSmoke(int numParticles)
{
	_size = 0.1f;
	_vbSize = 2048;
	_vbOffset = 0;
	_vbBatchSize = 512;
	m_isAlive = false;

	for(int i = 0; i < numParticles; i++)
		addParticle();
}

/**
 * \brief Resets particle to initial position.
 * \author Petar Bajic 
 * \date January, 16 2007.
 */
void CSmoke::resetParticle(Attribute* attribute)
{
	attribute->isAlive = false;
	D3DXVECTOR3 min = D3DXVECTOR3(-.1f, 2.0f, -.1f);
	D3DXVECTOR3 max = D3DXVECTOR3(.1f, 2.2f, .1f);
	GetRandomVector(&attribute->position,&min,&max);
	attribute->velocity.x = 0.0f;
	attribute->velocity.y = 0.0f;
	attribute->velocity.z = 0.0f;
}

/**
 * \brief Moves particle one frame.
 * \author Petar Bajic 
 * \date January, 16 2007.
 */
void CSmoke::Update(float timeDelta, bool trt, bool trt2)
{
	std::list<Attribute>::iterator i;
	m_isAlive = false;
	for(i = _particles.begin(); i != _particles.end(); i++)
	{
		// only update living particles
		if( i->isAlive )
		{
			m_isAlive = true;
			i->position += i->velocity * timeDelta;
			i->age += timeDelta;
			i->velocity *= 0.996f;//slow down velocity
			if(i->age > i->lifetime) // kill
				i->isAlive = false;
		}
	}
}

/**
 * \brief Emit particles from the source point.
 * \author Petar Bajic 
 * \date January, 16 2007.
 */
void CSmoke::puff(D3DXVECTOR3 location, D3DCOLOR color)
{
	_origin = location;
	std::list<Attribute>::iterator attribute;
	for(attribute = _particles.begin(); attribute != _particles.end(); attribute++)
	{
		attribute->isAlive = true;
		//attribute->position = _origin;
		float random = GetRandomFloat (-.3f, .3f);
		attribute->position.x = location.x + random;
		random = GetRandomFloat (-.3f, .3f);
		attribute->position.z = location.z + random -.9f;
		random = GetRandomFloat (-.3f, .3f);
		attribute->position.y = 3.6f + random; //lift up a little bit
		D3DXVECTOR3 min = D3DXVECTOR3(-2.0f, -1.0f, -2.0f);
		D3DXVECTOR3 max = D3DXVECTOR3( 2.0f, 1.0f, 2.0f);
		GetRandomVector(&attribute->velocity, &min, &max);
		// normalize to make spherical
		D3DXVec3Normalize(&attribute->velocity,	&attribute->velocity);
		random = GetRandomFloat (1.5f, 5.0f);
		attribute->velocity *= random;//use const value, not random, for perfect sphere;
		random = GetRandomFloat (8.0f, 19.0f); //randomize age for particles, to make desapeiring not in the same time
		attribute->lifetime = random; // lives for 8 to 19 seconds
		attribute->color = color;
		attribute->age = 0.0f;
	}
}

/**
 * \brief preRender sets rendering device parameters for particles.
 * \author Petar Bajic 
 * \date January, 16 2007.
 */
void CSmoke::preRender()
{
	PSystem::preRender();
	// read, but don't write particles to z-buffer
	_device->SetRenderState(D3DRS_ZWRITEENABLE, false);
}

/**
 * \brief postRender sets original rendering device parameters.
 * \author Petar Bajic 
 * \date January, 16 2007.
 */
void CSmoke::postRender()
{
	PSystem::postRender();
	_device->SetRenderState(D3DRS_ZWRITEENABLE, true);
}

/**
 * \brief checks if object is within the smoke effect.
 * \author Petar Bajic 
 * \date January, 16 2007.
 */
bool CSmoke::checkHit(D3DXVECTOR3 position, float radius)
{
	if ((abs(_origin.x - position.x) < radius) && (abs(_origin.z - position.z) < radius))
	{
		return true;
	}
	return false;
}

/**
 * \brief Constructor initializes grass.
 * \author Petar Bajic 
 * \date January, 16 2007.
 */
CPGrass::CPGrass(int numParticles, float size, float min_radius, float max_radius, int ringpart)
{
	_size = size;
	_vbSize = 2048;
	_vbOffset = 0;
	_vbBatchSize = 512;

	m_MaxRadius = max_radius;
	m_MinRadius = min_radius;
	m_Ringpart = ringpart;

	for(int i = 0; i < numParticles; i++)
		addParticle();
}

/**
 * \brief Resets particle to initial position.
 * \author Petar Bajic 
 * \date January, 16 2007.
 */
void CPGrass::resetParticle(Attribute* attribute)
{
	attribute->isAlive = true;
	m_double = false;
	//D3DXVECTOR3 min = D3DXVECTOR3(-50.0f, 0.0f, -50.0f);
	//D3DXVECTOR3 max = D3DXVECTOR3(50.0f, 0.5f, 50.0f);
	if(m_Ringpart)
		GetRandomVectorRingPart(&attribute->position,m_MinRadius,m_MaxRadius,m_Ringpart);
	else
		GetRandomVectorRing(&attribute->position,m_MinRadius,m_MaxRadius);
	attribute->velocity.x = 0.0f;//GetRandomFloat(0.8f, 1.0f)*-20.0f;
	attribute->velocity.y = 0.0f;//GetRandomFloat(3.0f, 10.0f)*-1.0f;
	attribute->velocity.z = 0.0f;
	attribute->color = D3DCOLOR_XRGB(255, 255, 255);

}

/**
 * \brief Updates particle position. 
 * Grass is not moving so this functino is empty.
 * \author Petar Bajic 
 * \date January, 16 2007.
 */
void CPGrass::Update(float timeDelta, bool slow, bool follow)
{
}

/**
 * \brief preRender sets rendering device parameters for particles.
 * \author Petar Bajic 
 * \date January, 16 2007.
 */
void CPGrass::preRender()
{
	PSystem::preRender();
	//_device->SetRenderState(D3DRS_SRCBLEND, D3DBLEND_ONE);
	//_device->SetRenderState(D3DRS_DESTBLEND, D3DBLEND_ONE);
	// read, but don't write particles to z-buffer
	_device->SetRenderState(D3DRS_ZWRITEENABLE, false);

}

/**
 * \brief postRender sets original rendering device parameters.
 * \author Petar Bajic 
 * \date January, 16 2007.
 */
void CPGrass::postRender()
{
	PSystem::postRender();
	_device->SetRenderState(D3DRS_ZWRITEENABLE, true);
}

/**
 * \brief Standard constructor.
 * \author Petar Bajic
 * \date January, 16 2007.
 */
CFlame::CFlame(int numParticles, float radius, D3DCOLOR color)
{
	_size = 0.3f;
	_vbSize = 2048;
	_vbOffset = 0;
	_vbBatchSize = 512;

	m_Radius = radius;
	m_Color = color;
	for(int i = 0; i < numParticles; i++)
		addParticle();
}

/**
 * \brief Reset particle to initial position.
 * \author Petar Bajic 
 * \date January, 16 2007.
 */
void CFlame::resetParticle(Attribute* attribute)
{
	attribute->isAlive = true;
	m_double = false;
	D3DXVECTOR3 min = D3DXVECTOR3(-.1f, 2.0f, -.1f);
	D3DXVECTOR3 max = D3DXVECTOR3(.1f, 2.2f, .1f);
	GetRandomVector(&attribute->position,&min,&max);
	float random = GetRandomFloat (1.5f, 3.0f);
	attribute->velocity.x = 0.0f;
	attribute->velocity.y = random;
	attribute->velocity.z = 0.0f;
	attribute->color = m_Color;
}

/**
 * \brief Moves particle by one frame
 * \param timeDelta this parameter is time between frames
 * \author Petar Bajic 
 * \date January, 16 2007.
 */
void CFlame::Update(float timeDelta, bool trt, bool trt2)
{
	std::list<Attribute>::iterator i;
	for(i = _particles.begin(); i != _particles.end(); i++)
	{
		// only update living particles
		if( i->isAlive )
		{
			i->position += i->velocity * timeDelta;
			//i->age += timeDelta;
			i->velocity *= 0.996f;//slow down velocity
			if(i->position.y > 4.0f) // reset
			{
				i->position.y = 2.0;
				float random = GetRandomFloat (1.5f, 3.0f);
				i->velocity.y = random;
			}
		}
	}
}
