/**
 *        ParticleEngine.h
 * description : fichier contenant les descriptions des moteurs de particules, particules, generators et physique
 *
 * ajout :
 * - 08/02/05 :	Ajout de la gestion de l'offset lors de l'ajout de particule au moteur (methode setParticle()).
 *				En effet lorsqu'on ajoutait des particule ayant une taille > a celle des particules de base, lors
 *				du parcourt du tableau de particules, il y avait decalage en memoire et donc utilisation d'une zone
 *				memoire non valide.
 * - 10/02/05 : Ajout du multiplicateur de vitesse qui permet d'augmenter la vitesse des particules sans changer leur 
 *				vecteur direction (en fait on multiplie le temps ecoulé.)
 * @author Michel de VERDELHAN <michel.deverdelhan@free.fr>
 */
#ifndef PARTICLEENGINE_H
#define PARTICLEENGINE_H

#include <stdio.h>

#include "MemoryManager/DebugNew.h"


/**
 * definition representant l'infinie. C'est en fait la plus grande valeure representable pour un nombre flottant.
 */
#define INFINITY 3.402823466e+38F

namespace ParticleSystem
{

enum ParticleSortType
{
	/**
	 * on ne veut pas trier les particule, ainsi le rendu sera plus rapide à effectuer (a utiliser avec du 
	 * blending additif)
	 */
	NO_SORT = 1,

	/**
	 * on veut trier les particules de la plus eloignée a la plus proche (à utiliser avec des blending
	 * necessitant une trie dans l'affichage (GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA) par exemple)
	 * 
	 * <B>ATTENTION</B> le trie des particule peut avoir une influence sur la rapiditée de rendu
	 */
	SORTED,

	/**
	 * on veut trier les particules de la plus proche a la plus eloignée (à utiliser avec des blending
	 * necessitant une trie dans l'affichage (GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA) par exemple)
	 * 
	 * <B>ATTENTION</B> le trie des particule peut avoir une influence sur la rapiditée de rendu
	 */
	INV_SORTED,
};

/**
 * la classe de moteur de particule
 * 
 * Un moteur de particules est en fait une classe contenant un vecteur de particules, chaque particules a ses propres
 * caracteristique de vie, couleur position, direction ... Afin de permettre une plus grande flexibilitée, chaque
 * particules se met a jour, se dessine et se regenere (a traver le ParticleGenerator) elle même, ainsi, le moteur
 * de particules n'a qu'a demander a chaque particule de se mettre a jour ou de se dessiner et la particule effectue
 * l'action elle même. Ceci permet a l'utilisateur de crée des particules avec des comportement customisables.
 * 
 * Le moteur de particule peut etre utilisé seul ou a travers un ParticleManager, ce qui est preferable. En effet,
 * en utilisant le moteur a traver un ParticleManager, l'utilisateur a acces à un certain nombres de services comme
 * la gestion memoire automatique ou encore une gestion de l'ordre d'affichage des moteurs...
 * 
 * Cette classe contient 3 classes internes :
 * - Particle : une particule de base avec une position,une direction et une physique
 * une vie, une vie max et un generateur.
 * a chaque frame, la particule s'auto update et si elle est morte, elle s'auto regerere
 * grace au particle gererator... ca permet au moteur de particule de juste avoir a verifier
 * les particule sans s'occuper des mechanismes de mouvements.
 * - ParticleGenerator : classe qui initialise les particules
 * - ParticlePhysique : classe qui gere le vecteur physique des particules.
 */
class ParticleEngine  
{
public:
	/**
	 * declaration en avance de la classe de particle generator pour la classe de particule
	 */
	class ParticleGenerator;

	/**
	 * declaration en avance de la classe de particlePhysique pour la classe de particule
	 */
	class ParticlePhysique;
	
	/**
	 * la classe particule utilisée par le systeme de particule
	 *
	 * Une particule est une entitée autonome avec une position, une direction et une durée de vie limitée.
	 * les particules sont possédée par un moteur de particules qui leur demande de se mettrent a jour.
	 * chaque particule se met a jour elle même, c'est a dire qu'il n'y a pas d'intervention du moteur de
	 * particule sur les attributs de la particule. Ainsi, on peut heriter facilement de cette classe de particule
	 * pour crée des particules avec un autre type de comportement (par exemple des particules qui interagissent 
	 * avec le moteur physique.
	 * Lorsque la particule est morte, et qu'elle a un generateur qui boucle, elle s'auto envoie a son generateur
	 * qui la regenere, ainsi, il n'y a pas intervention du moteur de particules pour la regeneration de la particule
	 * mais uniquement du generateur dont c'est le but...
	 * Les methodes draw() et update() de la particule sont declarée en virtuel, on peut donc en heriter pour crée des 
	 * sous classes de particules.
	 */
	class Particle
	{
	public:
		/**
		 * methode implementant l'affichage de la particule.
		 *
		 * La particule est affichée en billboarding a l'aide d'un carré avec du blendinf.
		 * <BR/>A la sortie de la fonction, l'etat du blending est le même qu'en entrée.
		 */ 
		virtual void draw();

