diff --git a/src/event/event.c b/src/event/event.c index 5557c5d8..56d3e179 100644 --- a/src/event/event.c +++ b/src/event/event.c @@ -1,11 +1,53 @@ #include "event/event.h" -#include "lovr.h" #include "glfw.h" +#include -void lovrEventPoll() { - glfwPollEvents(); +static EventState state; + +static void onClose(GLFWwindow* _window) { + if (_window == window) { + EventType type = EVENT_QUIT; + EventData data = { .quit = { 0 } }; + Event event = { .type = type, .data = data }; + lovrEventPush(event); + } } -void lovrEventQuit(int exitCode) { - lovrDestroy(exitCode); +void lovrEventInit() { + vec_init(&state.pumps); + vec_init(&state.events); + lovrEventAddPump(glfwPollEvents); + glfwSetWindowCloseCallback(window, onClose); +} + +void lovrEventDestroy() { + vec_deinit(&state.pumps); + vec_deinit(&state.events); +} + +void lovrEventAddPump(EventPump pump) { + vec_push(&state.pumps, pump); +} + +void lovrEventPump() { + int i; EventPump pump; + vec_foreach(&state.pumps, pump, i) { + pump(); + } +} + +void lovrEventPush(Event event) { + vec_insert(&state.events, 0, event); +} + +Event* lovrEventPoll() { + if (state.events.length == 0) { + return NULL; + } + + return &vec_pop(&state.events); +} + +void lovrEventClear() { + vec_clear(&state.events); } diff --git a/src/event/event.h b/src/event/event.h index 4b033b62..eefd710b 100644 --- a/src/event/event.h +++ b/src/event/event.h @@ -1,2 +1,41 @@ -void lovrEventPoll(); -void lovrEventQuit(int exitCode); +#include + +#ifndef LOVR_EVENT_TYPES +#define LOVR_EVENT_TYPES + +typedef enum { + EVENT_QUIT +} EventType; + +typedef struct { + int exitCode; +} QuitEvent; + +typedef union { + QuitEvent quit; +} EventData; + +typedef struct { + EventType type; + EventData data; +} Event; + +typedef void (*EventPump)(void); + +typedef vec_t(EventPump) vec_pump_t; +typedef vec_t(Event) vec_event_t; + +typedef struct { + vec_pump_t pumps; + vec_event_t events; +} EventState; + +#endif + +void lovrEventInit(); +void lovrEventDestroy(); +void lovrEventAddPump(void (*pump)(void)); +void lovrEventPump(); +void lovrEventPush(Event event); +Event* lovrEventPoll(); +void lovrEventClear(); diff --git a/src/glfw.c b/src/glfw.c index 5b6a7375..48f88cf5 100644 --- a/src/glfw.c +++ b/src/glfw.c @@ -3,7 +3,11 @@ #include #include -void initGlfw(GLFWerrorfun onError, GLFWwindowclosefun onClose, void* userPointer) { +static void onError(int code, const char* description) { + error(description); +} + +void initGlfw() { glfwSetErrorCallback(onError); if (!glfwInit()) { @@ -14,7 +18,6 @@ void initGlfw(GLFWerrorfun onError, GLFWwindowclosefun onClose, void* userPointe glfwWindowHint(GLFW_CONTEXT_VERSION_MINOR, 1); glfwWindowHint(GLFW_OPENGL_PROFILE, GLFW_OPENGL_CORE_PROFILE); glfwWindowHint(GLFW_OPENGL_FORWARD_COMPAT, GL_TRUE); - //glfwWindowHint(GLFW_VISIBLE, GLFW_FALSE); window = glfwCreateWindow(800, 600, "Window", NULL, NULL); @@ -23,8 +26,6 @@ void initGlfw(GLFWerrorfun onError, GLFWwindowclosefun onClose, void* userPointe error("Could not create window"); } - glfwSetWindowCloseCallback(window, onClose); - glfwSetWindowUserPointer(window, userPointer); glfwMakeContextCurrent(window); #ifdef _WIN32 diff --git a/src/glfw.h b/src/glfw.h index 53e962ab..f89e367f 100644 --- a/src/glfw.h +++ b/src/glfw.h @@ -8,4 +8,4 @@ GLFWwindow* window; -void initGlfw(GLFWerrorfun onError, GLFWwindowclosefun onClose, void* userPointer); +void initGlfw(); diff --git a/src/lovr.c b/src/lovr.c index 3b0994f7..4b2b7662 100644 --- a/src/lovr.c +++ b/src/lovr.c @@ -4,13 +4,27 @@ #include "lovr/graphics.h" #include "lovr/headset.h" #include "lovr/timer.h" +#include "glfw.h" #include "util.h" #include -void lovrInit(lua_State* L, int argc, char** argv) { +static int handleLuaError(lua_State* L) { + const char* message = luaL_checkstring(L, -1); + lua_getglobal(L, "lovr"); + lua_getfield(L, -1, "errhand"); - // Set up GLFW - initGlfw(lovrOnGlfwError, lovrOnClose, L); + if (lua_isfunction(L, -1)) { + lua_pushstring(L, message); + lua_call(L, 1, 0); + } else { + error(message); + } + + return 0; +} + +void lovrInit(lua_State* L, int argc, char** argv) { + initGlfw(); // arg global lua_newtable(L); @@ -71,10 +85,24 @@ void lovrInit(lua_State* L, int argc, char** argv) { "lovr.filesystem.setIdentity(conf.identity or 'default') " + "lovr.handlers = setmetatable({ " + " quit = function() end " + "}, { " + " __index = function(self, event) " + " error('Unknown event: ', event) " + " end " + "}) " + "function lovr.run() " " if lovr.load then lovr.load() end " " while true do " - " lovr.event.poll() " + " lovr.event.pump() " + " for name, a, b, c, d in lovr.event.poll() do " + " if name == 'quit' and (not lovr.quit or not lovr.quit()) then " + " return a " + " end " + " lovr.handlers[name](a, b, c, d) " + " end " " local dt = lovr.timer.step() " " if lovr.update then lovr.update(dt) end " " lovr.graphics.clear() " @@ -93,7 +121,7 @@ void lovrInit(lua_State* L, int argc, char** argv) { "function lovr.errhand(message, layer) " " local stackTrace = debug.traceback('Error: ' .. tostring(message), 1 + (layer or 1)) " - " print((stackTrace:gsub('\\n[^\\n]+$', ''))) " + " print((stackTrace:gsub('\\n[^\\n]+$', ''):gsub('stack traceback', 'Stack'))) " "end " "if lovr.filesystem.isFile('main.lua') then " @@ -106,7 +134,7 @@ void lovrInit(lua_State* L, int argc, char** argv) { error("Unable to bootstrap LOVR: %s", message); } - lua_atpanic(L, lovrOnLuaError); + lua_atpanic(L, handleLuaError); } void lovrDestroy(int exitCode) { @@ -119,44 +147,9 @@ void lovrRun(lua_State* L) { // lovr.run() lua_getglobal(L, "lovr"); lua_getfield(L, -1, "run"); - lua_call(L, 0, 0); -} - -int lovrOnLuaError(lua_State* L) { - const char* message = luaL_checkstring(L, -1); - lua_getglobal(L, "lovr"); - lua_getfield(L, -1, "errhand"); - - if (lua_isfunction(L, -1)) { - lua_pushstring(L, message); - lua_call(L, 1, 0); - } else { - error(message); - } - - return 0; -} - -void lovrOnGlfwError(int code, const char* description) { - error(description); -} - -void lovrOnClose(GLFWwindow* _window) { - if (_window == window) { - - lua_State* L = (lua_State*) glfwGetWindowUserPointer(window); - - // lovr.quit() - lua_getglobal(L, "lovr"); - lua_getfield(L, -1, "quit"); - - if (!lua_isnil(L, -1)) { - lua_call(L, 0, 0); - } - - if (glfwWindowShouldClose(window)) { - glfwDestroyWindow(window); - lovrDestroy(0); - } - } + lua_call(L, 0, 1); + + // Exit with return value from lovr.run + int exitCode = luaL_optint(L, -1, 0); + lovrDestroy(exitCode); } diff --git a/src/lovr.h b/src/lovr.h index 3ce24791..fa49e490 100644 --- a/src/lovr.h +++ b/src/lovr.h @@ -1,4 +1,3 @@ -#include "glfw.h" #include #include #include @@ -7,5 +6,3 @@ void lovrInit(lua_State* L, int argc, char** argv); void lovrDestroy(int exitCode); void lovrRun(lua_State* L); int lovrOnLuaError(lua_State* L); -void lovrOnGlfwError(int code, const char* description); -void lovrOnClose(GLFWwindow* window); diff --git a/src/lovr/event.c b/src/lovr/event.c index db3f081d..d310a330 100644 --- a/src/lovr/event.c +++ b/src/lovr/event.c @@ -1,8 +1,30 @@ #include "lovr/event.h" #include "event/event.h" +#include "util.h" + +static int nextEvent(lua_State* L) { + Event* event = lovrEventPoll(); + + if (!event) { + return 0; + } + + switch (event->type) { + case EVENT_QUIT: + lua_pushstring(L, "quit"); + lua_pushnumber(L, event->data.quit.exitCode); + return 2; + + default: + return 0; + } +} const luaL_Reg lovrEvent[] = { + { "clear", l_lovrEventClear }, { "poll", l_lovrEventPoll }, + { "pump", l_lovrEventPump }, + { "push", l_lovrEventPush }, { "quit", l_lovrEventQuit }, { NULL, NULL } }; @@ -10,16 +32,46 @@ const luaL_Reg lovrEvent[] = { int l_lovrEventInit(lua_State* L) { lua_newtable(L); luaL_register(L, NULL, lovrEvent); + map_init(&EventTypes); + map_set(&EventTypes, "quit", EVENT_QUIT); + lovrEventInit(); return 1; } +int l_lovrEventClear(lua_State* L) { + lovrEventClear(); + return 0; +} + int l_lovrEventPoll(lua_State* L) { - lovrEventPoll(); + lua_pushcclosure(L, nextEvent, 0); + return 1; +} + +int l_lovrEventPump(lua_State* L) { + lovrEventPump(); + return 0; +} + +int l_lovrEventPush(lua_State* L) { + EventType type = *(EventType*) luax_checkenum(L, 1, &EventTypes, "event type"); + EventData data; + + switch (type) { + case EVENT_QUIT: + data.quit.exitCode = luaL_optint(L, 2, 0); + break; + } + + Event event = { .type = type, .data = data }; + lovrEventPush(event); return 0; } int l_lovrEventQuit(lua_State* L) { int exitCode = luaL_optint(L, 1, 0); - lovrEventQuit(exitCode); - return 0; + lua_settop(L, 0); + lua_pushliteral(L, "quit"); + lua_pushinteger(L, exitCode); + return l_lovrEventPush(L); } diff --git a/src/lovr/event.h b/src/lovr/event.h index fabdeaf5..7be60a27 100644 --- a/src/lovr/event.h +++ b/src/lovr/event.h @@ -1,8 +1,14 @@ +#include "vendor/map/map.h" #include #include #include +map_int_t EventTypes; + extern const luaL_Reg lovrEvent[]; int l_lovrEventInit(lua_State* L); +int l_lovrEventClear(lua_State* L); int l_lovrEventPoll(lua_State* L); +int l_lovrEventPump(lua_State* L); +int l_lovrEventPush(lua_State* L); int l_lovrEventQuit(lua_State* L);