#define GL_GLEXT_PROTOTYPES
#define _USE_MATH_DEFINES

#include <uthash.h>

#if defined(_WIN32)
    #if defined(__GNUC__)
        #include <cpuid.h>
    #elif defined(_MSC_VER)
        #include <intrin.h>
    #endif
    //#define APIENTRY __stdcall
    #include <windows.h>
    #include <errno.h>
    #define GLEW_STATIC
    #include <GL/glew.h>
    //#include "glew/glew.h"
    //#include <GL/gl.h>
    //#include <GLES2/gl2.h>
    //#include <GLES2/gl2ext.h>
    //#define GLFW_INCLUDE_ES3
	#define GLFW_EXPOSE_NATIVE_WGL
    #define GLFW_EXPOSE_NATIVE_WIN
#else
    #include <GL/gl.h>
    //#include <GL/glext.h>
	#define GLFW_EXPOSE_NATIVE_X11
	#define GLFW_EXPOSE_NATIVE_GLX
#endif

#define GLFW_INCLUDE_NONE
#include <GLFW/glfw3.h>
#include <GLFW/glfw3native.h>

#include <stdio.h>
#include <stdlib.h>
#include <stdbool.h>

#include "linmathv2.h"

#include <math.h>
#ifndef M_PI
#define M_PI 3.14159265358979323846264338327950288
#endif
#define degToRad(angleInDegrees) ((angleInDegrees) * M_PI / 180.0)
#define radToDeg(angleInRadians) ((angleInRadians) * 180.0 / M_PI)

#define MIN(a,b) (((a)<(b))?(a):(b))
#define MAX(a,b) (((a)>(b))?(a):(b))
#define CLAMP(x, upper, lower) (MIN(upper, MAX(x, lower)))

#include "custom.h"

#include "input.h"
#include "shaders.h"
#include "text.h"
#include "player.h"
#include "sky.h"

vec3 up={0,1,0};

int invertControl=1;
//int should_render=1;

// moved to camera->theta
//float theta = 0.0f; // theta phi may be swapped
//float phi = 0.0f; // theta is horizontal angle
float x_input = 0.0f;
float y_input = 0.0f;
int is_moving = 0; // forward backward 
int is_turning = 0; // include strife if drag --
int is_elevating = 0;
// process all input: query GLFW whether relevant keys are pressed/released this frame and react accordingly
// ---------------------------------------------------------------------------------------------------------
float zoomDist = 3.0f; // set in custom.c InistializePlayer
float lastZoomDist = 0.0f;
bool readyZoomTog = false;
bool readyBlinkTog = false;
bool readyBlink = false;
bool readyManualSave = false;
bool readyResetPlayer = false;
bool readyPrintDetail = false;
bool shiftDown = false;
bool controlDown = false;
bool vDown = false;
float cubeScale = 0.25f;
bool readyCubeScale = false;
bool boundsTog = false; // start off
bool readyBoundsTog = false;
bool wireframeOn = false; // start off
bool readyWireframe = false;
bool gridOn = true; // start on
bool readyGrid = false;
int vsync = 1; // 1 = on, 2 = adaptive, 0 = off
bool readyVsync = false;
bool reloadShaders = false;
bool readyReloadShaders = false;
int fontIdx = 0; //
bool reloadFont = false;
bool readyReloadFont = false;
bool enableTracking = false;
bool readyTrackingTog = false;
bool readyPlayerTog = false;
bool hiddenTerrain = false;
int hiddenWater = 0;
int hiddenSky = 1; // default 1
int hiddenCloud = 1; // default 1
int readyHideTerrain = 0;
int readyHideWater = 0;
int readyHideSky = 0;
int readyHideCloud = 0;
int readyRendMode = 0;
bool readyWaterHeight = false;
bool waterHeightShow = false;