		/**
		 * methode mettant a jours les attributs de la particule.
		 *
		 * La position, la direction, la vie et la couleur de la particule sont mise a jours.
		 * Si la particule est morte, elle s'auto regenere aupres du generator (si celui ci est mis en
		 * mode loop ou que la particule n'avait pas encore été generée)
		 * @param elapsedTime: le temp ecoulé depuis le dernier appel à la methode (en secondes).
		 */
		virtual void update(float elapsedTime);

		/**
		 * methode permettant de savoir si la particule est encore vivante.
		 *
		 * Un particule est vivante si sa vie courante est inferieure a sa vie maximum.
		 * la vie d'une particule est toujours > 0 par contre sa vie max peut etre egale a -1.
		 * Ainsi, une particule qui a une vie max de -1 est considéré comme une particule n'ayant
		 * pas encore été initialisée. Ainsi une particule non initialisée ne peut jamais etre vivante
		 *
		 * @return bool: true si la particule est encore vivante
		 */
		virtual bool isAlive();

		/**
		 * permet de savoir si la particule a été inisialisée ou pas.
		 * 
		 * Une particule peut ne pas avoire été initialisée si le generateur de particule n'est pas utilisé
		 * a son plein regime par exemple.
		 * Une particule est considéré comme n'ayant pas été initialisé quand sa vie maximum est mise a -1.
		 *
		 * @return bool: true si la particule n'a pas encore été initialisée
		 */
		bool notInitialised();

		/**
		 * la position de la particule dans l'espace global.
		 * 
		 * La position n'utilise pas un vecteur afin de pouvoir l'utilisée avec n'importe quel type d'implementation
		 * de vecteur.
		 */
		float pos[3];		// la position de la particule

		/**
		 * la direction de deplacement de la particule.
		 *
		 * Comme pour la position, la direction n'utilise pas un vecteur pour permettre n'importe quelle implementation.
		 * La direction de la particule change en fonction du temps...
		 */
		float direction[3];	// la direction de la particule

		/**
		 * Le gestionnaire de physique de la particule. 
		 *
		 * Ce gestionnaire definit le vecteur physique qui sera appliqué a la particule en fonction du temps et
		 * de la masse de la particule.
		 * Le gestionnaire de physique de la particule n'est pas possédé par la particule mais par le moteur de 
		 * particules (il est partagé entre toute les particules du moteur...) et est mis a jour a chaque mise a
		 * jour du moteur de particules.
		 */ 
		ParticleEngine::ParticlePhysique * physique;	// la physique de la particule

		/**
		 * la couleur de la particule a un temps t donné.
		 * 
		 * cette couleur est la couleur affiché de la particule. c'est en fait le resultat de l'interpolation
		 * entre la couleur de debut de la particule et sa couleur de fin en fonction du temps de vie de la 
		 * particule.
		 * Cette couleur est codé sur 4 float afin de permettre d'utiliser l'alpha.
		 */
		float couleur[4];		// la couleur de la particule au temps t

		/**
		 * La couleur de depart de la particule.
		 *
		 * C'est la couleur de la particule au debut de sa vie.
		 * cette couleur est codé sur 4 float afin de permettre d'utiliser de l'alpha.
		 */
		float beginCouleur[4];	// la couleur de la particule au depart

		/**
		 * La couleur de fin de la particule
		 *
		 * C'est la couleur de la particule a la fin de sa vie.
		 * Cette couleur est codé sur 4 floats afin de permettre d'utiliser de l'alpha.
		 */
		float endCouleur[4];	// la couleur de la particule a la fin

		/**
		 * Le nombre de secondes ecoulé depuis la generation de la particule
		 *
		 * cette valeur est codé sur un float afin de permettre de gerer les fraction de secondes.
		 * La vie d'une particule ne doit JAMAIS etre inferieure a 0 !!!
		 */
		float life;			// la vie de la particule

		/**
		 * La durée de vie (en secondes) de la particule.
		 * 
		 * Cette durée de vie est le temps de vie de la particule. Si la particule depasse ce temps de vie,
		 * elle est considérée comme morte.
		 * Cet attribut est mis à -1 quand la particule n'a pas encore été generée.
		 */
		float maxLife;		// la vie max de la particule

