This is the new particle engine. It's in and it compiles, but it's not implemented fully yet. Will get to that soon.

This was SVN commit r3369.
This commit is contained in:
livingaftermidnight 2006-01-19 11:19:55 +00:00
parent 30b83db67b
commit aef0a42780
6 changed files with 1013 additions and 365 deletions

View File

@ -0,0 +1,157 @@
/////////////////////////////////////////////////////
// File Name: DefaultEmitter.cpp
// Date: 7/20/05
// Author: Will Dull
// Purpose: Implementation of the default
// emitter class.
/////////////////////////////////////////////////////
#include "precompiled.h"
#include "DefaultEmitter.h"
CDefaultEmitter::CDefaultEmitter(const int MAX_PARTICLES, const int lifetime) : CEmitter(MAX_PARTICLES, lifetime)
{
setupEmitter();
}
CDefaultEmitter::~CDefaultEmitter(void)
{
}
bool CDefaultEmitter::setupEmitter()
{
pos.x = 0.0f; // XYZ Position
pos.y = 0.0f; // XYZ Position
pos.z = 0.0f; // XYZ Position
yaw = DEGTORAD(0.0f);
yawVar = DEGTORAD(360.0f);
pitch = DEGTORAD(90.0f);
pitchVar = DEGTORAD(45.0f);
speed = 0.05f;
speedVar = 0.001f;
blend_mode = 1;
particleCount = 0;
emitsPerFrame = 100;
emitVar = 15;
life = 90;
lifeVar = 65;
startColor.r = 240;
startColor.g = 240;
startColor.b = 15;
startColorVar.r = 15;
startColorVar.g = 15;
startColorVar.b = 15;
endColor.r = 240;
endColor.g = 15;
endColor.b = 15;
endColorVar.r = 15;
endColorVar.g = 15;
endColorVar.b = 15;
force.x = 0.000f;
force.y = -0.001f;
force.z = 0.0f;
return true;
}
bool CDefaultEmitter::updateEmitter()
{
int emits;
// walk through the used list, and update each of the particles
tParticle *tempParticle = usedList; // start at the beginning of the used list
tParticle *prev = usedList;
while(tempParticle) // loop on a valid particle
{
// don't update if the particle is supposed to be dead
if(tempParticle->life > 0)
{
// update the particle
// Calculate the new pos
tempParticle->pos.x += tempParticle->dir.x;
tempParticle->pos.y += tempParticle->dir.y;
tempParticle->pos.z += tempParticle->dir.z;
// Add global force to direction
tempParticle->dir.x += force.x;
tempParticle->dir.y += force.y;
tempParticle->dir.z += force.z;
// Get the new color
tempParticle->color.r += tempParticle->deltaColor.r;
tempParticle->color.g += tempParticle->deltaColor.g;
tempParticle->color.b += tempParticle->deltaColor.b;
// fade it out
if(decrementAlpha)
tempParticle->alpha -= tempParticle->alphaDelta;
// gets a little older
if(decrementLife)
tempParticle->life--;
// move to the next particle in the list
prev = tempParticle;
tempParticle = tempParticle->next;
}
else // this means the particle lifetime is over
{
// if this is the first particle in usedList
// then set the pointers to the next in the usedList
// and open up the tempParticle
if(tempParticle == usedList)
{
usedList = tempParticle->next;
tempParticle->next = openList;
// set the open list head to the particle
openList = tempParticle;
prev = usedList;
tempParticle = usedList;
}
else
{
//// We need to pull the particle out of the
//// used list and insert it into the open list
// fix the previous node in the list to skip over the one we are pulling out
prev->next = tempParticle->next;
// set the particle to point to the head of the open list
tempParticle->next = openList;
// set the open list head to the particle
openList = tempParticle;
// move on to the next iteration
tempParticle = prev->next;
}
// and there is one less
particleCount--;
}
} // end of while
if(emitterLife > 0 || emitterLife == -1)
{
// Emit particles for this frame
emits = emitsPerFrame + (int)((float)emitVar * RandomNum());
// if the particle life is -1 that means it's infinite
if(emitterLife != -1)
emitterLife--;
for(int i = 0; i < emits; i++)
addParticle();
return true;
}
else
{
if(particleCount > 0)
{
return true;
}
else
{
isFinished = true;
return false; // this will be checked for and then it will be deleted
}
}
return false;
}

View File