int keystrlen=30; // change below and in header as well
int printKeys() {
    for(int i=0;i<keystrlen;i++) {
        printf("> %s\n",keystr[i]);
    }
    printf("\n\n");
    return 0;
}
const char *keystr[30] = { // remember change in header too
    "W | ARROW_UP",
    "S | ARROW_DOWN",
    "A | ARROW_LEFT",
    "D | ARROW_RIGHT",
    "E Speed/Blink forward",
    "",
    "Esc | Q  Quit the program",
    "Space    Ascend/Jump",
    "LControl Descend",
    "LShift   Speed increase",
    "V        Change FOV with scroll",
    "Z        Toggle vsync 1-2-0",
    "X        Toggle first person/3rd person (same as scroll but remembers zoomDist)",
    "G        Toggle grid",
    "B        Toggle bounding boxes",
    "I        Toggle wireframe all",
    "T        Toggle tracking player",
    "H        Toggle player mode/free mode (fly)", // moveMode = 0 to start flying, modeMode = 1 start falling
    "P        Show water height map",
    "L        Cycle depth views",
    "F        Toggle fullscreen/window",
    "R        Reload shaders live",
    "O        Manual save game",
    "0        Reset player position/view",
    "1        Cycle cube(player) scales",
    "2        Cycle fonts",
    "3        Toggle Sky",
    "4        Toggle Clouds",
    "5        Toggle Terrain",
    "6        Toggle Water"
};

