← index
Mutatris/source/android/puzzle.cpp
Source: Mutatris/source/android/puzzle.cpp
#include "puzzle.hpp"

#include<iostream>

#include<string>

#include<random>

#include<algorithm>

#include"util.hpp"

#include"game_over.hpp"


namespace obj {


    PuzzleObject::PuzzleObject(int diff) : game{diff} {}

    PuzzleObject::~PuzzleObject() {
        std::cout << "Mutatris: Game Released...\n";
        for(size_t i = 0; i < blocks.size(); ++i) {
            SDL_DestroyTexture(blocks[i]);
        }
        for(size_t i = 0; i < backgrounds.size(); ++i) {
            SDL_DestroyTexture(backgrounds[i]);
        }
        for(size_t i = 0; i <= 3;  ++i) {
            SDL_DestroyTexture(game_textures[i]);
        }

        if(pause_menu)
            SDL_DestroyTexture(pause_menu);


        if(font)
            TTF_CloseFont(font);
        
        if(paused_small)
            TTF_CloseFont(paused_small);

        if(paused_large)
            TTF_CloseFont(paused_large);
    }

    void PuzzleObject::drawGrid(SDL_Renderer *renderer, SDL_Texture *texture, int focus) {
              
        SDL_Texture* old_target = SDL_GetRenderTarget(renderer);
        SDL_SetRenderTarget(renderer, texture);
        SDL_RenderCopy(renderer, backgrounds[game.level < static_cast<int>(backgrounds.size()) ? game.level : backgrounds.size()-1], nullptr, nullptr);
        for (int i = 0; i < game.grid[focus].width(); ++i) {
            for (int z = 0; z < game.grid[focus].height(); ++z) {
                int pos_x = 32 * i;
                int pos_y = 16 * z;
                SDL_Rect rc = { pos_x, pos_y, 30, 14 };
                puzzle::Block *b = game.grid[focus].at(i, z);
                if(b != nullptr) {
                    if(b->color >= 0)
                        SDL_RenderCopy(renderer, blocks[b->color], nullptr, &rc);
                    else {
                        SDL_RenderCopy(renderer, blocks[1+(rand()%6)], nullptr, &rc);      
                    }
                    
                }
            }
        }

        
        if(cur_focus == focus) {
            int x_val = game.grid[focus].game_piece.getX();
            int y_val = game.grid[focus].game_piece.getY();  
            for(int q = 0; q < 3; ++q) {
                int cx = 32 * x_val;
                int cy = 16 * y_val + (16 * q);
                switch(game.grid[focus].game_piece.getDirection()) {
                    case 1:
                    cx = 32 * (x_val + q);
                    cy = (16 * y_val);
                    break;
                    case 2:
                    cx = 32 * (x_val - q);
                    cy = (16 * y_val);
                    break;
                    case 3:
                    cx = 32 * x_val;
                    cy = (16 * y_val) - (16 * q);
                    break;
                }
                SDL_Rect pos_rc = { cx, cy, 32, 16 };
                puzzle::Block *b = game.grid[focus].game_piece.at(q);
                if(b != nullptr)
                    SDL_RenderCopy(renderer, blocks[b->color], nullptr, &pos_rc);
            }
        }
        SDL_SetRenderTarget(renderer, old_target);
        game.procBlocks();
    }

    void PuzzleObject::twistColors() {
        static Uint32 previous_time = SDL_GetTicks();
        Uint32 current_time = SDL_GetTicks();
        Uint32 delta_time = current_time - previous_time;
        if (delta_time >= 25) {        
            for(int focus = 0; focus <= 3; focus ++) {
                for (int i = 0; i < game.grid[focus].width(); ++i) {
                    for (int z = 0; z < game.grid[focus].height(); ++z) {
                        puzzle::Block *b = game.grid[focus].at(i, z);
                        if (b && b->color < 0) {
                            b->color--;
                            if (b->color < -60) {
                                b->color = 0;
                            }
                        }
                    }
                }
            }
            previous_time += delta_time; 
        }
    }


