| @@ -0,0 +1,150 @@ | ||
| /* | ||
| * gui/ParticleManager.cpp | ||
| * | ||
| * This file is part of Leges Motus, a networked, 2D shooter set in zero gravity. | ||
| * | ||
| * Copyright 2009-2011 Andrew Ayer, Nathan Partlan, Jeffrey Pfau | ||
| * | ||
| * Leges Motus is free and open source software. You may redistribute it and/or | ||
| * modify it under the terms of version 2, or (at your option) version 3, of the | ||
| * GNU General Public License (GPL), as published by the Free Software Foundation. | ||
| * | ||
| * Leges Motus is distributed in the hope that it will be useful, but WITHOUT ANY | ||
| * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A | ||
| * PARTICULAR PURPOSE. See the full text of the GNU General Public License for | ||
| * further detail. | ||
| * | ||
| * For a full copy of the GNU General Public License, please see the COPYING file | ||
| * in the root of the source code tree. You may also retrieve a copy from | ||
| * <http://www.gnu.org/licenses/gpl-2.0.txt>, or request a copy by writing to the | ||
| * Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA | ||
| * 02111-1307 USA | ||
| * | ||
| */ | ||
|
|
||
| #include "ParticleManager.hpp" | ||
| #include "ParticleEmitter.hpp" | ||
| #include "Particle.hpp" | ||
|
|
||
| using namespace LM; | ||
| using namespace std; | ||
|
|
||
| ParticleManager::ParticleManager(Widget* parent, int num_initial_particles, bool can_expand_pool) : Widget(parent) { | ||
| for (int i = 0; i < num_initial_particles; i++) { | ||
| m_free_particles.push_back(new Particle()); | ||
| } | ||
|
|
||
| m_can_expand_pool = can_expand_pool; | ||
|
|
||
| m_total_particles = num_initial_particles; | ||
| } | ||
|
|
||
| ParticleManager::~ParticleManager() { | ||
| list<ParticleEmitter*>::iterator emitterator; | ||
| list<Particle*>::iterator it; | ||
|
|
||
| // Free all emitters | ||
| for (emitterator = m_emitters.begin(); emitterator != m_emitters.end(); emitterator++) { | ||
| for (it = (*emitterator)->get_particles().begin(); it != (*emitterator)->get_particles().end(); it++) { | ||
| m_free_particles.push_back((*it)); | ||
| } | ||
|
|
||
| (*emitterator)->clear(); | ||
|
|
||
| delete (*emitterator); | ||
| } | ||
|
|
||
| m_emitters.clear(); | ||
|
|
||
| // Free all particles | ||
| for (it = m_free_particles.begin(); it != m_free_particles.end(); it++) { | ||
| delete (*it); | ||
| } | ||
| m_free_particles.clear(); | ||
| } | ||
|
|
||
| void ParticleManager::add_emitter(ParticleEmitter* emitter) { | ||
| if (!emitter_exists(emitter)) { | ||
| m_emitters.push_back(emitter); | ||
| } | ||
| } | ||
|
|
||
| void ParticleManager::remove_emitter(ParticleEmitter* emitter) { | ||
| if (emitter_exists(emitter)) { | ||
| m_emitters.remove(emitter); | ||
|
|
||
| list<Particle*>::iterator it; | ||
|
|
||
| for (it = emitter->get_particles().begin(); it != emitter->get_particles().end(); it++) { | ||
| m_free_particles.push_back((*it)); | ||
| } | ||
|
|
||
| emitter->clear(); | ||
| } | ||
| } | ||
|
|
||
| bool ParticleManager::emitter_exists(ParticleEmitter* emitter) { | ||
| list<ParticleEmitter*>::iterator it; | ||
|
|
||
| for (it = m_emitters.begin(); it != m_emitters.end(); it++) { | ||
| if ((*it) == emitter) { | ||
| return true; | ||
| } | ||
| } | ||
|
|
||
| return false; | ||
| } | ||
|
|
||
| Particle* ParticleManager::request_particle() { | ||
| if (m_free_particles.size() == 0) { | ||
| if (!m_can_expand_pool) { | ||
| return NULL; | ||
| } | ||
|
|
||
| m_total_particles *= 2; | ||
| for (int i = 0; i < m_total_particles; i++) { | ||
| m_free_particles.push_back(new Particle()); | ||
| } | ||
| } | ||
|
|
||
| Particle* to_return = m_free_particles.back(); | ||
|
|
||
| m_free_particles.pop_back(); | ||
|
|
||
| return to_return; | ||
| } | ||
|
|
||
| void ParticleManager::free_particle(Particle* particle) { | ||
| m_free_particles.push_back(particle); | ||
| } | ||
|
|
||
| void ParticleManager::update(uint64_t timediff) { | ||
| list<ParticleEmitter*>::iterator it = m_emitters.begin(); | ||
|
|
||
| while (it != m_emitters.end()) { | ||
| // Update the emitter, then remove it if it is ready | ||
| if (!(*it)->update(timediff)) { | ||
| list<Particle*>::iterator it2; | ||
| for (it2 = (*it)->get_particles().begin(); it2 != (*it)->get_particles().end(); it2++) { | ||
| m_free_particles.push_back((*it2)); | ||
| } | ||
|
|
||
| (*it)->clear(); | ||
|
|
||
| delete *it; | ||
| m_emitters.erase(it++); | ||
| } else { | ||
| it++; | ||
| } | ||
| } | ||
| } | ||
|
|
||
| void ParticleManager::draw(DrawContext* context) const { | ||
| list<ParticleEmitter*>::const_iterator it; | ||
|
|
||
| for (it = m_emitters.begin(); it != m_emitters.end(); it++) { | ||
| //m_context->bind_shader_set(m_emitters->get_shader_program()); | ||
| (*it)->draw(context); | ||
| //m_context->unbind_shader_set(); | ||
| } | ||
| } |
| @@ -0,0 +1,57 @@ | ||
| /* | ||
| * gui/ParticleManager.hpp | ||
| * | ||
| * This file is part of Leges Motus, a networked, 2D shooter set in zero gravity. | ||
| * | ||
| * Copyright 2009-2011 Andrew Ayer, Nathan Partlan, Jeffrey Pfau | ||
| * | ||
| * Leges Motus is free and open source software. You may redistribute it and/or | ||
| * modify it under the terms of version 2, or (at your option) version 3, of the | ||
| * GNU General Public License (GPL), as published by the Free Software Foundation. | ||
| * | ||
| * Leges Motus is distributed in the hope that it will be useful, but WITHOUT ANY | ||
| * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A | ||
| * PARTICULAR PURPOSE. See the full text of the GNU General Public License for | ||
| * further detail. | ||
| * | ||
| * For a full copy of the GNU General Public License, please see the COPYING file | ||
| * in the root of the source code tree. You may also retrieve a copy from | ||
| * <http://www.gnu.org/licenses/gpl-2.0.txt>, or request a copy by writing to the | ||
| * Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA | ||
| * 02111-1307 USA | ||
| * | ||
| */ | ||
|
|
||
| #include "DrawContext.hpp" | ||
| #include "Widget.hpp" | ||
| #include <list> | ||
|
|
||
| #ifndef LM_GUI_PARTICLEMANAGER_HPP | ||
| #define LM_GUI_PARTICLEMANAGER_HPP | ||
|
|
||
| namespace LM { | ||
| class Particle; | ||
| class ParticleEmitter; | ||
|
|
||
| class ParticleManager : public Widget { | ||
| private: | ||
| std::list<ParticleEmitter*> m_emitters; | ||
| std::list<Particle*> m_free_particles; | ||
| bool m_can_expand_pool; | ||
| int m_total_particles; | ||
| public: | ||
| ParticleManager(Widget* parent, int num_initial_particles, bool can_expand_pool); | ||
| virtual ~ParticleManager(); | ||
|
|
||
| void add_emitter(ParticleEmitter* emitter); | ||
| void remove_emitter(ParticleEmitter* emitter); | ||
| bool emitter_exists(ParticleEmitter* emitter); | ||
| void update(uint64_t timediff); | ||
| virtual void draw(DrawContext* ctx) const; | ||
|
|
||
| Particle* request_particle(); | ||
| void free_particle(Particle* particle); | ||
| }; | ||
| } | ||
|
|
||
| #endif |
| @@ -0,0 +1,134 @@ | ||
| /* | ||
| * gui/SimpleRadialEmitter.cpp | ||
| * | ||
| * This file is part of Leges Motus, a networked, 2D shooter set in zero gravity. | ||
| * | ||
| * Copyright 2009-2011 Andrew Ayer, Nathan Partlan, Jeffrey Pfau | ||
| * | ||
| * Leges Motus is free and open source software. You may redistribute it and/or | ||
| * modify it under the terms of version 2, or (at your option) version 3, of the | ||
| * GNU General Public License (GPL), as published by the Free Software Foundation. | ||
| * | ||
| * Leges Motus is distributed in the hope that it will be useful, but WITHOUT ANY | ||
| * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A | ||
| * PARTICULAR PURPOSE. See the full text of the GNU General Public License for | ||
| * further detail. | ||
| * | ||
| * For a full copy of the GNU General Public License, please see the COPYING file | ||
| * in the root of the source code tree. You may also retrieve a copy from | ||
| * <http://www.gnu.org/licenses/gpl-2.0.txt>, or request a copy by writing to the | ||
| * Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA | ||
| * 02111-1307 USA | ||
| * | ||
| */ | ||
|
|
||
| #include "SimpleRadialEmitter.hpp" | ||
| #include "Particle.hpp" | ||
| #include <math.h> | ||
|
|
||
| using namespace LM; | ||
| using namespace std; | ||
|
|
||
| SimpleRadialEmitter::SimpleRadialEmitter(ParticleManager* manager, Point center, Image* image, DrawContext::BlendMode mode) : ParticleEmitter(manager, center, image, mode) { | ||
| m_lifetime = 0; | ||
| m_spawned_total = 0; | ||
| } | ||
|
|
||
| SimpleRadialEmitter::~SimpleRadialEmitter() { | ||
| delete m_settings; | ||
| } | ||
|
|
||
| void SimpleRadialEmitter::init(const SimpleRadialEmitterSettings* settings) { | ||
| m_settings = settings; | ||
|
|
||
| m_leftover_diff = 0; | ||
| m_lifetime = 0; | ||
| } | ||
|
|
||
| bool SimpleRadialEmitter::update(uint64_t timediff) { | ||
| timediff += m_leftover_diff; | ||
|
|
||
| if (timediff <= 0) { | ||
| return true; | ||
| } | ||
|
|
||
| m_leftover_diff = 0; | ||
| int num_to_spawn = int(m_settings->spawn_per_second * timediff/1000.0 + rand() % m_settings->spawn_variance * timediff/1000.0); | ||
|
|
||
| if (num_to_spawn == 0) { | ||
| m_leftover_diff += timediff; | ||
| } | ||
|
|
||
| // Spawn new particles | ||
| if ((m_settings->max_spawn <= 0 || m_spawned_total < m_settings->max_spawn) && | ||
| (m_settings->emitter_stop_spawning_millis <= 0 || m_settings->emitter_stop_spawning_millis > m_lifetime)) { | ||
| for (int i = 0; i < num_to_spawn; i++) { | ||
| Particle* particle = request_particle(); | ||
|
|
||
| init_particle(particle); | ||
|
|
||
| m_particles.push_back(particle); | ||
| m_spawned_total++; | ||
| if (particle == NULL) { | ||
| DEBUG("Could not spawn particle!"); | ||
| break; | ||
| } | ||
| } | ||
| } | ||
|
|
||
| // Update existing particles | ||
| list<Particle*>::iterator it = m_particles.begin(); | ||
| while (it != m_particles.end()) { | ||
| Particle* particle = *it; | ||
|
|
||
| if (particle->m_energy_left < timediff) { | ||
| free_particle(particle, it++); | ||
| continue; | ||
| } | ||
| particle->m_energy_left -= timediff; | ||
|
|
||
| particle->m_color.a = particle->m_energy_left / float(particle->m_initial_energy); | ||
|
|
||
| particle->m_prev_pos = particle->m_pos; | ||
| particle->m_vel += m_settings->global_force * timediff/1000.0f; | ||
| particle->m_pos += particle->m_vel * timediff/1000.0f; | ||
|
|
||
| it++; | ||
| } | ||
|
|
||
| // Check if we're done spawning/living | ||
| if (m_settings->max_spawn > 0) { | ||
| if (m_spawned_total > m_settings->max_spawn && m_particles.size() <= 0) { | ||
| return false; | ||
| } | ||
| } | ||
|
|
||
| m_lifetime += timediff; | ||
|
|
||
| if (m_settings->emitter_lifetime_millis > 0) { | ||
| if (m_lifetime > m_settings->emitter_lifetime_millis) { | ||
| return false; | ||
| } | ||
| } | ||
|
|
||
| return true; | ||
| } | ||
|
|
||
| void SimpleRadialEmitter::init_particle(Particle* particle) { | ||
| particle->m_pos = get_center(); | ||
| particle->m_prev_pos = particle->m_pos; | ||
| float speed = m_settings->particle_speed + (rand()/(float)RAND_MAX) * m_settings->speed_variance; | ||
| float dir = m_settings->rotation_rads + (rand()/(float)RAND_MAX) * m_settings->rotation_variance - m_settings->rotation_variance/2; | ||
|
|
||
| particle->m_vel = Vector(speed * sin(dir), speed * cos(dir)); | ||
|
|
||
| particle->m_energy_left = m_settings->lifetime_millis + rand() % m_settings->lifetime_variance; | ||
| particle->m_initial_energy = particle->m_energy_left; | ||
|
|
||
| particle->m_color.r = 255; | ||
| particle->m_color.g = 255; | ||
| particle->m_color.b = 255; | ||
| particle->m_color.a = 255; | ||
|
|
||
| particle->m_size = 1.0f; | ||
| } |
| @@ -0,0 +1,65 @@ | ||
| /* | ||
| * gui/SimpleRadialEmitter.hpp | ||
| * | ||
| * This file is part of Leges Motus, a networked, 2D shooter set in zero gravity. | ||
| * | ||
| * Copyright 2009-2011 Andrew Ayer, Nathan Partlan, Jeffrey Pfau | ||
| * | ||
| * Leges Motus is free and open source software. You may redistribute it and/or | ||
| * modify it under the terms of version 2, or (at your option) version 3, of the | ||
| * GNU General Public License (GPL), as published by the Free Software Foundation. | ||
| * | ||
| * Leges Motus is distributed in the hope that it will be useful, but WITHOUT ANY | ||
| * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A | ||
| * PARTICULAR PURPOSE. See the full text of the GNU General Public License for | ||
| * further detail. | ||
| * | ||
| * For a full copy of the GNU General Public License, please see the COPYING file | ||
| * in the root of the source code tree. You may also retrieve a copy from | ||
| * <http://www.gnu.org/licenses/gpl-2.0.txt>, or request a copy by writing to the | ||
| * Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA | ||
| * 02111-1307 USA | ||
| * | ||
| */ | ||
|
|
||
| #include "ParticleEmitter.hpp" | ||
|
|
||
| #ifndef LM_GUI_SIMPLERADIALEMITTER_HPP | ||
| #define LM_GUI_SIMPLERADIALEMITTER_HPP | ||
|
|
||
| namespace LM { | ||
| struct SimpleRadialEmitterSettings { | ||
| float particle_speed; | ||
| float speed_variance; | ||
| int spawn_per_second; | ||
| int spawn_variance; | ||
| uint64_t lifetime_millis; | ||
| uint64_t lifetime_variance; | ||
| float rotation_rads; | ||
| float rotation_variance; | ||
| Vector global_force; | ||
| int max_spawn; | ||
| uint64_t emitter_stop_spawning_millis; | ||
| uint64_t emitter_lifetime_millis; | ||
| }; | ||
|
|
||
| class SimpleRadialEmitter : public ParticleEmitter{ | ||
| private: | ||
| uint64_t m_lifetime; | ||
| uint64_t m_leftover_diff; | ||
| int m_spawned_total; | ||
|
|
||
| const SimpleRadialEmitterSettings* m_settings; | ||
|
|
||
| void init_particle(Particle* particle); | ||
| public: | ||
| SimpleRadialEmitter(ParticleManager* manager, Point center, Image* image, DrawContext::BlendMode mode = DrawContext::BLEND_ADD); | ||
| virtual ~SimpleRadialEmitter(); | ||
|
|
||
| void init(const SimpleRadialEmitterSettings* settings); | ||
|
|
||
| virtual bool update(uint64_t timediff); | ||
| }; | ||
| } | ||
|
|
||
| #endif |
| @@ -0,0 +1,127 @@ | ||
| #include "gui/SDLWindow.hpp" | ||
| #include "gui/GLESContext.hpp" | ||
| #include "gui/ShaderSet.hpp" | ||
| #include "gui/ResourceCache.hpp" | ||
| #include "gui/Image.hpp" | ||
| #include "gui/GraphicRegion.hpp" | ||
| #include "gui/GraphicContainer.hpp" | ||
| #include "gui/SimpleRadialEmitter.hpp" | ||
| #include "gui/ParticleManager.hpp" | ||
| #include "common/math.hpp" | ||
| #include "gui/DrawContext.hpp" | ||
|
|
||
| using namespace LM; | ||
| using namespace std; | ||
|
|
||
| void add_emitter(ParticleManager* particle_manager, Image* particle) { | ||
| SimpleRadialEmitter* simple_emitter = new SimpleRadialEmitter(particle_manager, Point(rand() % 400 + 50, rand() % 400 + 50), particle, DrawContext::BLEND_ADD); | ||
|
|
||
| SimpleRadialEmitterSettings* settings = new SimpleRadialEmitterSettings(); | ||
| settings->particle_speed = 100.0f; | ||
| settings->speed_variance = 0.05f; | ||
| settings->spawn_per_second = 1000.0f; | ||
| settings->spawn_variance = 1.0f; | ||
| settings->lifetime_millis = 500; | ||
| settings->lifetime_variance = 100; | ||
| settings->rotation_rads = 0.0f; | ||
| settings->rotation_variance = 2 * M_PI; | ||
| settings->global_force = Point(0.0f,0.0f); | ||
| settings->max_spawn = -1; | ||
| settings->emitter_stop_spawning_millis = 500; | ||
| settings->emitter_lifetime_millis = 1000; | ||
|
|
||
| simple_emitter->init(settings); | ||
|
|
||
| particle_manager->add_emitter(simple_emitter); | ||
| } | ||
|
|
||
| int main(int argc, char *argv[]) { | ||
| SDLWindow* window = SDLWindow::get_instance(512, 512, 24, Window::FLAG_VSYNC); | ||
| GLESContext* ctx = window->get_context(); | ||
| ResourceCache cache("data", ctx); | ||
| Image tile("metal_hazard64.png", &cache, true); | ||
| Image particle("blue_gate.png", &cache, true); | ||
|
|
||
| Widget w0; | ||
| w0.set_x(0); | ||
| w0.set_y(0); | ||
|
|
||
| GraphicRegion tile_s(&tile); | ||
| float c[] = { 4.0f, 8.0f, 0.5f, 1.0f }; | ||
| float s[] = { 9.0f, 14.0f }; | ||
| ShaderSet* program = ctx->create_shader_set(); | ||
| PixelShader shader = ctx->load_pixel_shader("data/shaders/gl/impact"); | ||
| program->attach_shader(shader); | ||
|
|
||
| tile_s.set_width(512); | ||
| tile_s.set_height(512); | ||
| tile_s.set_image_height(32); | ||
| tile_s.set_shader_set(program); | ||
|
|
||
| GraphicContainer g(true, &w0); | ||
| g.add_graphic("tile", &tile_s, -1); | ||
|
|
||
| ParticleManager* particle_manager = new ParticleManager(&w0, 100, true); | ||
|
|
||
| ctx->set_root_widget(&w0); | ||
|
|
||
| SDL_ShowCursor(SDL_TRUE); | ||
|
|
||
| bool running = true; | ||
| int frame = 0; | ||
| uint64_t last_frame_time = get_ticks(); | ||
|
|
||
| program->link(); | ||
| ctx->bind_shader_set(program); | ||
| program->set_variable("arc", 0.3f); | ||
| program->set_variable_2("size", 1, s); | ||
| program->set_variable("speed", 2.0f); | ||
| program->set_variable("offset", 0.0f); | ||
| program->set_variable("waves", 2.0f); | ||
| program->set_variable_2("center", 1, c); | ||
| program->set_variable("tex", 0); | ||
| while(running) { | ||
| SDL_Event e; | ||
| while(SDL_PollEvent(&e) != 0) { | ||
| switch(e.type) { | ||
| case SDL_QUIT: | ||
| running = 0; | ||
| break; | ||
| case SDL_KEYDOWN: | ||
| switch(e.key.keysym.sym) { | ||
| case SDLK_ESCAPE: | ||
| running = 0; | ||
| break; | ||
| default: | ||
| break; | ||
| } | ||
| } | ||
| } | ||
|
|
||
| //ctx->bind_shader_set(program); | ||
| //if (frame < 100) { | ||
| //program->set_variable("time", frame / 80.0f); | ||
| //} else if (frame < 150) { | ||
| // program->set_variable("time", 1.0f); | ||
| //} else { | ||
| // program->set_variable("time", 0); | ||
| //} | ||
|
|
||
| frame = (frame + 1) % 80; | ||
|
|
||
| if (frame % 20 == 0) { | ||
| add_emitter(particle_manager, &particle); | ||
| } | ||
|
|
||
| particle_manager->update(get_ticks() - last_frame_time); | ||
| last_frame_time = get_ticks(); | ||
|
|
||
| window->redraw(); | ||
|
|
||
| SDL_Delay(6); | ||
| } | ||
|
|
||
| delete particle_manager; | ||
|
|
||
| return 0; | ||
| } |