void processInput(GLFWwindow *window)
{
    struct Vec3 *pos = malloc(sizeof(struct Vec3));
    struct Vec3 *rot = malloc(sizeof(struct Vec3));
    bool updateTexts=false;
    // quit
    if (glfwGetKey(window, GLFW_KEY_ESCAPE) == GLFW_PRESS)
        glfwSetWindowShouldClose(window, true);
    if (glfwGetKey(window, GLFW_KEY_Q) == GLFW_PRESS)
        glfwSetWindowShouldClose(window, true);

    // move up down
    if (glfwGetKey(window, GLFW_KEY_W) == GLFW_PRESS ||
        glfwGetKey(window, GLFW_KEY_UP) == GLFW_PRESS) {
        
        updateTexts=true;
        is_moving=1;
    } else if (glfwGetKey(window, GLFW_KEY_S) == GLFW_PRESS ||
        glfwGetKey(window, GLFW_KEY_DOWN) == GLFW_PRESS) {
        
        updateTexts=true;
        is_moving=-1;
    } else if(is_moving != 0) {
        is_moving = 0; // forward/backward only
    }

    // move left right
    if (glfwGetKey(window, GLFW_KEY_A) == GLFW_PRESS ||
        glfwGetKey(window, GLFW_KEY_LEFT) == GLFW_PRESS) {
       
        updateTexts=true;
        is_turning = 1; 
    }
    if (glfwGetKey(window, GLFW_KEY_D) == GLFW_PRESS ||
        glfwGetKey(window, GLFW_KEY_RIGHT) == GLFW_PRESS) {
        
        updateTexts=true;
        is_turning = -1;
    }

    if (glfwGetKey(window, GLFW_KEY_SPACE) == GLFW_PRESS) {
        
        updateTexts=true;
        is_elevating = 1;
    } else if (glfwGetKey(window, GLFW_KEY_LEFT_CONTROL) == GLFW_PRESS) {
        
        updateTexts=true;
        is_elevating = -1;
        controlDown=true;
    } else if(is_elevating != 0) {
        is_elevating = 0; // forward/backward only
        controlDown=false;
    }
    if (glfwGetKey(window, GLFW_KEY_V) == GLFW_PRESS) {
        vDown=true;
    } else {
        vDown=false;
    }

    // live reload shaders
    if (glfwGetKey(window, GLFW_KEY_R) == GLFW_PRESS) {
        if(!readyReloadShaders) {
            readyReloadShaders=true;
            reloadShaders=true;
        }
    } else {
        readyReloadShaders=false;
    }

    if (glfwGetKey(window, GLFW_KEY_C) == GLFW_PRESS) {
        if(!readyPrintDetail) {
            printf("Print details;\n");
            printf("Player position: {%f,%f,%f}, scale: %f, phi: %f\n",player->transform->position->x,player->transform->position->y,player->transform->position->z,cubeScale,player->phi);
            printf("Camera position: {%f,%f,%f}, zoomDist: %f, theta: %f, phi: %f, xOffset: %f\n",camera->dir->forward->x,camera->dir->forward->y,camera->dir->forward->z,zoomDist,camera->theta,camera->phi,camera->xOffset);
            printf("\n");
            readyPrintDetail=true;
        }
    } else {
        readyPrintDetail=false;
    }

    if (glfwGetKey(window, GLFW_KEY_T) == GLFW_PRESS) {
        if(!readyTrackingTog) {
            readyTrackingTog=true;
            enableTracking=!enableTracking;
        }
    } else {
        readyTrackingTog=false;
    }

    // zoom in out
    if (glfwGetKey(window, GLFW_KEY_Z) == GLFW_PRESS) {
        if(readyVsync) {
            if(vsync == 1) { // adaptive
                vsync=2;
                glfwSwapInterval(-1);
            } else if(vsync == 0) { // on
                vsync=1;
                glfwSwapInterval(1);
            } else { // off
                vsync=0;
                glfwSwapInterval(0);
            }
            readyVsync=false;
        }
    } else {
        readyVsync=true;
    }
    if (glfwGetKey(window, GLFW_KEY_X) == GLFW_PRESS) {
        if(readyZoomTog) {
            if(zoomDist<1.0f) {
                zoomDist = lastZoomDist;
            } else {
                zoomDist = 0.01f;
            }
            readyZoomTog = false;
        }
    } else if(!readyZoomTog) {
        readyZoomTog=true;
    }

    if (glfwGetKey(window, GLFW_KEY_H) == GLFW_PRESS) {
        if(readyPlayerTog) {
            if(moveMode==0) { // moveMode in player.c
                moveMode=1;
            } else {
                moveMode=0;
            }
            readyPlayerTog=false;
        }
    } else if(!readyPlayerTog) {
        readyPlayerTog=true;
    }

    if (glfwGetKey(window, GLFW_KEY_B) == GLFW_PRESS) {
        if(readyBoundsTog) {
            boundsTog = !boundsTog;
            readyBoundsTog = false;
        }
    } else if(!readyBoundsTog) {
        readyBoundsTog=true;
    }
    if (glfwGetKey(window, GLFW_KEY_I) == GLFW_PRESS) {
        if(readyWireframe) {
            wireframeOn = !wireframeOn;

            readyWireframe = false;
        }
    } else if(!readyWireframe) {
        readyWireframe=true;
    }
    if (glfwGetKey(window, GLFW_KEY_O) == GLFW_PRESS) {
        if(readyManualSave) {
            saveGame();
            //saveCount=saveTime;
            float hhT = totalTime / 60 / 60;
            hh = floor(hhT);
            hhT -= hh;
            float mmT = hhT * 60;
            mm = floor(mmT);
            mmT -= mm;
            ss = mmT * 60;

            printf("[Manual] Game saved. (Game local time=%d:%02d:%02d\n",hh,mm,ss);

            readyManualSave = false;
        }
    } else if(!readyManualSave) {
        readyManualSave=true;
    }

    if (glfwGetKey(window, GLFW_KEY_E) == GLFW_PRESS) {
        if(readyBlinkTog) {
            readyBlink = true;

            readyBlinkTog = false;
        }
    } else if(!readyBlinkTog) {
        readyBlinkTog=true;
    }

    if (glfwGetKey(window, GLFW_KEY_L) == GLFW_PRESS) {
        if(readyRendMode) {
            rendMode++;
            if(rendMode>4) rendMode = 0;

            readyRendMode = false;
        }
    } else if(!readyRendMode) {
        readyRendMode=true;
    }
    if (glfwGetKey(window, GLFW_KEY_P) == GLFW_PRESS) {
        if(readyWaterHeight) {
            waterHeightShow = !waterHeightShow;

            readyWaterHeight = false;
        }
    } else if(!readyWaterHeight) {
        readyWaterHeight=true;
    }
    if (glfwGetKey(window, GLFW_KEY_G) == GLFW_PRESS) {
        if(readyGrid) {
            gridOn = !gridOn;

            readyGrid = false;
        }
    } else if(!readyGrid) {
        readyGrid=true;
    }
    if (glfwGetKey(window, GLFW_KEY_0) == GLFW_PRESS) {
        if(!readyResetPlayer) {
            readyResetPlayer=true;

            moveMode = 0; // free
            gridOn = 1;
            cubeScale = 0.25f;
            fontIdx = 0;
            wireframeOn = false;
            boundsTog = false;
            enableTracking = false;
            vsync = 1;
            rendMode = 0;
            waterHeightShow = false;
            FOV = 120;
            fovrad=degToRad(FOV);

            InitializePlayer();
        }
    } else if(readyResetPlayer) {
        readyResetPlayer=false;
    }
    if (glfwGetKey(window, GLFW_KEY_1) == GLFW_PRESS) {
        if(readyCubeScale) {
            if(cubeScale==5.0f) {
                cubeScale = 0.0f;
            } else if(cubeScale==0.0f) {
                cubeScale = 0.25f;
            } else if(cubeScale==3.0f) {
                cubeScale = 5.0f;
            } else if(cubeScale==2.0f) {
                cubeScale = 3.0f;
            } else if(cubeScale==1.0f) {
                cubeScale = 2.0f;
            } else if(cubeScale==0.5f) {
                cubeScale = 1.0f;
            } else if(cubeScale==0.25f) {
                cubeScale = 0.5f;
            }
            readyCubeScale = false;
        }
    } else if(!readyCubeScale) {
        readyCubeScale=true;
    }

    // live font reload
    if (glfwGetKey(window, GLFW_KEY_2) == GLFW_PRESS) {
        if(!readyReloadFont) {
            readyReloadFont=true;
            if(fontIdx==0) {
                fontIdx=1;
            } else if(fontIdx==1) {
                fontIdx=2;
            } else if(fontIdx==2) {
                fontIdx=3;
            } else if(fontIdx==3) {
                fontIdx=4;
            } else if(fontIdx==4) {
                fontIdx=0;
            }
            reloadFont = true;
        }
    } else {
        readyReloadFont=false;
    }


    if (glfwGetKey(window, GLFW_KEY_3) == GLFW_PRESS) {
        if(readyHideSky==0) {
            readyHideSky=1;
            if(hiddenSky==0) {
                hiddenSky=1;
            } else if(hiddenSky==1) {
                hiddenSky=2;
            } else {
                hiddenSky=0;
            }
        }
    } else if(readyHideSky==1) {
        readyHideSky=0;
    }

    if (glfwGetKey(window, GLFW_KEY_4) == GLFW_PRESS) {
        if(readyHideCloud==0) {
            readyHideCloud=1;
            if(hiddenCloud==0) {
                hiddenCloud=1;
            } else if(hiddenCloud==1) {
                hiddenCloud=0;
            }
        }
    } else if(readyHideCloud==1) {
        readyHideCloud=0;
    }

    if (glfwGetKey(window, GLFW_KEY_5) == GLFW_PRESS) {
        if(readyHideTerrain==0) {
            readyHideTerrain=1;
            hiddenTerrain=!hiddenTerrain;
        }
    } else if(readyHideTerrain==1) {
        readyHideTerrain=0;
    }

    if (glfwGetKey(window, GLFW_KEY_6) == GLFW_PRESS) {
        if(readyHideWater==0) {
            readyHideWater=1;
            if(hiddenWater==1) { // for also passing int to shader underwater
                hiddenWater=0;
            } else {
                hiddenWater=1;
            }
        }
    } else if(readyHideWater==1) {
        readyHideWater=0;
    }



    if (glfwGetKey(window, GLFW_KEY_F) == GLFW_PRESS) {
        if(readyFullScreen==0) {
            readyFullScreen=1;
        }
    } else if(readyFullScreen==2) {
        readyFullScreen=0;
    }


    // speed
    if (glfwGetKey(window, GLFW_KEY_LEFT_SHIFT) == GLFW_PRESS ||
        glfwGetKey(window, GLFW_KEY_RIGHT_SHIFT) == GLFW_PRESS) {
        speedMulti=2.0f;
        shiftDown = true;
    } else if(shiftDown) {
        speedMulti=1.0f;
        shiftDown = false;
    }


    if(updateTexts) {
        //// get direction temporary value normalized 0-1 
        //sprintf(campostext,"campos x=%f, y=%f, z=%f\n", camera->eye->position->x, camera->eye->position->y, camera->eye->position->z);
        //sprintf(camrottext,"playerpos x=%f, y=%f, z=%f\n", player->transform->position->x, player->transform->position->y, player->transform->position->z);
        //sprintf(camdirtext,"input X theta=%f, phi=%f, ?=%f\n", theta, phi, 0.0f);
        //rot->x=0.0f; rot->y=0.0f; rot->z=0.0f; pos->z=0.0f;
        //pos->x=0.0f; pos->y=50.0f;
        //UpdateText(7, pos, rot, 1.0f, Align.topleft);
        //pos->x=0.0f; pos->y=60.0f;
        //UpdateText(8, pos, rot, 1.0f, Align.topleft);
        //pos->x=0.0f; pos->y=70.0f;
        //UpdateText(9, pos, rot, 1.0f, Align.topleft);
    }

    free(pos);
    free(rot);
}

