mirror of
https://github.com/AquariaOSE/Aquaria.git
synced 2024-11-29 12:03:51 +00:00
68b3c61852
This will eventually handle all mutable state during rendering
347 lines
6.6 KiB
C++
347 lines
6.6 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"
|
|
#include "RenderBase.h"
|
|
|
|
Emitter::Emitter(ParticleEffect *pe) : Quad(), pe(pe)
|
|
{
|
|
//HACK:
|
|
cull = false;
|
|
hasRot = false;
|
|
}
|
|
|
|
void Emitter::destroy()
|
|
{
|
|
for (Particles::iterator i = particles.begin(); i != particles.end(); i++)
|
|
{
|
|
(*i)->active = false;
|
|
(*i)->emitter = 0;
|
|
}
|
|
particles.clear();
|
|
Quad::destroy();
|
|
|
|
}
|
|
|
|
void Emitter::spawnParticle(float perc)
|
|
{
|
|
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.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);
|
|
|
|
|
|
|
|
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);
|
|
|
|
}
|
|
|
|
void Emitter::onRender(const RenderState& rs) const
|
|
{
|
|
if (particles.empty()) return;
|
|
|
|
if (!data.spawnLocal)
|
|
{
|
|
glLoadIdentity();
|
|
|
|
core->setupRenderPositionAndScale();
|
|
}
|
|
|
|
float w2 = width*0.5f;
|
|
float h2 = height*0.5f;
|
|
|
|
if (texture)
|
|
texture->apply();
|
|
|
|
|
|
|
|
if (hasRot)
|
|
{
|
|
Vector colorMult = data.inheritColor ? pe->color : Vector(1, 1, 1);
|
|
float alphaMult = data.inheritAlpha ? pe->alpha.x : 1;
|
|
for (Particles::const_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;
|
|
|
|
Vector col = p->color * colorMult;
|
|
glColor4f(col.x, col.y, col.z, p->alpha.x * alphaMult);
|
|
|
|
|
|
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()))))
|
|
{
|
|
|
|
glRotatef(180, 0, 1, 0);
|
|
}
|
|
|
|
|
|
|
|
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();
|
|
}
|
|
}
|
|
}
|
|
}
|
|
else
|
|
{
|
|
glBegin(GL_QUADS);
|
|
for (Particles::const_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();
|
|
}
|
|
|
|
|
|
|
|
}
|