/** 
 * \file Particles.h
 * \brief Header file for the PSystem and CGun class.  Its declaraction is found here.
 * 
 * \author Petar Bajic, MPE (C) All Rights Reserved, Homepage: www.mystic-peanut.com
 * \date January, 16 2007.
 */

#include "d3dx9.h"
#include <list> //required for using std::list

#ifndef MPE_PARTICLES
#define MPE_PARTICLES

struct Particle
{
	D3DXVECTOR3 position;
	D3DCOLOR	color;
	static const DWORD FVF;
};


struct Attribute
{
	D3DXVECTOR3 position;
	D3DXVECTOR3 velocity;
	D3DXVECTOR3 acceleration;
	D3DXVECTOR3 left;
	D3DXVECTOR3 right;
	float lifetime;
	float age;
	D3DCOLOR color;
	D3DCOLOR colorFade;
	bool isAlive;
};

/**
 * \brief PSystem class describes particle system. 
 *
 * This basic particle class provides functions for adding, updating, and rendering particles.
 * \author Petar Bajic \date January, 16 2007.
 */
class PSystem
{
public:
	PSystem();
	virtual ~PSystem();
	virtual bool init(LPDIRECT3DDEVICE9 device, const WCHAR* texFileName);
	virtual void reset();
	virtual void resetParticle(Attribute* attribute) = 0;
	virtual void addParticle();
	virtual void Update(float timeDelta, bool slow, bool follow) = 0;
	virtual void preRender();
	virtual void Render();
	virtual void postRender();
	bool isEmpty();
	bool isDead();
	//void addFloorFlake(); //for snow cover on the floor
	float _size;
	bool m_double; //for gun
protected:
	virtual void removeDeadParticles();
protected:
	LPDIRECT3DDEVICE9 _device;
	D3DXVECTOR3 _origin;
	//d3d::BoundingBox _boundingBox;
	float _emitRate;
	IDirect3DTexture9* _tex;
	IDirect3DVertexBuffer9* _vb;
	std::list<Attribute> _particles;
	int _maxParticles;
	DWORD _vbSize;
	DWORD _vbOffset;
	DWORD _vbBatchSize;
};

/**
 * \brief Class Particle Gun
 *
 * Turtle gun fire is displayed with particle system.
 * \author Petar Bajic \date January, 16 2007.
 */
class CGun : public PSystem
{
public:
	bool m_harmless;
	CGun(/*d3d::BoundingBox* boundingBox,*/ int numParticles);
	bool checkHit(D3DXVECTOR3 position, float radius);
	void shootParticle(D3DXVECTOR3 position, float facing);
	void resetParticle(Attribute* attribute);
	void Update(float timeDelta, bool slow, bool follow);
	void SetParticleColor(D3DCOLOR color);
};

/**
 * \brief Class Particle Smoke
 *
 * Smoke particles are radiated from center all around, like a slow explosion.
 * \author Petar Bajic \date January, 16 2007.
 */
class CSmoke : public PSystem
{
public:
	bool m_isAlive;
	CSmoke(int numParticles);
	void resetParticle(Attribute* attribute);
	void Update(float timeDelta, bool slow, bool follow);
	void preRender();
	void postRender();
	void puff(D3DXVECTOR3 location, D3DCOLOR color); //emit particles from center
	bool checkHit(D3DXVECTOR3 position, float radius); //check if position is within smoke radius
};

/**
 * \brief Class Particle Grass
 *
 * Grass on the field is displayed with particle system using this class.
 * \author Petar Bajic \date January, 16 2007.
 */
class CPGrass : public PSystem
{
public:
	CPGrass(int numParticles, float size, float radiusmin, float radiusmax, int ringpart);
	void resetParticle(Attribute* attribute);
	void Update(float timeDelta, bool slow, bool follow);
	void preRender();
	void postRender();

	int m_Ringpart;
	float m_MaxRadius;
	float m_MinRadius;
};

/**
 * \brief Class Particle Flame
 *
 * Flame effect emits particles above magic flowers, making them rise up and disappear.
 * \author Petar Bajic \date January, 16 2007.
 */
class CFlame : public PSystem
{
public:
	CFlame(int numParticles, float radius, D3DCOLOR color);
	void resetParticle(Attribute* attribute);
	void Update(float timeDelta, bool slow, bool follow);
	//void preRender();
	//void postRender();
	D3DCOLOR m_Color;
	float m_Radius;
};

#ifndef SAFE_DELETE
#define SAFE_DELETE(p)       { if(p) { delete (p);     (p)=NULL; } }
#endif    
#ifndef SAFE_DELETE_ARRAY
#define SAFE_DELETE_ARRAY(p) { if(p) { delete[] (p);   (p)=NULL; } }
#endif    
#ifndef SAFE_RELEASE
#define SAFE_RELEASE(p)      { if(p) { (p)->Release(); (p)=NULL; } }
#endif
#ifndef V
#define V(x)           { hr = x; }
#endif
#ifndef V_RETURN
#define V_RETURN(x)    { hr = x; if( FAILED(hr) ) { return hr; } }
#endif

#endif//MPE_PARTICLES