@ -0,0 +1,38 @@
/////////////////////////////////////////////////////
// File Name: DefaultEmitter.h
// Date: 7/20/05
// Author: Will Dull
// Purpose: Default emitter
/////////////////////////////////////////////////////
#ifndef _DEFAULTEMITTER_H_
#define _DEFAULTEMITTER_H_
#include "ParticleEmitter.h"
class CDefaultEmitter : public CEmitter
{
public:
CDefaultEmitter(const int MAX_PARTICLES = 4000, const int lifetime = -1);
//////////////////////////////////////////////////////////////
//Func Name: setupEmitter
//Date: 7/19/05
//Author: Will Dull
//Notes: Sets up emitter to the default particle
// effect.
//////////////////////////////////////////////////////////////
virtual bool setupEmitter();
//////////////////////////////////////////////////////////////
//Func Name: updateEmitter
//Date: 7/19/05
//Author: Will Dull
//Notes: Updates emitter.
//////////////////////////////////////////////////////////////
virtual bool updateEmitter();
virtual ~CDefaultEmitter(void);
};
#endif

View File

@ -1,280 +1,189 @@
/*==================================================================
|
| Name: ParticleEmitter.cpp
|
|===================================================================
|
| Author: Ben Vinegar
| Contact: benvinegar () hotmail ! com
|
|
| Last Modified: 03/08/04
|
| Overview: Particle emitter class that emits particles from
| an origin (or area) with a variety of set colours,
| durations, forces and a single common sprite.
|
|
| Usage: Instantiate one emitter per desired effect. Set the
| various fields (preferably all, the defaults are rather
| boring) and then call Frame() - you guessed it - every
| frame.
|
| To do: TBA
|
| More Information: TBA
|
==================================================================*/
/////////////////////////////////////////////////////
// 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 "timer.h"
#include "ogl.h"
#include <stdlib.h>
#include "ParticleEngine.h"
using namespace std;
#define PAR_LOG(a,b,c) LOG_SYS::GetInstance()->WriteC(a, LOG_SYS::OBJ, b, c)
CParticleEmitter::CParticleEmitter() :
m_origin(0.0f, 0.0f, 0.0f),
m_originSpread(0.0f, 0.0f, 0.0f),
m_velocity(0.0f, 0.0f, 0.0f),
m_velocitySpread(0.0f, 0.0f, 0.0f),
m_gravity(0.0f, 0.0f, 0.0f),
m_maxParticles(0),
m_minParticles(0),
m_numParticles(0),
m_maxLifetime(0),
m_minLifetime(0),
m_timeOfLastFrame(0.0f),
m_timeSinceLastEmit(0.0f)
{
m_particles.clear();
}
CParticleEmitter::~CParticleEmitter()
{
}
void CParticleEmitter::Frame()
{
Update();
Render();
}
void CParticleEmitter::Render()
CEmitter::CEmitter(const int MAX_PARTICLES, const int lifetime, int 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;
glEnable(GL_ALPHA_TEST);
glEnable(GL_BLEND);
glDisable(GL_DEPTH_TEST);
// init the used/open list
usedList = NULL;
openList = NULL;
glAlphaFunc(GL_GREATER, 0.0f);
glBlendFunc(GL_SRC_ALPHA,GL_ONE);
vector<CParticle *>::iterator itor = m_particles.begin();
while (itor != m_particles.end())
// link all the particles in the heap
// into one large open list
for(int i = 0; i < max_particles - 1; i++)
{
CParticle * curParticle = (*itor);
curParticle->Frame();
++itor;
heap[i].next = &(heap[i + 1]);
}
glDisable(GL_ALPHA_TEST);
glDisable(GL_BLEND);
glEnable(GL_DEPTH_TEST);
openList = heap;
}
void CParticleEmitter::Update()
CEmitter::~CEmitter(void)
{
double timeElapsed = get_time() - m_timeOfLastFrame;
// update existing particles
vector<CParticle *>::iterator itor = m_particles.begin();
while (itor != m_particles.end())
/*int open = 0;
int used = 0;
int final = 0;
tParticle *iter = openList;
while(iter)
{
CParticle * curParticle = (*itor);
open++;
iter = iter->next;
}
curParticle->Update();
iter = usedList;
while(iter)
{
used++;
iter = iter->next;
}
final = open + used;*/
// destroy particle if it has lived beyond its duration
if (curParticle->m_timeElapsedTotal >= curParticle->m_duration)
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
//tParticleNode *tempNode = openList; // get the top of the list that we have been filling in
//openList = tempNode->next;
//tempNode->next = usedList; // have it link to the top of the used list
//usedList = tempNode; // set the new linked node as the start of the 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)
{
m_particles.erase(itor);
delete curParticle;
--m_numParticles;
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;
}
++itor;
}
// Bind the texture. Use the texture assigned to this emitter.
glBindTexture(GL_TEXTURE_2D, texture);
double secondsPerEmit = 1 / (m_minParticles / m_minLifetime);
if (m_timeSinceLastEmit > secondsPerEmit)
{
glBegin(GL_QUADS);
{
tParticle *tempParticle = usedList;
float duration;
CVector3D position, velocity;
float colour[4];
bool moreParticlesToEmit = true;
while (moreParticlesToEmit) {
CParticle * newParticle = new CParticle();
// calculate particle duration
duration = (float)m_minLifetime;
duration += (rand() % (int)((m_maxLifetime - m_minLifetime) * 1000.0f + 1)) / 1000.0f;
newParticle->m_duration = duration;
// calculate particle start position from spread
position = m_origin;
position.X += (rand() % (int)(m_originSpread.X * 2000.0f + 1)) / 1000.0f - m_originSpread.X;
position.Y += (rand() % (int)(m_originSpread.Y * 2000.0f + 1)) / 1000.0f - m_originSpread.Y;
position.Z += (rand() % (int)(m_originSpread.Z * 2000.0f + 1)) / 1000.0f - m_originSpread.Z;
newParticle->m_position = position;
// calculate particle velocity from spread
velocity = m_velocity;
velocity.X += (rand() % (int)(m_velocitySpread.X * 2000.0f + 1)) / 1000.0f - m_velocitySpread.X;
velocity.Y += (rand() % (int)(m_velocitySpread.Y * 2000.0f + 1)) / 1000.0f - m_velocitySpread.Y;
velocity.Z += (rand() % (int)(m_velocitySpread.Z * 2000.0f + 1)) / 1000.0f - m_velocitySpread.Z;
newParticle->m_velocity = velocity;
newParticle->m_gravity = m_gravity;
// calculate and assign colour
memcpy2(colour, m_startColour, sizeof(float) * 4);
colour[0] += (rand() % (int)((m_endColour[0] - m_startColour[0]) * 1000.0f + 1)) / 1000.0f;
colour[1] += (rand() % (int)((m_endColour[1] - m_startColour[1]) * 1000.0f + 1)) / 1000.0f;
colour[2] += (rand() % (int)((m_endColour[2] - m_startColour[2]) * 1000.0f + 1)) / 1000.0f;
colour[3] += (rand() % (int)((m_endColour[3] - m_startColour[3]) * 1000.0f + 1)) / 1000.0f;
memcpy2(newParticle->m_colour, colour, sizeof(float) * 4);
// assign sprite
newParticle->m_sprite = m_sprite;
// final pre-processing init call
newParticle->Init();
// add to vector of particles
m_particles.push_back(newParticle);
timeElapsed -= secondsPerEmit;
if (timeElapsed < secondsPerEmit)
while(tempParticle)
{
moreParticlesToEmit = false;
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;
}
++m_numParticles;
}
m_timeSinceLastEmit = 0.0f;
glEnd();
return true;
}
else
m_timeSinceLastEmit += (float)timeElapsed;
m_timeOfLastFrame = get_time();
}
void CParticleEmitter::SetSprite(CSprite * sprite)
{
m_sprite = sprite;
}
void CParticleEmitter::SetOrigin(CVector3D origin)
{
m_origin = origin;
}
void CParticleEmitter::SetOrigin(float x, float y, float z)
{
m_origin.X = x;
m_origin.Y = y;
m_origin.Z = z;
}
void CParticleEmitter::SetOriginSpread(CVector3D spread)
{
m_originSpread = spread;
}
void CParticleEmitter::SetOriginSpread(float x, float y, float z)
{
m_originSpread.X = x;
m_originSpread.Y = y;
m_originSpread.Z = z;
}
void CParticleEmitter::SetGravity(CVector3D gravity)
{
m_gravity = gravity;
}
void CParticleEmitter::SetGravity(float x, float y, float z)
{
m_gravity.X = x;
m_gravity.Y = y;
m_gravity.Z = z;
}
void CParticleEmitter::SetVelocity(CVector3D velocity)
{
m_velocity = velocity;
}
void CParticleEmitter::SetVelocity(float x, float y, float z)
{
m_velocity.X = x;
m_velocity.Y = y;
m_velocity.Z = z;
}
void CParticleEmitter::SetVelocitySpread(CVector3D spread)
{
m_velocitySpread = spread;
}
void CParticleEmitter::SetVelocitySpread(float x, float y, float z)
{
m_velocitySpread.X = x;
m_velocitySpread.Y = y;
m_velocitySpread.Z = z;
}
void CParticleEmitter::SetStartColour(float r, float g, float b, float a)
{
m_startColour[0] = r;
m_startColour[1] = g;
m_startColour[2] = b;
m_startColour[3] = a;
}
void CParticleEmitter::SetEndColour(float r, float g, float b, float a)
{
m_endColour[0] = r;
m_endColour[1] = g;
m_endColour[2] = b;
m_endColour[3] = a;
}
void CParticleEmitter::SetMaxLifetime(double maxLife)
{
m_maxLifetime = maxLife;
}
void CParticleEmitter::SetMinLifetime(double minLife)
{
m_minLifetime = minLife;
}
void CParticleEmitter::SetMaxParticles(int maxParticles)
{
m_maxParticles = maxParticles;
}
void CParticleEmitter::SetMinParticles(int minParticles)
{
m_minParticles = minParticles;
}
return false;
}

