From 45ec13db451445821d667a516ff3d2134ba3c976 Mon Sep 17 00:00:00 2001 From: Shylie Date: Tue, 11 Jun 2024 00:40:43 -0400 Subject: [PATCH] Add mouse callbacks --- .gitignore | 4 +- examples/atlas.cpp | 6 +- examples/basic.cpp | 6 +- examples/rogue.cpp | 6 +- examples/towers.cpp | 6 +- include/glerminal.h | 55 +++++++++++------- lua-examples/basic/main.lua | 8 ++- source/glerminal-main.cpp | 111 ++++++++++++++++++++++++++++++++++-- source/glerminal-private.h | 8 ++- source/glerminal.cpp | 61 +++++++++++++++----- 10 files changed, 212 insertions(+), 59 deletions(-) diff --git a/.gitignore b/.gitignore index d163863..387849e 100644 --- a/.gitignore +++ b/.gitignore @@ -1 +1,3 @@ -build/ \ No newline at end of file +build/ +cmake-build-*/ +.idea/ \ No newline at end of file diff --git a/examples/atlas.cpp b/examples/atlas.cpp index 055212d..aad3932 100644 --- a/examples/atlas.cpp +++ b/examples/atlas.cpp @@ -9,9 +9,9 @@ namespace glerminal_load_sprites_file("resources/atlas.png"); } - void mainloop(float dt) + void mainloop(double dt) { - static float time = 1; + static double time = 1; time += dt; @@ -42,5 +42,5 @@ namespace int main(int argc, char** argv) { - glerminal_run(init, mainloop, nullptr, nullptr); + glerminal_run({init, mainloop}); } \ No newline at end of file diff --git a/examples/basic.cpp b/examples/basic.cpp index 0885d57..0e6e6d8 100644 --- a/examples/basic.cpp +++ b/examples/basic.cpp @@ -18,9 +18,9 @@ namespace } } - void mainloop(float dt) + void mainloop(double dt) { - static float time = 0; + static double time = 0; time += dt; time = fmodf(time, 3.1415926f * 2); @@ -39,5 +39,5 @@ namespace int main(int argc, char** argv) { - glerminal_run(init, mainloop, nullptr, nullptr); + glerminal_run({init, mainloop}); } \ No newline at end of file diff --git a/examples/rogue.cpp b/examples/rogue.cpp index 8e3e160..eaf2e37 100644 --- a/examples/rogue.cpp +++ b/examples/rogue.cpp @@ -43,9 +43,9 @@ namespace } } - void mainloop(float dt) + void mainloop(double dt) { - static float time = 0; + static double time = 0; time += dt; const float cx = GRID_WIDTH / 2.0f * cosf(time / 2) + GRID_WIDTH / 2.0f; @@ -80,5 +80,5 @@ namespace int main(int argc, char** argv) { - glerminal_run(init, mainloop, nullptr, nullptr); + glerminal_run({init, mainloop}); } \ No newline at end of file diff --git a/examples/towers.cpp b/examples/towers.cpp index 49e4ca5..ff5ee8e 100644 --- a/examples/towers.cpp +++ b/examples/towers.cpp @@ -34,9 +34,9 @@ namespace } } - void mainloop(float dt) + void mainloop(double dt) { - static float time = 0; + static double time = 0; time += dt; @@ -64,5 +64,5 @@ namespace int main(int argc, char** argv) { - glerminal_run(init, mainloop, nullptr, nullptr); + glerminal_run({init, mainloop}); } \ No newline at end of file diff --git a/include/glerminal.h b/include/glerminal.h index dafb7b9..b9d14bd 100644 --- a/include/glerminal.h +++ b/include/glerminal.h @@ -9,17 +9,24 @@ extern "C" #endif typedef void (*glerminal_init_cb)(); -typedef void (*glerminal_main_cb)(float dt); +typedef void (*glerminal_main_cb)(double dt); typedef void (*glerminal_keys_cb)(int key); +typedef void (*glerminal_mousemoved_cb)(double x, double y); +typedef void (*glerminal_mousepress_cb)(int button, double x, double y); + +typedef struct { + glerminal_init_cb init; + glerminal_main_cb main; + glerminal_keys_cb keypress, keyrelease; + glerminal_mousemoved_cb moved; + glerminal_mousepress_cb mousepress, mouserelease; +} glerminal_init_params; /** * @brief Call init once, then run the application's mainloop - * @param init initialization callback - * @param main main calllback - * @param pressed key pressed callback (can be null) - * @param released key released callback (can be null) + * @param params Initialization parameters */ -void glerminal_run(glerminal_init_cb init, glerminal_main_cb main, glerminal_keys_cb pressed, glerminal_keys_cb released); +void glerminal_run(glerminal_init_params params); void glerminal_quit(); @@ -30,39 +37,43 @@ void glerminal_flush(); /** * @brief Set a cell's sprite - * @param x position of the cell in the range [0, 40) - * @param y position of the cell in the range [0, 25) - * @param layer layer of the cell in the range [0, 8) - * @param sprite sprite's index in the range [0, 256) + * @param x position of the cell in the range [0, GRID_WIDTH) + * @param y position of the cell in the range [0, GRID_HEIGHT) + * @param layer layer of the cell in the range [0, LAYER_COUNT) + * @param sprite sprite's index in the range [0, 4096) */ void glerminal_set(unsigned char x, unsigned char y, unsigned char layer, unsigned short sprite); /** * @brief Get a cell's sprite - * @param x position of the cell in the range [0, 40) - * @param y position of the cell in the range [0, 25) - * @param layer layer of the cell in the range [0, 8) + * @param x position of the cell in the range [0, GRID_WIDTH) + * @param y position of the cell in the range [0, GRID_HEIGHT) + * @param layer layer of the cell in the range [0, LAYER_COUNT) * @return sprite index currently assigned to the cell */ unsigned char glerminal_get(unsigned char x, unsigned char y, unsigned short layer); /** * @brief Set a cell's offset - * @param x position of the cell in the range [0, 40) - * @param y position of the cell in the range [0, 25) - * @param layer layer of the cell in the range [0, 8) - * @param x_offset offset of the cell on the x axis in the range [-128, 127], where 0 is no offset - * @param y_offset offset of the cell on the y axis in the range [-128, 127], where 0 is no offset + * @param x position of the cell in the range [0, GRID_WIDTH) + * @param y position of the cell in the range [0, GRID_HEIGHT) + * @param layer layer of the cell in the range [0, LAYER_COUNT) + * @param x_offset offset of the cell on the x axis in cells + * @param y_offset offset of the cell on the y axis in cells */ void glerminal_offset(unsigned char x, unsigned char y, unsigned char layer, float x_offset, float y_offset); /** - * @brief Set a layer's color - * @param layer The layer to modify + * @brief Set a cell's color + * @param x position of the cell in the range [0, GRID_WIDTH) + * @param y position of the cell in the range [0, GRID_HEIGHT) + * @param layer layer of the cell in the range [0, LAYER_COUNT) * @param color The new color */ void glerminal_color(unsigned char x, unsigned char y, unsigned char layer, unsigned int color); /** - * @brief Set a layer's scale - * @param layer The layer to modify + * @brief Set a cell's scale + * @param x position of the cell in the range [0, GRID_WIDTH) + * @param y position of the cell in the range [0, GRID_HEIGHT) + * @param layer layer of the cell in the range [0, LAYER_COUNT) * @param scale The new scale */ void glerminal_scale(unsigned char x, unsigned char y, unsigned char layer, float scale); diff --git a/lua-examples/basic/main.lua b/lua-examples/basic/main.lua index c871817..8100b5a 100644 --- a/lua-examples/basic/main.lua +++ b/lua-examples/basic/main.lua @@ -26,4 +26,10 @@ function glerminal.main(dt) end glerminal.flush() -end \ No newline at end of file +end + +function glerminal.keypresse(key) end +function glerminal.keyrelease(key) end +function glerminal.mousemove(x, y) end +function glerminal.mousepress(button, x, y) end +function glerminal.mouserelease(button, x, y) end \ No newline at end of file diff --git a/source/glerminal-main.cpp b/source/glerminal-main.cpp index 32d6562..4197ac8 100644 --- a/source/glerminal-main.cpp +++ b/source/glerminal-main.cpp @@ -139,7 +139,7 @@ namespace lua_remove(L, handler); } - void mainloop(float dt) + void mainloop(double dt) { lua_pushcfunction(L, message_handler); const int handler = lua_gettop(L); @@ -155,7 +155,7 @@ namespace lua_remove(L, handler); } - void pressed(int key) + void keypressed(int key) { const char* const name = glfwGetKeyName(key, 0); if (name) @@ -163,7 +163,7 @@ namespace lua_pushcfunction(L, message_handler); const int handler = lua_gettop(L); lua_getglobal(L, "glerminal"); - lua_getfield(L, -1, "pressed"); + lua_getfield(L, -1, "keypress"); lua_remove(L, -2); lua_pushstring(L, name); if (lua_pcall(L, 1, 0, handler) != LUA_OK) @@ -175,7 +175,7 @@ namespace } } - void released(int key) + void keyrelease(int key) { const char* const name = glfwGetKeyName(key, 0); if (name) @@ -183,7 +183,7 @@ namespace lua_pushcfunction(L, message_handler); const int handler = lua_gettop(L); lua_getglobal(L, "glerminal"); - lua_getfield(L, -1, "released"); + lua_getfield(L, -1, "keyrelease"); lua_remove(L, -2); lua_pushstring(L, name); if (lua_pcall(L, 1, 0, handler) != LUA_OK) @@ -194,6 +194,97 @@ namespace lua_remove(L, handler); } } + + void mousemove(double x, double y) + { + lua_pushcfunction(L, message_handler); + const int handler = lua_gettop(L); + lua_getglobal(L, "glerminal"); + lua_getfield(L, -1, "mousemove"); + lua_remove(L, -2); + lua_pushnumber(L, x); + lua_pushnumber(L, y); + if (lua_pcall(L, 2, 0, handler) != LUA_OK) + { + std::cout << lua_tostring(L, -1) << std::endl; + lua_pop(L, 1); + } + lua_remove(L, handler); + } + + void mousepress(int button, double x, double y) + { + const char* button_name = nullptr; + switch (button) + { + case GLFW_MOUSE_BUTTON_LEFT: + button_name = "left"; + break; + + case GLFW_MOUSE_BUTTON_RIGHT: + button_name = "right"; + break; + + case GLFW_MOUSE_BUTTON_MIDDLE: + button_name = "middle"; + break; + } + + if (button_name) + { + lua_pushcfunction(L, message_handler); + const int handler = lua_gettop(L); + lua_getglobal(L, "glerminal"); + lua_getfield(L, -1, "mousepress"); + lua_remove(L, -2); + lua_pushstring(L, button_name); + lua_pushnumber(L, x); + lua_pushnumber(L, y); + if (lua_pcall(L, 3, 0, handler) != LUA_OK) + { + std::cout << lua_tostring(L, -1) << std::endl; + lua_pop(L, 1); + } + lua_remove(L, handler); + } + } + + void mouserelease(int button, double x, double y) + { + const char* button_name = nullptr; + switch (button) + { + case GLFW_MOUSE_BUTTON_LEFT: + button_name = "left"; + break; + + case GLFW_MOUSE_BUTTON_RIGHT: + button_name = "right"; + break; + + case GLFW_MOUSE_BUTTON_MIDDLE: + button_name = "middle"; + break; + } + + if (button_name) + { + lua_pushcfunction(L, message_handler); + const int handler = lua_gettop(L); + lua_getglobal(L, "glerminal"); + lua_getfield(L, -1, "mouserelease"); + lua_remove(L, -2); + lua_pushstring(L, button_name); + lua_pushnumber(L, x); + lua_pushnumber(L, y); + if (lua_pcall(L, 3, 0, handler) != LUA_OK) + { + std::cout << lua_tostring(L, -1) << std::endl; + lua_pop(L, 1); + } + lua_remove(L, handler); + } + } } int main(int argc, char** argv) @@ -232,7 +323,15 @@ int main(int argc, char** argv) } else { - glerminal_run(init, mainloop, pressed, released); + glerminal_init_params params; + params.init = init; + params.main = mainloop; + params.keypress = keypressed; + params.keyrelease = keyrelease; + params.moved = mousemove; + params.mousepress = mousepress; + params.mouserelease = mouserelease; + glerminal_run(params); } lua_close(L); diff --git a/source/glerminal-private.h b/source/glerminal-private.h index 805e047..6aa7004 100644 --- a/source/glerminal-private.h +++ b/source/glerminal-private.h @@ -27,7 +27,7 @@ namespace glerminal class glerminal { public: - glerminal(glerminal_init_cb init, glerminal_main_cb main, glerminal_keys_cb pressed, glerminal_keys_cb released); + explicit glerminal(glerminal_init_params params); ~glerminal(); glerminal(const glerminal&) = delete; @@ -83,7 +83,9 @@ namespace glerminal unsigned int m_sprites[(CELL_SIZE + 2) * (CELL_SIZE + 2) * MAX_SPRITES]; glerminal_main_cb m_main; - glerminal_keys_cb m_pressed, m_released; + glerminal_keys_cb m_keypressed, m_keyreleased; + glerminal_mousemoved_cb m_mousemoved; + glerminal_mousepress_cb m_mousepressed, m_mousereleased; #ifdef GLERMINAL_OPENGL_DEBUG_CONTEXT mutable std::ofstream m_log; @@ -101,6 +103,8 @@ namespace glerminal void update_scales(); static void glfw_key_handler(GLFWwindow* window, int key, int scancode, int action, int mods); + static void glfw_mousemoved_handler(GLFWwindow* window, double x, double y); + static void glfw_mousepress_handler(GLFWwindow* window, int button, int action, int mods); }; } diff --git a/source/glerminal.cpp b/source/glerminal.cpp index 7305a81..b7c4c36 100644 --- a/source/glerminal.cpp +++ b/source/glerminal.cpp @@ -189,10 +189,13 @@ namespace namespace glerminal { - glerminal::glerminal(glerminal_init_cb init, glerminal_main_cb main, glerminal_keys_cb pressed, glerminal_keys_cb released) : - m_main(main), - m_pressed(pressed), - m_released(released), + glerminal::glerminal(glerminal_init_params params) : + m_main(params.main), + m_keypressed(params.keypress), + m_keyreleased(params.keyrelease), + m_mousemoved(params.moved), + m_mousepressed(params.mousepress), + m_mousereleased(params.mouserelease), m_cells{ }, m_offsets{ }, m_sprites{ }, @@ -208,7 +211,7 @@ namespace glerminal } // unsure if this should be an error - if (!init) + if (!params.init) { throw std::runtime_error("No init callback provided."); } @@ -229,7 +232,7 @@ namespace glerminal GLERMINAL_G = this; - init(); + params.init(); } glerminal::~glerminal() @@ -242,12 +245,12 @@ namespace glerminal void glerminal::run() { - float last = glfwGetTime(); + double last = glfwGetTime(); while (!glfwWindowShouldClose(m_window)) { glfwPollEvents(); - const float current = glfwGetTime(); + const double current = glfwGetTime(); m_main(current - last); @@ -382,7 +385,9 @@ namespace glerminal } glfwSetWindowUserPointer(m_window, this); - glfwSetKeyCallback(m_window, glerminal::glfw_key_handler); + glfwSetKeyCallback(m_window, glfw_key_handler); + glfwSetCursorPosCallback(m_window, glfw_mousemoved_handler); + glfwSetMouseButtonCallback(m_window, glfw_mousepress_handler); } void glerminal::log(GLenum type, GLuint id, GLenum severity, const char* message) const @@ -780,23 +785,49 @@ namespace glerminal { glerminal* const self = static_cast(glfwGetWindowUserPointer(window)); - if (self->m_pressed && action == GLFW_PRESS) + if (self->m_keypressed && action == GLFW_PRESS) { - self->m_pressed(key); + self->m_keypressed(key); } - if (self->m_released && action == GLFW_RELEASE) + if (self->m_keyreleased && action == GLFW_RELEASE) { - self->m_released(key); + self->m_keyreleased(key); } } + + void glerminal::glfw_mousemoved_handler(GLFWwindow *window, double x, double y) + { + glerminal* const self = static_cast(glfwGetWindowUserPointer(window)); + + if (self->m_mousemoved) { self->m_mousemoved(x / CELL_SIZE, y / CELL_SIZE); } + } + + void glerminal::glfw_mousepress_handler(GLFWwindow *window, int button, int action, int mods) + { + glerminal* const self = static_cast(glfwGetWindowUserPointer(window)); + + double x, y; + glfwGetCursorPos(window, &x, &y); + + if (self->m_mousepressed && action == GLFW_PRESS) + { + self->m_mousepressed(button, x / CELL_SIZE, y / CELL_SIZE); + } + + if (self->m_mousereleased && action == GLFW_RELEASE) + { + self->m_mousereleased(button, x / CELL_SIZE, y / CELL_SIZE); + } + } + } -void glerminal_run(glerminal_init_cb init, glerminal_main_cb main, glerminal_keys_cb pressed, glerminal_keys_cb released) +void glerminal_run(glerminal_init_params params) { try { - glerminal::glerminal* g = new glerminal::glerminal(init, main, pressed, released); + glerminal::glerminal* g = new glerminal::glerminal(params); g->run(); delete g; }