/*
 * ExNihilo 3D Engine
 * 
 *  This program is free software; you can redistribute it and/or modify
 *  it under the terms of the GNU General Public License as published by
 *  the Free Software Foundation; either version 2 of the License, or
 *  (at your option) any later version.
 *
 *  This program is distributed in the hope that it will be useful,
 *  but WITHOUT ANY WARRANTY; without even the implied warranty of
 *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 *  GNU Library General Public License for more details.
 *
 *  You should have received a copy of the GNU General Public License
 *  along with this program; if not, write to the Free Software
 *  Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
 *
 * Please read AUTHORS file !!!
 * 
 * $Id: ExCSystemeParticule.cpp,v 1.35 2002/12/13 11:45:03 data Exp $
 *
 */

#include "ExCSystemeParticule.h"

ExCSystemeParticule::ExCSystemeParticule(void)
{
Guard(ExCSystemeParticule::ExCSystemeParticule(void))
	m_MaxLifeSpan	= 100;
	m_MinLifeSpan	= 10;
	m_MaxSize		= 0.3f;
	m_MinSize		= 0.00f;	
	m_MaxWeight		= 10;
	m_MinWeight		= 1;
	m_MaxColorR		= 255;
	m_MinColorR		= 0;
	m_MaxColorG		= 255;
	m_MinColorG		= 0;
	m_MaxColorB		= 255;
	m_MinColorB		= 0;
	m_MaxBlending	= 255;
	m_MinBlending	= 200;	
	m_MaxVelocity.SetValue(0.0f,1.0f,0.0f);
	m_MinVelocity.SetValue(0.0f,1.0f,0.0f);	
	m_MaxAcceleration.SetValue(0.0f,0.0f,0.0f);
	m_MinAcceleration.SetValue(0.0f,0.0f,0.0f);
	m_MaxGravity.SetValue(0.0f,0.0f,0.0f);
	m_MinGravity.SetValue(0.0f,0.0f,0.0f);
    m_Type				= PARTICULE_TEXTURE;
	m_TimeLastParticule=0;

	m_MaxParticule	=100;
	m_EmissionRate	=10;//in particule by seconde
	m_Pause=false;
	m_State=true;
	m_angle=5;
	m_rayon=3.0f;
	m_vitesseangle=1.0f;
	m_ParticuleSystemeName = new char[20];
	m_TypeEmmeteur=EMMETEUR_POINT;
	m_TextureID=-1;

	m_P1.SetValue(0.0f,0.0f,0.0f);
	m_P2.SetValue(10.0f,0.0f,0.0f);

   	SetName("ExCSystemeParticule");
	SetType(typeid(this).name());

UnGuard
}

ExCSystemeParticule::~ExCSystemeParticule(void)
{
Guard(ExCSystemeParticule::~ExCSystemeParticule(void))
UnGuard
}

void ExCSystemeParticule::SetParticuleSystemeName(char * name)
{
Guard(void ExCParticule::SetParticuleSystemeName(char * name))
	m_ParticuleSystemeName=new char[strlen(name)];
	strcpy(m_ParticuleSystemeName,name);
UnGuard
}

void ExCSystemeParticule::SetParticuleType(int type)
{
Guard(void ExCParticule::SetParticuleType(int type))
	m_Type=type;
	if(m_Type>3)m_Type=1;
UnGuard
}

void ExCSystemeParticule::Start(void)
{
Guard(void ExCSystemeParticule::Start(void))
	m_State=true;
	m_Pause=false;
UnGuard
}

void ExCSystemeParticule::Pause(void)
{
Guard(void ExCSystemeParticule::Pause(void))
	m_Pause=true;
UnGuard
}

void ExCSystemeParticule::Stop(void)
{
Guard(void ExCSystemeParticule::Stop(void))
	m_Pause=true;
	m_State=false;
UnGuard
}

void ExCSystemeParticule::SetParticuleTexture(std::string Name)
{
Guard(void ExCParticule::SetParticuleTexture(std::string Name))
	ManagerTexture->Load(Name);
	m_TextureName=Name;
	m_TextureID=ManagerTexture->GetTextureId(m_TextureName);
	ManagerTexture->SetCurrentObject(Name);
	glTexParameteri(GL_TEXTURE_2D,GL_TEXTURE_MIN_FILTER, GL_LINEAR);
	glTexParameteri(GL_TEXTURE_2D,GL_TEXTURE_MAG_FILTER, GL_LINEAR);

UnGuard
}