		/**
		 * La masse de la particule.
		 *
		 * La masse est en fait un multiplicateur de l'influence de la physique sur la direction de la particule.
		 * ainsi si on pose
		 * <BR/>Dt = vecteur de direction de la particule a un temps t
		 * <BR/>Pt+1 = vecteur de physique de la particule au temps t+1
		 * <BR/>M = masse de la particule (constant au cours du temp)
		 * <BR/>la formule de la nouvelle direction de la particule au temps t+1 est
		 * <BR/>Dt+1 = Dt + (Pt+1*M)
		 */
		float masse;		// la masse de la particule

		/**
		 * la taille de la particule
		 *
		 * Cette taille represente le diametre de la particule (et non pas son rayon.) Ainsi une particule avec
		 * une taille de 2 depassera du centre d'une unitée dans chaque direction (haut bas gauche droite).
		 * Attention, l'affichage des particule se fait a l'aide d'un carré, pas d'un cercle, ainsi la point en haut
		 * a gauche de la particule sera distant de (size/2)*sqrt(2) du centre... 
		 */
		float size;			// la taille de la particule

		/**
		 * La distance de la particule par rapport a la camera. ne doit pas etre changé par l'utilisateur
		 * 
		 * La distance à la camera est utilisée pour trier les particules en fonction de leur distance.
		 * Cette variable est suceptible d'etre changée a chaque affichage du moteur de particule.
		 */
		float distance;		// la distance de la particule par rapport à la camera

		/**
		 * Le generateur de particule qui regenere la particule quand elle est morte.
		 *
		 * Ce generateur sert a régenerer la particule quand celle ci a depassée sa vie maximum (a condition que
		 * le generateur soit mis en mode boucle (generator->loop == true) et qu'il puisse encore generer des
		 * particule (generator->generation < generator->maxGeneration))
		 */
		ParticleEngine::ParticleGenerator * generator;	// le generateur de particule.

		/**
		 * constructeur par defaut de la classe de particules.
		 * 
		 * La particule est positionnée au centre du monde, avec une direction nulle, la vie a 0,
		 * la vie maximum a -1 (la particule n'a pas encore été générée), une masse a 1 et une couleure
		 * blanche.
		 */
		Particle()
		{
			pos[0] = 0.0f;pos[1] = 0.0f;pos[2] = 0.0f;
			direction[0] = 0.0f;direction[1] = 0.0f;direction[2] = 0.0f;
			life = 0.0f;
			maxLife = -1.0f;
			masse = 1.0f;
			size = 1.0f;
			beginCouleur[0]=1.0f;beginCouleur[1]=1.0f;beginCouleur[2]=1.0f;beginCouleur[3]=1.0f;
			couleur[0]=1.0f;couleur[1]=1.0f;couleur[2]=1.0f;couleur[3]=1.0f;
			endCouleur[0]=1.0f;endCouleur[1]=1.0f;endCouleur[2]=1.0f;endCouleur[3]=1.0f;
			generator = NULL;
			physique = NULL;
			distance = INFINITY;
		};

		/**
		 * destructeur par defaut.
		 */
		virtual ~Particle(){};
	};

	/**
	 * La classe qui gere la generation des particules
	 *
	 * Cette classe s'occupe de la generation des particules. C'est juste une classe de base qui doit
	 * servire d'interface a des classe derivée qui créeront ainsi differents comportement de generation
	 * de particules.
	 * 
	 * Un generateur de particule peut etre mis en mode loop pour boucler. Ainsi, lorsqu'une particule est morte,
	 * elle verifie si son generateur est mis en mode loop. Si il est en mode loop, elle se regenere, sinon elle ne
	 * se regenere pas et est considerée comme etant morte.
	 * 
	 * La methode importante de cette classe est la methode generate() qui permet de generer (ou régénérer) une
	 * particule qui est soit non initialisée soit morte.
	 */ 
	class ParticleGenerator
	{
	public:
		/**
		 * Le constructeur par defaut du ParticleGenerator.
		 */ 
		ParticleGenerator();

		/**
		 * Methode permettant de generer une particule.
		 *
		 * Cette methode est la methode la plus importante de cette classe, c'est elle qui doit etre redefinie
		 * lorsqu'on a besoin de crée une sous classe de ParticleGenerator.
		 *
		 * Cette methode n'effectue rien dans l'etat actuel des chose, l'utilisateur est obligé de redefinire cette
		 * methode si il veut avoir un fonctionnement personnalisé.
		 * @param particle: Pointeur sur la particule à régénérer. A la sortie de la methode, rien n'oblige le
		 * generator a avoir effectivement régénéré la particule (il peut par exemple avoir atteint son niveau max
		 * de generations...
		 */
		virtual void generate(ParticleEngine::Particle * particle){};