    void PuzzleObject::draw(SDL_Renderer *renderer) {

        if(paused) {
            SDL_RenderCopy(renderer, pause_menu, nullptr, nullptr);
            util::printText(renderer, paused_large, 580, 325, "Paused", {255, 255, 255, 255});
            util::printText(renderer, paused_small, 600, 595, "Press Space",{255,255,255,255});
            return;
        }

        SDL_RenderCopy(renderer, backgrounds[game.level < static_cast<int>(backgrounds.size()) ? game.level : backgrounds.size()-1], nullptr, nullptr);
        drawGrid(renderer, game_textures[0], 0);
        int width = 0, height = 0;
        SDL_QueryTexture(game_textures[0], nullptr, nullptr, &width, &height);
        int window_x = (1280/2) - (width/2);
        SDL_Rect rc = {window_x, 0, width, height};
        SDL_RenderCopy(renderer, game_textures[0], nullptr, &rc);

        drawGrid(renderer, game_textures[1], 1);
        SDL_QueryTexture(game_textures[1], nullptr, nullptr, &width, &height);
        window_x = 32;
        int window_y = (720/2) - (height/2);
        SDL_Rect rc2 = { window_x, window_y, width, height };
        SDL_RenderCopyEx(renderer, game_textures[1], nullptr, &rc2, -90.0, nullptr, SDL_FLIP_NONE);  
        
        drawGrid(renderer, game_textures[2], 2);
        SDL_QueryTexture(game_textures[2], nullptr, nullptr, &width, &height);
        window_x = (1280/2) - (width/2);
        window_y = (720/2)+5;
        SDL_Rect rc3 = { window_x, window_y, width, height };
        SDL_RenderCopyEx(renderer, game_textures[2], nullptr, &rc3, 0, nullptr, SDL_FLIP_VERTICAL);  
        
        drawGrid(renderer, game_textures[3], 3);
        SDL_QueryTexture(game_textures[3], nullptr, nullptr, &width, &height);
        window_x = (1280)-width -32;
        window_y = (720/2)-(height/2);
        SDL_Rect rc4 = { window_x, window_y, width, height };
        SDL_RenderCopyEx(renderer, game_textures[3], nullptr, &rc4, 90.0, nullptr, SDL_FLIP_HORIZONTAL);  

        util::printText(renderer, font, 25, 25, "Level: " + std::to_string(game.level+1) + " Timeout: " + std::to_string(game.timeout), {255, 255, 255, 255});
        util::printText(renderer, font, 25, 55, "Score: " + std::to_string(game.score), {255,255,255,255});
        util::printText(renderer, font, 25, 85, "Direction: " + std::to_string(cur_focus), {255, 255, 255, 255});
        
        
        twistColors();

        static Uint32 previous_time = SDL_GetTicks();
        Uint32 current_time = SDL_GetTicks();
        if (current_time - previous_time >= game.timeout) {
            if(game.grid[cur_focus].canMoveDown()) {
                game.grid[cur_focus].game_piece.moveDown();
                previous_time = current_time;
            } else {
                obj::setObject(new obj::GameOverObject(game.score, game.clears));
                obj::object->load(renderer);
                return;
            }
        }

        for(auto &c : util::stick) {
            handleControllerButtonRepeat(c, cur_focus, current_time);
        }
    }

    void PuzzleObject::handleControllerButtonRepeat(SDL_GameController *controller, int cur_focus, Uint32 current_time) {
        for (auto &entry : button_states) {
            SDL_GameControllerButton button = entry.first;
            ButtonState &state = entry.second;

            if (state.is_pressed) {
                if (current_time - state.last_repeat_time >= REPEAT_INTERVAL) {
                    procDPad(cur_focus, button);
                    state.last_repeat_time = current_time;
                }
            }
        }
    }

