mirror of
https://github.com/AquariaOSE/Aquaria.git
synced 2024-12-26 14:45:48 +00:00
414 lines
7.8 KiB
C++
414 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);
|
||
|
*/
|
||
|
}
|