From ce0b5a4971be9226bd5c83410dacea128f81771a Mon Sep 17 00:00:00 2001 From: sanine-a Date: Fri, 23 Oct 2020 21:52:10 -0500 Subject: add key binding input functions --- demo/main.lua | 10 +- src/common.h | 31 + src/honey_lua.c | 184 ++++- src/input/input.c | 2041 +++++++++++++++++++++++++++-------------------------- src/input/input.h | 11 +- src/main.c | 153 ++-- 6 files changed, 1334 insertions(+), 1096 deletions(-) diff --git a/demo/main.lua b/demo/main.lua index ba548b9..ae0684e 100644 --- a/demo/main.lua +++ b/demo/main.lua @@ -4,10 +4,14 @@ end local total_time = 0 +local a_func = function(action, data) + print('a: ', action) +end + +honey.input.bind_key(honey.input.key.a, a_func) + function honey.update(dt) - if honey.input.is_down(honey.input.key.a) then - print('a pressed!') - end + end --function honey.draw() diff --git a/src/common.h b/src/common.h index bf9a528..66500eb 100644 --- a/src/common.h +++ b/src/common.h @@ -74,16 +74,47 @@ void honey_error_set_string2(char* string); */ void honey_human_readable_error(char* error_string, honey_result error); +/** @brief Generate a string from a format string. + * + * This function allocates memory for the destination; the user is + * responsible for deallocating it. As a side effect of this, the destination + * pointer cannot overlap with any of the varargs. + * + * @param[out] string Pointer to the destination string. + * @param[in] format_string The format string used to generate the result. + * @param[in] ... The arguments for the format string. + * + * @returns HONEY_OK on success; HONEY_MEMORY_ALLOCATION_ERROR on a + * memory allocation error. + */ +honey_result honey_format_string(char** string, + char* format_string, + ...); + /* lua binding functions */ typedef enum { + HONEY_BOOL, HONEY_INT, HONEY_NUM, HONEY_STRING, HONEY_FUNC, HONEY_TABLE, + HONEY_NIL, + HONEY_ANY } honey_lua_type; +/** @brief Check that a functions' arguments are of the correct type. + * + * @param[in] L The lua state to validate. + * @param[in] n_types The number of types to validate. + * @param[in] ... Variadic list of honey_lua_types to validate against the stack. + * + * @returns true if the validation was successful; false otherwise, pushing an error message + * to the lua stack. + */ +bool honey_lua_validate_types(lua_State* L, unsigned int n_types, ...); + /** @brief Wrap C objects for lua. */ typedef struct honey_lua_element { char* name; diff --git a/src/honey_lua.c b/src/honey_lua.c index 1cbd483..f397872 100644 --- a/src/honey_lua.c +++ b/src/honey_lua.c @@ -1,46 +1,192 @@ #include "common.h" +/* ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ */ + +honey_result honey_format_string(char** string, + char* format_string, + ...) +{ + honey_result res; + va_list args, args_; + va_start(args, format_string); + va_copy(args_, args); + + int string_size = vsnprintf(NULL, 0, format_string, args_); + va_end(args_); + *string = malloc((string_size+1) * sizeof(char)); + if (*string == NULL) + res = HONEY_MEMORY_ALLOCATION_ERROR; + else { + vsnprintf(*string, string_size+1, format_string, args); + res = HONEY_OK; + } + + va_end(args); + + return res; +} + +/* ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ */ + +bool honey_lua_validate_types(lua_State* L, + unsigned int n_types, + ...) +{ + va_list args; + va_start(args, n_types); + + for (int i=0; i= HONEY_N_KEYS) - lua_pushboolean(L, false); + lua_pushboolean(L, false); else - lua_pushboolean(L, honey_key_states[key]); + lua_pushboolean(L, honey_key_states[key]); - printf("check key %d: %d\n", key, honey_key_states[key]); - return 1; } /* ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ */ -void honey_key_bind(int key, - void (*callback)(void*, int), - void* data) +int honey_key_bind(lua_State* L) { + /* lua params: (int) key, (func) callback, (arb) data */ + int n_args = lua_gettop(L); + if (n_args == 3) { + if (!honey_lua_validate_types(L, 3, HONEY_INT, HONEY_FUNC, HONEY_ANY)) { + lua_error(L); + } + } + else if (n_args == 2) { + if (!honey_lua_validate_types(L, 2, HONEY_INT, HONEY_FUNC)) { + lua_error(L); + } + } + else { + char* error_message; + honey_format_string(error_message, "expected 2 or 3 arguments; received %d instead", n_args); + free(error_message); + lua_error(L); + } + + int key = lua_tointeger(L, 1); + lua_pushvalue(L, 2); + int callback = luaL_ref(L, LUA_REGISTRYINDEX); + lua_pushvalue(L, 3); + int data = luaL_ref(L, LUA_REGISTRYINDEX); + if (key >= 0 && key < HONEY_N_KEYS) { - honey_key_callbacks[key] = callback; - honey_key_callbacks_data[key] = data; + honey_key_callbacks[key] = callback; + honey_key_callbacks_data[key] = data; } + + return 0; } /* ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ */ -void honey_key_unbind(int key) +int honey_key_unbind(lua_State* L) { + /* lua params: (int) key */ + if (!honey_lua_validate_types(L, 1, HONEY_INT)) + lua_error(L); + + int key = lua_tointeger(L, 1); + if (key >=0 && key < HONEY_N_KEYS) { - honey_key_callbacks[key] = NULL; - honey_key_callbacks_data[key] = NULL; + honey_key_callbacks[key] = LUA_NOREF; + honey_key_callbacks_data[key] = LUA_NOREF; + } + else { + char* error_message; + honey_format_string(&error_message, "'%d' is not a valid keycode", key); + lua_pushstring(L, error_message); + free(error_message); + lua_error(L); } + return 0; } /* ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ */ -void honey_key_unbind_all() +int honey_key_unbind_all(lua_State* L) { for (int i=0; iverbose = true; - break; - - case 'h': - // print help - break; - - case '?': - if (isprint (optopt)) - fprintf (stderr, "Unknown option `-%c'.\n", optopt); - else - fprintf (stderr, - "Unknown option character `\\x%x'.\n", - optopt); - return false; - - default: - return false; - } + switch (c) { + case 'v': + opt->verbose = true; + break; + + case 'h': + // print help + break; + + case '?': + if (isprint (optopt)) + fprintf (stderr, "Unknown option `-%c'.\n", optopt); + else + fprintf (stderr, + "Unknown option character `\\x%x'.\n", + optopt); + return false; + + default: + return false; + } } if (optind < argc) { - opt->run = true; - opt->scriptdir = argv[optind]; + opt->run = true; + opt->scriptdir = argv[optind]; } return true; @@ -66,18 +66,18 @@ GLFWwindow* setup_window(int width, int height, char* title) GLFWwindow* window = glfwCreateWindow(width, height, title, NULL, NULL); if (window == NULL) { - fprintf(stderr, "ERROR: failed to create window!\n"); - glfwTerminate(); - return NULL; + fprintf(stderr, "ERROR: failed to create window!\n"); + glfwTerminate(); + return NULL; } glfwMakeContextCurrent(window); glfwSetInputMode(window, GLFW_CURSOR, GLFW_CURSOR_DISABLED); if (!gladLoadGLLoader((GLADloadproc) glfwGetProcAddress)) { - fprintf(stderr, "ERROR: failed to initialize GLAD!\n"); - glfwTerminate(); - return NULL; + fprintf(stderr, "ERROR: failed to initialize GLAD!\n"); + glfwTerminate(); + return NULL; } honey_setup_keyboard(); @@ -95,16 +95,19 @@ int main(int argc, char** argv) { struct options opt; if (!parse_options(&opt, argc, argv)) { - fprintf(stderr, "ERROR: failed to parse command line options!\n"); - return 1; + fprintf(stderr, "ERROR: failed to parse command line options!\n"); + return 1; } if (!opt.run) - return 0; + return 0; + printf("%d\n", LUA_NOREF); + GLFWwindow* window = setup_window(480, 320, "honey-engine"); lua_State* L = luaL_newstate(); + glfwSetWindowUserPointer(window, L); luaL_openlibs(L); lua_createtable(L, 0, 1); @@ -117,20 +120,20 @@ int main(int argc, char** argv) size_t dirlen = strlen(opt.scriptdir) + 10; char* scriptfile = malloc(sizeof(char) * dirlen); if (scriptfile == NULL) { - fprintf(stderr, "ERROR: failed to allocate memory for script file string!\n"); - return 1; + fprintf(stderr, "ERROR: failed to allocate memory for script file string!\n"); + return 1; } snprintf(scriptfile, dirlen, "%s/main.lua", opt.scriptdir); if (luaL_loadfile(L, scriptfile) == 0) { - if (lua_pcall(L, 0, 1, 0) == 0) { - lua_pop(L, lua_gettop(L)); - } + if (lua_pcall(L, 0, 1, 0) == 0) { + lua_pop(L, lua_gettop(L)); + } } else { - fprintf(stderr, "ERROR: failed to open %s!\n", scriptfile); - return 1; + fprintf(stderr, "ERROR: failed to open %s!\n", scriptfile); + return 1; } opt.has_update = has_function(L, "update"); @@ -141,41 +144,41 @@ int main(int argc, char** argv) float dt; while (!glfwWindowShouldClose(window)) { - currentTime = (float) glfwGetTime(); - dt = currentTime - prevTime; - prevTime = currentTime; - glfwPollEvents(); - - lua_getglobal(L, "honey"); - - if (opt.has_update) { - lua_getfield(L, -1, "update"); - if (lua_isfunction(L, -1)) { - lua_pushnumber(L, dt); - int result = lua_pcall(L, 1, 0, 0); - if (result != 0) { - glfwSetWindowShouldClose(window, true); - } - } - else { - lua_pop(L, 1); - } - } - - if (opt.has_draw) { - lua_getfield(L, -1, "draw"); - if (lua_isfunction(L, -1)) { - int result = lua_pcall(L, 0, 0, 0); - if (result != 0) { - glfwSetWindowShouldClose(window, true); - } - } - else { - lua_pop(L, 1); - } - } - - lua_pop(L, 1); + currentTime = (float) glfwGetTime(); + dt = currentTime - prevTime; + prevTime = currentTime; + glfwPollEvents(); + + lua_getglobal(L, "honey"); + + if (opt.has_update) { + lua_getfield(L, -1, "update"); + if (lua_isfunction(L, -1)) { + lua_pushnumber(L, dt); + int result = lua_pcall(L, 1, 0, 0); + if (result != 0) { + glfwSetWindowShouldClose(window, true); + } + } + else { + lua_pop(L, 1); + } + } + + if (opt.has_draw) { + lua_getfield(L, -1, "draw"); + if (lua_isfunction(L, -1)) { + int result = lua_pcall(L, 0, 0, 0); + if (result != 0) { + glfwSetWindowShouldClose(window, true); + } + } + else { + lua_pop(L, 1); + } + } + + lua_pop(L, 1); } lua_close(L); -- cgit v1.2.1