← index
LostMasterPiece2/src/main.cpp
Source: LostMasterPiece2/src/main.cpp
#include"mx.hpp"

#include"gl.hpp"

#include"model.hpp"

#include"quadtris.hpp"

#include"intro.hpp"

#include"start.hpp"

#include"gameover.hpp"

#include<cstdlib>

#include<ctime>

#include<filesystem>

#include<atomic>

#if defined(__APPLE__) || defined(_WIN32) || defined(__linux__)

#include"argz.hpp"

#endif

#include"shader_library.hpp"


std::unique_ptr<shader::Library> library;

#if defined(__EMSCRIPTEN__) || defined(__ANDORID__)

    const char *m_vSource = R"(#version 300 es
            precision highp 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 *m_fSource = R"(#version 300 es
        precision highp float; 
        in vec2 TexCoord;
        out vec4 FragColor;
        uniform sampler2D textTexture; 
        uniform float alpha;
        void main() {
            vec4 fcolor = texture(textTexture, TexCoord);
            FragColor = fcolor * alpha;
        }
    )";

    const char *v_mainShader = R"(#version 300 es
        precision mediump float; 
        layout(location = 0) in vec3 position;   
        layout(location = 1) in vec3 normal;     
        layout(location = 2) in vec2 texCoord;   

        out vec3 fragPos;       
        out vec3 fragNormal;    
        out vec2 fragTexCoord;  

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

        void main() {
            fragPos = vec3(model * vec4(position, 1.0));              
            fragNormal = mat3(transpose(inverse(model))) * normal;    
            fragTexCoord = texCoord;                                 

            gl_Position = projection * view * vec4(fragPos, 1.0);    
        }
    )";
    const char *f_mainShader = R"(#version 300 es
        precision highp float;  

        in vec3 fragPos;       
        in vec3 fragNormal;    
        in vec2 fragTexCoord;  
        out vec4 fragColor;

        uniform sampler2D texture1; 
        uniform vec3 lightPos;
        uniform vec3 viewPos;
        uniform vec3 lightColor;

        void main() {
            float ambientStrength = 0.15;
            vec3 ambient = ambientStrength * lightColor;
            vec3 norm = normalize(fragNormal);
            vec3 lightDir = normalize(lightPos - fragPos);
            float diff = max(dot(norm, lightDir), 0.0);
            vec3 diffuse = diff * lightColor;
            float specularStrength = 0.5;
            vec3 viewDir = normalize(viewPos - fragPos);
            vec3 reflectDir = reflect(-lightDir, norm);
            float spec = pow(max(dot(viewDir, reflectDir), 0.0), 32.0); 
            vec3 specular = specularStrength * spec * lightColor;
            vec3 textureColor = texture(texture1, fragTexCoord).rgb; 
            vec3 result = (ambient + diffuse + specular) * textureColor;
            fragColor = vec4(result, 1.0); 
            fragColor.a = 0.8;
        }
)";

#else

    const char *v_mainShader = R"(#version 330 core
        layout(location = 0) in vec3 position;   
        layout(location = 1) in vec3 normal;     
        layout(location = 2) in vec2 texCoord;   

        out vec3 fragPos;       
        out vec3 fragNormal;    
        out vec2 fragTexCoord;  

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

        void main() {
            fragPos = vec3(model * vec4(position, 1.0));              
            fragNormal = mat3(transpose(inverse(model))) * normal;    
            fragTexCoord = texCoord;                                 

            gl_Position = projection * view * vec4(fragPos, 1.0);    
        }
    )";
    
    const char *f_mainShader = R"(#version 330 core
        in vec3 fragPos;       
        in vec3 fragNormal;    
        in vec2 fragTexCoord;  
        out vec4 fragColor;

        uniform sampler2D texture1; 
        uniform vec3 lightPos;
        uniform vec3 viewPos;
        uniform vec3 lightColor;

        void main() {
            float ambientStrength = 0.15;
            vec3 ambient = ambientStrength * lightColor;
            vec3 norm = normalize(fragNormal);
            vec3 lightDir = normalize(lightPos - fragPos);
            float diff = max(dot(norm, lightDir), 0.0);
            vec3 diffuse = diff * lightColor;
            float specularStrength = 0.5;
            vec3 viewDir = normalize(viewPos - fragPos);
            vec3 reflectDir = reflect(-lightDir, norm);
            float spec = pow(max(dot(viewDir, reflectDir), 0.0), 32.0); 
            vec3 specular = specularStrength * spec * lightColor;
            vec3 textureColor = texture(texture1, fragTexCoord).rgb; 
            vec3 result = (ambient + diffuse + specular) * textureColor;
            fragColor = vec4(result, 1.0); 
            fragColor.a = 0.8;
        }
    )";
    

    const char *m_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 *m_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 = fcolor * alpha; 
        }
    )";