    void PuzzleObject::procStick(int cur_focus, int x_axis, int y_axis) {
        const int DEADZONE = 8000;
        if (cur_focus == 0) {
            if (x_axis < -DEADZONE) {
                game.grid[cur_focus].game_piece.moveLeft();
            } else if (x_axis > DEADZONE) {
                game.grid[cur_focus].game_piece.moveRight();
            }
            if (y_axis > DEADZONE) {
                game.grid[cur_focus].game_piece.moveDown();
            }
        } else if (cur_focus == 1) {
            if (y_axis > DEADZONE) {
                game.grid[cur_focus].game_piece.moveLeft();
            } else if (y_axis < -DEADZONE) {
                game.grid[cur_focus].game_piece.moveRight();
            }
            if (x_axis > DEADZONE) {
                game.grid[cur_focus].game_piece.moveDown();
            }
        } else if (cur_focus == 2) {
            if (x_axis > DEADZONE) {
                game.grid[cur_focus].game_piece.moveRight();
            } else if (x_axis < -DEADZONE) {
                game.grid[cur_focus].game_piece.moveLeft();
            }

            if (y_axis < -DEADZONE) {
                game.grid[cur_focus].game_piece.moveDown();
            }
        } else if (cur_focus == 3) {
            if (y_axis > DEADZONE) {
                game.grid[cur_focus].game_piece.moveLeft();
            } else if (y_axis < -DEADZONE) {
                game.grid[cur_focus].game_piece.moveRight();
            }

            if (x_axis < -DEADZONE) {
                game.grid[cur_focus].game_piece.moveDown();
            }
        }
    }

    void PuzzleObject::procDPad(int cur_focus, int button) {
        switch (cur_focus) {
            case 0:
                if (button == SDL_CONTROLLER_BUTTON_DPAD_LEFT) {
                    game.grid[cur_focus].game_piece.moveLeft();
                } else if (button == SDL_CONTROLLER_BUTTON_DPAD_RIGHT) {
                    game.grid[cur_focus].game_piece.moveRight();
                }
                if (button == SDL_CONTROLLER_BUTTON_DPAD_DOWN) {
                    game.grid[cur_focus].game_piece.moveDown();
                }
                break;
            case 1:
                if (button == SDL_CONTROLLER_BUTTON_DPAD_DOWN) {
                    game.grid[cur_focus].game_piece.moveLeft();
                } else if (button == SDL_CONTROLLER_BUTTON_DPAD_UP) {
                    game.grid[cur_focus].game_piece.moveRight();
                }
                if (button == SDL_CONTROLLER_BUTTON_DPAD_RIGHT) {
                    game.grid[cur_focus].game_piece.moveDown();
                }
                break;
            case 2:
                if (button == SDL_CONTROLLER_BUTTON_DPAD_RIGHT) {
                    game.grid[cur_focus].game_piece.moveRight();
                } else if (button == SDL_CONTROLLER_BUTTON_DPAD_LEFT) {
                    game.grid[cur_focus].game_piece.moveLeft();
                }
                if (button == SDL_CONTROLLER_BUTTON_DPAD_UP) {
                    game.grid[cur_focus].game_piece.moveDown();
                }
                break;
            case 3:
                if (button == SDL_CONTROLLER_BUTTON_DPAD_DOWN) {
                    game.grid[cur_focus].game_piece.moveLeft();
                } else if (button == SDL_CONTROLLER_BUTTON_DPAD_UP) {
                    game.grid[cur_focus].game_piece.moveRight();
                }
                if (button == SDL_CONTROLLER_BUTTON_DPAD_LEFT) {
                    game.grid[cur_focus].game_piece.moveDown();
                }
                break;
            default:
                break;
        }

        switch(button) {
            case SDL_CONTROLLER_BUTTON_A:
            game.grid[cur_focus].game_piece.shiftColors();
            break;
            case SDL_CONTROLLER_BUTTON_B:
            game.grid[cur_focus].game_piece.shiftDirection();
            break;
            case SDL_CONTROLLER_BUTTON_Y:
            game.grid[cur_focus].game_piece.drop();
            break;
        }
    }

