168 lines
4.2 KiB
C++
168 lines
4.2 KiB
C++
/**
|
|
* =========================================================================
|
|
* File : ParticleEmitter.cpp
|
|
* Project : 0 A.D.
|
|
* Description : Particle and Emitter base classes.
|
|
* =========================================================================
|
|
*/
|
|
|
|
#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::Render()
|
|
{
|
|
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);
|
|
CVector3D *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;
|
|
}
|