/*
 * 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: ExCParticule.cpp,v 1.25 2002/12/08 17:57:07 data Exp $
 *
 */

#include "ExCParticule.h"

ExCParticule::ExCParticule(void)
{
Guard(ExCParticule::ExCParticule(void))
	m_LifeSpan=1000;
	m_Size=0.6;
	m_Weight=1;
	m_Mass=1;
	m_Type=PARTICULE_LINE;
	m_ColorR=255;
	m_ColorG=255;
	m_ColorB=255;
	m_Velocity.SetValue(0.0f,0.1f,0.0f);
	m_Position.SetValue(0.0f,0.0f,0.0f);
	m_Acceleration.SetValue(1.0f,1.0f,1.0f);
	m_Gravity.SetValue(0.0f,0.0f,0.0f);
	SetName("ExCParticule");
	SetType(typeid(this).name());
	m_Growth=100;//in %
	m_CollisionSphere.m_Radius=m_Weight;

	m_Rotation=5;

	char *ext = (char*)glGetString( GL_EXTENSIONS );

	if( strstr( ext, "GL_EXT_point_parameters" ) == NULL )
	{
		std::cout<<"GL_EXT_point_parameters extension was not found"<<std::endl;
		return;
	}
	else
	{
        glPointParameterfEXT  = (PFNGLPOINTPARAMETERFEXTPROC)wglGetProcAddress("glPointParameterfEXT");
        glPointParameterfvEXT = (PFNGLPOINTPARAMETERFVEXTPROC)wglGetProcAddress("glPointParameterfvEXT");

		if( !glPointParameterfEXT || !glPointParameterfvEXT )
		{
			std::cout<<"One or more GL_EXT_point_parameters functions were not found"<<std::endl;
			return;
		}
	}

    if( strstr( ext, "GL_NV_point_sprite" ) == NULL )
	{
		std::cout<<"GL_NV_point_sprite extension was not found"<<std::endl;
		return;
	}
	else
	{
        glPointParameteriNV   = (PFNGLPOINTPARAMETERINVPROC)wglGetProcAddress("glPointParameteriNV");
        glPointParameterivNV  = (PFNGLPOINTPARAMETERIVNVPROC)wglGetProcAddress("glPointParameterivNV");

		if( !glPointParameteriNV  || !glPointParameterivNV )
		{
			std::cout<<"One or more GL_NV_point_sprite functions were not found"<<std::endl;
			return;
		}
	}
UnGuard
}
/*
ExCParticule::ExCParticule(const ExCParticule &Particule)
{
Guard(ExCParticule::ExCParticule(const ExCParticule &Particule))
	m_LifeSpan=Particule.m_LifeSpan;
	m_Size=Particule.m_Size;
	m_Weight=Particule.m_Weight;
	m_Mass=Particule.m_Mass;
	m_Type=Particule.m_Type;
	m_ColorR=Particule.m_ColorR;
	m_ColorG=Particule.m_ColorG;
	m_ColorB=Particule.m_ColorB;
	m_Velocity=Particule.m_Velocity;
	m_Position=Particule.m_Position;
	m_Acceleration=Particule.m_Acceleration;
	m_Gravity=Particule.m_Gravity;
	m_Growth=Particule.m_Growth;//in %
	SetName(Particule.m_ObjectName);
	SetType(Particule.m_ObjectType);
	m_VecPosition=Particule.m_VecPosition;
	m_CollisionSphere.m_Radius=Particule.m_Weight;

UnGuard
}*/

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


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


