// ============================================================================ // LUA BINDINGS - IMPLEMENTATION // ============================================================================ // Exposes C++ rendering and input APIs to Lua scripts #include "lua_bindings.h" #include "lua_game.h" #include "../display/low_level_render.h" #include "../display/low_level_gui.h" #include "../lib/input_manager.h" #include // Registry key for LuaGame pointer static const char* LUAGAME_REGISTRY_KEY = "LUAGAME_PTR"; // Helper: Get LuaGame instance from registry static LuaGame* get_game(lua_State* L) { lua_pushstring(L, LUAGAME_REGISTRY_KEY); lua_gettable(L, LUA_REGISTRYINDEX); LuaGame* game = (LuaGame*)lua_touserdata(L, -1); lua_pop(L, 1); return game; } // ============================================================================ // RENDERER BINDINGS // ============================================================================ // renderer.clear(white) static int lua_renderer_clear(lua_State* L) { LuaGame* game = get_game(L); if (!game) return 0; bool white = lua_toboolean(L, 1); game->renderer->clear_buffer(); return 0; } // renderer.pixel(x, y, on) static int lua_renderer_pixel(lua_State* L) { LuaGame* game = get_game(L); if (!game) return 0; int x = luaL_checkinteger(L, 1); int y = luaL_checkinteger(L, 2); bool on = lua_toboolean(L, 3); game->renderer->set_pixel(x, y, on); return 0; } // renderer.rect(x, y, w, h, on, filled) static int lua_renderer_rect(lua_State* L) { LuaGame* game = get_game(L); if (!game) return 0; int x = luaL_checkinteger(L, 1); int y = luaL_checkinteger(L, 2); int w = luaL_checkinteger(L, 3); int h = luaL_checkinteger(L, 4); bool on = lua_toboolean(L, 5); bool filled = lua_isnone(L, 6) ? false : lua_toboolean(L, 6); if (filled) { game->renderer->draw_filled_rectangle(x, y, w, h, on, 1); } else { game->renderer->draw_rectangle(x, y, w, h, on, 1); } return 0; } // renderer.circle(x, y, radius, on, filled) static int lua_renderer_circle(lua_State* L) { LuaGame* game = get_game(L); if (!game) return 0; int x = luaL_checkinteger(L, 1); int y = luaL_checkinteger(L, 2); int radius = luaL_checkinteger(L, 3); bool on = lua_toboolean(L, 4); bool filled = lua_isnone(L, 5) ? false : lua_toboolean(L, 5); if (filled) { game->renderer->draw_filled_circle(x, y, radius, on); } else { game->renderer->draw_circle(x, y, radius, on); } return 0; } // renderer.line(x0, y0, x1, y1, on, width) static int lua_renderer_line(lua_State* L) { LuaGame* game = get_game(L); if (!game) return 0; int x0 = luaL_checkinteger(L, 1); int y0 = luaL_checkinteger(L, 2); int x1 = luaL_checkinteger(L, 3); int y1 = luaL_checkinteger(L, 4); bool on = lua_toboolean(L, 5); int width = lua_isnone(L, 6) ? 1 : luaL_checkinteger(L, 6); game->renderer->draw_line(x0, y0, x1, y1, on, width); return 0; } // renderer.text(x, y, text, on) static int lua_renderer_text(lua_State* L) { LuaGame* game = get_game(L); if (!game) return 0; int x = luaL_checkinteger(L, 1); int y = luaL_checkinteger(L, 2); const char* text = luaL_checkstring(L, 3); bool on = lua_toboolean(L, 4); game->renderer->set_text_color(on); game->renderer->draw_string(x, y, text, true); return 0; } // renderer.text_scaled(x, y, text, on, scale) static int lua_renderer_text_scaled(lua_State* L) { LuaGame* game = get_game(L); if (!game) return 0; int x = luaL_checkinteger(L, 1); int y = luaL_checkinteger(L, 2); const char* text = luaL_checkstring(L, 3); bool on = lua_toboolean(L, 4); int scale = lua_isnone(L, 5) ? 1 : luaL_checkinteger(L, 5); game->renderer->set_text_color(on); game->renderer->draw_string_scaled(x, y, text, scale, 1); return 0; } // renderer.triangle(x0, y0, x1, y1, x2, y2, on, filled) static int lua_renderer_triangle(lua_State* L) { LuaGame* game = get_game(L); if (!game) return 0; int x0 = luaL_checkinteger(L, 1); int y0 = luaL_checkinteger(L, 2); int x1 = luaL_checkinteger(L, 3); int y1 = luaL_checkinteger(L, 4); int x2 = luaL_checkinteger(L, 5); int y2 = luaL_checkinteger(L, 6); bool on = lua_toboolean(L, 7); bool filled = lua_isnone(L, 8) ? false : lua_toboolean(L, 8); if (filled) { game->renderer->draw_filled_triangle(x0, y0, x1, y1, x2, y2, on); } else { game->renderer->draw_triangle(x0, y0, x1, y1, x2, y2, on); } return 0; } // ============================================================================ // GAME STATE BINDINGS // ============================================================================ // Global table to store persistent state variables // game.vars[key] = value // game.width() - get display width static int lua_game_width(lua_State* L) { LuaGame* game = get_game(L); if (!game) return 0; lua_pushinteger(L, game->width); return 1; } // game.height() - get display height static int lua_game_height(lua_State* L) { LuaGame* game = get_game(L); if (!game) return 0; lua_pushinteger(L, game->height); return 1; } // game.exit() - request exit to launcher static int lua_game_exit(lua_State* L) { LuaGame* game = get_game(L); if (!game) return 0; // Set exit flag (will be checked in wants_to_exit()) lua_pushstring(L, "__exit_requested"); lua_pushboolean(L, true); lua_settable(L, LUA_REGISTRYINDEX); return 0; } // game.set_frame_updates(enabled) - enable/disable continuous frame tick events static int lua_game_set_frame_updates(lua_State* L) { LuaGame* game = get_game(L); if (!game) return 0; bool enabled = lua_toboolean(L, 1); // Set frame updates flag (will be checked in wants_frame_updates()) lua_pushstring(L, "__wants_frame_updates"); lua_pushboolean(L, enabled); lua_settable(L, LUA_REGISTRYINDEX); return 0; } // ============================================================================ // INPUT TYPE CONSTANTS // ============================================================================ // Set up input type constants as global table static void register_input_constants(lua_State* L) { lua_newtable(L); lua_pushstring(L, "NONE"); lua_pushinteger(L, 0); lua_settable(L, -3); lua_pushstring(L, "TOUCH_DOWN"); lua_pushinteger(L, 1); lua_settable(L, -3); lua_pushstring(L, "TOUCH_MOVE"); lua_pushinteger(L, 2); lua_settable(L, -3); lua_pushstring(L, "TOUCH_UP"); lua_pushinteger(L, 3); lua_settable(L, -3); lua_pushstring(L, "BUTTON_0"); lua_pushinteger(L, 4); lua_settable(L, -3); lua_pushstring(L, "BUTTON_1"); lua_pushinteger(L, 5); lua_settable(L, -3); lua_pushstring(L, "GESTURE"); lua_pushinteger(L, 6); lua_settable(L, -3); lua_pushstring(L, "FRAME_TICK"); lua_pushinteger(L, 7); lua_settable(L, -3); lua_setglobal(L, "INPUT"); } // ============================================================================ // MAIN REGISTRATION FUNCTION // ============================================================================ void lua_bindings_register(lua_State* L, LuaGame* game) { // Store game pointer in registry lua_pushstring(L, LUAGAME_REGISTRY_KEY); lua_pushlightuserdata(L, game); lua_settable(L, LUA_REGISTRYINDEX); // Create renderer table lua_newtable(L); lua_pushstring(L, "clear"); lua_pushcfunction(L, lua_renderer_clear); lua_settable(L, -3); lua_pushstring(L, "pixel"); lua_pushcfunction(L, lua_renderer_pixel); lua_settable(L, -3); lua_pushstring(L, "rect"); lua_pushcfunction(L, lua_renderer_rect); lua_settable(L, -3); lua_pushstring(L, "circle"); lua_pushcfunction(L, lua_renderer_circle); lua_settable(L, -3); lua_pushstring(L, "line"); lua_pushcfunction(L, lua_renderer_line); lua_settable(L, -3); lua_pushstring(L, "text"); lua_pushcfunction(L, lua_renderer_text); lua_settable(L, -3); lua_pushstring(L, "text_scaled"); lua_pushcfunction(L, lua_renderer_text_scaled); lua_settable(L, -3); lua_pushstring(L, "triangle"); lua_pushcfunction(L, lua_renderer_triangle); lua_settable(L, -3); lua_setglobal(L, "renderer"); // Create game table lua_newtable(L); lua_pushstring(L, "width"); lua_pushcfunction(L, lua_game_width); lua_settable(L, -3); lua_pushstring(L, "height"); lua_pushcfunction(L, lua_game_height); lua_settable(L, -3); lua_pushstring(L, "exit"); lua_pushcfunction(L, lua_game_exit); lua_settable(L, -3); lua_pushstring(L, "set_frame_updates"); lua_pushcfunction(L, lua_game_set_frame_updates); lua_settable(L, -3); // Create empty vars table for persistent state lua_pushstring(L, "vars"); lua_newtable(L); lua_settable(L, -3); lua_setglobal(L, "game"); // Register input type constants register_input_constants(L); printf("Lua bindings registered\n"); }