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

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


class Game : public obj::Object {
public:
    Game();
    ~Game() override;

    constexpr static int tex_width = 640, tex_height = 480;

    void load(mx::mxWindow* win) override;
    void draw(mx::mxWindow* win) override;
    void event(mx::mxWindow* win, SDL_Event& e) override;

private:
    int cur_screen = 0;
    SDL_Texture* draw_tex = nullptr;
    SDL_Texture* logo = nullptr;
    SDL_Texture* start = nullptr;
    SDL_Texture* cursor = nullptr;
    SDL_Texture* gamebg = nullptr;
    SDL_Texture* blocks[12] = { nullptr };
    SDL_Texture* alien = nullptr;
    Uint32 startTime = 0;
    Uint32 waitTime = 3000;
    int cursor_pos = 0;
    Uint32 startTime2 = 0;
    Uint32 waitTime2 = 1000;
    bool show_cursor = false;
    mx::Font the_font;
    mx::Joystick stick;

    class TileMatrix {
    public:
        struct GameData {
            unsigned long score;
            int lines;
            int speed;
            int lineamt;
            int linenum = 0;

            bool game_is_over = false;

            void gameover() {
                game_is_over = true;
            }

            bool isGameOver() const {
                return game_is_over;
            }

            GameData() {
                newgame();
            }

            void newgame() {
                score = 0;
                lines = 0;
                speed = 1500;
                lineamt = 0;
                game_is_over = false;
            }

            void addline() {
                lines++;
                score += 6;
                lineamt++;

                if (lineamt >= linenum) {
                    lineamt = 0;
                    speed -= 101;
                    if (speed < 100) {
                        speed = 100;
                    }
                }
            }
        };

        struct GameBlock {
            struct Color {
                int c1, c2, c3;

                void randcolor() {
                    c1 = rand() % 10;
                    c2 = rand() % 10;
                    c3 = rand() % 10;
                    if (c1 == 0) { c1++; }
                    if (c2 == 0) { c2++; }
                    if (c3 == 0) { c3++; }

                    if (c1 == c2 && c1 == c3) {
                        randcolor();
                        return;
                    }
                }

                void copycolor(const Color* c) {
                    c1 = c->c1;
                    c2 = c->c2;
                    c3 = c->c3;
                }

                void shiftcolor(bool dir) {
                    int ic1 = c1, ic2 = c2, ic3 = c3;

                    if (dir) {
                        c1 = ic3;
                        c2 = ic1;
                        c3 = ic2;
                    }
                    else {
                        c1 = ic2;
                        c2 = ic3;
                        c3 = ic1;
                    }
                }
            };

            Color color;
            Color nextcolor;
            int x, y;

            GameBlock() {
                color.randcolor();
                nextcolor.randcolor();
                x = 3;
                y = 0;
            }

            void NextBlock() {
                color.copycolor(&nextcolor);
                nextcolor.randcolor();
                x = 3;
                y = 0;
            }

            void MoveDown() {
                if (y + 2 < 16) {
                    y++;
                }
            }

            void MoveLeft() {
                if (x > 0) {
                    x--;
                }
            }

            void MoveRight() {
                if (x < 7) {
                    x++;
                }
            }
        };

        GameData Game;
        GameBlock block;
        int Tiles[17][8];  // 17 rows, 8 columns

        TileMatrix() {
            cleartiles();
        }

        void cleartiles() {
            for (int i = 0; i < 17; i++) {
                for (int j = 0; j < 8; j++) {
                    Tiles[i][j] = 0;
                }
            }
        }

        void init_matrix() {
            cleartiles();
            Game.newgame();
            block.NextBlock();
        }

        void setblock() {
            if (block.y <= 0) {
                Game.gameover();
            }

            if (block.y < 15) {  
                Tiles[block.y][block.x] = block.color.c1;
                Tiles[block.y + 1][block.x] = block.color.c2;
                Tiles[block.y + 2][block.x] = block.color.c3;
                block.NextBlock();
            }
        }

        void ProccessBlocks() {
            for (int z = 0; z < 8; z++) {
                for (int i = 0; i < 16; i++) {
                    if (Tiles[i][z] != 0 && Tiles[i + 1][z] == 0) {
                        Tiles[i + 1][z] = Tiles[i][z];
                        Tiles[i][z] = 0;
                    }
                }
            }
        }

        void clearBlocks() {
            for (int z = 0; z < 8; z++) {
                for (int i = 0; i < 17; i++) {
                    if (Tiles[i][z] == -1) {
                        Tiles[i][z] = 0;
                    }
                }
            }
        }
    };