    void PuzzleObject::procHat(int cur_focus, int value) {
        if(cur_focus == 0) {
                switch(value) {
                    case 8:
                        game.grid[cur_focus].game_piece.moveLeft();
                    break;
                    case 2:
                        game.grid[cur_focus].game_piece.moveRight(); 
                    break;
                    case 4:
                        game.grid[cur_focus].game_piece.moveDown();
                    break;
                    default:
                    break;
                }

            } else if(cur_focus == 1) {
                switch(value) {
                    case 4:
                        game.grid[cur_focus].game_piece.moveLeft();
                    break;
                    case 1:
                        game.grid[cur_focus].game_piece.moveRight();     
                    break;
                    case 2:
                        game.grid[cur_focus].game_piece.moveDown();
                    break;
                    default:
                    break;
                }

            } else if(cur_focus == 2) {
                switch(value) {
                    case 1:
                        game.grid[cur_focus].game_piece.moveDown();     
                    break;
                    case 8:
                        game.grid[cur_focus].game_piece.moveLeft(); 
                    break;
                    case 2:
                        game.grid[cur_focus].game_piece.moveRight();
                    break;
                    default:
                    break;
                }
            } else if(cur_focus == 3) {
                switch(value) {
                    case 4:
                        game.grid[cur_focus].game_piece.moveLeft();
                    break;
                    case 1:
                        game.grid[cur_focus].game_piece.moveRight();     
                    break;
                    case 8:
                        game.grid[cur_focus].game_piece.moveDown(); 
                    break;
                    default:
                    break;
                }
            }
    }