		/**
		 * verifie si le generator peut encore generer des particules (cad si son nombre de generations est
		 * inferieur a son nombre max de generation par delai de temps.
		 * @return bool: true si le generateur peut encore generer des particules.
		 */
		bool canGenerate(){return (generation < maxGeneration);};

		/**
		 * methode utilisée pour mettre a jour le generateur.
		 *
		 * @param elapsedTime : le temp ecoulé depuis le dernier appel a la methode
		 */
		virtual void update(float elapsedTime){};

		/**
		 * Le nombre maximum de generation que peut effectuer le generator pendant le lapse de temps definit
		 * par generationDelay.
		 */
		int maxGeneration;	// le nombre max de generation par frame

		/**
		 * le nombre de generations pendant le delais courant.
		 */
		int generation;		// le nombre de generation durant le delay courant

		/**
		 * La position du generateur.
		 */
		float pos[3];		// la position du generateur

		/**
		 * delais pendant lequel le generator peut generer un maximum de maxGeneration.
		 *
		 * quand ce delais est ecoulé, le nombre de generation effectuée est remis a 0 et le generateur peut a nouveau
		 * produire son nombre max de particules.
		 */
		float generationDelay;

		/**
		 * le temps precedent, utilisé pour la gestion du temps (notamment le generationDelay) neanmoins, cet attribut
		 * peut etre utilisé par l'utilisateur dans la methode generate.
		 */
		float previousTime;

		/**
		 * permet de savoir si le generator doit regenerer une particule qui est morte.
		 */
		bool loop;
	};

	/**
	 * Classe prenant en charge la gestion de la physique des particule.
	 * 
	 * Comme la classe de particleGenerator, cette classe sert de classe de base pour des sous classe redefinissant
	 * la methode update(). Neanmoins, contrairement a la classe de ParticleGenerator de base, la classe de
	 * ParticlePhysique de base assure la gestion de la physique terrestre.
	 */
	class ParticlePhysique
	{
	public:
		/**
		 * constructeur par defaut. met le vecteur physique a {0,0.89,0} (physique terrestre)
		 */
		ParticlePhysique();
		
		/**
		 * vecteur de physique qui sera ajouté a la direction de chaque particule a chaque frame
		 */
		float physique[3];

		/**
		 * methode mettant a jour le vecteur de physique.
		 *
		 * cette methode est la plus importante de la classe, c'est elle qui doit etre redefinit pour
		 * permetre a l'utilisateur de crée ses propres phenomenes physiques (simuler du vent, faire
		 * monter des particules de fumée...)
		 *
		 * la methode resemble le pluspart du temps a ca :
		 * <PRE>
		 * update(float elapsedTime)
		 * {
		 *		// modification du vecteur de physique en fonction du temp ecoulé
		 *		setPhysique(physique[0]+modif*elapsedTime,physique[1]+modif*elapsedTime,physique[2]+modif*elapsedTime);
		 * }
		 * </PRE>
		 * @param elapsedTime: le temps ecoulé depuis le dernier appel a la methode (en secondes)
		 */
		virtual void update(float elapsedTime){};

		/**
		 * methode qui definit le vecteur de physique.
		 * @param x: la composante x du vecteur de physique
		 * @param y: la composante y du vecteur de physique
		 * @param z: la composante z du vecteur de physique
		 */
		void setPhysique(float x,float y,float z){physique[0]=x;physique[1]=y;physique[2]=z;};
	};

	///////////////////////////////////////////////////////////////////	
	
	/**
	 * constructeur par defaut du moteur de particules.
	 */
	ParticleEngine();

	/**
	 * destructeur par defaut.
	 */
	virtual ~ParticleEngine();

	/**
	 * methode dessinant le moteur de particules.
	 *
	 * cette methode parcours toutes les particules et les dessines en billboarding.
	 * Les parametres de blending a la sortie de la fonction sont restaurées, ils sont donc
	 * identiques a ceux present a l'appel de la fonction.
	 */
	virtual void draw();

	/**
	 * methode mettant a jours les particules du moteur de particules.
	 *
	 * les particules sont mises a jours et regenerer si besoin.
	 * @param elapsedTime: le temps ecoulé depuis le dernier appel a la methode.
	 */
	virtual void update(float elapsedTime);