    TileMatrix matrix;
    void newGame();
    void resetGame();
    void setScreen(int scr);

    void load_gfx(mx::mxWindow* win);
    void release_gfx();
    void draw_intro(mx::mxWindow* win);
    void draw_start(mx::mxWindow* win);
    void draw_game(mx::mxWindow* win);
    void draw_credits(mx::mxWindow* win);
    void draw_options(mx::mxWindow* win);
    void blockProc();
};

Game::Game() {
    
}

Game::~Game() {
    if (draw_tex != nullptr)
        SDL_DestroyTexture(draw_tex);
    release_gfx();
}

void Game::load(mx::mxWindow* win) {

    if(stick.open(0)) {
        mx::system_out << "Initalized Joystick: " << stick.name() << "\n";
    }

    SDL_Renderer* ren = win->renderer;
    load_gfx(win);
    the_font.loadFont(win->util.getFilePath("mp_dat/font.ttf"), 14);
    draw_tex = SDL_CreateTexture(ren, SDL_PIXELFORMAT_RGBA8888, SDL_TEXTUREACCESS_TARGET, tex_width, tex_height);
    if (!draw_tex) {
        std::cerr << "Could not create texture.\n";
        exit(EXIT_FAILURE);
    }
    resetGame();
}

void Game::load_gfx(mx::mxWindow* win) {
    int w, h;
    logo = win->util.loadTexture(win->renderer, "mp_dat/intro.png");
    start = win->util.loadTexture(win->renderer, "mp_dat/start.png");
    SDL_Color color = { 255, 0, 255 };
    cursor = win->util.loadTexture(win->renderer, "mp_dat/cursor.png", w, h, true, color);
    gamebg = win->util.loadTexture(win->renderer, "mp_dat/gamebg.png");
    const char* grid_block_paths[12] = {
        "mp_dat/block_black.png",
        "mp_dat/block_yellow.png",
        "mp_dat/block_orange.png",
        "mp_dat/block_ltblue.png",
        "mp_dat/block_dblue.png",
        "mp_dat/block_purple.png",
        "mp_dat/block_pink.png",
        "mp_dat/block_gray.png",
        "mp_dat/block_red.png",
        "mp_dat/block_green.png",
        "mp_dat/block_clear.png",
        nullptr
    };
    for (int i = 0; grid_block_paths[i] != nullptr; ++i) {
        blocks[i] = win->util.loadTexture(win->renderer, grid_block_paths[i]);
    }
    alien = win->util.loadTexture(win->renderer, "mp_dat/mp.alien.png");
}

void Game::release_gfx() {
    if (logo != nullptr)
        SDL_DestroyTexture(logo);
    if (start != nullptr)
        SDL_DestroyTexture(start);
    if (cursor != nullptr)
        SDL_DestroyTexture(cursor);
    if (gamebg != nullptr)
        SDL_DestroyTexture(gamebg);

    for (int i = 0; i < 11; ++i) {
        if (blocks[i] != nullptr)
            SDL_DestroyTexture(blocks[i]);
    }
    if (alien != nullptr) {
        SDL_DestroyTexture(alien);
    }
}

void Game::resetGame() {
    startTime = 0;
    waitTime = 3000;
    cur_screen = 0;
    cursor_pos = 0;
}

void Game::newGame() {
    cur_screen = 2;
    matrix.init_matrix();
    waitTime2 = 1000;
}

void Game::setScreen(int scr) {
    cur_screen = scr;
}

void Game::draw(mx::mxWindow* win) {
    SDL_Renderer* ren = win->renderer;
    SDL_SetRenderDrawColor(ren, 0, 0, 0, 255);
   
    switch (cur_screen) {
    case 0:
        draw_intro(win);
        break;
    case 1:
        draw_start(win);
        break;
    case 2:
        draw_game(win);
        break;
    case 4:
        draw_credits(win);
        break;
    case 3:
        draw_options(win);
        break;
    }
}

