Project::OSiRiON - Git repositories
Project::OSiRiON
News . About . Screenshots . Downloads . Forum . Wiki . Tracker . Git
summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorStijn Buys <ingar@osirion.org>2013-01-20 21:37:11 +0000
committerStijn Buys <ingar@osirion.org>2013-01-20 21:37:11 +0000
commitd4f9da2f3c19511b028da2569d7b6a8d1371e135 (patch)
treee1bba0d8dd3b15169612f865612d3fca6475639a /src/render/particleejector.cc
parent4feff2411d1b703a3b93d8a342112bd998b1ffed (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.cc251
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
+