	/**
	 * crée number particules de base dans la moteur de particules.
	 *
	 * Les particules crée sont des particules de base, pour utiliser des particules definit par
	 * l'utilisateur, il faut appeler la methode setParticles().
	 * 
	 * Lors de l'appel a cette methode, un certain nombre de particules est crée, et chaque particule se voit
	 * assigner le generator et la physique du moteur de particules.
	 * @param number: le nombre de particule a crée. Attention a bien equilibrer ce nombre de particules. une bonne
	 * methode pour equilibrer ce nombre est de tester le moteur avec un nombre important de particules, de le tester
	 * puis de recuperer le nombre maximum de particule vivantes en même temps (getMaxParticleAlive()) puis de
	 * redefinire le nombre de particules necessaires pour le bon fonctionnement du moteur (attention a bien
	 * ajouter plus de particules que le nombre max, ceci etant basé sur un test empirique du au phenomene aleatoire du
	 * moteur de particules, il est possible qu'en conditions réelles, le nombre de particule soit superieur.
	 * Une autre methode consiste a appeler la methode computeMaxParticleNumber() qui simule un fonctionnement dans
	 * des conditions ideales du moteur de particules. cependant l'appel a cette methode est bloquant et peut prendre 
	 * beaucoup de temps.
	 */
	void createParticles(int number);

	/**
	 * demarre le moteur de particules
	 *
	 * @param loop: si loop est a true (valeur par defaut), le moteur de particule est lancé en boucle.
	 */
	void start(bool loop = true);

	/**
	 * methode dessinant la bounding box du moteur de particule.
	 *
	 * La bounding box est une AABB qui englobe la totalité du moteur de particules.
	 */
	void drawBoundingBox();

	/**
	 * Methode permettant de calculer le nombre maximum de particules vivantes en même temps dans le moteur.
	 *
	 * Cette methode n'est pas basé sur une methode de calcule mathematique qu nombre maximum de particules
	 * mais sur une methode empirique, cad que le resultat n'est pas forcement toujours bon (etant donné la nature
	 * aleatoire du moteur de particules). Neanmoins, elle permet de se faire une idée approximative sur le nombre
	 * maximum de particules que doit utiliser le moteur de particules.
	 *
	 * Attention n'utiliser cette methode que durante des phases de teste des moturs de particules. en effet
	 * cette methode est bloquante et peut prendre plusieurs secondes pour retourner, elle n'est donc absolument
	 * pas adapter pour etre utilisée dans un produit final, mais est juste fournit a des fin de reglages des moteurs
	 * de particules.
	 */
	void computeMaxParticleNumber();

	/**
	 * methode definissant le generator du moteur de particule.
	 *
	 * l'appel a cette methode detruit le generator precedent et prend comme generator courante le generator
	 * passé en parametres. Ce nouveau generator sera appliqué a toutes les particules du moteur.
	 * ATTENTION : une fois passé au moteur de particule, le generator est possédé par le moteur de particules,
	 * c'est donc lui qui le detruit et non plus l'utilisateur...
	 * @param gen: pointeur sur le generateur a assigner au moteur de particule. Ce generateur est possédé par le moteur
	 * de particules, c'est donc lui qui le detruit, et il faut IMPERATIVEMENT que ce generateur soit alloué sur le TAS
	 * et non en pile ou comme variable globale...
	 */
	void setGenerator(ParticleEngine::ParticleGenerator * gen);

	/**
	 * methode permettant d'acceder au generator du moteur de particules.
	 * 
	 * Le generator retourner peut etre modifié par l'utilisateur mais en aucun cas il ne doit le detruire
	 * ou l'alloué a un autre moteur de particule. En effet, le moteur possedant le generator, si il est alloué a 2
	 * moteurs de particules differents, il serait alors detruit par les 2 moteurs.
	 * @return ParticleGenerator: le generator du moteur de particules
	 */
	ParticleEngine::ParticleGenerator * getGenerator(){return generator;};

	/** 
	 * methode definissant la physique a appliquer a chaque particule du moteur de particules.
	 *
	 * Comme pour le generator, la physique est possadé par le moteur de particules et ne doit donc pas etre
	 * supprimé par l'utilisateur.
	 * 
	 * La physique precedente est detruite lors de l'appel de cette methode.
	 * Pour plus d'informations sur la gestion de la memoire, voir la methode setGenerator().
	 * @param phy: la physique à appliquer au moteur de particules.
	 */
	void setPhysique(ParticleEngine::ParticlePhysique * phy);

	/**
	 * methode retournant la physique utilisée par le moteur de particules.
	 *
	 * Comme pour le generator, la physique peut etre modifiée mais ne doit pas etre detruite ou assignée a un autre
	 * moteur de particules.
	 * @return ParticlePhysique: la physique du moteur de particules.
	 */
	ParticleEngine::ParticlePhysique * getPhysique(){return physique;};