// glfw: whenever the window size changed (by OS or user resize) this callback function executes
// ---------------------------------------------------------------------------------------------
//void framebuffer_size_callback(__attribute__((unused)) GLFWwindow* window, __attribute__((unused)) int width, __attribute__((unused)) int height)
//{
    // make sure the viewport matches the new window dimensions; note that width and
    // height will be significantly larger than specified on retina displays.
    //SCR_WIDTH = width;
    //SCR_HEIGHT = height;
    //ratio = SCR_WIDTH / (float) SCR_HEIGHT;

    //glViewport(0, 0, width, height);

    //CreateFrameMsaa(1);

    //glUseProgram(0);
    //glUseProgram(programPost);
    //setUniform1i(&programPost, "viewport_width", SCR_WIDTH);
    //setUniform1i(&programPost, "viewport_height", SCR_HEIGHT);

    //rerenderText=1;
    //should_render = 1;
//}

int is_pressed = 0;
bool mouse_drag = false;
bool mouse_drag_started=false;
float lastMouseX, lastMouseY;
float lockMouseX, lockMouseY;
// glfw: whenever the mouse moves, this callback is called
// -------------------------------------------------------
//void mouse_mov_callback(GLFWwindow*, double xposIn, double yposIn)
void mouse_mov_callback(GLFWwindow* window, double xposIn, double yposIn)
{
    float xpos = (float)(xposIn);
    float ypos = (float)(yposIn);

    if(is_pressed>0) {
        if(!mouse_drag) {
            lockMouseX = xpos;
            lockMouseY = ypos;
            mouse_drag=true;
        }
    } else {
        if(mouse_drag) {
            mouse_drag=false;
            mouse_drag_started=false;
    
            glfwSetInputMode(window, GLFW_CURSOR, GLFW_CURSOR_NORMAL);
        }
    }

    float diffLockX = xpos - lockMouseX;
    float diffLockY = ypos - lockMouseY;
    //float diffLastX = xpos - lastMouseX;
    //float diffLastY = ypos - lastMouseY;

    struct Vec3 *pos = malloc(sizeof(struct Vec3));
    struct Vec3 *rot = malloc(sizeof(struct Vec3));

    bool updateTexts=false;
    if(mouse_drag) {
        if(!mouse_drag_started) {
            //sprintf(mousextext, "MX=%f, MY=%f", xpos, ypos);
            updateTexts=true;

            if(diffLockX > 2.0f || diffLockX< -2.0f ||
                diffLockY > 2.0f || diffLockY < -2.0f) {
                mouse_drag_started=true;
            
                glfwSetInputMode(window, GLFW_CURSOR, GLFW_CURSOR_HIDDEN);

                //glfwSetCursorPos(window, lockMouseX, lockMouseY);
            }
        } else {
            //sprintf(mousextext, "MX=%f [DX=%f], MY=%f [DY=%f]", xpos, diffLockX, ypos, diffLockY);
            updateTexts=true;

            glfwSetCursorPos(window, lockMouseX, lockMouseY);

            x_input = diffLockX;
            y_input = diffLockY;

            camera->eye->rotation->x = x_input; // for sprintf
            camera->eye->rotation->y = y_input;

            lastMouseX = xpos;
            lastMouseY = ypos;
        }
    } else {
        //sprintf(mousextext, "MX=%f, MY=%f", xpos, ypos);
        updateTexts=true;
    }
    
    if(updateTexts) {
        //// mousextext
        //rot->x=0.0f; rot->y=0.0f; rot->z=0.0f; pos->z=0.0f;
        //pos->x=0.0f; pos->y=20.0f;
        //UpdateText(4, pos, rot, 1.0f, Align.topleft);

        //sprintf(campostext,"campos x=%f, y=%f, z=%f\n", camera->eye->position->x, camera->eye->position->y, camera->eye->position->z);
        //sprintf(camrottext,"playerpos x=%f, y=%f, z=%f\n", player->transform->position->x, player->transform->position->y, player->transform->position->z);
        //sprintf(camdirtext,"input M theta=%f, phi=%f, ?=%f\n", theta, phi, 0.0f);
        //rot->x=0.0f; rot->y=0.0f; rot->z=0.0f; pos->z=0.0f;
        //pos->x=0.0f; pos->y=50.0f;
        //UpdateText(7, pos, rot, 1.0f, Align.topleft);
        //pos->x=0.0f; pos->y=60.0f;
        //UpdateText(8, pos, rot, 1.0f, Align.topleft);
        //pos->x=0.0f; pos->y=70.0f;
        //UpdateText(9, pos, rot, 1.0f, Align.topleft);
    }

    free(pos);
    free(rot);
}