View File

@ -1,119 +1,268 @@
/*==================================================================
|
| Name: ParticleEmitter.h
|
|===================================================================
|
| Author: Ben Vinegar
| Contact: benvinegar () hotmail ! com
|
|
| Last Modified: 03/08/04
|
| Overview: Particle emitter class that emits particles from
| an origin (or area) with a variety of set colours,
| durations, forces and a single common sprite.
|
|
| Usage: Instantiate one emitter per desired effect. Set the
| various fields (preferably all, the defaults are rather
| boring) and then call Frame() - you guessed it - every
| frame.
|
| To do: TBA
|
| More Information: TBA
|
==================================================================*/
/////////////////////////////////////////////////////
// File Name: ParticleEmitter.h
// Date: 6/29/05
// Author: Will Dull
// Purpose: The base particle and emitter
// classes.
/////////////////////////////////////////////////////
#ifndef PARTICLE_EMITTER_H
#define PARTICLE_EMITTER_H
#ifndef _PARTICLEEMITTER_H_
#define _PARTICLEEMITTER_H_
//--------------------------------------------------------
// Includes / Compiler directives
//--------------------------------------------------------
#include "precompiled.h"
#include <iostream>
#include <windows.h>
#include "ogl.h"
#include <math.h>
#include "Particle.h"
#include "Sprite.h"
#include "Vector3D.h"
#include <vector>
#define M_PI 3.14159265358979323846f
#define HALF_PI 1.57079632679489661923f
#define DEGTORAD(d) ((d * (float)M_PI) / 180.0f);
#define RADTODEG(r) ((r * 180.0f) /(float)M_PI);
//--------------------------------------------------------
// Declarations
//--------------------------------------------------------
const int HALF_RAND = (RAND_MAX / 2);
class CParticleEmitter
struct tVector
{
public:
CParticleEmitter();
~CParticleEmitter();
// must be performed before first frame/render/update call
bool Init();
// renders and updates particles
void Frame();
// renders without updating particles
void Render();
void Update();
void SetSprite(CSprite * sprite);
void SetOrigin(CVector3D origin);
void SetOrigin(float x, float y, float z);
void SetOriginSpread(CVector3D spread);
void SetOriginSpread(float x, float y, float z);
void SetGravity(CVector3D gravity);
void SetGravity(float x, float y, float z);
void SetVelocity(CVector3D direction);
void SetVelocity(float x, float y, float z);
void SetVelocitySpread(CVector3D spread);
void SetVelocitySpread(float x, float y, float z);
void SetStartColour(float r, float g, float b, float a);
void SetEndColour(float r, float g, float b, float a);
// in milliseconds
void SetMaxLifetime(double maxLife);
// in milliseconds
void SetMinLifetime(double minLife);
void SetMaxParticles(int maxParticles);
void SetMinParticles(int minParticles);
private:
CSprite * m_sprite;
std::vector<CParticle *> m_particles;
CVector3D m_origin;
CVector3D m_originSpread;
CVector3D m_velocity;
CVector3D m_velocitySpread;
CVector3D m_gravity;
float m_startColour[4];
float m_endColour[4];
int m_maxParticles;
int m_minParticles;
int m_numParticles;
double m_maxLifetime;
double m_minLifetime;
double m_timeOfLastFrame;
float m_timeSinceLastEmit;
float x,y,z;
};
#endif // PARTICLE_EMITTER_H
class CEmitter
{
public:
struct tColor
{
unsigned char r, g, b;
};
struct tParticle
{
// base stuff
tVector pos; // Current position 12
tVector dir; // Current direction with speed 12
float alpha; // Fade value 4
float alphaDelta; // Change of fade 4
tColor color; // Current color of particle 3
tColor deltaColor; // Change of color 3
short life; // How long it will last 2
// particle text stuff
tVector endPos; // For particle texture 12
bool inPos; // 1
tParticle *next; // pointer for link lists 4
tParticle()
{
next = 0;
}
};
//struct tParticleNode
//{
// tParticle *pParticle;
// tParticleNode *next;
//};
protected:
int texture; // Texture ID
bool isFinished; // tells the engine it's ready to be deleted
// Transformation Info
tVector pos; // XYZ Position
tVector finalPos; // Final position of the particles (IF IMPLOSION)
float yaw, yawVar; // Yaw and variation
float pitch, pitchVar; // Pitch and variation
float speed, speedVar; // Speed and variation
float updateSpeed; // Controls how fast emitter is updated.
float size; // size of the particles (if point sprites is not enabled)
// Particle
tParticle *heap; // Pointer to beginning of array
tParticle *openList; // linked list of unused particles
tParticle *usedList; // linked list of used particles
int blend_mode; // Method used to blend particles.
int max_particles; // Maximum particles emitter can put out
int particleCount; // Total emitted right now
int emitsPerFrame, emitVar; // Emits per frame and variation
int life, lifeVar; // Life count and variation (in Frames)
int emitterLife; // Life of the emitter
bool decrementLife; // Controls whether or not the particles life is decremented every update.
bool decrementAlpha; // Controls whether or not the particles alpha is decremented every update.
bool renderParticles; // Controls the rendering of the particles.
tColor startColor, startColorVar; // Current color of particle
tColor endColor, endColorVar; // Current color of particle
// Physics
tVector force; // Forces that affect the particles
public:
// Constructor
CEmitter(const int MAX_PARTICLES = 4000, const int lifetime = -1, int textureID = 0);
//////////////////////////////////////////////////////////////
//Func Name: setupEmitter
//Date: 9/18/05
//Author: Will Dull
//Notes: Setup emitter. Setup so that a derived class can
// overload this function to suit the specific particles
// needs.
//////////////////////////////////////////////////////////////
virtual bool setupEmitter() { return false;}
//////////////////////////////////////////////////////////////
//Func Name: addParticle
//Date: 9/18/05
//Author: Will Dull
//Notes: Sets up and adds a particle to an emitter. Setup so
// that a derived class can overload this function to
// suit the specific particles needs.
//////////////////////////////////////////////////////////////
virtual bool addParticle();
//////////////////////////////////////////////////////////////
//Func Name: updateEmitter
//Date: 9/18/05
//Author: Will Dull
//Notes: Updates emitter. Setup so that a derived class can
// overload this function to suit the specific particles
// needs.
//////////////////////////////////////////////////////////////
virtual bool updateEmitter() { return false; }
//////////////////////////////////////////////////////////////
//Func Name: renderEmitter
//Date: 9/18/05
//Author: Will Dull
//Notes: Renders emitter. Setup so that a derived class can
// overload this function to suit the specific particles
// needs.
//////////////////////////////////////////////////////////////
virtual bool renderEmitter();
inline float RandomNum()
{
int rn;
rn = rand();
return ((float)(rn - HALF_RAND) / (float)HALF_RAND);
}
inline char RandomChar()
{
return (unsigned char)(rand() >> 24);
}
inline void RotationToDirection(float pitch, float yaw, tVector *direction)
{
direction->x = (float)(-sin(yaw) * cos(pitch));
direction->y = (float)sin(pitch);
direction->z = (float)(cos(pitch) * cos(yaw));
}
///////////////////////////////////////////////////////////////////
//
// Accessors
//
///////////////////////////////////////////////////////////////////
float getPosX() { return pos.x; }
float getPosY() { return pos.y; }
float getPosZ() { return pos.z; }
tVector getPosVec() { return pos; }
float getFinalPosX() { return finalPos.x; }
float getFinalPosY() { return finalPos.y; }
float getFinalPosZ() { return finalPos.z; }
bool getIsFinished(void) { return isFinished; }
int getEmitterLife() { return emitterLife; }
int getParticleCount() { return particleCount; }
float getUpdateSpeed() { return updateSpeed; }
int getMaxParticles(void) { return max_particles; }
tColor getStartColor(void) { return startColor; }
tColor getStartColorVar(void) { return startColorVar; }
tColor getEndColor(void) { return endColor; }
tColor getEndColorVar(void) { return endColorVar; }
int getBlendMode(void) { return blend_mode; }
float getSize(void) { return size; }
float getYaw(void) { return yaw; }
float getYawVar(void) { return yawVar; }
float getPitch(void) { return pitch; }
float getPitchVar(void) { return pitchVar; }
float getSpeed(void) { return speed; }
float getSpeedVar(void) { return speedVar; }
int getEmitsPerFrame(void) { return emitsPerFrame; }
int getEmitVar(void) { return emitVar; }
int getLife(void) { return life; }
int getLifeVar(void) { return lifeVar; }
float getForceX(void) { return force.x; }
float getForceY(void) { return force.y; }
float getForceZ(void) { return force.z; }
///////////////////////////////////////////////////////////////////
//
// Mutators
//
///////////////////////////////////////////////////////////////////
void setPosX(float posX) { pos.x = posX; }
void setPosY(float posY) { pos.y = posY; }
void setPosZ(float posZ) { pos.z = posZ; }
inline void setPosVec(tVector newPos)
{
pos.x = newPos.x;
pos.y = newPos.y;
pos.z = newPos.z;
}
void setFinalPosX(float finalposX) { finalPos.x = finalposX; }
void setFinalPosY(float finalposY) { finalPos.y = finalposY; }
void setFinalPosZ(float finalposZ) { finalPos.z = finalposZ; }
void setTexture(int id) { texture = id; }
void setIsFinished(bool finished) { isFinished = finished; }
void setEmitterLife(int life) { emitterLife = life; }
void setUpdateSpeed(float speed) { updateSpeed = speed; }
void setLife(int newlife) { life = newlife; }
void setLifeVar(int newlifevar) { lifeVar = newlifevar; }
void setSpeed(float newspeed) { speed = newspeed; }
void setSpeedVar(float newspeedvar) { speedVar = newspeedvar; }
void setYaw(float newyaw) { yaw = newyaw; }
void setYawVar(float newyawvar) { yawVar = newyawvar; }
void setPitch(float newpitch) { pitch = newpitch; }
void setPitchVar(float newpitchvar) { pitchVar = newpitchvar; }
void setStartColor(tColor newColor) { startColor = newColor; }
void setStartColorVar(tColor newColorVar) { startColorVar = newColorVar; }
void setEndColor(tColor newColor) { endColor = newColor; }
void setEndColorVar(tColor newColorVar) { endColorVar = newColorVar; }
void setStartColorR(int newColorR) { startColor.r = newColorR; }
void setStartColorG(int newColorG) { startColor.g = newColorG; }
void setStartColorB(int newColorB) { startColor.b = newColorB; }
void setStartColorVarR(int newColorVarR) { startColorVar.r = newColorVarR; }
void setStartColorVarG(int newColorVarG) { startColorVar.g = newColorVarG; }
void setStartColorVarB(int newColorVarB) { startColorVar.b = newColorVarB; }
void setEndColorR(int newColorR) { endColor.r = newColorR; }
void setEndColorG(int newColorG) { endColor.g = newColorG; }
void setEndColorB(int newColorB) { endColor.b = newColorB; }
void setEndColorVarR(int newColorVarR) { endColorVar.r = newColorVarR; }
void setEndColorVarG(int newColorVarG) { endColorVar.g = newColorVarG; }
void setEndColorVarB(int newColorVarB) { endColorVar.b = newColorVarB; }
inline void setBlendMode(int blendmode)
{
if(blendmode >= 1 && blendmode <= 4)
blend_mode = blendmode;
else
blend_mode = 1;
}
void setEmitsPerFrame(int emitsperframe) { emitsPerFrame = emitsperframe; }
void setEmitVar(int emitvar) { emitVar = emitvar; }
void setForceX(float forceX) { force.x = forceX; }
void setForceY(float forceY) { force.y = forceY; }
void setForceZ(float forceZ) { force.z = forceZ; }
void setSize(float newSize) { size = newSize; }
void setRenderParticles(bool render) { renderParticles = render; }
// Destructor
virtual ~CEmitter(void);
};
#endif