    void PuzzleObject::event(SDL_Renderer *renderer, SDL_Event &e) {

        util::connectJoystick(e);

        static bool isDragging = false;
        static SDL_Point lastMousePos = {0, 0};
        static int screenWidth = 1280;
        static int screenHeight = 720;

        if (!paused) {
            if (e.type == SDL_KEYDOWN && e.key.keysym.sym == SDLK_p) {
                paused = true;
                return;
            }
        } else {
            if (e.type == SDL_KEYDOWN && e.key.keysym.sym == SDLK_SPACE) {
                paused = false;
            }
            return;
        }

        if (e.type == SDL_KEYDOWN && e.key.keysym.sym == SDLK_s) {
            game.grid[cur_focus].game_piece.drop();
            return;
        }

        Uint32 current_time = SDL_GetTicks();

        switch (e.type) {
            case SDL_CONTROLLERBUTTONDOWN: {
                SDL_GameControllerButton button = static_cast<SDL_GameControllerButton>(e.cbutton.button);
                button_states[button] = { true, current_time + REPEAT_DELAY };
                break;
            }
            case SDL_CONTROLLERBUTTONUP: {
                SDL_GameControllerButton button = static_cast<SDL_GameControllerButton>(e.cbutton.button);
                button_states[button].is_pressed = false;
                break;
            }
                case SDL_KEYDOWN:
                    if(e.key.keysym.sym == SDLK_w) {
                        game.grid[cur_focus].game_piece.shiftColors();
                        return;
                    }

                    if (cur_focus == 0) {
                        switch (e.key.keysym.sym) {
                            case SDLK_LEFT:
                                game.grid[cur_focus].game_piece.moveLeft();
                                break;
                            case SDLK_RIGHT:
                                game.grid[cur_focus].game_piece.moveRight();
                                break;
                            case SDLK_UP:
                                game.grid[cur_focus].game_piece.shiftColors();
                                break;
                            case SDLK_DOWN:
                                game.grid[cur_focus].game_piece.moveDown();
                                break;
                            case SDLK_a:
                            case SDLK_SPACE:
                                game.grid[cur_focus].game_piece.shiftDirection();
                                break;
                            default:
                                break;
                        }
                    } else if (cur_focus == 1) {
                        switch (e.key.keysym.sym) {
                            case SDLK_DOWN:
                                game.grid[cur_focus].game_piece.moveLeft();
                                break;
                            case SDLK_UP:
                                game.grid[cur_focus].game_piece.moveRight();
                                break;
                            case SDLK_LEFT:
                                game.grid[cur_focus].game_piece.shiftColors();
                                break;
                            case SDLK_RIGHT:
                                game.grid[cur_focus].game_piece.moveDown();
                                break;
                            case SDLK_a:
                            case SDLK_SPACE:
                                game.grid[cur_focus].game_piece.shiftDirection();
                                break;
                            default:
                                break;
                        }
                    } else if (cur_focus == 2) {
                        switch (e.key.keysym.sym) {
                            case SDLK_DOWN:
                                game.grid[cur_focus].game_piece.shiftColors();
                                break;
                            case SDLK_UP:
                                game.grid[cur_focus].game_piece.moveDown();
                                break;
                            case SDLK_LEFT:
                                game.grid[cur_focus].game_piece.moveLeft();
                                break;
                            case SDLK_RIGHT:
                                game.grid[cur_focus].game_piece.moveRight();
                                break;
                            case SDLK_a:
                            case SDLK_SPACE:
                                game.grid[cur_focus].game_piece.shiftDirection();
                                break;
                            default:
                                break;
                        }
                    } else if (cur_focus == 3) {
                        switch (e.key.keysym.sym) {
                            case SDLK_DOWN:
                                game.grid[cur_focus].game_piece.moveLeft();
                                break;
                            case SDLK_UP:
                                game.grid[cur_focus].game_piece.moveRight();
                                break;
                            case SDLK_LEFT:
                                game.grid[cur_focus].game_piece.moveDown();
                                break;
                            case SDLK_RIGHT:
                                game.grid[cur_focus].game_piece.shiftColors();
                                break;
                            case SDLK_a:
                            case SDLK_SPACE:
                                game.grid[cur_focus].game_piece.shiftDirection();
                                break;
                            default:
                                break;
                        }
                    }
                break;
            case SDL_MOUSEBUTTONDOWN: {
                if (e.button.button == SDL_BUTTON_LEFT) {
                    isDragging = true;
                    Uint32 currentTime = SDL_GetTicks();
                    int x = e.button.x;
                    int y = e.button.y;
                    if (currentTime - lastTapTime > DOUBLE_TAP_THRESHOLD) {
                        lastTapTime = 0;
                    }
                    if (currentTime - lastTapTime <= DOUBLE_TAP_THRESHOLD &&
                        abs(x - lastTapPos.x) <= DOUBLE_TAP_DISTANCE &&
                        abs(y - lastTapPos.y) <= DOUBLE_TAP_DISTANCE) {
                        handleDoubleTap({x, y});
                        lastTapTime = 0;
                    } else {
                        lastTapTime = currentTime;
                        lastTapPos = {x, y};
                    }

                    lastMousePos = { e.button.x, e.button.y };
                    swipeStartPos = lastMousePos;
                    swipeStartTime = SDL_GetTicks();
                    moveBlockToPosition(lastMousePos);
                }
                break;
            }

            case SDL_MOUSEBUTTONUP: {
                if (e.button.button == SDL_BUTTON_LEFT) {
                    isDragging = false;
                    SDL_Point mouseEndPos = { e.button.x, e.button.y };
                    Uint32 swipeEndTime = SDL_GetTicks();
                    detectSwipe(swipeStartPos, mouseEndPos, swipeStartTime, swipeEndTime);
                }
                break;
            }

            case SDL_MOUSEMOTION: {
                if (isDragging) {
                    SDL_Point currentMousePos = { e.motion.x, e.motion.y };
                    moveBlockToPosition(currentMousePos);
                    lastMousePos = currentMousePos;
                }
                break;
            }
            case SDL_FINGERDOWN: {
                int x = static_cast<int>(e.tfinger.x * screenWidth);
                int y = static_cast<int>(e.tfinger.y * screenHeight);
                Uint32 currentTime = SDL_GetTicks();

                if (isTapPending) {
                    if (currentTime - lastTapTime <= DOUBLE_TAP_THRESHOLD &&
                        abs(x - lastTapPos.x) <= DOUBLE_TAP_DISTANCE &&
                        abs(y - lastTapPos.y) <= DOUBLE_TAP_DISTANCE) {
                        handleDoubleTap({x, y});
                        isTapPending = false;
                        lastTapTime = 0;
                    } else {
                        handleSingleTap({lastTapPos.x, lastTapPos.y});
                        isTapPending = false;
                        lastTapTime = currentTime;
                        lastTapPos = {x, y};
                    }
                } else {
                    isTapPending = true;
                    lastTapTime = currentTime;
                    lastTapPos = {x, y};
                    SDL_AddTimer(DOUBLE_TAP_THRESHOLD, [](Uint32 interval, void* param) -> Uint32 {
                        PuzzleObject* self = static_cast<PuzzleObject*>(param);
                        if (self->isTapPending) {
                            self->handleSingleTap(self->lastTapPos);
                            self->isTapPending = false;
                        }
                        return 0; 
                    }, this);
                }
                break;
            }
            case SDL_FINGERUP: {
                if (isDragging) {
                    isDragging = false;
                    int x = static_cast<int>(e.tfinger.x * screenWidth);
                    int y = static_cast<int>(e.tfinger.y * screenHeight);
                    SDL_Point touchEndPos = { x, y };
                    Uint32 swipeEndTime = SDL_GetTicks();
                    detectSwipe(swipeStartPos, touchEndPos, swipeStartTime, swipeEndTime);
                }
            }
                break;

            case SDL_FINGERMOTION: {
                isDragging = true;
                int x = static_cast<int>(e.tfinger.x * screenWidth);
                int y = static_cast<int>(e.tfinger.y * screenHeight);
                lastMousePos = { x, y };
                moveBlockToPosition(lastMousePos);
            }
            break;

            default:
                break;
        }
    }