void ExCSystemeParticule::CreateNewParticle(void)
{
Guard(void ExCParticule::CreateNewParticle(void))
	ExCParticule Particule;
	Particule.SetId(GetId());
	Particule.SetManagerCollision(ManagerCollision);
	ExCRandomNumber  Randomnum;
	ExCVec3D Velocity,Acceleration,Gravity;
	Particule.SetParticuleTexture(m_TextureID);
	Particule.SetParticuleType(m_Type);
	Particule.SetParticulePosition(m_CurrentEmitPosition);
	Particule.SetParticuleLife(Randomnum.getInt(m_MinLifeSpan,m_MaxLifeSpan));
	Particule.SetParticuleWeight(Randomnum.getInt(m_MinWeight,m_MaxWeight));
	Particule.SetParticuleColorB(Randomnum.getInt(m_MinColorB,m_MaxColorB));
	Particule.SetParticuleColorG(Randomnum.getInt(m_MinColorG,m_MaxColorG));
	Particule.SetParticuleColorR(Randomnum.getInt(m_MinColorR,m_MaxColorR));
	Particule.SetParticuleBlending(Randomnum.getInt(m_MinBlending,m_MaxBlending));
	Particule.SetParticuleMass(1.0f);
	Particule.SetParticuleSize(Randomnum.getFloat (m_MinSize,m_MaxSize));
	Particule.SetParticuleGrowth(Randomnum.getFloat (m_MinGrowth,m_MaxGrowth));
	Velocity.m_Vector[0]=Randomnum.getFloat(m_MaxVelocity.m_Vector[0],m_MinVelocity.m_Vector[0]);
	Velocity.m_Vector[1]=Randomnum.getFloat(m_MaxVelocity.m_Vector[1],m_MinVelocity.m_Vector[1]);
	Velocity.m_Vector[2]=Randomnum.getFloat(m_MaxVelocity.m_Vector[2],m_MinVelocity.m_Vector[2]);
	Particule.SetParticuleVelocity(Velocity);
	Acceleration.m_Vector[0]=Randomnum.getFloat(m_MaxAcceleration.m_Vector[0],m_MinAcceleration.m_Vector[0]);
	Acceleration.m_Vector[1]=Randomnum.getFloat(m_MaxAcceleration.m_Vector[1],m_MinAcceleration.m_Vector[1]);
	Acceleration.m_Vector[2]=Randomnum.getFloat(m_MaxAcceleration.m_Vector[2],m_MinAcceleration.m_Vector[2]);
	Particule.SetParticuleAcceleration(Acceleration);
	Gravity.m_Vector[0]=Randomnum.getFloat(m_MaxGravity.m_Vector[0],m_MinGravity.m_Vector[0]);
	Gravity.m_Vector[1]=Randomnum.getFloat(m_MaxGravity.m_Vector[1],m_MinGravity.m_Vector[1]);
	Gravity.m_Vector[2]=Randomnum.getFloat(m_MaxGravity.m_Vector[2],m_MinGravity.m_Vector[2]);
	Particule.SetParticuleGravity(Gravity);
	Particule.PrecalculeParticuleTrajectory(0,Particule.GetParticuleLife());
	m_VecParticule.push_back(Particule);	
UnGuard
}

void ExCSystemeParticule::CalculateEmitPosition(void)
{
Guard(void ExCParticule::CalculateEmitPosition(void))
	ExCRandomNumber  Randomnum;
		
	switch(m_TypeEmmeteur)
	{
	case EMMETEUR_POINT	:
		m_CurrentEmitPosition=m_Position+m_P1;
		break;

	case EMMETEUR_LIGNE :
	case EMMETEUR_RECTANGLE :
	case EMMETEUR_CUBE :
		m_CurrentEmitPosition.SetValue(Randomnum.getFloat(m_P1.m_Vector[0],m_P2.m_Vector[0]),
							Randomnum.getFloat(m_P1.m_Vector[1],m_P2.m_Vector[1]),
							Randomnum.getFloat(m_P1.m_Vector[2],m_P2.m_Vector[2]));
		m_CurrentEmitPosition=m_Position+m_CurrentEmitPosition;
		break;

	case EMMETEUR_CERCLE :
		m_angle=Randomnum.getInt(0,360);
		m_CurrentEmitPosition.SetValue(Cos[m_angle]*m_rayon,Randomnum.getFloat(m_P1.m_Vector[1],m_P2.m_Vector[1]),Sin[m_angle]*m_rayon);
		m_CurrentEmitPosition=m_Position+m_CurrentEmitPosition;
		break;

	case EMMETEUR_DISQUE :
		m_angle++;
		if(m_angle>360)m_angle=0;
		m_CurrentEmitPosition.SetValue(Sin[m_angle]*m_rayon,Randomnum.getFloat(m_P1.m_Vector[1],m_P2.m_Vector[1]),Sin[m_angle]*(Randomnum.getFloat(0.0f,m_rayon)));
		m_CurrentEmitPosition=m_Position+m_CurrentEmitPosition;
		break;

	case EMMETEUR_SPIRAL :
		m_angle+=m_vitesseangle;
		if(m_angle>360)m_angle=0;
		m_CurrentEmitPosition.SetValue(Cos[m_angle]*m_rayon,Randomnum.getFloat(m_P1.m_Vector[1],m_P2.m_Vector[1]),Sin[m_angle]*m_rayon);
		m_CurrentEmitPosition=m_Position+m_CurrentEmitPosition;
		break;
	}
UnGuard
}

