/* render/particlesystem.cc This file is part of the Osirion project and is distributed under the terms of the GNU General Public License version 2 */ #include "render/gl.h" #include "render/particlesystem.h" namespace render { ParticleSystem::ParticleSystem(const ParticleSystemScript *script, const core::Entity *entity, const model::Particles *modelclass) { // constructor asserts that modelclass->parent == entity->model particlesystem_modelscale = 1.0f; particlesystem_entity = entity; if (modelclass) { particlesystem_location.assign(modelclass->location()); particlesystem_axis.assign(modelclass->axis()); } if (entity && entity->model() && entity->model()->radius()) { particlesystem_modelscale = entity->radius() / entity->model()->radius(); particlesystem_location *= particlesystem_modelscale; } // add ParticleEjectors as defined by the ParticleSystemScript for (ParticleSystemScript::Ejectors::const_iterator it = script->ejectors().begin(); it != script->ejectors().end(); ++it) { ParticleEjector *ejector = 0; switch ((*it)->type()) { case ParticleEjector::Sprite: ejector = new ParticleEjectorSprite(*(*it)); break; case ParticleEjector::Flare: ejector = new ParticleEjectorFlare(*(*it)); break; case ParticleEjector::Trail: ejector = new ParticleEjectorTrail(*(*it)); break; case ParticleEjector::Streak: ejector = new ParticleEjectorStreak(*(*it)); break; default: break; } if (ejector) { // safety values if (!ejector->interval()) { ejector->set_interval(1000); } ejectors().push_back(ejector); if (entity) { if (ejector->entity()) { if (ejector->entity_second()) { for (size_t i = 0; i < 3; i++) { ejector->get_color()[i] = (entity->color()[i] + entity->color_second()[i]) * 0.5f; } } else { ejector->set_color(entity->color()); } } else if (ejector->entity_second()) { ejector->set_color(entity->color_second()); } else if (ejector->engine()) { if (entity->model()) { ejector->set_color(entity->model()->enginecolor()); } } } if (modelclass) { // modelclass overrides script parameters if (modelclass->has_color()) { ejector->set_color(modelclass->color()); } if (entity) { if (modelclass->entity()) { if (modelclass->entity_second()) { for (size_t i = 0; i < 3; i++) { ejector->get_color()[i] = (entity->color()[i] + entity->color_second()[i]) * 0.5f; } } else { ejector->set_color(entity->color()); } } else if (modelclass->entity_second()) { ejector->set_color(entity->color_second()); } else if (modelclass->engine()) { if (entity->model()) { ejector->set_color(entity->model()->enginecolor()); } } } } if (entity && ejector->scaled()) { ejector->get_speed_vec() *= entity->radius(); ejector->get_tailspeed_vec() *= entity->radius(); ejector->get_radius_vec() *= entity->radius(); ejector->set_acceleration(ejector->acceleration() * entity->radius()); } if (modelclass && (modelclass->scale() != 1.0f)) { ejector->get_speed_vec() *= modelclass->scale(); ejector->get_tailspeed_vec() *= modelclass->scale(); ejector->get_radius_vec() *= modelclass->scale(); ejector->set_acceleration(ejector->acceleration() * modelclass->scale()); } } } } ParticleSystem::~ParticleSystem() { for (Ejectors::iterator it = ejectors().begin(); it != ejectors().end(); ++it) { delete (*it); (*it) = 0; } ejectors().clear(); } void ParticleSystem::clear() { for (Ejectors::iterator it = ejectors().begin(); it != ejectors().end(); ++it) { (*it)->clear(); } } void ParticleSystem::draw(const float seconds, const Camera &camera) { // clear particles for docked entities if ( entity() && (entity()->type() == core::Entity::Controlable)) { const core::EntityControlable *controlable = static_cast(entity()); if (controlable->state() == core::Entity::Docked) { clear(); return; } } math::Vector3f current_location(entity() ? entity()->location() + (entity()->axis() * location()) : location()); math::Axis current_axis(entity() ? entity()->axis() * axis() : axis()); for (Ejectors::iterator it = ejectors().begin(); it != ejectors().end(); ++it) { ParticleEjector *ejector = (*it); if (entity()) { float thrust_factor = 1.0f; bool ejector_active = true; if (ejector->thrust()) { thrust_factor = 0.0f; } if (ejector->impulse() || ejector->thrust() || ejector->explosion()) { ejector_active = false; } if (entity()->type() == core::Entity::Controlable) { const core::EntityControlable *controlable = static_cast(entity()); switch (controlable->state()) { case core::Entity::Impulse: case core::Entity::ImpulseInitiate: if (ejector->impulse()) { ejector_active = true; thrust_factor = 1.0f; } break; case core::Entity::Normal: if (ejector->thrust()) { if (controlable->thrust() > 0.0f) { ejector_active = true; thrust_factor = 0.25f + controlable->thrust() * 0.75f; } } break; case core::Entity::Destroyed: if (ejector->explosion()) { ejector_active = true; } break; case core::Entity::NoPower: ejector_active = false; break; default: break; } } else if (entity()->type() == core::Entity::Dynamic) { const core::EntityDynamic *dynamic = static_cast(entity()); if (dynamic->state() == core::Entity::NoPower) { ejector_active = false; } switch (dynamic->state()) { case core::Entity::Impulse: case core::Entity::ImpulseInitiate: case core::Entity::Normal: break; case core::Entity::Destroyed: if (ejector->explosion()) { ejector_active = true; } break; case core::Entity::NoPower: ejector_active = false; break; default: break; } } ejector->enable(ejector_active); (*it)->frame(seconds, camera, current_location, current_axis * ejector->axis(), thrust_factor); } } } }