janwas
c0ed950657
this snowballed into a massive search+destroy of the hodgepodge of mostly equivalent types we had in use (int, uint, unsigned, unsigned int, i32, u32, ulong, uintN). it is more efficient to use 64-bit types in 64-bit mode, so the preferred default is size_t (for anything remotely resembling a size or index). tile coordinates are ssize_t to allow more efficient conversion to/from floating point. flags are int because we almost never need more than 15 distinct bits, bit test/set is not slower and int is fastest to type. finally, some data that is pretty much directly passed to OpenGL is now typed accordingly. after several hours, the code now requires fewer casts and less guesswork. other changes: - unit and player IDs now have an "invalid id" constant in the respective class to avoid casting and -1 - fix some endian/64-bit bugs in the map (un)packing. added a convenience function to write/read a size_t. - ia32: change CPUID interface to allow passing in ecx (required for cache topology detection, which I need at work). remove some unneeded functions from asm, replace with intrinsics where possible. This was SVN commit r5942.
251 lines
5.2 KiB
C++
251 lines
5.2 KiB
C++
/**
|
|
* =========================================================================
|
|
* File : ParticleEngine.cpp
|
|
* Project : 0 A.D.
|
|
* Description : Particle engine 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");
|
|
|
|
int 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->IsFinished())
|
|
{
|
|
// 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->Update();
|
|
|
|
// 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->Render();
|
|
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);
|
|
}
|