0ad/source/graphics/ParticleEngine.cpp
2006-02-17 02:02:29 +00:00

251 lines
5.4 KiB
C++

/////////////////////////////////////////////////////
// File Name: ParticleEngine.cpp
// Date: 6/29/05
// Author: Will Dull
// Purpose: The particle engine system
// implementation.
/////////////////////////////////////////////////////
#include "precompiled.h"
#include "ParticleEngine.h"
CParticleEngine *CParticleEngine::m_pInstance = 0;
CParticleEngine::CParticleEngine(void)
{
m_pHead = NULL;
totalParticles = 0;
}
CParticleEngine::~CParticleEngine(void)
{
}
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
CTexture pTex;
pTex.SetName("art/textures/particles/sprite.tga");
u32 flags = 0;
if(!(g_Renderer.LoadTexture(&pTex, flags)))
return false;
g_Renderer.SetTexture(0, &pTex);
idTexture[DEFAULTTEXT] = pTex;
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)
{
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);
glDepthMask(true);
//glEnable(GL_LIGHTING);
glDisable(GL_TEXTURE_2D);
glPopMatrix();
glDisable(GL_BLEND);
}