mirror of
https://github.com/AquariaOSE/Aquaria.git
synced 2025-10-04 13:27:14 +00:00
initial commit. This is icculus version 5542b94cae02a6333845854bbbd1abe0a259f1a4
This commit is contained in:
commit
3096eaf5e2
2519 changed files with 816064 additions and 0 deletions
497
BBGE/ParticleManager.cpp
Normal file
497
BBGE/ParticleManager.cpp
Normal file
|
@ -0,0 +1,497 @@
|
|||
/*
|
||||
Copyright (C) 2007, 2010 - Bit-Blot
|
||||
|
||||
This file is part of Aquaria.
|
||||
|
||||
Aquaria is free software; you can redistribute it and/or
|
||||
modify it under the terms of the GNU General Public License
|
||||
as published by the Free Software Foundation; either version 2
|
||||
of the License, or (at your option) any later version.
|
||||
|
||||
This program is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
|
||||
|
||||
See the GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with this program; if not, write to the Free Software
|
||||
Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
|
||||
*/
|
||||
#include "Particles.h"
|
||||
|
||||
ParticleManager *particleManager = 0;
|
||||
|
||||
typedef std::map<std::string, ParticleEffect*> ParticleBank;
|
||||
ParticleBank particleBank;
|
||||
|
||||
std::string ParticleManager::particleBankPath = "";
|
||||
|
||||
ParticleManager::ParticleManager(int size)
|
||||
{
|
||||
particleManager = this;
|
||||
particles.resize(size);
|
||||
used = 0;
|
||||
free = 0;
|
||||
oldFree = 0;
|
||||
|
||||
|
||||
collideFunction = 0;
|
||||
specialFunction = 0;
|
||||
|
||||
numActive = 0;
|
||||
|
||||
setSize(size);
|
||||
}
|
||||
|
||||
void ParticleManager::setSize(int size)
|
||||
{
|
||||
// dangerous!
|
||||
for (int i = 0; i < particles.size(); i++)
|
||||
{
|
||||
Particle *p = &particles[i];
|
||||
if (p->emitter)
|
||||
{
|
||||
p->emitter->removeParticle(p);
|
||||
}
|
||||
}
|
||||
|
||||
particles.clear();
|
||||
|
||||
particles.resize(size);
|
||||
|
||||
this->size = size;
|
||||
this->halfSize = size*0.5f;
|
||||
|
||||
free = oldFree = 0;
|
||||
}
|
||||
|
||||
void ParticleManager::setNumSuckPositions(int num)
|
||||
{
|
||||
suckPositions.resize(num);
|
||||
}
|
||||
|
||||
void ParticleManager::setSuckPosition(int idx, const Vector &pos)
|
||||
{
|
||||
if (idx < 0 || idx >= suckPositions.size()) return;
|
||||
suckPositions[idx] = pos;
|
||||
}
|
||||
|
||||
Vector *ParticleManager::getSuckPosition(int idx)
|
||||
{
|
||||
if (idx < 0 || idx >= suckPositions.size()) return 0;
|
||||
return &suckPositions[idx];
|
||||
}
|
||||
|
||||
void ParticleManager::updateParticle(Particle *p, float dt)
|
||||
{
|
||||
if (!p->active) return;
|
||||
numActive++;
|
||||
if (p->emitter && p->emitter->data.pauseLevel < core->particlesPaused)
|
||||
return;
|
||||
|
||||
p->color.update(dt);
|
||||
p->alpha.update(dt);
|
||||
p->scale.update(dt);
|
||||
p->rot.update(dt);
|
||||
p->pos += p->vel * dt;
|
||||
p->life = p->life - dt;
|
||||
p->vel += p->gvy * dt;
|
||||
|
||||
if (p->emitter)
|
||||
{
|
||||
if (p->emitter->data.influenced)
|
||||
{
|
||||
ParticleInfluence *pinf=0;
|
||||
|
||||
if (collideFunction)
|
||||
{
|
||||
if (collideFunction(p->pos))
|
||||
{
|
||||
const bool bounce = false;
|
||||
if (bounce)
|
||||
{
|
||||
p->pos = p->lpos;
|
||||
p->vel = -p->vel;
|
||||
}
|
||||
else
|
||||
{
|
||||
// fade out
|
||||
p->vel = 0;
|
||||
endParticle(p);
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (specialFunction)
|
||||
{
|
||||
specialFunction(p);
|
||||
}
|
||||
p->lpos = p->pos;
|
||||
Influences::iterator i = influences.begin();
|
||||
for (; i != influences.end(); i++)
|
||||
{
|
||||
|
||||
pinf = &(*i);
|
||||
Vector pos = p->pos;
|
||||
//HACK: what? ->
|
||||
if (p->emitter->data.spawnLocal && p->emitter->getParent())
|
||||
pos += p->emitter->getParent()->position;
|
||||
if ((pinf->pos - pos).isLength2DIn(pinf->size + p->emitter->data.influenced))
|
||||
{
|
||||
Vector dir = pos - pinf->pos;
|
||||
dir.setLength2D(pinf->spd);
|
||||
if (!pinf->pull)
|
||||
p->vel += dir * dt;
|
||||
else
|
||||
p->vel -= dir * dt;
|
||||
}
|
||||
}
|
||||
}
|
||||
if (p->emitter->data.suckIndex > -1)
|
||||
{
|
||||
Vector *suckPos = getSuckPosition(p->emitter->data.suckIndex);
|
||||
if (suckPos)
|
||||
{
|
||||
Vector dir = (*suckPos) - p->emitter->getWorldCollidePosition(p->pos);
|
||||
dir.setLength2D(p->emitter->data.suckStr);
|
||||
p->vel += dir * dt;
|
||||
}
|
||||
}
|
||||
if (p->rot.z != 0 || p->rot.isInterpolating())
|
||||
p->emitter->hasRot = true;
|
||||
}
|
||||
|
||||
p->lpos = p->pos;
|
||||
|
||||
|
||||
if (p->life <= 0)
|
||||
{
|
||||
endParticle(p);
|
||||
}
|
||||
}
|
||||
|
||||
void ParticleManager::endParticle(Particle *p)
|
||||
{
|
||||
if (!p) return;
|
||||
|
||||
if (p->emitter)
|
||||
{
|
||||
if (!p->emitter->data.deathPrt.empty())
|
||||
{
|
||||
RenderObject *r = p->emitter->getTopParent();
|
||||
if (r)
|
||||
core->createParticleEffect(p->emitter->data.deathPrt, p->pos, r->layer, p->rot.z);
|
||||
}
|
||||
p->emitter->removeParticle(p);
|
||||
}
|
||||
if (p->index != -1)
|
||||
{
|
||||
/*
|
||||
// set free if the neighbours are also free
|
||||
int backupFree = free;
|
||||
int oldFree = p->index;
|
||||
free = oldFree;
|
||||
nextFree();
|
||||
if (!particles[free].active)
|
||||
{
|
||||
free = oldFree;
|
||||
prevFree();
|
||||
if (!particles[free].active)
|
||||
{
|
||||
// good to go!
|
||||
}
|
||||
else
|
||||
{
|
||||
free = backupFree;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
free = backupFree;
|
||||
}
|
||||
*/
|
||||
//if (p->index > free)
|
||||
//{
|
||||
//free = p->index;
|
||||
//}
|
||||
}
|
||||
p->reset();
|
||||
}
|
||||
|
||||
void ParticleManager::nextFree(int jump)
|
||||
{
|
||||
free+=jump;
|
||||
if (free >= size)
|
||||
free -= size;
|
||||
}
|
||||
|
||||
void ParticleManager::prevFree(int jump)
|
||||
{
|
||||
free -= jump;
|
||||
if (free < 0)
|
||||
free += size;
|
||||
}
|
||||
|
||||
void ParticleManager::setFree(int free)
|
||||
{
|
||||
if (free != -1)
|
||||
{
|
||||
this->free = free;
|
||||
}
|
||||
}
|
||||
|
||||
const int spread = 8;
|
||||
const int spreadCheck = 128;
|
||||
|
||||
// travel the list until you find an empty or give up
|
||||
Particle *ParticleManager::stomp()
|
||||
{
|
||||
int c = 0, idx = -1;
|
||||
//int bFree = free;
|
||||
Particle *p = 0;
|
||||
bool exceed = false;
|
||||
|
||||
|
||||
nextFree();
|
||||
do
|
||||
{
|
||||
if (c >= spreadCheck)
|
||||
{
|
||||
exceed = true;
|
||||
break;
|
||||
}
|
||||
|
||||
p = &particles[free];
|
||||
idx = free;
|
||||
nextFree();
|
||||
c++;
|
||||
}
|
||||
while (p->active);
|
||||
|
||||
/*
|
||||
int nFree = free;
|
||||
int pFree = free;
|
||||
|
||||
nextFree();
|
||||
nFree = free;
|
||||
|
||||
free = bFree;
|
||||
prevFree();
|
||||
pFree = free;
|
||||
|
||||
do
|
||||
{
|
||||
free = nFree;
|
||||
p = &particles[free];
|
||||
idx = free;
|
||||
nextFree();
|
||||
nFree = free;
|
||||
|
||||
if (p->active)
|
||||
{
|
||||
free = pFree;
|
||||
p = &particles[free];
|
||||
idx = free;
|
||||
prevFree();
|
||||
pFree = free;
|
||||
}
|
||||
c++;
|
||||
if (c >= spreadCheck)
|
||||
{
|
||||
exceed = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
while (p->active);
|
||||
*/
|
||||
/*
|
||||
if (p->active)
|
||||
{
|
||||
c = 0;
|
||||
free = backupFree;
|
||||
nextFree();
|
||||
do
|
||||
{
|
||||
p = &particles[free];
|
||||
idx = free;
|
||||
nextFree();
|
||||
c++;
|
||||
if (c >= 8)
|
||||
{
|
||||
exceed = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
while (p->active);
|
||||
}
|
||||
*/
|
||||
|
||||
if (exceed)
|
||||
{
|
||||
//debugLog("EXCEEDED");
|
||||
}
|
||||
|
||||
endParticle(p);
|
||||
p->index = idx;
|
||||
return p;
|
||||
}
|
||||
|
||||
/*
|
||||
const int FREELISTSIZE = 32;
|
||||
|
||||
void ParticleManager::getFreeList(int list)
|
||||
{
|
||||
for (int i = 0; i < FREELISTSIZE; i++)
|
||||
{
|
||||
if (freeList[curList] != -1)
|
||||
{
|
||||
Particle *p = &particles[freeList[curList]];
|
||||
freeList[curList] = -1;
|
||||
return p;
|
||||
}
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
void ParticleManager::addFreeList()
|
||||
{
|
||||
}
|
||||
*/
|
||||
|
||||
Particle *ParticleManager::getFreeParticle(Emitter *emitter)
|
||||
{
|
||||
BBGE_PROF(ParticleManager_getFreeParticle);
|
||||
if (size == 0) return 0;
|
||||
|
||||
Particle *p = 0;
|
||||
|
||||
p = &particles[free];
|
||||
|
||||
if (p->active)
|
||||
{
|
||||
p = stomp();
|
||||
}
|
||||
else
|
||||
{
|
||||
endParticle(p);
|
||||
p->index = free;
|
||||
nextFree(spread);
|
||||
}
|
||||
|
||||
/*
|
||||
static int lpstep = 0;
|
||||
if (c > lpstep)
|
||||
lpstep = c;
|
||||
std::ostringstream os;
|
||||
os << "psteps: " << c << " largest: " << lpstep;
|
||||
debugLog(os.str());
|
||||
*/
|
||||
|
||||
|
||||
/*
|
||||
p = &particles[free];
|
||||
nextFree();
|
||||
*/
|
||||
|
||||
|
||||
|
||||
if (emitter)
|
||||
{
|
||||
p->emitter = emitter;
|
||||
|
||||
emitter->addParticle(p);
|
||||
}
|
||||
|
||||
return p;
|
||||
}
|
||||
|
||||
void loadParticleCallback(const std::string &filename, intptr_t param)
|
||||
{
|
||||
ParticleEffect *e = new ParticleEffect();
|
||||
|
||||
std::string ident;
|
||||
int first = filename.find_last_of('/')+1;
|
||||
ident = filename.substr(first, filename.find_last_of('.')-first);
|
||||
stringToLower(ident);
|
||||
|
||||
e->bankLoad(ident, ParticleManager::particleBankPath);
|
||||
|
||||
particleBank[ident] = e;
|
||||
}
|
||||
|
||||
void ParticleManager::loadParticleBank(const std::string &bank1, const std::string &bank2)
|
||||
{
|
||||
clearParticleBank();
|
||||
|
||||
particleBankPath = bank1;
|
||||
forEachFile(bank1, ".txt", loadParticleCallback, 0);
|
||||
|
||||
if (!bank2.empty())
|
||||
{
|
||||
particleBankPath = bank2;
|
||||
forEachFile(bank2, ".txt", loadParticleCallback, 0);
|
||||
}
|
||||
|
||||
particleBankPath = "";
|
||||
}
|
||||
|
||||
void ParticleManager::loadParticleEffectFromBank(const std::string &name, ParticleEffect *load)
|
||||
{
|
||||
std::string realName = name;
|
||||
stringToLower(realName);
|
||||
ParticleEffect *fx = particleBank[realName];
|
||||
|
||||
if (fx)
|
||||
fx->transfer(load);
|
||||
else
|
||||
{
|
||||
std::ostringstream os;
|
||||
os << "Did not find PE [" << name << "] in particle bank";
|
||||
debugLog(os.str());
|
||||
}
|
||||
}
|
||||
|
||||
void ParticleManager::clearParticleBank()
|
||||
{
|
||||
for (ParticleBank::iterator i = particleBank.begin(); i != particleBank.end(); i++)
|
||||
{
|
||||
ParticleEffect *e = (*i).second;
|
||||
if (e)
|
||||
{
|
||||
e->destroy();
|
||||
delete e;
|
||||
}
|
||||
}
|
||||
particleBank.clear();
|
||||
}
|
||||
|
||||
int ParticleManager::getSize()
|
||||
{
|
||||
return size;
|
||||
}
|
||||
|
||||
void ParticleManager::update(float dt)
|
||||
{
|
||||
BBGE_PROF(ParticleManager_update);
|
||||
numActive = 0;
|
||||
for (int i = 0; i < particles.size(); i++)
|
||||
{
|
||||
if (particles[i].active)
|
||||
{
|
||||
updateParticle(&particles[i], dt);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void ParticleManager::clearInfluences()
|
||||
{
|
||||
influences.clear();
|
||||
}
|
||||
|
||||
void ParticleManager::addInfluence(ParticleInfluence inf)
|
||||
{
|
||||
influences.push_back(inf);
|
||||
}
|
||||
|
Loading…
Add table
Add a link
Reference in a new issue