#endif


class Game : public gl::GLObject {
public:

    bool cmd_echo = true;
 
    Game(int diff) : mp(diff) {
        mp.grid.game_piece.setCallback([]() {});
    }
    ~Game() override {
        for (auto &t : textures)  {
            glDeleteTextures(1, &t);
        }
    }

    gl::GLWindow *window_handle = nullptr;

    virtual void load(gl::GLWindow *win) override {
        if (win == nullptr) {
            throw mx::Exception("Window is null");
        }
        window_handle = win;
        fade_in = true;
        mp.newGame();
        if(cube.openModel(win->util.getFilePath("data/cube.mxmod")) == false) {
            throw mx::Exception("Failed to open model");
        }
        if(program.loadProgramFromText(v_mainShader, f_mainShader) == false) {
            throw mx::Exception("Failed to load shader program");
        }
        const char *texture_files[] = {"data/block_clear.png","data/punk.png","data/block_ltblue.png","data/block_yellow.png","data/block_purple.png", "data/block_green.png", 0 };
        for(int i = 0; texture_files[i] != 0; ++i) {
            GLuint tex = gl::loadTexture(win->util.getFilePath(texture_files[i]));
            if(tex == 0) {
                throw mx::Exception("Failed to load texture: " + std::string(texture_files[i]));
            }
            textures.push_back(tex);
        }
        background = library->getShader(0)->shader();
        bg.initSize(win->w, win->h);
        bg.loadTexture(&background, win->util.getFilePath("data/bg.png"), 0.0f, 0.0f, win->w, win->h);
        font.loadFont(win->util.getFilePath("data/font.ttf"), 24);
        resize(win, win->w, win->h);
        mouse_x = mouse_y = 0;
    }
    virtual void draw(gl::GLWindow *win) override {
        Uint32 currentTime = SDL_GetTicks();
        deltaTime = (currentTime - lastUpdateTime) / 1000.0f;        
        if((currentTime - lastUpdateTime) > 25) {
            lastUpdateTime = currentTime;
            mp.grid.spin();
            mp.procBlocks();
            if(fade_in == true && fade <= 0.5f) fade += 0.05;
            else fade_in = false;
        }
        static Uint32 previous_time = SDL_GetTicks();
        Uint32 current_time = SDL_GetTicks();
        if (current_time - previous_time >= mp.timeout) {
            if(fade_in == false) {
                if(win->console_visible == false) {
                    if(mp.grid.canMoveDown()) {
                        if(mp.drop == false) {
                            mp.grid.game_piece.moveDown();
                        }
                        previous_time = current_time;
                    } else if(mp.drop == false) {
                        // Game over

                        win->setObject(new GameOver(mp.score, mp.level));
                        win->object->load(win);
                        return;
                    }
                }
            }
        }
        glDisable(GL_DEPTH_TEST);
        glEnable(GL_BLEND); 
        glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
        background.useProgram();
        background.setSilent(true);
        glUniform2f(glGetUniformLocation(background.id(), "iResolution"), win->w, win->h);
        background.setUniform("alpha", fade);
        background.setUniform("time_f", SDL_GetTicks() / 1000.0f); 
        bg.initSize(win->w, win->h);
        bg.draw();
        glDisable(GL_BLEND); 
        glEnable(GL_DEPTH_TEST);
        program.useProgram();
        glm::vec3 cameraPos(0.0f, 0.0f,10.0f);
        glm::vec3 lightPos(0.0f, 3.0f, 2.0f); 
        glm::vec3 viewPos = cameraPos;
        glm::vec3 lightColor(1.2f, 1.2f, 1.2f); 
        program.setUniform("lightPos", lightPos);
        program.setUniform("viewPos", viewPos);
        program.setUniform("lightColor", lightColor);
        for(int i = 0; i < mp.grid.width(); ++i) {
            for(int z = 0; z < mp.grid.height(); ++z) {
                glActiveTexture(GL_TEXTURE0);
                program.setName("texture1");  
                puzzle::Block *b = mp.grid.at(i, z);
                if(b != nullptr && b->color > 0) {
                    drawGridXY(i, z, b->color, 0);   
                } else if(b->color == -1) {
                    drawGridXY(i, z, 1+(rand()%3), b->rotate_x);
                }
            }
        }
        if(fade_in == false && mp.drop == false) {
            int x_val = mp.grid.game_piece.getX();
            int y_val = mp.grid.game_piece.getY();  
            for(int q = 0; q < 3; ++q) {
                int cx =  x_val;
                int cy =  y_val;
                switch(mp.grid.game_piece.getDirection()) {
                    case 0:
                    cx = x_val;
                    cy = y_val + q;
                    break;
                    case 1:
                    cx = x_val + q;
                    cy = y_val;
                    break;
                    case 2:
                    cx = x_val - q;
                    cy = y_val;
                    break;
                    case 3:
                    cx = x_val;
                    cy = y_val - q;
                    break;
                }
                puzzle::Block *b = mp.grid.game_piece.at(q);
                if (b != nullptr) {
                    drawGridXY(cx, cy, b->color, 0.0f);
                }
            }
        }
        if(fade_in == false)  {
            win->text.setColor({255, 255, 255, 255});
            win->text.printText_Solid(font, 25.0f, 25.0f, "Score: " + std::to_string(mp.score));
            win->text.setColor({255, 0, 0, 255});
            win->text.printText_Solid(font, 25.0f, 60.0f, "Level: " + std::to_string(mp.level));
        }
    }
    void drawGridXY(int x, int y, int color, float rotate_) {
        glm::mat4 model = glm::mat4(1.0f);
        model = glm::rotate(model, glm::radians(rotateX), glm::vec3(1.0f, 0.0f, 0.0f));
        model = glm::rotate(model, glm::radians(rotateY), glm::vec3(0.0f, 1.0f, 0.0f));
        model = glm::rotate(model, glm::radians(rotateZ), glm::vec3(0.0f, 0.0f, 1.0f));
        model = glm::translate(model, glm::vec3(0.0f, 0.0f,zoom ));
        float gridWidthOffset = -(mp.grid.width() * 1.2f) / 2.0f;
        model = glm::translate(model, glm::vec3(gridWidthOffset, 0.0f, 0.0f));
        model = glm::translate(model, glm::vec3(x * 1.2f, -y * 1.2f, 0.0f)); 
        program.setUniform("model", model);
        glActiveTexture(GL_TEXTURE0);
        program.setName("texture1"); 
        if(rotate_ > 0) {         
            glEnable(GL_BLEND);
            glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
            glDepthMask(GL_FALSE);
            glm::mat4 rotated = glm::rotate(glm::mat4(1.0f), rotate_ * deltaTime, glm::vec3(0.0f, 1.0, 0.0f));
            program.setUniform("model", model * rotated);
        } else if(color > 0){
            program.setUniform("model", model);
        }
        cube.drawArraysWithTexture(textures[color], "texture1");
        glDepthMask(GL_TRUE);
        glDisable(GL_BLEND);
    }
    void dropPiece() {
        if(mp.drop == false) {
            mp.drop = true;
            mp.grid.game_piece.drop();
        }
    }
    virtual void event(gl::GLWindow *win, SDL_Event &e) override {
        if(win->console_visible) {    
            if(e.type == SDL_KEYDOWN) {
              
            }
            return;
        }
        
            switch(e.type) {
            case SDL_KEYUP:
                if(!win->console_visible && e.key.keysym.sym == SDLK_RETURN) {
                    dropPiece();
                    win->console.thread_safe_print("\nCTRL+C Interrupt - No Command Running\n");
                    win->console.process_message_queue();  
                }
            break;
            case SDL_KEYDOWN: {

                int index = mx::generateRandomInt(0, library->size() - 1);
                std::cout << "Loaded: " << library->getShader(index)->filename << std::endl;
                background = library->getShader(index)->shader();

                switch(e.key.keysym.sym) {
                    case SDLK_LEFT:
                        mp.grid.game_piece.moveLeft();
                    break;
                    case SDLK_RIGHT:
                        mp.grid.game_piece.moveRight(); 
                    break;
                    case SDLK_UP:
                        mp.grid.game_piece.shiftColors();
                        win->console.print("Shift Colors\n");
                    break;
                    case SDLK_DOWN:
                        mp.grid.game_piece.moveDown();
                    break;
                    case SDLK_SPACE:
                    
                        mp.grid.game_piece.shiftDirection();
                        win->console.print("Shift Direction\n");
                    break;
                    case SDLK_w:
                        rotateX += 0.5f;
                        win->console.printf("RotateX: %f ", rotateX);
                    break;
                    case SDLK_s:
                        rotateX -= 0.5;
                        win->console.printf("RotateX: %f ", rotateX);
                    break;
                    case SDLK_a:
                        rotateY -= 0.5f;
                        win->console.printf("RotateY: %f ", rotateY);
                    break;
                    case SDLK_d:
                        rotateY += 0.5f;
                        win->console.printf("RotateY: %f ", rotateY);
                    break;
                    case SDLK_z:
                        rotateZ -= 0.5f;
                        win->console.printf("RotateZ: %f ", rotateZ);
                    break;
                    case SDLK_x:
                        rotateZ +=  0.5f;
                        win->console.printf("RotateZ: %f ", rotateZ);
                    break;
                    case SDLK_EQUALS:
                        zoom += 0.5f;
                        win->console.printf("Zoom: %f ",zoom);
                    break;
                    case SDLK_MINUS:
                        zoom -= 0.5f;
                        win->console.printf("Zoom: %f ",zoom);
                    break;
                    case SDLK_k:
                    //std::cout << "ZOOM: " << zoom << " X,Y,Z" << rotateX << "," << rotateY << "," << rotateZ << std::endl;

                    break;
                }
            }
                break;
                case SDL_MOUSEBUTTONDOWN:
                case SDL_FINGERDOWN:
                {
                     int index = mx::generateRandomInt(0, library->size() - 1);
                     std::cout << "Loaded: " << library->getShader(index)->filename << std::endl;
                     background = library->getShader(index)->shader();

                    int x, y;
                    if (e.type == SDL_MOUSEBUTTONDOWN) {
                        x = e.button.x;
                        y = e.button.y;
                        mouse_down = true;
                        mouse_x = x;
                        mouse_y = y;
                        mouse_click_time = SDL_GetTicks();
                        double_click = false;
                        if (SDL_GetTicks() - last_click_time < double_click_interval) {
                            double_click = true;
                        }
                        last_click_time = SDL_GetTicks();
                    } else {
                        x = e.tfinger.x * win->w;
                        y = e.tfinger.y * win->h;
                        num_fingers++;
                        if (num_fingers == 1) {
                            mouse_down = true;
                            mouse_x = x;
                            mouse_y = y;
                        } else if (num_fingers == 2) {
                            dropPiece();
                        }
                    }
                    break;
                }
                case SDL_MOUSEBUTTONUP:
                case SDL_FINGERUP:
                {
                    if (e.type == SDL_MOUSEBUTTONUP) {
                        mouse_down = false;
                        int dy = e.button.y - mouse_y;
                        if (dy < -50) {
                            mp.grid.game_piece.shiftColors();
                        } else if (dy > 50) {
                            mp.grid.game_piece.shiftDirection();
                        } else if (double_click == true) {
                            dropPiece();
                            double_click = false;
                        }
                    } else {
                        num_fingers--;
                        if (num_fingers <= 0) {
                            mouse_down = false;
                            num_fingers = 0;
                        }
                        int y = e.tfinger.y * win->h;
                        int dy = y - mouse_y;
                        if (dy < -50) {
                            mp.grid.game_piece.shiftColors();
                        } else if (dy > 50) {
                            mp.grid.game_piece.shiftDirection();
                        }
                    }
                    break;
                }
                case SDL_MOUSEMOTION:
                case SDL_FINGERMOTION:
                {
                    int x;
                    if (e.type == SDL_MOUSEMOTION) {
                        x = e.motion.x;
                    } else {
                        x = e.tfinger.x * win->w;
                    }
                    if (mouse_down) {
                        int dx = x - mouse_x;
                        if (dx > 25) {
                            mp.grid.game_piece.moveRight();
                            mouse_x = x;
                        } else if (dx < -25) {
                            mp.grid.game_piece.moveLeft();
                            mouse_x = x;
                        }
                    }
                    break;
            }
        }
     }