    void PuzzleObject::detectSwipe(SDL_Point startPos, SDL_Point endPos, Uint32 startTime, Uint32 endTime) {
        int deltaX = endPos.x - startPos.x;
        int deltaY = endPos.y - startPos.y;
        Uint32 deltaTime = endTime - startTime;
 
        if (deltaTime > SWIPE_TIME_THRESHOLD) {
            return;
        }

        if (abs(deltaX) < SWIPE_DISTANCE_THRESHOLD && abs(deltaY) < SWIPE_DISTANCE_THRESHOLD) {
            return;
        }

        SwipeDirection swipeDir = SWIPE_NONE;
        if (abs(deltaX) > abs(deltaY)) {
            swipeDir = (deltaX > 0) ? SWIPE_RIGHT : SWIPE_LEFT;
        } else {
            swipeDir = (deltaY > 0) ? SWIPE_DOWN : SWIPE_UP;
        }
        if (isDropSwipe(swipeDir)) {
            game.grid[cur_focus].game_piece.drop();
        }
        if(isSwitchSwipe(swipeDir)) {
            game.grid[cur_focus].game_piece.shiftColors();
        }
    }

    void PuzzleObject::handleDoubleTap(SDL_Point p) {
        game.grid[cur_focus].game_piece.shiftDirection();
    }

    bool PuzzleObject::isDropSwipe(SwipeDirection swipeDir) {
        switch (cur_focus) {
            case 0: 
                return swipeDir == SWIPE_DOWN;
            case 1: 
                return swipeDir == SWIPE_RIGHT;
            case 2: 
                return swipeDir == SWIPE_UP;
            case 3: 
                return swipeDir == SWIPE_LEFT;
            default:
                return false;
        }
    }

    void PuzzleObject::handleSingleTap(SDL_Point tapPos) {
    }

    bool PuzzleObject::isSwitchSwipe(SwipeDirection swipeDir) {
        switch (cur_focus) {
            case 0: 
                return swipeDir == SWIPE_UP;
            case 1: 
                return swipeDir == SWIPE_LEFT;
            case 2: 
                return swipeDir == SWIPE_DOWN;
            case 3: 
                return swipeDir == SWIPE_RIGHT;
            default:
                return false;
        }
    }