bool click_ready = false;
bool LMB_press = false;
bool RMB_press = false;
int click_trace = 0;

//void mouse_btn_callback(GLFWwindow *window, int button, int action, int mods)
void mouse_btn_callback(GLFWwindow *window, int button, int action, __attribute__((unused)) int mods)
{
                
    struct Vec3 *pos = malloc(sizeof(struct Vec3));
    struct Vec3 *rot = malloc(sizeof(struct Vec3));

    bool updateTexts=false;
    if (button == GLFW_MOUSE_BUTTON_LEFT && action == GLFW_PRESS)
    {
        if(!LMB_press) {
            LMB_press = true;

            if(!RMB_press) {
                click_ready = true;
            }
        }
    } else if (button == GLFW_MOUSE_BUTTON_LEFT && action == GLFW_REPEAT) {
        // holding
        if(!LMB_press)
            LMB_press = true;
        } else if (button == GLFW_MOUSE_BUTTON_LEFT && action == GLFW_RELEASE) {
            if(LMB_press) {
                LMB_press = false;

                if(!RMB_press && click_ready) {
                    //sprintf(mouseetext, "MouseAction=LMB (Click)");
                    updateTexts=true;
                    click_trace = 1;
                    double xposition, yposition;
                    glfwGetCursorPos(window, &xposition, &yposition);
                    lockMouseX = (float)xposition;
                    lockMouseY = (float)yposition;

                    is_pressed = false;
                    //mouse_drag=true;
                    mouse_drag=false;
                    mouse_drag_started=false;
                }
                click_ready = false;
                glfwSetInputMode(window, GLFW_CURSOR, GLFW_CURSOR_NORMAL);
            }
        }
        
        if (button == GLFW_MOUSE_BUTTON_RIGHT && action == GLFW_PRESS)
        {
            if(!RMB_press) {
                RMB_press = true;

                if(!LMB_press) {
                    click_ready = true;
                }
            }
        }
    else if (button == GLFW_MOUSE_BUTTON_RIGHT && action == GLFW_REPEAT)
    {
        // holding
        if(!RMB_press)
            RMB_press = true;
    }
    else if (button == GLFW_MOUSE_BUTTON_RIGHT && action == GLFW_RELEASE)
    {
        if(RMB_press) {
            RMB_press = false;

            if(!LMB_press && click_ready) {
                //sprintf(mouseetext, "MouseAction=RMB (Click)");
                updateTexts=true;
                click_trace = 2;
                double xposition, yposition;
                glfwGetCursorPos(window, &xposition, &yposition);
                lockMouseX = (float)xposition;
                lockMouseY = (float)yposition;

                is_pressed = false;
                //mouse_drag=true;
                mouse_drag=false;
                mouse_drag_started=false;
            }
            click_ready = false;
            glfwSetInputMode(window, GLFW_CURSOR, GLFW_CURSOR_NORMAL);
        }
    }

    if(LMB_press && RMB_press)
    {
        if(is_pressed!=3) {
            is_pressed = 3;

            //sprintf(mouseetext, "MouseAction=LMB+RMB");
            updateTexts=true;
        }
    }
    else if(RMB_press)
    {
        if(is_pressed!=2) {
            is_pressed = 2;

            //sprintf(mouseetext, "MouseAction=RMB");
            updateTexts=true;
        }
    }
    else if(LMB_press)
    {
        if(is_pressed!=1) {
            is_pressed = 1;

            //sprintf(mouseetext, "MouseAction=LMB");
            updateTexts=true;
        }
    }
    else
    {
        if(is_pressed!=0) {
            is_pressed = 0;
            
            if(!click_ready) {
                //sprintf(mouseetext, "MouseAction=none");
                updateTexts=true;
            }

            if(mouse_drag) {
                mouse_drag=false;
                mouse_drag_started=false;

                glfwSetInputMode(window, GLFW_CURSOR, GLFW_CURSOR_NORMAL);
            }
        }
    }

    if(updateTexts) {
        //// mouseetext
        //rot->x=0.0f; rot->y=0.0f; rot->z=0.0f; pos->z=0.0f;
        //pos->x=0.0f; pos->y=40.0f;
        //UpdateText(6, pos, rot, 1.0f, Align.topleft);

        //sprintf(campostext,"position M x=%f, y=%f, z=%f\n", camera->eye->position->x, camera->eye->position->y, camera->eye->position->z);
        //sprintf(camrottext,"playerpos x=%f, y=%f, z=%f\n", player->transform->position->x, player->transform->position->y, player->transform->position->z);
        ////sprintf(camdirtext,"direction M x=%f, y=%f, z=%f\n", camera->center->position->x, camera->center->position->y, camera->center->position->z);
        //sprintf(camdirtext,"direction MD x=%f, y=%f, z=%f\n", camera->center->rotation->x, camera->center->rotation->y, camera->center->rotation->z);
        //rot->x=0.0f; rot->y=0.0f; rot->z=0.0f; pos->z=0.0f;
        //pos->x=0.0f; pos->y=50.0f;
        //UpdateText(7, pos, rot, 1.0f, Align.topleft);
        //pos->x=0.0f; pos->y=60.0f;
        //UpdateText(8, pos, rot, 1.0f, Align.topleft);
        //pos->x=0.0f; pos->y=70.0f;
        //UpdateText(9, pos, rot, 1.0f, Align.topleft);
    }

    free(pos);
    free(rot);
}

//float scrollStep = 10.0f;
// glfw: whenever the mouse scroll wheel scrolls, this callback is called
// ----------------------------------------------------------------------
void scroll_callback(__attribute__((unused)) GLFWwindow* window, __attribute__((unused)) double xoffset, double yoffset)
{
    if(vDown) { // fov change
        if(yoffset<0) {
            FOV+=1.0f;
        } else if(yoffset>0) {
            FOV-=1.0f;
        }
        fovrad=degToRad(FOV);
        printf("new FOV set to %d degree (%f) [default 120]\n",FOV,fovrad);
    } else { // distance camera zoom
        if(yoffset<0) {
            zoomDist+=1.0f;
        } else if(yoffset>0) {
            zoomDist-=1.0f;
        }
        zoomDist=CLAMP(zoomDist,200.0f,0.01f);
        if(zoomDist<3.0f && zoomDist>2.0f) zoomDist = 2.0f; // reset 2.01
        
        lastZoomDist = zoomDist;
    }
}