void Game::event(mx::mxWindow* win, SDL_Event& e) {
    SDL_Rect ir = { 0, 0, win->width, win->height };
    static int x1 = 0, y1x = 0, x2 = 0, y2 = 0;
    static const int drag_threshold = 15;
    if (cur_screen == 2 && e.type == SDL_MOUSEBUTTONDOWN && e.button.button == SDL_BUTTON_LEFT) {
        x1 = e.button.x - ir.x;
        y1x = e.button.y - ir.y;
    }
    else if (cur_screen == 2 && e.type == SDL_MOUSEBUTTONUP && e.button.button == SDL_BUTTON_LEFT) {
        if (!(e.button.x >= ir.x && e.button.x <= ir.x + ir.w && e.button.y >= ir.y && e.button.y <= ir.y + ir.h)) {
            return;
        }
        x2 = e.button.x - ir.x;
        y2 = e.button.y - ir.y;
        if (abs(y1x - y2) > abs(x1 - x2)) {
            if (y1x < y2 && abs(y1x - y2) > drag_threshold) {
                x1 = x2;
                y1x = y2;
                matrix.block.MoveDown();
            }
            else if (y1x > y2 && abs(y2 - y1x) > drag_threshold) {
                matrix.block.color.shiftcolor(true);
                x1 = x2;
                y1x = y2;
            }
        }
        else {
            if (x1 < x2 && abs(x1 - x2) > drag_threshold) {
                x1 = x2;
                y1x = y2;
                matrix.block.MoveRight();
            }
            else if (x1 > x2 && abs(x2 - x1) > drag_threshold) {
                matrix.block.MoveLeft();
                x1 = x2;
                y1x = y2;
            }
        }
    }

    switch (e.type) {
    case SDL_MOUSEMOTION: {
        if (cur_screen == 1) {
            SDL_Rect startMeRect;
            int rectWidth = static_cast<int>(ir.w * 0.2);
            int rectHeight = static_cast<int>(ir.h * 0.1);
            startMeRect.x = (ir.w / 2) - (rectWidth / 2);
            startMeRect.y = (ir.h / 2) - (rectHeight / 2);
            startMeRect.w = rectWidth;
            startMeRect.h = rectHeight;
            SDL_Point p = { e.motion.x - ir.x, e.motion.y - ir.y };
            if (SDL_PointInRect(&p, &startMeRect)) {
                show_cursor = true;
            }
            else {
                show_cursor = false;
            }
        }
        break;
    }
    case SDL_MOUSEBUTTONDOWN: {
        if (e.button.button == SDL_BUTTON_LEFT) {
            if (e.button.x >= ir.x && e.button.x <= ir.x + ir.w && e.button.y >= ir.y && e.button.y <= ir.y + ir.h) {
                if (cur_screen == 1) {
                    SDL_Rect startMeRect;
                    int rectWidth = static_cast<int>(ir.w * 0.2);
                    int rectHeight = static_cast<int>(ir.h * 0.1);
                    startMeRect.x = (ir.w / 2) - (rectWidth / 2);
                    startMeRect.y = (ir.h / 2) - (rectHeight / 2);
                    startMeRect.w = rectWidth;
                    startMeRect.h = rectHeight;

                    SDL_Point p = { e.button.x - ir.x, e.button.y - ir.y };
                    if (SDL_PointInRect(&p, &startMeRect)) {
                        newGame();
                    }
                }
            }
        }
        break;
    }

    case SDL_JOYHATMOTION: 
        if (cur_screen == 2 && e.jhat.hat == 0) {
            switch (e.jhat.value) {
                case SDL_HAT_LEFT:
                    matrix.block.MoveLeft();
                    break;
                case SDL_HAT_RIGHT:
                    matrix.block.MoveRight();
                    break;
                case SDL_HAT_DOWN:
                    matrix.block.MoveDown();
                    break;
                case SDL_HAT_UP:
                    matrix.block.color.shiftcolor(true);
                    break;
                case SDL_HAT_CENTERED:
                    break;
                default:
                    break;
            }
        }
        break;
        case SDL_JOYBUTTONDOWN: {
            switch(e.jbutton.button) { 
                case 1:
                if(cur_screen == 4 || cur_screen == 3) {
                    cur_screen = 1;
                }
                break;
                case 2:
                if(cur_screen == 1) {
                    if(cursor_pos == 0) {
                        newGame();
                    }
                }
                break;
            }
        }
        break;

    case SDL_KEYDOWN:
        switch (e.key.keysym.sym) {
        case SDLK_UP:
            if (cur_screen == 2) {
                matrix.block.color.shiftcolor(true);
            }
            break;
        case SDLK_DOWN:
            if (cur_screen == 2) {
                matrix.block.MoveDown();
            }
            break;
        case SDLK_LEFT:
            if (cur_screen == 2) {
                matrix.block.MoveLeft();
            }
            break;
        case SDLK_RIGHT:
            if (cur_screen == 2) {
                matrix.block.MoveRight();
            }
            break;
        case SDLK_SPACE:
            if (cur_screen == 4 || cur_screen == 3) {
                cur_screen = 1;
            }
            break;
        case SDLK_RETURN:
            if (cur_screen == 1) {
                switch (cursor_pos) {
                case 0:
                    newGame();
                    break;
                }
            }
            break;
        }
        break;
    }
}