void ExCParticule::Draw(void)
{
Guard(void ExCParticule::Draw(void))

	float final,pas,current;
	
	float x,y,z,x1,y1,z1;
	float GravityX,GravityY,GravityZ;
	int TimeNow=(m_TotalLife-m_LifeSpan);
	
	final=((float)m_Size/100)*m_Growth;
	pas=(float)(final-m_Size)/m_TotalLife;
	current=m_Size+(TimeNow*pas);

	if(TimeNow>=m_TotalLife){return;}

	float quadratic[] =  { 1.0f, 1.0f, 1.0f };
	float maxSize = 0.0f;
	ExCVec3D v1,v2,v3,v4,up,right,CollisionResult;
	GLfloat viewMatrix[16];

	switch(m_Type)
	{
	case PARTICULE_POINT:
		glPushMatrix();
			glTranslatef(m_Position.m_Vector[0],m_Position.m_Vector[1],m_Position.m_Vector[2]);
			m_Position=m_Position+m_Velocity;
			glColor4ub(m_ColorR,m_ColorG,m_ColorB,m_Blending);
			glBegin(GL_POINT);
				glVertex3fv(m_Position.m_Vector);
			glEnd();
		glPopMatrix();
		break;

	case PARTICULE_LINE:
		GravityX=((TimeNow*TimeNow)*(m_Gravity.m_Vector[0])/20);
		GravityY=((TimeNow*TimeNow)*(m_Gravity.m_Vector[1])/20);
		GravityZ=((TimeNow*TimeNow)*(m_Gravity.m_Vector[2])/20);
				
		x=m_Position.m_Vector[0]+(m_Velocity.m_Vector[0]*TimeNow)-GravityX;
		y=m_Position.m_Vector[1]+(m_Velocity.m_Vector[1]*TimeNow)-GravityY;
		z=m_Position.m_Vector[2]+(m_Velocity.m_Vector[2]*TimeNow)-GravityZ;	

		x1=m_Position.m_Vector[0]+(m_Velocity.m_Vector[0]*(TimeNow+current))-GravityX;
		y1=m_Position.m_Vector[1]+(m_Velocity.m_Vector[1]*(TimeNow+current))-GravityY;
		z1=m_Position.m_Vector[2]+(m_Velocity.m_Vector[2]*(TimeNow+current))-GravityZ;
		
		glPushMatrix();
		//glPushAttrib(GL_ALL_ATTRIB_BITS);
			glTranslatef(x,y,z);
			glColor4ub(m_ColorR,m_ColorG,m_ColorB,m_Blending);
			glDisable(GL_LIGHTING);
			glEnable(GL_BLEND);
			glEnable(GL_ALPHA);
			glBlendFunc(GL_ONE,GL_ONE);
			glEnable(GL_ALPHA_TEST);
			glAlphaFunc(GL_GREATER,0);
			glLineWidth(2.0f);
			glBegin(GL_LINES);
				glVertex3f(x,y,z);	
				glVertex3f(x1,y1,z1);
			glEnd();
		//glPopAttrib();
		glPopMatrix();
		break;

	case PARTICULE_TEXTURE:
		glPushMatrix();
		//glPushAttrib(GL_ALL_ATTRIB_BITS);
			m_Position=m_VecPosition.at(TimeNow);
			//CollisionResult=ManagerCollision->OneTestCollision(this);
			//if(CollisionResult.GetX()!=0)
			//{
			//	glColor3f(1,0,0);
			//	m_Position=m_OldPosition;
			//}


			glTranslatef(m_Position.m_Vector[0],m_Position.m_Vector[1],m_Position.m_Vector[2]);
			m_CollisionSphere.m_Radius=current;
			glLineWidth(0.2);

			glMatrixMode(GL_TEXTURE);
				glRotatef(m_Rotation,0,0,1);
				m_Rotation+=m_Rotation;
			glMatrixMode(GL_MODELVIEW);	
			
			//m_CollisionSphere.Draw();
			
			// Orienation of particule
			
			glGetFloatv(GL_MODELVIEW_MATRIX, viewMatrix);
			
			right.SetValue(viewMatrix[0],viewMatrix[4],viewMatrix[8]);
			up.SetValue(viewMatrix[1],viewMatrix[5],viewMatrix[9]);

			
			v1=m_Position+(right+up)*-current;
			v2=m_Position+(right-up)*current;
			v3=m_Position+(right+up)*current;
			v4=m_Position+(up-right)*current;

			glEnable(GL_BLEND);
			glBlendFunc(GL_SRC_ALPHA,GL_ONE);
			glEnable(GL_TEXTURE_2D);
			glDisable(GL_LIGHTING);
			glTexEnvf(GL_TEXTURE_ENV,GL_TEXTURE_ENV_MODE,GL_MODULATE);
			glBindTexture(GL_TEXTURE_2D, m_Texture);
			glColor4ub(m_ColorR,m_ColorG,m_ColorB,m_Blending);


			glBegin(GL_QUADS);
				glTexCoord2f(0.0f, 0.0f); glVertex3fv(v1.m_Vector);
				glTexCoord2f(1.0f, 0.0f); glVertex3fv(v2.m_Vector);
				glTexCoord2f(1.0f, 1.0f); glVertex3fv(v3.m_Vector);
				glTexCoord2f(0.0f, 1.0f); glVertex3fv(v4.m_Vector);
			glEnd();
			
		//glPopAttrib();
		glPopMatrix();

		glMatrixMode(GL_TEXTURE);
			glLoadIdentity();
		glMatrixMode(GL_MODELVIEW);

		break;

	case PARTICULE_TEXTURE_NV:
		m_Position=m_VecPosition.at(TimeNow);
		glPushMatrix();
		glPushAttrib(GL_ALL_ATTRIB_BITS);
			glEnable( GL_BLEND );
			glBlendFunc( GL_SRC_ALPHA, GL_ONE );
			glEnable(GL_TEXTURE_2D);
			glDisable(GL_LIGHTING);
			glTexEnvf(GL_TEXTURE_ENV,GL_TEXTURE_ENV_MODE,GL_MODULATE);
			//glTexEnvf(GL_TEXTURE_ENV,GL_TEXTURE_ENV_MODE,GL_REPLACE);
			glBindTexture(GL_TEXTURE_2D, m_Texture);
			
			glPointParameterfvEXT( GL_DISTANCE_ATTENUATION_EXT, quadratic );

			// Query for the max point size supported by the hardware
			glGetFloatv( GL_POINT_SIZE_MAX_EXT, &maxSize );
			glPointSize( maxSize );

			glPointParameterfEXT( GL_POINT_FADE_THRESHOLD_SIZE_EXT, 1.0f );

			glPointParameterfEXT( GL_POINT_SIZE_MIN_EXT, 1.0f );
			glPointParameterfEXT( GL_POINT_SIZE_MAX_EXT, 2.0f );

			// Specify point sprite texture coordinate replacement mode for each texture unit
			glTexEnvf( GL_POINT_SPRITE_NV, GL_COORD_REPLACE_NV, GL_TRUE );

	/*		glPointParameteriNV( GL_POINT_SPRITE_R_MODE_NV, GL_ZERO );
			glPointParameteriNV( GL_POINT_SPRITE_R_MODE_NV, GL_S );
			glPointParameteriNV( GL_POINT_SPRITE_R_MODE_NV, GL_R );
*/
			glEnable( GL_POINT_SPRITE_NV );

			glBegin( GL_POINTS );
			{
				glColor4ub(m_ColorR,m_ColorG,m_ColorB,m_Blending);
				glVertex3fv(m_Position.m_Vector);
			}
			glEnd();
		glPopAttrib();
		glPopMatrix();
		break;
	}
	m_OldPosition=m_Position;
UnGuard
}

