2011-08-03 22:05:33 +02:00
|
|
|
/*
|
|
|
|
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"
|
2016-07-09 04:18:40 +02:00
|
|
|
#include "RenderBase.h"
|
2011-08-03 22:05:33 +02:00
|
|
|
|
2025-02-01 07:32:54 +01:00
|
|
|
|
|
|
|
SpawnParticleData::SpawnParticleData()
|
|
|
|
{
|
|
|
|
suckIndex = -1;
|
|
|
|
suckStr = 0;
|
|
|
|
|
|
|
|
randomScale1 = 1;
|
|
|
|
randomScale2 = 1;
|
|
|
|
randomAlphaMod1 = 1;
|
|
|
|
randomAlphaMod2 = 1;
|
|
|
|
influenced = 0;
|
|
|
|
spawnLocal = false;
|
|
|
|
life = 1;
|
|
|
|
blendType = BLEND_DEFAULT;
|
|
|
|
scale = Vector(1,1,1);
|
|
|
|
width = 64;
|
|
|
|
height = 64;
|
|
|
|
color = Vector(1,1,1);
|
|
|
|
alpha = 1;
|
|
|
|
randomSpawnRadius = 0;
|
|
|
|
|
|
|
|
randomRotationRange = 0;
|
|
|
|
number = 1;
|
|
|
|
|
|
|
|
randomSpawnRadiusRange = 0;
|
|
|
|
randomSpawnMod = Vector(1,1);
|
|
|
|
|
|
|
|
randomVelocityMagnitude = 0;
|
|
|
|
|
|
|
|
copyParentRotation = 0;
|
2025-02-05 04:54:37 +01:00
|
|
|
justOne = false;
|
2025-02-01 07:32:54 +01:00
|
|
|
flipH = flipV = 0;
|
|
|
|
spawnTimeOffset = 0;
|
|
|
|
pauseLevel = 0;
|
|
|
|
copyParentFlip = 0;
|
|
|
|
inheritColor = false;
|
|
|
|
inheritAlpha = false;
|
|
|
|
}
|
|
|
|
|
2011-08-03 22:05:33 +02:00
|
|
|
Emitter::Emitter(ParticleEffect *pe) : Quad(), pe(pe)
|
|
|
|
{
|
|
|
|
//HACK:
|
|
|
|
cull = false;
|
|
|
|
}
|
|
|
|
|
|
|
|
void Emitter::destroy()
|
|
|
|
{
|
|
|
|
for (Particles::iterator i = particles.begin(); i != particles.end(); i++)
|
|
|
|
{
|
|
|
|
(*i)->active = false;
|
|
|
|
(*i)->emitter = 0;
|
|
|
|
}
|
|
|
|
particles.clear();
|
|
|
|
Quad::destroy();
|
2016-05-05 19:40:28 +02:00
|
|
|
|
2011-08-03 22:05:33 +02:00
|
|
|
}
|
|
|
|
|
2025-02-05 04:54:37 +01:00
|
|
|
Particle *Emitter::spawnParticle(const Vector& spawnpos)
|
2011-08-03 22:05:33 +02:00
|
|
|
{
|
|
|
|
Particle *p = particleManager->getFreeParticle(this);
|
|
|
|
|
|
|
|
p->active = true;
|
2016-05-05 19:40:28 +02:00
|
|
|
|
2011-08-03 22:05:33 +02:00
|
|
|
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;
|
|
|
|
|
2025-02-05 04:54:37 +01:00
|
|
|
p->pos = spawnpos;
|
2011-08-03 22:05:33 +02:00
|
|
|
|
2025-02-01 07:32:54 +01:00
|
|
|
float finalRadius = data.randomSpawnRadius + rng.f01() * data.randomSpawnRadiusRange;
|
2011-08-03 22:05:33 +02:00
|
|
|
|
|
|
|
{
|
2025-02-01 07:32:54 +01:00
|
|
|
float a = randAngle();
|
2011-08-03 22:05:33 +02:00
|
|
|
p->pos += Vector(sinf(a)*finalRadius * data.randomSpawnMod.x, cosf(a)*finalRadius * data.randomSpawnMod.y);
|
|
|
|
}
|
|
|
|
|
|
|
|
{
|
2025-02-01 07:32:54 +01:00
|
|
|
float sz = lerp(data.randomScale1, data.randomScale2, rng.f01());
|
2025-02-01 19:35:55 +01:00
|
|
|
p->scale *= sz;
|
|
|
|
if(p->scale.data)
|
|
|
|
p->scale.data->target *= sz;
|
2011-08-03 22:05:33 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
if (data.randomRotationRange > 0)
|
|
|
|
{
|
2025-02-01 07:32:54 +01:00
|
|
|
p->rot.z = rng.f01() * data.randomRotationRange;
|
2025-02-01 19:35:55 +01:00
|
|
|
if(p->rot.data)
|
|
|
|
p->rot.data->target.z += p->rot.z;
|
2011-08-03 22:05:33 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
if (data.randomVelocityMagnitude > 0)
|
|
|
|
{
|
2025-02-01 07:32:54 +01:00
|
|
|
float a = randAngle();
|
2011-08-03 22:05:33 +02:00
|
|
|
Vector v = Vector(sinf(a)*data.randomVelocityMagnitude, cosf(a)*data.randomVelocityMagnitude);
|
|
|
|
p->vel += v;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (data.copyParentRotation)
|
|
|
|
{
|
|
|
|
p->rot.z = getAbsoluteRotation().z;
|
|
|
|
}
|
2025-02-05 04:54:37 +01:00
|
|
|
|
|
|
|
return p;
|
2011-08-03 22:05:33 +02:00
|
|
|
}
|
|
|
|
|
2025-02-01 07:32:54 +01:00
|
|
|
float Emitter::randAngle()
|
|
|
|
{
|
|
|
|
return 2 * PI * rng.f01();
|
|
|
|
}
|
|
|
|
|
2011-08-03 22:05:33 +02:00
|
|
|
Vector Emitter::getSpawnPosition()
|
|
|
|
{
|
|
|
|
if (!data.spawnLocal)
|
|
|
|
return pe->getWorldPosition();
|
|
|
|
return Vector(0,0);
|
|
|
|
}
|
|
|
|
|
|
|
|
void Emitter::onUpdate(float dt)
|
|
|
|
{
|
|
|
|
Quad::onUpdate(dt);
|
2016-05-05 19:40:28 +02:00
|
|
|
|
2025-02-01 07:32:54 +01:00
|
|
|
if(!(pe->isRunning() && core->particlesPaused <= data.pauseLevel))
|
|
|
|
return;
|
2016-05-05 19:40:28 +02:00
|
|
|
|
2011-08-03 22:05:33 +02:00
|
|
|
|
2025-02-01 07:32:54 +01:00
|
|
|
if (data.spawnTimeOffset > 0)
|
2011-08-03 22:05:33 +02:00
|
|
|
{
|
2025-02-01 07:32:54 +01:00
|
|
|
data.spawnTimeOffset -= dt;
|
2011-08-03 22:05:33 +02:00
|
|
|
if (data.spawnTimeOffset > 0)
|
2025-02-01 07:32:54 +01:00
|
|
|
return;
|
2025-02-05 04:54:37 +01:00
|
|
|
lastSpawn = getSpawnPosition();
|
2025-02-01 07:32:54 +01:00
|
|
|
}
|
2011-08-03 22:05:33 +02:00
|
|
|
|
2025-02-05 04:54:37 +01:00
|
|
|
int spawnCount = 0;
|
2025-02-01 07:32:54 +01:00
|
|
|
float spawnPerc;
|
|
|
|
if (data.justOne)
|
|
|
|
{
|
2025-02-05 04:54:37 +01:00
|
|
|
if (!didOne)
|
2025-02-01 07:32:54 +01:00
|
|
|
spawnCount = data.justOne;
|
2025-02-05 04:54:37 +01:00
|
|
|
spawnPerc = 0; // Spawn all of them in the same spot
|
|
|
|
didOne = true;
|
2025-02-01 07:32:54 +01:00
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
float num = data.number.x * dt;
|
2025-02-05 04:54:37 +01:00
|
|
|
num += lastDTDifference;
|
2025-02-01 07:32:54 +01:00
|
|
|
spawnCount = int(num);
|
2025-02-05 04:54:37 +01:00
|
|
|
lastDTDifference = num - float(spawnCount);
|
2011-08-03 22:05:33 +02:00
|
|
|
if (spawnCount > 0)
|
2025-02-05 04:54:37 +01:00
|
|
|
spawnPerc = 1.0f / num;
|
2025-02-01 07:32:54 +01:00
|
|
|
}
|
2011-08-03 22:05:33 +02:00
|
|
|
|
2025-02-01 07:32:54 +01:00
|
|
|
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).
|
2025-02-05 04:54:37 +01:00
|
|
|
const Vector currentSpawn = getSpawnPosition();
|
2025-02-01 07:32:54 +01:00
|
|
|
|
2025-02-05 04:54:37 +01:00
|
|
|
// Given the last spawn position and the new spawn position, interpolate as many particles
|
|
|
|
// along the line between both positions. Start at current and move back to prev.
|
|
|
|
// For convenience, 0 is the current pos and 1 is the prev. pos.
|
|
|
|
float percAccu = 0;
|
|
|
|
for(int i = 0; i < spawnCount; ++i)
|
2025-02-01 07:32:54 +01:00
|
|
|
{
|
2025-02-05 04:54:37 +01:00
|
|
|
spawnParticle(lerp(currentSpawn, lastSpawn, percAccu));
|
|
|
|
// This is unlikely to reach 1 perfectly, which is good since what is currently 1
|
|
|
|
// was 0 in the previous iteration, and that is known to be hit perfectly.
|
|
|
|
// This way we usually don't end up placing 2 particles in the same spot.
|
|
|
|
percAccu += spawnPerc;
|
2011-08-03 22:05:33 +02:00
|
|
|
}
|
|
|
|
|
2025-02-01 07:32:54 +01:00
|
|
|
lastSpawn = currentSpawn;
|
2025-02-05 04:54:37 +01:00
|
|
|
|
2011-08-03 22:05:33 +02:00
|
|
|
}
|
2025-02-01 07:32:54 +01:00
|
|
|
|
|
|
|
data.number.update(dt);
|
2011-08-03 22:05:33 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
void Emitter::start()
|
|
|
|
{
|
2025-02-05 04:54:37 +01:00
|
|
|
didOne = false;
|
|
|
|
lastDTDifference = 0;
|
2011-08-03 22:05:33 +02:00
|
|
|
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);
|
2016-05-05 19:40:28 +02:00
|
|
|
|
2011-08-03 22:05:33 +02:00
|
|
|
}
|
|
|
|
|
2022-05-20 01:04:19 +02:00
|
|
|
void Emitter::onRender(const RenderState& rs) const
|
2011-08-03 22:05:33 +02:00
|
|
|
{
|
|
|
|
if (particles.empty()) return;
|
|
|
|
|
|
|
|
if (!data.spawnLocal)
|
|
|
|
{
|
|
|
|
glLoadIdentity();
|
2016-05-05 19:40:28 +02:00
|
|
|
|
2011-08-03 22:05:33 +02:00
|
|
|
core->setupRenderPositionAndScale();
|
|
|
|
}
|
|
|
|
|
|
|
|
if (texture)
|
|
|
|
texture->apply();
|
|
|
|
|
2025-02-05 05:30:46 +01:00
|
|
|
Vector colorMult = rs.color;
|
|
|
|
if(data.inheritColor)
|
|
|
|
colorMult *= pe->color;
|
|
|
|
float alphaMult = rs.alpha;
|
|
|
|
if(data.inheritAlpha)
|
|
|
|
alphaMult *= pe->alpha.x;
|
2011-08-03 22:05:33 +02:00
|
|
|
|
2025-02-05 05:30:46 +01:00
|
|
|
const RenderGrid * const rquad = core->getDefaultQuadGrid();
|
2023-10-20 03:53:29 +02:00
|
|
|
const bool flip = data.flipH != (data.copyParentFlip && pe->isfhr());
|
2011-08-03 22:05:33 +02:00
|
|
|
|
2025-02-05 05:30:46 +01:00
|
|
|
for (Particles::const_iterator i = particles.begin(); i != particles.end(); i++)
|
2011-08-03 22:05:33 +02:00
|
|
|
{
|
2025-02-05 05:30:46 +01:00
|
|
|
Particle *p = *i;
|
|
|
|
if (p->active)
|
2011-08-03 22:05:33 +02:00
|
|
|
{
|
2025-02-05 05:30:46 +01:00
|
|
|
const Vector col = p->color * colorMult;
|
|
|
|
glColor4f(col.x, col.y, col.z, p->alpha.x * alphaMult);
|
|
|
|
|
|
|
|
glPushMatrix();
|
2011-08-03 22:05:33 +02:00
|
|
|
|
2025-02-05 05:30:46 +01:00
|
|
|
glTranslatef(p->pos.x, p->pos.y,0);
|
|
|
|
glScalef(width * p->scale.x, height * p->scale.y, 0);
|
2016-05-05 19:40:28 +02:00
|
|
|
|
2025-02-05 05:30:46 +01:00
|
|
|
glRotatef(p->rot.z, 0, 0, 1);
|
2011-08-03 22:05:33 +02:00
|
|
|
|
2025-02-05 05:30:46 +01:00
|
|
|
if (flip)
|
|
|
|
glRotatef(180, 0, 1, 0);
|
2011-08-03 22:05:33 +02:00
|
|
|
|
2025-02-05 05:30:46 +01:00
|
|
|
rquad->render(rs);
|
2016-05-05 19:40:28 +02:00
|
|
|
|
2025-02-05 05:30:46 +01:00
|
|
|
glPopMatrix();
|
2011-08-03 22:05:33 +02:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|