diff options
author | Stijn Buys <ingar@osirion.org> | 2013-01-20 21:37:11 +0000 |
---|---|---|
committer | Stijn Buys <ingar@osirion.org> | 2013-01-20 21:37:11 +0000 |
commit | d4f9da2f3c19511b028da2569d7b6a8d1371e135 (patch) | |
tree | e1bba0d8dd3b15169612f865612d3fca6475639a /src/render/particleejector.cc | |
parent | 4feff2411d1b703a3b93d8a342112bd998b1ffed (diff) |
Major overhaul of the particle system back-end, support multiple ejectors per particle system.
Diffstat (limited to 'src/render/particleejector.cc')
-rw-r--r-- | src/render/particleejector.cc | 251 |
1 files changed, 251 insertions, 0 deletions
diff --git a/src/render/particleejector.cc b/src/render/particleejector.cc new file mode 100644 index 0000000..5b26d59 --- /dev/null +++ b/src/render/particleejector.cc @@ -0,0 +1,251 @@ +/* + render/particleejector.cc + This file is part of the Osirion project and is distributed under + the terms of the GNU General Public License version 2 +*/ + +#include "core/application.h" +#include "render/particleejector.h" +#include "render/camera.h" +#include "render/gl.h" +#include "render/textures.h" +#include "render/draw.h" + +namespace render { + +/* ---- class ParticleEjector -------------------------------------- */ + +ParticleEjector::ParticleEjector(const ParticleEjectorScript &script) : ParticleEjectorScript(script) +{ + ejector_last_eject = 0; + ejector_enabled = true; +} + +ParticleEjector::~ParticleEjector() +{ + clear(); +} + +void ParticleEjector::clear() +{ + for (Particles::iterator it = particles().begin(); it != particles().end(); ++it) { + delete (*it); + (*it) = 0; + } + ejector_last_eject = 0; +} + +void ParticleEjector::frame(const float seconds, const math::Vector3f & ps_location, const math::Axis & ps_axis) +{ + unsigned long now = core::application()->timestamp(); + + // remove dead particles + Particles::reverse_iterator it = particles().rbegin(); + while ((it != particles().rend()) && ((*it)->timestamp() + lifespan() <= now)) { + delete(*particles().rbegin()); + particles().pop_back(); + it = particles().rbegin(); + } + + // add new particles + if ( (ejector_enabled) && (ejector_last_eject + interval() <= now) ) + { + math::Vector3f particle_location(ps_location); + math::Axis particle_axis(ps_axis * axis()); + + if (cone() > 0) { + particle_axis.change_roll(math::randomf(360.0f)); + particle_axis.change_pitch(math::randomf(cone()) - (cone() * 0.5f) ); + } + if (spawn_radius() > 0) { + // FIXME find a faster formula + math::Axis random_axis(ps_axis); + random_axis.change_roll(math::randomf(360.0f)); + random_axis.change_pitch(math::randomf(180.0f)); + particle_location += random_axis.forward() * spawn_radius(); + } + + Particle *particle = new Particle(particle_location, particle_axis.forward() * speed(), now); + particle->set_radius(radius_vec()[0]); + particle->set_alpha(alpha_vec()[0]); + + particles().push_front(particle); + ejector_last_eject = now; + } + + for (Particles::iterator it = particles().begin(); it != particles().end(); ++it) { + Particle *particle = (*it); + if (particle->timestamp() < now) { + // apply velocity + particle->get_location() += (particle->velocity() * seconds); + + // set particle radius_vec and alpha_vec + const float age = (float) (now - particle->timestamp()); + const float halflife = offset() * (float) lifespan(); + + if (age < halflife) { + const float t = age / halflife; + + particle->set_radius((1.0f - t) * radius_vec()[0] + t * radius_vec()[1]); + particle->set_alpha((1.0f - t) * alpha_vec()[0] + t * alpha_vec()[1]); + } else { + const float t = (age - halflife) / ((float) lifespan() - halflife); + + particle->set_radius((1.0f - t) * radius_vec()[1] + t * radius_vec()[2]); + particle->set_alpha((1.0f - t) * alpha_vec()[1] + t * alpha_vec()[2]); + } + + } + } + + switch(cull()) { + case model::CullNone: + gl::disable(GL_CULL_FACE); + break; + + case model::CullBack: + gl::enable(GL_CULL_FACE); + gl::cullface(GL_BACK); + break; + + case model::CullFront: + gl::enable(GL_CULL_FACE); + gl::cullface(GL_FRONT); + break; + } + + if (particles().size()) { + draw(ps_location); + } +} + +void ParticleEjector::draw(const math::Vector3f & ps_location) +{ + +} + +/* ---- class ParticleEjectorSpray --------------------------------- */ + +ParticleEjectorSpray::ParticleEjectorSpray(const ParticleEjectorScript &script) : ParticleEjector(script) +{ + +} + +ParticleEjectorSpray::~ParticleEjectorSpray() +{ + +} + +void ParticleEjectorSpray::draw(const math::Vector3f & ps_location) +{ + math::Vector3f quad[4]; + Textures::bind(texture()); + gl::begin(gl::Quads); + + quad[0].assign((Camera::axis().up() - Camera::axis().left())); + quad[1].assign((Camera::axis().up() + Camera::axis().left())); + quad[2].assign((Camera::axis().up() * -1 + Camera::axis().left())); + quad[3].assign((Camera::axis().up() * -1 - Camera::axis().left())); + + math::Color c(color()); + + for (Particles::iterator it = particles().begin(); it != particles().end(); it++) { + Particle *particle = (*it); + + const float r = particle->radius(); + + c.a = particle->alpha(); + gl::color(c); + + glTexCoord2f(0, 1); + gl::vertex(particle->location() + quad[0] * r); + glTexCoord2f(0, 0); + gl::vertex(particle->location() + quad[1] * r); + glTexCoord2f(1, 0); + gl::vertex(particle->location() + quad[2] * r); + glTexCoord2f(1, 1); + gl::vertex(particle->location() + quad[3] * r); + Stats::quads++; + } + gl::end(); +} + +/* ---- class ParticleEjectorTrail --------------------------------- */ + +ParticleEjectorTrail::ParticleEjectorTrail(const ParticleEjectorScript &script) : ParticleEjector(script) +{ + +} + +ParticleEjectorTrail::~ParticleEjectorTrail() +{ + +} + +void ParticleEjectorTrail::draw(const math::Vector3f & ps_location) +{ + if (!particles().size()) { + return; + } + + (*particles().rbegin())->set_alpha(0.0f); + + Particles::iterator first = particles().begin(); + Particles::iterator next = first; + ++next; + + Textures::bind(texture()); + gl::begin(gl::Quads); + + math::Color c(color()); + c.a = (*first)->alpha(); + gl::color(c); + + math::Vector3f first_normal(math::crossproduct(((*first)->location() - ps_location), ((*first)->location() - Camera::eye()))); + first_normal.normalize(); + + math::Vector3f next_normal(first_normal); + + glTexCoord2f(1, 0); + gl::vertex(ps_location - first_normal * (*first)->radius()); + glTexCoord2f(0, 0); + gl::vertex(ps_location + first_normal * (*first)->radius()); + + glTexCoord2f(0, 1); + gl::vertex((*first)->location() + next_normal * (*first)->radius()); + glTexCoord2f(1, 1); + gl::vertex((*first)->location() - next_normal * (*first)->radius()); + Stats::quads++; + + while (next != particles().end()) { + next_normal.assign(math::crossproduct(((*next)->location() - (*first)->location()), ((*next)->location() - Camera::eye()))); + next_normal.normalize(); + + c.a = (*first)->alpha(); + gl::color(c); + + glTexCoord2f(1, 0); + gl::vertex((*first)->location() - first_normal * (*first)->radius()); + glTexCoord2f(0, 0); + gl::vertex((*first)->location() + first_normal * (*first)->radius()); + + c.a = (*next)->alpha(); + gl::color(c); + + glTexCoord2f(0, 1); + gl::vertex((*next)->location() + next_normal * (*next)->radius()); + glTexCoord2f(1, 1); + gl::vertex((*next)->location() - next_normal * (*next)->radius()); + + Stats::quads++; + + first_normal = next_normal; + first = next; + ++next; + } + + gl::end(); +} + +} // namespace render + |