← index
libmx2/libmx/space3d/explode.cpp
Source: libmx2/libmx/space3d/explode.cpp
#include "explode.hpp"


#ifdef __EMSCRIPTEN__

#else

#endif


namespace effect {

#ifndef __EMSCRIPTEN__


const char *s_vSource = R"(#version 330 core

layout (location = 0) in vec3 aPos;
layout (location = 1) in vec4 aColor;

out vec4 particleColor;

uniform mat4 model;
uniform mat4 view;
uniform mat4 projection;

void main() {
    gl_Position = projection * view * model * vec4(aPos, 1.0);
    gl_PointSize = 10.0;
    particleColor = aColor;
})";

const char *s_fSource = R"(#version 330 core

in vec4 particleColor;
out vec4 FragColor;

uniform sampler2D sprite;

void main() {
    float dist = length(gl_PointCoord - vec2(0.5));
    if (dist > 0.3) {
        discard;
    }
    vec4 texColor = texture(sprite, gl_PointCoord);
    FragColor = texColor * particleColor;
})";

#else


const char *s_vSource = R"(#version 300 es


precision highp float;

layout(location = 0) in vec3 aPos;
layout(location = 1) in vec4 aColor;

out vec4 particleColor;

uniform mat4 model;
uniform mat4 view;
uniform mat4 projection;

void main() {
    gl_Position = projection * view * model * vec4(aPos, 1.0);
    gl_PointSize = 10.0;
    particleColor = aColor;
})";


const char *s_fSource = R"(#version 300 es


precision mediump float;

in vec4 particleColor;
out vec4 FragColor;

uniform sampler2D sprite;

void main() {
    float dist = length(gl_PointCoord - vec2(0.5));
    if (dist > 0.3) {
        discard;
    }
    vec4 texColor = texture(sprite, gl_PointCoord);
    FragColor = texColor * particleColor;
})";

#endif


    Explosion::Explosion(unsigned int max, bool isBoss) : maxParticles(max), VAO(0), VBO(0), isBoss(isBoss) { 

    }

    void Explosion::load(gl::GLWindow *win) {
        particles.resize(maxParticles);

        glGenVertexArrays(1, &VAO);
        glGenBuffers(1, &VBO);

        glBindVertexArray(VAO);
        glBindBuffer(GL_ARRAY_BUFFER, VBO);
        glBufferData(GL_ARRAY_BUFFER, maxParticles * sizeof(Particle), nullptr, GL_DYNAMIC_DRAW);

        glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, sizeof(Particle), (void*)offsetof(Particle, position));
        glEnableVertexAttribArray(0);

        glVertexAttribPointer(1, 4, GL_FLOAT, GL_FALSE, sizeof(Particle), (void*)offsetof(Particle, color));
        glEnableVertexAttribArray(1);

        glBindBuffer(GL_ARRAY_BUFFER, 0);
        glBindVertexArray(0);
    }

    void Explosion::setInfo(gl::ShaderProgram *prog, GLuint texture_id) {
        this->shader_program = prog;
        this->textureID = texture_id;
    }

    void Explosion::update(float deltaTime) {
        is_active = false;
        for (auto &particle : particles) {
            if (particle.lifetime > 0.0f) {
                particle.lifetime -= deltaTime;
                particle.position += particle.velocity * deltaTime;
                particle.color.a = particle.lifetime;
                is_active = true;
            }
        }
    }

    void Explosion::draw(gl::GLWindow *win) {
#ifndef __EMSCRIPTEN__

        glEnable(GL_PROGRAM_POINT_SIZE);
#endif

        glDisable(GL_DEPTH_TEST);
        shader_program->useProgram();
        glBindVertexArray(VAO);
        glBindBuffer(GL_ARRAY_BUFFER, VBO);
        glBufferSubData(GL_ARRAY_BUFFER, 0, particles.size() * sizeof(Particle), particles.data());
        glEnable(GL_BLEND);
        glBlendFunc(GL_SRC_ALPHA, GL_ONE);
        shader_program->setUniform("sprite", 0);
        glActiveTexture(GL_TEXTURE0);
        glBindTexture(GL_TEXTURE_2D, textureID);
        glDrawArrays(GL_POINTS, 0, particles.size());

        glBindVertexArray(0);
        glUseProgram(0);
    }

    void Explosion::event(gl::GLWindow *win, SDL_Event &e) {}

    bool Explosion::active() const {

        return is_active;
    }

    void Explosion::trigger(glm::vec3 origin) {
        is_active = true;
        for (auto &particle : particles) {
            resetParticle(particle, origin);
        }
    }

    void Explosion::resetParticle(Particle &particle, glm::vec3 origin) {
        particle.position = origin;
        float velocityScale = 4.0f;
        float lifetimeScale = 0.5f;

        if (isBoss) {
            velocityScale = 8.0f; 
            lifetimeScale = 1.0f; 
        }

        particle.velocity = glm::sphericalRand(velocityScale);
        particle.lifetime = glm::linearRand(lifetimeScale, lifetimeScale * 4.0f);
        particle.color = particleColor;
    }

    ExplosionEmiter::ExplosionEmiter() : shader_program{}, texture{0} {}

    void ExplosionEmiter::load(gl::GLWindow *win) {
        if (!shader_program.loadProgramFromText(s_vSource, s_fSource)) {
            throw mx::Exception("Couldn't load Explosion Shader");
        }
        projection = glm::perspective(glm::radians(45.0f), (float)win->w / (float)win->h, 0.1f, 100.0f);
        view = glm::lookAt(glm::vec3(0.0f, 0.0f, 5.0f), glm::vec3(0.0f, 0.0f, 0.0f), glm::vec3(0.0f, 1.0f, 0.0f));
        model = glm::mat4(1.0f);
        shader_program.useProgram();
        shader_program.setUniform("projection", projection);
        shader_program.setUniform("view", view);
        shader_program.setUniform("model", model);
        texture = gl::loadTexture(win->util.getFilePath("data/star.png"));
    }

    void ExplosionEmiter::update(gl::GLWindow *win, float deltaTime) {
        for (int i = static_cast<int>(explosions.size()) - 1; i >= 0; i--) {
            explosions[i]->update(deltaTime);
            if (!explosions[i]->active()) {
                explosions.erase(explosions.begin() + i);
            }
        }
    }
    void ExplosionEmiter::draw(gl::GLWindow *win) {
        for (auto &e : explosions) {
            if (e->active())
                e->draw(win);
        }
    }

    void ExplosionEmiter::explode(gl::GLWindow *win, glm::vec3 pos, glm::vec4 particleColor, bool isBoss) { 
        if(isBoss)
            explosions.push_back(std::make_unique<Explosion>(500, isBoss));
        else
            explosions.push_back(std::make_unique<Explosion>(100, isBoss));

        explosions.back()->setInfo(&shader_program, texture);
        explosions.back()->particleColor = particleColor;
        explosions.back()->load(win);
        explosions.back()->trigger(pos);
    }

}