	/**
	 * methode permettant de definire les particules qui seront utilisée par le moteur de particules.
	 *
	 * Cette methode doit etre utilisée quand on veut utiliser dans le moteur des particules definit
	 * par l'utilisateur.
	 *
	 * Apres l'appel a cette methode, les particules seront passedées par le moteur de particules, c'est donc lui
	 * qui se charge de les detruires. Ne surtout pas essayer de partager des particules entres 2 moteurs de particules
	 * differents, il y aurait conflit lors de la destruction des particules.
	 * @param part: les particules a assigner au moteur de particules.
	 * @param number: le nombre de particules.
	 * @param offset: taille memoire de la structure de particule passée en parametre. La classe passant en parametre
	 * heritant de ParticleEngine::Particle, ce parametre doit donc imperativement etre de valeure superieure ou egale
	 * a sizeof(ParticleEngine::Particle).
	 */
	void setParticles(ParticleEngine::Particle * part, int number, int offset);

	/**
	 * methode deffinissant l'identifiant de texture openGL utilisé par le moteur de particules.
	 * 
	 * @param texId :l'identifiant de texture openGL.
	 */
	void setTextureId(unsigned int texId){textureId = texId;};

	/** 
	 * methode permettant de savoir si le moteur de particules est terminé, cad si il ne va plus generer de
	 * particules.
	 * 
	 * @return bool: true si le moteur de particules ne va plus generer de particules.
	 */
	bool isFinish(){return finish&&!loop;};

	/**
	 * methode deffinissant les parametre de la fonction de blending openGL.
	 *
	 * Les 2 parametre correspondent respectivement au 2 parametre de la fonction openGL
	 * <PRE>
	 * glBlendFunc(sourceFactor,destinationFactor);
	 * </PRE>
	 *
	 * @param source: le facteur source de l'operation de blending
	 * @param dest: le facteur destination de l'operation de blending.
	 */ 
	void setBlendFunc(int source,int dest){glSourceFactor = source;glDestinationFactor = dest;};

	/**
	 * methode definissant le type de tri a utiliser pour le moteur de particules.
	 *
	 * Cette methode est a utiliser quand on veut activer le tri des particules en fonction de leur distance
	 * par rapport a la camera ou qu'au contraire on veut le desactiver.
	 *
	 * ATTENTION : activer le tri peut avoir des consequence sur les performances.
	 *
	 * @param s: le type de tri a utiliser : voir ParticleSortType
	 */
	void setSortType(ParticleSortType s){sortType = s;};

	/** 
	 * methode retournant le type de tri utilisé.
	 *
	 * @return ParticleSortType: le type de tri utilisé.
	 */
	ParticleSortType getSortType(){return sortType;};

	/**
	 * methode retournant le nombre maximum de particules utilisée simultanement depuis le dernier lancement du moteur
	 * de particules (voir start())
	 *
	 * cette methode peut etre utilisée pour avoir une approximation du nombre de particules à allouer au moteur de
	 * particule si son generator est en mode loop.
	 *
	 * @return int: le nombre maximum de particule vivante en même temps.
	 */
	int getMaxParticleAlive(){return maxParticleAlive;};

	/**
	 * methode retournant la bounding box du moteur de particules.
	 *
	 * @return float: pointeur vers un tableau de 6 float representant la bounding box. ces 6 float representent en
	 * fait 2 vecteur qui sont le point situé en (haut,gauche,arriere) et (bas,droite,avant).
	 */
	const float * getBoundingBox(){return bbox;};

	/**
	 * methode static definissant la position de la camera.
	 *
	 * Cette methode doit imperativement etre appelé avant de tenter de dessiner un moteur de particule.
	 * Elle doit etre appelé entre le positionnement de la camera et le dessin du premier moteur de particules.
	 *
	 * @param x: la position x de la camera
	 * @param y: la position y de la camera
	 * @param z: la position z de la camera
	 */
	static void setCameraPos(float x, float y, float z);

	/**
	 * methode statique permettant de recuperer la position de la camera passé par setCameraPos()
	 *
	 * Cette methode est utilisée par certaines classe comme le ParticleDrawer pour recuperer des informations
	 * utilises à l'affichage. Elle ne doit pas etre utilisée par l'utilisateur pour recuperer la position de la
	 * camera.
	 *
	 * @return pointeur constant sur les 3 float representant la position de la camera.
	 */
	static const float * getCameraPos(){return cameraPos;};

