/////////////////////////////////////////////////////
//	File Name:	ParticleEmitter.cpp
//	Date:		6/29/05
//	Author:		Will Dull
//	Purpose:	The base particle and emitter
//				classes implementations.
/////////////////////////////////////////////////////

#include "precompiled.h"
#include "ParticleEmitter.h"
#include "ParticleEngine.h"

CEmitter::CEmitter(const int MAX_PARTICLES, const int lifetime, int UNUSED(textureID))
{
	particleCount = 0;
	// declare the pool of nodes
	max_particles = MAX_PARTICLES;
	heap = new tParticle[max_particles];
	emitterLife = lifetime;
	decrementLife = true;
	decrementAlpha = true;
	renderParticles = true;
	isFinished = false;
	updateSpeed = 0.02f;
	blend_mode		= 1;
	size = 0.15f;
	//texture = textureID;
	texture = 0;
	
	// init the used/open list
	usedList = NULL;
	openList = NULL;

	// link all the particles in the heap
	//	into one large open list
	for(int i = 0; i < max_particles - 1; i++)
	{
		heap[i].next = &(heap[i + 1]);	 
	}
	openList = heap;
}

CEmitter::~CEmitter(void)
{
	delete [] heap;
}

bool CEmitter::addParticle()
{
	tColor start, end;
	float fYaw, fPitch, fSpeed;

	if(!openList)
		return false;

	if(particleCount < max_particles)
	{
		// get a particle from the open list
		tParticle *particle = openList;

		// set it's initial position to the emitter's position
		particle->pos.x = pos.x;
		particle->pos.y = pos.y;
		particle->pos.z = pos.z;

		// Calculate the starting direction vector
		fYaw = yaw + (yawVar * RandomNum());
		fPitch = pitch + (pitchVar * RandomNum());

		// Convert the rotations to a vector
		RotationToDirection(fPitch,fYaw,&particle->dir);

		// Multiply in the speed factor
		fSpeed = speed + (speedVar * RandomNum());
		particle->dir.x *= fSpeed;
		particle->dir.y *= fSpeed;
		particle->dir.z *= fSpeed;

		// Calculate the life span
		particle->life = life + (int)((float)lifeVar * RandomNum());

		// Calculate the colors
		start.r = startColor.r + (startColorVar.r * RandomChar());
		start.g = startColor.g + (startColorVar.g * RandomChar());
		start.b = startColor.b + (startColorVar.b * RandomChar());
		end.r = endColor.r + (endColorVar.r * RandomChar());
		end.g = endColor.g + (endColorVar.g * RandomChar());
		end.b = endColor.b + (endColorVar.b * RandomChar());

		// set the initial color of the particle
		particle->color.r = start.r;
		particle->color.g = start.g;
		particle->color.b = start.b;

		// Create the color delta
		particle->deltaColor.r = (end.r - start.r) / particle->life;
		particle->deltaColor.g = (end.g - start.g) / particle->life;
		particle->deltaColor.b = (end.b - start.b) / particle->life;

		particle->alpha = 255.0f;
		particle->alphaDelta = particle->alpha / particle->life;

		particle->inPos = false;

		// Now, we pop a node from the open list and put it into the used list
		openList = particle->next;
		particle->next = usedList;
		usedList = particle;

		// update the length of the used list (particle Count)
		particleCount++;
		return true;
	}

	return false;
}

bool CEmitter::renderEmitter()
{
	if(renderParticles)
	{
		switch(blend_mode)
		{
		case 1:
			glBlendFunc(GL_SRC_ALPHA, GL_ONE);						// Fire
			break;
		case 2:
			glBlendFunc(GL_SRC_COLOR, GL_ONE);						// Crappy Fire
			break;
		case 3:
			glBlendFunc(GL_SRC_COLOR, GL_ONE_MINUS_SRC_COLOR);		// Plain Particles
			break;
		case 4:
			glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_COLOR);		// Nice fade out effect
			break;
		}

		// Bind the texture. Use the texture assigned to this emitter.
		int unit = 0;
		g_Renderer.SetTexture(unit, texture);

		glBegin(GL_QUADS);
		{
			tParticle *tempParticle = usedList;
		
			while(tempParticle)
			{
				tColor *pColor = &(tempParticle->color);
				glColor4ub(pColor->r,pColor->g, pColor->b, (GLubyte)tempParticle->alpha);
				glTexCoord2d(0.0, 0.0);
				tVector *pPos = &(tempParticle->pos);
				glVertex3f(pPos->x - size, pPos->y + size, pPos->z);
				glTexCoord2d(0.0, 1.0);
				glVertex3f(pPos->x - size, pPos->y - size, pPos->z);
				glTexCoord2d(1.0, 1.0);
				glVertex3f(pPos->x + size, pPos->y - size, pPos->z);
				glTexCoord2d(1.0, 0.0);
				glVertex3f(pPos->x + size, pPos->y + size, pPos->z);
				tempParticle = tempParticle->next;
			}
		}
		glEnd();

		return true;
	}
	return false;
}
