← index
libmx2/libmx/gl_surface_test/window.cpp
Source: libmx2/libmx/gl_surface_test/window.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

class Game : public gl::GLObject {
public:
    
    Game() = default;
    ~Game() override {
        if(surface) {
            SDL_FreeSurface(surface);
        }
        if(texture) {
            glDeleteTextures(1, &texture);
        } 
    }
    void load(gl::GLWindow *win) override {
        font.loadFont(win->util.getFilePath("data/font.ttf"), 16);
        if(!shader.loadProgramFromText(gl::vSource, gl::fSource)) {
            throw mx::Exception("Could not load shader");
        }
        surface = gl::createSurface(640, 480);
        if(!surface) {
            throw mx::Exception("Error creating surface");
        }
        SDL_FillRect(surface, 0, SDL_MapRGBA(surface->format,255, 255, 255, 255));
        texture = gl::createTexture(surface, true);
        sprite.initSize(win->w, win->h);
        sprite.initWithTexture(&shader, texture, 0, 0, win->w, win->h);
    }

    Uint8 value = 0;

    void draw(gl::GLWindow *win) override {
        Uint32 currentTime = SDL_GetTicks();
        float deltaTime = (currentTime - lastUpdateTime) / 1000.0f; // Convert to seconds
        lastUpdateTime = currentTime;
        if(deltaTime > 0.005) {
            value += 1;
            if(value >= 254) value = 0;
        }
        update(deltaTime);
        SDL_FillRect(surface, 0, SDL_MapRGBA(surface->format, value, value, value, 255));
        sprite.updateTexture(surface);
        sprite.draw();
        win->text.printText_Solid(font, 5.0f, 5.0f, "Hello, World!");
        win->text.printText_Solid(font, 250.0f, 250.0f, "OpenGL Text");
    }
    void event(gl::GLWindow *win, SDL_Event &e) override {}
    void update(float deltaTime) {}
private:
    Uint32 lastUpdateTime = SDL_GetTicks();
    mx::Font font;
    gl::GLSprite sprite;
    GLuint texture;
    SDL_Surface *surface = nullptr;
    gl::ShaderProgram shader;
};

#ifdef __EMSCRIPTEN__
    const char *vSource = R"(#version 300 es
            precision mediump float;
            layout (location = 0) in vec3 aPos;
            layout (location = 1) in vec2 aTexCoord;

            out vec2 TexCoord;

            void main() {
                gl_Position = vec4(aPos, 1.0); 
                TexCoord = aTexCoord;         
            }
    )";
    const char *fSource = R"(#version 300 es
        precision mediump float;
        in vec2 TexCoord;
        out vec4 FragColor;
        uniform sampler2D textTexture; 
        uniform float alpha;
        void main() {
            vec4 fcolor = texture(textTexture, TexCoord);
            FragColor = mix(fcolor, vec4(0.0, 0.0, 0.0, fcolor.a), alpha);
        }
    )";
#else
    const char *vSource = R"(#version 330 core
        layout (location = 0) in vec3 aPos;
        layout (location = 1) in vec2 aTexCoord;
        out vec2 TexCoord;
        void main() {
            gl_Position = vec4(aPos, 1.0); 
            TexCoord = aTexCoord;        
        }
    )";
    const char *fSource = R"(#version 330 core
        in vec2 TexCoord;
        out vec4 FragColor;
        uniform sampler2D textTexture; 
        uniform float alpha;
        void main() {
            vec4 fcolor = texture(textTexture, TexCoord);
            FragColor = mix(fcolor, vec4(0.0, 0.0, 0.0, fcolor.a), alpha);
        }
    )";
#endif

class IntroScreen : public gl::GLObject {
    float fade = 0.0f;
public:
    IntroScreen() = default;
    ~IntroScreen() override {

    }

    virtual void load(gl::GLWindow *win) override {
        if(!program.loadProgramFromText(vSource, fSource)) {
            throw mx::Exception("Error loading shader program");
        }
        logo.initSize(win->w, win->h);
        logo.loadTexture(&program, win->util.getFilePath("data/logo.png"), 0, 0, win->w, win->h);
    }

    void draw(gl::GLWindow *win) override {
#ifndef __EMSCRIPTEN__
        Uint32 currentTime = SDL_GetTicks();
#else
        double currentTime = emscripten_get_now();
#endif
        program.useProgram();
        program.setUniform("alpha", fade);
        logo.draw();
        if((currentTime - lastUpdateTime) > 25) {
            lastUpdateTime = currentTime;
            fade += 0.01;
        }
        if(fade >= 1.0) {
            win->setObject(new Game());
            win->object->load(win);
            return;
        }
    }
    void event(gl::GLWindow *win, SDL_Event &e) override {}

private:
    Uint32 lastUpdateTime;
    gl::GLSprite logo;
    gl::ShaderProgram program;
};

class MainWindow : public gl::GLWindow {
public:
    MainWindow(std::string path, int tw, int th) : gl::GLWindow("GL Window", tw, th) {
        setPath(path);
        setObject(new IntroScreen());
        object->load(this);
    }
    
    ~MainWindow() override {}
    
    virtual void event(SDL_Event &e) override {
        object->event(this, e);
    }
    
    virtual void draw() override {
        glClearColor(0.0f, 0.0f, 0.0f, 1.0f);
        glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_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
    Argz<std::string> parser(argc, argv);
    parser.addOptionSingle('h', "Display help message")
        .addOptionSingleValue('p', "assets path")
        .addOptionDoubleValue('P', "path", "assets path")
        .addOptionSingleValue('r',"Resolution WidthxHeight")
        .addOptionDoubleValue('R',"resolution", "Resolution WidthxHeight");
    Argument<std::string> arg;
    std::string path;
    int value = 0;
    int tw = 960, th = 720;
    try {
        while((value = parser.proc(arg)) != -1) {
            switch(value) {
                case 'h':
                case 'v':
                    parser.help(std::cout);
                    exit(EXIT_SUCCESS);
                    break;
                case 'p':
                case 'P':
                    path = arg.arg_value;
                    break;
                case 'r':
                case 'R': {
                    auto pos = arg.arg_value.find("x");
                    if(pos == std::string::npos)  {
                        mx::system_err << "Error invalid resolution use WidthxHeight\n";
                        mx::system_err.flush();
                        exit(EXIT_FAILURE);
                    }
                    std::string left, right;
                    left = arg.arg_value.substr(0, pos);
                    right = arg.arg_value.substr(pos+1);
                    tw = atoi(left.c_str());
                    th = atoi(right.c_str());
                }
                    break;
            }
        }
    } catch (const ArgException<std::string>& e) {
        mx::system_err << e.text() << "\n";
    }
    if(path.empty()) {
        mx::system_out << "mx: No path provided trying default current directory.\n";
        path = ".";
    }
    try {
        MainWindow main_window(path, tw, th);
        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;
}