	/**
	 * methode retournant les 3 vecteurs formant l'axes de la camera.
	 *
	 * Ces 3 vecteurs servent a realiser le billboarding sans avoir a recuperer la matrice a chaque affichage de
	 * moteur de particules.
	 *
	 * @return tableau de 9 float representant les 3 vecteurs formant l'axe de la camera. les indices {0,1,2}
	 * representent l'axes X, les indices {3,4,5} representent l'axes Y et les indices {6,7,8} l'axe Z.
	 */ 
	static const float * getBillboardAxes(){return axes;};

	/**
	 * affiche dans la console les informations de chaque particule du moteur.
	 */
	void printParticleInfo();

	/**
	 * methode permettant d'afficher les particules comme des points.
	 */
	void drawPointParticle();

	/**
	 * methode permettant de definir le mode d'affichage des particules.
	 *
	 * Le mode d'affichage est le mode utilisé par la fonction openGL glBegin(mode).
	 * 
	 * Le mode par defaut des moteur de particules est GL_QUADS, mais si l'utilisateur veut utiliser des ARB_POINT_SPRITE
	 * avec l'extention ARB_POINT_PARAMETER, il lui suffit de passer en parametre GL_POINTS.
	 *
	 * Attention a ne pas utiliser de mode d'affichage dependant de l'affichage precedent, par exemple utiliser des
	 * GL_TRIANGLE_STRIP va poser probleme car chaque particule partagera une face avec la particules precedente...
	 *
	 * @param mode: le mode d'affichage du moteur (doit correspondre a un mode d'affichage openGL valide)
	 */
	void setDrawMode(int mode){drawMode = mode;};

	/**
	 * definit la valeur du facteur de vitesse.
	 *
	 * Le facteur de vitesse sert a accelerer le fonctionnement du moteur de particules. Ceci permet d'avoir
	 * des particules qui se deplacent plus vite sans changer leur comportement. C'est utile quand on utilise le moteur
	 * physique ave les particule, car cela permet de ne pas augmenter le vecteur direction qui entraine alors des 
	 * rebond sur les objets plus fort (et parfois moins realiste.)
	 *
	 * @param factor: float la valeur de facteur de vitesse. 1.0f par defaut. Une valeure > 1 augmente la vitesse
	 * du moteur alors qu'une vitesse < 1 le ralentit.
	 *
	 * Cette valeure ne doit pas etre < a 0. ceci correspondrait a un inversement du temps. De même il faut eviter des 
	 * valeurs trop importantes, car elle peuvent entrainer une non validitée des algorithmes du moteur physique et de
	 * generation des particules.
	 */
	void setSpeedFactor(float factor = 1.0f);

	/**
	 * retourne le facteur de vitesse du moteur
	 *
	 * @return float: le facteur de vitesse du moteur.
	 */
	float getSpeedFactor();

	/**
	 * methode permettant de definir le delay minimum devant s'ecouler entre 2 mise a jour du moteur de particules.
	 *
	 * Cette methode permet de ne pas mettre a jour le moteur de particules à chaque frame. Par exemple un moteur de
	 * particules avec un updateDelay de 1/60 secondes ne sera mis a jour que 60 fois par secondes maximum.
	 *
	 * @param delay : le delay minimum entre 2 mise a jour effective. avant que ce delay ne soit ecoulé, les mise
	 * a jour du moteur de particules avec la methode update() n'auront aucun effets sur le moteur. Attention a bien
	 * regler ce parametre, un delais trop court n'aura qu'un effet tres limité, alors qu'un delay trop important
	 * rendra le moteur sacadé. Il est deconseillé de mettre une valaure inferieure a 1/24 secondes.
	 */
	void setUpdateDelay(float delay){updateDelay = delay;};

	/**
	 * methode permettant de recuperer le delay minimum de mise a jour des moteurs de particules
	 *
	 * @return float : le delay minimim durant lequel le moteur n'est pas mis a jour.
	 */
	float getUpdateDelay(){return updateDelay;};

	/**
	 * methode permettant de definir le nombre de mise a jours pas secondes voulut par l'utilisateur.
	 *
	 * Si l'utilisateur definit un moteur de particules a 30 maj/secondes, le moteur ne sera mis au maximum a jour
	 * que 30 fois (neanmoins, ceci est une valeur maximum mais n'assure pas que le moteur puisse etre mis a jour moins
	 * souvent, si l'ordinateur est ralenti par exemple.)
	 *
	 * Ceci permet d'economiser du temps de calcule pour des mises a jours invisibles à l'oeil nu. Les valeurs utilisée
	 * deoivent de preference se trouver dans la plage [24:60]. Une valeure trop importante reduit l'utilitée de la
	 * methode alors qu'une valaure trop petite donnera l'impression que le moteur est saccadé.
	 *
	 * @param frame : le nombre maximum de mise a jours par secondes desiré.
	 */
	void setFramePerSecondes(int frame){updateDelay = 1.0f/frame;};

