← index
libmx2/libmx/gl_stencil_test/skeleton.cpp
Source: libmx2/libmx/gl_stencil_test/skeleton.cpp
#include"mx.hpp"
#include"argz.hpp"

#ifdef __EMSCRIPTEN__
#include <emscripten/emscripten.h>
#include <GLES3/gl3.h>
#endif

#include"gl.hpp"
#include"loadpng.hpp"

#define CHECK_GL_ERROR() \
{ GLenum err = glGetError(); \
if (err != GL_NO_ERROR) \
printf("OpenGL Error: %d at %s:%d\n", err, __FILE__, __LINE__); }

#ifndef M_PI
#define M_PI 3.14159265358979323846
#endif

#ifdef __EMSCRIPTEN__
    const char *fxSource = R"(#version 300 es
        precision highp float;
        in vec2 TexCoord;
        out vec4 FragColor;
        uniform sampler2D textTexture;
        uniform float time_f;
        uniform vec2 iResolution;

        vec3 rainbow(float t) {
            t = fract(t);
            float r = abs(t * 6.0 - 3.0) - 1.0;
            float g = 2.0 - abs(t * 6.0 - 2.0);
            float b = 2.0 - abs(t * 6.0 - 4.0);
            return clamp(vec3(r, g, b), 0.0, 1.0);
        }

        void main(void) {
            vec2 tc = TexCoord;
            vec2 uv = tc * 2.0 - 1.0;
            uv.y *= iResolution.y / iResolution.x;
            float wave = sin(uv.x * 10.0 + time_f * 2.0) * 0.1;
            float angle = atan(uv.y + wave, uv.x) + time_f * 2.0;
            vec3 rainbow_color = rainbow(angle / (2.0 * 3.14159));
            vec4 original_color = texture(textTexture, tc);
            vec3 blended_color = mix(original_color.rgb, rainbow_color, 0.5);
            FragColor = vec4(sin(blended_color * time_f), original_color.a);
            vec4 color = texture(textTexture, TexCoord);
            FragColor += color + 0.5;
        }
    )";
#else
const char *fxSource = R"(#version 330
        in vec2 TexCoord;
        out vec4 FragColor;
        uniform sampler2D textTexture;
        uniform float time_f;
        uniform vec2 iResolution;

        vec3 rainbow(float t) {
            t = fract(t);
            float r = abs(t * 6.0 - 3.0) - 1.0;
            float g = 2.0 - abs(t * 6.0 - 2.0);
            float b = 2.0 - abs(t * 6.0 - 4.0);
            return clamp(vec3(r, g, b), 0.0, 1.0);
        }

        void main(void) {
            vec2 tc = TexCoord;
            vec2 uv = tc * 2.0 - 1.0;
            uv.y *= iResolution.y / iResolution.x;
            float wave = sin(uv.x * 10.0 + time_f * 2.0) * 0.1;
            float angle = atan(uv.y + wave, uv.x) + time_f * 2.0;
            vec3 rainbow_color = rainbow(angle / (2.0 * 3.14159));
            vec4 original_color = texture(textTexture, tc);
            vec3 blended_color = mix(original_color.rgb, rainbow_color, 0.5);
            FragColor = vec4(sin(blended_color * time_f), original_color.a);
            vec4 color = texture(textTexture, TexCoord);
            FragColor += color + 0.5;
        }
    )";
#endif

class Game : public gl::GLObject {
public:
    Game() = default;
    virtual ~Game() override {}

    void load(gl::GLWindow *win) override {
        if(shader.loadProgramFromText(gl::vSource, fxSource) == false) {
            throw mx::Exception("Failed to load shader program");
        }
        font.loadFont(win->util.getFilePath("data/font.ttf"), 76);
        img.initSize(win->w, win->h);
        shader.useProgram();
        glUniform2f(glGetUniformLocation(shader.id(), "iResolution"), win->w, win->h);
        img.loadTexture(&shader, win->util.getFilePath("data/logo.png"), 0, 0, win->w, win->h);
    }

    void draw(gl::GLWindow *win) override {
        glEnable(GL_STENCIL_TEST);
        glStencilFunc(GL_ALWAYS, 1, 0xFF);  
        glStencilOp(GL_KEEP, GL_KEEP, GL_REPLACE);  
        glColorMask(GL_FALSE, GL_FALSE, GL_FALSE, GL_FALSE);
        win->text.setColor({255,255,255,255});
        win->text.printText_Solid(font, 25.0f, 25.0f, "Hello World, with OpenGL!");
        glColorMask(GL_TRUE, GL_TRUE, GL_TRUE, GL_TRUE);
        glStencilFunc(GL_EQUAL, 1, 0xFF);
        glStencilOp(GL_KEEP, GL_KEEP, GL_KEEP);
        shader.useProgram();
        static float time_f = 0.0f;
        Uint32 currentTime = SDL_GetTicks();
        float deltaTime = (currentTime - lastUpdateTime) / 1000.0f; // Convert to seconds
        lastUpdateTime = currentTime;
        time_f += deltaTime;
        shader.setUniform("time_f", time_f);
        img.draw();
        glDisable(GL_STENCIL_TEST);
        update(deltaTime);
    }
    
    void event(gl::GLWindow *win, SDL_Event &e) override {}
    void update(float deltaTime) {}
    
private:
    mx::Font font;
    gl::GLSprite img;
    gl::ShaderProgram shader;
    Uint32 lastUpdateTime = SDL_GetTicks();
};

class MainWindow : public gl::GLWindow {
public:
    MainWindow(std::string path, int tw, int th) : gl::GLWindow("Skeleton", tw, th) {
        setPath(path);
        setObject(new Game());
        object->load(this);
    }
    
    ~MainWindow() override {}
    
    virtual void event(SDL_Event &e) override {
    }
    
    virtual void draw() override {
        glClearColor(0.0f, 0.0f, 0.0f, 1.0f);
        glClearStencil(0);
        glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT | GL_STENCIL_BUFFER_BIT);
        glEnable(GL_DEPTH_TEST);
        
        glViewport(0, 0, w, h);
        object->draw(this);
        swap();
        delay();
    }
};

MainWindow *main_w = nullptr;

void eventProc() {
    main_w->proc();
}

int main(int argc, char **argv) {
#ifdef __EMSCRIPTEN__
    MainWindow main_window("/", 960, 720);
    main_w =&main_window;
    emscripten_set_main_loop(eventProc, 0, 1);
#else
    Arguments args = proc_args(argc, argv);
    try {
        MainWindow main_window(args.path, args.width, args.height);
        main_window.loop();
    } catch(const mx::Exception &e) {
        mx::system_err << "mx: Exception: " << e.text() << "\n";
        mx::system_err.flush();
        exit(EXIT_FAILURE);
    }
#endif
    return 0;
}