View File

@ -0,0 +1,253 @@
/////////////////////////////////////////////////////
// File Name: ParticleEngine.cpp
// Date: 6/29/05
// Author: Will Dull
// Purpose: The particle engine system
// implementation.
/////////////////////////////////////////////////////
#include "precompiled.h"
#include "ParticleEngine.h"
#include <windows.h>
#include "ogl.h"
CParticleEngine *CParticleEngine::m_pInstance = 0;
CParticleEngine::CParticleEngine(void)
{
m_pHead = NULL;
totalParticles = 0;
}
CParticleEngine::~CParticleEngine(void)
{
//// Release all resources.
//for(int i = 0; i < MAX_TEXTURES; i++)
// glDeleteTextures(1, &idTexture[i]);
}
void CParticleEngine::cleanup()
{
tEmitterNode *temp = m_pHead;
totalParticles = 0;
while(temp)
{
tEmitterNode *pTemp = temp->next;
if(!temp->prev)
m_pHead = temp->next;
else
temp->prev->next = temp->next;
if(pTemp)
temp->next->prev = temp->prev;
delete temp->pEmitter;
delete temp;
temp = pTemp;
}
DeleteInstance();
}
CParticleEngine *CParticleEngine::GetInstance(void)
{
// Check to see if one hasn't been made yet.
if (m_pInstance == 0)
m_pInstance = new CParticleEngine;
// Return the address of the instance.
return m_pInstance;
}
void CParticleEngine::DeleteInstance()
{
if (m_pInstance)
delete m_pInstance;
m_pInstance = 0;
}
bool CParticleEngine::initParticleSystem()
{
// Texture Loading
// Needs error checking and testing.
idTexture[DEFAULTTEXT] = ogl_tex_load("art/textures/particles/sprite.tga");
idTexture[DEFAULTTEXT] = ogl_tex_bind(idTexture[DEFAULTTEXT], 0);
glBindTexture(GL_TEXTURE_2D, idTexture[DEFAULTTEXT]);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_REPEAT);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP);
glTexEnvi(GL_TEXTURE_ENV,GL_TEXTURE_ENV_MODE,GL_MODULATE);
//glTexEnvi(GL_TEXTURE_ENV,GL_TEXTURE_ENV_MODE,GL_DECAL);
//glTexEnvi(GL_TEXTURE_ENV,GL_TEXTURE_ENV_MODE,GL_BLEND);
//glTexEnvi(GL_TEXTURE_ENV,GL_TEXTURE_ENV_MODE,GL_REPLACE);
return true;
}
bool CParticleEngine::addEmitter(CEmitter *emitter, int type, int ID)
{
// without array you could do:
//emitter->texture = type + idTextureBase;
emitter->setTexture(idTexture[type]);
if(m_pHead == NULL)
{
tEmitterNode *temp = new tEmitterNode;
temp->pEmitter = emitter;
temp->prev = NULL;
temp->next = NULL;
temp->ID = ID;
m_pHead = temp;
return true;
}
else
{
tEmitterNode *temp = new tEmitterNode;
temp->pEmitter = emitter;
temp->next = m_pHead;
temp->prev = NULL;
temp->ID = ID;
m_pHead->prev = temp;
m_pHead = temp;
return true;
}
}
CEmitter* CParticleEngine::findEmitter(int ID)
{
tEmitterNode *temp = m_pHead;
while(temp)
{
if(temp->ID < 0 || temp->ID > MAX_EMIT)
continue;
// NOTE: In the event that there are two different
// emitters with the same ID, this will only
// return the first one that it finds. So
// make sure your emitter has a unique ID
// if you want to use this function.
if(temp->ID == ID)
return temp->pEmitter;
temp = temp->next;
}
// NOTE: Just in case this happens, it's VERY important
// that you wrap this function in a if statement
// to check for this condition because you could
// end up with a crash if you try to change an
// emitter when you couldn't find it and returned
// NULL instead.
return NULL;
}
void CParticleEngine::updateEmitters()
{
tEmitterNode *temp = m_pHead;
totalParticles = 0;
while(temp)
{
// are we ready for deletion?
if(temp->pEmitter->getIsFinished())
{
// store a pointer to the next node
tEmitterNode *pTemp = temp->next;
// check for the head
if(!temp->prev)
m_pHead = pTemp;
else
// forward the previous's pointer
temp->prev->next = pTemp;
// if there is any next one,
if(pTemp)
// fix the backwards pointer
pTemp->prev = temp->prev;
delete temp->pEmitter;
delete temp;
temp = pTemp;
}
else
{
temp->pEmitter->updateEmitter();
// Add current emitter to particle count
totalParticles += temp->pEmitter->getParticleCount();
temp = temp->next;
}
}
}
void CParticleEngine::renderParticles()
{
EnterParticleContext();
tEmitterNode *temp = m_pHead;
while(temp)
{
temp->pEmitter->renderEmitter();
temp = temp->next;
}
LeaveParticleContext();
}
void CParticleEngine::destroyAllEmitters(bool fade)
{
tEmitterNode *temp = m_pHead;
while(temp)
{
if(fade)
{
temp->pEmitter->setEmitterLife(0);
temp = temp->next;
}
else
{
// store a pointer to the next node
tEmitterNode *pTemp = temp->next;
// check for the head
if(!temp->prev)
m_pHead = pTemp;
else
// forward the previous's pointer
temp->prev->next = pTemp;
// if there is any next one,
if(pTemp)
// fix the backwards pointer
pTemp->prev = temp->prev;
delete temp->pEmitter;
delete temp;
temp = pTemp;
}
}
m_pHead = NULL;
updateEmitters();
}
void CParticleEngine::EnterParticleContext(void)
{
glEnable(GL_DEPTH_TEST); // Enable depth testing for hidden surface removal.
glDepthMask(false);
glDisable(GL_LIGHTING);
glEnable(GL_TEXTURE_2D); // Enable texture mapping.
glPushMatrix();
glEnable(GL_BLEND);
}
void CParticleEngine::LeaveParticleContext(void)
{
glDisable(GL_DEPTH_TEST);
glDisable(GL_TEXTURE_2D);
glDepthMask(true);
glPopMatrix();
glEnable(GL_LIGHTING);
glDisable(GL_BLEND);
}