    virtual void resize(gl::GLWindow *win, int w, int h) override {
        program.useProgram();
        cube.setShaderProgram(&program);
        glm::mat4 model = glm::mat4(1.0f);
        glm::mat4 view = glm::lookAt(
             glm::vec3(0.0f, 3.0f, 5.0f),  
             glm::vec3(0.0f, 0.0f, 0.0f),  
             glm::vec3(0.0f, 1.0f, 0.0f)   
         );
         glm::mat4 projection = glm::perspective(glm::radians(45.0f), (float)win->w / win->h, 0.1f, 1000.0f);
         program.setUniform("model", model);
         program.setUniform("view", view);
         program.setUniform("projection", projection); 
    }
private:
    gl::ShaderProgram program, background, grid;
    mx::Model cube;
    std::vector<GLuint> textures;
    puzzle::MasterPiece mp;
    gl::GLSprite bg;
    gl::GLSprite grid_bg;
    mx::Font font;
    Uint32 lastUpdateTime = 0;
    float rotateX = 0.0f;
    float rotateY = 0.0f;
    float rotateZ = -0.5f;
    float zoom = -14.0f;
    bool mouse_down = false;
    int mouse_x = 0;
    int mouse_y = 0;
    Uint32 mouse_click_time = 0;
    Uint32 last_click_time = 0;
    bool double_click = false;
    Uint32 double_click_interval = 250;
    int num_fingers = 0;
    bool fade_in = false;
    float fade = 0.0f;
    float deltaTime = 0.0f;
};

