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>2008-11-23 22:13:40 +0000
committerStijn Buys <ingar@osirion.org>2008-11-23 22:13:40 +0000
commit2e93e755a4f4631419ba0eee26660a5638a7a7c6 (patch)
tree38e0e0327c16cecaab0600493d4c6bb78b70caf3 /src/render/particles.cc
parentd01664f17503d52d4be1c31e099065da0d38d7f3 (diff)
particle systems
Diffstat (limited to 'src/render/particles.cc')
-rw-r--r--src/render/particles.cc374
1 files changed, 308 insertions, 66 deletions
diff --git a/src/render/particles.cc b/src/render/particles.cc
index 94a3a07..638b8b3 100644
--- a/src/render/particles.cc
+++ b/src/render/particles.cc
@@ -4,13 +4,14 @@
the terms of the GNU General Public License version 2
*/
+#include "auxiliary/functions.h"
#include "render/particles.h"
#include "render/camera.h"
#include "render/gl.h"
#include "render/draw.h"
#include "render/textures.h"
-
#include "core/application.h"
+
namespace render {
/* ---- class Particle --------------------------------------------- */
@@ -20,111 +21,261 @@ Particle::Particle(const math::Vector3f &location, float time) : particle_locati
particle_time = time;
}
-Particle::Particle(const math::Vector3f &location, const math::Vector3f &up, const math::Vector3f &left, float time) : particle_location(location), particle_up(up), particle_left(left)
+Particle::Particle(const math::Vector3f &location, const math::Axis &axis, float time) : particle_location(location), particle_axis(axis)
{
particle_time = time;
}
-/* ---- class ParticleStream --------------------------------------- */
-ParticleStream::ParticleStream(const math::Vector3f &location, const math::Color &color, float radius, size_t texture, core::EntityControlable *entity, bool oriented) : particles_location(location), particles_color(color)
+/* ---- static ParticleScript registry ---------------------------------- */
+
+ParticleScript::Registry ParticleScript::particles_registry;
+
+void ParticleScript::clear()
{
- particles_texture = texture;
- particles_entity = entity;
- if (!entity) {
- particles_oriented = false;
- } else {
- particles_oriented = oriented;
+ for (Registry::iterator it = particles_registry.begin(); it != particles_registry.end(); it++) {
+ delete (*it).second;
+ (*it).second = 0;
}
+ particles_registry.clear();
+}
- particles_radius = radius;
+ParticleScript *ParticleScript::find(const std::string &label)
+{
+ Registry::iterator it = particles_registry.find(label);
- particles_timeout = 1.5f; // a particles lives for 3 seconds
- particles_eject = 0.02f; // a particle is ejected every 0.2 seconds
+ if (it != particles_registry.end()) {
+ return (*it).second;
+ } else {
+ return 0;
+ }
+}
+
+void ParticleScript::init()
+{
+ clear();
- particles_last_eject = 0; // timestamp of the last eject
+ ParticleScript *script = 0;
+
+ filesystem::IniFile inifile;
+ inifile.open("particles");
+
+ if (!inifile.is_open()) {
+ con_error << "Could not open " << inifile.name() << std::endl;
+ return;
+ }
+
+ con_print << "^BLoading particle systems..." << std::endl;
+
+ std::string strval;
+
+ while (inifile.getline()) {
+
+ if (inifile.got_section()) {
+ if (inifile.got_section("particles")) {
+ if (script) {
+ if (script->label().size()) {
+ if (find(script->label())) {
+ con_warn << "Duplicate particle system '" << script->label() << "'" << std::endl;
+ delete script;
+ } else {
+ particles_registry[script->label()] = script;
+ }
+ } else {
+ con_warn << "Particle system without label" << std::endl;
+ delete script;
+ }
+ }
+ script = new ParticleScript();
+ }
+
+ } else if (inifile.got_key()) {
+
+ if (inifile.in_section("particles")) {
+
+ if (inifile.got_key_string("label", script->particles_label)) {
+ continue;
+ } else if (inifile.got_key_string("type", strval)) {
+ aux::to_label(strval);
+ if (strval.compare("flame") == 0) {
+ script->particles_type = ParticleScript::Flame;
+ } else if (strval.compare("jet") == 0) {
+ script->particles_type = ParticleScript::Jet;
+ } else if (strval.compare("trail") == 0) {
+ script->particles_type = ParticleScript::Trail;
+ } else {
+ inifile.unknown_value();
+ }
+ continue;
+ } else if (inifile.got_key_string("texture", script->particles_texture)) {
+ Textures::load("textures/" + script->texture());
+ continue;
+ } else if (inifile.got_key_float("speed", script->particles_speed)) {
+ continue;
+ } else if (inifile.got_key_float("alpha", script->particles_alpha)) {
+ continue;
+ } else if (inifile.got_key_float("radius", script->particles_radius)) {
+ script->particles_radius *= model::SCALE;
+ continue;
+ } else if (inifile.got_key_float("eject", script->particles_eject)) {
+ continue;
+ } else if (inifile.got_key_float("timeout", script->particles_timeout)) {
+ continue;
+ } else if (inifile.got_key_color("color", script->particles_color)) {
+ continue;
+ } else {
+ inifile.unkown_key();
+ }
+ }
+ }
+ }
+ inifile.close();
+
+ if (script) {
+ if (script->label().size()) {
+ if (find(script->label())) {
+ con_warn << "Duplicate particle system '" << script->label() << "'" << std::endl;
+ delete script;
+ } else {
+ particles_registry[script->label()] = script;
+ }
+ } else {
+ con_warn << "Particle system without label" << std::endl;
+ delete script;
+ }
+ }
+
+ con_debug << " " << inifile.name() << " " << particles_registry.size() << " " << aux::plural("particle system", particles_registry.size()) << std::endl;
+}
+
+/* ---- class ParticleScript --------------------------------------- */
+
+ParticleScript::ParticleScript()
+{
+ particles_radius = 1.0f;
+ particles_alpha = 1.0f;
+
+ particles_speed = 0.0f;
+ particles_timeout = 2.0f;
+ particles_eject = 0.25f;
+
+ particles_color.assign(1.0f, 1.0f);
+}
+
+ParticleScript::~ParticleScript()
+{
+}
+
+/* ---- class ParticleSystem --------------------------------------- */
+
+ParticleSystem::ParticleSystem(ParticleScript *script, core::Entity *entity, const math::Vector3f &location) :
+ particlesystem_location(location)
+{
+ particlesystem_entity = entity;
+ particlesystem_last_eject = 0; // timestamp of the last eject
+
+ particlesystem_script = script;
+ particlesystem_texture = 0;
+
+ if (particlesystem_script) {
+ particlesystem_texture = Textures::load("textures/" + particlesystem_script->texture());
+ color.assign(particlesystem_script->color());
+ }
}
-ParticleStream::~ParticleStream()
+ParticleSystem::~ParticleSystem()
{
- for (Particles::iterator it = particles_stream.begin(); it != particles_stream.end(); it++) {
+ for (Stream::iterator it = particlesystem_stream.begin(); it != particlesystem_stream.end(); it++) {
delete (*it);
}
- particles_stream.clear();
+ particlesystem_stream.clear();
}
-void ParticleStream::draw() {
- float now = core::application()->time();
+void ParticleSystem::draw(float elapsed)
+{
+ now = core::application()->time();
+ ejector_location.assign(particlesystem_entity->location() + (particlesystem_entity->axis() * location()));
// remove dead particles
- Particles::iterator it = particles_stream.begin();
- while ((it != particles_stream.end()) && ((*it)->time() + particles_timeout <= now)) {
+ Stream::iterator it = particlesystem_stream.begin();
+ while ((it != particlesystem_stream.end()) && ((*it)->time() + particlesystem_script->timeout() <= now)) {
delete (*it);
- particles_stream.erase(it);
- it = particles_stream.begin();
+ particlesystem_stream.erase(it);
+ it = particlesystem_stream.begin();
}
- // add new particles
- if (particles_last_eject + particles_eject <= now) {
- if (particles_entity) {
- float u = 0;
- if ((particles_entity->eventstate() == core::Entity::ImpulseInitiate ) || (particles_entity->eventstate() == core::Entity::Impulse)) {
- u = 1.0f;
- } else if(particles_entity->eventstate() == core::Entity::Normal) {
- u = particles_entity->thrust();
+ // apply speed
+ bool ejector_active = false;
+ if (particlesystem_script->speed()) {
+ for (Stream::reverse_iterator rit = particlesystem_stream.rbegin(); rit != particlesystem_stream.rend(); rit++) {
+ Particle *particle = (*rit);
+ particle->location() += particle->axis().forward() * particlesystem_script->speed() * elapsed;
+ }
+ } else {
+ if (particlesystem_entity->type() == core::Entity::Dynamic) {
+ core::EntityDynamic *ed = static_cast<core::EntityDynamic *>(particlesystem_entity);
+ if (ed->speed()) {
+ ejector_active = true;
}
- if (u > 0.0f) {
- math::Vector3f l(particles_entity->location() + (particles_entity->axis() * location()));
- Particle *p = 0;
- if (particles_oriented) {
- p = new Particle(l, particles_entity->axis().up(), particles_entity->axis().left(), now);
- } else {
- p = new Particle(l, now);
- }
- particles_stream.push_back(p);
+ } else if (particlesystem_entity->type() == core::Entity::Controlable) {
+ core::EntityControlable *ec = static_cast<core::EntityControlable *>(particlesystem_entity);
+ if ((ec->thrust() > 0.0f) || (ec->eventstate() == core::Entity::ImpulseInitiate) || (ec->eventstate() == core::Entity::Impulse)) {
+ ejector_active = true;
}
- } else {
- particles_stream.push_back(new Particle(location(), now));
}
- particles_last_eject = now;
}
+ // add new particles
+ if (ejector_active && (particlesystem_last_eject + particlesystem_script->eject() <= now)) {
+ particlesystem_stream.push_back(new Particle(ejector_location, particlesystem_entity->axis() * particlesystem_axis, now));
+ particlesystem_last_eject = now;
+ }
+}
+
+/* ---- class Jet -------------------------------------------------- */
+
+Jet::Jet(ParticleScript *script, core::Entity *entity, const math::Vector3f &location) :
+ ParticleSystem(script, entity, location) {
+}
+
+Jet::~Jet()
+{}
+
+void Jet::draw(float elapsed) {
+ if (!particlesystem_script)
+ return;
+
+ ParticleSystem::draw(elapsed);
+
math::Vector3f quad[4];
- if (particles_stream.size()) {
- Textures::bind(particles_texture);
+ if (particlesystem_stream.size()) {
+ Textures::bind(particlesystem_texture);
gl::begin(gl::Quads);
- for (Particles::reverse_iterator rit = particles_stream.rbegin(); rit != particles_stream.rend(); rit++) {
+ for (Stream::reverse_iterator rit = particlesystem_stream.rbegin(); rit != particlesystem_stream.rend(); rit++) {
Particle *particle = (*rit);
-
- if (particles_oriented) {
- quad[0].assign(particle->up() - particle->left());
- quad[1].assign(particle->up() + particle->left());
- quad[2].assign(particle->up() * -1 + particle->left());
- quad[3].assign(particle->up() * -1 - particle->left());
- } else {
- 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());
- }
-
+
+ quad[0].assign(particle->axis().up() - particle->axis().left());
+ quad[1].assign(particle->axis().up() + particle->axis().left());
+ quad[2].assign(particle->axis().up() * -1 + particle->axis().left());
+ quad[3].assign(particle->axis().up() * -1 - particle->axis().left());
+
float t = now - particle->time();
float f = 0;
- if (t < particles_timeout * 0.1f) {
- f = t / (0.1f * particles_timeout);
+ if (t < particlesystem_script->timeout() * 0.1f) {
+ f = t / (0.1f * particlesystem_script->timeout());
} else {
- t = t - particles_timeout * 0.1f;
- f = t / (0.9f * particles_timeout);
+ t = t - particlesystem_script->timeout() * 0.1f;
+ f = t / (0.9f * particlesystem_script->timeout());
f = 1.0 - f;
}
f *= f;
- float radius = particles_radius * f;
- particles_color.a = f;
- gl::color(particles_color);
+ float radius = particlesystem_script->radius() * f;
+ color.a = f * particlesystem_script->alpha();
+ gl::color(color);
glTexCoord2f(0,1);
gl::vertex(particle->location() + quad[0] * radius);
@@ -141,4 +292,95 @@ void ParticleStream::draw() {
}
}
+/* ---- class Trail ------------------------------------------------ */
+
+Trail::Trail(ParticleScript *script, core::Entity *entity, const math::Vector3f &location) :
+ ParticleSystem(script, entity, location) {
+}
+
+Trail::~Trail()
+{}
+
+void Trail::draw(float elapsed) {
+
+ if (!particlesystem_script)
+ return;
+
+ ParticleSystem::draw(elapsed);
+
+ if (particlesystem_stream.size() > 1) {
+ Textures::bind(particlesystem_texture);
+
+ gl::begin(gl::Quads);
+
+ Stream::reverse_iterator previous = particlesystem_stream.rbegin();
+
+ float tp = now - (*previous)->time();
+ float fp = 0;
+
+ if (tp < particlesystem_script->timeout() * 0.1f) {
+ fp = tp / (0.1f * particlesystem_script->timeout());
+ } else {
+ tp = tp - particlesystem_script->timeout() * 0.1f;
+ fp = tp / (0.9f * particlesystem_script->timeout());
+ fp = 1.0 - fp;
+ }
+
+ Stream::reverse_iterator next = previous;
+ for (next++; next != particlesystem_stream.rend(); next++) {
+
+ float t = now - (*next)->time();
+ float f = 0;
+
+ if (t < particlesystem_script->timeout() * 0.1f) {
+ f = t / (0.1f * particlesystem_script->timeout());
+ } else {
+ t = t - particlesystem_script->timeout() * 0.1f;
+ f = t / (0.9f * particlesystem_script->timeout());
+ f = 1.0 - f;
+ }
+
+ color.a = f * particlesystem_script->alpha();
+ gl::color(color);
+
+ glTexCoord2f(1,0);
+ gl::vertex((*next)->location() - (*next)->axis().left() * particlesystem_script->radius() * f);
+ glTexCoord2f(0,0);
+ gl::vertex((*next)->location() + (*next)->axis().left() * particlesystem_script->radius() * f);
+
+ color.a = fp * particlesystem_script->alpha();
+ gl::color(color);
+
+ glTexCoord2f(0,1);
+ gl::vertex((*previous)->location() + (*previous)->axis().left() * particlesystem_script->radius() * fp);
+ glTexCoord2f(1,1);
+ gl::vertex((*previous)->location() - (*previous)->axis().left() * particlesystem_script->radius() * fp);
+ Stats::quads++;
+
+ previous = next;
+ fp = f;
+ tp = t;
+ }
+
+ color.a = 0.0f;
+ gl::color(color);
+
+ glTexCoord2f(1,0);
+ gl::vertex(ejector_location);
+ glTexCoord2f(0,0);
+ gl::vertex(ejector_location);
+
+ color.a = fp;
+ gl::color(color);
+
+ glTexCoord2f(0,1);
+ gl::vertex((*previous)->location() + (*previous)->axis().left() * particlesystem_script->radius() * fp);
+ glTexCoord2f(1,1);
+ gl::vertex((*previous)->location() - (*previous)->axis().left() * particlesystem_script->radius() * fp);
+ Stats::quads++;
+
+ gl::end();
+ }
+}
+
} // namespace render