void Game::draw_intro(mx::mxWindow* win) {
    SDL_Renderer* ren = win->renderer;
    SDL_Rect rc = { 0, 0, tex_width, tex_height };

    if (startTime == 0) {
        startTime = SDL_GetTicks();
    }

    Uint32 elapsedTime = SDL_GetTicks() - startTime;
    if (elapsedTime > waitTime) {
        elapsedTime = waitTime;
    }

    Uint8 alphaLogo = 255 - (255 * elapsedTime / waitTime);
    Uint8 alphaStart = 255 * elapsedTime / waitTime;

    SDL_SetTextureAlphaMod(logo, alphaLogo);
    SDL_RenderCopy(ren, logo, nullptr, &rc);

    SDL_SetTextureAlphaMod(start, alphaStart);
    SDL_RenderCopy(ren, start, nullptr, &rc);

    if (elapsedTime >= waitTime) {
        cur_screen = 1;
        startTime = 0;
    }
}

void Game::draw_start(mx::mxWindow* win) {
    SDL_Renderer* ren = win->renderer;
    SDL_Rect rc = { 0, 0, tex_width, tex_height };
    SDL_RenderCopy(ren, start, nullptr, &rc);
}

void Game::draw_credits(mx::mxWindow* win) {
    SDL_Renderer* ren = win->renderer;
    SDL_Rect rc = { 0, 0, tex_width, tex_height };
    SDL_RenderCopy(ren, start, nullptr, &rc);
    SDL_SetRenderDrawColor(ren, 0, 0, 0, 255);
    SDL_Rect rc2 = { 35, 92, tex_width - 35, tex_height - 130 };
    SDL_RenderFillRect(ren, &rc2);
    SDL_Color color = { 255, 255, 255, 255 };
    SDL_Color color2 = { 255, 0, 0, 255 };
    SDL_Color color3 = { 0, 0, 255, 255 };

    win->util.printText(ren, the_font.wrapper().unwrap(), 60, 110, "MasterPiece MX Edition", color);
    win->util.printText(ren, the_font.wrapper().unwrap(), 60, 135, "written by Jared Bruni", color2);
    win->util.printText(ren, the_font.wrapper().unwrap(), (tex_width / 2) - (200 / 2) + 15, 200, "[ Press Space to Return ]", color3);

    SDL_Rect rc3 = { (tex_width / 2) - (150 / 2), 225, 150, 150 };
    SDL_RenderCopy(ren, alien, nullptr, &rc3);
}

void Game::draw_options(mx::mxWindow* win) {
    SDL_Renderer* ren = win->renderer;
    SDL_Rect rc = { 0, 0, tex_width, tex_height };
    SDL_RenderCopy(ren, start, nullptr, &rc);
    SDL_SetRenderDrawColor(ren, 0, 0, 0, 255);
    SDL_Rect rc2 = { 35, 92, tex_width - 35, tex_height - 130 };
    SDL_RenderFillRect(ren, &rc2);
    SDL_Color color = { 255, 255, 255, 255 };
    win->util.printText(ren, the_font.wrapper().unwrap(), 60, 110, "[ Options Menu - Space to Return ]", color);
}