void Intro::draw(gl::GLWindow *win) {
    glDisable(GL_DEPTH_TEST);
#ifndef __EMSCRIPTEN__

    Uint32 currentTime = SDL_GetTicks();
#else

    double currentTime = emscripten_get_now();
#endif

    program->useProgram();
    program->setSilent(true);
    glUniform2f(glGetUniformLocation(program->id(), "iResolution"), win->w, win->h);
    program->setUniform("alpha", fade);
    program->setUniform("time_f", SDL_GetTicks() / 1000.0f);
    intro.draw();
    if((currentTime - lastUpdateTime) > 25) {
        lastUpdateTime = currentTime;
        fade -= .01;
    }
    if(fade <= 0.1) {
        win->setObject(new Start());
        win->object->load(win);
        return;
    }
}

void Start::setGame(gl::GLWindow *win) {
    win->setObject(new Game(0));
    win->object->load(win);
}


void Start::event(gl::GLWindow *win, SDL_Event &e) {
    if(fade_in == true && (e.type == SDL_KEYDOWN || e.type == SDL_FINGERUP || e.type == SDL_MOUSEBUTTONUP)) {
        fade = 1.0f;
        fade_in = false;
        return;
    }
}

void Intro::event(gl::GLWindow *win, SDL_Event &e) {
    if(e.type == SDL_KEYDOWN || e.type == SDL_FINGERUP || e.type == SDL_MOUSEBUTTONUP) {
        win->setObject(new Start());
        win->object->load(win);
        return;
    }
}