	/**
	 * methode retournant le nombre maximum d'images par secondes du moteur de particules.
	 *
	 * Attention : A cause de probleme d'arrondie des variables flottantes, il est possible que la valeure retournée
	 * differe legerement de celle passé en parametre a la methode setFramePerSecondes(). Pour une gestion plus sure du
	 * nombre maximum de mises a jours par secondes, il faut plutot utiliser les methodes setUpdateDelay() et 
	 * getUpdateDelay().
	 *
	 * @return int : le nombre maximum de mises a jours par secondes desiré.
	 */
	int getFramePerSecondes(){return (int)(1.0f/updateDelay);};
private:

	/**
	 * le delay minimum entre 2 update. permet de ne pas mettre a jour le moteur de particules a chaque frames.
	 */
	float updateDelay;

	/**
	 * le temps ecoulé depuis le dernier update
	 */
	float updateElapsedTime;
	
	/**
	 * Le nombre de particules du moteur de particules
	 */
	int particleNumber;

	/**
	 * Les particules.
	 */
	Particle * particle;

	/**
	 * le generator appliqué a toutes les particules du moteur.
	 */
	ParticleGenerator * generator;

	/**
	 * la physique appliqué a toutes les particules du moteur.
	 */
	ParticlePhysique * physique;

	/**
	 * Le type de tri utilisée par le moteur.
	 *
	 * L'utilisation d'une methode de tri peut entrainer des partes de performance.
	 */
	ParticleSortType sortType;

	/**
	 * l'identifiant openGL de la texture utilisée par les particules.
	 */
	unsigned int textureId;

	/**
	 * booleen permettant de savoir si le fonctionnement du moteur de particules est terminé.
	 */
	bool finish;

	/** 
	 * le nombre de particules vivantes
	 */
	int particleAlive;

	/** 
	 * le nombre maximal de particules vivante simultanement.
	 */
	int maxParticleAlive;

	/** 
	 * booleen permettant de saoir si le moteur est mis en mode boucle.
	 */
	bool loop;

	/** 
	 * le facteur de destination de l'operation de blending utilisée lors du rendu.
	 */
	int glDestinationFactor;

	/**
	 * le facteur de source de l'operation de blending utilisée lors du rendu.
	 */ 
	int glSourceFactor;

	/**
	 * le mode de dessin des particules.
	 *
	 * Ce mode correspond au mode de dessine openGL utilisé par glBegin()
	 */ 
	int drawMode;

	/** 
	 * la bounding box du moteur de particules.
	 *
	 * c'est une AABB representée par 2 vecteur qui sont les points {gauche,haut,arriere} et {droite,bas,avant} de la 
	 * bounding box
	 */
	float bbox[6];

	/**
	 * methode verifiant si la particule est contenue dans la bounding box ou pas.
	 *
	 * Si la particule n'est pas contenue dans la bounding box, celle ci est agrandie pour contenire
	 * la particule.
	 *
	 * @param p: la particule a tester.
	 */
	void bboxCheck(const ParticleEngine::Particle * p);

	/**
	 * decalage memoire utilisé pour parcourire le tableau de particules du moteurs.
	 * 
	 * cet offset sert a pouvoir utiliser des classes de particules de taille plus grosses que la particules
	 * de base du moteur de particules (ParticleEngine::Particle)
	 */
	int particleOffset;

	/**
	 * facteur de multiplication du temps ecoulé. ainsi on peut accelerer les particules sans changer leur comportement.
	 * ceci est particulierement utile en cas d'utilisation de particule avec le moteur physique. En effet, l'autre
	 * methode pour accelerer des particules consiste a augmenter leur vecteur direction, mais ceci pose un probleme
	 * lors des rebond...
	 */
	float speedFactor;

	/**
	 * variable booleen utilisée pour savoir si le moteur de particules a été mis a jour depuis le dernier appel à
	 * la methode draw().
	 */
	bool haveBeenUpdated;

	/**
	 * varialbe booleen utilisée pour savoir si la position de la camera a bougé depuis la dernier appel à la methode 
	 * setCameraPos().
	 */
	static bool sameCamePos;

	/**
	 * la position de la camera (variable partagée entre toute les instances de moteur de particules).
	 *
	 * cet attribut sert a connaitre la position de la camera pour les algorithme de trie en fonction de la profondeur.
	 */
	static float cameraPos[3];

	/**
	 * les 2 axes utilisée pour rendre les particules en billboarding.
	 */
	static float axes[9];
};


}// namespace ParticleSystem

#include "MemoryManager/DebugNewOff.h"



#endif