View File

@ -0,0 +1,142 @@
/////////////////////////////////////////////////////
// File Name: ParticleEngine.h
// Date: 6/29/05
// Author: Will Dull
// Purpose: The particle engine system.
// controls and maintain particles
// through emitters that are passed
// into each of the main functions.
/////////////////////////////////////////////////////
#ifndef _PARTICLEENGINE_H_
#define _PARTICLEENGINE_H_
#include "ParticleEmitter.h"
#include "lib/res/graphics/tex.h"
#include "lib/res/graphics/ogl_tex.h"
#include "ps/CLogger.h"
#include "ps/Loader.h"
// Different textures
enum PText { DEFAULTTEXT, MAX_TEXTURES };
// Different emitters
enum PEmit { DEFAULTEMIT, MAX_EMIT };
class CParticleEngine
{
public:
virtual ~CParticleEngine(void);
//////////////////////////////////////////////////////////////
//Func Name: GetInstance
//Date: 8/1/05
//Author: Will Dull
//Purpose: returns the instance of the singleton class
//////////////////////////////////////////////////////////////
static CParticleEngine* GetInstance();
//////////////////////////////////////////////////////////////
//Func Name: DeleteInstance
//Date: 8/1/05
//Author: Will Dull
//Purpose: deletes the instance of the singleton class
//////////////////////////////////////////////////////////////
static void DeleteInstance();
//////////////////////////////////////////////////////////////
//Func Name: initParticleSystem
//Date: 6/29/05
//Author: Will Dull
//Out: True if particle system initialized correctly,
// false otherwise
//Purpose: inits particle system.
//////////////////////////////////////////////////////////////
bool initParticleSystem(void);
//////////////////////////////////////////////////////////////
//Func Name: addEmitter
//Date: 7/20/05
//Author: Will Dull
//In: emitter to add, texture type, id of emitter
//Out: True if emitter added correctly,
// false otherwise
//Purpose: adds the emitter to the engines list
//////////////////////////////////////////////////////////////
bool addEmitter(CEmitter *emitter, int type = DEFAULTTEXT, int ID = DEFAULTEMIT);
//////////////////////////////////////////////////////////////
//Func Name: findEmitter
//Date: 7/21/05
//Author: Will Dull
//In: id of emitter to find
//Out: the emitter if found,
// NULL otherwise
//Purpose: finds the emitter using its ID
//////////////////////////////////////////////////////////////
CEmitter* findEmitter(int ID);
//////////////////////////////////////////////////////////////
//Func Name: updateEmitters
//Date: 7/20/05
//Author: Will Dull
//Purpose: Checks if the emitter is ready to be deleted
// and removed. If not it calls the emitters update
// function.
//////////////////////////////////////////////////////////////
void updateEmitters();
//////////////////////////////////////////////////////////////
//Func Name: renderParticles
//Date: 7/20/05
//Author: Will Dull
//Purpose: Renders the emitter and all it's particles
//////////////////////////////////////////////////////////////
void renderParticles();
//////////////////////////////////////////////////////////////
//Func Name: destroyAllEmitters
//Date: 8/1/05
//Author: Will Dull
//In: fade - if true, will allow the emitter to fade itself out
// if false, emitter and particles will disappear instantly
//Purpose: Destroys every active emitter on screen.
//////////////////////////////////////////////////////////////
void destroyAllEmitters(bool fade = true);
//////////////////////////////////////////////////////////////
//Func Name: cleanup
//Date: 8/3/05
//Author: Will Dull
//Purpose: Any cleanup not done in the destructor.
//////////////////////////////////////////////////////////////
void cleanup();
void EnterParticleContext(void);
void LeaveParticleContext(void);
int getTotalParticles() { return totalParticles; }
void SetTotalParticles(int particles) { totalParticles = particles; }
void AddToTotalParticles(int addAmount) { totalParticles += addAmount; }
void SubToTotalParticles(int subAmount) { totalParticles -= subAmount; }
private:
CParticleEngine(void);
static CParticleEngine* m_pInstance; // The singleton instance
Handle idTexture[MAX_TEXTURES];
int totalParticles; // Total Amount of particles of all emitters.
struct tEmitterNode
{
CEmitter *pEmitter;
tEmitterNode *prev, *next;
int ID;
};
tEmitterNode *m_pHead;
friend class CEmitter;
};
#endif