void GameOver::draw(gl::GLWindow *win) {
    glDisable(GL_DEPTH_TEST);
    program.useProgram();
    GLint loc = glGetUniformLocation(program.id(), "iResolution");
    glUniform2f(loc, win->w, win->h);
    program.setUniform("time_f", static_cast<float>(SDL_GetTicks()) / 1000.0f);
    game_over.draw();
    win->text.setColor({255, 255, 255, 255});
    int tw = 0, th = 0;
    TTF_Font *f = font.unwrap();
    std::string gameover_text = "Game Over Your Score: " + std::to_string(score_);
    std::string play_again = "Tap or Enter to play again";
    TTF_SizeText(f, gameover_text.c_str(), &tw, &th);
    float centerX = static_cast<float>(win->w - tw) / 2.0f;
    float centerY = static_cast<float>(win->h - th) / 2.0f;
    win->text.setColor({150, 80, 255, 255});
    win->text.printText_Solid(font, centerX, centerY, gameover_text.c_str());
    TTF_SizeText(f, play_again.c_str(), &tw, &th);
    centerX = static_cast<float>(win->w - tw) / 2.0f;
    centerY = static_cast<float>(win->h - th) / 2.0f;
    win->text.setColor({255, 255, 255, 255});
    win->text.printText_Solid(font, centerX, centerY + 80.0f, play_again.c_str());
}

