From 315a8c2dff9b76ac5e1ebbef265f13ac19d65e3d Mon Sep 17 00:00:00 2001 From: Stijn Buys Date: Sun, 16 Nov 2008 13:53:44 +0000 Subject: engine trails --- src/render/Makefile.am | 9 +-- src/render/draw.cc | 114 +++++++++++++++++++++++++------------- src/render/particles.cc | 144 ++++++++++++++++++++++++++++++++++++++++++++++++ src/render/particles.h | 73 ++++++++++++++++++++++++ src/render/renderext.cc | 32 ++++++++--- src/render/renderext.h | 20 ++++--- src/render/tgafile.cc | 2 +- 7 files changed, 334 insertions(+), 60 deletions(-) create mode 100644 src/render/particles.cc create mode 100644 src/render/particles.h (limited to 'src/render') diff --git a/src/render/Makefile.am b/src/render/Makefile.am index 4054490..9fd8f50 100644 --- a/src/render/Makefile.am +++ b/src/render/Makefile.am @@ -10,7 +10,8 @@ endif librender_la_LDFLAGS = -avoid-version -no-undefined @GL_LIBS@ librender_la_LIBADD = $(top_builddir)/src/math/libmath.la librender_la_SOURCES = camera.cc draw.cc dust.cc gl.cc image.cc jpgfile.cc \ - pngfile.cc render.cc renderext.cc screenshot.cc state.cc text.cc textures.cc \ - tgafile.cc -noinst_HEADERS = camera.h draw.h dust.h gl.h image.h jpgfile.h pngfile.h \ - render.h renderext.h screenshot.h state.h text.h textures.h tgafile.h + particles.cc pngfile.cc render.cc renderext.cc screenshot.cc state.cc text.cc \ + textures.cc tgafile.cc +noinst_HEADERS = camera.h draw.h dust.h gl.h image.h jpgfile.h particles.h \ + pngfile.h render.h renderext.h screenshot.h state.h text.h \ + textures.h tgafile.h diff --git a/src/render/draw.cc b/src/render/draw.cc index 4f58f3d..a700d14 100644 --- a/src/render/draw.cc +++ b/src/render/draw.cc @@ -225,8 +225,19 @@ void draw_globe(core::EntityGlobe *globe) glLightfv(GL_LIGHT1, GL_POSITION, fake_light); } } + gl::push(); gl::translate(location); + gl::multmatrix(globe->axis()); + + if (globe->rotationspeed()) { + float angle = math::degrees360f(core::application()->time() * globe->rotationspeed()); + gl::rotate(angle, math::Vector3f::Zaxis()); + } + + draw_sphere(globe->color(), radius); + gl::pop(); + if(flag_is_set(globe->flags(), core::Entity::Bright)) { @@ -234,19 +245,16 @@ void draw_globe(core::EntityGlobe *globe) v.normalize(); float a = dotproduct(v, Camera::axis().forward()); if (a > 0.1f) { - // FIXME a corona is actually just a giant flare + // FIXME a corona is actually just a giant flare if (!globe->render_texture) { gl::enable(GL_TEXTURE_2D); } Textures::bind("bitmaps/fx/corona"); - + /* if (ext_render(globe)->distance() <= farplane) { gl::depthmask(GL_FALSE); - } - - //glDisableClientState(GL_VERTEX_ARRAY); - //glDisableClientState(GL_TEXTURE_COORD_ARRAY); - //glDisableClientState(GL_NORMAL_ARRAY); + }*/ + gl::disable(GL_DEPTH_TEST); math::Color color(globe->color()); color.a = a - 0.1f; @@ -256,42 +264,30 @@ void draw_globe(core::EntityGlobe *globe) gl::begin(gl::Quads); glTexCoord2f(0,1); - gl::vertex((Camera::axis().up() - Camera::axis().left()) * radius * 4.0f); + gl::vertex(location+ (Camera::axis().up() - Camera::axis().left()) * radius * 4.0f); glTexCoord2f(0,0); - gl::vertex((Camera::axis().up() + Camera::axis().left()) * radius * 4.0f); + gl::vertex(location+ (Camera::axis().up() + Camera::axis().left()) * radius * 4.0f); glTexCoord2f(1,0); - gl::vertex((Camera::axis().up() * -1 + Camera::axis().left()) * radius * 4.0f); + gl::vertex(location+ (Camera::axis().up() * -1 + Camera::axis().left()) * radius * 4.0f); glTexCoord2f(1,1); - gl::vertex((Camera::axis().up() * -1 - Camera::axis().left()) * radius * 4.0f); + gl::vertex(location+ (Camera::axis().up() * -1 - Camera::axis().left()) * radius * 4.0f); gl::end(); Stats::quads++; - - //glEnableClientState(GL_VERTEX_ARRAY); - //glEnableClientState(GL_TEXTURE_COORD_ARRAY); - //glEnableClientState(GL_NORMAL_ARRAY); gl::disable(GL_BLEND); + /* if (ext_render(globe)->distance() <= farplane) { gl::depthmask(GL_TRUE); - } + }*/ if (!globe->render_texture) { gl::disable(GL_TEXTURE_2D); } - } - } - - gl::multmatrix(globe->axis()); - - if (globe->rotationspeed()) { - float angle = math::degrees360f(core::application()->time() * globe->rotationspeed()); - gl::rotate(angle, math::Vector3f::Zaxis()); + gl::enable(GL_DEPTH_TEST); + } } - draw_sphere(globe->color(), radius); - - gl::pop(); if (ext_render(globe)->distance() > farplane) { @@ -713,28 +709,29 @@ void draw_pass_model_fragments() void draw_pass_model_fx(float elapsed) { - const size_t count = 8; // number of engine trail particles + //const size_t count = 8; // number of engine trail particles float t = 0.0f; - float u = 0.0f; + //float u = 0.0f; float a = 0.0f; float light_size = 0.0f; - float engine_size = 0.0f; - float trail_size = 0.0f; + //float engine_size = 0.0f; + //float trail_size = 0.0f; bool power = true; + float thrust; - math::Vector3f quad[4]; + //math::Vector3f quad[4]; math::Vector3f location; math::Vector3f offset; math::Color color; model::Light *light; model::Flare *flare; - model::Engine *engine; + //model::Engine *engine; math::Axis flare_axis; - size_t circle_texture = Textures::load("bitmaps/fx/circle01"); + //size_t circle_texture = Textures::load("bitmaps/fx/circle01"); size_t current_texture = Textures::bind("bitmaps/fx/flare00"); gl::enable(GL_TEXTURE_2D); @@ -744,6 +741,7 @@ void draw_pass_model_fx(float elapsed) core::Entity *entity = (*it); power = true; + if ((entity->type() == core::Entity::Dynamic) && (static_cast(entity)->eventstate() == core::Entity::NoPower)) { power = false; @@ -794,13 +792,24 @@ void draw_pass_model_fx(float elapsed) // draw flares for (model::Model::Flares::iterator flit = entity->model()->flares().begin(); flit != entity->model()->flares().end(); flit++) { flare = (*flit); - + + // engine flares + thrust = 1.0f; + if (flare->engine() && ( entity->type() == core::Entity::Controlable)) { + core::EntityControlable *ec = static_cast(entity); + if ((ec->eventstate() == core::Entity::ImpulseInitiate) || (ec->eventstate() == core::Entity::Impulse)) { + thrust = 1.0f; + } else { + thrust = ec->thrust(); + } + } + // strobe frequency t = 1.0f; if (flare->strobe()) t = (core::application()->time() + ext_render(entity)->fuzz() - flare->offset()) * flare->frequency(); - if ((!flare->strobe()) || (( t - floorf(t)) <= flare->time())) { + if ((thrust > 0 ) && ((!flare->strobe()) || (( t - floorf(t)) <= flare->time()))) { flare_axis.assign(entity->axis()); if (flare->angle()) flare_axis.change_direction(flare->angle()); @@ -819,10 +828,19 @@ void draw_pass_model_fx(float elapsed) } else { color.assign(flare->color()); } - + a = dotproduct(flare_axis.forward(), Camera::axis().forward()); if (a < -0.1f) { - color.a = -a - 0.1f; + a = -a - 0.1f; + if (flare->entity()) { + color.assign(entity->color()); + } else if (flare->engine()) { + color.assign(entity->model()->enginecolor()); + a *= thrust; + } else { + color.assign(flare->color()); + } + color.a = a; gl::color(color); glTexCoord2f(0,1); @@ -840,6 +858,7 @@ void draw_pass_model_fx(float elapsed) } } +/* // draw model engines for Controlable entities if ((entity->type() == core::Entity::Controlable) && entity->model()->engines().size()) { core::EntityControlable *ec = static_cast(entity); @@ -936,10 +955,27 @@ void draw_pass_model_fx(float elapsed) } } } - } + */ + + // draw particles + if (ext_render(entity)->particles().size()) { + gl::end(); + gl::disable(GL_CULL_FACE); + + for (RenderExt::Particles::iterator it = ext_render(entity)->particles().begin(); it != ext_render(entity)->particles().end(); it++) { + ParticleStream *particles = (*it); + particles->draw(); + } + + gl::enable(GL_CULL_FACE); + current_texture = Textures::bind("bitmaps/fx/flare00"); + gl::begin(gl::Quads); + } + } } gl::end(); + gl::disable(GL_TEXTURE_2D); } diff --git a/src/render/particles.cc b/src/render/particles.cc new file mode 100644 index 0000000..94a3a07 --- /dev/null +++ b/src/render/particles.cc @@ -0,0 +1,144 @@ +/* + render/particles.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/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 --------------------------------------------- */ + +Particle::Particle(const math::Vector3f &location, float time) : particle_location(location) +{ + 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_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) +{ + particles_texture = texture; + particles_entity = entity; + if (!entity) { + particles_oriented = false; + } else { + particles_oriented = oriented; + } + + particles_radius = radius; + + particles_timeout = 1.5f; // a particles lives for 3 seconds + particles_eject = 0.02f; // a particle is ejected every 0.2 seconds + + particles_last_eject = 0; // timestamp of the last eject +} + +ParticleStream::~ParticleStream() +{ + for (Particles::iterator it = particles_stream.begin(); it != particles_stream.end(); it++) { + delete (*it); + } + particles_stream.clear(); +} + +void ParticleStream::draw() { + float now = core::application()->time(); + + // remove dead particles + Particles::iterator it = particles_stream.begin(); + while ((it != particles_stream.end()) && ((*it)->time() + particles_timeout <= now)) { + delete (*it); + particles_stream.erase(it); + it = particles_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(); + } + 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 { + particles_stream.push_back(new Particle(location(), now)); + } + particles_last_eject = now; + } + + math::Vector3f quad[4]; + + if (particles_stream.size()) { + Textures::bind(particles_texture); + gl::begin(gl::Quads); + + for (Particles::reverse_iterator rit = particles_stream.rbegin(); rit != particles_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()); + } + + float t = now - particle->time(); + float f = 0; + + if (t < particles_timeout * 0.1f) { + f = t / (0.1f * particles_timeout); + } else { + t = t - particles_timeout * 0.1f; + f = t / (0.9f * particles_timeout); + f = 1.0 - f; + } + + f *= f; + float radius = particles_radius * f; + particles_color.a = f; + gl::color(particles_color); + + glTexCoord2f(0,1); + gl::vertex(particle->location() + quad[0] * radius); + glTexCoord2f(0,0); + gl::vertex(particle->location() + quad[1] * radius); + glTexCoord2f(1,0); + gl::vertex(particle->location() + quad[2] * radius); + glTexCoord2f(1,1); + gl::vertex(particle->location() + quad[3] * radius); + Stats::quads++; + } + + gl::end(); + } +} + +} // namespace render diff --git a/src/render/particles.h b/src/render/particles.h new file mode 100644 index 0000000..400971c --- /dev/null +++ b/src/render/particles.h @@ -0,0 +1,73 @@ +/* + render/particles.h + This file is part of the Osirion project and is distributed under + the terms of the GNU General Public License version 2 +*/ + +#ifndef __INCLUDED_RENDER_PARTICLES_H__ +#define __INCLUDED_RENDER_PARTICLES_H__ + +#include + +#include "math/color.h" +#include "math/vector3f.h" +#include "core/entity.h" + +namespace render { + +class Particle { +public: + Particle(const math::Vector3f &location, float time); + Particle(const math::Vector3f &location, const math::Vector3f &up, const math::Vector3f &left, float time); + + inline const math::Vector3f &location() const { return particle_location; } + + inline const math::Vector3f &up() const { return particle_up; } + + inline const math::Vector3f &left() const { return particle_left; } + + inline const float time() const { return particle_time; } + +protected: + math::Vector3f particle_location; + math::Vector3f particle_up; + math::Vector3f particle_left; + + float particle_time; +}; + + +class ParticleStream { +public: + ParticleStream(const math::Vector3f &location, const math::Color &color, float radius, size_t texture, core::EntityControlable *entity = 0, bool oriented = false); + ~ParticleStream(); + + void draw(); + + inline const size_t texture() const { return particles_texture; } + + inline const math::Vector3f &location() const { return particles_location; } + +protected: + typedef std::deque Particles; + + math::Vector3f particles_location; + math::Color particles_color; + size_t particles_texture; + bool particles_oriented; + + float particles_radius; + float particles_timeout; + float particles_eject; + + float particles_last_eject; + + core::EntityControlable *particles_entity; + + Particles particles_stream; +}; + + +} // namespace render + +#endif // __INCLUDED_RENDER_PARTICLES_H__ diff --git a/src/render/renderext.cc b/src/render/renderext.cc index ffe462f..5b6f3b4 100644 --- a/src/render/renderext.cc +++ b/src/render/renderext.cc @@ -23,10 +23,16 @@ RenderExt::RenderExt(core::Entity *entity) : core::Extension(core::Extension::Re state_detailvisible = false; state_fuzz = math::randomf(); - state_engine_trail_offset = 0; + //state_engine_trail_offset = 0; using namespace model; + if (!entity->model() && entity->modelname().size()) { + entity->set_modelname(entity->modelname()); + if (!entity->model()) + entity->set_modelname(""); + } + if (entity->model()) { model::Model *model = entity->model(); @@ -39,17 +45,20 @@ RenderExt::RenderExt(core::Entity *entity) : core::Extension(core::Extension::Re light->render_texture = Textures::load(flarename.str()); } - for(Model::Engines::iterator eit = model->engines().begin(); eit != model->engines().end(); eit++) { - Engine *engine = (*eit); + if ((entity->type() == core::Entity::Controlable) && entity->model()->engines().size()) { - if (!engine->flare()) engine->engine_flare = 1; + size_t trail_texure = Textures::load("bitmaps/fx/circle00"); - // load engine texture - std::stringstream flarename; - flarename << "bitmaps/fx/flare" << std::setfill('0') << std::setw(2) << engine->flare(); - engine->render_texture = Textures::load(flarename.str()); + for(Model::Engines::iterator eit = model->engines().begin(); eit != model->engines().end(); eit++) { + Engine *engine = (*eit); + + // add trail particles + math::Color c; + ParticleStream *p = new ParticleStream(engine->location(), c, 0.0625 * engine->radius(), trail_texure, static_cast(entity), true); + state_particles.push_back(p); + } } - + for (Model::Flares::iterator flit = model->flares().begin(); flit != model->flares().end(); flit++) { Flare *flare = (*flit); @@ -58,6 +67,7 @@ RenderExt::RenderExt(core::Entity *entity) : core::Extension(core::Extension::Re flarename << "bitmaps/fx/flare" << std::setfill('0') << std::setw(2) << flare->flare(); flare->render_texture = Textures::load(flarename.str()); } + } else if (entity->type() == core::Entity::Globe) { core::EntityGlobe *globe = static_cast(entity); @@ -74,6 +84,10 @@ RenderExt::RenderExt(core::Entity *entity) : core::Extension(core::Extension::Re RenderExt::~RenderExt() { + for (Particles::iterator it = state_particles.begin(); it != state_particles.end(); it++) { + delete (*it); + } + state_particles.clear(); } void RenderExt::frame(float elapsed) diff --git a/src/render/renderext.h b/src/render/renderext.h index eafa707..eb2ae67 100644 --- a/src/render/renderext.h +++ b/src/render/renderext.h @@ -7,7 +7,10 @@ #ifndef __INCLUDED_RENDER_RENDEREXT_H__ #define __INCLUDED_RENDER_RENDEREXT_H__ +#include + #include "core/extension.h" +#include "render/particles.h" namespace render { @@ -18,6 +21,8 @@ public: RenderExt(core::Entity *entity); ~RenderExt(); + typedef std::list Particles; + virtual void frame(float elapsed); inline bool visible() const { return state_visible; } @@ -28,15 +33,16 @@ public: /// distance to the camera inline float distance() const { return state_distance; } - // FIXME - float state_engine_trail_offset; - + /// particles + inline Particles &particles() { return state_particles; } private: - bool state_visible; - bool state_detailvisible; + bool state_visible; + bool state_detailvisible; - float state_fuzz; - float state_distance; + float state_fuzz; + float state_distance; + + Particles state_particles; }; } // namespace render diff --git a/src/render/tgafile.cc b/src/render/tgafile.cc index 5a27648..c4e6b56 100644 --- a/src/render/tgafile.cc +++ b/src/render/tgafile.cc @@ -298,7 +298,7 @@ void TGA::save(const char *filename, Image & image) } else { - // compressed block and pixel data is identical + // compressed block and pixel data are identical if (memcmp(block_data, pixel_data, image.channels()) == 0) { block_length++; -- cgit v1.2.3