    void PuzzleObject::moveBlockToPosition(SDL_Point position) {
        const int cellWidth = 32;    
        const int cellHeight = 16;   
        int gridOffsetX = 0;         
        int gridOffsetY = 0;         
        switch(cur_focus) {
            case 0: { 
                int gridWidth = game.grid[0].width();
                gridOffsetX = (1280 / 2) - ((gridWidth * cellWidth) / 2);
                gridOffsetY = 0;
                break;
            }
            case 1: { 
                int gridWidth = game.grid[1].width();
                gridOffsetX = 32;
                gridOffsetY = (720 / 2) - ((gridWidth * cellHeight) / 2); 
                break;
            }
            case 2: { 
                int gridWidth = game.grid[2].width();
                gridOffsetX = (1280 / 2) - ((gridWidth * cellWidth) / 2);
                gridOffsetY = (720 / 2) + 5;
                break;
            }
            case 3: { 
                int gridWidth = game.grid[3].width();
                gridOffsetX = 1280 - (gridWidth * cellWidth) - 32;
                gridOffsetY = (720 / 2) - ((gridWidth * cellHeight) / 2); 
                break;
            }
            default:
                return; 
        }

        int gridX = 0;
        int gridY = 0;
        switch(cur_focus) {
            case 0: { 
                gridX = (position.x - gridOffsetX) / cellWidth;
                gridY = (position.y - gridOffsetY) / cellHeight;
                break;
            }
            case 1: { 
                gridX = (position.y - gridOffsetY) / cellHeight;
                gridY = (position.x - gridOffsetX) / cellWidth;
                gridY = game.grid[1].width() - 1 - gridY;
                break;
            }
            case 2: { 
                gridX = (position.x - gridOffsetX) / cellWidth;
                gridY = (position.y - gridOffsetY) / cellHeight;
                gridY = game.grid[2].height() - 1 - gridY;
                break;
            }
            case 3: { 
                gridX = (position.y - gridOffsetY) / cellHeight;
                gridY = (position.x - gridOffsetX) / cellWidth;
                gridY = game.grid[3].width() - 1 - gridY;
                break;
            }
        }
        gridX = std::max(0, std::min(gridX, game.grid[cur_focus].width() - 1));
        gridY = std::max(0, std::min(gridY, game.grid[cur_focus].height() - 1));
        if(cur_focus == 1 || cur_focus == 3 )
            game.grid[cur_focus].game_piece.setPosition(game.grid[1].width()-gridX-1, gridY);
        else
            game.grid[cur_focus].game_piece.setPosition(gridX, gridY);

    }


    void PuzzleObject::load(SDL_Renderer *renderer) {
        std::cout << "Mutatris: Game Init...\n";
        static const char *filenames[] = { "block_black.png", "block_clear.png", "block_dblue.png", "block_green.png", "block_ltblue.png", "block_orange.png", "block_red.png", "block_yellow.png", 0};
        for(int i = 0; filenames[i] != 0; ++i) {
            blocks.push_back(util::loadTexture(renderer, filenames[i]));
        }
        static const char *bg_filenames[] = {"blocks.png","blocks1.png","blocks2.png","blocks3.png", "blocks4.png", "blocks5.png", "blocks6.png", "blocks7.png", "blocks8.png", "blocks9.png", "blocks10.png", 0};
        for(int i = 0; bg_filenames[i] != 0; ++i) {
            backgrounds.push_back(util::loadTexture(renderer, bg_filenames[i]));
        }
        std::random_device rd;
        std::mt19937 rng(rd()); 
        std::shuffle(backgrounds.begin(), backgrounds.end(), rng);
        game.setCallback([&]() -> void {
            cur_focus++;
            if(cur_focus > 3)
                cur_focus = 0;
        });
        for(int i = 0; i <= 3; ++i) {
            game_textures[i] = SDL_CreateTexture(renderer, SDL_PIXELFORMAT_RGBA8888, SDL_TEXTUREACCESS_TARGET, 32 * game.grid[i].width(), 16 * game.grid[i].height());
            if(!game_textures[i]) {
               SDL_Log("Mutatris: Error creating grid texture..\n");
               return;
            }
        }
        font = util::loadFont("font.ttf", 32);
        pause_menu = util::loadTexture(renderer, "start.png");
        paused_large = util::loadFont("font.ttf", 44);
        paused_small = util::loadFont("font.ttf", 20);
      
    }
}