void GameOver::event(gl::GLWindow *win, SDL_Event &e) {
    if((e.type == SDL_KEYDOWN && e.key.keysym.sym == SDLK_RETURN) || (e.type == SDL_FINGERUP) || (e.type == SDL_MOUSEBUTTONUP)) {
        win->setObject(new Intro());
        win->object->load(win);
        return;
    }
}


class Startup : public gl::GLObject {
public:
    virtual void load(gl::GLWindow *win) override {
        font.loadFont(win->util.getFilePath("data/font.ttf"), 24);
        counter = 0;
    }
    virtual void draw(gl::GLWindow *win) override {
        win->text.printText_Solid(font, 25.0f, 25.0f, "Loading shaders...");
        counter++;
        if(counter == 2) {
            library.reset(new shader::Library(win->util.getFilePath("data")));
            win->setObject(new Intro());
            win->object->load(win);
            return;
        }
    }   
    virtual void event(gl::GLWindow *win, SDL_Event &e) override {}
private:
    mx::Font font;
    int counter = 0;
};

class MainWindow : public gl::GLWindow {
public:
    MainWindow(const std::string &path, int wx, int wy) : gl::GLWindow("MasterPiece3D", wx, wy) {
        setPath(path);
        swap();
        SDL_Surface *ico = png::LoadPNG(util.getFilePath("data/punk.png").c_str());
        if(ico != nullptr) {
            setWindowIcon(ico);
            SDL_FreeSurface(ico);
        }
        setObject(new Startup());
        object->load(this);
        activateConsole(util.getFilePath("data/font.ttf"),16,{255,255,255});
        console.hide();
        updateViewport();
    }

    virtual void draw() override {
        glClearColor(0.0f, 0.0f, 0.0f, 1.0f);
        glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
        object->draw(this);
        swap();
        delay();
    }
    
    virtual void event(SDL_Event &e) override {
#if defined(__ANDROID__) || defined(__EMSCRIPTEN__)

        if (e.type == SDL_WINDOWEVENT) {
            if (e.window.event == SDL_WINDOWEVENT_SIZE_CHANGED) {
                updateViewport();
            }
        } 
#endif

    }   
};

MainWindow *main_w = nullptr;

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

int main(int argc, char **argv) {
    srand(static_cast<int>(time(0)));
#ifdef __EMSCRIPTEN__

    MainWindow main_window(".", 1920, 1080);
    main_w =&main_window;
    emscripten_set_main_loop(eventProc, 0, 1);
#else

#if defined(_WIN32) || defined(__linux__) || defined(__APPLE__)

    Arguments args = proc_args(argc, argv);
    try {
        MainWindow main_window(args.path, args.width, args.height);
        if(args.fullscreen)
            main_window.setFullScreen(true);
        main_window.loop();
    }  catch(mx::Exception &e) {
        SDL_Log("mx: Exception: %s", e.text().c_str());
    }
#elif defined(__ANDROID__)

    try {
        MainWindow main_window("");
        main_window.loop();
    }  catch(mx::Exception &e) {
        SDL_Log("mx: Exception: %s", e.text().c_str());
    }
#endif

#endif

    return 0;
}