void ExCSystemeParticule::Draw(void)
{
Guard(void ExCSystemeParticule::Draw(void))
	int i;
	//----------------------------------------
	//DRAW AND DESTROY PARTICULE
	//----------------------------------------
	ExCFrustum Frustrum;
	Frustrum.CalculateFrustum();
	glPushMatrix();
	glPushAttrib(GL_ALL_ATTRIB_BITS);
		glRotatef(m_Angle.GetX(),1,0,0);
		glRotatef(m_Angle.GetY(),0,1,0);
		glRotatef(m_Angle.GetZ(),0,0,1);
		if(m_VecParticule.size()>0)
		{
			for(i=0,m_ItVecParticule=m_VecParticule.begin();(unsigned)i<m_VecParticule.size();m_ItVecParticule++,i++)
			{
				
				if(Frustrum.PointInFrustum(m_ItVecParticule->GetPositionNow().GetX(),m_ItVecParticule->GetPositionNow().GetY(),m_ItVecParticule->GetPositionNow().GetZ()))
				{
					m_ItVecParticule->Draw();
					
				}				
				if(!m_Pause)m_ItVecParticule->DecreaseLifeSpan();
				if(!m_State)m_ItVecParticule->DecreaseLifeSpan();
				if(m_ItVecParticule->GetParticuleLife()<=0)m_VecParticule.erase(m_ItVecParticule);
			}
		}
	glPopAttrib();
	glPopMatrix();
	if(m_Pause)return;
	//----------------------------------------
	//CREATE NEW PARTICULE
	//----------------------------------------
	for(unsigned int j=0;j<m_EmissionRate;j++)
	{
		if(m_VecParticule.size()<m_MaxParticule)
		{
			CalculateEmitPosition();
			CreateNewParticle();
		}else return;
	}
UnGuard
}