void Game::draw_game(mx::mxWindow* win) {
    SDL_Renderer* ren = win->renderer;
    SDL_Rect rc = { 0, 0, tex_width, tex_height };
    SDL_RenderCopy(ren, gamebg, nullptr, &rc);

    const int STARTPOSX = 185;
    const int STARTPOSY = 95;
    int x = STARTPOSX, y = STARTPOSY;
    int blockWidth = 32;
    int blockHeight = 16;

    for (int i = 0; i < 17; i++) {
        for (int j = 0; j < 8; j++) {
            if (matrix.Tiles[i][j] != -1) {
                if (matrix.Tiles[i][j] != 0) {
                    SDL_Rect dstRect = { x, y, blockWidth, blockHeight };
                    SDL_RenderCopy(ren, blocks[matrix.Tiles[i][j]], nullptr, &dstRect);
                }
                x += blockWidth;
            }
            else {
                SDL_Rect dstRect = { x, y, blockWidth, blockHeight };
                SDL_RenderCopy(ren, blocks[1 + (rand() % 8)], nullptr, &dstRect);
                x += blockWidth;
            }
        }
        x = STARTPOSX;
        y += blockHeight;
    }

    int bx = 510, by = 200;

    SDL_Rect nextBlockRect1 = { bx, by, blockWidth, blockHeight };
    SDL_RenderCopy(ren, blocks[matrix.block.nextcolor.c1], nullptr, &nextBlockRect1);

    SDL_Rect nextBlockRect2 = { bx, by + blockHeight, blockWidth, blockHeight };
    SDL_RenderCopy(ren, blocks[matrix.block.nextcolor.c2], nullptr, &nextBlockRect2);

    SDL_Rect nextBlockRect3 = { bx, by + 2 * blockHeight, blockWidth, blockHeight };
    SDL_RenderCopy(ren, blocks[matrix.block.nextcolor.c3], nullptr, &nextBlockRect3);

    auto getcords = [](int r, int c, int& rx, int& ry) {
        const int STARTPOSX = 185;
        const int STARTPOSY = 95;
        rx = STARTPOSX + c * 32;
        ry = STARTPOSY + r * 16;
    };

    getcords(matrix.block.y, matrix.block.x, bx, by);
    SDL_Rect blockRect1 = { bx, by, blockWidth, blockHeight };
    SDL_RenderCopy(ren, blocks[matrix.block.color.c1], nullptr, &blockRect1);

    getcords(matrix.block.y + 1, matrix.block.x, bx, by);
    SDL_Rect blockRect2 = { bx, by, blockWidth, blockHeight };
    SDL_RenderCopy(ren, blocks[matrix.block.color.c2], nullptr, &blockRect2);

    getcords(matrix.block.y + 2, matrix.block.x, bx, by);
    SDL_Rect blockRect3 = { bx, by, blockWidth, blockHeight };
    SDL_RenderCopy(ren, blocks[matrix.block.color.c3], nullptr, &blockRect3);

    SDL_Color white{ 255,255,255,255 };
    win->util.printText(ren, the_font.wrapper().unwrap(), 200, 60, "Score: " + std::to_string(matrix.Game.score), white);
    win->util.printText(ren, the_font.wrapper().unwrap(), 310, 60, "Lines: " + std::to_string(matrix.Game.lines), white);
    blockProc();

    if (startTime2 == 0) {
        startTime2 = SDL_GetTicks();
    }

    waitTime2 = matrix.Game.speed;

    Uint32 elapsedTime = SDL_GetTicks() - startTime2;
    if (elapsedTime > waitTime2) {
        elapsedTime = waitTime2;
    }
    if (elapsedTime >= waitTime2) {
        matrix.block.MoveDown();
        startTime2 = 0;
        matrix.clearBlocks();
    }

    if (matrix.Game.isGameOver())
        cur_screen = 0;
}