void ExCParticule::PrecalculeParticuleTrajectory(int start,int end)
{
Guard(void ExCParticule::PrecalculeParticuleTrajectory(int start,int end))
	float GravityX,GravityY,GravityZ;
	ExCVec3D Position;
	for(int i=start;i<end;i++)
	{
		GravityX=((i*i)*(m_Gravity.m_Vector[0])/2000);
		GravityY=((i*i)*(m_Gravity.m_Vector[1])/2000);
		GravityZ=((i*i)*(m_Gravity.m_Vector[2])/2000);
				
		Position.m_Vector[0]=m_Position.m_Vector[0]+(m_Velocity.m_Vector[0]*i)-GravityX;
		Position.m_Vector[1]=m_Position.m_Vector[1]+(m_Velocity.m_Vector[1]*i)-GravityY;
		Position.m_Vector[2]=m_Position.m_Vector[2]+(m_Velocity.m_Vector[2]*i)-GravityZ;	
		m_VecPosition.push_back(Position);
	}
UnGuard
}

void ExCParticule::ApplyForceToParitcule(ExCVec3D force)
{
Guard(void ExCParticule::ApplyForceToParitcule(ExCVec3D force))
	
UnGuard
}

ExCVec3D ExCParticule::GetPositionNow(void)
{
Guard(ExCVec3D ExCParticule::GetPositionNow(void))

return m_VecPosition.at(m_TotalLife-m_LifeSpan);

UnGuard
}