bool ExCSystemeParticule::Load(std::string FileName)
{
Guard(bool ExCParticule::Load(std::string FileName))
	SetName(ExNihilo::ExtracValueFromSring(FileName,"/Data/ParticuleSystem/",".part"));
	m_EmissionRate	= ExNihilo::ExtractIntValueFromFile(FileName,"<EmissionRate>","<#EmissionRate>");
	m_MaxParticule	= ExNihilo::ExtractIntValueFromFile(FileName,"<MaxParticule>","<#MaxParticule>");
	m_TypeEmmeteur  = ExNihilo::ExtractIntValueFromFile(FileName,"<TypeEmmeteur>","<#TypeEmmeteur>");
	m_rayon         = ExNihilo::ExtractFloatValueFromFile(FileName,"<Rayon>","<#Rayon>");
	m_vitesseangle  = ExNihilo::ExtractFloatValueFromFile(FileName,"<VitessAngle>","<#VitessAngle>");
	m_MaxLifeSpan	= ExNihilo::ExtractIntValueFromFile(FileName,"<MaxLifeSpan>","<#MaxLifeSpan>");
	m_MinLifeSpan	= ExNihilo::ExtractIntValueFromFile(FileName,"<MinLifeSpan>","<#MinLifeSpan>");
	m_MinGrowth		= ExNihilo::ExtractFloatValueFromFile(FileName,"<MinGrowth>","<#MinGrowth>");
	m_MaxGrowth		= ExNihilo::ExtractFloatValueFromFile(FileName,"<MaxGrowth>","<#MaxGrowth>");
	m_MaxSize		= ExNihilo::ExtractFloatValueFromFile(FileName,"<MaxSize>","<#MaxSize>");
	m_MinSize		= ExNihilo::ExtractFloatValueFromFile(FileName,"<MinSize>","<#MinSize>");	
	m_MaxWeight		= ExNihilo::ExtractIntValueFromFile(FileName,"<MaxWeight>","<#MaxWeight>");
	m_MinWeight		= ExNihilo::ExtractIntValueFromFile(FileName,"<MinWeight>","<#MinWeight>");
	m_MaxColorR		= ExNihilo::ExtractIntValueFromFile(FileName,"<MaxColorR>","<#MaxColorR>");
	m_MinColorR		= ExNihilo::ExtractIntValueFromFile(FileName,"<MinColorR>","<#MinColorR>");
	m_MaxColorG		= ExNihilo::ExtractIntValueFromFile(FileName,"<MaxColorG>","<#MaxColorG>");
	m_MinColorG		= ExNihilo::ExtractIntValueFromFile(FileName,"<MinColorG>","<#MinColorG>");
	m_MaxColorB		= ExNihilo::ExtractIntValueFromFile(FileName,"<MaxColorB>","<#MaxColorB>");
	m_MinColorB		= ExNihilo::ExtractIntValueFromFile(FileName,"<MinColorB>","<#MinColorB>");
	m_MaxBlending	= ExNihilo::ExtractIntValueFromFile(FileName,"<MaxBlending>","<#MaxBlending>");
	m_MinBlending	= ExNihilo::ExtractIntValueFromFile(FileName,"<MinBlending>","<#MinBlending>");	
	m_Type			= ExNihilo::ExtractIntValueFromFile(FileName,"<Type>","<#Type>");
	m_P1.SetX(ExNihilo::ExtractFloatValueFromFile(FileName,"<Point1X>","<#Point1X>"));
	m_P1.SetY(ExNihilo::ExtractFloatValueFromFile(FileName,"<Point1y>","<#Point1y>"));
	m_P1.SetZ(ExNihilo::ExtractFloatValueFromFile(FileName,"<Point1z>","<#Point1z>"));
	m_P2.SetX(ExNihilo::ExtractFloatValueFromFile(FileName,"<Point2X>","<#Point2X>"));
	m_P2.SetY(ExNihilo::ExtractFloatValueFromFile(FileName,"<Point2y>","<#Point2y>"));
	m_P2.SetZ(ExNihilo::ExtractFloatValueFromFile(FileName,"<Point2z>","<#Point2z>"));
	m_MaxVelocity.SetX(ExNihilo::ExtractFloatValueFromFile(FileName,"<MaxVelocityX>","<#MaxVelocityX>"));
	m_MaxVelocity.SetY(ExNihilo::ExtractFloatValueFromFile(FileName,"<MaxVelocityY>","<#MaxVelocityY>"));
	m_MaxVelocity.SetZ(ExNihilo::ExtractFloatValueFromFile(FileName,"<MaxVelocityZ>","<#MaxVelocityZ>"));
	m_MinVelocity.SetX(ExNihilo::ExtractFloatValueFromFile(FileName,"<MinVelocityX>","<#MinVelocityX>"));
	m_MinVelocity.SetY(ExNihilo::ExtractFloatValueFromFile(FileName,"<MinVelocityY>","<#MinVelocityY>"));
	m_MinVelocity.SetZ(ExNihilo::ExtractFloatValueFromFile(FileName,"<MinVelocityZ>","<#MinVelocityZ>"));
	m_MaxAcceleration.SetX(ExNihilo::ExtractFloatValueFromFile(FileName,"<MaxAccelerationX>","<#MaxAccelerationX>"));
	m_MaxAcceleration.SetY(ExNihilo::ExtractFloatValueFromFile(FileName,"<MaxAccelerationY>","<#MaxAccelerationY>"));
	m_MaxAcceleration.SetZ(ExNihilo::ExtractFloatValueFromFile(FileName,"<MaxAccelerationZ>","<#MaxAccelerationZ>"));
	m_MinAcceleration.SetX(ExNihilo::ExtractFloatValueFromFile(FileName,"<MinAccelerationX>","<#MinAccelerationX>"));
	m_MinAcceleration.SetY(ExNihilo::ExtractFloatValueFromFile(FileName,"<MinAccelerationY>","<#MinAccelerationY>"));
	m_MinAcceleration.SetZ(ExNihilo::ExtractFloatValueFromFile(FileName,"<MinAccelerationZ>","<#MinAccelerationZ>"));
	m_MaxGravity.SetX(ExNihilo::ExtractFloatValueFromFile(FileName,"<MaxGravityX>","<#MaxGravityX>"));
	m_MaxGravity.SetY(ExNihilo::ExtractFloatValueFromFile(FileName,"<MaxGravityY>","<#MaxGravityY>"));
	m_MaxGravity.SetZ(ExNihilo::ExtractFloatValueFromFile(FileName,"<MaxGravityZ>","<#MaxGravityZ>"));
	m_MinGravity.SetX(ExNihilo::ExtractFloatValueFromFile(FileName,"<MinGravityX>","<#MinGravityX>"));
	m_MinGravity.SetY(ExNihilo::ExtractFloatValueFromFile(FileName,"<MinGravityY>","<#MinGravityY>"));
	m_MinGravity.SetZ(ExNihilo::ExtractFloatValueFromFile(FileName,"<MinGravityZ>","<#MinGravityZ>"));
	if(m_Type>2)
	{
		SetParticuleTexture(ExNihilo::ExtracStringValueFromFile(FileName,"<Texture>","<#Texture>"));
	}
    return true;	
UnGuard
}