void Game::blockProc() {
    if (matrix.block.y + 2 >= 16) {
        matrix.setblock();
        return;
    }

    if (matrix.block.y + 3 < 17 && matrix.Tiles[matrix.block.y + 3][matrix.block.x] != 0) {
        matrix.setblock();
        return;
    }

    for (int i = 0; i < 17; i++) {
        for (int j = 0; j < 8 - 2; j++) {
            int cur_color = matrix.Tiles[i][j];
            if (cur_color != 0 && cur_color != -1) {
                if (matrix.Tiles[i][j + 1] == cur_color && matrix.Tiles[i][j + 2] == cur_color) {
                    matrix.Game.addline();
                    matrix.Tiles[i][j] = -1;
                    matrix.Tiles[i][j + 1] = -1;
                    matrix.Tiles[i][j + 2] = -1;
                    return;
                }
            }
        }
    }

    for (int z = 0; z < 8; z++) {
        for (int q = 0; q < 17 - 2; q++) {
            int cur_color = matrix.Tiles[q][z];
            if (cur_color != 0 && cur_color != -1) {
                if (matrix.Tiles[q + 1][z] == cur_color && matrix.Tiles[q + 2][z] == cur_color) {
                    matrix.Tiles[q][z] = -1;
                    matrix.Tiles[q + 1][z] = -1;
                    matrix.Tiles[q + 2][z] = -1;
                    matrix.Game.addline();
                    return;
                }
            }
        }
    }

    for (int p = 0; p < 8; p++) {
        for (int w = 0; w < 17; w++) {
            int cur_color = matrix.Tiles[w][p];

            if (cur_color != 0 && cur_color != -1) {
                if (w + 2 < 17 && p + 2 < 8) {
                    if (matrix.Tiles[w + 1][p + 1] == cur_color && matrix.Tiles[w + 2][p + 2] == cur_color) {
                        matrix.Tiles[w][p] = -1;
                        matrix.Tiles[w + 1][p + 1] = -1;
                        matrix.Tiles[w + 2][p + 2] = -1;
                        matrix.Game.addline();
                    }
                }
                if (w - 2 >= 0 && p - 2 >= 0) {
                    if (matrix.Tiles[w - 1][p - 1] == cur_color && matrix.Tiles[w - 2][p - 2] == cur_color) {
                        matrix.Tiles[w][p] = -1;
                        matrix.Tiles[w - 1][p - 1] = -1;
                        matrix.Tiles[w - 2][p - 2] = -1;
                        matrix.Game.addline();
                    }
                }
                if (w - 2 >= 0 && p + 2 < 8) {
                    if (matrix.Tiles[w - 1][p + 1] == cur_color && matrix.Tiles[w - 2][p + 2] == cur_color) {
                        matrix.Tiles[w][p] = -1;
                        matrix.Tiles[w - 1][p + 1] = -1;
                        matrix.Tiles[w - 2][p + 2] = -1;
                        matrix.Game.addline();
                    }
                }
                if (w + 2 < 17 && p - 2 >= 0) {
                    if (matrix.Tiles[w + 1][p - 1] == cur_color && matrix.Tiles[w + 2][p - 2] == cur_color) {
                        matrix.Tiles[w][p] = -1;
                        matrix.Tiles[w + 1][p - 1] = -1;
                        matrix.Tiles[w + 2][p - 2] = -1;
                        matrix.Game.addline();
                    }
                }
            }
        }
    }

    matrix.ProccessBlocks();
}

class Intro : public obj::Object {
public:
    Intro() {}
    ~Intro() override {}

    virtual void load(mx::mxWindow *win) override {
        tex.loadTexture(win, win->util.getFilePath("mp_dat/logo.png"));
        bg.loadTexture(win, win->util.getFilePath("mp_dat/bg.png"));
    }

    virtual void draw(mx::mxWindow *win) override {
        static Uint32 previous_time = SDL_GetTicks();
        Uint32 current_time = SDL_GetTicks();
        static int alpha = 255;
        static bool fading_out = true;
        static bool done = false;

        SDL_RenderCopy(win->renderer, bg.wrapper().unwrap(), nullptr, nullptr);
        SDL_SetTextureAlphaMod(tex.wrapper().unwrap(), alpha);
        SDL_RenderCopy(win->renderer, tex.wrapper().unwrap(), nullptr, nullptr);

        if(done == true) {
            win->setObject(new Game());
            win->object->load(win);
            return;
        }
        
        if (current_time - previous_time >= 15) {
            previous_time = current_time;
            if (fading_out) {
                alpha -= 3;  
                if (alpha <= 0) {
                    alpha = 0;
                    fading_out = false;
                    done = true;
                }
            } else {
                alpha += 3;
                if (alpha >= 255) {
                    alpha = 255;
                    fading_out = true;
                    previous_time = SDL_GetTicks();
                }
            }
        }
    }

    virtual void event(mx::mxWindow *win, SDL_Event &e) override {

    }
private:
    mx::Texture tex;
    mx::Texture bg;
};




class MainWindow : public mx::mxWindow {
public:
    
    MainWindow(std::string path, int tw, int th) : mx::mxWindow("MasterPiece", tw, th, false) {
        tex.createTexture(this, 640, 480);
      	setPath(path);
        setObject(new Intro());
		object->load(this);
    }
    
    ~MainWindow() override {

    }
    
    virtual void event(SDL_Event &e) override {}

    virtual void draw(SDL_Renderer *renderer) override {
        SDL_SetRenderTarget(renderer, tex.wrapper().unwrap());
        SDL_SetRenderDrawColor(renderer, 0, 0, 0, 255);
        SDL_RenderClear(renderer);
        // draw
        object->draw(this);
        SDL_SetRenderTarget(renderer,nullptr);
        SDL_RenderCopy(renderer, tex.wrapper().unwrap(), nullptr, nullptr);
        SDL_RenderPresent(renderer);
    }
private:
    mx::Texture tex;
};

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;
}