Particle System
unknown
c_cpp
4 years ago
5.2 kB
103
Indexable
#include "Emitter.h" #include <iostream> #include "ResourceManager.h" using namespace glm; /* From the Header */ // ----------------- // Represents a single particle and its state struct Particle { vec2 Position, Velocity; vec4 Color; float Life; float Rotation; short int type; Particle() : Position(0.0f), Velocity(0.0f), Color(1.0f), Rotation(0.0f), type(0), Life(0.0f) { } }; // ----------------- std::vector<Particle> Emitter::particles; unsigned int Emitter::amount; Shader Emitter::shader; unsigned int Emitter::SpriteSheetID; unsigned int Emitter::VAO; void Emitter::Init( unsigned int a ) { shader = ResourceManager::GetShader("particle"); SpriteSheetID = SpriteSheet::LoadSpriteSheet("particles", "particles.png", 16, 16); amount = a; init(); } void Emitter::Update(float dt) { // update all particles for (unsigned int i = 0; i < amount; ++i) { Particle& p = particles[i]; p.Life -= dt; // reduce life if (p.Life > 0.0f) { // particle is alive, thus update p.Position -= p.Velocity * dt; p.Color.a -= dt * 2.5f; } } } void Emitter::AddParticles(short int type, vec2 position, vec2 velocity, float rotation, unsigned int newParticles, vec2 offset) { // add new particles for (unsigned int i = 0; i < newParticles; ++i) { int unusedParticle = firstUnusedParticle(); respawnParticle(particles[unusedParticle], type, position, velocity, rotation, offset); } } // render all particles void Emitter::Draw() { // use additive blending to give it a 'glow' effect glBlendFunc(GL_SRC_ALPHA, GL_ONE); shader.Use(); glActiveTexture(GL_TEXTURE0); glBindTexture(GL_TEXTURE_2D_ARRAY, SpriteSheetID); for (Particle particle : particles) { if (particle.Life > 0.0f) { // Prepare transformations // Create a model matrix mat4 model = mat4(1.0f); // Move the sprite to the desired position model = translate(model, vec3(abs(particle.Position.x) - 15, abs(particle.Position.y) - 15, 0.0f)); model = translate(model, vec3(0.5 * 30, 0.5f * 30, 0.0f)); // Move the sprite so the origin is in the center model = rotate(model, radians(particle.Rotation), vec3(0.0f, 0.0f, 1.0f)); // Rotate around the center model = translate(model, vec3(-0.5 * 30, -0.5f * 30, 0.0f)); // Reverse previous translation model = scale(model, vec3(30, 30, 1.0f)); // Finally, scale if needed shader.SetMatrix4("model", model); // Set the model matrix shader.SetVector4f("color", particle.Color); shader.SetFloat("type", particle.type); // Set the model matrix glBindVertexArray(VAO); glDrawArrays(GL_TRIANGLES, 0, 6); glBindVertexArray(0); } } // don't forget to reset to default blending mode glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA); } void Emitter::init() { // set up mesh and attribute properties unsigned int VBO; float particle_quad[] = { 0.0f, 1.0f, 0.0f, 1.0f, 1.0f, 0.0f, 1.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 1.0f, 0.0f, 1.0f, 1.0f, 1.0f, 1.0f, 1.0f, 1.0f, 0.0f, 1.0f, 0.0f }; glGenVertexArrays(1, &VAO); glGenBuffers(1, &VBO); glBindVertexArray(VAO); // fill mesh buffer glBindBuffer(GL_ARRAY_BUFFER, VBO); glBufferData(GL_ARRAY_BUFFER, sizeof(particle_quad), particle_quad, GL_STATIC_DRAW); // set mesh attributes glEnableVertexAttribArray(0); glVertexAttribPointer(0, 4, GL_FLOAT, GL_FALSE, 4 * sizeof(float), (void*)0); glBindVertexArray(0); // create amount default particle instances for (unsigned int i = 0; i < amount; ++i) particles.push_back(Particle()); } // stores the index of the last particle used (for quick access to next dead particle) unsigned int lastUsedParticle = 0; unsigned int Emitter::firstUnusedParticle() { // first search from last used particle, this will usually return almost instantly for (unsigned int i = lastUsedParticle; i < amount; ++i) { if (particles[i].Life <= 0.0f) { lastUsedParticle = i; return i; } } // otherwise, do a linear search for (unsigned int i = 0; i < lastUsedParticle; ++i) { if (particles[i].Life <= 0.0f) { lastUsedParticle = i; return i; } } // all particles are taken, override the first one (note that if it repeatedly hits this case, more particles should be reserved) lastUsedParticle = 0; return 0; } void Emitter::respawnParticle(Particle& particle, short int type, vec2 position, vec2 velocity, float rotation, vec2 offset) { particle.Position = position + offset; particle.Color = vec4(1, 1, 1, 1.0f); particle.Life = 1.0f; particle.type = type; particle.Rotation = rotation; particle.Velocity = velocity * 0.1f; }
Editor is loading...