diff options
author | Stijn Buys <ingar@osirion.org> | 2008-11-23 22:13:40 +0000 |
---|---|---|
committer | Stijn Buys <ingar@osirion.org> | 2008-11-23 22:13:40 +0000 |
commit | 2e93e755a4f4631419ba0eee26660a5638a7a7c6 (patch) | |
tree | 38e0e0327c16cecaab0600493d4c6bb78b70caf3 /src/render/particles.cc | |
parent | d01664f17503d52d4be1c31e099065da0d38d7f3 (diff) |
particle systems
Diffstat (limited to 'src/render/particles.cc')
-rw-r--r-- | src/render/particles.cc | 374 |
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 |