1
0
Fork 0
mirror of https://github.com/AquariaOSE/Aquaria.git synced 2024-12-25 14:15:46 +00:00
Aquaria/BBGE/Emitter.cpp

413 lines
7.8 KiB
C++

/*
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"
Emitter::Emitter(ParticleEffect *pe) : Quad(), pe(pe)
{
//HACK:
cull = false;
hasRot = false;
}
void Emitter::destroy()
{
BBGE_PROF(Emitter_destroy);
for (Particles::iterator i = particles.begin(); i != particles.end(); i++)
{
(*i)->active = false;
(*i)->emitter = 0;
}
particles.clear();
Quad::destroy();
//particleManager->setFree(firstFree);
}
void Emitter::spawnParticle(float perc)
{
BBGE_PROF(Emitter_spawnParticle);
Particle *p = particleManager->getFreeParticle(this);
p->active = true;
p->life = data.life;
setBlendType(data.blendType);
width = data.width;
height = data.height;
p->color = data.color;
p->alpha = data.alpha;
p->vel += data.initialVelocity;
p->gvy = data.gravity;
p->scale = data.scale;
p->rot = data.rotation;
p->pos = lastSpawn + ((currentSpawn - lastSpawn) * perc);
int finalRadius = data.randomSpawnRadius;
if (data.randomSpawnRadiusRange > 0)
finalRadius += rand()%data.randomSpawnRadiusRange;
switch (data.spawnArea)
{
case SpawnParticleData::SPAWN_CIRCLE:
{
float a = rand()%360;
p->pos += Vector(sinf(a)*finalRadius * data.randomSpawnMod.x, cosf(a)*finalRadius * data.randomSpawnMod.y);
}
break;
case SpawnParticleData::SPAWN_LINE:
{
if (rand()%2 == 0)
p->pos.x += finalRadius;
else
p->pos.x -= finalRadius;
}
break;
}
if (data.randomScale1 == 1 && data.randomScale1 == data.randomScale2)
{
}
else
{
int r = rand()%(int(data.randomScale2*100) - int(data.randomScale1*100));
float sz = data.randomScale1 + float(r)/100.0f;
p->scale = Vector(sz,sz);
}
if (data.randomRotationRange > 0)
{
p->rot.z = rand()%int(data.randomRotationRange);
p->rot.ensureData();
p->rot.data->target.z += p->rot.z;
}
/*
if (data.calculateVelocityToCenter)
{
Vector pos = p->position - this->position;
pos.setLength2D(1);
quad->velocity = -p*particles[i].velocityMagnitude.x;
}
*/
if (data.randomVelocityMagnitude > 0)
{
float a = rand()%data.randomVelocityRange;
Vector v = Vector(sinf(a)*data.randomVelocityMagnitude, cosf(a)*data.randomVelocityMagnitude);
p->vel += v;
}
if (data.copyParentRotation)
{
p->rot.z = getAbsoluteRotation().z;
}
}
Vector Emitter::getSpawnPosition()
{
if (!data.spawnLocal)
return pe->getWorldPosition();
return Vector(0,0);
}
void Emitter::onUpdate(float dt)
{
Quad::onUpdate(dt);
/*
for (Particles::iterator i = particles.begin(); i != particles.end(); i++)
{
particleManager->updateParticle(*i, dt);
}
*/
if (pe->isRunning() && core->particlesPaused <= data.pauseLevel)
{
if (data.spawnTimeOffset > 0)
{
data.spawnTimeOffset -= dt;
if (data.spawnTimeOffset > 0)
return;
}
int spawnCount;
float spawnPerc;
if (data.justOne)
{
if (data.didOne)
spawnCount = 0;
else
spawnCount = data.justOne;
spawnPerc = 1;
data.didOne = 1;
}
else if (data.useSpawnRate)
{
spawnCount = 0;
spawnPerc = 1;
data.counter += dt;
while (data.counter > data.spawnRate.x) // Faster than division
{
data.counter -= data.spawnRate.x;
spawnCount++;
}
}
else
{
float num = data.number.x * dt;
num += data.lastDTDifference;
spawnCount = int(num);
data.lastDTDifference = num - float(spawnCount);
if (spawnCount > 0)
spawnPerc = 1.0f / float(spawnCount);
}
if (spawnCount > 0)
{
// Avoid calling this until we know we actually need it for
// generating a particle (it has to apply the matrix chain,
// which is slow).
currentSpawn = getSpawnPosition();
if (lastSpawn.isZero())
lastSpawn = currentSpawn;
for (; spawnCount > 0; spawnCount--)
{
spawnParticle(spawnPerc);
}
lastSpawn = currentSpawn;
}
data.number.update(dt);
data.velocityMagnitude.update(dt);
data.spawnOffset.update(dt);
}
}
void Emitter::start()
{
data.didOne = 0;
lastSpawn = getSpawnPosition();
}
void Emitter::stop()
{
}
void Emitter::addParticle(Particle *p)
{
particles.push_front(p);
}
void Emitter::removeParticle(Particle *p)
{
if (particles.back() == p)
{
particles.pop_back();
}
else
particles.remove(p);
/*
for (Particles::reverse_iterator i = particles.rbegin(); i != particles.rend(); i++)
{
if (*i == p)
{
particles.erase(i);
return;
}
}
*/
}
void Emitter::render()
{
Quad::render();
}
void Emitter::onRender()
{
BBGE_PROF(Emitter_onRender);
if (particles.empty()) return;
if (!data.spawnLocal)
{
#ifdef BBGE_BUILD_OPENGL
glLoadIdentity();
#endif
/*
if (pe && pe->followCamera)
{
glLoadIdentity();
glScalef(core->globalResolutionScale.x, core->globalResolutionScale.y,0);
}
else
{
core->setupRenderPositionAndScale();
}
*/
core->setupRenderPositionAndScale();
}
float w2 = width*0.5f;
float h2 = height*0.5f;
if (texture)
texture->apply();
if (hasRot)
{
for (Particles::iterator i = particles.begin(); i != particles.end(); i++)
{
Particle *p = *i;
if (p->active)
{
const float dx = w2 * p->scale.x;
const float dy = h2 * p->scale.y;
#ifdef BBGE_BUILD_OPENGL
glColor4f(p->color.x, p->color.y, p->color.z, p->alpha.x);
if (p->rot.z != 0 || p->rot.isInterpolating())
{
glPushMatrix();
glTranslatef(p->pos.x, p->pos.y,0);
glRotatef(p->rot.z, 0, 0, 1);
if (data.flipH || (data.copyParentFlip && (pe->isfh() || (pe->getParent() && pe->getParent()->isfh()))))
{
glDisable(GL_CULL_FACE);
glRotatef(180, 0, 1, 0);
}
/*
if (data.flipV || (data.copyParentFlip && (this->isfv() || (parent && parent->isfv()))))
{
glDisable(GL_CULL_FACE);
}
*/
glBegin(GL_QUADS);
glTexCoord2f(0,1);
glVertex2f(-dx, +dy);
glTexCoord2f(1,1);
glVertex2f(+dx, +dy);
glTexCoord2f(1,0);
glVertex2f(+dx, -dy);
glTexCoord2f(0,0);
glVertex2f(-dx, -dy);
glEnd();
glPopMatrix();
}
else
{
const float x = p->pos.x;
const float y = p->pos.y;
glBegin(GL_QUADS);
glTexCoord2f(0,1);
glVertex2f(x-dx, y+dy);
glTexCoord2f(1,1);
glVertex2f(x+dx, y+dy);
glTexCoord2f(1,0);
glVertex2f(x+dx, y-dy);
glTexCoord2f(0,0);
glVertex2f(x-dx, y-dy);
glEnd();
}
#endif
}
}
}
else
{
#ifdef BBGE_BUILD_OPENGL
glBegin(GL_QUADS);
for (Particles::iterator i = particles.begin(); i != particles.end(); i++)
{
Particle *p = *i;
if (p->active)
{
const float x = p->pos.x;
const float y = p->pos.y;
const float dx = w2 * p->scale.x;
const float dy = h2 * p->scale.y;
glColor4f(p->color.x, p->color.y, p->color.z, p->alpha.x);
glTexCoord2f(0,1);
glVertex2f(x-dx, y+dy);
glTexCoord2f(1,1);
glVertex2f(x+dx, y+dy);
glTexCoord2f(1,0);
glVertex2f(x+dx, y-dy);
glTexCoord2f(0,0);
glVertex2f(x-dx, y-dy);
}
}
glEnd();
#endif
}
/*
glDisable(GL_TEXTURE_2D);
glPointSize(4);
glBegin(GL_POINTS);
for (Particles::iterator i = particles.begin(); i != particles.end(); i++)
{
Particle *p = *i;
if (p->active)
{
glColor4f(1, 0, 0, 1);
x = p->pos.x;
y = p->pos.y;
glVertex2f(x, y);
}
}
glEnd();
glEnable(GL_TEXTURE_2D);
*/
}