diff --git a/assets/entities/plane.lua b/assets/entities/plane.lua index a1b45316..04c23272 100644 --- a/assets/entities/plane.lua +++ b/assets/entities/plane.lua @@ -1,16 +1,19 @@ module('entity') +module('math') +module('color') function entityInit() entityPositionAdd(ENTITY_ID) local phys = entityPhysicsAdd(ENTITY_ID) phys.bodyType = PHYSICS_BODY_STATIC - phys:setShapePlane(0, 1, 0, 0) + phys:setShapePlane(vec3(0, 1, 0), 0) local mesh = entityMeshAdd(ENTITY_ID) mesh:generatePlane(20, 20) - entityMaterialAdd(ENTITY_ID) + local mat = entityMaterialAdd(ENTITY_ID) + mat.color = colorBlack() end function entityDispose() diff --git a/assets/entities/player.lua b/assets/entities/player.lua index d54dabaf..c3e5a07b 100644 --- a/assets/entities/player.lua +++ b/assets/entities/player.lua @@ -9,6 +9,7 @@ module('entitycamera') local phys local updateSub local SPEED = 4.0 +local mat function entityInit() local pos = entityPositionAdd(ENTITY_ID) @@ -22,8 +23,7 @@ function entityInit() local mesh = entityMeshAdd(ENTITY_ID) mesh:generateCapsule(0.3, 0.9) - local mat = entityMaterialAdd(ENTITY_ID) - mat.color = colorBlue() + mat = entityMaterialAdd(ENTITY_ID) updateSub = eventSubscribe(SCENE_EVENT_UPDATE, onUpdate) end @@ -32,6 +32,8 @@ function onUpdate() local moveX = inputAxis(INPUT_ACTION_LEFT, INPUT_ACTION_RIGHT) local moveZ = inputAxis(INPUT_ACTION_DOWN, INPUT_ACTION_UP) + mat.color = colorRainbow() + local cam = entityCameraGetCurrent() local fwd = cam:getForward() local right = cam:getRight() diff --git a/assets/init.lua b/assets/init.lua index 71748497..2b437dc5 100644 --- a/assets/init.lua +++ b/assets/init.lua @@ -1,8 +1,3 @@ -module('input') -module('platform') -module('scene') -module('locale') - -- Default Input bindings. if PSP then inputBind("up", INPUT_ACTION_UP) @@ -77,5 +72,4 @@ else print("Unknown platform, no default input bindings set.") end --- Hand off to initial scene. -sceneSet('test/scene.lua') \ No newline at end of file +print('Inited') \ No newline at end of file diff --git a/src/dusk/engine/engine.c b/src/dusk/engine/engine.c index 8c3b772e..dc2b2613 100644 --- a/src/dusk/engine/engine.c +++ b/src/dusk/engine/engine.c @@ -47,13 +47,10 @@ errorret_t engineInit(const int32_t argc, const char_t **argv) { physicsManagerInit(); errorChain(networkInit()); errorChain(gameInit()); - consolePrint("Engine initialized"); - + /* Run the init script. */ - scriptcontext_t ctx; - errorChain(scriptContextInit(&ctx)); - errorChain(scriptContextExecFile(&ctx, "init.lua")); - scriptContextDispose(&ctx); + consolePrint("Engine initialized"); + errorChain(scriptContextExecFile(&SCRIPT_MANAGER.mainContext, "init.lua")); errorOk(); } diff --git a/src/dusk/event/event.c b/src/dusk/event/event.c index 178a472d..0f6bf074 100644 --- a/src/dusk/event/event.c +++ b/src/dusk/event/event.c @@ -8,6 +8,17 @@ #include "event.h" #include "assert/assert.h" #include "util/memory.h" +#include "console/console.h" + +static int eventLuaTraceback(lua_State *L) { + const char *msg = lua_tostring(L, 1); + if(msg) { + luaL_traceback(L, L, msg, 1); + } else { + lua_pushliteral(L, "(no error message)"); + } + return 1; +} void eventInit( event_t *event, @@ -221,6 +232,8 @@ void eventInvoke( lua_State *L = listener->user.script.context->luaState; assertNotNull(L, "Lua state in event listener cannot be NULL"); + lua_pushcfunction(L, eventLuaTraceback); + int handlerIdx = lua_gettop(L); lua_rawgeti(L, LUA_REGISTRYINDEX, listener->user.script.luaFunctionRef); int numArgs = 0; @@ -229,11 +242,15 @@ void eventInvoke( numArgs = 1; } - if(lua_pcall(L, numArgs, 0, 0) != LUA_OK) { + printf("Invoking Lua event listener with %d argument(s)\n", numArgs); + + if(lua_pcall(L, numArgs, 0, handlerIdx) != LUA_OK) { const char_t *strErr = lua_tostring(L, -1); + consolePrint("Error invoking Lua event listener:\n%s\n", strErr); lua_pop(L, 1); - printf("Error invoking Lua event listener: %s\n", strErr); } + + lua_pop(L, 1); } else { assertUnreachable("Unknown event listener type"); } diff --git a/src/dusk/script/CMakeLists.txt b/src/dusk/script/CMakeLists.txt index e086520c..91f823f5 100644 --- a/src/dusk/script/CMakeLists.txt +++ b/src/dusk/script/CMakeLists.txt @@ -8,8 +8,6 @@ target_sources(${DUSK_LIBRARY_TARGET_NAME} PUBLIC scriptmanager.c scriptcontext.c - scriptmodule.c ) -# Subdirectories -add_subdirectory(module) \ No newline at end of file +# Subdirectories \ No newline at end of file diff --git a/src/dusk/script/module/CMakeLists.txt b/src/dusk/script/module/CMakeLists.txt deleted file mode 100644 index acc955d4..00000000 --- a/src/dusk/script/module/CMakeLists.txt +++ /dev/null @@ -1,16 +0,0 @@ -# Copyright (c) 2026 Dominic Masters -# -# This software is released under the MIT License. -# https://opensource.org/licenses/MIT - -# Subdirectories -add_subdirectory(display) -add_subdirectory(entity) -add_subdirectory(event) -add_subdirectory(input) -add_subdirectory(locale) -add_subdirectory(math) -add_subdirectory(system) -add_subdirectory(scene) -add_subdirectory(time) -add_subdirectory(ui) \ No newline at end of file diff --git a/src/dusk/script/module/display/CMakeLists.txt b/src/dusk/script/module/display/CMakeLists.txt deleted file mode 100644 index 86e38c6e..00000000 --- a/src/dusk/script/module/display/CMakeLists.txt +++ /dev/null @@ -1,17 +0,0 @@ -# Copyright (c) 2026 Dominic Masters -# -# This software is released under the MIT License. -# https://opensource.org/licenses/MIT - -# Sources -target_sources(${DUSK_LIBRARY_TARGET_NAME} - PUBLIC - moduleglm.c - modulespritebatch.c - modulecolor.c - moduletext.c - modulescreen.c - moduletileset.c - moduletexture.c - moduleshader.c -) \ No newline at end of file diff --git a/src/dusk/script/module/display/modulecolor.c b/src/dusk/script/module/display/modulecolor.c deleted file mode 100644 index 8fe4f0f5..00000000 --- a/src/dusk/script/module/display/modulecolor.c +++ /dev/null @@ -1,186 +0,0 @@ -/** - * Copyright (c) 2026 Dominic Masters - * - * This software is released under the MIT License. - * https://opensource.org/licenses/MIT - */ - -#include "modulecolor.h" -#include "display/color.h" -#include "assert/assert.h" -#include "util/string.h" -#include "time/time.h" - -void moduleColor(scriptcontext_t *context) { - assertNotNull(context, "Context cannot be NULL."); - - if(luaL_newmetatable(context->luaState, "color_mt")) { - // Metatable is new, set __index and __newindex - lua_pushstring(context->luaState, "__index"); - lua_pushcfunction(context->luaState, moduleColorIndex); - lua_settable(context->luaState, -3); - - lua_pushstring(context->luaState, "__newindex"); - lua_pushcfunction(context->luaState, moduleColorNewIndex); - lua_settable(context->luaState, -3); - - lua_pushstring(context->luaState, "__tostring"); - lua_pushcfunction(context->luaState, moduleColorToString); - lua_settable(context->luaState, -3); - } - lua_pop(context->luaState, 1); - - lua_register(context->luaState, "color", moduleColorFuncColor); - lua_register(context->luaState, "colorRainbow", moduleColorRainbow); - - scriptContextExec(context, COLOR_SCRIPT); -} - -int moduleColorFuncColor(lua_State *L) { - assertNotNull(L, "Lua state cannot be NULL."); - - scriptcontext_t *context = *(scriptcontext_t **)lua_getextraspace(L); - assertNotNull(context, "Script context cannot be NULL."); - - // Needs 4 channel uint8_t - if( - !lua_isnumber(L, 1) || !lua_isnumber(L, 2) || - !lua_isnumber(L, 3) || !lua_isnumber(L, 4) - ) { - return luaL_error(L, "color(r, g, b, a) requires four number arguments."); - } - - colorchannel8_t r = (colorchannel8_t)lua_tonumber(L, 1); - colorchannel8_t g = (colorchannel8_t)lua_tonumber(L, 2); - colorchannel8_t b = (colorchannel8_t)lua_tonumber(L, 3); - colorchannel8_t a = (colorchannel8_t)lua_tonumber(L, 4); - - // Create color_t as lua memory, and push metatable - color_t *color = (color_t *)lua_newuserdata(L, sizeof(color_t)); - luaL_getmetatable(L, "color_mt"); - lua_setmetatable(L, -2); - - // Initial values. - color->r = r; - color->g = g; - color->b = b; - color->a = a; - - return 1; -} - -int moduleColorIndex(lua_State *L) { - assertNotNull(L, "Lua state cannot be NULL."); - - const char_t *key = lua_tostring(L, 2); - assertStrLenMin(key, 1, "Key cannot be empty."); - - const color_t *color = (const color_t*)luaL_checkudata(L, 1, "color_mt"); - assertNotNull(color, "Color struct cannot be NULL."); - - if(stringCompare(key, "r") == 0) { - lua_pushnumber(L, color->r); - return 1; - } - if(stringCompare(key, "g") == 0) { - lua_pushnumber(L, color->g); - return 1; - } - if(stringCompare(key, "b") == 0) { - lua_pushnumber(L, color->b); - return 1; - } - if(stringCompare(key, "a") == 0) { - lua_pushnumber(L, color->a); - return 1; - } - - lua_pushnil(L); - return 1; -} - -int moduleColorNewIndex(lua_State *L) { - assertNotNull(L, "Lua state cannot be NULL."); - - const char_t *key = lua_tostring(L, 2); - assertStrLenMin(key, 1, "Key cannot be empty."); - - color_t *color = (color_t*)luaL_checkudata(L, 1, "color_mt"); - assertNotNull(color, "Color struct cannot be NULL."); - - if(stringCompare(key, "r") == 0) { - if(!lua_isnumber(L, 3)) { - return luaL_error(L, "color channel r must be a number."); - } - color->r = (colorchannel8_t)lua_tonumber(L, 3); - return 0; - } else if(stringCompare(key, "g") == 0) { - if(!lua_isnumber(L, 3)) { - return luaL_error(L, "color channel g must be a number."); - } - color->g = (colorchannel8_t)lua_tonumber(L, 3); - return 0; - } else if(stringCompare(key, "b") == 0) { - if(!lua_isnumber(L, 3)) { - return luaL_error(L, "color channel b must be a number."); - } - color->b = (colorchannel8_t)lua_tonumber(L, 3); - return 0; - } else if(stringCompare(key, "a") == 0) { - if(!lua_isnumber(L, 3)) { - return luaL_error(L, "color channel a must be a number."); - } - color->a = (colorchannel8_t)lua_tonumber(L, 3); - return 0; - } - - return 0; -} - -int moduleColorToString(lua_State *L) { - assertNotNull(L, "Lua state cannot be NULL."); - - const color_t *color = (const color_t*)luaL_checkudata(L, 1, "color_mt"); - assertNotNull(color, "Color struct cannot be NULL."); - - lua_pushfstring( - L, "color(r=%d, g=%d, b=%d, a=%d)", - color->r, color->g, color->b, color->a - ); - - return 1; -} - -int moduleColorRainbow(lua_State *L) { - assertNotNull(L, "Lua state cannot be NULL."); - - // Allow time offset - float_t t = TIME.time; - if(lua_gettop(L) >= 1) { - if(!lua_isnumber(L, 1)) { - return luaL_error(L, "Rainbow time offset must be a number."); - } - t += (float_t)lua_tonumber(L, 1); - } - - // Allow speed multiplier - if(lua_gettop(L) >= 2) { - if(!lua_isnumber(L, 2)) { - return luaL_error(L, "Rainbow speed multiplier must be a number."); - } - t *= (float_t)lua_tonumber(L, 2); - } - - // Generate rainbow based on time. - color_t *color = (color_t *)lua_newuserdata(L, sizeof(color_t)); - color->r = (colorchannel8_t)((sinf(t) + 1.0f) * 0.5f * 255.0f); - color->g = (colorchannel8_t)((sinf(t + 2.0f) + 1.0f) * 0.5f * 255.0f); - color->b = (colorchannel8_t)((sinf(t + 4.0f) + 1.0f) * 0.5f * 255.0f); - color->a = 255; - - // Set metatable - luaL_getmetatable(L, "color_mt"); - lua_setmetatable(L, -2); - - return 1; -} \ No newline at end of file diff --git a/src/dusk/script/module/display/modulecolor.h b/src/dusk/script/module/display/modulecolor.h index 950be54b..de7838d3 100644 --- a/src/dusk/script/module/display/modulecolor.h +++ b/src/dusk/script/module/display/modulecolor.h @@ -1,55 +1,121 @@ /** * Copyright (c) 2026 Dominic Masters - * + * * This software is released under the MIT License. * https://opensource.org/licenses/MIT */ #pragma once -#include "script/scriptcontext.h" +#include "script/module/modulebase.h" +#include "display/color.h" +#include "time/time.h" -/** - * Registers the color module with the given script context. - * - * @param context The script context to register the module with. - */ -void moduleColor(scriptcontext_t *context); +static int moduleColorIndex(lua_State *L) { + const color_t *color = (const color_t *)luaL_checkudata(L, 1, "color_mt"); + assertNotNull(color, "Color struct cannot be NULL."); + const char_t *key = luaL_checkstring(L, 2); -/** - * Lua function to create a color. - * - * @param L The Lua state. - * @return Number of return values. - */ -int moduleColorFuncColor(lua_State *L); + if(stringCompare(key, "r") == 0) { lua_pushnumber(L, color->r); return 1; } + if(stringCompare(key, "g") == 0) { lua_pushnumber(L, color->g); return 1; } + if(stringCompare(key, "b") == 0) { lua_pushnumber(L, color->b); return 1; } + if(stringCompare(key, "a") == 0) { lua_pushnumber(L, color->a); return 1; } -/** - * Index function for the color structure. - * @param L The Lua state. - * @return Number of return values. - */ -int moduleColorIndex(lua_State *L); + lua_getmetatable(L, 1); + lua_getfield(L, -1, key); + return 1; +} -/** - * New index function for the color structure. - * - * @param L The Lua state. - * @return Number of return values. - */ -int moduleColorNewIndex(lua_State *L); +static int moduleColorNewIndex(lua_State *L) { + color_t *color = (color_t *)luaL_checkudata(L, 1, "color_mt"); + assertNotNull(color, "Color struct cannot be NULL."); + const char_t *key = luaL_checkstring(L, 2); -/** - * Color to string method for script - * - * @param L The Lua state. - * @return Number of return values. - */ -int moduleColorToString(lua_State *L); + if(stringCompare(key, "r") == 0) { + color->r = (colorchannel8_t)luaL_checknumber(L, 3); return 0; + } else if(stringCompare(key, "g") == 0) { + color->g = (colorchannel8_t)luaL_checknumber(L, 3); return 0; + } else if(stringCompare(key, "b") == 0) { + color->b = (colorchannel8_t)luaL_checknumber(L, 3); return 0; + } else if(stringCompare(key, "a") == 0) { + color->a = (colorchannel8_t)luaL_checknumber(L, 3); return 0; + } -/** - * Lua function to create a rainbow color based on time. - * - * @param L The Lua state. - * @return Number of return values. - */ -int moduleColorRainbow(lua_State *L); \ No newline at end of file + luaL_error(L, "color: unknown property '%s'", key); + return 0; +} + +static int moduleColorToString(lua_State *L) { + const color_t *color = (const color_t *)luaL_checkudata(L, 1, "color_mt"); + assertNotNull(color, "Color struct cannot be NULL."); + lua_pushfstring(L, "color(r=%d, g=%d, b=%d, a=%d)", + color->r, color->g, color->b, color->a + ); + return 1; +} + +static int moduleColorFuncColor(lua_State *L) { + assertNotNull(L, "Lua state cannot be NULL."); + + if( + !lua_isnumber(L, 1) || !lua_isnumber(L, 2) || + !lua_isnumber(L, 3) || !lua_isnumber(L, 4) + ) { + return luaL_error(L, "color(r, g, b, a) requires four number arguments."); + } + + color_t *color = (color_t *)lua_newuserdata(L, sizeof(color_t)); + luaL_getmetatable(L, "color_mt"); + lua_setmetatable(L, -2); + + color->r = (colorchannel8_t)lua_tonumber(L, 1); + color->g = (colorchannel8_t)lua_tonumber(L, 2); + color->b = (colorchannel8_t)lua_tonumber(L, 3); + color->a = (colorchannel8_t)lua_tonumber(L, 4); + return 1; +} + +static int moduleColorRainbow(lua_State *L) { + float_t t = TIME.time * 4.0f; + if(lua_gettop(L) >= 1) { + if(!lua_isnumber(L, 1)) { + return luaL_error(L, "Rainbow time offset must be a number."); + } + t += (float_t)lua_tonumber(L, 1); + } + + if(lua_gettop(L) >= 2) { + if(!lua_isnumber(L, 2)) { + return luaL_error(L, "Rainbow speed multiplier must be a number."); + } + t *= (float_t)lua_tonumber(L, 2); + } + + color_t *color = (color_t *)lua_newuserdata(L, sizeof(color_t)); + color->r = (colorchannel8_t)((sinf(t) + 1.0f) * 0.5f * 255.0f); + color->g = (colorchannel8_t)((sinf(t + 2.0f) + 1.0f) * 0.5f * 255.0f); + color->b = (colorchannel8_t)((sinf(t + 4.0f) + 1.0f) * 0.5f * 255.0f); + color->a = 255; + + luaL_getmetatable(L, "color_mt"); + lua_setmetatable(L, -2); + return 1; +} + +static void moduleColor(lua_State *L) { + assertNotNull(L, "Lua state cannot be NULL."); + + if(luaL_newmetatable(L, "color_mt")) { + lua_pushcfunction(L, moduleColorIndex); + lua_setfield(L, -2, "__index"); + lua_pushcfunction(L, moduleColorNewIndex); + lua_setfield(L, -2, "__newindex"); + lua_pushcfunction(L, moduleColorToString); + lua_setfield(L, -2, "__tostring"); + } + lua_pop(L, 1); + + lua_register(L, "color", moduleColorFuncColor); + lua_register(L, "colorRainbow", moduleColorRainbow); + + luaL_dostring(L, COLOR_SCRIPT); +} diff --git a/src/dusk/script/module/display/moduleglm.c b/src/dusk/script/module/display/moduleglm.c deleted file mode 100644 index cc7119c2..00000000 --- a/src/dusk/script/module/display/moduleglm.c +++ /dev/null @@ -1,15 +0,0 @@ -/** - * Copyright (c) 2026 Dominic Masters - * - * This software is released under the MIT License. - * https://opensource.org/licenses/MIT - */ - -#include "moduleglm.h" -#include "script/module/math/modulemath.h" -#include "assert/assert.h" - -void moduleGLM(scriptcontext_t *context) { - assertNotNull(context, "Context cannot be NULL."); - moduleMath(context); -} diff --git a/src/dusk/script/module/display/modulescreen.c b/src/dusk/script/module/display/modulescreen.c deleted file mode 100644 index 1ea23c4e..00000000 --- a/src/dusk/script/module/display/modulescreen.c +++ /dev/null @@ -1,43 +0,0 @@ -/** - * Copyright (c) 2026 Dominic Masters - * - * This software is released under the MIT License. - * https://opensource.org/licenses/MIT - */ - -#include "modulescreen.h" -#include "assert/assert.h" -#include "display/screen/screen.h" - -void moduleScreen(scriptcontext_t *context) { - assertNotNull(context, "Context cannot be NULL."); - - lua_register(context->luaState, "screenGetWidth", moduleScreenGetWidth); - lua_register(context->luaState, "screenGetHeight", moduleScreenGetHeight); - lua_register(context->luaState, "screenSetBackground", moduleScreenSetBackground); -} - -int moduleScreenGetWidth(lua_State *L) { - assertNotNull(L, "Lua state is null"); - lua_pushnumber(L, SCREEN.width); - return 1; -} - -int moduleScreenGetHeight(lua_State *L) { - assertNotNull(L, "Lua state is null"); - lua_pushnumber(L, SCREEN.height); - return 1; -} - -int moduleScreenSetBackground(lua_State *L) { - assertNotNull(L, "Lua state is null"); - - if(!lua_isuserdata(L, 1)) { - luaL_error(L, "Screen background color must be a color struct"); - return 0; - } - - color_t *color = (color_t*)luaL_checkudata(L, 1, "color_mt"); - SCREEN.background = *color; - return 0; -} \ No newline at end of file diff --git a/src/dusk/script/module/display/modulescreen.h b/src/dusk/script/module/display/modulescreen.h index baa7e662..021f0f5f 100644 --- a/src/dusk/script/module/display/modulescreen.h +++ b/src/dusk/script/module/display/modulescreen.h @@ -1,40 +1,42 @@ /** * Copyright (c) 2026 Dominic Masters - * + * * This software is released under the MIT License. * https://opensource.org/licenses/MIT */ #pragma once -#include "script/scriptcontext.h" +#include "script/module/modulebase.h" +#include "display/screen/screen.h" -/** - * Registers the Screen module with the given script context. - * - * @param context The script context to register the module with. - */ -void moduleScreen(scriptcontext_t *context); +static int moduleScreenGetWidth(lua_State *L) { + assertNotNull(L, "Lua state is null"); + lua_pushnumber(L, SCREEN.width); + return 1; +} -/** - * Gets the current screen width. - * - * @param L The Lua state. - * @return Count of return values. - */ -int moduleScreenGetWidth(lua_State *L); +static int moduleScreenGetHeight(lua_State *L) { + assertNotNull(L, "Lua state is null"); + lua_pushnumber(L, SCREEN.height); + return 1; +} -/** - * Gets the current screen height. - * - * @param L The Lua state. - * @return Count of return values. - */ -int moduleScreenGetHeight(lua_State *L); +static int moduleScreenSetBackground(lua_State *L) { + assertNotNull(L, "Lua state is null"); -/** - * Sets the screen background color. - * - * @param L The Lua state. - * @return Count of return values. - */ -int moduleScreenSetBackground(lua_State *L); \ No newline at end of file + if(!lua_isuserdata(L, 1)) { + luaL_error(L, "Screen background color must be a color struct"); + return 0; + } + + color_t *color = (color_t*)luaL_checkudata(L, 1, "color_mt"); + SCREEN.background = *color; + return 0; +} + +static void moduleScreen(lua_State *L) { + assertNotNull(L, "Lua state cannot be NULL."); + lua_register(L, "screenGetWidth", moduleScreenGetWidth); + lua_register(L, "screenGetHeight", moduleScreenGetHeight); + lua_register(L, "screenSetBackground", moduleScreenSetBackground); +} diff --git a/src/dusk/script/module/display/moduleshader.c b/src/dusk/script/module/display/moduleshader.c deleted file mode 100644 index e114d229..00000000 --- a/src/dusk/script/module/display/moduleshader.c +++ /dev/null @@ -1,119 +0,0 @@ -/** - * Copyright (c) 2026 Dominic Masters - * - * This software is released under the MIT License. - * https://opensource.org/licenses/MIT - */ - -#include "moduleshader.h" -#include "assert/assert.h" -#include "display/shader/shader.h" -#include "display/shader/shaderunlit.h" - -void moduleShader(scriptcontext_t *context) { - assertNotNull(context, "Context cannot be NULL."); - - // Shader unlit defs - lua_pushlightuserdata(context->luaState, &SHADER_UNLIT); - lua_setglobal(context->luaState, "SHADER_UNLIT"); - - lua_pushstring(context->luaState, SHADER_UNLIT_PROJECTION); - lua_setglobal(context->luaState, "SHADER_UNLIT_PROJECTION"); - lua_pushstring(context->luaState, SHADER_UNLIT_VIEW); - lua_setglobal(context->luaState, "SHADER_UNLIT_VIEW"); - lua_pushstring(context->luaState, SHADER_UNLIT_MODEL); - lua_setglobal(context->luaState, "SHADER_UNLIT_MODEL"); - lua_pushstring(context->luaState, SHADER_UNLIT_TEXTURE); - lua_setglobal(context->luaState, "SHADER_UNLIT_TEXTURE"); - - // Shader methods - lua_register(context->luaState, "shaderBind", moduleShaderBind); - lua_register(context->luaState, "shaderSetMatrix", moduleShaderSetMatrix); - lua_register(context->luaState, "shaderSetTexture", moduleShaderSetTexture); -} - -int moduleShaderBind(lua_State *l) { - assertNotNull(l, "Lua state cannot be NULL."); - - // Should be passed a shader userdata pointer only. - shader_t *shader = (shader_t *)lua_touserdata(l, 1); - assertNotNull(shader, "Shader pointer cannot be NULL."); - - errorret_t ret = shaderBind(shader); - if(ret.code != ERROR_OK) { - luaL_error(l, "Failed to bind shader: %s", ret.state->message); - errorCatch(errorPrint(ret)); - return 0; - } - - return 0; -} - -int moduleShaderSetMatrix(lua_State *l) { - assertNotNull(l, "Lua state cannot be NULL."); - - // Expect shader, string and matrix. - if(!lua_isuserdata(l, 1)) { - luaL_error(l, "First argument must be a shader_mt userdata."); - return 0; - } - - if(!lua_isstring(l, 2)) { - luaL_error(l, "Second argument must be a string."); - return 0; - } - - if(!lua_isuserdata(l, 3)) { - luaL_error(l, "Third argument must be a mat4_mt userdata."); - return 0; - } - - shader_t *shader = (shader_t *)lua_touserdata(l, 1); - assertNotNull(shader, "Shader pointer cannot be NULL."); - - const char_t *uniformName = luaL_checkstring(l, 2); - assertStrLenMin(uniformName, 1, "Uniform name cannot be empty."); - - mat4 *mat = (mat4 *)lua_touserdata(l, 3); - assertNotNull(mat, "Matrix pointer cannot be NULL."); - - errorret_t ret = shaderSetMatrix(shader, uniformName, *mat); - if(ret.code != ERROR_OK) { - luaL_error(l, "Failed to set shader matrix: %s", ret.state->message); - errorCatch(errorPrint(ret)); - return 0; - } - - return 0; -} - -int moduleShaderSetTexture(lua_State *l) { - assertNotNull(l, "Lua state cannot be NULL."); - - shader_t *shader = (shader_t *)lua_touserdata(l, 1); - assertNotNull(shader, "Shader pointer cannot be NULL."); - - const char_t *uniformName = luaL_checkstring(l, 2); - assertStrLenMin(uniformName, 1, "Uniform name cannot be empty."); - - texture_t *texture; - // Texture can be Nil or a pointer, if not nil it must be a texture pointer. - if(lua_isnil(l, 3)) { - texture = NULL; - } else if(lua_isuserdata(l, 3)) { - texture = (texture_t *)lua_touserdata(l, 3); - assertNotNull(texture, "Texture pointer cannot be NULL."); - } else { - luaL_error(l, "Third argument must be a texture_mt userdata or nil."); - return 0; - } - - errorret_t ret = shaderSetTexture(shader, uniformName, texture); - if(ret.code != ERROR_OK) { - luaL_error(l, "Failed to set shader texture: %s", ret.state->message); - errorCatch(errorPrint(ret)); - return 0; - } - - return 0; -} \ No newline at end of file diff --git a/src/dusk/script/module/display/moduleshader.h b/src/dusk/script/module/display/moduleshader.h index d50e33c0..7a19a8ba 100644 --- a/src/dusk/script/module/display/moduleshader.h +++ b/src/dusk/script/module/display/moduleshader.h @@ -1,42 +1,90 @@ /** * Copyright (c) 2026 Dominic Masters - * + * * This software is released under the MIT License. * https://opensource.org/licenses/MIT */ #pragma once -#include "script/scriptcontext.h" +#include "script/module/modulebase.h" +#include "display/shader/shader.h" +#include "display/shader/shaderunlit.h" +#include "script/module/math/modulemat4.h" -/** - * Register shader functions to the given script context. - * - * @param context The script context to register shader functions to. - */ -void moduleShader(scriptcontext_t *context); +static int moduleShaderBind(lua_State *l) { + assertNotNull(l, "Lua state cannot be NULL."); + shader_t *shader = (shader_t *)lua_touserdata(l, 1); + assertNotNull(shader, "Shader pointer cannot be NULL."); -/** - * Script binding for binding a shader. - * - * @param l The Lua state. - * @return Number of return values on the Lua stack. - */ -int moduleShaderBind(lua_State *l); + errorret_t ret = shaderBind(shader); + if(ret.code != ERROR_OK) { + luaL_error(l, "Failed to bind shader: %s", ret.state->message); + errorCatch(errorPrint(ret)); + return 0; + } + return 0; +} -/** - * Script binding for setting a matrix uniform in a shader. - * - * @param l The Lua state. - * @return Number of return values on the Lua stack. - */ -int moduleShaderSetMatrix(lua_State *l); +static int moduleShaderSetMatrix(lua_State *l) { + assertNotNull(l, "Lua state cannot be NULL."); + shader_t *shader = (shader_t *)lua_touserdata(l, 1); + assertNotNull(shader, "Shader pointer cannot be NULL."); + const char_t *uniformName = luaL_checkstring(l, 2); + mat4 *mat = (mat4 *)luaL_checkudata(l, 3, "mat4_mt"); + assertNotNull(mat, "Matrix pointer cannot be NULL."); -/** - * Script binding for setting a texture uniform in a shader. - * - * @param l The Lua state. - * @return Number of return values on the Lua stack. - */ -int moduleShaderSetTexture(lua_State *l); + errorret_t ret = shaderSetMatrix(shader, uniformName, *mat); + if(ret.code != ERROR_OK) { + luaL_error(l, "Failed to set shader matrix: %s", ret.state->message); + errorCatch(errorPrint(ret)); + return 0; + } + return 0; +} -errorret_t doThing(); \ No newline at end of file +static int moduleShaderSetTexture(lua_State *l) { + assertNotNull(l, "Lua state cannot be NULL."); + shader_t *shader = (shader_t *)lua_touserdata(l, 1); + assertNotNull(shader, "Shader pointer cannot be NULL."); + const char_t *uniformName = luaL_checkstring(l, 2); + assertStrLenMin(uniformName, 1, "Uniform name cannot be empty."); + + texture_t *texture; + if(lua_isnil(l, 3)) { + texture = NULL; + } else if(lua_isuserdata(l, 3)) { + texture = (texture_t *)lua_touserdata(l, 3); + assertNotNull(texture, "Texture pointer cannot be NULL."); + } else { + luaL_error(l, "Third argument must be a texture_mt userdata or nil."); + return 0; + } + + errorret_t ret = shaderSetTexture(shader, uniformName, texture); + if(ret.code != ERROR_OK) { + luaL_error(l, "Failed to set shader texture: %s", ret.state->message); + errorCatch(errorPrint(ret)); + return 0; + } + return 0; +} + +static void moduleShader(lua_State *L) { + assertNotNull(L, "Lua state cannot be NULL."); + + lua_pushlightuserdata(L, &SHADER_UNLIT); + lua_setglobal(L, "SHADER_UNLIT"); + + lua_pushstring(L, SHADER_UNLIT_PROJECTION); + lua_setglobal(L, "SHADER_UNLIT_PROJECTION"); + lua_pushstring(L, SHADER_UNLIT_VIEW); + lua_setglobal(L, "SHADER_UNLIT_VIEW"); + lua_pushstring(L, SHADER_UNLIT_MODEL); + lua_setglobal(L, "SHADER_UNLIT_MODEL"); + lua_pushstring(L, SHADER_UNLIT_TEXTURE); + lua_setglobal(L, "SHADER_UNLIT_TEXTURE"); + + lua_register(L, "shaderBind", moduleShaderBind); + lua_register(L, "shaderSetMatrix", moduleShaderSetMatrix); + lua_register(L, "shaderSetTexture", moduleShaderSetTexture); +} diff --git a/src/dusk/script/module/display/modulespritebatch.c b/src/dusk/script/module/display/modulespritebatch.c deleted file mode 100644 index c042c1fd..00000000 --- a/src/dusk/script/module/display/modulespritebatch.c +++ /dev/null @@ -1,105 +0,0 @@ -/** - * Copyright (c) 2026 Dominic Masters - * - * This software is released under the MIT License. - * https://opensource.org/licenses/MIT - */ - -#include "modulespritebatch.h" -#include "display/spritebatch/spritebatch.h" -#include "assert/assert.h" - -void moduleSpriteBatch(scriptcontext_t *context) { - lua_register(context->luaState, "spriteBatchFlush", moduleSpriteBatchFlush); - lua_register(context->luaState, "spriteBatchClear", moduleSpriteBatchClear); - lua_register(context->luaState, "spriteBatchPush", moduleSpriteBatchPush); -} - -int moduleSpriteBatchFlush(lua_State *L) { - assertNotNull(L, "Lua state is null"); - - spriteBatchFlush(); - return 0; -} - -int moduleSpriteBatchClear(lua_State *L) { - assertNotNull(L, "Lua state is null"); - - spriteBatchClear(); - return 0; -} - -int moduleSpriteBatchPush(lua_State *L) { - assertNotNull(L, "Lua state is null"); - - // MinX, MinY, MaxX, MaxY - if( - !lua_isnumber(L, 1) || !lua_isnumber(L, 2) || !lua_isnumber(L, 3) || - !lua_isnumber(L, 4) - ) { - return luaL_error(L, "Sprite coordinates must be numbers"); - } - - // Color (struct) or nil for white - color_t *color = NULL; - if(lua_gettop(L) < 5 || lua_isnil(L, 5)) { - // Allow NULL - } else if(lua_isuserdata(L, 5)) { - color = (color_t*)luaL_checkudata(L, 5, "color_mt"); - } else { - return luaL_error(L, "Sprite color must be a color struct or nil"); - } - - // Optional UV min and maxes, defaults to 0,0 -> 1,1 - float_t u0 = 0.0f; - float_t v0 = 0.0f; - float_t u1 = 1.0f; - float_t v1 = 1.0f; - - if(lua_gettop(L) >= 7) { - if(!lua_isnumber(L, 6) || !lua_isnumber(L, 7)) { - return luaL_error(L, "Sprite UV min coordinates must be numbers"); - } - - u0 = (float_t)lua_tonumber(L, 6); - v0 = (float_t)lua_tonumber(L, 7); - } - - if(lua_gettop(L) >= 9) { - if(!lua_isnumber(L, 8) || !lua_isnumber(L, 9)) { - return luaL_error(L, "Sprite UV max coordinates must be numbers"); - } - - u1 = (float_t)lua_tonumber(L, 8); - v1 = (float_t)lua_tonumber(L, 9); - } - - float_t minX = (float_t)lua_tonumber(L, 1); - float_t minY = (float_t)lua_tonumber(L, 2); - float_t maxX = (float_t)lua_tonumber(L, 3); - float_t maxY = (float_t)lua_tonumber(L, 4); - - errorret_t ret = spriteBatchPush( - minX, - minY, - maxX, - maxY, - #if MESH_ENABLE_COLOR - color == NULL ? COLOR_WHITE : *color, - #endif - u0, - v0, - u1, - v1 - ); - if(ret.code != ERROR_OK) { - int err = luaL_error(L, - "Failed to push sprite to batch: %s", - ret.state->message - ); - errorCatch(errorPrint(ret)); - return err; - } - - return 0; -} \ No newline at end of file diff --git a/src/dusk/script/module/display/modulespritebatch.h b/src/dusk/script/module/display/modulespritebatch.h index 85c6d284..b457b503 100644 --- a/src/dusk/script/module/display/modulespritebatch.h +++ b/src/dusk/script/module/display/modulespritebatch.h @@ -1,40 +1,71 @@ /** * Copyright (c) 2026 Dominic Masters - * + * * This software is released under the MIT License. * https://opensource.org/licenses/MIT */ #pragma once -#include "script/scriptcontext.h" +#include "script/module/modulebase.h" +#include "display/spritebatch/spritebatch.h" +#include "script/module/math/modulevec2.h" +#include "script/module/math/modulevec4.h" -/** - * Register sprite batch functions to the given script context. - * - * @param context The script context to register sprite batch functions to. - */ -void moduleSpriteBatch(scriptcontext_t *context); +static int moduleSpriteBatchFlush(lua_State *L) { + assertNotNull(L, "Lua state is null"); + spriteBatchFlush(); + return 0; +} -/** - * Script binding for flushing the sprite batch. - * - * @param L The Lua state. - * @return Number of return values on the Lua stack. - */ -int moduleSpriteBatchFlush(lua_State *L); +static int moduleSpriteBatchClear(lua_State *L) { + assertNotNull(L, "Lua state is null"); + spriteBatchClear(); + return 0; +} -/** - * Script binding for clearing the sprite batch. - * - * @param L The Lua state. - * @return Number of return values on the Lua stack. - */ -int moduleSpriteBatchClear(lua_State *L); +static int moduleSpriteBatchPush(lua_State *L) { + assertNotNull(L, "Lua state is null"); -/** - * Script binding for pushing a sprite to the sprite batch. - * - * @param L The Lua state. - * @return Number of return values on the Lua stack. - */ -int moduleSpriteBatchPush(lua_State *L); \ No newline at end of file + vec2 min, max; + luaVec2Check(L, 1, min); + luaVec2Check(L, 2, max); + + color_t *color = NULL; + if(lua_gettop(L) < 3 || lua_isnil(L, 3)) { + // allow NULL (white) + } else if(lua_isuserdata(L, 3)) { + color = (color_t *)luaL_checkudata(L, 3, "color_mt"); + } else { + return luaL_error(L, "Sprite color must be a color struct or nil"); + } + + float_t u0 = 0.0f, v0 = 0.0f, u1 = 1.0f, v1 = 1.0f; + if(lua_gettop(L) >= 4 && !lua_isnil(L, 4)) { + vec4 uv; luaVec4Check(L, 4, uv); + u0 = uv[0]; v0 = uv[1]; u1 = uv[2]; v1 = uv[3]; + } + + errorret_t ret = spriteBatchPush( + min[0], min[1], max[0], max[1], + #if MESH_ENABLE_COLOR + color == NULL ? COLOR_WHITE : *color, + #endif + u0, v0, u1, v1 + ); + if(ret.code != ERROR_OK) { + int err = luaL_error(L, + "Failed to push sprite to batch: %s", + ret.state->message + ); + errorCatch(errorPrint(ret)); + return err; + } + + return 0; +} + +static void moduleSpriteBatch(lua_State *L) { + lua_register(L, "spriteBatchFlush", moduleSpriteBatchFlush); + lua_register(L, "spriteBatchClear", moduleSpriteBatchClear); + lua_register(L, "spriteBatchPush", moduleSpriteBatchPush); +} diff --git a/src/dusk/script/module/display/moduletext.c b/src/dusk/script/module/display/moduletext.c deleted file mode 100644 index de18aecc..00000000 --- a/src/dusk/script/module/display/moduletext.c +++ /dev/null @@ -1,92 +0,0 @@ -/** - * Copyright (c) 2026 Dominic Masters - * - * This software is released under the MIT License. - * https://opensource.org/licenses/MIT - */ - -#include "moduletext.h" -#include "assert/assert.h" -#include "display/text/text.h" -#include "display/spritebatch/spritebatch.h" - -void moduleText(scriptcontext_t *context) { - assertNotNull(context, "Script context is null"); - - lua_register(context->luaState, "textDraw", moduleTextDraw); - lua_register(context->luaState, "textMeasure", moduleTextMeasure); -} - -int moduleTextDraw(lua_State *L) { - assertNotNull(L, "Lua state is null"); - - // Position. - if(!lua_isnumber(L, 1)) { - return luaL_error(L, "X position must be a number"); - } - if(!lua_isnumber(L, 2)) { - return luaL_error(L, "Y position must be a number"); - } - - const float_t x = (float_t)lua_tonumber(L, 1); - const float_t y = (float_t)lua_tonumber(L, 2); - - // String - if(!lua_isstring(L, 3)) { - return luaL_error(L, "Text to draw must be a string"); - } - const char_t *text = (const char_t*)lua_tostring(L, 3); - - // Optional color - color_t *color = NULL; - if(lua_gettop(L) < 4 || lua_isnil(L, 4)) { - // Allow NULL - } else if(lua_isuserdata(L, 4)) { - color = (color_t*)luaL_checkudata(L, 4, "color_mt"); - } else { - return luaL_error(L, "Sprite color must be a color struct or nil"); - } - - // For now, use the default font tileset and texture. - errorret_t ret = textDraw( - x, - y, - text, - color == NULL ? COLOR_WHITE : *color, - &DEFAULT_FONT_TILESET, - &DEFAULT_FONT_TEXTURE - ); - if(ret.code != ERROR_OK) { - errorCatch(errorPrint(ret)); - luaL_error(L, "Failed to draw text"); - } - - ret = spriteBatchFlush(); - if(ret.code != ERROR_OK) { - errorCatch(errorPrint(ret)); - luaL_error(L, "Failed to flush sprite batch after drawing text"); - } -} - -int moduleTextMeasure(lua_State *L) { - assertNotNull(L, "Lua state is null"); - - // String - if(!lua_isstring(L, 1)) { - return luaL_error(L, "Text to measure must be a string"); - } - const char_t *text = (const char_t*)lua_tostring(L, 1); - - int32_t width = 0; - int32_t height = 0; - textMeasure( - text, - &DEFAULT_FONT_TILESET, - &width, - &height - ); - - lua_pushnumber(L, width); - lua_pushnumber(L, height); - return 2; -} \ No newline at end of file diff --git a/src/dusk/script/module/display/moduletext.h b/src/dusk/script/module/display/moduletext.h index 680e9b3f..03b39f7e 100644 --- a/src/dusk/script/module/display/moduletext.h +++ b/src/dusk/script/module/display/moduletext.h @@ -1,32 +1,72 @@ /** * Copyright (c) 2026 Dominic Masters - * + * * This software is released under the MIT License. * https://opensource.org/licenses/MIT */ #pragma once -#include "script/scriptcontext.h" +#include "script/module/modulebase.h" +#include "display/text/text.h" +#include "display/spritebatch/spritebatch.h" +#include "script/module/math/modulevec2.h" -/** - * Register text rendering functions to the given script context. - * - * @param context The script context to register text functions to. - */ -void moduleText(scriptcontext_t *context); +static int moduleTextDraw(lua_State *L) { + assertNotNull(L, "Lua state is null"); -/** - * Script binding for drawing text. - * - * @param L The Lua state. - * @return Number of return values on the Lua stack. - */ -int moduleTextDraw(lua_State *L); + vec2 pos; luaVec2Check(L, 1, pos); -/** - * Script binding for measuring text dimensions. - * - * @param L The Lua state. - * @return Number of return values on the Lua stack. - */ -int moduleTextMeasure(lua_State *L); \ No newline at end of file + if(!lua_isstring(L, 2)) { + return luaL_error(L, "Text to draw must be a string"); + } + const char_t *text = (const char_t *)lua_tostring(L, 2); + + color_t *color = NULL; + if(lua_gettop(L) < 3 || lua_isnil(L, 3)) { + // allow NULL (white) + } else if(lua_isuserdata(L, 3)) { + color = (color_t *)luaL_checkudata(L, 3, "color_mt"); + } else { + return luaL_error(L, "Text color must be a color struct or nil"); + } + + errorret_t ret = textDraw( + pos[0], pos[1], text, + color == NULL ? COLOR_WHITE : *color, + &DEFAULT_FONT_TILESET, + &DEFAULT_FONT_TEXTURE + ); + if(ret.code != ERROR_OK) { + errorCatch(errorPrint(ret)); + luaL_error(L, "Failed to draw text"); + } + + ret = spriteBatchFlush(); + if(ret.code != ERROR_OK) { + errorCatch(errorPrint(ret)); + luaL_error(L, "Failed to flush sprite batch after drawing text"); + } + return 0; +} + +static int moduleTextMeasure(lua_State *L) { + assertNotNull(L, "Lua state is null"); + + if(!lua_isstring(L, 1)) { + return luaL_error(L, "Text to measure must be a string"); + } + const char_t *text = (const char_t *)lua_tostring(L, 1); + + int32_t w = 0, h = 0; + textMeasure(text, &DEFAULT_FONT_TILESET, &w, &h); + + vec2 size = { (float_t)w, (float_t)h }; + luaVec2Push(L, size); + return 1; +} + +static void moduleText(lua_State *L) { + assertNotNull(L, "Lua state is null"); + lua_register(L, "textDraw", moduleTextDraw); + lua_register(L, "textMeasure", moduleTextMeasure); +} diff --git a/src/dusk/script/module/display/moduletexture.c b/src/dusk/script/module/display/moduletexture.c deleted file mode 100644 index b819b292..00000000 --- a/src/dusk/script/module/display/moduletexture.c +++ /dev/null @@ -1,119 +0,0 @@ -/** - * Copyright (c) 2026 Dominic Masters - * - * This software is released under the MIT License. - * https://opensource.org/licenses/MIT - */ - -#include "moduletexture.h" -#include "assert/assert.h" -#include "display/texture/texture.h" -#include "asset/loader/display/assettextureloader.h" -#include "util/memory.h" -#include "util/string.h" - -void moduleTexture(scriptcontext_t *ctx) { - assertNotNull(ctx, "Script context cannot be null"); - - lua_State *l = ctx->luaState; - assertNotNull(l, "Lua state cannot be null"); - - // Create metatable for texture structure. - if(luaL_newmetatable(l, "texture_mt") == 1) { - lua_pushcfunction(l, moduleTextureIndex); - lua_setfield(l, -2, "__index"); - - lua_pushcfunction(l, moduleTextureToString); - lua_setfield(l, -2, "__tostring"); - - lua_pushcfunction(l, moduleTextureGC); - lua_setfield(l, -2, "__gc"); - } - - // Texture formats - lua_pushnumber(l, TEXTURE_FORMAT_RGBA); - lua_setglobal(l, "TEXTURE_FORMAT_RGBA"); - - lua_register(ctx->luaState, "textureLoad", moduleTextureLoad); -} - -int moduleTextureIndex(lua_State *l) { - assertNotNull(l, "Lua state cannot be NULL."); - - texture_t *tex = (texture_t *)luaL_checkudata(l, 1, "texture_mt"); - assertNotNull(tex, "Texture pointer cannot be NULL."); - - const char *key = luaL_checkstring(l, 2); - assertNotNull(key, "Key cannot be NULL."); - - if(stringCompare(key, "width") == 0) { - lua_pushnumber(l, tex->width); - return 1; - } else if(stringCompare(key, "height") == 0) { - lua_pushnumber(l, tex->height); - return 1; - } - - lua_pushnil(l); - return 1; -} - -int moduleTextureToString(lua_State *l) { - assertNotNull(l, "Lua state cannot be NULL."); - - texture_t *tex = (texture_t *)luaL_checkudata(l, 1, "texture_mt"); - assertNotNull(tex, "Texture pointer cannot be NULL."); - - char buffer[64]; - snprintf(buffer, sizeof(buffer), "Texture(%dx%d)", tex->width, tex->height); - lua_pushstring(l, buffer); - return 1; -} - -int moduleTextureGC(lua_State *l) { - assertNotNull(l, "Lua state cannot be NULL."); - - texture_t *tex = (texture_t *)luaL_checkudata(l, 1, "texture_mt"); - assertNotNull(tex, "Texture pointer cannot be NULL."); - - textureDispose(tex); - return 0; -} - -int moduleTextureLoad(lua_State *l) { - assertNotNull(l, "Lua state cannot be NULL."); - - if(!lua_isstring(l, 1)) { - luaL_error(l, "First argument must be a string filename."); - return 0; - } - - if(!lua_isnumber(l, 2)) { - luaL_error(l, "Second argument must be a number format."); - return 0; - } - - const char_t *filename = lua_tostring(l, 1); - assertNotNull(filename, "Filename cannot be NULL."); - assertStrLenMin(filename, 1, "Filename cannot be empty."); - - // Create texture owned to lua - texture_t *tex = (texture_t *)lua_newuserdata(l, sizeof(texture_t)); - memoryZero(tex, sizeof(texture_t)); - - textureformat_t format = (textureformat_t)lua_tonumber(l, 2); - - errorret_t ret = assetTextureLoad(filename, tex, format); - if(ret.code != ERROR_OK) { - errorCatch(errorPrint(ret)); - luaL_error(l, "Failed to load texture asset: %s", filename); - return 0; - } - - // Set metatable - luaL_getmetatable(l, "texture_mt"); - lua_setmetatable(l, -2); - - // Return the texture - return 1; -} \ No newline at end of file diff --git a/src/dusk/script/module/display/moduletexture.h b/src/dusk/script/module/display/moduletexture.h index 5d8e1796..9300ff48 100644 --- a/src/dusk/script/module/display/moduletexture.h +++ b/src/dusk/script/module/display/moduletexture.h @@ -1,15 +1,97 @@ /** * Copyright (c) 2026 Dominic Masters - * + * * This software is released under the MIT License. * https://opensource.org/licenses/MIT */ #pragma once -#include "script/scriptcontext.h" +#include "script/module/modulebase.h" +#include "display/texture/texture.h" +#include "asset/loader/display/assettextureloader.h" -void moduleTexture(scriptcontext_t *ctx); -int moduleTextureIndex(lua_State *l); -int moduleTextureToString(lua_State *l); -int moduleTextureGC(lua_State *l); -int moduleTextureLoad(lua_State *l); \ No newline at end of file +static int moduleTextureIndex(lua_State *l) { + assertNotNull(l, "Lua state cannot be NULL."); + + texture_t *tex = (texture_t *)luaL_checkudata(l, 1, "texture_mt"); + assertNotNull(tex, "Texture pointer cannot be NULL."); + const char *key = luaL_checkstring(l, 2); + assertNotNull(key, "Key cannot be NULL."); + + if(stringCompare(key, "width") == 0) { + lua_pushnumber(l, tex->width); return 1; + } else if(stringCompare(key, "height") == 0) { + lua_pushnumber(l, tex->height); return 1; + } + + lua_pushnil(l); + return 1; +} + +static int moduleTextureToString(lua_State *l) { + assertNotNull(l, "Lua state cannot be NULL."); + texture_t *tex = (texture_t *)luaL_checkudata(l, 1, "texture_mt"); + assertNotNull(tex, "Texture pointer cannot be NULL."); + char buffer[64]; + snprintf(buffer, sizeof(buffer), "Texture(%dx%d)", tex->width, tex->height); + lua_pushstring(l, buffer); + return 1; +} + +static int moduleTextureGC(lua_State *l) { + assertNotNull(l, "Lua state cannot be NULL."); + texture_t *tex = (texture_t *)luaL_checkudata(l, 1, "texture_mt"); + assertNotNull(tex, "Texture pointer cannot be NULL."); + textureDispose(tex); + return 0; +} + +static int moduleTextureLoad(lua_State *l) { + assertNotNull(l, "Lua state cannot be NULL."); + + if(!lua_isstring(l, 1)) { + luaL_error(l, "First argument must be a string filename."); + return 0; + } + if(!lua_isnumber(l, 2)) { + luaL_error(l, "Second argument must be a number format."); + return 0; + } + + const char_t *filename = lua_tostring(l, 1); + assertNotNull(filename, "Filename cannot be NULL."); + assertStrLenMin(filename, 1, "Filename cannot be empty."); + + texture_t *tex = (texture_t *)lua_newuserdata(l, sizeof(texture_t)); + memoryZero(tex, sizeof(texture_t)); + + textureformat_t format = (textureformat_t)lua_tonumber(l, 2); + errorret_t ret = assetTextureLoad(filename, tex, format); + if(ret.code != ERROR_OK) { + errorCatch(errorPrint(ret)); + luaL_error(l, "Failed to load texture asset: %s", filename); + return 0; + } + + luaL_getmetatable(l, "texture_mt"); + lua_setmetatable(l, -2); + return 1; +} + +static void moduleTexture(lua_State *L) { + assertNotNull(L, "Lua state cannot be null"); + + if(luaL_newmetatable(L, "texture_mt") == 1) { + lua_pushcfunction(L, moduleTextureIndex); + lua_setfield(L, -2, "__index"); + lua_pushcfunction(L, moduleTextureToString); + lua_setfield(L, -2, "__tostring"); + lua_pushcfunction(L, moduleTextureGC); + lua_setfield(L, -2, "__gc"); + } + + lua_pushnumber(L, TEXTURE_FORMAT_RGBA); + lua_setglobal(L, "TEXTURE_FORMAT_RGBA"); + + lua_register(L, "textureLoad", moduleTextureLoad); +} diff --git a/src/dusk/script/module/display/moduletileset.c b/src/dusk/script/module/display/moduletileset.c deleted file mode 100644 index de13430b..00000000 --- a/src/dusk/script/module/display/moduletileset.c +++ /dev/null @@ -1,164 +0,0 @@ -/** - * Copyright (c) 2026 Dominic Masters - * - * This software is released under the MIT License. - * https://opensource.org/licenses/MIT - */ - -#include "moduletileset.h" -#include "assert/assert.h" -#include "display/texture/tileset.h" -#include "util/memory.h" -#include "util/string.h" -#include "asset/loader/display/assettilesetloader.h" - -void moduleTileset(scriptcontext_t *ctx) { - assertNotNull(ctx, "Script context cannot be NULL"); - - // Tileset metatable - if(luaL_newmetatable(ctx->luaState, "tileset_mt")) { - lua_pushcfunction(ctx->luaState, moduleTilesetIndex); - lua_setfield(ctx->luaState, -2, "__index"); - - lua_pushcfunction(ctx->luaState, moduleTilesetToString); - lua_setfield(ctx->luaState, -2, "__tostring"); - } - lua_pop(ctx->luaState, 1); // Pop the metatable - - lua_register(ctx->luaState, "tilesetLoad", moduleTilesetLoad); - lua_register(ctx->luaState, "tilesetTileGetUV", moduleTilesetTileGetUV); - lua_register( - ctx->luaState, "tilesetPositionGetUV", moduleTilesetPositionGetUV - ); -} - -int moduleTilesetIndex(lua_State *l) { - assertNotNull(l, "Lua state cannot be NULL."); - - const char_t *key = luaL_checkstring(l, 2); - assertNotNull(key, "Key cannot be NULL."); - - tileset_t *ts = (tileset_t *)luaL_checkudata(l, 1, "tileset_mt"); - assertNotNull(ts, "Tileset pointer cannot be NULL."); - - if(stringCompare(key, "tileWidth") == 0) { - lua_pushnumber(l, ts->tileWidth); - return 1; - } else if(stringCompare(key, "tileHeight") == 0) { - lua_pushnumber(l, ts->tileHeight); - return 1; - } else if(stringCompare(key, "tileCount") == 0) { - lua_pushnumber(l, ts->tileCount); - return 1; - } else if(stringCompare(key, "columns") == 0) { - lua_pushnumber(l, ts->columns); - return 1; - } else if(stringCompare(key, "rows") == 0) { - lua_pushnumber(l, ts->rows); - return 1; - } - - lua_pushnil(l); - return 1; -} - -int moduleTilesetToString(lua_State *l) { - tileset_t *ts = (tileset_t *)luaL_checkudata(l, 1, "tileset_mt"); - assertNotNull(ts, "Tileset pointer cannot be NULL."); - - lua_pushfstring(l, "Tileset: %dx%d tile, %d columns, %d rows", - ts->tileWidth, ts->tileHeight, ts->columns, ts->rows - ); - return 1; -} - -int moduleTilesetTileGetUV(lua_State *l) { - assertNotNull(l, "Lua state cannot be NULL."); - - if(!lua_isuserdata(l, 1)) { - luaL_error(l, "First argument must be a tileset userdata."); - return 0; - } - - tileset_t *ts = (tileset_t *)luaL_checkudata(l, 1, "tileset_mt"); - assertNotNull(ts, "Tileset pointer cannot be NULL."); - - if(!lua_isnumber(l, 2)) { - luaL_error(l, "Second arguments must be tile index."); - return 0; - } - uint16_t tileIndex = (uint16_t)lua_tonumber(l, 2); - - // Create vec4 that lua owns - vec4 *uv = (vec4 *)lua_newuserdata(l, sizeof(vec4)); - tilesetTileGetUV(ts, tileIndex, *uv); - - // Set metatable - luaL_getmetatable(l, "vec4_mt"); - lua_setmetatable(l, -2); - return 1; -} - -int moduleTilesetPositionGetUV(lua_State *l) { - assertNotNull(l, "Lua state cannot be NULL."); - - if(!lua_isuserdata(l, 1)) { - luaL_error(l, "First argument must be a tileset userdata."); - return 0; - } - - tileset_t *ts = (tileset_t *)luaL_checkudata(l, 1, "tileset_mt"); - assertNotNull(ts, "Tileset pointer cannot be NULL."); - - if(!lua_isnumber(l, 2)) { - luaL_error(l, "Second arguments must be column number."); - return 0; - } - uint16_t column = (uint16_t)lua_tonumber(l, 2); - - if(!lua_isnumber(l, 3)) { - luaL_error(l, "Third arguments must be row number."); - return 0; - } - uint16_t row = (uint16_t)lua_tonumber(l, 3); - - // Create vec4 that lua owns - vec4 *uv = (vec4 *)lua_newuserdata(l, sizeof(vec4)); - tilesetPositionGetUV(ts, column, row, *uv); - - // Set metatable - luaL_getmetatable(l, "vec4_mt"); - lua_setmetatable(l, -2); - return 1; -} - -int moduleTilesetLoad(lua_State *l) { - assertNotNull(l, "Lua state cannot be NULL."); - - if(!lua_isstring(l, 1)) { - luaL_error(l, "First argument must be a string filename."); - return 0; - } - - const char_t *filename = lua_tostring(l, 1); - assertNotNull(filename, "Filename cannot be NULL."); - assertStrLenMin(filename, 1, "Filename cannot be empty."); - - // Create texture owned to lua - tileset_t *tileset = (tileset_t *)lua_newuserdata(l, sizeof(tileset_t)); - memoryZero(tileset, sizeof(tileset_t)); - - errorret_t ret = assetTilesetLoad(filename, tileset); - if(ret.code != ERROR_OK) { - errorCatch(errorPrint(ret)); - luaL_error(l, "Failed to load tileset asset: %s", filename); - return 0; - } - - // Set metatable - luaL_getmetatable(l, "tileset_mt"); - lua_setmetatable(l, -2); - - // Return the tileset - return 1; -} \ No newline at end of file diff --git a/src/dusk/script/module/display/moduletileset.h b/src/dusk/script/module/display/moduletileset.h index 5489e089..fd9f4b08 100644 --- a/src/dusk/script/module/display/moduletileset.h +++ b/src/dusk/script/module/display/moduletileset.h @@ -1,56 +1,108 @@ /** * Copyright (c) 2026 Dominic Masters - * + * * This software is released under the MIT License. * https://opensource.org/licenses/MIT */ #pragma once -#include "script/scriptcontext.h" +#include "script/module/modulebase.h" +#include "display/texture/tileset.h" +#include "asset/loader/display/assettilesetloader.h" +#include "script/module/math/modulevec4.h" -/** - * Registers the tileset module in the scripting context. - * - * @param ctx The scripting context to register the module in. - */ -void moduleTileset(scriptcontext_t *ctx); +static int moduleTilesetIndex(lua_State *l) { + assertNotNull(l, "Lua state cannot be NULL."); + const char_t *key = luaL_checkstring(l, 2); + assertNotNull(key, "Key cannot be NULL."); + tileset_t *ts = (tileset_t *)luaL_checkudata(l, 1, "tileset_mt"); + assertNotNull(ts, "Tileset pointer cannot be NULL."); -/** - * __index metamethod for tileset userdata. - * - * @param l The Lua state. - * @return The number of return values on the Lua stack. - */ -int moduleTilesetIndex(lua_State *l); + if(stringCompare(key, "tileWidth") == 0) { + lua_pushnumber(l, ts->tileWidth); return 1; + } else if(stringCompare(key, "tileHeight") == 0) { + lua_pushnumber(l, ts->tileHeight); return 1; + } else if(stringCompare(key, "tileCount") == 0) { + lua_pushnumber(l, ts->tileCount); return 1; + } else if(stringCompare(key, "columns") == 0) { + lua_pushnumber(l, ts->columns); return 1; + } else if(stringCompare(key, "rows") == 0) { + lua_pushnumber(l, ts->rows); return 1; + } -/** - * __tostring metamethod for tileset userdata. - * - * @param l The Lua state. - * @return The number of return values on the Lua stack. - */ -int moduleTilesetToString(lua_State *l); + lua_pushnil(l); + return 1; +} -/** - * Lua function to get the UV coordinates for a tile index in a tileset. - * - * @param l The Lua state. - * @return The number of return values on the Lua stack. - */ -int moduleTilesetTileGetUV(lua_State *l); +static int moduleTilesetToString(lua_State *l) { + tileset_t *ts = (tileset_t *)luaL_checkudata(l, 1, "tileset_mt"); + assertNotNull(ts, "Tileset pointer cannot be NULL."); + lua_pushfstring(l, "Tileset: %dx%d tile, %d columns, %d rows", + ts->tileWidth, ts->tileHeight, ts->columns, ts->rows + ); + return 1; +} -/** - * Lua function to get the UV coordinates for a tile position in a tileset. - * - * @param l The Lua state. - * @return The number of return values on the Lua stack. - */ -int moduleTilesetPositionGetUV(lua_State *l); +static int moduleTilesetTileGetUV(lua_State *l) { + assertNotNull(l, "Lua state cannot be NULL."); + tileset_t *ts = (tileset_t *)luaL_checkudata(l, 1, "tileset_mt"); + assertNotNull(ts, "Tileset pointer cannot be NULL."); + uint16_t tileIndex = (uint16_t)luaL_checknumber(l, 2); + vec4 uv; tilesetTileGetUV(ts, tileIndex, uv); + luaVec4Push(l, uv); + return 1; +} -/** - * Lua function to load a tileset from a texture and tile dimensions. - * - * @param l The Lua state. - * @return The number of return values on the Lua stack. - */ -int moduleTilesetLoad(lua_State *l); \ No newline at end of file +static int moduleTilesetPositionGetUV(lua_State *l) { + assertNotNull(l, "Lua state cannot be NULL."); + tileset_t *ts = (tileset_t *)luaL_checkudata(l, 1, "tileset_mt"); + assertNotNull(ts, "Tileset pointer cannot be NULL."); + uint16_t column = (uint16_t)luaL_checknumber(l, 2); + uint16_t row = (uint16_t)luaL_checknumber(l, 3); + vec4 uv; tilesetPositionGetUV(ts, column, row, uv); + luaVec4Push(l, uv); + return 1; +} + +static int moduleTilesetLoad(lua_State *l) { + assertNotNull(l, "Lua state cannot be NULL."); + + if(!lua_isstring(l, 1)) { + luaL_error(l, "First argument must be a string filename."); + return 0; + } + + const char_t *filename = lua_tostring(l, 1); + assertNotNull(filename, "Filename cannot be NULL."); + assertStrLenMin(filename, 1, "Filename cannot be empty."); + + tileset_t *tileset = (tileset_t *)lua_newuserdata(l, sizeof(tileset_t)); + memoryZero(tileset, sizeof(tileset_t)); + + errorret_t ret = assetTilesetLoad(filename, tileset); + if(ret.code != ERROR_OK) { + errorCatch(errorPrint(ret)); + luaL_error(l, "Failed to load tileset asset: %s", filename); + return 0; + } + + luaL_getmetatable(l, "tileset_mt"); + lua_setmetatable(l, -2); + return 1; +} + +static void moduleTileset(lua_State *L) { + assertNotNull(L, "Lua state cannot be NULL"); + + if(luaL_newmetatable(L, "tileset_mt")) { + lua_pushcfunction(L, moduleTilesetIndex); + lua_setfield(L, -2, "__index"); + lua_pushcfunction(L, moduleTilesetToString); + lua_setfield(L, -2, "__tostring"); + } + lua_pop(L, 1); + + lua_register(L, "tilesetLoad", moduleTilesetLoad); + lua_register(L, "tilesetTileGetUV", moduleTilesetTileGetUV); + lua_register(L, "tilesetPositionGetUV", moduleTilesetPositionGetUV); +} diff --git a/src/dusk/script/module/entity/CMakeLists.txt b/src/dusk/script/module/entity/CMakeLists.txt deleted file mode 100644 index 5a511cb0..00000000 --- a/src/dusk/script/module/entity/CMakeLists.txt +++ /dev/null @@ -1,15 +0,0 @@ -# Copyright (c) 2026 Dominic Masters -# -# This software is released under the MIT License. -# https://opensource.org/licenses/MIT - -# Sources -target_sources(${DUSK_LIBRARY_TARGET_NAME} - PUBLIC - moduleentity.c -) - -# Subdirectories -add_subdirectory(display) -add_subdirectory(physics) -add_subdirectory(script) diff --git a/src/dusk/script/module/entity/display/CMakeLists.txt b/src/dusk/script/module/entity/display/CMakeLists.txt deleted file mode 100644 index 8b90f2f8..00000000 --- a/src/dusk/script/module/entity/display/CMakeLists.txt +++ /dev/null @@ -1,12 +0,0 @@ -# Copyright (c) 2026 Dominic Masters -# -# This software is released under the MIT License. -# https://opensource.org/licenses/MIT - -target_sources(${DUSK_LIBRARY_TARGET_NAME} - PUBLIC - moduleentityposition.c - moduleentitycamera.c - moduleentitymesh.c - moduleentitymaterial.c -) diff --git a/src/dusk/script/module/entity/display/moduleentitycamera.c b/src/dusk/script/module/entity/display/moduleentitycamera.c deleted file mode 100644 index 942f97a6..00000000 --- a/src/dusk/script/module/entity/display/moduleentitycamera.c +++ /dev/null @@ -1,135 +0,0 @@ -/** - * Copyright (c) 2026 Dominic Masters - * - * This software is released under the MIT License. - * https://opensource.org/licenses/MIT - */ - -#include "moduleentitycamera.h" -#include "assert/assert.h" -#include "entity/entity.h" -#include "entity/component/display/entitycamera.h" -#include "script/module/math/modulevec2.h" - -typedef struct { - entityid_t entityId; - componentid_t compId; -} entitycamera_handle_t; - -static void pushEntityCameraHandle( - lua_State *L, - entityid_t entityId, - componentid_t compId -) { - entitycamera_handle_t *h = lua_newuserdata( - L, sizeof(entitycamera_handle_t) - ); - h->entityId = entityId; - h->compId = compId; - luaL_getmetatable(L, "entitycamera_mt"); - lua_setmetatable(L, -2); -} - -static int entityCameraIndex(lua_State *L) { - entitycamera_handle_t *h = luaL_checkudata(L, 1, "entitycamera_mt"); - assertNotNull(h, "EntityCamera handle cannot be NULL"); - const char *key = luaL_checkstring(L, 2); - - if(strcmp(key, "zNear") == 0) { - lua_pushnumber( - L, (lua_Number)entityCameraGetZNear(h->entityId, h->compId) - ); - return 1; - } else if(strcmp(key, "zFar") == 0) { - lua_pushnumber( - L, (lua_Number)entityCameraGetZFar(h->entityId, h->compId) - ); - return 1; - } - - lua_getmetatable(L, 1); - lua_getfield(L, -1, key); - return 1; -} - -static int entityCameraNewindex(lua_State *L) { - entitycamera_handle_t *h = luaL_checkudata(L, 1, "entitycamera_mt"); - assertNotNull(h, "EntityCamera handle cannot be NULL"); - const char *key = luaL_checkstring(L, 2); - - if(strcmp(key, "zNear") == 0) { - entityCameraSetZNear( - h->entityId, h->compId, (float_t)luaL_checknumber(L, 3) - ); - return 0; - } else if(strcmp(key, "zFar") == 0) { - entityCameraSetZFar( - h->entityId, h->compId, (float_t)luaL_checknumber(L, 3) - ); - return 0; - } - - luaL_error(L, "entitycamera: unknown property '%s'", key); - return 0; -} - -static int entityCameraGetForwardMethod(lua_State *L) { - entitycamera_handle_t *h = luaL_checkudata(L, 1, "entitycamera_mt"); - assertNotNull(h, "EntityCamera handle cannot be NULL"); - vec2 fwd; - entityCameraGetForward(h->entityId, fwd); - luaVec2Push(L, fwd); - return 1; -} - -static int entityCameraGetRightMethod(lua_State *L) { - entitycamera_handle_t *h = luaL_checkudata(L, 1, "entitycamera_mt"); - assertNotNull(h, "EntityCamera handle cannot be NULL"); - vec2 right; - entityCameraGetRight(h->entityId, right); - luaVec2Push(L, right); - return 1; -} - -static int entityCameraAdd(lua_State *L) { - assertNotNull(L, "Lua state cannot be NULL"); - entityid_t entityId = (entityid_t)luaL_checknumber(L, 1); - componentid_t compId = entityAddComponent(entityId, COMPONENT_TYPE_CAMERA); - pushEntityCameraHandle(L, entityId, compId); - return 1; -} - -static int entityCameraGetCurrentGlobal(lua_State *L) { - assertNotNull(L, "Lua state cannot be NULL"); - entityid_t camEnts[ENTITY_COUNT_MAX]; - componentid_t camComps[ENTITY_COUNT_MAX]; - entityid_t count = componentGetEntitiesWithComponent( - COMPONENT_TYPE_CAMERA, camEnts, camComps - ); - if(count == 0) { - lua_pushnil(L); - return 1; - } - pushEntityCameraHandle(L, camEnts[0], camComps[0]); - return 1; -} - -void moduleEntityCamera(scriptcontext_t *ctx) { - assertNotNull(ctx, "Script context cannot be NULL"); - - lua_State *L = ctx->luaState; - - luaL_newmetatable(L, "entitycamera_mt"); - lua_pushcfunction(L, entityCameraIndex); - lua_setfield(L, -2, "__index"); - lua_pushcfunction(L, entityCameraNewindex); - lua_setfield(L, -2, "__newindex"); - lua_pushcfunction(L, entityCameraGetForwardMethod); - lua_setfield(L, -2, "getForward"); - lua_pushcfunction(L, entityCameraGetRightMethod); - lua_setfield(L, -2, "getRight"); - lua_pop(L, 1); - - lua_register(L, "entityCameraAdd", entityCameraAdd); - lua_register(L, "entityCameraGetCurrent", entityCameraGetCurrentGlobal); -} diff --git a/src/dusk/script/module/entity/display/moduleentitycamera.h b/src/dusk/script/module/entity/display/moduleentitycamera.h index f5acfe20..85cca377 100644 --- a/src/dusk/script/module/entity/display/moduleentitycamera.h +++ b/src/dusk/script/module/entity/display/moduleentitycamera.h @@ -6,6 +6,128 @@ */ #pragma once -#include "script/scriptcontext.h" +#include "script/module/modulebase.h" +#include "entity/entity.h" +#include "entity/component/display/entitycamera.h" +#include "script/module/math/modulevec2.h" -void moduleEntityCamera(scriptcontext_t *ctx); +typedef struct { + entityid_t entityId; + componentid_t compId; +} entitycamera_handle_t; + +static void pushEntityCameraHandle( + lua_State *L, + entityid_t entityId, + componentid_t compId +) { + entitycamera_handle_t *h = lua_newuserdata( + L, sizeof(entitycamera_handle_t) + ); + h->entityId = entityId; + h->compId = compId; + luaL_getmetatable(L, "entitycamera_mt"); + lua_setmetatable(L, -2); +} + +static int entityCameraIndex(lua_State *L) { + entitycamera_handle_t *h = luaL_checkudata(L, 1, "entitycamera_mt"); + assertNotNull(h, "EntityCamera handle cannot be NULL"); + const char *key = luaL_checkstring(L, 2); + + if(stringCompare(key, "zNear") == 0) { + lua_pushnumber( + L, (lua_Number)entityCameraGetZNear(h->entityId, h->compId) + ); + return 1; + } else if(stringCompare(key, "zFar") == 0) { + lua_pushnumber( + L, (lua_Number)entityCameraGetZFar(h->entityId, h->compId) + ); + return 1; + } + + lua_getmetatable(L, 1); + lua_getfield(L, -1, key); + return 1; +} + +static int entityCameraNewindex(lua_State *L) { + entitycamera_handle_t *h = luaL_checkudata(L, 1, "entitycamera_mt"); + assertNotNull(h, "EntityCamera handle cannot be NULL"); + const char *key = luaL_checkstring(L, 2); + + if(stringCompare(key, "zNear") == 0) { + entityCameraSetZNear( + h->entityId, h->compId, (float_t)luaL_checknumber(L, 3) + ); + return 0; + } else if(stringCompare(key, "zFar") == 0) { + entityCameraSetZFar( + h->entityId, h->compId, (float_t)luaL_checknumber(L, 3) + ); + return 0; + } + + luaL_error(L, "entitycamera: unknown property '%s'", key); + return 0; +} + +static int entityCameraGetForwardMethod(lua_State *L) { + entitycamera_handle_t *h = luaL_checkudata(L, 1, "entitycamera_mt"); + assertNotNull(h, "EntityCamera handle cannot be NULL"); + vec2 fwd; + entityCameraGetForward(h->entityId, fwd); + luaVec2Push(L, fwd); + return 1; +} + +static int entityCameraGetRightMethod(lua_State *L) { + entitycamera_handle_t *h = luaL_checkudata(L, 1, "entitycamera_mt"); + assertNotNull(h, "EntityCamera handle cannot be NULL"); + vec2 right; + entityCameraGetRight(h->entityId, right); + luaVec2Push(L, right); + return 1; +} + +static int entityCameraAdd(lua_State *L) { + assertNotNull(L, "Lua state cannot be NULL"); + entityid_t entityId = (entityid_t)luaL_checknumber(L, 1); + componentid_t compId = entityAddComponent(entityId, COMPONENT_TYPE_CAMERA); + pushEntityCameraHandle(L, entityId, compId); + return 1; +} + +static int entityCameraGetCurrentGlobal(lua_State *L) { + assertNotNull(L, "Lua state cannot be NULL"); + entityid_t camEnts[ENTITY_COUNT_MAX]; + componentid_t camComps[ENTITY_COUNT_MAX]; + entityid_t count = componentGetEntitiesWithComponent( + COMPONENT_TYPE_CAMERA, camEnts, camComps + ); + if(count == 0) { + lua_pushnil(L); + return 1; + } + pushEntityCameraHandle(L, camEnts[0], camComps[0]); + return 1; +} + +static void moduleEntityCamera(lua_State *L) { + assertNotNull(L, "Lua state cannot be NULL"); + + luaL_newmetatable(L, "entitycamera_mt"); + lua_pushcfunction(L, entityCameraIndex); + lua_setfield(L, -2, "__index"); + lua_pushcfunction(L, entityCameraNewindex); + lua_setfield(L, -2, "__newindex"); + lua_pushcfunction(L, entityCameraGetForwardMethod); + lua_setfield(L, -2, "getForward"); + lua_pushcfunction(L, entityCameraGetRightMethod); + lua_setfield(L, -2, "getRight"); + lua_pop(L, 1); + + lua_register(L, "entityCameraAdd", entityCameraAdd); + lua_register(L, "entityCameraGetCurrent", entityCameraGetCurrentGlobal); +} diff --git a/src/dusk/script/module/entity/display/moduleentitymaterial.c b/src/dusk/script/module/entity/display/moduleentitymaterial.c deleted file mode 100644 index 93e54447..00000000 --- a/src/dusk/script/module/entity/display/moduleentitymaterial.c +++ /dev/null @@ -1,74 +0,0 @@ -/** - * Copyright (c) 2026 Dominic Masters - * - * This software is released under the MIT License. - * https://opensource.org/licenses/MIT - */ - -#include "moduleentitymaterial.h" -#include "assert/assert.h" -#include "entity/entity.h" -#include "entity/component/display/entitymaterial.h" - -typedef struct { - entityid_t entityId; - componentid_t compId; -} entitymaterial_handle_t; - -static void pushEntityMaterialHandle( - lua_State *L, - entityid_t entityId, - componentid_t compId -) { - entitymaterial_handle_t *h = lua_newuserdata( - L, sizeof(entitymaterial_handle_t) - ); - h->entityId = entityId; - h->compId = compId; - luaL_getmetatable(L, "entitymaterial_mt"); - lua_setmetatable(L, -2); -} - -static int entityMaterialIndex(lua_State *L) { - lua_getmetatable(L, 1); - lua_getfield(L, -1, luaL_checkstring(L, 2)); - return 1; -} - -static int entityMaterialNewindex(lua_State *L) { - entitymaterial_handle_t *h = luaL_checkudata(L, 1, "entitymaterial_mt"); - assertNotNull(h, "EntityMaterial handle cannot be NULL"); - const char *key = luaL_checkstring(L, 2); - - if(strcmp(key, "color") == 0) { - const color_t *col = (const color_t *)luaL_checkudata(L, 3, "color_mt"); - entityMaterialSetColor(h->entityId, h->compId, *col); - return 0; - } - - luaL_error(L, "entitymaterial: unknown property '%s'", key); - return 0; -} - -static int entityMaterialAdd(lua_State *L) { - assertNotNull(L, "Lua state cannot be NULL"); - entityid_t entityId = (entityid_t)luaL_checknumber(L, 1); - componentid_t compId = entityAddComponent(entityId, COMPONENT_TYPE_MATERIAL); - pushEntityMaterialHandle(L, entityId, compId); - return 1; -} - -void moduleEntityMaterial(scriptcontext_t *ctx) { - assertNotNull(ctx, "Script context cannot be NULL"); - - lua_State *L = ctx->luaState; - - luaL_newmetatable(L, "entitymaterial_mt"); - lua_pushcfunction(L, entityMaterialIndex); - lua_setfield(L, -2, "__index"); - lua_pushcfunction(L, entityMaterialNewindex); - lua_setfield(L, -2, "__newindex"); - lua_pop(L, 1); - - lua_register(L, "entityMaterialAdd", entityMaterialAdd); -} diff --git a/src/dusk/script/module/entity/display/moduleentitymaterial.h b/src/dusk/script/module/entity/display/moduleentitymaterial.h index 38fb004c..bd183f22 100644 --- a/src/dusk/script/module/entity/display/moduleentitymaterial.h +++ b/src/dusk/script/module/entity/display/moduleentitymaterial.h @@ -6,6 +6,67 @@ */ #pragma once -#include "script/scriptcontext.h" +#include "script/module/modulebase.h" +#include "entity/entity.h" +#include "entity/component/display/entitymaterial.h" -void moduleEntityMaterial(scriptcontext_t *ctx); +typedef struct { + entityid_t entityId; + componentid_t compId; +} entitymaterial_handle_t; + +static void pushEntityMaterialHandle( + lua_State *L, + entityid_t entityId, + componentid_t compId +) { + entitymaterial_handle_t *h = lua_newuserdata( + L, sizeof(entitymaterial_handle_t) + ); + h->entityId = entityId; + h->compId = compId; + luaL_getmetatable(L, "entitymaterial_mt"); + lua_setmetatable(L, -2); +} + +static int entityMaterialIndex(lua_State *L) { + lua_getmetatable(L, 1); + lua_getfield(L, -1, luaL_checkstring(L, 2)); + return 1; +} + +static int entityMaterialNewindex(lua_State *L) { + entitymaterial_handle_t *h = luaL_checkudata(L, 1, "entitymaterial_mt"); + assertNotNull(h, "EntityMaterial handle cannot be NULL"); + const char *key = luaL_checkstring(L, 2); + + if(stringCompare(key, "color") == 0) { + const color_t *col = (const color_t *)luaL_checkudata(L, 3, "color_mt"); + entityMaterialSetColor(h->entityId, h->compId, *col); + return 0; + } + + luaL_error(L, "entitymaterial: unknown property '%s'", key); + return 0; +} + +static int entityMaterialAdd(lua_State *L) { + assertNotNull(L, "Lua state cannot be NULL"); + entityid_t entityId = (entityid_t)luaL_checknumber(L, 1); + componentid_t compId = entityAddComponent(entityId, COMPONENT_TYPE_MATERIAL); + pushEntityMaterialHandle(L, entityId, compId); + return 1; +} + +static void moduleEntityMaterial(lua_State *L) { + assertNotNull(L, "Lua state cannot be NULL"); + + luaL_newmetatable(L, "entitymaterial_mt"); + lua_pushcfunction(L, entityMaterialIndex); + lua_setfield(L, -2, "__index"); + lua_pushcfunction(L, entityMaterialNewindex); + lua_setfield(L, -2, "__newindex"); + lua_pop(L, 1); + + lua_register(L, "entityMaterialAdd", entityMaterialAdd); +} diff --git a/src/dusk/script/module/entity/display/moduleentitymesh.c b/src/dusk/script/module/entity/display/moduleentitymesh.c deleted file mode 100644 index 09a2728b..00000000 --- a/src/dusk/script/module/entity/display/moduleentitymesh.c +++ /dev/null @@ -1,85 +0,0 @@ -/** - * Copyright (c) 2026 Dominic Masters - * - * This software is released under the MIT License. - * https://opensource.org/licenses/MIT - */ - -#include "moduleentitymesh.h" -#include "assert/assert.h" -#include "entity/entity.h" -#include "entity/component/display/entitymesh.h" - -typedef struct { - entityid_t entityId; - componentid_t compId; -} entitymesh_handle_t; - -static void pushEntityMeshHandle( - lua_State *L, - entityid_t entityId, - componentid_t compId -) { - entitymesh_handle_t *h = lua_newuserdata(L, sizeof(entitymesh_handle_t)); - h->entityId = entityId; - h->compId = compId; - luaL_getmetatable(L, "entitymesh_mt"); - lua_setmetatable(L, -2); -} - -static int entityMeshIndex(lua_State *L) { - lua_getmetatable(L, 1); - lua_getfield(L, -1, luaL_checkstring(L, 2)); - return 1; -} - -static int entityMeshGeneratePlaneMethod(lua_State *L) { - entitymesh_handle_t *h = luaL_checkudata(L, 1, "entitymesh_mt"); - assertNotNull(h, "EntityMesh handle cannot be NULL"); - float_t width = (float_t)luaL_checknumber(L, 2); - float_t height = (float_t)luaL_checknumber(L, 3); - errorret_t err = entityMeshGeneratePlane(h->entityId, h->compId, width, height); - if(err.code != ERROR_OK) { - luaL_error(L, "Failed to generate plane mesh"); - } - return 0; -} - -static int entityMeshGenerateCapsuleMethod(lua_State *L) { - entitymesh_handle_t *h = luaL_checkudata(L, 1, "entitymesh_mt"); - assertNotNull(h, "EntityMesh handle cannot be NULL"); - float_t radius = (float_t)luaL_checknumber(L, 2); - float_t halfHeight = (float_t)luaL_checknumber(L, 3); - errorret_t err = entityMeshGenerateCapsule( - h->entityId, h->compId, radius, halfHeight - ); - if(err.code != ERROR_OK) { - luaL_error(L, "Failed to generate capsule mesh"); - } - return 0; -} - -static int entityMeshAdd(lua_State *L) { - assertNotNull(L, "Lua state cannot be NULL"); - entityid_t entityId = (entityid_t)luaL_checknumber(L, 1); - componentid_t compId = entityAddComponent(entityId, COMPONENT_TYPE_MESH); - pushEntityMeshHandle(L, entityId, compId); - return 1; -} - -void moduleEntityMesh(scriptcontext_t *ctx) { - assertNotNull(ctx, "Script context cannot be NULL"); - - lua_State *L = ctx->luaState; - - luaL_newmetatable(L, "entitymesh_mt"); - lua_pushcfunction(L, entityMeshIndex); - lua_setfield(L, -2, "__index"); - lua_pushcfunction(L, entityMeshGeneratePlaneMethod); - lua_setfield(L, -2, "generatePlane"); - lua_pushcfunction(L, entityMeshGenerateCapsuleMethod); - lua_setfield(L, -2, "generateCapsule"); - lua_pop(L, 1); - - lua_register(L, "entityMeshAdd", entityMeshAdd); -} diff --git a/src/dusk/script/module/entity/display/moduleentitymesh.h b/src/dusk/script/module/entity/display/moduleentitymesh.h index 0b8ab3d0..6a227ca9 100644 --- a/src/dusk/script/module/entity/display/moduleentitymesh.h +++ b/src/dusk/script/module/entity/display/moduleentitymesh.h @@ -6,6 +6,78 @@ */ #pragma once -#include "script/scriptcontext.h" +#include "script/module/modulebase.h" +#include "entity/entity.h" +#include "entity/component/display/entitymesh.h" -void moduleEntityMesh(scriptcontext_t *ctx); +typedef struct { + entityid_t entityId; + componentid_t compId; +} entitymesh_handle_t; + +static void pushEntityMeshHandle( + lua_State *L, + entityid_t entityId, + componentid_t compId +) { + entitymesh_handle_t *h = lua_newuserdata(L, sizeof(entitymesh_handle_t)); + h->entityId = entityId; + h->compId = compId; + luaL_getmetatable(L, "entitymesh_mt"); + lua_setmetatable(L, -2); +} + +static int entityMeshIndex(lua_State *L) { + lua_getmetatable(L, 1); + lua_getfield(L, -1, luaL_checkstring(L, 2)); + return 1; +} + +static int entityMeshGeneratePlaneMethod(lua_State *L) { + entitymesh_handle_t *h = luaL_checkudata(L, 1, "entitymesh_mt"); + assertNotNull(h, "EntityMesh handle cannot be NULL"); + float_t width = (float_t)luaL_checknumber(L, 2); + float_t height = (float_t)luaL_checknumber(L, 3); + errorret_t err = entityMeshGeneratePlane(h->entityId, h->compId, width, height); + if(err.code != ERROR_OK) { + luaL_error(L, "Failed to generate plane mesh"); + } + return 0; +} + +static int entityMeshGenerateCapsuleMethod(lua_State *L) { + entitymesh_handle_t *h = luaL_checkudata(L, 1, "entitymesh_mt"); + assertNotNull(h, "EntityMesh handle cannot be NULL"); + float_t radius = (float_t)luaL_checknumber(L, 2); + float_t halfHeight = (float_t)luaL_checknumber(L, 3); + errorret_t err = entityMeshGenerateCapsule( + h->entityId, h->compId, radius, halfHeight + ); + if(err.code != ERROR_OK) { + luaL_error(L, "Failed to generate capsule mesh"); + } + return 0; +} + +static int entityMeshAdd(lua_State *L) { + assertNotNull(L, "Lua state cannot be NULL"); + entityid_t entityId = (entityid_t)luaL_checknumber(L, 1); + componentid_t compId = entityAddComponent(entityId, COMPONENT_TYPE_MESH); + pushEntityMeshHandle(L, entityId, compId); + return 1; +} + +static void moduleEntityMesh(lua_State *L) { + assertNotNull(L, "Lua state cannot be NULL"); + + luaL_newmetatable(L, "entitymesh_mt"); + lua_pushcfunction(L, entityMeshIndex); + lua_setfield(L, -2, "__index"); + lua_pushcfunction(L, entityMeshGeneratePlaneMethod); + lua_setfield(L, -2, "generatePlane"); + lua_pushcfunction(L, entityMeshGenerateCapsuleMethod); + lua_setfield(L, -2, "generateCapsule"); + lua_pop(L, 1); + + lua_register(L, "entityMeshAdd", entityMeshAdd); +} diff --git a/src/dusk/script/module/entity/display/moduleentityposition.c b/src/dusk/script/module/entity/display/moduleentityposition.c deleted file mode 100644 index bc406e96..00000000 --- a/src/dusk/script/module/entity/display/moduleentityposition.c +++ /dev/null @@ -1,153 +0,0 @@ -/** - * Copyright (c) 2026 Dominic Masters - * - * This software is released under the MIT License. - * https://opensource.org/licenses/MIT - */ - -#include "moduleentityposition.h" -#include "assert/assert.h" -#include "entity/entity.h" -#include "entity/component/display/entityposition.h" -#include "script/module/math/modulevec3.h" - -typedef struct { - entityid_t entityId; - componentid_t compId; -} entityposition_handle_t; - -static void pushEntityPositionHandle( - lua_State *L, - entityid_t entityId, - componentid_t compId -) { - entityposition_handle_t *h = lua_newuserdata( - L, sizeof(entityposition_handle_t) - ); - h->entityId = entityId; - h->compId = compId; - luaL_getmetatable(L, "entityposition_mt"); - lua_setmetatable(L, -2); -} - -static int entityPositionIndex(lua_State *L) { - entityposition_handle_t *h = luaL_checkudata(L, 1, "entityposition_mt"); - assertNotNull(h, "EntityPosition handle cannot be NULL"); - const char *key = luaL_checkstring(L, 2); - - if(strcmp(key, "x") == 0) { - vec3 v; entityPositionGetPosition(h->entityId, h->compId, v); - lua_pushnumber(L, v[0]); return 1; - } else if(strcmp(key, "y") == 0) { - vec3 v; entityPositionGetPosition(h->entityId, h->compId, v); - lua_pushnumber(L, v[1]); return 1; - } else if(strcmp(key, "z") == 0) { - vec3 v; entityPositionGetPosition(h->entityId, h->compId, v); - lua_pushnumber(L, v[2]); return 1; - } else if(strcmp(key, "rotX") == 0) { - vec3 v; entityPositionGetRotation(h->entityId, h->compId, v); - lua_pushnumber(L, v[0]); return 1; - } else if(strcmp(key, "rotY") == 0) { - vec3 v; entityPositionGetRotation(h->entityId, h->compId, v); - lua_pushnumber(L, v[1]); return 1; - } else if(strcmp(key, "rotZ") == 0) { - vec3 v; entityPositionGetRotation(h->entityId, h->compId, v); - lua_pushnumber(L, v[2]); return 1; - } else if(strcmp(key, "scaleX") == 0) { - vec3 v; entityPositionGetScale(h->entityId, h->compId, v); - lua_pushnumber(L, v[0]); return 1; - } else if(strcmp(key, "scaleY") == 0) { - vec3 v; entityPositionGetScale(h->entityId, h->compId, v); - lua_pushnumber(L, v[1]); return 1; - } else if(strcmp(key, "scaleZ") == 0) { - vec3 v; entityPositionGetScale(h->entityId, h->compId, v); - lua_pushnumber(L, v[2]); return 1; - } - - lua_getmetatable(L, 1); - lua_getfield(L, -1, key); - return 1; -} - -static int entityPositionNewindex(lua_State *L) { - entityposition_handle_t *h = luaL_checkudata(L, 1, "entityposition_mt"); - assertNotNull(h, "EntityPosition handle cannot be NULL"); - const char *key = luaL_checkstring(L, 2); - - if(strcmp(key, "x") == 0) { - vec3 v; entityPositionGetPosition(h->entityId, h->compId, v); - v[0] = (float_t)luaL_checknumber(L, 3); - entityPositionSetPosition(h->entityId, h->compId, v); return 0; - } else if(strcmp(key, "y") == 0) { - vec3 v; entityPositionGetPosition(h->entityId, h->compId, v); - v[1] = (float_t)luaL_checknumber(L, 3); - entityPositionSetPosition(h->entityId, h->compId, v); return 0; - } else if(strcmp(key, "z") == 0) { - vec3 v; entityPositionGetPosition(h->entityId, h->compId, v); - v[2] = (float_t)luaL_checknumber(L, 3); - entityPositionSetPosition(h->entityId, h->compId, v); return 0; - } else if(strcmp(key, "rotX") == 0) { - vec3 v; entityPositionGetRotation(h->entityId, h->compId, v); - v[0] = (float_t)luaL_checknumber(L, 3); - entityPositionSetRotation(h->entityId, h->compId, v); return 0; - } else if(strcmp(key, "rotY") == 0) { - vec3 v; entityPositionGetRotation(h->entityId, h->compId, v); - v[1] = (float_t)luaL_checknumber(L, 3); - entityPositionSetRotation(h->entityId, h->compId, v); return 0; - } else if(strcmp(key, "rotZ") == 0) { - vec3 v; entityPositionGetRotation(h->entityId, h->compId, v); - v[2] = (float_t)luaL_checknumber(L, 3); - entityPositionSetRotation(h->entityId, h->compId, v); return 0; - } else if(strcmp(key, "scaleX") == 0) { - vec3 v; entityPositionGetScale(h->entityId, h->compId, v); - v[0] = (float_t)luaL_checknumber(L, 3); - entityPositionSetScale(h->entityId, h->compId, v); return 0; - } else if(strcmp(key, "scaleY") == 0) { - vec3 v; entityPositionGetScale(h->entityId, h->compId, v); - v[1] = (float_t)luaL_checknumber(L, 3); - entityPositionSetScale(h->entityId, h->compId, v); return 0; - } else if(strcmp(key, "scaleZ") == 0) { - vec3 v; entityPositionGetScale(h->entityId, h->compId, v); - v[2] = (float_t)luaL_checknumber(L, 3); - entityPositionSetScale(h->entityId, h->compId, v); return 0; - } - - luaL_error(L, "entityposition: unknown property '%s'", key); - return 0; -} - -static int entityPositionLookAtMethod(lua_State *L) { - entityposition_handle_t *h = luaL_checkudata(L, 1, "entityposition_mt"); - assertNotNull(h, "EntityPosition handle cannot be NULL"); - vec3 target, up, eye; - luaVec3Check(L, 2, target); - luaVec3Check(L, 3, up); - luaVec3Check(L, 4, eye); - entityPositionLookAt(h->entityId, h->compId, target, up, eye); - return 0; -} - -static int entityPositionAdd(lua_State *L) { - assertNotNull(L, "Lua state cannot be NULL"); - entityid_t entityId = (entityid_t)luaL_checknumber(L, 1); - componentid_t compId = entityAddComponent(entityId, COMPONENT_TYPE_POSITION); - pushEntityPositionHandle(L, entityId, compId); - return 1; -} - -void moduleEntityPosition(scriptcontext_t *ctx) { - assertNotNull(ctx, "Script context cannot be NULL"); - - lua_State *L = ctx->luaState; - - luaL_newmetatable(L, "entityposition_mt"); - lua_pushcfunction(L, entityPositionIndex); - lua_setfield(L, -2, "__index"); - lua_pushcfunction(L, entityPositionNewindex); - lua_setfield(L, -2, "__newindex"); - lua_pushcfunction(L, entityPositionLookAtMethod); - lua_setfield(L, -2, "lookAt"); - lua_pop(L, 1); - - lua_register(L, "entityPositionAdd", entityPositionAdd); -} diff --git a/src/dusk/script/module/entity/display/moduleentityposition.h b/src/dusk/script/module/entity/display/moduleentityposition.h index 6097ac0e..fef8900e 100644 --- a/src/dusk/script/module/entity/display/moduleentityposition.h +++ b/src/dusk/script/module/entity/display/moduleentityposition.h @@ -6,6 +6,164 @@ */ #pragma once -#include "script/scriptcontext.h" +#include "script/module/modulebase.h" +#include "entity/entity.h" +#include "entity/component/display/entityposition.h" +#include "script/module/math/modulevec3.h" -void moduleEntityPosition(scriptcontext_t *ctx); +typedef struct { + entityid_t entityId; + componentid_t compId; +} entityposition_handle_t; + +static void pushEntityPositionHandle( + lua_State *L, + entityid_t entityId, + componentid_t compId +) { + entityposition_handle_t *h = lua_newuserdata( + L, sizeof(entityposition_handle_t) + ); + h->entityId = entityId; + h->compId = compId; + luaL_getmetatable(L, "entityposition_mt"); + lua_setmetatable(L, -2); +} + +static int entityPositionIndex(lua_State *L) { + entityposition_handle_t *h = luaL_checkudata(L, 1, "entityposition_mt"); + assertNotNull(h, "EntityPosition handle cannot be NULL"); + const char *key = luaL_checkstring(L, 2); + + if(stringCompare(key, "x") == 0) { + vec3 v; entityPositionGetPosition(h->entityId, h->compId, v); + lua_pushnumber(L, v[0]); return 1; + } else if(stringCompare(key, "y") == 0) { + vec3 v; entityPositionGetPosition(h->entityId, h->compId, v); + lua_pushnumber(L, v[1]); return 1; + } else if(stringCompare(key, "z") == 0) { + vec3 v; entityPositionGetPosition(h->entityId, h->compId, v); + lua_pushnumber(L, v[2]); return 1; + } else if(stringCompare(key, "rotX") == 0) { + vec3 v; entityPositionGetRotation(h->entityId, h->compId, v); + lua_pushnumber(L, v[0]); return 1; + } else if(stringCompare(key, "rotY") == 0) { + vec3 v; entityPositionGetRotation(h->entityId, h->compId, v); + lua_pushnumber(L, v[1]); return 1; + } else if(stringCompare(key, "rotZ") == 0) { + vec3 v; entityPositionGetRotation(h->entityId, h->compId, v); + lua_pushnumber(L, v[2]); return 1; + } else if(stringCompare(key, "scaleX") == 0) { + vec3 v; entityPositionGetScale(h->entityId, h->compId, v); + lua_pushnumber(L, v[0]); return 1; + } else if(stringCompare(key, "scaleY") == 0) { + vec3 v; entityPositionGetScale(h->entityId, h->compId, v); + lua_pushnumber(L, v[1]); return 1; + } else if(stringCompare(key, "scaleZ") == 0) { + vec3 v; entityPositionGetScale(h->entityId, h->compId, v); + lua_pushnumber(L, v[2]); return 1; + } else if(stringCompare(key, "position") == 0) { + vec3 v; entityPositionGetPosition(h->entityId, h->compId, v); + luaVec3Push(L, v); return 1; + } else if(stringCompare(key, "rotation") == 0) { + vec3 v; entityPositionGetRotation(h->entityId, h->compId, v); + luaVec3Push(L, v); return 1; + } else if(stringCompare(key, "scale") == 0) { + vec3 v; entityPositionGetScale(h->entityId, h->compId, v); + luaVec3Push(L, v); return 1; + } + + lua_getmetatable(L, 1); + lua_getfield(L, -1, key); + return 1; +} + +static int entityPositionNewindex(lua_State *L) { + entityposition_handle_t *h = luaL_checkudata(L, 1, "entityposition_mt"); + assertNotNull(h, "EntityPosition handle cannot be NULL"); + const char *key = luaL_checkstring(L, 2); + + if(stringCompare(key, "x") == 0) { + vec3 v; entityPositionGetPosition(h->entityId, h->compId, v); + v[0] = (float_t)luaL_checknumber(L, 3); + entityPositionSetPosition(h->entityId, h->compId, v); return 0; + } else if(stringCompare(key, "y") == 0) { + vec3 v; entityPositionGetPosition(h->entityId, h->compId, v); + v[1] = (float_t)luaL_checknumber(L, 3); + entityPositionSetPosition(h->entityId, h->compId, v); return 0; + } else if(stringCompare(key, "z") == 0) { + vec3 v; entityPositionGetPosition(h->entityId, h->compId, v); + v[2] = (float_t)luaL_checknumber(L, 3); + entityPositionSetPosition(h->entityId, h->compId, v); return 0; + } else if(stringCompare(key, "rotX") == 0) { + vec3 v; entityPositionGetRotation(h->entityId, h->compId, v); + v[0] = (float_t)luaL_checknumber(L, 3); + entityPositionSetRotation(h->entityId, h->compId, v); return 0; + } else if(stringCompare(key, "rotY") == 0) { + vec3 v; entityPositionGetRotation(h->entityId, h->compId, v); + v[1] = (float_t)luaL_checknumber(L, 3); + entityPositionSetRotation(h->entityId, h->compId, v); return 0; + } else if(stringCompare(key, "rotZ") == 0) { + vec3 v; entityPositionGetRotation(h->entityId, h->compId, v); + v[2] = (float_t)luaL_checknumber(L, 3); + entityPositionSetRotation(h->entityId, h->compId, v); return 0; + } else if(stringCompare(key, "scaleX") == 0) { + vec3 v; entityPositionGetScale(h->entityId, h->compId, v); + v[0] = (float_t)luaL_checknumber(L, 3); + entityPositionSetScale(h->entityId, h->compId, v); return 0; + } else if(stringCompare(key, "scaleY") == 0) { + vec3 v; entityPositionGetScale(h->entityId, h->compId, v); + v[1] = (float_t)luaL_checknumber(L, 3); + entityPositionSetScale(h->entityId, h->compId, v); return 0; + } else if(stringCompare(key, "scaleZ") == 0) { + vec3 v; entityPositionGetScale(h->entityId, h->compId, v); + v[2] = (float_t)luaL_checknumber(L, 3); + entityPositionSetScale(h->entityId, h->compId, v); return 0; + } else if(stringCompare(key, "position") == 0) { + vec3 v; luaVec3Check(L, 3, v); + entityPositionSetPosition(h->entityId, h->compId, v); return 0; + } else if(stringCompare(key, "rotation") == 0) { + vec3 v; luaVec3Check(L, 3, v); + entityPositionSetRotation(h->entityId, h->compId, v); return 0; + } else if(stringCompare(key, "scale") == 0) { + vec3 v; luaVec3Check(L, 3, v); + entityPositionSetScale(h->entityId, h->compId, v); return 0; + } + + luaL_error(L, "entityposition: unknown property '%s'", key); + return 0; +} + +static int entityPositionLookAtMethod(lua_State *L) { + entityposition_handle_t *h = luaL_checkudata(L, 1, "entityposition_mt"); + assertNotNull(h, "EntityPosition handle cannot be NULL"); + vec3 target, up, eye; + luaVec3Check(L, 2, target); + luaVec3Check(L, 3, up); + luaVec3Check(L, 4, eye); + entityPositionLookAt(h->entityId, h->compId, target, up, eye); + return 0; +} + +static int entityPositionAdd(lua_State *L) { + assertNotNull(L, "Lua state cannot be NULL"); + entityid_t entityId = (entityid_t)luaL_checknumber(L, 1); + componentid_t compId = entityAddComponent(entityId, COMPONENT_TYPE_POSITION); + pushEntityPositionHandle(L, entityId, compId); + return 1; +} + +static void moduleEntityPosition(lua_State *L) { + assertNotNull(L, "Lua state cannot be NULL"); + + luaL_newmetatable(L, "entityposition_mt"); + lua_pushcfunction(L, entityPositionIndex); + lua_setfield(L, -2, "__index"); + lua_pushcfunction(L, entityPositionNewindex); + lua_setfield(L, -2, "__newindex"); + lua_pushcfunction(L, entityPositionLookAtMethod); + lua_setfield(L, -2, "lookAt"); + lua_pop(L, 1); + + lua_register(L, "entityPositionAdd", entityPositionAdd); +} diff --git a/src/dusk/script/module/entity/moduleentity.c b/src/dusk/script/module/entity/moduleentity.c deleted file mode 100644 index 82a8b3f3..00000000 --- a/src/dusk/script/module/entity/moduleentity.c +++ /dev/null @@ -1,52 +0,0 @@ -/** - * Copyright (c) 2026 Dominic Masters - * - * This software is released under the MIT License. - * https://opensource.org/licenses/MIT - */ - -#include "moduleentity.h" -#include "assert/assert.h" -#include "entity/entitymanager.h" -#include "entity/entity.h" -#include "display/moduleentityposition.h" -#include "display/moduleentitycamera.h" -#include "display/moduleentitymesh.h" -#include "display/moduleentitymaterial.h" -#include "physics/moduleentityphysics.h" -#include "script/moduleentityscript.h" - -void moduleEntity(scriptcontext_t *ctx) { - assertNotNull(ctx, "Script context cannot be NULL"); - - lua_register(ctx->luaState, "entityAdd", moduleEntityAdd); - lua_register(ctx->luaState, "entityRemove", moduleEntityRemove); - - moduleEntityPosition(ctx); - moduleEntityCamera(ctx); - moduleEntityMesh(ctx); - moduleEntityMaterial(ctx); - moduleEntityPhysics(ctx); - moduleEntityScript(ctx); -} - -int moduleEntityAdd(lua_State *L) { - assertNotNull(L, "Lua state cannot be NULL"); - - entityid_t id = entityManagerAdd(); - lua_pushnumber(L, (lua_Number)id); - return 1; -} - -int moduleEntityRemove(lua_State *L) { - assertNotNull(L, "Lua state cannot be NULL"); - - if(!lua_isnumber(L, 1)) { - luaL_error(L, "entityRemove requires a number entity ID"); - return 0; - } - - entityid_t id = (entityid_t)luaL_checknumber(L, 1); - entityDispose(id); - return 0; -} diff --git a/src/dusk/script/module/entity/moduleentity.h b/src/dusk/script/module/entity/moduleentity.h index 3f7da12f..e393a8a6 100644 --- a/src/dusk/script/module/entity/moduleentity.h +++ b/src/dusk/script/module/entity/moduleentity.h @@ -6,27 +6,47 @@ */ #pragma once -#include "script/scriptcontext.h" +#include "script/module/modulebase.h" +#include "entity/entitymanager.h" +#include "entity/entity.h" +#include "display/moduleentityposition.h" +#include "display/moduleentitycamera.h" +#include "display/moduleentitymesh.h" +#include "display/moduleentitymaterial.h" +#include "physics/moduleentityphysics.h" +#include "script/moduleentityscript.h" -/** - * Register the entity module within the given script context. - * - * @param ctx The script context to register the module in. - */ -void moduleEntity(scriptcontext_t *ctx); +static int moduleEntityAdd(lua_State *L) { + assertNotNull(L, "Lua state cannot be NULL"); -/** - * Lua binding for entityManagerAdd - creates a new entity and returns its ID. - * - * @param L The Lua state. - * @return int Number of return values on the Lua stack. - */ -int moduleEntityAdd(lua_State *L); + entityid_t id = entityManagerAdd(); + lua_pushnumber(L, (lua_Number)id); + return 1; +} -/** - * Lua binding for entityDispose - disposes of an entity by its ID. - * - * @param L The Lua state. - * @return int Number of return values on the Lua stack. - */ -int moduleEntityRemove(lua_State *L); +static int moduleEntityRemove(lua_State *L) { + assertNotNull(L, "Lua state cannot be NULL"); + + if(!lua_isnumber(L, 1)) { + luaL_error(L, "entityRemove requires a number entity ID"); + return 0; + } + + entityid_t id = (entityid_t)luaL_checknumber(L, 1); + entityDispose(id); + return 0; +} + +static void moduleEntity(lua_State *L) { + assertNotNull(L, "Lua state cannot be NULL"); + + lua_register(L, "entityAdd", moduleEntityAdd); + lua_register(L, "entityRemove", moduleEntityRemove); + + moduleEntityPosition(L); + moduleEntityCamera(L); + moduleEntityMesh(L); + moduleEntityMaterial(L); + moduleEntityPhysics(L); + moduleEntityScript(L); +} diff --git a/src/dusk/script/module/entity/physics/CMakeLists.txt b/src/dusk/script/module/entity/physics/CMakeLists.txt deleted file mode 100644 index ba860634..00000000 --- a/src/dusk/script/module/entity/physics/CMakeLists.txt +++ /dev/null @@ -1,9 +0,0 @@ -# Copyright (c) 2026 Dominic Masters -# -# This software is released under the MIT License. -# https://opensource.org/licenses/MIT - -target_sources(${DUSK_LIBRARY_TARGET_NAME} - PUBLIC - moduleentityphysics.c -) diff --git a/src/dusk/script/module/entity/physics/moduleentityphysics.c b/src/dusk/script/module/entity/physics/moduleentityphysics.c deleted file mode 100644 index 6a9a0016..00000000 --- a/src/dusk/script/module/entity/physics/moduleentityphysics.c +++ /dev/null @@ -1,195 +0,0 @@ -/** - * Copyright (c) 2026 Dominic Masters - * - * This software is released under the MIT License. - * https://opensource.org/licenses/MIT - */ - -#include "moduleentityphysics.h" -#include "assert/assert.h" -#include "entity/entity.h" -#include "entity/component/physics/entityphysics.h" -#include "physics/physicsbodytype.h" -#include "script/module/math/modulevec3.h" - -typedef struct { - entityid_t entityId; - componentid_t compId; -} entityphysics_handle_t; - -static void pushEntityPhysicsHandle( - lua_State *L, - entityid_t entityId, - componentid_t compId -) { - entityphysics_handle_t *h = lua_newuserdata( - L, sizeof(entityphysics_handle_t) - ); - h->entityId = entityId; - h->compId = compId; - luaL_getmetatable(L, "entityphysics_mt"); - lua_setmetatable(L, -2); -} - -static int entityPhysicsIndex(lua_State *L) { - entityphysics_handle_t *h = luaL_checkudata(L, 1, "entityphysics_mt"); - assertNotNull(h, "EntityPhysics handle cannot be NULL"); - const char *key = luaL_checkstring(L, 2); - - if(strcmp(key, "bodyType") == 0) { - lua_pushnumber( - L, (lua_Number)entityPhysicsGetBodyType(h->entityId, h->compId) - ); - return 1; - } else if(strcmp(key, "velocityX") == 0) { - vec3 v; entityPhysicsGetVelocity(h->entityId, h->compId, v); - lua_pushnumber(L, v[0]); return 1; - } else if(strcmp(key, "velocityY") == 0) { - vec3 v; entityPhysicsGetVelocity(h->entityId, h->compId, v); - lua_pushnumber(L, v[1]); return 1; - } else if(strcmp(key, "velocityZ") == 0) { - vec3 v; entityPhysicsGetVelocity(h->entityId, h->compId, v); - lua_pushnumber(L, v[2]); return 1; - } else if(strcmp(key, "velocity") == 0) { - vec3 v; entityPhysicsGetVelocity(h->entityId, h->compId, v); - luaVec3Push(L, v); return 1; - } else if(strcmp(key, "onGround") == 0) { - lua_pushboolean( - L, (int)entityPhysicsIsOnGround(h->entityId, h->compId) - ); - return 1; - } - - lua_getmetatable(L, 1); - lua_getfield(L, -1, key); - return 1; -} - -static int entityPhysicsNewindex(lua_State *L) { - entityphysics_handle_t *h = luaL_checkudata(L, 1, "entityphysics_mt"); - assertNotNull(h, "EntityPhysics handle cannot be NULL"); - const char *key = luaL_checkstring(L, 2); - - if(strcmp(key, "bodyType") == 0) { - physicsbodytype_t t = (physicsbodytype_t)luaL_checknumber(L, 3); - entityPhysicsSetBodyType(h->entityId, h->compId, t); - return 0; - } else if(strcmp(key, "velocityX") == 0) { - vec3 v; entityPhysicsGetVelocity(h->entityId, h->compId, v); - v[0] = (float_t)luaL_checknumber(L, 3); - entityPhysicsSetVelocity(h->entityId, h->compId, v); return 0; - } else if(strcmp(key, "velocityY") == 0) { - vec3 v; entityPhysicsGetVelocity(h->entityId, h->compId, v); - v[1] = (float_t)luaL_checknumber(L, 3); - entityPhysicsSetVelocity(h->entityId, h->compId, v); return 0; - } else if(strcmp(key, "velocityZ") == 0) { - vec3 v; entityPhysicsGetVelocity(h->entityId, h->compId, v); - v[2] = (float_t)luaL_checknumber(L, 3); - entityPhysicsSetVelocity(h->entityId, h->compId, v); return 0; - } else if(strcmp(key, "velocity") == 0) { - vec3 v; luaVec3Check(L, 3, v); - entityPhysicsSetVelocity(h->entityId, h->compId, v); return 0; - } - - luaL_error(L, "entityphysics: unknown property '%s'", key); - return 0; -} - -static int entityPhysicsSetShapeCapsuleMethod(lua_State *L) { - entityphysics_handle_t *h = luaL_checkudata(L, 1, "entityphysics_mt"); - assertNotNull(h, "EntityPhysics handle cannot be NULL"); - physicsshape_t shape; - shape.type = PHYSICS_SHAPE_CAPSULE; - shape.data.capsule.radius = (float_t)luaL_checknumber(L, 2); - shape.data.capsule.halfHeight = (float_t)luaL_checknumber(L, 3); - entityPhysicsSetShape(h->entityId, h->compId, shape); - return 0; -} - -static int entityPhysicsSetShapePlaneMethod(lua_State *L) { - entityphysics_handle_t *h = luaL_checkudata(L, 1, "entityphysics_mt"); - assertNotNull(h, "EntityPhysics handle cannot be NULL"); - physicsshape_t shape; - shape.type = PHYSICS_SHAPE_PLANE; - shape.data.plane.normal[0] = (float_t)luaL_checknumber(L, 2); - shape.data.plane.normal[1] = (float_t)luaL_checknumber(L, 3); - shape.data.plane.normal[2] = (float_t)luaL_checknumber(L, 4); - shape.data.plane.distance = (float_t)luaL_checknumber(L, 5); - entityPhysicsSetShape(h->entityId, h->compId, shape); - return 0; -} - -static int entityPhysicsSetShapeSphereMethod(lua_State *L) { - entityphysics_handle_t *h = luaL_checkudata(L, 1, "entityphysics_mt"); - assertNotNull(h, "EntityPhysics handle cannot be NULL"); - physicsshape_t shape; - shape.type = PHYSICS_SHAPE_SPHERE; - shape.data.sphere.radius = (float_t)luaL_checknumber(L, 2); - entityPhysicsSetShape(h->entityId, h->compId, shape); - return 0; -} - -static int entityPhysicsSetShapeCubeMethod(lua_State *L) { - entityphysics_handle_t *h = luaL_checkudata(L, 1, "entityphysics_mt"); - assertNotNull(h, "EntityPhysics handle cannot be NULL"); - physicsshape_t shape; - shape.type = PHYSICS_SHAPE_CUBE; - shape.data.cube.halfExtents[0] = (float_t)luaL_checknumber(L, 2); - shape.data.cube.halfExtents[1] = (float_t)luaL_checknumber(L, 3); - shape.data.cube.halfExtents[2] = (float_t)luaL_checknumber(L, 4); - entityPhysicsSetShape(h->entityId, h->compId, shape); - return 0; -} - -static int entityPhysicsApplyImpulseMethod(lua_State *L) { - entityphysics_handle_t *h = luaL_checkudata(L, 1, "entityphysics_mt"); - assertNotNull(h, "EntityPhysics handle cannot be NULL"); - vec3 impulse = { - (float_t)luaL_checknumber(L, 2), - (float_t)luaL_checknumber(L, 3), - (float_t)luaL_checknumber(L, 4) - }; - entityPhysicsApplyImpulse(h->entityId, h->compId, impulse); - return 0; -} - -static int entityPhysicsAdd(lua_State *L) { - assertNotNull(L, "Lua state cannot be NULL"); - entityid_t entityId = (entityid_t)luaL_checknumber(L, 1); - componentid_t compId = entityAddComponent(entityId, COMPONENT_TYPE_PHYSICS); - pushEntityPhysicsHandle(L, entityId, compId); - return 1; -} - -void moduleEntityPhysics(scriptcontext_t *ctx) { - assertNotNull(ctx, "Script context cannot be NULL"); - - lua_State *L = ctx->luaState; - - #define SET(name, val) \ - lua_pushnumber(L, (lua_Number)(val)); \ - lua_setglobal(L, name) - SET("PHYSICS_BODY_STATIC", PHYSICS_BODY_STATIC); - SET("PHYSICS_BODY_DYNAMIC", PHYSICS_BODY_DYNAMIC); - SET("PHYSICS_BODY_KINEMATIC", PHYSICS_BODY_KINEMATIC); - #undef SET - - luaL_newmetatable(L, "entityphysics_mt"); - lua_pushcfunction(L, entityPhysicsIndex); - lua_setfield(L, -2, "__index"); - lua_pushcfunction(L, entityPhysicsNewindex); - lua_setfield(L, -2, "__newindex"); - lua_pushcfunction(L, entityPhysicsSetShapeCapsuleMethod); - lua_setfield(L, -2, "setShapeCapsule"); - lua_pushcfunction(L, entityPhysicsSetShapePlaneMethod); - lua_setfield(L, -2, "setShapePlane"); - lua_pushcfunction(L, entityPhysicsSetShapeSphereMethod); - lua_setfield(L, -2, "setShapeSphere"); - lua_pushcfunction(L, entityPhysicsSetShapeCubeMethod); - lua_setfield(L, -2, "setShapeCube"); - lua_pushcfunction(L, entityPhysicsApplyImpulseMethod); - lua_setfield(L, -2, "applyImpulse"); - lua_pop(L, 1); - - lua_register(L, "entityPhysicsAdd", entityPhysicsAdd); -} diff --git a/src/dusk/script/module/entity/physics/moduleentityphysics.h b/src/dusk/script/module/entity/physics/moduleentityphysics.h index 30e967b9..56599f66 100644 --- a/src/dusk/script/module/entity/physics/moduleentityphysics.h +++ b/src/dusk/script/module/entity/physics/moduleentityphysics.h @@ -6,6 +6,186 @@ */ #pragma once -#include "script/scriptcontext.h" +#include "script/module/modulebase.h" +#include "entity/entity.h" +#include "entity/component/physics/entityphysics.h" +#include "physics/physicsbodytype.h" +#include "script/module/math/modulevec3.h" -void moduleEntityPhysics(scriptcontext_t *ctx); +typedef struct { + entityid_t entityId; + componentid_t compId; +} entityphysics_handle_t; + +static void pushEntityPhysicsHandle( + lua_State *L, + entityid_t entityId, + componentid_t compId +) { + entityphysics_handle_t *h = lua_newuserdata( + L, sizeof(entityphysics_handle_t) + ); + h->entityId = entityId; + h->compId = compId; + luaL_getmetatable(L, "entityphysics_mt"); + lua_setmetatable(L, -2); +} + +static int entityPhysicsIndex(lua_State *L) { + entityphysics_handle_t *h = luaL_checkudata(L, 1, "entityphysics_mt"); + assertNotNull(h, "EntityPhysics handle cannot be NULL"); + const char *key = luaL_checkstring(L, 2); + + if(stringCompare(key, "bodyType") == 0) { + lua_pushnumber( + L, (lua_Number)entityPhysicsGetBodyType(h->entityId, h->compId) + ); + return 1; + } else if(stringCompare(key, "velocityX") == 0) { + vec3 v; entityPhysicsGetVelocity(h->entityId, h->compId, v); + lua_pushnumber(L, v[0]); return 1; + } else if(stringCompare(key, "velocityY") == 0) { + vec3 v; entityPhysicsGetVelocity(h->entityId, h->compId, v); + lua_pushnumber(L, v[1]); return 1; + } else if(stringCompare(key, "velocityZ") == 0) { + vec3 v; entityPhysicsGetVelocity(h->entityId, h->compId, v); + lua_pushnumber(L, v[2]); return 1; + } else if(stringCompare(key, "velocity") == 0) { + vec3 v; entityPhysicsGetVelocity(h->entityId, h->compId, v); + luaVec3Push(L, v); return 1; + } else if(stringCompare(key, "onGround") == 0) { + lua_pushboolean( + L, (int)entityPhysicsIsOnGround(h->entityId, h->compId) + ); + return 1; + } + + lua_getmetatable(L, 1); + lua_getfield(L, -1, key); + return 1; +} + +static int entityPhysicsNewindex(lua_State *L) { + entityphysics_handle_t *h = luaL_checkudata(L, 1, "entityphysics_mt"); + assertNotNull(h, "EntityPhysics handle cannot be NULL"); + const char *key = luaL_checkstring(L, 2); + + if(stringCompare(key, "bodyType") == 0) { + physicsbodytype_t t = (physicsbodytype_t)luaL_checknumber(L, 3); + entityPhysicsSetBodyType(h->entityId, h->compId, t); + return 0; + } else if(stringCompare(key, "velocityX") == 0) { + vec3 v; entityPhysicsGetVelocity(h->entityId, h->compId, v); + v[0] = (float_t)luaL_checknumber(L, 3); + entityPhysicsSetVelocity(h->entityId, h->compId, v); return 0; + } else if(stringCompare(key, "velocityY") == 0) { + vec3 v; entityPhysicsGetVelocity(h->entityId, h->compId, v); + v[1] = (float_t)luaL_checknumber(L, 3); + entityPhysicsSetVelocity(h->entityId, h->compId, v); return 0; + } else if(stringCompare(key, "velocityZ") == 0) { + vec3 v; entityPhysicsGetVelocity(h->entityId, h->compId, v); + v[2] = (float_t)luaL_checknumber(L, 3); + entityPhysicsSetVelocity(h->entityId, h->compId, v); return 0; + } else if(stringCompare(key, "velocity") == 0) { + vec3 v; luaVec3Check(L, 3, v); + entityPhysicsSetVelocity(h->entityId, h->compId, v); return 0; + } + + luaL_error(L, "entityphysics: unknown property '%s'", key); + return 0; +} + +static int entityPhysicsSetShapeCapsuleMethod(lua_State *L) { + entityphysics_handle_t *h = luaL_checkudata(L, 1, "entityphysics_mt"); + assertNotNull(h, "EntityPhysics handle cannot be NULL"); + physicsshape_t shape; + shape.type = PHYSICS_SHAPE_CAPSULE; + shape.data.capsule.radius = (float_t)luaL_checknumber(L, 2); + shape.data.capsule.halfHeight = (float_t)luaL_checknumber(L, 3); + entityPhysicsSetShape(h->entityId, h->compId, shape); + return 0; +} + +static int entityPhysicsSetShapePlaneMethod(lua_State *L) { + entityphysics_handle_t *h = luaL_checkudata(L, 1, "entityphysics_mt"); + assertNotNull(h, "EntityPhysics handle cannot be NULL"); + physicsshape_t shape; + shape.type = PHYSICS_SHAPE_PLANE; + vec3 normal; luaVec3Check(L, 2, normal); + shape.data.plane.normal[0] = normal[0]; + shape.data.plane.normal[1] = normal[1]; + shape.data.plane.normal[2] = normal[2]; + shape.data.plane.distance = (float_t)luaL_checknumber(L, 3); + entityPhysicsSetShape(h->entityId, h->compId, shape); + return 0; +} + +static int entityPhysicsSetShapeSphereMethod(lua_State *L) { + entityphysics_handle_t *h = luaL_checkudata(L, 1, "entityphysics_mt"); + assertNotNull(h, "EntityPhysics handle cannot be NULL"); + physicsshape_t shape; + shape.type = PHYSICS_SHAPE_SPHERE; + shape.data.sphere.radius = (float_t)luaL_checknumber(L, 2); + entityPhysicsSetShape(h->entityId, h->compId, shape); + return 0; +} + +static int entityPhysicsSetShapeCubeMethod(lua_State *L) { + entityphysics_handle_t *h = luaL_checkudata(L, 1, "entityphysics_mt"); + assertNotNull(h, "EntityPhysics handle cannot be NULL"); + physicsshape_t shape; + shape.type = PHYSICS_SHAPE_CUBE; + vec3 half; luaVec3Check(L, 2, half); + shape.data.cube.halfExtents[0] = half[0]; + shape.data.cube.halfExtents[1] = half[1]; + shape.data.cube.halfExtents[2] = half[2]; + entityPhysicsSetShape(h->entityId, h->compId, shape); + return 0; +} + +static int entityPhysicsApplyImpulseMethod(lua_State *L) { + entityphysics_handle_t *h = luaL_checkudata(L, 1, "entityphysics_mt"); + assertNotNull(h, "EntityPhysics handle cannot be NULL"); + vec3 impulse; luaVec3Check(L, 2, impulse); + entityPhysicsApplyImpulse(h->entityId, h->compId, impulse); + return 0; +} + +static int entityPhysicsAdd(lua_State *L) { + assertNotNull(L, "Lua state cannot be NULL"); + entityid_t entityId = (entityid_t)luaL_checknumber(L, 1); + componentid_t compId = entityAddComponent(entityId, COMPONENT_TYPE_PHYSICS); + pushEntityPhysicsHandle(L, entityId, compId); + return 1; +} + +static void moduleEntityPhysics(lua_State *L) { + assertNotNull(L, "Lua state cannot be NULL"); + + #define SET(name, val) \ + lua_pushnumber(L, (lua_Number)(val)); \ + lua_setglobal(L, name) + SET("PHYSICS_BODY_STATIC", PHYSICS_BODY_STATIC); + SET("PHYSICS_BODY_DYNAMIC", PHYSICS_BODY_DYNAMIC); + SET("PHYSICS_BODY_KINEMATIC", PHYSICS_BODY_KINEMATIC); + #undef SET + + luaL_newmetatable(L, "entityphysics_mt"); + lua_pushcfunction(L, entityPhysicsIndex); + lua_setfield(L, -2, "__index"); + lua_pushcfunction(L, entityPhysicsNewindex); + lua_setfield(L, -2, "__newindex"); + lua_pushcfunction(L, entityPhysicsSetShapeCapsuleMethod); + lua_setfield(L, -2, "setShapeCapsule"); + lua_pushcfunction(L, entityPhysicsSetShapePlaneMethod); + lua_setfield(L, -2, "setShapePlane"); + lua_pushcfunction(L, entityPhysicsSetShapeSphereMethod); + lua_setfield(L, -2, "setShapeSphere"); + lua_pushcfunction(L, entityPhysicsSetShapeCubeMethod); + lua_setfield(L, -2, "setShapeCube"); + lua_pushcfunction(L, entityPhysicsApplyImpulseMethod); + lua_setfield(L, -2, "applyImpulse"); + lua_pop(L, 1); + + lua_register(L, "entityPhysicsAdd", entityPhysicsAdd); +} diff --git a/src/dusk/script/module/entity/script/CMakeLists.txt b/src/dusk/script/module/entity/script/CMakeLists.txt deleted file mode 100644 index d1fa1a37..00000000 --- a/src/dusk/script/module/entity/script/CMakeLists.txt +++ /dev/null @@ -1,9 +0,0 @@ -# Copyright (c) 2026 Dominic Masters -# -# This software is released under the MIT License. -# https://opensource.org/licenses/MIT - -target_sources(${DUSK_LIBRARY_TARGET_NAME} - PUBLIC - moduleentityscript.c -) diff --git a/src/dusk/script/module/entity/script/moduleentityscript.c b/src/dusk/script/module/entity/script/moduleentityscript.c deleted file mode 100644 index d9c85553..00000000 --- a/src/dusk/script/module/entity/script/moduleentityscript.c +++ /dev/null @@ -1,85 +0,0 @@ -/** - * Copyright (c) 2026 Dominic Masters - * - * This software is released under the MIT License. - * https://opensource.org/licenses/MIT - */ - -#include "moduleentityscript.h" -#include "assert/assert.h" -#include "entity/entity.h" -#include "entity/entitymanager.h" -#include "entity/component/script/entityscript.h" - -void moduleEntityScript(scriptcontext_t *ctx) { - assertNotNull(ctx, "Script context cannot be NULL"); - - #define REG(name, func) lua_register(ctx->luaState, name, func) - REG("entityScriptAdd", moduleEntityScriptAdd); - REG("entityScriptSetScript", moduleEntityScriptSetScript); - REG("entityScriptUpdate", moduleEntityScriptUpdate); - REG("entityAddScripted", moduleEntityAddScripted); - #undef REG -} - -int moduleEntityScriptAdd(lua_State *L) { - assertNotNull(L, "Lua state cannot be NULL"); - - entityid_t entityId = (entityid_t)luaL_checknumber(L, 1); - componentid_t compId = entityAddComponent(entityId, COMPONENT_TYPE_ENTITYSCRIPT); - lua_pushnumber(L, (lua_Number)compId); - return 1; -} - -int moduleEntityScriptSetScript(lua_State *L) { - assertNotNull(L, "Lua state cannot be NULL"); - - entityid_t entityId = (entityid_t)luaL_checknumber(L, 1); - componentid_t compId = (componentid_t)luaL_checknumber(L, 2); - const char_t *filename = luaL_checkstring(L, 3); - - errorret_t err = entityScriptSetScript(entityId, compId, filename); - if(err.code != ERROR_OK) { - luaL_error(L, "Failed to set entity script: %s", filename); - errorCatch(errorPrint(err)); - return 0; - } - - return 0; -} - -int moduleEntityAddScripted(lua_State *L) { - assertNotNull(L, "Lua state cannot be NULL"); - - const char_t *filename = luaL_checkstring(L, 1); - - entityid_t entityId = entityManagerAdd(); - componentid_t compId = entityAddComponent(entityId, COMPONENT_TYPE_ENTITYSCRIPT); - - errorret_t err = entityScriptSetScript(entityId, compId, filename); - if(err.code != ERROR_OK) { - luaL_error(L, "Failed to set entity script: %s", filename); - errorCatch(errorPrint(err)); - return 0; - } - - lua_pushnumber(L, (lua_Number)entityId); - lua_pushnumber(L, (lua_Number)compId); - return 2; -} - -int moduleEntityScriptUpdate(lua_State *L) { - assertNotNull(L, "Lua state cannot be NULL"); - - entityid_t entityId = (entityid_t)luaL_checknumber(L, 1); - componentid_t compId = (componentid_t)luaL_checknumber(L, 2); - - errorret_t err = entityScriptUpdate(entityId, compId); - if(err.code != ERROR_OK) { - luaL_error(L, "Failed to update entity script"); - errorCatch(errorPrint(err)); - return 0; - } - - return 0; -} diff --git a/src/dusk/script/module/entity/script/moduleentityscript.h b/src/dusk/script/module/entity/script/moduleentityscript.h index 00ab45ab..abbaa3ed 100644 --- a/src/dusk/script/module/entity/script/moduleentityscript.h +++ b/src/dusk/script/module/entity/script/moduleentityscript.h @@ -6,11 +6,78 @@ */ #pragma once -#include "script/scriptcontext.h" +#include "script/module/modulebase.h" +#include "entity/entity.h" +#include "entity/entitymanager.h" +#include "entity/component/script/entityscript.h" -void moduleEntityScript(scriptcontext_t *ctx); +static int moduleEntityScriptAdd(lua_State *L) { + assertNotNull(L, "Lua state cannot be NULL"); -int moduleEntityScriptAdd(lua_State *L); -int moduleEntityScriptSetScript(lua_State *L); -int moduleEntityScriptUpdate(lua_State *L); -int moduleEntityAddScripted(lua_State *L); + entityid_t entityId = (entityid_t)luaL_checknumber(L, 1); + componentid_t compId = entityAddComponent(entityId, COMPONENT_TYPE_ENTITYSCRIPT); + lua_pushnumber(L, (lua_Number)compId); + return 1; +} + +static int moduleEntityScriptSetScript(lua_State *L) { + assertNotNull(L, "Lua state cannot be NULL"); + + entityid_t entityId = (entityid_t)luaL_checknumber(L, 1); + componentid_t compId = (componentid_t)luaL_checknumber(L, 2); + const char_t *filename = luaL_checkstring(L, 3); + + errorret_t err = entityScriptSetScript(entityId, compId, filename); + if(err.code != ERROR_OK) { + luaL_error(L, "Failed to set entity script: %s", filename); + errorCatch(errorPrint(err)); + return 0; + } + + return 0; +} + +static int moduleEntityAddScripted(lua_State *L) { + assertNotNull(L, "Lua state cannot be NULL"); + + const char_t *filename = luaL_checkstring(L, 1); + + entityid_t entityId = entityManagerAdd(); + componentid_t compId = entityAddComponent(entityId, COMPONENT_TYPE_ENTITYSCRIPT); + + errorret_t err = entityScriptSetScript(entityId, compId, filename); + if(err.code != ERROR_OK) { + luaL_error(L, "Failed to set entity script: %s", filename); + errorCatch(errorPrint(err)); + return 0; + } + + lua_pushnumber(L, (lua_Number)entityId); + lua_pushnumber(L, (lua_Number)compId); + return 2; +} + +static int moduleEntityScriptUpdate(lua_State *L) { + assertNotNull(L, "Lua state cannot be NULL"); + + entityid_t entityId = (entityid_t)luaL_checknumber(L, 1); + componentid_t compId = (componentid_t)luaL_checknumber(L, 2); + + errorret_t err = entityScriptUpdate(entityId, compId); + if(err.code != ERROR_OK) { + luaL_error(L, "Failed to update entity script"); + errorCatch(errorPrint(err)); + return 0; + } + + return 0; +} + +static void moduleEntityScript(lua_State *L) { + assertNotNull(L, "Lua state cannot be NULL"); + + lua_register(L, "entityScriptAdd", moduleEntityScriptAdd); + lua_register(L, "entityScriptSetScript", moduleEntityScriptSetScript); + lua_register(L, "entityScriptUpdate", moduleEntityScriptUpdate); + lua_register(L, "entityAddScripted", moduleEntityAddScripted); +} diff --git a/src/dusk/script/module/event/CMakeLists.txt b/src/dusk/script/module/event/CMakeLists.txt deleted file mode 100644 index ffc4e91c..00000000 --- a/src/dusk/script/module/event/CMakeLists.txt +++ /dev/null @@ -1,10 +0,0 @@ -# Copyright (c) 2025 Dominic Masters -# -# This software is released under the MIT License. -# https://opensource.org/licenses/MIT - -# Sources -target_sources(${DUSK_LIBRARY_TARGET_NAME} - PUBLIC - moduleevent.c -) \ No newline at end of file diff --git a/src/dusk/script/module/event/moduleevent.c b/src/dusk/script/module/event/moduleevent.c deleted file mode 100644 index ef72cf2e..00000000 --- a/src/dusk/script/module/event/moduleevent.c +++ /dev/null @@ -1,64 +0,0 @@ -/** - * Copyright (c) 2026 Dominic Masters - * - * This software is released under the MIT License. - * https://opensource.org/licenses/MIT - */ - -#include "moduleevent.h" -#include "event/event.h" -#include "engine/engine.h" -#include "assert/assert.h" - -int moduleEventSubscribe(lua_State *L) { - assertNotNull(L, "Lua state cannot be NULL"); - - // State has user pointer to owning scriptcontext_t - scriptcontext_t *context = *(scriptcontext_t **)lua_getextraspace(L); - assertNotNull(context, "Script context cannot be NULL"); - - // Expecting event pointer - if(!lua_islightuserdata(L, 1)) { - luaL_error(L, "eventSubscribe: Expected event pointer as first argument"); - return 0; - } - - // Expecting callback function (Lua function) - if(!lua_isfunction(L, 2)) { - luaL_error(L, "eventSubscribe: Expected function as second argument"); - return 0; - } - - event_t *event = (event_t *)lua_touserdata(L, 1); - assertNotNull(event, "Event cannot be NULL"); - - eventsub_t id = eventSubscribeScriptContext(event, context, 2); - - // Pass back to lua. - lua_pushnumber(L, id); - return 1; -} - -int moduleEventUnsubscribe(lua_State *L) { - assertNotNull(L, "Lua state cannot be NULL"); - - if(!lua_islightuserdata(L, 1)) { - luaL_error(L, "eventUnsubscribe: Expected event pointer as first argument"); - return 0; - } - if(!lua_isnumber(L, 2)) { - luaL_error(L, "eventUnsubscribe: Expected subscription ID as second argument"); - return 0; - } - - event_t *event = (event_t *)lua_touserdata(L, 1); - assertNotNull(event, "Event cannot be NULL"); - eventsub_t id = (eventsub_t)lua_tonumber(L, 2); - eventUnsubscribe(event, id); - return 0; -} - -void moduleEvent(scriptcontext_t *context) { - lua_register(context->luaState, "eventSubscribe", moduleEventSubscribe); - lua_register(context->luaState, "eventUnsubscribe", moduleEventUnsubscribe); -} \ No newline at end of file diff --git a/src/dusk/script/module/event/moduleevent.h b/src/dusk/script/module/event/moduleevent.h index dfdc805f..e6bee709 100644 --- a/src/dusk/script/module/event/moduleevent.h +++ b/src/dusk/script/module/event/moduleevent.h @@ -1,26 +1,58 @@ /** * Copyright (c) 2026 Dominic Masters - * + * * This software is released under the MIT License. * https://opensource.org/licenses/MIT */ #pragma once -#include "script/scriptcontext.h" +#include "script/module/modulebase.h" +#include "event/event.h" -/** - * Register event functions to the given script context. - * - * @param context The script context to register event functions to. - */ -void moduleEvent(scriptcontext_t *context); +static int moduleEventSubscribe(lua_State *L) { + assertNotNull(L, "Lua state cannot be NULL"); -/** - * Script binding for subscribing to an event. - */ -int moduleEventSubscribe(lua_State *L); + scriptcontext_t *context = *(scriptcontext_t **)lua_getextraspace(L); + assertNotNull(context, "Script context cannot be NULL"); -/** - * Script binding for unsubscribing from an event. - */ -int moduleEventUnsubscribe(lua_State *L); \ No newline at end of file + if(!lua_islightuserdata(L, 1)) { + luaL_error(L, "eventSubscribe: Expected event pointer as first argument"); + return 0; + } + + if(!lua_isfunction(L, 2)) { + luaL_error(L, "eventSubscribe: Expected function as second argument"); + return 0; + } + + event_t *event = (event_t *)lua_touserdata(L, 1); + assertNotNull(event, "Event cannot be NULL"); + + eventsub_t id = eventSubscribeScriptContext(event, context, 2); + lua_pushnumber(L, id); + return 1; +} + +static int moduleEventUnsubscribe(lua_State *L) { + assertNotNull(L, "Lua state cannot be NULL"); + + if(!lua_islightuserdata(L, 1)) { + luaL_error(L, "eventUnsubscribe: Expected event pointer as first argument"); + return 0; + } + if(!lua_isnumber(L, 2)) { + luaL_error(L, "eventUnsubscribe: Expected subscription ID as second argument"); + return 0; + } + + event_t *event = (event_t *)lua_touserdata(L, 1); + assertNotNull(event, "Event cannot be NULL"); + eventsub_t id = (eventsub_t)lua_tonumber(L, 2); + eventUnsubscribe(event, id); + return 0; +} + +static void moduleEvent(lua_State *L) { + lua_register(L, "eventSubscribe", moduleEventSubscribe); + lua_register(L, "eventUnsubscribe", moduleEventUnsubscribe); +} diff --git a/src/dusk/script/module/input/CMakeLists.txt b/src/dusk/script/module/input/CMakeLists.txt deleted file mode 100644 index 928bd2de..00000000 --- a/src/dusk/script/module/input/CMakeLists.txt +++ /dev/null @@ -1,10 +0,0 @@ -# Copyright (c) 2025 Dominic Masters -# -# This software is released under the MIT License. -# https://opensource.org/licenses/MIT - -# Sources -target_sources(${DUSK_LIBRARY_TARGET_NAME} - PUBLIC - moduleinput.c -) \ No newline at end of file diff --git a/src/dusk/script/module/input/moduleinput.c b/src/dusk/script/module/input/moduleinput.c deleted file mode 100644 index d9293a53..00000000 --- a/src/dusk/script/module/input/moduleinput.c +++ /dev/null @@ -1,217 +0,0 @@ -/** - * Copyright (c) 2026 Dominic Masters - * - * This software is released under the MIT License. - * https://opensource.org/licenses/MIT - */ - -#include "moduleinput.h" -#include "input/input.h" -#include "assert/assert.h" -#include "util/string.h" - -void moduleInput(scriptcontext_t *context) { - assertNotNull(context, "Script context cannot be NULL"); - - // Setup enums. - scriptContextExec(context, INPUT_ACTION_SCRIPT); - - // Input values. - scriptContextExec(context, - "" - #ifdef DUSK_INPUT_KEYBOARD - "INPUT_KEYBOARD = true\n" - #endif - #ifdef DUSK_INPUT_GAMEPAD - "INPUT_GAMEPAD = true\n" - #endif - #ifdef DUSK_INPUT_POINTER - "INPUT_POINTER = true\n" - #endif - #ifdef DUSK_INPUT_TOUCH - "INPUT_TOUCH = true\n" - #endif - ); - - // Metatable - if(luaL_newmetatable(context->luaState, "input_mt")) { - lua_pushcfunction(context->luaState, moduleInputIndex); - lua_setfield(context->luaState, -2, "__index"); - } - lua_pop(context->luaState, 1); - - // Events - lua_pushlightuserdata(context->luaState, &INPUT.eventPressed); - lua_setglobal(context->luaState, "INPUT_EVENT_PRESSED"); - - lua_pushlightuserdata(context->luaState, &INPUT.eventReleased); - lua_setglobal(context->luaState, "INPUT_EVENT_RELEASED"); - - // Bind methods - lua_register(context->luaState, "inputBind", moduleInputBind); - lua_register(context->luaState, "inputIsDown", moduleInputIsDown); - lua_register(context->luaState, "inputPressed", moduleInputPressed); - lua_register(context->luaState, "inputReleased", moduleInputReleased); - lua_register(context->luaState, "inputGetValue", moduleInputGetValue); - lua_register(context->luaState, "inputAxis", moduleInputAxis); -} - -int moduleInputIndex(lua_State *l) { - assertNotNull(l, "Lua state cannot be NULL"); - - const char_t *key = luaL_checkstring(l, 2); - assertStrLenMin(key, 1, "Key cannot be empty."); - - if(stringCompare(key, "action") == 0) { - const inputevent_t *event = (const inputevent_t*)lua_touserdata(l, 1); - if(event == NULL) { - luaL_error(l, "Expected input event as first argument"); - return 0; - } - - lua_pushnumber(l, event->action); - return 1; - } - - lua_pushnil(l); - return 1; -} - -int moduleInputBind(lua_State *L) { - assertNotNull(L, "Lua state cannot be NULL"); - - // Requires action and button. - if(!lua_isstring(L, 1)) { - luaL_error(L, "inputBind: Expected button name as first argument"); - return 0; - } - - // Expect action ID - if(!lua_isnumber(L, 2)) { - luaL_error(L, "inputBind: Expected action ID as second argument"); - return 0; - } - - const char_t *strBtn = lua_tostring(L, 1); - const inputaction_t action = (inputaction_t)lua_tonumber(L, 2); - - if(strBtn == NULL || strlen(strBtn) == 0) { - luaL_error(L, "inputBind: Button name cannot be NULL or empty"); - return 0; - } - - // Validate action - if(action < INPUT_ACTION_NULL || action >= INPUT_ACTION_COUNT) { - luaL_error(L, "inputBind: Invalid action ID %d with str %s", action, strBtn); - return 0; - } - - // Get button by name - inputbutton_t btn = inputButtonGetByName(strBtn); - if(btn.type == INPUT_BUTTON_TYPE_NONE) { - luaL_error(L, "inputBind: Invalid button name '%s'", strBtn); - return 0; - } - - inputBind(btn, action); - return 0; -} - -int moduleInputIsDown(lua_State *L) { - assertNotNull(L, "Lua state cannot be NULL"); - - if(!lua_isnumber(L, 1)) { - luaL_error(L, "inputIsDown: Expected action ID as first argument"); - return 0; - } - - const inputaction_t action = (inputaction_t)lua_tonumber(L, 1); - - if(action < INPUT_ACTION_NULL || action >= INPUT_ACTION_COUNT) { - luaL_error(L, "inputIsDown: Invalid action ID %d", action); - return 0; - } - - lua_pushboolean(L, inputIsDown(action)); - return 1; -} - -int moduleInputPressed(lua_State *L) { - assertNotNull(L, "Lua state cannot be NULL"); - - if(!lua_isnumber(L, 1)) { - luaL_error(L, "inputPressed: Expected action ID as first argument"); - return 0; - } - - const inputaction_t action = (inputaction_t)lua_tonumber(L, 1); - - if(action < INPUT_ACTION_NULL || action >= INPUT_ACTION_COUNT) { - luaL_error(L, "inputPressed: Invalid action ID %d", action); - return 0; - } - - lua_pushboolean(L, inputPressed(action)); - return 1; -} - -int moduleInputReleased(lua_State *L) { - assertNotNull(L, "Lua state cannot be NULL"); - - if(!lua_isnumber(L, 1)) { - luaL_error(L, "inputReleased: Expected action ID as first argument"); - return 0; - } - - const inputaction_t action = (inputaction_t)lua_tonumber(L, 1); - - if(action < INPUT_ACTION_NULL || action >= INPUT_ACTION_COUNT) { - luaL_error(L, "inputReleased: Invalid action ID %d", action); - return 0; - } - - lua_pushboolean(L, inputReleased(action)); - return 1; -} - -int moduleInputGetValue(lua_State *L) { - assertNotNull(L, "Lua state cannot be NULL"); - - if(!lua_isnumber(L, 1)) { - luaL_error(L, "inputGetValue: Expected action ID as first argument"); - return 0; - } - - const inputaction_t action = (inputaction_t)lua_tonumber(L, 1); - if(action < INPUT_ACTION_NULL || action >= INPUT_ACTION_COUNT) { - luaL_error(L, "inputGetValue: Invalid action ID %d", action); - return 0; - } - - lua_pushnumber(L, inputGetCurrentValue(action)); - return 1; -} - -int moduleInputAxis(lua_State *L) { - assertNotNull(L, "Lua state cannot be NULL"); - - if(!lua_isnumber(L, 1) || !lua_isnumber(L, 2)) { - luaL_error(L, "inputAxis: Expected two action IDs as arguments (neg, pos)"); - return 0; - } - - const inputaction_t neg = (inputaction_t)lua_tonumber(L, 1); - const inputaction_t pos = (inputaction_t)lua_tonumber(L, 2); - - if(neg < INPUT_ACTION_NULL || neg >= INPUT_ACTION_COUNT) { - luaL_error(L, "inputAxis: Invalid negative action ID %d", neg); - return 0; - } - if(pos < INPUT_ACTION_NULL || pos >= INPUT_ACTION_COUNT) { - luaL_error(L, "inputAxis: Invalid positive action ID %d", pos); - return 0; - } - - lua_pushnumber(L, inputAxis(neg, pos)); - return 1; -} \ No newline at end of file diff --git a/src/dusk/script/module/input/moduleinput.h b/src/dusk/script/module/input/moduleinput.h index ff3e9053..a953cf55 100644 --- a/src/dusk/script/module/input/moduleinput.h +++ b/src/dusk/script/module/input/moduleinput.h @@ -1,71 +1,206 @@ /** * Copyright (c) 2025 Dominic Masters - * + * * This software is released under the MIT License. * https://opensource.org/licenses/MIT */ #pragma once -#include "script/scriptcontext.h" +#include "script/module/modulebase.h" +#include "input/input.h" -/** - * Register input functions to the given script context. - * - * @param context The script context to register input functions to. - */ -void moduleInput(scriptcontext_t *context); +static int moduleInputIndex(lua_State *l) { + assertNotNull(l, "Lua state cannot be NULL"); -/** - * Getter for input structure fields. - * - * @param l The Lua state. - */ -int moduleInputIndex(lua_State *l); + const char_t *key = luaL_checkstring(l, 2); + assertStrLenMin(key, 1, "Key cannot be empty."); -/** - * Script binding for binding an input button to an action. - * - * @param L The Lua state. - * @return Number of return values on the Lua stack. - */ -int moduleInputBind(lua_State *L); + if(stringCompare(key, "action") == 0) { + const inputevent_t *event = (const inputevent_t*)lua_touserdata(l, 1); + if(event == NULL) { + luaL_error(l, "Expected input event as first argument"); + return 0; + } + lua_pushnumber(l, event->action); + return 1; + } -/** - * Script binding for checking if an input action is currently pressed. - * - * @param L The Lua state. - * @return Number of return values on the Lua stack. - */ -int moduleInputIsDown(lua_State *L); + lua_pushnil(l); + return 1; +} -/** - * Script binding for checking if an input action was pressed this frame. - * - * @param L The Lua state. - * @return Number of return values on the Lua stack. - */ -int moduleInputPressed(lua_State *L); +static int moduleInputBind(lua_State *L) { + assertNotNull(L, "Lua state cannot be NULL"); -/** - * Script binding for checking if an input action was released this frame. - * - * @param L The Lua state. - * @return Number of return values on the Lua stack. - */ -int moduleInputReleased(lua_State *L); + if(!lua_isstring(L, 1)) { + luaL_error(L, "inputBind: Expected button name as first argument"); + return 0; + } -/** - * Script binding for getting the value of an input axis. - * - * @param L The Lua state. - * @return Number of return values on the Lua stack. - */ -int moduleInputGetValue(lua_State *L); + if(!lua_isnumber(L, 2)) { + luaL_error(L, "inputBind: Expected action ID as second argument"); + return 0; + } -/** - * Script binding for inputAxis. - * - * @param L The Lua state. - * @return Number of return values on the Lua stack. - */ -int moduleInputAxis(lua_State *L); \ No newline at end of file + const char_t *strBtn = lua_tostring(L, 1); + const inputaction_t action = (inputaction_t)lua_tonumber(L, 2); + + if(strBtn == NULL || strlen(strBtn) == 0) { + luaL_error(L, "inputBind: Button name cannot be NULL or empty"); + return 0; + } + + if(action < INPUT_ACTION_NULL || action >= INPUT_ACTION_COUNT) { + luaL_error(L, "inputBind: Invalid action ID %d with str %s", action, strBtn); + return 0; + } + + inputbutton_t btn = inputButtonGetByName(strBtn); + if(btn.type == INPUT_BUTTON_TYPE_NONE) { + luaL_error(L, "inputBind: Invalid button name '%s'", strBtn); + return 0; + } + + inputBind(btn, action); + return 0; +} + +static int moduleInputIsDown(lua_State *L) { + assertNotNull(L, "Lua state cannot be NULL"); + + if(!lua_isnumber(L, 1)) { + luaL_error(L, "inputIsDown: Expected action ID as first argument"); + return 0; + } + + const inputaction_t action = (inputaction_t)lua_tonumber(L, 1); + + if(action < INPUT_ACTION_NULL || action >= INPUT_ACTION_COUNT) { + luaL_error(L, "inputIsDown: Invalid action ID %d", action); + return 0; + } + + lua_pushboolean(L, inputIsDown(action)); + return 1; +} + +static int moduleInputPressed(lua_State *L) { + assertNotNull(L, "Lua state cannot be NULL"); + + if(!lua_isnumber(L, 1)) { + luaL_error(L, "inputPressed: Expected action ID as first argument"); + return 0; + } + + const inputaction_t action = (inputaction_t)lua_tonumber(L, 1); + + if(action < INPUT_ACTION_NULL || action >= INPUT_ACTION_COUNT) { + luaL_error(L, "inputPressed: Invalid action ID %d", action); + return 0; + } + + lua_pushboolean(L, inputPressed(action)); + return 1; +} + +static int moduleInputReleased(lua_State *L) { + assertNotNull(L, "Lua state cannot be NULL"); + + if(!lua_isnumber(L, 1)) { + luaL_error(L, "inputReleased: Expected action ID as first argument"); + return 0; + } + + const inputaction_t action = (inputaction_t)lua_tonumber(L, 1); + + if(action < INPUT_ACTION_NULL || action >= INPUT_ACTION_COUNT) { + luaL_error(L, "inputReleased: Invalid action ID %d", action); + return 0; + } + + lua_pushboolean(L, inputReleased(action)); + return 1; +} + +static int moduleInputGetValue(lua_State *L) { + assertNotNull(L, "Lua state cannot be NULL"); + + if(!lua_isnumber(L, 1)) { + luaL_error(L, "inputGetValue: Expected action ID as first argument"); + return 0; + } + + const inputaction_t action = (inputaction_t)lua_tonumber(L, 1); + if(action < INPUT_ACTION_NULL || action >= INPUT_ACTION_COUNT) { + luaL_error(L, "inputGetValue: Invalid action ID %d", action); + return 0; + } + + lua_pushnumber(L, inputGetCurrentValue(action)); + return 1; +} + +static int moduleInputAxis(lua_State *L) { + assertNotNull(L, "Lua state cannot be NULL"); + + if(!lua_isnumber(L, 1) || !lua_isnumber(L, 2)) { + luaL_error(L, "inputAxis: Expected two action IDs as arguments (neg, pos)"); + return 0; + } + + const inputaction_t neg = (inputaction_t)lua_tonumber(L, 1); + const inputaction_t pos = (inputaction_t)lua_tonumber(L, 2); + + if(neg < INPUT_ACTION_NULL || neg >= INPUT_ACTION_COUNT) { + luaL_error(L, "inputAxis: Invalid negative action ID %d", neg); + return 0; + } + if(pos < INPUT_ACTION_NULL || pos >= INPUT_ACTION_COUNT) { + luaL_error(L, "inputAxis: Invalid positive action ID %d", pos); + return 0; + } + + lua_pushnumber(L, inputAxis(neg, pos)); + return 1; +} + +static void moduleInput(lua_State *L) { + assertNotNull(L, "Lua state cannot be NULL"); + + luaL_dostring(L, INPUT_ACTION_SCRIPT); + + luaL_dostring(L, + "" + #ifdef DUSK_INPUT_KEYBOARD + "INPUT_KEYBOARD = true\n" + #endif + #ifdef DUSK_INPUT_GAMEPAD + "INPUT_GAMEPAD = true\n" + #endif + #ifdef DUSK_INPUT_POINTER + "INPUT_POINTER = true\n" + #endif + #ifdef DUSK_INPUT_TOUCH + "INPUT_TOUCH = true\n" + #endif + ); + + if(luaL_newmetatable(L, "input_mt")) { + lua_pushcfunction(L, moduleInputIndex); + lua_setfield(L, -2, "__index"); + } + lua_pop(L, 1); + + lua_pushlightuserdata(L, &INPUT.eventPressed); + lua_setglobal(L, "INPUT_EVENT_PRESSED"); + + lua_pushlightuserdata(L, &INPUT.eventReleased); + lua_setglobal(L, "INPUT_EVENT_RELEASED"); + + lua_register(L, "inputBind", moduleInputBind); + lua_register(L, "inputIsDown", moduleInputIsDown); + lua_register(L, "inputPressed", moduleInputPressed); + lua_register(L, "inputReleased", moduleInputReleased); + lua_register(L, "inputGetValue", moduleInputGetValue); + lua_register(L, "inputAxis", moduleInputAxis); +} diff --git a/src/dusk/script/module/locale/CMakeLists.txt b/src/dusk/script/module/locale/CMakeLists.txt deleted file mode 100644 index fc5b99b5..00000000 --- a/src/dusk/script/module/locale/CMakeLists.txt +++ /dev/null @@ -1,10 +0,0 @@ -# Copyright (c) 2026 Dominic Masters -# -# This software is released under the MIT License. -# https://opensource.org/licenses/MIT - -# Sources -target_sources(${DUSK_LIBRARY_TARGET_NAME} - PUBLIC - modulelocale.c -) \ No newline at end of file diff --git a/src/dusk/script/module/locale/modulelocale.c b/src/dusk/script/module/locale/modulelocale.c deleted file mode 100644 index ef0312fe..00000000 --- a/src/dusk/script/module/locale/modulelocale.c +++ /dev/null @@ -1,99 +0,0 @@ -/** - * Copyright (c) 2026 Dominic Masters - * - * This software is released under the MIT License. - * https://opensource.org/licenses/MIT - */ - -#include "modulelocale.h" -#include "locale/localemanager.h" -#include "assert/assert.h" - -void moduleLocale(scriptcontext_t *context) { - assertNotNull(context, "Script context cannot be NULL"); - - // Execute the locale script definitions. - lua_register(context->luaState, "localeGetText", moduleLocaleGetText); -} - -int moduleLocaleGetText(lua_State *L) { - // Expect string param for the id - if(!lua_isstring(L, 1)) { - luaL_error(L, "Expected message ID as first argument"); - return 0; - } - - const char_t *id = lua_tostring(L, 1); - if(id == NULL || strlen(id) == 0) { - luaL_error(L, "Message ID cannot be NULL or empty"); - return 0; - } - - // Optional plural param, default to 0 - int32_t plural = 0; - int top = lua_gettop(L); - int argStart = 2; - - if(top >= 2 && !lua_isnil(L, 2)) { - if(!lua_isnumber(L, 2)) { - luaL_error(L, "Expected plural as second argument"); - return 0; - } - - plural = (int32_t)lua_tointeger(L, 2); - if(plural < 0) { - luaL_error(L, "Plural cannot be negative"); - return 0; - } - - argStart = 3; - } - - // Build structured arg list from remaining Lua args - size_t argCount = (top >= argStart) ? (size_t)(top - argStart + 1) : 0; - #define MODULE_LOCALE_MAX_ARGS 16 - assetlocalearg_t argsStack[MODULE_LOCALE_MAX_ARGS]; - assetlocalearg_t *args = argsStack; - - if(argCount > MODULE_LOCALE_MAX_ARGS) { - luaL_error(L, "Too many args (max %d)", MODULE_LOCALE_MAX_ARGS); - return 0; - } - - for(size_t i = 0; i < argCount; ++i) { - int luaIndex = argStart + (int)i; - - if(lua_isinteger(L, luaIndex)) { - args[i].type = ASSET_LOCALE_ARG_INT; - args[i].intValue = (int32_t)lua_tonumber(L, luaIndex); - } else if(lua_isnumber(L, luaIndex)) { - args[i].type = ASSET_LOCALE_ARG_FLOAT; - args[i].floatValue = lua_tonumber(L, luaIndex); - } else if(lua_isstring(L, luaIndex)) { - args[i].type = ASSET_LOCALE_ARG_STRING; - args[i].stringValue = lua_tostring(L, luaIndex); - } else { - luaL_error(L, "Unsupported localization argument type"); - return 0; - } - } - - char_t buffer[1024]; - errorret_t err = localeManagerGetTextArgs( - id, - buffer, - sizeof(buffer), - plural, - args, - argCount - ); - - if(err.code != ERROR_OK) { - errorCatch(errorPrint(err)); - luaL_error(L, "Failed to get localized text for ID '%s'", id); - return 0; - } - - lua_pushstring(L, buffer); - return 1; -} \ No newline at end of file diff --git a/src/dusk/script/module/locale/modulelocale.h b/src/dusk/script/module/locale/modulelocale.h index b93c6c63..98431b03 100644 --- a/src/dusk/script/module/locale/modulelocale.h +++ b/src/dusk/script/module/locale/modulelocale.h @@ -1,24 +1,85 @@ /** * Copyright (c) 2026 Dominic Masters - * + * * This software is released under the MIT License. * https://opensource.org/licenses/MIT */ #pragma once -#include "script/scriptcontext.h" +#include "script/module/modulebase.h" +#include "locale/localemanager.h" -/** - * Register locale functions to the given script context. - * - * @param context The script context to register locale functions to. - */ -void moduleLocale(scriptcontext_t *context); +static int moduleLocaleGetText(lua_State *L) { + if(!lua_isstring(L, 1)) { + luaL_error(L, "Expected message ID as first argument"); + return 0; + } -/** - * Script binding for getting a localized string. - * - * @param L The Lua state. - * @return The number of return values on the Lua stack. - */ -int moduleLocaleGetText(lua_State *L); \ No newline at end of file + const char_t *id = lua_tostring(L, 1); + if(id == NULL || strlen(id) == 0) { + luaL_error(L, "Message ID cannot be NULL or empty"); + return 0; + } + + int32_t plural = 0; + int top = lua_gettop(L); + int argStart = 2; + + if(top >= 2 && !lua_isnil(L, 2)) { + if(!lua_isnumber(L, 2)) { + luaL_error(L, "Expected plural as second argument"); + return 0; + } + plural = (int32_t)lua_tointeger(L, 2); + if(plural < 0) { + luaL_error(L, "Plural cannot be negative"); + return 0; + } + argStart = 3; + } + + size_t argCount = (top >= argStart) ? (size_t)(top - argStart + 1) : 0; + #define MODULE_LOCALE_MAX_ARGS 16 + assetlocalearg_t argsStack[MODULE_LOCALE_MAX_ARGS]; + + if(argCount > MODULE_LOCALE_MAX_ARGS) { + luaL_error(L, "Too many args (max %d)", MODULE_LOCALE_MAX_ARGS); + return 0; + } + + for(size_t i = 0; i < argCount; ++i) { + int luaIndex = argStart + (int)i; + if(lua_isinteger(L, luaIndex)) { + argsStack[i].type = ASSET_LOCALE_ARG_INT; + argsStack[i].intValue = (int32_t)lua_tonumber(L, luaIndex); + } else if(lua_isnumber(L, luaIndex)) { + argsStack[i].type = ASSET_LOCALE_ARG_FLOAT; + argsStack[i].floatValue = lua_tonumber(L, luaIndex); + } else if(lua_isstring(L, luaIndex)) { + argsStack[i].type = ASSET_LOCALE_ARG_STRING; + argsStack[i].stringValue = lua_tostring(L, luaIndex); + } else { + luaL_error(L, "Unsupported localization argument type"); + return 0; + } + } + #undef MODULE_LOCALE_MAX_ARGS + + char_t buffer[1024]; + errorret_t err = localeManagerGetTextArgs( + id, buffer, sizeof(buffer), plural, argsStack, argCount + ); + if(err.code != ERROR_OK) { + errorCatch(errorPrint(err)); + luaL_error(L, "Failed to get localized text for ID '%s'", id); + return 0; + } + + lua_pushstring(L, buffer); + return 1; +} + +static void moduleLocale(lua_State *L) { + assertNotNull(L, "Lua state cannot be NULL"); + lua_register(L, "localeGetText", moduleLocaleGetText); +} diff --git a/src/dusk/script/module/math/CMakeLists.txt b/src/dusk/script/module/math/CMakeLists.txt deleted file mode 100644 index 53d97b02..00000000 --- a/src/dusk/script/module/math/CMakeLists.txt +++ /dev/null @@ -1,13 +0,0 @@ -# Copyright (c) 2026 Dominic Masters -# -# This software is released under the MIT License. -# https://opensource.org/licenses/MIT - -target_sources(${DUSK_LIBRARY_TARGET_NAME} - PUBLIC - modulevec2.c - modulevec3.c - modulevec4.c - modulemat4.c - modulemath.c -) diff --git a/src/dusk/script/module/math/modulemat4.c b/src/dusk/script/module/math/modulemat4.c deleted file mode 100644 index 48e3cd48..00000000 --- a/src/dusk/script/module/math/modulemat4.c +++ /dev/null @@ -1,117 +0,0 @@ -/** - * Copyright (c) 2026 Dominic Masters - * - * This software is released under the MIT License. - * https://opensource.org/licenses/MIT - */ - -#include "modulemat4.h" -#include "modulevec3.h" -#include "modulevec4.h" -#include "assert/assert.h" - -void luaMat4Push(lua_State *L, mat4 m) { - mat4 *u = (mat4 *)lua_newuserdata(L, sizeof(mat4)); - glm_mat4_copy(m, *u); - luaL_getmetatable(L, "mat4_mt"); - lua_setmetatable(L, -2); -} - -void luaMat4Check(lua_State *L, int idx, mat4 out) { - mat4 *m = (mat4 *)luaL_checkudata(L, idx, "mat4_mt"); - glm_mat4_copy(*m, out); -} - -static int mat4Index(lua_State *L) { - lua_getmetatable(L, 1); - lua_getfield(L, -1, luaL_checkstring(L, 2)); - return 1; -} - -static int mat4OpMul(lua_State *L) { - mat4 *a = (mat4 *)luaL_checkudata(L, 1, "mat4_mt"); - mat4 *b = (mat4 *)luaL_checkudata(L, 2, "mat4_mt"); - mat4 r; glm_mat4_mul(*a, *b, r); - luaMat4Push(L, r); return 1; -} - -static int mat4OpToString(lua_State *L) { - lua_pushstring(L, "mat4(...)"); return 1; -} - -static int mat4Transpose(lua_State *L) { - mat4 *m = (mat4 *)luaL_checkudata(L, 1, "mat4_mt"); - mat4 r; glm_mat4_transpose_to(*m, r); - luaMat4Push(L, r); return 1; -} - -static int mat4Inverse(lua_State *L) { - mat4 *m = (mat4 *)luaL_checkudata(L, 1, "mat4_mt"); - mat4 r; glm_mat4_inv(*m, r); - luaMat4Push(L, r); return 1; -} - -static int mat4MulVec3(lua_State *L) { - mat4 *m = (mat4 *)luaL_checkudata(L, 1, "mat4_mt"); - vec3 v; luaVec3Check(L, 2, v); - float_t w = lua_gettop(L) >= 3 ? (float_t)luaL_checknumber(L, 3) : 1.0f; - vec3 r; glm_mat4_mulv3(*m, v, w, r); - luaVec3Push(L, r); return 1; -} - -static int mat4MulVec4(lua_State *L) { - mat4 *m = (mat4 *)luaL_checkudata(L, 1, "mat4_mt"); - vec4 v; luaVec4Check(L, 2, v); - vec4 r; glm_mat4_mulv(*m, v, r); - luaVec4Push(L, r); return 1; -} - -static int mat4Translate(lua_State *L) { - mat4 *m = (mat4 *)luaL_checkudata(L, 1, "mat4_mt"); - vec3 v; luaVec3Check(L, 2, v); - mat4 r; glm_mat4_copy(*m, r); - glm_translate(r, v); - luaMat4Push(L, r); return 1; -} - -static int mat4Scale(lua_State *L) { - mat4 *m = (mat4 *)luaL_checkudata(L, 1, "mat4_mt"); - vec3 v; luaVec3Check(L, 2, v); - mat4 r; glm_mat4_copy(*m, r); - glm_scale(r, v); - luaMat4Push(L, r); return 1; -} - -static int mat4Identity(lua_State *L) { - mat4 r; glm_mat4_identity(r); - luaMat4Push(L, r); return 1; -} - -static int mat4Determinant(lua_State *L) { - mat4 *m = (mat4 *)luaL_checkudata(L, 1, "mat4_mt"); - lua_pushnumber(L, (lua_Number)glm_mat4_det(*m)); return 1; -} - -static int mat4Create(lua_State *L) { - mat4 m; glm_mat4_identity(m); - luaMat4Push(L, m); return 1; -} - -void moduleMathMat4(lua_State *L) { - if(!luaL_newmetatable(L, "mat4_mt")) { lua_pop(L, 1); return; } - - lua_pushcfunction(L, mat4Index); lua_setfield(L, -2, "__index"); - lua_pushcfunction(L, mat4OpMul); lua_setfield(L, -2, "__mul"); - lua_pushcfunction(L, mat4OpToString); lua_setfield(L, -2, "__tostring"); - lua_pushcfunction(L, mat4Transpose); lua_setfield(L, -2, "transpose"); - lua_pushcfunction(L, mat4Inverse); lua_setfield(L, -2, "inverse"); - lua_pushcfunction(L, mat4MulVec3); lua_setfield(L, -2, "mulVec3"); - lua_pushcfunction(L, mat4MulVec4); lua_setfield(L, -2, "mulVec4"); - lua_pushcfunction(L, mat4Translate); lua_setfield(L, -2, "translate"); - lua_pushcfunction(L, mat4Scale); lua_setfield(L, -2, "scale"); - lua_pushcfunction(L, mat4Identity); lua_setfield(L, -2, "identity"); - lua_pushcfunction(L, mat4Determinant); lua_setfield(L, -2, "determinant"); - lua_pop(L, 1); - - lua_register(L, "mat4", mat4Create); -} diff --git a/src/dusk/script/module/math/modulemat4.h b/src/dusk/script/module/math/modulemat4.h index 5d5bf591..07b0e3a5 100644 --- a/src/dusk/script/module/math/modulemat4.h +++ b/src/dusk/script/module/math/modulemat4.h @@ -6,8 +6,112 @@ */ #pragma once -#include "script/scriptcontext.h" +#include "script/module/modulebase.h" +#include "modulevec3.h" +#include "modulevec4.h" -void luaMat4Push(lua_State *L, mat4 m); -void luaMat4Check(lua_State *L, int idx, mat4 out); -void moduleMathMat4(lua_State *L); +static void luaMat4Push(lua_State *L, mat4 m) { + mat4 *u = (mat4 *)lua_newuserdata(L, sizeof(mat4)); + glm_mat4_copy(m, *u); + luaL_getmetatable(L, "mat4_mt"); + lua_setmetatable(L, -2); +} + +static void luaMat4Check(lua_State *L, int idx, mat4 out) { + mat4 *m = (mat4 *)luaL_checkudata(L, idx, "mat4_mt"); + glm_mat4_copy(*m, out); +} + +static int mat4Index(lua_State *L) { + lua_getmetatable(L, 1); + lua_getfield(L, -1, luaL_checkstring(L, 2)); + return 1; +} + +static int mat4OpMul(lua_State *L) { + mat4 *a = (mat4 *)luaL_checkudata(L, 1, "mat4_mt"); + mat4 *b = (mat4 *)luaL_checkudata(L, 2, "mat4_mt"); + mat4 r; glm_mat4_mul(*a, *b, r); + luaMat4Push(L, r); return 1; +} + +static int mat4OpToString(lua_State *L) { + lua_pushstring(L, "mat4(...)"); return 1; +} + +static int mat4Transpose(lua_State *L) { + mat4 *m = (mat4 *)luaL_checkudata(L, 1, "mat4_mt"); + mat4 r; glm_mat4_transpose_to(*m, r); + luaMat4Push(L, r); return 1; +} + +static int mat4Inverse(lua_State *L) { + mat4 *m = (mat4 *)luaL_checkudata(L, 1, "mat4_mt"); + mat4 r; glm_mat4_inv(*m, r); + luaMat4Push(L, r); return 1; +} + +static int mat4MulVec3(lua_State *L) { + mat4 *m = (mat4 *)luaL_checkudata(L, 1, "mat4_mt"); + vec3 v; luaVec3Check(L, 2, v); + float_t w = lua_gettop(L) >= 3 ? (float_t)luaL_checknumber(L, 3) : 1.0f; + vec3 r; glm_mat4_mulv3(*m, v, w, r); + luaVec3Push(L, r); return 1; +} + +static int mat4MulVec4(lua_State *L) { + mat4 *m = (mat4 *)luaL_checkudata(L, 1, "mat4_mt"); + vec4 v; luaVec4Check(L, 2, v); + vec4 r; glm_mat4_mulv(*m, v, r); + luaVec4Push(L, r); return 1; +} + +static int mat4Translate(lua_State *L) { + mat4 *m = (mat4 *)luaL_checkudata(L, 1, "mat4_mt"); + vec3 v; luaVec3Check(L, 2, v); + mat4 r; glm_mat4_copy(*m, r); + glm_translate(r, v); + luaMat4Push(L, r); return 1; +} + +static int mat4Scale(lua_State *L) { + mat4 *m = (mat4 *)luaL_checkudata(L, 1, "mat4_mt"); + vec3 v; luaVec3Check(L, 2, v); + mat4 r; glm_mat4_copy(*m, r); + glm_scale(r, v); + luaMat4Push(L, r); return 1; +} + +static int mat4Identity(lua_State *L) { + mat4 r; glm_mat4_identity(r); + luaMat4Push(L, r); return 1; +} + +static int mat4Determinant(lua_State *L) { + mat4 *m = (mat4 *)luaL_checkudata(L, 1, "mat4_mt"); + lua_pushnumber(L, (lua_Number)glm_mat4_det(*m)); return 1; +} + +static int mat4Create(lua_State *L) { + mat4 m; glm_mat4_identity(m); + luaMat4Push(L, m); return 1; +} + +static void moduleMathMat4(lua_State *L) { + if(!luaL_newmetatable(L, "mat4_mt")) { lua_pop(L, 1); return; } + + lua_pushcfunction(L, mat4Index); lua_setfield(L, -2, "__index"); + lua_pushcfunction(L, mat4OpMul); lua_setfield(L, -2, "__mul"); + lua_pushcfunction(L, mat4OpToString); lua_setfield(L, -2, "__tostring"); + lua_pushcfunction(L, mat4Transpose); lua_setfield(L, -2, "transpose"); + lua_pushcfunction(L, mat4Inverse); lua_setfield(L, -2, "inverse"); + lua_pushcfunction(L, mat4MulVec3); lua_setfield(L, -2, "mulVec3"); + lua_pushcfunction(L, mat4MulVec4); lua_setfield(L, -2, "mulVec4"); + lua_pushcfunction(L, mat4Translate); lua_setfield(L, -2, "translate"); + lua_pushcfunction(L, mat4Scale); lua_setfield(L, -2, "scale"); + lua_pushcfunction(L, mat4Identity); lua_setfield(L, -2, "identity"); + lua_pushcfunction(L, mat4Determinant); lua_setfield(L, -2, "determinant"); + lua_pop(L, 1); + + lua_register(L, "mat4", mat4Create); +} diff --git a/src/dusk/script/module/math/modulemath.c b/src/dusk/script/module/math/modulemath.c deleted file mode 100644 index ff198ecb..00000000 --- a/src/dusk/script/module/math/modulemath.c +++ /dev/null @@ -1,22 +0,0 @@ -/** - * Copyright (c) 2026 Dominic Masters - * - * This software is released under the MIT License. - * https://opensource.org/licenses/MIT - */ - -#include "modulemath.h" -#include "modulevec2.h" -#include "modulevec3.h" -#include "modulevec4.h" -#include "modulemat4.h" -#include "assert/assert.h" - -void moduleMath(scriptcontext_t *ctx) { - assertNotNull(ctx, "Script context cannot be NULL"); - lua_State *L = ctx->luaState; - moduleMathVec2(L); - moduleMathVec3(L); - moduleMathVec4(L); - moduleMathMat4(L); -} diff --git a/src/dusk/script/module/math/modulemath.h b/src/dusk/script/module/math/modulemath.h index 5cf31a3b..f55b608c 100644 --- a/src/dusk/script/module/math/modulemath.h +++ b/src/dusk/script/module/math/modulemath.h @@ -6,6 +6,16 @@ */ #pragma once -#include "script/scriptcontext.h" +#include "script/module/modulebase.h" +#include "modulevec2.h" +#include "modulevec3.h" +#include "modulevec4.h" +#include "modulemat4.h" -void moduleMath(scriptcontext_t *ctx); +static void moduleMath(lua_State *L) { + assertNotNull(L, "Lua state cannot be NULL"); + moduleMathVec2(L); + moduleMathVec3(L); + moduleMathVec4(L); + moduleMathMat4(L); +} diff --git a/src/dusk/script/module/math/modulevec2.c b/src/dusk/script/module/math/modulevec2.c deleted file mode 100644 index 0c542ff1..00000000 --- a/src/dusk/script/module/math/modulevec2.c +++ /dev/null @@ -1,169 +0,0 @@ -/** - * Copyright (c) 2026 Dominic Masters - * - * This software is released under the MIT License. - * https://opensource.org/licenses/MIT - */ - -#include "modulevec2.h" -#include "assert/assert.h" - -void luaVec2Push(lua_State *L, vec2 v) { - vec2 *u = (vec2 *)lua_newuserdata(L, sizeof(vec2)); - glm_vec2_copy(v, *u); - luaL_getmetatable(L, "vec2_mt"); - lua_setmetatable(L, -2); -} - -void luaVec2Check(lua_State *L, int idx, vec2 out) { - vec2 *v = (vec2 *)luaL_checkudata(L, idx, "vec2_mt"); - glm_vec2_copy(*v, out); -} - -static int vec2Index(lua_State *L) { - vec2 *v = (vec2 *)luaL_checkudata(L, 1, "vec2_mt"); - const char *key = luaL_checkstring(L, 2); - if(strcmp(key, "x") == 0) { lua_pushnumber(L, (lua_Number)(*v)[0]); return 1; } - if(strcmp(key, "y") == 0) { lua_pushnumber(L, (lua_Number)(*v)[1]); return 1; } - lua_getmetatable(L, 1); - lua_getfield(L, -1, key); - return 1; -} - -static int vec2Newindex(lua_State *L) { - vec2 *v = (vec2 *)luaL_checkudata(L, 1, "vec2_mt"); - const char *key = luaL_checkstring(L, 2); - if(strcmp(key, "x") == 0) { (*v)[0] = (float_t)luaL_checknumber(L, 3); return 0; } - if(strcmp(key, "y") == 0) { (*v)[1] = (float_t)luaL_checknumber(L, 3); return 0; } - luaL_error(L, "vec2: unknown property '%s'", key); - return 0; -} - -static int vec2OpAdd(lua_State *L) { - vec2 *a = (vec2 *)luaL_checkudata(L, 1, "vec2_mt"); - vec2 *b = (vec2 *)luaL_checkudata(L, 2, "vec2_mt"); - vec2 r; glm_vec2_add(*a, *b, r); - luaVec2Push(L, r); return 1; -} - -static int vec2OpSub(lua_State *L) { - vec2 *a = (vec2 *)luaL_checkudata(L, 1, "vec2_mt"); - vec2 *b = (vec2 *)luaL_checkudata(L, 2, "vec2_mt"); - vec2 r; glm_vec2_sub(*a, *b, r); - luaVec2Push(L, r); return 1; -} - -static int vec2OpMul(lua_State *L) { - vec2 r; - if(lua_isnumber(L, 1)) { - float_t s = (float_t)lua_tonumber(L, 1); - vec2 *v = (vec2 *)luaL_checkudata(L, 2, "vec2_mt"); - glm_vec2_scale(*v, s, r); - } else { - vec2 *v = (vec2 *)luaL_checkudata(L, 1, "vec2_mt"); - float_t s = (float_t)luaL_checknumber(L, 2); - glm_vec2_scale(*v, s, r); - } - luaVec2Push(L, r); return 1; -} - -static int vec2OpDiv(lua_State *L) { - vec2 *v = (vec2 *)luaL_checkudata(L, 1, "vec2_mt"); - float_t s = (float_t)luaL_checknumber(L, 2); - vec2 r; glm_vec2_divs(*v, s, r); - luaVec2Push(L, r); return 1; -} - -static int vec2OpUnm(lua_State *L) { - vec2 *v = (vec2 *)luaL_checkudata(L, 1, "vec2_mt"); - vec2 r; glm_vec2_negate_to(*v, r); - luaVec2Push(L, r); return 1; -} - -static int vec2OpEq(lua_State *L) { - vec2 *a = (vec2 *)luaL_checkudata(L, 1, "vec2_mt"); - vec2 *b = (vec2 *)luaL_checkudata(L, 2, "vec2_mt"); - lua_pushboolean(L, (*a)[0] == (*b)[0] && (*a)[1] == (*b)[1]); - return 1; -} - -static int vec2OpToString(lua_State *L) { - vec2 *v = (vec2 *)luaL_checkudata(L, 1, "vec2_mt"); - char buf[64]; - snprintf(buf, sizeof(buf), "vec2(%.3f, %.3f)", (*v)[0], (*v)[1]); - lua_pushstring(L, buf); return 1; -} - -static int vec2Dot(lua_State *L) { - vec2 *a = (vec2 *)luaL_checkudata(L, 1, "vec2_mt"); - vec2 *b = (vec2 *)luaL_checkudata(L, 2, "vec2_mt"); - lua_pushnumber(L, (lua_Number)glm_vec2_dot(*a, *b)); return 1; -} - -static int vec2Length(lua_State *L) { - vec2 *v = (vec2 *)luaL_checkudata(L, 1, "vec2_mt"); - lua_pushnumber(L, (lua_Number)glm_vec2_norm(*v)); return 1; -} - -static int vec2LengthSq(lua_State *L) { - vec2 *v = (vec2 *)luaL_checkudata(L, 1, "vec2_mt"); - lua_pushnumber(L, (lua_Number)glm_vec2_norm2(*v)); return 1; -} - -static int vec2Normalize(lua_State *L) { - vec2 *v = (vec2 *)luaL_checkudata(L, 1, "vec2_mt"); - vec2 r; glm_vec2_normalize_to(*v, r); - luaVec2Push(L, r); return 1; -} - -static int vec2Lerp(lua_State *L) { - vec2 *a = (vec2 *)luaL_checkudata(L, 1, "vec2_mt"); - vec2 *b = (vec2 *)luaL_checkudata(L, 2, "vec2_mt"); - float_t t = (float_t)luaL_checknumber(L, 3); - vec2 r; glm_vec2_lerp(*a, *b, t, r); - luaVec2Push(L, r); return 1; -} - -static int vec2Distance(lua_State *L) { - vec2 *a = (vec2 *)luaL_checkudata(L, 1, "vec2_mt"); - vec2 *b = (vec2 *)luaL_checkudata(L, 2, "vec2_mt"); - lua_pushnumber(L, (lua_Number)glm_vec2_distance(*a, *b)); return 1; -} - -static int vec2Negate(lua_State *L) { - vec2 *v = (vec2 *)luaL_checkudata(L, 1, "vec2_mt"); - vec2 r; glm_vec2_negate_to(*v, r); - luaVec2Push(L, r); return 1; -} - -static int vec2Create(lua_State *L) { - vec2 v = {0, 0}; - int top = lua_gettop(L); - if(top >= 1) v[0] = (float_t)luaL_checknumber(L, 1); - if(top >= 2) v[1] = (float_t)luaL_checknumber(L, 2); - luaVec2Push(L, v); return 1; -} - -void moduleMathVec2(lua_State *L) { - if(!luaL_newmetatable(L, "vec2_mt")) { lua_pop(L, 1); return; } - - lua_pushcfunction(L, vec2Index); lua_setfield(L, -2, "__index"); - lua_pushcfunction(L, vec2Newindex); lua_setfield(L, -2, "__newindex"); - lua_pushcfunction(L, vec2OpAdd); lua_setfield(L, -2, "__add"); - lua_pushcfunction(L, vec2OpSub); lua_setfield(L, -2, "__sub"); - lua_pushcfunction(L, vec2OpMul); lua_setfield(L, -2, "__mul"); - lua_pushcfunction(L, vec2OpDiv); lua_setfield(L, -2, "__div"); - lua_pushcfunction(L, vec2OpUnm); lua_setfield(L, -2, "__unm"); - lua_pushcfunction(L, vec2OpEq); lua_setfield(L, -2, "__eq"); - lua_pushcfunction(L, vec2OpToString); lua_setfield(L, -2, "__tostring"); - lua_pushcfunction(L, vec2Dot); lua_setfield(L, -2, "dot"); - lua_pushcfunction(L, vec2Length); lua_setfield(L, -2, "length"); - lua_pushcfunction(L, vec2LengthSq); lua_setfield(L, -2, "lengthSq"); - lua_pushcfunction(L, vec2Normalize); lua_setfield(L, -2, "normalize"); - lua_pushcfunction(L, vec2Lerp); lua_setfield(L, -2, "lerp"); - lua_pushcfunction(L, vec2Distance); lua_setfield(L, -2, "distance"); - lua_pushcfunction(L, vec2Negate); lua_setfield(L, -2, "negate"); - lua_pop(L, 1); - - lua_register(L, "vec2", vec2Create); -} diff --git a/src/dusk/script/module/math/modulevec2.h b/src/dusk/script/module/math/modulevec2.h index 03c1431b..4f7843c7 100644 --- a/src/dusk/script/module/math/modulevec2.h +++ b/src/dusk/script/module/math/modulevec2.h @@ -6,8 +6,164 @@ */ #pragma once -#include "script/scriptcontext.h" +#include "script/module/modulebase.h" -void luaVec2Push(lua_State *L, vec2 v); -void luaVec2Check(lua_State *L, int idx, vec2 out); -void moduleMathVec2(lua_State *L); +static void luaVec2Push(lua_State *L, vec2 v) { + vec2 *u = (vec2 *)lua_newuserdata(L, sizeof(vec2)); + glm_vec2_copy(v, *u); + luaL_getmetatable(L, "vec2_mt"); + lua_setmetatable(L, -2); +} + +static void luaVec2Check(lua_State *L, int idx, vec2 out) { + vec2 *v = (vec2 *)luaL_checkudata(L, idx, "vec2_mt"); + glm_vec2_copy(*v, out); +} + +static int vec2Index(lua_State *L) { + vec2 *v = (vec2 *)luaL_checkudata(L, 1, "vec2_mt"); + const char *key = luaL_checkstring(L, 2); + if(stringCompare(key, "x") == 0) { lua_pushnumber(L, (lua_Number)(*v)[0]); return 1; } + if(stringCompare(key, "y") == 0) { lua_pushnumber(L, (lua_Number)(*v)[1]); return 1; } + lua_getmetatable(L, 1); + lua_getfield(L, -1, key); + return 1; +} + +static int vec2Newindex(lua_State *L) { + vec2 *v = (vec2 *)luaL_checkudata(L, 1, "vec2_mt"); + const char *key = luaL_checkstring(L, 2); + if(stringCompare(key, "x") == 0) { (*v)[0] = (float_t)luaL_checknumber(L, 3); return 0; } + if(stringCompare(key, "y") == 0) { (*v)[1] = (float_t)luaL_checknumber(L, 3); return 0; } + luaL_error(L, "vec2: unknown property '%s'", key); + return 0; +} + +static int vec2OpAdd(lua_State *L) { + vec2 *a = (vec2 *)luaL_checkudata(L, 1, "vec2_mt"); + vec2 *b = (vec2 *)luaL_checkudata(L, 2, "vec2_mt"); + vec2 r; glm_vec2_add(*a, *b, r); + luaVec2Push(L, r); return 1; +} + +static int vec2OpSub(lua_State *L) { + vec2 *a = (vec2 *)luaL_checkudata(L, 1, "vec2_mt"); + vec2 *b = (vec2 *)luaL_checkudata(L, 2, "vec2_mt"); + vec2 r; glm_vec2_sub(*a, *b, r); + luaVec2Push(L, r); return 1; +} + +static int vec2OpMul(lua_State *L) { + vec2 r; + if(lua_isnumber(L, 1)) { + float_t s = (float_t)lua_tonumber(L, 1); + vec2 *v = (vec2 *)luaL_checkudata(L, 2, "vec2_mt"); + glm_vec2_scale(*v, s, r); + } else { + vec2 *v = (vec2 *)luaL_checkudata(L, 1, "vec2_mt"); + float_t s = (float_t)luaL_checknumber(L, 2); + glm_vec2_scale(*v, s, r); + } + luaVec2Push(L, r); return 1; +} + +static int vec2OpDiv(lua_State *L) { + vec2 *v = (vec2 *)luaL_checkudata(L, 1, "vec2_mt"); + float_t s = (float_t)luaL_checknumber(L, 2); + vec2 r; glm_vec2_divs(*v, s, r); + luaVec2Push(L, r); return 1; +} + +static int vec2OpUnm(lua_State *L) { + vec2 *v = (vec2 *)luaL_checkudata(L, 1, "vec2_mt"); + vec2 r; glm_vec2_negate_to(*v, r); + luaVec2Push(L, r); return 1; +} + +static int vec2OpEq(lua_State *L) { + vec2 *a = (vec2 *)luaL_checkudata(L, 1, "vec2_mt"); + vec2 *b = (vec2 *)luaL_checkudata(L, 2, "vec2_mt"); + lua_pushboolean(L, (*a)[0] == (*b)[0] && (*a)[1] == (*b)[1]); + return 1; +} + +static int vec2OpToString(lua_State *L) { + vec2 *v = (vec2 *)luaL_checkudata(L, 1, "vec2_mt"); + char buf[64]; + snprintf(buf, sizeof(buf), "vec2(%.3f, %.3f)", (*v)[0], (*v)[1]); + lua_pushstring(L, buf); return 1; +} + +static int vec2Dot(lua_State *L) { + vec2 *a = (vec2 *)luaL_checkudata(L, 1, "vec2_mt"); + vec2 *b = (vec2 *)luaL_checkudata(L, 2, "vec2_mt"); + lua_pushnumber(L, (lua_Number)glm_vec2_dot(*a, *b)); return 1; +} + +static int vec2Length(lua_State *L) { + vec2 *v = (vec2 *)luaL_checkudata(L, 1, "vec2_mt"); + lua_pushnumber(L, (lua_Number)glm_vec2_norm(*v)); return 1; +} + +static int vec2LengthSq(lua_State *L) { + vec2 *v = (vec2 *)luaL_checkudata(L, 1, "vec2_mt"); + lua_pushnumber(L, (lua_Number)glm_vec2_norm2(*v)); return 1; +} + +static int vec2Normalize(lua_State *L) { + vec2 *v = (vec2 *)luaL_checkudata(L, 1, "vec2_mt"); + vec2 r; glm_vec2_normalize_to(*v, r); + luaVec2Push(L, r); return 1; +} + +static int vec2Lerp(lua_State *L) { + vec2 *a = (vec2 *)luaL_checkudata(L, 1, "vec2_mt"); + vec2 *b = (vec2 *)luaL_checkudata(L, 2, "vec2_mt"); + float_t t = (float_t)luaL_checknumber(L, 3); + vec2 r; glm_vec2_lerp(*a, *b, t, r); + luaVec2Push(L, r); return 1; +} + +static int vec2Distance(lua_State *L) { + vec2 *a = (vec2 *)luaL_checkudata(L, 1, "vec2_mt"); + vec2 *b = (vec2 *)luaL_checkudata(L, 2, "vec2_mt"); + lua_pushnumber(L, (lua_Number)glm_vec2_distance(*a, *b)); return 1; +} + +static int vec2Negate(lua_State *L) { + vec2 *v = (vec2 *)luaL_checkudata(L, 1, "vec2_mt"); + vec2 r; glm_vec2_negate_to(*v, r); + luaVec2Push(L, r); return 1; +} + +static int vec2Create(lua_State *L) { + vec2 v = {0, 0}; + int top = lua_gettop(L); + if(top >= 1) v[0] = (float_t)luaL_checknumber(L, 1); + if(top >= 2) v[1] = (float_t)luaL_checknumber(L, 2); + luaVec2Push(L, v); return 1; +} + +static void moduleMathVec2(lua_State *L) { + if(!luaL_newmetatable(L, "vec2_mt")) { lua_pop(L, 1); return; } + + lua_pushcfunction(L, vec2Index); lua_setfield(L, -2, "__index"); + lua_pushcfunction(L, vec2Newindex); lua_setfield(L, -2, "__newindex"); + lua_pushcfunction(L, vec2OpAdd); lua_setfield(L, -2, "__add"); + lua_pushcfunction(L, vec2OpSub); lua_setfield(L, -2, "__sub"); + lua_pushcfunction(L, vec2OpMul); lua_setfield(L, -2, "__mul"); + lua_pushcfunction(L, vec2OpDiv); lua_setfield(L, -2, "__div"); + lua_pushcfunction(L, vec2OpUnm); lua_setfield(L, -2, "__unm"); + lua_pushcfunction(L, vec2OpEq); lua_setfield(L, -2, "__eq"); + lua_pushcfunction(L, vec2OpToString); lua_setfield(L, -2, "__tostring"); + lua_pushcfunction(L, vec2Dot); lua_setfield(L, -2, "dot"); + lua_pushcfunction(L, vec2Length); lua_setfield(L, -2, "length"); + lua_pushcfunction(L, vec2LengthSq); lua_setfield(L, -2, "lengthSq"); + lua_pushcfunction(L, vec2Normalize); lua_setfield(L, -2, "normalize"); + lua_pushcfunction(L, vec2Lerp); lua_setfield(L, -2, "lerp"); + lua_pushcfunction(L, vec2Distance); lua_setfield(L, -2, "distance"); + lua_pushcfunction(L, vec2Negate); lua_setfield(L, -2, "negate"); + lua_pop(L, 1); + + lua_register(L, "vec2", vec2Create); +} diff --git a/src/dusk/script/module/math/modulevec3.c b/src/dusk/script/module/math/modulevec3.c deleted file mode 100644 index ef23b400..00000000 --- a/src/dusk/script/module/math/modulevec3.c +++ /dev/null @@ -1,180 +0,0 @@ -/** - * Copyright (c) 2026 Dominic Masters - * - * This software is released under the MIT License. - * https://opensource.org/licenses/MIT - */ - -#include "modulevec3.h" -#include "assert/assert.h" - -void luaVec3Push(lua_State *L, vec3 v) { - vec3 *u = (vec3 *)lua_newuserdata(L, sizeof(vec3)); - glm_vec3_copy(v, *u); - luaL_getmetatable(L, "vec3_mt"); - lua_setmetatable(L, -2); -} - -void luaVec3Check(lua_State *L, int idx, vec3 out) { - vec3 *v = (vec3 *)luaL_checkudata(L, idx, "vec3_mt"); - glm_vec3_copy(*v, out); -} - -static int vec3Index(lua_State *L) { - vec3 *v = (vec3 *)luaL_checkudata(L, 1, "vec3_mt"); - const char *key = luaL_checkstring(L, 2); - if(strcmp(key, "x") == 0) { lua_pushnumber(L, (lua_Number)(*v)[0]); return 1; } - if(strcmp(key, "y") == 0) { lua_pushnumber(L, (lua_Number)(*v)[1]); return 1; } - if(strcmp(key, "z") == 0) { lua_pushnumber(L, (lua_Number)(*v)[2]); return 1; } - lua_getmetatable(L, 1); - lua_getfield(L, -1, key); - return 1; -} - -static int vec3Newindex(lua_State *L) { - vec3 *v = (vec3 *)luaL_checkudata(L, 1, "vec3_mt"); - const char *key = luaL_checkstring(L, 2); - if(strcmp(key, "x") == 0) { (*v)[0] = (float_t)luaL_checknumber(L, 3); return 0; } - if(strcmp(key, "y") == 0) { (*v)[1] = (float_t)luaL_checknumber(L, 3); return 0; } - if(strcmp(key, "z") == 0) { (*v)[2] = (float_t)luaL_checknumber(L, 3); return 0; } - luaL_error(L, "vec3: unknown property '%s'", key); - return 0; -} - -static int vec3OpAdd(lua_State *L) { - vec3 *a = (vec3 *)luaL_checkudata(L, 1, "vec3_mt"); - vec3 *b = (vec3 *)luaL_checkudata(L, 2, "vec3_mt"); - vec3 r; glm_vec3_add(*a, *b, r); - luaVec3Push(L, r); return 1; -} - -static int vec3OpSub(lua_State *L) { - vec3 *a = (vec3 *)luaL_checkudata(L, 1, "vec3_mt"); - vec3 *b = (vec3 *)luaL_checkudata(L, 2, "vec3_mt"); - vec3 r; glm_vec3_sub(*a, *b, r); - luaVec3Push(L, r); return 1; -} - -static int vec3OpMul(lua_State *L) { - vec3 r; - if(lua_isnumber(L, 1)) { - float_t s = (float_t)lua_tonumber(L, 1); - vec3 *v = (vec3 *)luaL_checkudata(L, 2, "vec3_mt"); - glm_vec3_scale(*v, s, r); - } else { - vec3 *v = (vec3 *)luaL_checkudata(L, 1, "vec3_mt"); - float_t s = (float_t)luaL_checknumber(L, 2); - glm_vec3_scale(*v, s, r); - } - luaVec3Push(L, r); return 1; -} - -static int vec3OpDiv(lua_State *L) { - vec3 *v = (vec3 *)luaL_checkudata(L, 1, "vec3_mt"); - float_t s = (float_t)luaL_checknumber(L, 2); - vec3 r; glm_vec3_divs(*v, s, r); - luaVec3Push(L, r); return 1; -} - -static int vec3OpUnm(lua_State *L) { - vec3 *v = (vec3 *)luaL_checkudata(L, 1, "vec3_mt"); - vec3 r; glm_vec3_negate_to(*v, r); - luaVec3Push(L, r); return 1; -} - -static int vec3OpEq(lua_State *L) { - vec3 *a = (vec3 *)luaL_checkudata(L, 1, "vec3_mt"); - vec3 *b = (vec3 *)luaL_checkudata(L, 2, "vec3_mt"); - lua_pushboolean(L, (*a)[0] == (*b)[0] && (*a)[1] == (*b)[1] && (*a)[2] == (*b)[2]); - return 1; -} - -static int vec3OpToString(lua_State *L) { - vec3 *v = (vec3 *)luaL_checkudata(L, 1, "vec3_mt"); - char buf[80]; - snprintf(buf, sizeof(buf), "vec3(%.3f, %.3f, %.3f)", (*v)[0], (*v)[1], (*v)[2]); - lua_pushstring(L, buf); return 1; -} - -static int vec3Dot(lua_State *L) { - vec3 *a = (vec3 *)luaL_checkudata(L, 1, "vec3_mt"); - vec3 *b = (vec3 *)luaL_checkudata(L, 2, "vec3_mt"); - lua_pushnumber(L, (lua_Number)glm_vec3_dot(*a, *b)); return 1; -} - -static int vec3Cross(lua_State *L) { - vec3 *a = (vec3 *)luaL_checkudata(L, 1, "vec3_mt"); - vec3 *b = (vec3 *)luaL_checkudata(L, 2, "vec3_mt"); - vec3 r; glm_vec3_cross(*a, *b, r); - luaVec3Push(L, r); return 1; -} - -static int vec3Length(lua_State *L) { - vec3 *v = (vec3 *)luaL_checkudata(L, 1, "vec3_mt"); - lua_pushnumber(L, (lua_Number)glm_vec3_norm(*v)); return 1; -} - -static int vec3LengthSq(lua_State *L) { - vec3 *v = (vec3 *)luaL_checkudata(L, 1, "vec3_mt"); - lua_pushnumber(L, (lua_Number)glm_vec3_norm2(*v)); return 1; -} - -static int vec3Normalize(lua_State *L) { - vec3 *v = (vec3 *)luaL_checkudata(L, 1, "vec3_mt"); - vec3 r; glm_vec3_normalize_to(*v, r); - luaVec3Push(L, r); return 1; -} - -static int vec3Lerp(lua_State *L) { - vec3 *a = (vec3 *)luaL_checkudata(L, 1, "vec3_mt"); - vec3 *b = (vec3 *)luaL_checkudata(L, 2, "vec3_mt"); - float_t t = (float_t)luaL_checknumber(L, 3); - vec3 r; glm_vec3_lerp(*a, *b, t, r); - luaVec3Push(L, r); return 1; -} - -static int vec3Distance(lua_State *L) { - vec3 *a = (vec3 *)luaL_checkudata(L, 1, "vec3_mt"); - vec3 *b = (vec3 *)luaL_checkudata(L, 2, "vec3_mt"); - lua_pushnumber(L, (lua_Number)glm_vec3_distance(*a, *b)); return 1; -} - -static int vec3Negate(lua_State *L) { - vec3 *v = (vec3 *)luaL_checkudata(L, 1, "vec3_mt"); - vec3 r; glm_vec3_negate_to(*v, r); - luaVec3Push(L, r); return 1; -} - -static int vec3Create(lua_State *L) { - vec3 v = {0, 0, 0}; - int top = lua_gettop(L); - if(top >= 1) v[0] = (float_t)luaL_checknumber(L, 1); - if(top >= 2) v[1] = (float_t)luaL_checknumber(L, 2); - if(top >= 3) v[2] = (float_t)luaL_checknumber(L, 3); - luaVec3Push(L, v); return 1; -} - -void moduleMathVec3(lua_State *L) { - if(!luaL_newmetatable(L, "vec3_mt")) { lua_pop(L, 1); return; } - - lua_pushcfunction(L, vec3Index); lua_setfield(L, -2, "__index"); - lua_pushcfunction(L, vec3Newindex); lua_setfield(L, -2, "__newindex"); - lua_pushcfunction(L, vec3OpAdd); lua_setfield(L, -2, "__add"); - lua_pushcfunction(L, vec3OpSub); lua_setfield(L, -2, "__sub"); - lua_pushcfunction(L, vec3OpMul); lua_setfield(L, -2, "__mul"); - lua_pushcfunction(L, vec3OpDiv); lua_setfield(L, -2, "__div"); - lua_pushcfunction(L, vec3OpUnm); lua_setfield(L, -2, "__unm"); - lua_pushcfunction(L, vec3OpEq); lua_setfield(L, -2, "__eq"); - lua_pushcfunction(L, vec3OpToString); lua_setfield(L, -2, "__tostring"); - lua_pushcfunction(L, vec3Dot); lua_setfield(L, -2, "dot"); - lua_pushcfunction(L, vec3Cross); lua_setfield(L, -2, "cross"); - lua_pushcfunction(L, vec3Length); lua_setfield(L, -2, "length"); - lua_pushcfunction(L, vec3LengthSq); lua_setfield(L, -2, "lengthSq"); - lua_pushcfunction(L, vec3Normalize); lua_setfield(L, -2, "normalize"); - lua_pushcfunction(L, vec3Lerp); lua_setfield(L, -2, "lerp"); - lua_pushcfunction(L, vec3Distance); lua_setfield(L, -2, "distance"); - lua_pushcfunction(L, vec3Negate); lua_setfield(L, -2, "negate"); - lua_pop(L, 1); - - lua_register(L, "vec3", vec3Create); -} diff --git a/src/dusk/script/module/math/modulevec3.h b/src/dusk/script/module/math/modulevec3.h index b7cef869..97146be7 100644 --- a/src/dusk/script/module/math/modulevec3.h +++ b/src/dusk/script/module/math/modulevec3.h @@ -6,8 +6,175 @@ */ #pragma once -#include "script/scriptcontext.h" +#include "script/module/modulebase.h" -void luaVec3Push(lua_State *L, vec3 v); -void luaVec3Check(lua_State *L, int idx, vec3 out); -void moduleMathVec3(lua_State *L); +static void luaVec3Push(lua_State *L, vec3 v) { + vec3 *u = (vec3 *)lua_newuserdata(L, sizeof(vec3)); + glm_vec3_copy(v, *u); + luaL_getmetatable(L, "vec3_mt"); + lua_setmetatable(L, -2); +} + +static void luaVec3Check(lua_State *L, int idx, vec3 out) { + vec3 *v = (vec3 *)luaL_checkudata(L, idx, "vec3_mt"); + glm_vec3_copy(*v, out); +} + +static int vec3Index(lua_State *L) { + vec3 *v = (vec3 *)luaL_checkudata(L, 1, "vec3_mt"); + const char *key = luaL_checkstring(L, 2); + if(stringCompare(key, "x") == 0) { lua_pushnumber(L, (lua_Number)(*v)[0]); return 1; } + if(stringCompare(key, "y") == 0) { lua_pushnumber(L, (lua_Number)(*v)[1]); return 1; } + if(stringCompare(key, "z") == 0) { lua_pushnumber(L, (lua_Number)(*v)[2]); return 1; } + lua_getmetatable(L, 1); + lua_getfield(L, -1, key); + return 1; +} + +static int vec3Newindex(lua_State *L) { + vec3 *v = (vec3 *)luaL_checkudata(L, 1, "vec3_mt"); + const char *key = luaL_checkstring(L, 2); + if(stringCompare(key, "x") == 0) { (*v)[0] = (float_t)luaL_checknumber(L, 3); return 0; } + if(stringCompare(key, "y") == 0) { (*v)[1] = (float_t)luaL_checknumber(L, 3); return 0; } + if(stringCompare(key, "z") == 0) { (*v)[2] = (float_t)luaL_checknumber(L, 3); return 0; } + luaL_error(L, "vec3: unknown property '%s'", key); + return 0; +} + +static int vec3OpAdd(lua_State *L) { + vec3 *a = (vec3 *)luaL_checkudata(L, 1, "vec3_mt"); + vec3 *b = (vec3 *)luaL_checkudata(L, 2, "vec3_mt"); + vec3 r; glm_vec3_add(*a, *b, r); + luaVec3Push(L, r); return 1; +} + +static int vec3OpSub(lua_State *L) { + vec3 *a = (vec3 *)luaL_checkudata(L, 1, "vec3_mt"); + vec3 *b = (vec3 *)luaL_checkudata(L, 2, "vec3_mt"); + vec3 r; glm_vec3_sub(*a, *b, r); + luaVec3Push(L, r); return 1; +} + +static int vec3OpMul(lua_State *L) { + vec3 r; + if(lua_isnumber(L, 1)) { + float_t s = (float_t)lua_tonumber(L, 1); + vec3 *v = (vec3 *)luaL_checkudata(L, 2, "vec3_mt"); + glm_vec3_scale(*v, s, r); + } else { + vec3 *v = (vec3 *)luaL_checkudata(L, 1, "vec3_mt"); + float_t s = (float_t)luaL_checknumber(L, 2); + glm_vec3_scale(*v, s, r); + } + luaVec3Push(L, r); return 1; +} + +static int vec3OpDiv(lua_State *L) { + vec3 *v = (vec3 *)luaL_checkudata(L, 1, "vec3_mt"); + float_t s = (float_t)luaL_checknumber(L, 2); + vec3 r; glm_vec3_divs(*v, s, r); + luaVec3Push(L, r); return 1; +} + +static int vec3OpUnm(lua_State *L) { + vec3 *v = (vec3 *)luaL_checkudata(L, 1, "vec3_mt"); + vec3 r; glm_vec3_negate_to(*v, r); + luaVec3Push(L, r); return 1; +} + +static int vec3OpEq(lua_State *L) { + vec3 *a = (vec3 *)luaL_checkudata(L, 1, "vec3_mt"); + vec3 *b = (vec3 *)luaL_checkudata(L, 2, "vec3_mt"); + lua_pushboolean(L, (*a)[0] == (*b)[0] && (*a)[1] == (*b)[1] && (*a)[2] == (*b)[2]); + return 1; +} + +static int vec3OpToString(lua_State *L) { + vec3 *v = (vec3 *)luaL_checkudata(L, 1, "vec3_mt"); + char buf[80]; + snprintf(buf, sizeof(buf), "vec3(%.3f, %.3f, %.3f)", (*v)[0], (*v)[1], (*v)[2]); + lua_pushstring(L, buf); return 1; +} + +static int vec3Dot(lua_State *L) { + vec3 *a = (vec3 *)luaL_checkudata(L, 1, "vec3_mt"); + vec3 *b = (vec3 *)luaL_checkudata(L, 2, "vec3_mt"); + lua_pushnumber(L, (lua_Number)glm_vec3_dot(*a, *b)); return 1; +} + +static int vec3Cross(lua_State *L) { + vec3 *a = (vec3 *)luaL_checkudata(L, 1, "vec3_mt"); + vec3 *b = (vec3 *)luaL_checkudata(L, 2, "vec3_mt"); + vec3 r; glm_vec3_cross(*a, *b, r); + luaVec3Push(L, r); return 1; +} + +static int vec3Length(lua_State *L) { + vec3 *v = (vec3 *)luaL_checkudata(L, 1, "vec3_mt"); + lua_pushnumber(L, (lua_Number)glm_vec3_norm(*v)); return 1; +} + +static int vec3LengthSq(lua_State *L) { + vec3 *v = (vec3 *)luaL_checkudata(L, 1, "vec3_mt"); + lua_pushnumber(L, (lua_Number)glm_vec3_norm2(*v)); return 1; +} + +static int vec3Normalize(lua_State *L) { + vec3 *v = (vec3 *)luaL_checkudata(L, 1, "vec3_mt"); + vec3 r; glm_vec3_normalize_to(*v, r); + luaVec3Push(L, r); return 1; +} + +static int vec3Lerp(lua_State *L) { + vec3 *a = (vec3 *)luaL_checkudata(L, 1, "vec3_mt"); + vec3 *b = (vec3 *)luaL_checkudata(L, 2, "vec3_mt"); + float_t t = (float_t)luaL_checknumber(L, 3); + vec3 r; glm_vec3_lerp(*a, *b, t, r); + luaVec3Push(L, r); return 1; +} + +static int vec3Distance(lua_State *L) { + vec3 *a = (vec3 *)luaL_checkudata(L, 1, "vec3_mt"); + vec3 *b = (vec3 *)luaL_checkudata(L, 2, "vec3_mt"); + lua_pushnumber(L, (lua_Number)glm_vec3_distance(*a, *b)); return 1; +} + +static int vec3Negate(lua_State *L) { + vec3 *v = (vec3 *)luaL_checkudata(L, 1, "vec3_mt"); + vec3 r; glm_vec3_negate_to(*v, r); + luaVec3Push(L, r); return 1; +} + +static int vec3Create(lua_State *L) { + vec3 v = {0, 0, 0}; + int top = lua_gettop(L); + if(top >= 1) v[0] = (float_t)luaL_checknumber(L, 1); + if(top >= 2) v[1] = (float_t)luaL_checknumber(L, 2); + if(top >= 3) v[2] = (float_t)luaL_checknumber(L, 3); + luaVec3Push(L, v); return 1; +} + +static void moduleMathVec3(lua_State *L) { + if(!luaL_newmetatable(L, "vec3_mt")) { lua_pop(L, 1); return; } + + lua_pushcfunction(L, vec3Index); lua_setfield(L, -2, "__index"); + lua_pushcfunction(L, vec3Newindex); lua_setfield(L, -2, "__newindex"); + lua_pushcfunction(L, vec3OpAdd); lua_setfield(L, -2, "__add"); + lua_pushcfunction(L, vec3OpSub); lua_setfield(L, -2, "__sub"); + lua_pushcfunction(L, vec3OpMul); lua_setfield(L, -2, "__mul"); + lua_pushcfunction(L, vec3OpDiv); lua_setfield(L, -2, "__div"); + lua_pushcfunction(L, vec3OpUnm); lua_setfield(L, -2, "__unm"); + lua_pushcfunction(L, vec3OpEq); lua_setfield(L, -2, "__eq"); + lua_pushcfunction(L, vec3OpToString); lua_setfield(L, -2, "__tostring"); + lua_pushcfunction(L, vec3Dot); lua_setfield(L, -2, "dot"); + lua_pushcfunction(L, vec3Cross); lua_setfield(L, -2, "cross"); + lua_pushcfunction(L, vec3Length); lua_setfield(L, -2, "length"); + lua_pushcfunction(L, vec3LengthSq); lua_setfield(L, -2, "lengthSq"); + lua_pushcfunction(L, vec3Normalize); lua_setfield(L, -2, "normalize"); + lua_pushcfunction(L, vec3Lerp); lua_setfield(L, -2, "lerp"); + lua_pushcfunction(L, vec3Distance); lua_setfield(L, -2, "distance"); + lua_pushcfunction(L, vec3Negate); lua_setfield(L, -2, "negate"); + lua_pop(L, 1); + + lua_register(L, "vec3", vec3Create); +} diff --git a/src/dusk/script/module/math/modulevec4.c b/src/dusk/script/module/math/modulevec4.c deleted file mode 100644 index ed076593..00000000 --- a/src/dusk/script/module/math/modulevec4.c +++ /dev/null @@ -1,168 +0,0 @@ -/** - * Copyright (c) 2026 Dominic Masters - * - * This software is released under the MIT License. - * https://opensource.org/licenses/MIT - */ - -#include "modulevec4.h" -#include "assert/assert.h" - -void luaVec4Push(lua_State *L, vec4 v) { - vec4 *u = (vec4 *)lua_newuserdata(L, sizeof(vec4)); - glm_vec4_copy(v, *u); - luaL_getmetatable(L, "vec4_mt"); - lua_setmetatable(L, -2); -} - -void luaVec4Check(lua_State *L, int idx, vec4 out) { - vec4 *v = (vec4 *)luaL_checkudata(L, idx, "vec4_mt"); - glm_vec4_copy(*v, out); -} - -static int vec4Index(lua_State *L) { - vec4 *v = (vec4 *)luaL_checkudata(L, 1, "vec4_mt"); - const char *key = luaL_checkstring(L, 2); - if(strcmp(key, "x") == 0 || strcmp(key, "u0") == 0) { lua_pushnumber(L, (lua_Number)(*v)[0]); return 1; } - if(strcmp(key, "y") == 0 || strcmp(key, "v0") == 0) { lua_pushnumber(L, (lua_Number)(*v)[1]); return 1; } - if(strcmp(key, "z") == 0 || strcmp(key, "u1") == 0) { lua_pushnumber(L, (lua_Number)(*v)[2]); return 1; } - if(strcmp(key, "w") == 0 || strcmp(key, "v1") == 0) { lua_pushnumber(L, (lua_Number)(*v)[3]); return 1; } - lua_getmetatable(L, 1); - lua_getfield(L, -1, key); - return 1; -} - -static int vec4Newindex(lua_State *L) { - vec4 *v = (vec4 *)luaL_checkudata(L, 1, "vec4_mt"); - const char *key = luaL_checkstring(L, 2); - if(strcmp(key, "x") == 0 || strcmp(key, "u0") == 0) { (*v)[0] = (float_t)luaL_checknumber(L, 3); return 0; } - if(strcmp(key, "y") == 0 || strcmp(key, "v0") == 0) { (*v)[1] = (float_t)luaL_checknumber(L, 3); return 0; } - if(strcmp(key, "z") == 0 || strcmp(key, "u1") == 0) { (*v)[2] = (float_t)luaL_checknumber(L, 3); return 0; } - if(strcmp(key, "w") == 0 || strcmp(key, "v1") == 0) { (*v)[3] = (float_t)luaL_checknumber(L, 3); return 0; } - luaL_error(L, "vec4: unknown property '%s'", key); - return 0; -} - -static int vec4OpAdd(lua_State *L) { - vec4 *a = (vec4 *)luaL_checkudata(L, 1, "vec4_mt"); - vec4 *b = (vec4 *)luaL_checkudata(L, 2, "vec4_mt"); - vec4 r; glm_vec4_add(*a, *b, r); - luaVec4Push(L, r); return 1; -} - -static int vec4OpSub(lua_State *L) { - vec4 *a = (vec4 *)luaL_checkudata(L, 1, "vec4_mt"); - vec4 *b = (vec4 *)luaL_checkudata(L, 2, "vec4_mt"); - vec4 r; glm_vec4_sub(*a, *b, r); - luaVec4Push(L, r); return 1; -} - -static int vec4OpMul(lua_State *L) { - vec4 r; - if(lua_isnumber(L, 1)) { - float_t s = (float_t)lua_tonumber(L, 1); - vec4 *v = (vec4 *)luaL_checkudata(L, 2, "vec4_mt"); - glm_vec4_scale(*v, s, r); - } else { - vec4 *v = (vec4 *)luaL_checkudata(L, 1, "vec4_mt"); - float_t s = (float_t)luaL_checknumber(L, 2); - glm_vec4_scale(*v, s, r); - } - luaVec4Push(L, r); return 1; -} - -static int vec4OpDiv(lua_State *L) { - vec4 *v = (vec4 *)luaL_checkudata(L, 1, "vec4_mt"); - float_t s = (float_t)luaL_checknumber(L, 2); - vec4 r; glm_vec4_divs(*v, s, r); - luaVec4Push(L, r); return 1; -} - -static int vec4OpUnm(lua_State *L) { - vec4 *v = (vec4 *)luaL_checkudata(L, 1, "vec4_mt"); - vec4 r; glm_vec4_negate_to(*v, r); - luaVec4Push(L, r); return 1; -} - -static int vec4OpEq(lua_State *L) { - vec4 *a = (vec4 *)luaL_checkudata(L, 1, "vec4_mt"); - vec4 *b = (vec4 *)luaL_checkudata(L, 2, "vec4_mt"); - lua_pushboolean(L, (*a)[0] == (*b)[0] && (*a)[1] == (*b)[1] && (*a)[2] == (*b)[2] && (*a)[3] == (*b)[3]); - return 1; -} - -static int vec4OpToString(lua_State *L) { - vec4 *v = (vec4 *)luaL_checkudata(L, 1, "vec4_mt"); - char buf[96]; - snprintf(buf, sizeof(buf), "vec4(%.3f, %.3f, %.3f, %.3f)", (*v)[0], (*v)[1], (*v)[2], (*v)[3]); - lua_pushstring(L, buf); return 1; -} - -static int vec4Dot(lua_State *L) { - vec4 *a = (vec4 *)luaL_checkudata(L, 1, "vec4_mt"); - vec4 *b = (vec4 *)luaL_checkudata(L, 2, "vec4_mt"); - lua_pushnumber(L, (lua_Number)glm_vec4_dot(*a, *b)); return 1; -} - -static int vec4Length(lua_State *L) { - vec4 *v = (vec4 *)luaL_checkudata(L, 1, "vec4_mt"); - lua_pushnumber(L, (lua_Number)glm_vec4_norm(*v)); return 1; -} - -static int vec4LengthSq(lua_State *L) { - vec4 *v = (vec4 *)luaL_checkudata(L, 1, "vec4_mt"); - lua_pushnumber(L, (lua_Number)glm_vec4_norm2(*v)); return 1; -} - -static int vec4Normalize(lua_State *L) { - vec4 *v = (vec4 *)luaL_checkudata(L, 1, "vec4_mt"); - vec4 r; glm_vec4_normalize_to(*v, r); - luaVec4Push(L, r); return 1; -} - -static int vec4Lerp(lua_State *L) { - vec4 *a = (vec4 *)luaL_checkudata(L, 1, "vec4_mt"); - vec4 *b = (vec4 *)luaL_checkudata(L, 2, "vec4_mt"); - float_t t = (float_t)luaL_checknumber(L, 3); - vec4 r; glm_vec4_lerp(*a, *b, t, r); - luaVec4Push(L, r); return 1; -} - -static int vec4Negate(lua_State *L) { - vec4 *v = (vec4 *)luaL_checkudata(L, 1, "vec4_mt"); - vec4 r; glm_vec4_negate_to(*v, r); - luaVec4Push(L, r); return 1; -} - -static int vec4Create(lua_State *L) { - vec4 v = {0, 0, 0, 0}; - int top = lua_gettop(L); - if(top >= 1) v[0] = (float_t)luaL_checknumber(L, 1); - if(top >= 2) v[1] = (float_t)luaL_checknumber(L, 2); - if(top >= 3) v[2] = (float_t)luaL_checknumber(L, 3); - if(top >= 4) v[3] = (float_t)luaL_checknumber(L, 4); - luaVec4Push(L, v); return 1; -} - -void moduleMathVec4(lua_State *L) { - if(!luaL_newmetatable(L, "vec4_mt")) { lua_pop(L, 1); return; } - - lua_pushcfunction(L, vec4Index); lua_setfield(L, -2, "__index"); - lua_pushcfunction(L, vec4Newindex); lua_setfield(L, -2, "__newindex"); - lua_pushcfunction(L, vec4OpAdd); lua_setfield(L, -2, "__add"); - lua_pushcfunction(L, vec4OpSub); lua_setfield(L, -2, "__sub"); - lua_pushcfunction(L, vec4OpMul); lua_setfield(L, -2, "__mul"); - lua_pushcfunction(L, vec4OpDiv); lua_setfield(L, -2, "__div"); - lua_pushcfunction(L, vec4OpUnm); lua_setfield(L, -2, "__unm"); - lua_pushcfunction(L, vec4OpEq); lua_setfield(L, -2, "__eq"); - lua_pushcfunction(L, vec4OpToString); lua_setfield(L, -2, "__tostring"); - lua_pushcfunction(L, vec4Dot); lua_setfield(L, -2, "dot"); - lua_pushcfunction(L, vec4Length); lua_setfield(L, -2, "length"); - lua_pushcfunction(L, vec4LengthSq); lua_setfield(L, -2, "lengthSq"); - lua_pushcfunction(L, vec4Normalize); lua_setfield(L, -2, "normalize"); - lua_pushcfunction(L, vec4Lerp); lua_setfield(L, -2, "lerp"); - lua_pushcfunction(L, vec4Negate); lua_setfield(L, -2, "negate"); - lua_pop(L, 1); - - lua_register(L, "vec4", vec4Create); -} diff --git a/src/dusk/script/module/math/modulevec4.h b/src/dusk/script/module/math/modulevec4.h index fcead9a4..cad467c2 100644 --- a/src/dusk/script/module/math/modulevec4.h +++ b/src/dusk/script/module/math/modulevec4.h @@ -6,8 +6,163 @@ */ #pragma once -#include "script/scriptcontext.h" +#include "script/module/modulebase.h" -void luaVec4Push(lua_State *L, vec4 v); -void luaVec4Check(lua_State *L, int idx, vec4 out); -void moduleMathVec4(lua_State *L); +static void luaVec4Push(lua_State *L, vec4 v) { + vec4 *u = (vec4 *)lua_newuserdata(L, sizeof(vec4)); + glm_vec4_copy(v, *u); + luaL_getmetatable(L, "vec4_mt"); + lua_setmetatable(L, -2); +} + +static void luaVec4Check(lua_State *L, int idx, vec4 out) { + vec4 *v = (vec4 *)luaL_checkudata(L, idx, "vec4_mt"); + glm_vec4_copy(*v, out); +} + +static int vec4Index(lua_State *L) { + vec4 *v = (vec4 *)luaL_checkudata(L, 1, "vec4_mt"); + const char *key = luaL_checkstring(L, 2); + if(stringCompare(key, "x") == 0 || stringCompare(key, "u0") == 0) { lua_pushnumber(L, (lua_Number)(*v)[0]); return 1; } + if(stringCompare(key, "y") == 0 || stringCompare(key, "v0") == 0) { lua_pushnumber(L, (lua_Number)(*v)[1]); return 1; } + if(stringCompare(key, "z") == 0 || stringCompare(key, "u1") == 0) { lua_pushnumber(L, (lua_Number)(*v)[2]); return 1; } + if(stringCompare(key, "w") == 0 || stringCompare(key, "v1") == 0) { lua_pushnumber(L, (lua_Number)(*v)[3]); return 1; } + lua_getmetatable(L, 1); + lua_getfield(L, -1, key); + return 1; +} + +static int vec4Newindex(lua_State *L) { + vec4 *v = (vec4 *)luaL_checkudata(L, 1, "vec4_mt"); + const char *key = luaL_checkstring(L, 2); + if(stringCompare(key, "x") == 0 || stringCompare(key, "u0") == 0) { (*v)[0] = (float_t)luaL_checknumber(L, 3); return 0; } + if(stringCompare(key, "y") == 0 || stringCompare(key, "v0") == 0) { (*v)[1] = (float_t)luaL_checknumber(L, 3); return 0; } + if(stringCompare(key, "z") == 0 || stringCompare(key, "u1") == 0) { (*v)[2] = (float_t)luaL_checknumber(L, 3); return 0; } + if(stringCompare(key, "w") == 0 || stringCompare(key, "v1") == 0) { (*v)[3] = (float_t)luaL_checknumber(L, 3); return 0; } + luaL_error(L, "vec4: unknown property '%s'", key); + return 0; +} + +static int vec4OpAdd(lua_State *L) { + vec4 *a = (vec4 *)luaL_checkudata(L, 1, "vec4_mt"); + vec4 *b = (vec4 *)luaL_checkudata(L, 2, "vec4_mt"); + vec4 r; glm_vec4_add(*a, *b, r); + luaVec4Push(L, r); return 1; +} + +static int vec4OpSub(lua_State *L) { + vec4 *a = (vec4 *)luaL_checkudata(L, 1, "vec4_mt"); + vec4 *b = (vec4 *)luaL_checkudata(L, 2, "vec4_mt"); + vec4 r; glm_vec4_sub(*a, *b, r); + luaVec4Push(L, r); return 1; +} + +static int vec4OpMul(lua_State *L) { + vec4 r; + if(lua_isnumber(L, 1)) { + float_t s = (float_t)lua_tonumber(L, 1); + vec4 *v = (vec4 *)luaL_checkudata(L, 2, "vec4_mt"); + glm_vec4_scale(*v, s, r); + } else { + vec4 *v = (vec4 *)luaL_checkudata(L, 1, "vec4_mt"); + float_t s = (float_t)luaL_checknumber(L, 2); + glm_vec4_scale(*v, s, r); + } + luaVec4Push(L, r); return 1; +} + +static int vec4OpDiv(lua_State *L) { + vec4 *v = (vec4 *)luaL_checkudata(L, 1, "vec4_mt"); + float_t s = (float_t)luaL_checknumber(L, 2); + vec4 r; glm_vec4_divs(*v, s, r); + luaVec4Push(L, r); return 1; +} + +static int vec4OpUnm(lua_State *L) { + vec4 *v = (vec4 *)luaL_checkudata(L, 1, "vec4_mt"); + vec4 r; glm_vec4_negate_to(*v, r); + luaVec4Push(L, r); return 1; +} + +static int vec4OpEq(lua_State *L) { + vec4 *a = (vec4 *)luaL_checkudata(L, 1, "vec4_mt"); + vec4 *b = (vec4 *)luaL_checkudata(L, 2, "vec4_mt"); + lua_pushboolean(L, (*a)[0] == (*b)[0] && (*a)[1] == (*b)[1] && (*a)[2] == (*b)[2] && (*a)[3] == (*b)[3]); + return 1; +} + +static int vec4OpToString(lua_State *L) { + vec4 *v = (vec4 *)luaL_checkudata(L, 1, "vec4_mt"); + char buf[96]; + snprintf(buf, sizeof(buf), "vec4(%.3f, %.3f, %.3f, %.3f)", (*v)[0], (*v)[1], (*v)[2], (*v)[3]); + lua_pushstring(L, buf); return 1; +} + +static int vec4Dot(lua_State *L) { + vec4 *a = (vec4 *)luaL_checkudata(L, 1, "vec4_mt"); + vec4 *b = (vec4 *)luaL_checkudata(L, 2, "vec4_mt"); + lua_pushnumber(L, (lua_Number)glm_vec4_dot(*a, *b)); return 1; +} + +static int vec4Length(lua_State *L) { + vec4 *v = (vec4 *)luaL_checkudata(L, 1, "vec4_mt"); + lua_pushnumber(L, (lua_Number)glm_vec4_norm(*v)); return 1; +} + +static int vec4LengthSq(lua_State *L) { + vec4 *v = (vec4 *)luaL_checkudata(L, 1, "vec4_mt"); + lua_pushnumber(L, (lua_Number)glm_vec4_norm2(*v)); return 1; +} + +static int vec4Normalize(lua_State *L) { + vec4 *v = (vec4 *)luaL_checkudata(L, 1, "vec4_mt"); + vec4 r; glm_vec4_normalize_to(*v, r); + luaVec4Push(L, r); return 1; +} + +static int vec4Lerp(lua_State *L) { + vec4 *a = (vec4 *)luaL_checkudata(L, 1, "vec4_mt"); + vec4 *b = (vec4 *)luaL_checkudata(L, 2, "vec4_mt"); + float_t t = (float_t)luaL_checknumber(L, 3); + vec4 r; glm_vec4_lerp(*a, *b, t, r); + luaVec4Push(L, r); return 1; +} + +static int vec4Negate(lua_State *L) { + vec4 *v = (vec4 *)luaL_checkudata(L, 1, "vec4_mt"); + vec4 r; glm_vec4_negate_to(*v, r); + luaVec4Push(L, r); return 1; +} + +static int vec4Create(lua_State *L) { + vec4 v = {0, 0, 0, 0}; + int top = lua_gettop(L); + if(top >= 1) v[0] = (float_t)luaL_checknumber(L, 1); + if(top >= 2) v[1] = (float_t)luaL_checknumber(L, 2); + if(top >= 3) v[2] = (float_t)luaL_checknumber(L, 3); + if(top >= 4) v[3] = (float_t)luaL_checknumber(L, 4); + luaVec4Push(L, v); return 1; +} + +static void moduleMathVec4(lua_State *L) { + if(!luaL_newmetatable(L, "vec4_mt")) { lua_pop(L, 1); return; } + + lua_pushcfunction(L, vec4Index); lua_setfield(L, -2, "__index"); + lua_pushcfunction(L, vec4Newindex); lua_setfield(L, -2, "__newindex"); + lua_pushcfunction(L, vec4OpAdd); lua_setfield(L, -2, "__add"); + lua_pushcfunction(L, vec4OpSub); lua_setfield(L, -2, "__sub"); + lua_pushcfunction(L, vec4OpMul); lua_setfield(L, -2, "__mul"); + lua_pushcfunction(L, vec4OpDiv); lua_setfield(L, -2, "__div"); + lua_pushcfunction(L, vec4OpUnm); lua_setfield(L, -2, "__unm"); + lua_pushcfunction(L, vec4OpEq); lua_setfield(L, -2, "__eq"); + lua_pushcfunction(L, vec4OpToString); lua_setfield(L, -2, "__tostring"); + lua_pushcfunction(L, vec4Dot); lua_setfield(L, -2, "dot"); + lua_pushcfunction(L, vec4Length); lua_setfield(L, -2, "length"); + lua_pushcfunction(L, vec4LengthSq); lua_setfield(L, -2, "lengthSq"); + lua_pushcfunction(L, vec4Normalize); lua_setfield(L, -2, "normalize"); + lua_pushcfunction(L, vec4Lerp); lua_setfield(L, -2, "lerp"); + lua_pushcfunction(L, vec4Negate); lua_setfield(L, -2, "negate"); + lua_pop(L, 1); + + lua_register(L, "vec4", vec4Create); +} diff --git a/src/dusk/script/module/module.h b/src/dusk/script/module/module.h new file mode 100644 index 00000000..30ea7cc2 --- /dev/null +++ b/src/dusk/script/module/module.h @@ -0,0 +1,48 @@ +/** + * Copyright (c) 2026 Dominic Masters + * + * This software is released under the MIT License. + * https://opensource.org/licenses/MIT + */ + +#pragma once +#include "script/module/script/modulescript.h" +#include "script/module/entity/moduleentity.h" +#include "script/module/input/moduleinput.h" +#include "script/module/moduleplatform.h" +#include "script/module/scene/modulescene.h" +#include "script/module/locale/modulelocale.h" +#include "script/module/time/moduletime.h" +#include "script/module/event/moduleevent.h" +#include "script/module/display/modulecolor.h" +#include "script/module/display/modulespritebatch.h" +#include "script/module/math/modulemath.h" +#include "script/module/display/moduleshader.h" +#include "script/module/ui/moduleui.h" +#include "script/module/display/moduletext.h" +#include "script/module/display/modulescreen.h" +#include "script/module/display/moduletexture.h" +#include "script/module/display/moduletileset.h" + +void moduleRegister(lua_State *L) { + assertNotNull(L, "Lua state cannot be NULL"); + + moduleScript(L); + moduleEntity(L); + moduleInput(L); + modulePlatform(L); + moduleScene(L); + moduleLocale(L); + moduleTime(L); + moduleEvent(L); + moduleColor(L); + moduleSpriteBatch(L); + moduleMath(L); + moduleShader(L); + moduleUi(L); + moduleText(L); + moduleScreen(L); + moduleTexture(L); + moduleTileset(L); + moduleScript(L); +} \ No newline at end of file diff --git a/src/dusk/script/module/display/moduleglm.h b/src/dusk/script/module/modulebase.h similarity index 69% rename from src/dusk/script/module/display/moduleglm.h rename to src/dusk/script/module/modulebase.h index 01a648e1..d7183a64 100644 --- a/src/dusk/script/module/display/moduleglm.h +++ b/src/dusk/script/module/modulebase.h @@ -1,11 +1,12 @@ /** * Copyright (c) 2026 Dominic Masters - * + * * This software is released under the MIT License. * https://opensource.org/licenses/MIT */ #pragma once #include "script/scriptcontext.h" - -void moduleGLM(scriptcontext_t *context); +#include "assert/assert.h" +#include "util/string.h" +#include "util/memory.h" \ No newline at end of file diff --git a/src/dusk/script/module/moduleplatform.h b/src/dusk/script/module/moduleplatform.h index a45f5695..2920c20c 100644 --- a/src/dusk/script/module/moduleplatform.h +++ b/src/dusk/script/module/moduleplatform.h @@ -16,12 +16,12 @@ #define MODULE_PLATFORM_VALUE "PLATFORM = '" DUSK_TARGET_SYSTEM "'\n" -void modulePlatform(scriptcontext_t *ctx) { - assertNotNull(ctx, "Script context cannot be NULL"); +static void modulePlatform(lua_State *L) { + assertNotNull(L, "Lua state cannot be NULL"); - scriptContextExec(ctx, MODULE_PLATFORM_VALUE); + luaL_dostring(L, MODULE_PLATFORM_VALUE); #ifdef modulePlatformPlatform - modulePlatformPlatform(ctx); + modulePlatformPlatform(L); #endif } \ No newline at end of file diff --git a/src/dusk/script/module/scene/CMakeLists.txt b/src/dusk/script/module/scene/CMakeLists.txt deleted file mode 100644 index 9b099835..00000000 --- a/src/dusk/script/module/scene/CMakeLists.txt +++ /dev/null @@ -1,10 +0,0 @@ -# Copyright (c) 2026 Dominic Masters -# -# This software is released under the MIT License. -# https://opensource.org/licenses/MIT - -# Sources -target_sources(${DUSK_LIBRARY_TARGET_NAME} - PUBLIC - modulescene.c -) \ No newline at end of file diff --git a/src/dusk/script/module/scene/modulescene.c b/src/dusk/script/module/scene/modulescene.c deleted file mode 100644 index 13575607..00000000 --- a/src/dusk/script/module/scene/modulescene.c +++ /dev/null @@ -1,35 +0,0 @@ -/** - * Copyright (c) 2026 Dominic Masters - * - * This software is released under the MIT License. - * https://opensource.org/licenses/MIT - */ - -#include "modulescene.h" -#include "assert/assert.h" -#include "scene/scene.h" - -void moduleScene(scriptcontext_t *ctx) { - assertNotNull(ctx, "Script context cannot be NULL"); - - lua_register(ctx->luaState, "sceneSet", moduleSceneSet); - - lua_pushlightuserdata(ctx->luaState, &SCENE.eventUpdate); - lua_setglobal(ctx->luaState, "SCENE_EVENT_UPDATE"); -} - -int moduleSceneSet(lua_State *L) { - assertNotNull(L, "Lua state cannot be NULL"); - - // Need string - if(!lua_isstring(L, 1)) { - luaL_error(L, "sceneSet requires a string argument"); - return 0; - } - - const char_t *script = lua_tostring(L, 1); - - sceneSet(script); - - return 0; -} \ No newline at end of file diff --git a/src/dusk/script/module/scene/modulescene.h b/src/dusk/script/module/scene/modulescene.h index 773d05f4..03b80620 100644 --- a/src/dusk/script/module/scene/modulescene.h +++ b/src/dusk/script/module/scene/modulescene.h @@ -1,24 +1,31 @@ /** * Copyright (c) 2025 Dominic Masters - * + * * This software is released under the MIT License. * https://opensource.org/licenses/MIT */ #pragma once -#include "script/scriptcontext.h" +#include "script/module/modulebase.h" +#include "scene/scene.h" -/** - * Register the scene module within the given script context. - * - * @param ctx The script context to register the module in. - */ -void moduleScene(scriptcontext_t *ctx); +static int moduleSceneSet(lua_State *L) { + assertNotNull(L, "Lua state cannot be NULL"); -/** - * Lua binding for sceneSet function. - * - * @param L The Lua state. - * @return int Number of return values on the Lua stack. - */ -int moduleSceneSet(lua_State *L); \ No newline at end of file + if(!lua_isstring(L, 1)) { + luaL_error(L, "sceneSet requires a string argument"); + return 0; + } + + sceneSet(lua_tostring(L, 1)); + return 0; +} + +static void moduleScene(lua_State *L) { + assertNotNull(L, "Lua state cannot be NULL"); + + lua_register(L, "sceneSet", moduleSceneSet); + + lua_pushlightuserdata(L, &SCENE.eventUpdate); + lua_setglobal(L, "SCENE_EVENT_UPDATE"); +} diff --git a/src/dusk/script/module/system/modulescript.c b/src/dusk/script/module/script/modulescript.h similarity index 51% rename from src/dusk/script/module/system/modulescript.c rename to src/dusk/script/module/script/modulescript.h index 5ab48760..82c5a113 100644 --- a/src/dusk/script/module/system/modulescript.c +++ b/src/dusk/script/module/script/modulescript.h @@ -5,21 +5,11 @@ * https://opensource.org/licenses/MIT */ -#include "modulescript.h" -#include "assert/assert.h" +#pragma once +#include "script/module/modulebase.h" #include "console/console.h" -#include "util/string.h" -#include "script/scriptmodule.h" -void moduleScript(scriptcontext_t *context) { - assertNotNull(context, "Script context cannot be NULL"); - - lua_register(context->luaState, "print", moduleScriptPrint); - lua_register(context->luaState, "include", moduleScriptInclude); - lua_register(context->luaState, "module", moduleScriptModule); -} - -int moduleScriptPrint(lua_State *L) { +static int moduleScriptPrint(lua_State *L) { assertNotNull(L, "Lua state cannot be NULL"); int n = lua_gettop(L); @@ -40,7 +30,7 @@ int moduleScriptPrint(lua_State *L) { return 0; } -int moduleScriptInclude(lua_State *L) { +static int moduleScriptInclude(lua_State *L) { assertNotNull(L, "Lua state cannot be NULL"); if(!lua_isstring(L, 1)) { @@ -60,14 +50,11 @@ int moduleScriptInclude(lua_State *L) { return 0; } - // Copy out filename to mutable buffer char_t buffer[1024]; stringCopy(buffer, filename, 1024); - // Ensure it has .lua extension size_t len = strlen(buffer); - if(len < 4 || strcmp(&buffer[len - 4], ".lua") != 0) { - // Append .lua + if(len < 4 || stringCompare(&buffer[len - 4], ".lua") != 0) { if(len + 4 >= 1024) { luaL_error(L, "Filename too long to append .lua"); return 0; @@ -75,11 +62,7 @@ int moduleScriptInclude(lua_State *L) { stringCopy(&buffer[len], ".lua", 5); } - // Execute the script file - errorret_t err = scriptContextExecFile( - ctx, - buffer - ); + errorret_t err = scriptContextExecFile(ctx, buffer); if(err.code != ERROR_OK) { luaL_error(L, "Failed to include script file"); errorCatch(errorPrint(err)); @@ -89,33 +72,9 @@ int moduleScriptInclude(lua_State *L) { return 0; } -int moduleScriptModule(lua_State *L) { +static void moduleScript(lua_State *L) { assertNotNull(L, "Lua state cannot be NULL"); - if(!lua_isstring(L, 1)) { - luaL_error(L, "Expected string module name"); - return 0; - } - - const char_t *moduleName = luaL_checkstring(L, 1); - if(moduleName == NULL) { - luaL_error(L, "Module name cannot be NULL"); - return 0; - } - - const scriptmodule_t *module = scriptModuleGetByName(moduleName); - if(module == NULL) { - luaL_error(L, "Module '%s' not found", moduleName); - return 0; - } - - scriptcontext_t* ctx = *(scriptcontext_t**)lua_getextraspace(L); - if(ctx == NULL) { - luaL_error(L, "Script context is NULL"); - return 0; - } - - module->callback(ctx); - - return 0; + lua_register(L, "print", moduleScriptPrint); + lua_register(L, "include", moduleScriptInclude); } diff --git a/src/dusk/script/module/system/CMakeLists.txt b/src/dusk/script/module/system/CMakeLists.txt deleted file mode 100644 index 8ec9c9c5..00000000 --- a/src/dusk/script/module/system/CMakeLists.txt +++ /dev/null @@ -1,10 +0,0 @@ -# Copyright (c) 2026 Dominic Masters -# -# This software is released under the MIT License. -# https://opensource.org/licenses/MIT - -# Sources -target_sources(${DUSK_LIBRARY_TARGET_NAME} - PUBLIC - modulescript.c -) \ No newline at end of file diff --git a/src/dusk/script/module/system/modulescript.h b/src/dusk/script/module/system/modulescript.h deleted file mode 100644 index a089d10f..00000000 --- a/src/dusk/script/module/system/modulescript.h +++ /dev/null @@ -1,40 +0,0 @@ -/** - * Copyright (c) 2025 Dominic Masters - * - * This software is released under the MIT License. - * https://opensource.org/licenses/MIT - */ - -#pragma once -#include "script/scriptcontext.h" - -/** - * Register system module functions to the given script context. - * - * @param context The script context to register system module functions to. - */ -void moduleScript(scriptcontext_t *context); - -/** - * Script binding for printing messages to the debug console. - * - * @param L The Lua state. - * @return Number of return values on the Lua stack. - */ -int moduleScriptPrint(lua_State *L); - -/** - * Script binding for including and executing another script file. - * - * @param L The Lua state. - * @return Number of return values on the Lua stack. - */ -int moduleScriptInclude(lua_State *L); - -/** - * Script binding for loading a script module by name. - * - * @param L The Lua state. - * @return Number of return values on the Lua stack. - */ -int moduleScriptModule(lua_State *L); diff --git a/src/dusk/script/module/time/CMakeLists.txt b/src/dusk/script/module/time/CMakeLists.txt deleted file mode 100644 index 8fd83bcb..00000000 --- a/src/dusk/script/module/time/CMakeLists.txt +++ /dev/null @@ -1,10 +0,0 @@ -# Copyright (c) 2026 Dominic Masters -# -# This software is released under the MIT License. -# https://opensource.org/licenses/MIT - -# Sources -target_sources(${DUSK_LIBRARY_TARGET_NAME} - PUBLIC - moduletime.c -) \ No newline at end of file diff --git a/src/dusk/script/module/time/moduletime.c b/src/dusk/script/module/time/moduletime.c deleted file mode 100644 index 60eda525..00000000 --- a/src/dusk/script/module/time/moduletime.c +++ /dev/null @@ -1,41 +0,0 @@ -/** - * Copyright (c) 2026 Dominic Masters - * - * This software is released under the MIT License. - * https://opensource.org/licenses/MIT - */ - -#include "moduletime.h" -#include "assert/assert.h" - -void moduleTime(scriptcontext_t *ctx) { - assertNotNull(ctx, "Script context cannot be NULL"); - - // Script structure - if(luaL_newmetatable(ctx->luaState, "time_mt")) { - lua_pushcfunction(ctx->luaState, moduleTimeIndex); - lua_setfield(ctx->luaState, -2, "__index"); - } - lua_pop(ctx->luaState, 1); - - dusktime_t **ud = (dusktime_t**)lua_newuserdata(ctx->luaState, sizeof(dusktime_t*)); - *ud = &TIME; - luaL_setmetatable(ctx->luaState, "time_mt"); - lua_setglobal(ctx->luaState, "TIME"); -} - -int moduleTimeIndex(lua_State *L) { - const char_t *key = lua_tostring(L, 2); - assertStrLenMin(key, 1, "Key cannot be empty."); - - if(stringCompare(key, "delta") == 0) { - lua_pushnumber(L, TIME.delta); - return 1; - } else if(stringCompare(key, "time") == 0) { - lua_pushnumber(L, TIME.time); - return 1; - } - - lua_pushnil(L); - return 1; -} \ No newline at end of file diff --git a/src/dusk/script/module/time/moduletime.h b/src/dusk/script/module/time/moduletime.h index d6b3070b..69b07190 100644 --- a/src/dusk/script/module/time/moduletime.h +++ b/src/dusk/script/module/time/moduletime.h @@ -1,25 +1,41 @@ /** * Copyright (c) 2026 Dominic Masters - * + * * This software is released under the MIT License. * https://opensource.org/licenses/MIT */ #pragma once -#include "script/scriptcontext.h" +#include "script/module/modulebase.h" #include "time/time.h" -#include "util/string.h" -/** - * Registers the time module within the given script context. - * - * @param ctx The script context to register the module in. - */ -void moduleTime(scriptcontext_t *ctx); +static int moduleTimeIndex(lua_State *L) { + const char_t *key = lua_tostring(L, 2); + assertStrLenMin(key, 1, "Key cannot be empty."); -/** - * Index function for the time structure. - * @param L The Lua state. - * @return Number of return values. - */ -int moduleTimeIndex(lua_State *L); \ No newline at end of file + if(stringCompare(key, "delta") == 0) { + lua_pushnumber(L, TIME.delta); + return 1; + } else if(stringCompare(key, "time") == 0) { + lua_pushnumber(L, TIME.time); + return 1; + } + + lua_pushnil(L); + return 1; +} + +static void moduleTime(lua_State *L) { + assertNotNull(L, "Lua state cannot be NULL"); + + if(luaL_newmetatable(L, "time_mt")) { + lua_pushcfunction(L, moduleTimeIndex); + lua_setfield(L, -2, "__index"); + } + lua_pop(L, 1); + + dusktime_t **ud = (dusktime_t**)lua_newuserdata(L, sizeof(dusktime_t*)); + *ud = &TIME; + luaL_setmetatable(L, "time_mt"); + lua_setglobal(L, "TIME"); +} diff --git a/src/dusk/script/module/ui/CMakeLists.txt b/src/dusk/script/module/ui/CMakeLists.txt deleted file mode 100644 index 8fc42de6..00000000 --- a/src/dusk/script/module/ui/CMakeLists.txt +++ /dev/null @@ -1,10 +0,0 @@ -# Copyright (c) 2026 Dominic Masters -# -# This software is released under the MIT License. -# https://opensource.org/licenses/MIT - -# Sources -target_sources(${DUSK_LIBRARY_TARGET_NAME} - PUBLIC - moduleui.c -) \ No newline at end of file diff --git a/src/dusk/script/module/ui/moduleui.c b/src/dusk/script/module/ui/moduleui.c deleted file mode 100644 index f71ad19e..00000000 --- a/src/dusk/script/module/ui/moduleui.c +++ /dev/null @@ -1,15 +0,0 @@ -/** - * Copyright (c) 2026 Dominic Masters - * - * This software is released under the MIT License. - * https://opensource.org/licenses/MIT - */ - -#include "moduleui.h" -#include "assert/assert.h" -#include "ui/ui.h" - -void moduleUi(scriptcontext_t *ctx) { - assertNotNull(ctx, "Script context cannot be NULL"); - -} \ No newline at end of file diff --git a/src/dusk/script/module/ui/moduleui.h b/src/dusk/script/module/ui/moduleui.h index 3e65ea4c..78dc99e8 100644 --- a/src/dusk/script/module/ui/moduleui.h +++ b/src/dusk/script/module/ui/moduleui.h @@ -1,17 +1,13 @@ /** * Copyright (c) 2026 Dominic Masters - * + * * This software is released under the MIT License. * https://opensource.org/licenses/MIT */ #pragma once -#include "script/scriptcontext.h" -#include "error/error.h" +#include "script/module/modulebase.h" -/** - * Registers the ui module within the given script context. - * - * @param ctx The script context to register the module in. - */ -void moduleUi(scriptcontext_t *ctx); \ No newline at end of file +static void moduleUi(lua_State *L) { + assertNotNull(L, "Lua state cannot be NULL"); +} diff --git a/src/dusk/script/scriptcontext.c b/src/dusk/script/scriptcontext.c index e8ae1ad5..8e971e40 100644 --- a/src/dusk/script/scriptcontext.c +++ b/src/dusk/script/scriptcontext.c @@ -9,9 +9,13 @@ #include "assert/assert.h" #include "asset/asset.h" #include "util/memory.h" -#include "script/scriptmodule.h" #include "event/event.h" #include "asset/loader/script/assetscriptloader.h" +#include "script/module/module.h" + +#ifdef SCRIPT_GAME_INIT + #include "script/scriptgame.h" +#endif errorret_t scriptContextInit(scriptcontext_t *context) { assertNotNull(context, "Script context cannot be NULL"); @@ -27,13 +31,14 @@ errorret_t scriptContextInit(scriptcontext_t *context) { // Store context in Lua extraspace *(scriptcontext_t**)lua_getextraspace(context->luaState) = context; - - // All scripts get the script module - const scriptmodule_t *sysScript = scriptModuleGetByName("script"); - if(sysScript == NULL) { - errorThrow("Failed to find system script module"); - } - sysScript->callback(context); + + // Register built-in script modules. + moduleRegister(context->luaState); + + // Fire any game script init function if defined. + #ifdef SCRIPT_GAME_INIT + SCRIPT_GAME_INIT(L); + #endif errorOk(); } diff --git a/src/dusk/script/scriptmanager.c b/src/dusk/script/scriptmanager.c index 684e8e84..097c28f0 100644 --- a/src/dusk/script/scriptmanager.c +++ b/src/dusk/script/scriptmanager.c @@ -14,9 +14,17 @@ scriptmanager_t SCRIPT_MANAGER; errorret_t scriptManagerInit() { memoryZero(&SCRIPT_MANAGER, sizeof(scriptmanager_t)); + + errorChain(scriptContextInit(&SCRIPT_MANAGER.mainContext)); + errorChain(scriptContextExec( + &SCRIPT_MANAGER.mainContext, + "print('Main Script Context Ready!')" + )); + errorOk(); } errorret_t scriptManagerDispose() { + scriptContextDispose(&SCRIPT_MANAGER.mainContext); errorOk(); } \ No newline at end of file diff --git a/src/dusk/script/scriptmodule.c b/src/dusk/script/scriptmodule.c deleted file mode 100644 index 1b08ea15..00000000 --- a/src/dusk/script/scriptmodule.c +++ /dev/null @@ -1,81 +0,0 @@ -/** - * Copyright (c) 2025 Dominic Masters - * - * This software is released under the MIT License. - * https://opensource.org/licenses/MIT - */ - -#include "scriptmodule.h" -#include "script/module/system/modulescript.h" -#include "script/module/entity/moduleentity.h" -#include "script/module/input/moduleinput.h" -#include "script/module/moduleplatform.h" -#include "script/module/scene/modulescene.h" -#include "script/module/locale/modulelocale.h" -#include "script/module/time/moduletime.h" -#include "script/module/event/moduleevent.h" -#include "script/module/display/modulecolor.h" -#include "script/module/display/modulespritebatch.h" -#include "script/module/display/moduleglm.h" -#include "script/module/math/modulemath.h" -#include "script/module/display/moduleshader.h" -#include "script/module/ui/moduleui.h" -#include "script/module/display/moduletext.h" -#include "script/module/display/modulescreen.h" -#include "script/module/display/moduletexture.h" -#include "script/module/display/moduletileset.h" -#include "script/module/entity/display/moduleentityposition.h" -#include "script/module/entity/display/moduleentitycamera.h" -#include "script/module/entity/display/moduleentitymesh.h" -#include "script/module/entity/display/moduleentitymaterial.h" -#include "script/module/entity/physics/moduleentityphysics.h" -#include "script/module/entity/script/moduleentityscript.h" - -#include "script/scriptgame.h" -#include "util/string.h" - -const scriptmodule_t SCRIPT_MODULE_LIST[] = { - #define REG(strName, fnCallback) { .name = strName, .callback = fnCallback }, - REG("script", moduleScript) - REG("entityposition", moduleEntityPosition) - REG("entitycamera", moduleEntityCamera) - REG("entitymesh", moduleEntityMesh) - REG("entitymaterial", moduleEntityMaterial) - REG("entityphysics", moduleEntityPhysics) - REG("entityscript", moduleEntityScript) - REG("entity", moduleEntity) - REG("input", moduleInput) - REG("platform", modulePlatform) - REG("color", moduleColor) - REG("scene", moduleScene) - REG("locale", moduleLocale) - REG("time", moduleTime) - REG("event", moduleEvent) - REG("spritebatch", moduleSpriteBatch) - REG("glm", moduleGLM) - REG("math", moduleMath) - REG("ui", moduleUi) - REG("text", moduleText) - REG("screen", moduleScreen) - REG("texture", moduleTexture) - REG("tileset", moduleTileset) - REG("shader", moduleShader) - #undef REG - - #ifdef SCRIPT_GAME_LIST - SCRIPT_GAME_LIST - #endif -}; - -#define SCRIPT_MODULE_COUNT ( \ - sizeof(SCRIPT_MODULE_LIST) / sizeof(scriptmodule_t) \ -) - -const scriptmodule_t * scriptModuleGetByName(const char_t *name) { - for(uint_fast8_t i = 0; i < SCRIPT_MODULE_COUNT; i++) { - if(stringCompare(SCRIPT_MODULE_LIST[i].name, name) != 0) continue; - return &SCRIPT_MODULE_LIST[i]; - } - - return NULL; -} \ No newline at end of file diff --git a/src/dusk/script/scriptmodule.h b/src/dusk/script/scriptmodule.h deleted file mode 100644 index da9cf8e8..00000000 --- a/src/dusk/script/scriptmodule.h +++ /dev/null @@ -1,24 +0,0 @@ -/** - * Copyright (c) 2025 Dominic Masters - * - * This software is released under the MIT License. - * https://opensource.org/licenses/MIT - */ - -#pragma once -#include "scriptcontext.h" - -typedef struct scriptmodule_s { - const char_t *name; - void (*callback)(scriptcontext_t *ctx); -} scriptmodule_t; - -extern const scriptmodule_t SCRIPT_MODULE_LIST[]; - -/** - * Retrieves a script module by its name. - * - * @param name The name of the script module. - * @return Pointer to the script module, or NULL if not found. - */ -const scriptmodule_t * scriptModuleGetByName(const char_t *name); \ No newline at end of file diff --git a/src/dusklinux/asset/assetlinux.c b/src/dusklinux/asset/assetlinux.c index a7e93b5c..76b1a5ce 100644 --- a/src/dusklinux/asset/assetlinux.c +++ b/src/dusklinux/asset/assetlinux.c @@ -50,12 +50,20 @@ errorret_t assetInitLinux(void) { const char_t **path = ASSET_LINUX_SEARCH_PATHS; int32_t error; do { - sprintf( - searchPath, + char_t temp[ASSET_FILE_PATH_MAX]; + snprintf( + temp, + ASSET_FILE_PATH_MAX, *path, - ASSET.platform.systemPath, ASSET_FILE_NAME ); + snprintf( + searchPath, + ASSET_FILE_PATH_MAX, + "%s/%s", + ASSET.platform.systemPath, + temp + ); // Try open ASSET.zip = zip_open(searchPath, ZIP_RDONLY, &error); diff --git a/src/dusklinux/asset/assetlinux.h b/src/dusklinux/asset/assetlinux.h index 2bd7cddc..56c9f437 100644 --- a/src/dusklinux/asset/assetlinux.h +++ b/src/dusklinux/asset/assetlinux.h @@ -10,7 +10,6 @@ #include "asset/assetfile.h" static const char_t *ASSET_LINUX_SEARCH_PATHS[] = { - "%s/%s", "%s", "../%s", "../../%s", diff --git a/src/dusklinux/script/module/moduleplatformlinux.h b/src/dusklinux/script/module/moduleplatformlinux.h index 6dfd383f..eb476dac 100644 --- a/src/dusklinux/script/module/moduleplatformlinux.h +++ b/src/dusklinux/script/module/moduleplatformlinux.h @@ -8,6 +8,6 @@ #pragma once #include "script/scriptcontext.h" -void modulePlatformLinux(scriptcontext_t *ctx) { - scriptContextExec(ctx, "LINUX = true\n"); +static void modulePlatformLinux(lua_State *L) { + luaL_dostring(L, "LINUX = true\n"); } \ No newline at end of file diff --git a/src/duskrpg/script/module/item/CMakeLists.txt b/src/duskrpg/script/module/item/CMakeLists.txt index 250fc610..84f36e34 100644 --- a/src/duskrpg/script/module/item/CMakeLists.txt +++ b/src/duskrpg/script/module/item/CMakeLists.txt @@ -3,8 +3,3 @@ # This software is released under the MIT License. # https://opensource.org/licenses/MIT -# Sources -target_sources(${DUSK_LIBRARY_TARGET_NAME} - PUBLIC - moduleitem.c -) \ No newline at end of file diff --git a/src/duskrpg/script/module/item/moduleitem.c b/src/duskrpg/script/module/item/moduleitem.c deleted file mode 100644 index 3e26dbc6..00000000 --- a/src/duskrpg/script/module/item/moduleitem.c +++ /dev/null @@ -1,262 +0,0 @@ -/** - * Copyright (c) 2026 Dominic Masters - * - * This software is released under the MIT License. - * https://opensource.org/licenses/MIT - */ - -#include "moduleitem.h" -#include "item/inventory.h" -#include "item/backpack.h" -#include "assert/assert.h" - -void moduleItem(scriptcontext_t *context) { - assertNotNull(context, "Script context cannot be NULL"); - - // Set item information - scriptContextExec(context, ITEM_SCRIPT); - - // Bind BACKPACK const pointer - lua_pushlightuserdata(context->luaState, &BACKPACK); - lua_setglobal(context->luaState, "BACKPACK"); - - // Bind Methods - lua_register( - context->luaState, "inventoryItemExists", moduleInventoryItemExists - ); - lua_register(context->luaState, "inventoryAdd", moduleInventoryAdd); - lua_register(context->luaState, "inventorySet", moduleInventorySet); - lua_register(context->luaState, "inventoryRemove", moduleInventoryRemove); - lua_register(context->luaState, "inventoryGetCount", moduleInventoryGetCount); - lua_register(context->luaState, "inventoryIsFull", moduleInventoryIsFull); - lua_register(context->luaState, "inventoryItemFull", moduleInventoryItemFull); - lua_register(context->luaState, "inventorySort", moduleInventorySort); -} - -int moduleInventoryItemExists(lua_State *L) { - assertNotNull(L, "Lua state cannot be NULL"); - - // Expect inventory pointer and item ID - if(!lua_islightuserdata(L, 1)) { - luaL_error(L, "inventoryItemExists: Expected inventory pointer as first argument"); - return 0; - } - - if(!lua_isnumber(L, 2)) { - luaL_error(L, "inventoryItemExists: Expected item ID as second argument"); - return 0; - } - - inventory_t *inventory = (inventory_t *)lua_touserdata(L, 1); - itemid_t item = (itemid_t)lua_tonumber(L, 2); - - assertNotNull(inventory, "Inventory pointer cannot be NULL."); - - // Error if item is ITEM_ID_NULL - if(item == ITEM_ID_NULL) { - luaL_error(L, "inventoryItemExists: Item ID cannot be ITEM_ID_NULL"); - return 0; - } - - bool_t hasItem = inventoryItemExists(inventory, item); - lua_pushboolean(L, hasItem); - return 1; -} - -int moduleInventorySet(lua_State *L) { - assertNotNull(L, "Lua state cannot be NULL"); - - // Requires inventory pointer, item ID and quantity (uint8_t) - if(!lua_islightuserdata(L, 1)) { - luaL_error(L, "inventorySet: Expected inventory pointer as first argument"); - return 0; - } - - if(!lua_isnumber(L, 2)) { - luaL_error(L, "inventorySet: Expected item ID as second argument"); - return 0; - } - - if(!lua_isnumber(L, 3)) { - luaL_error(L, "inventorySet: Expected quantity as third argument"); - return 0; - } - - inventory_t *inventory = (inventory_t *)lua_touserdata(L, 1); - itemid_t item = (itemid_t)lua_tonumber(L, 2); - uint8_t quantity = (uint8_t)lua_tonumber(L, 3); - - assertNotNull(inventory, "Inventory pointer cannot be NULL."); - inventorySet(inventory, item, quantity); - return 0; -} - -int moduleInventoryAdd(lua_State *L) { - assertNotNull(L, "Lua state cannot be NULL"); - - // Requires inventory pointer, item ID and quantity (uint8_t) - if(!lua_islightuserdata(L, 1)) { - luaL_error(L, "inventoryAdd: Expected inventory pointer as first argument"); - return 0; - } - - if(!lua_isnumber(L, 2)) { - luaL_error(L, "inventoryAdd: Expected item ID as second argument"); - return 0; - } - - if(!lua_isnumber(L, 3)) { - luaL_error(L, "inventoryAdd: Expected quantity as third argument"); - return 0; - } - - inventory_t *inventory = (inventory_t *)lua_touserdata(L, 1); - itemid_t item = (itemid_t)lua_tonumber(L, 2); - uint8_t quantity = (uint8_t)lua_tonumber(L, 3); - - assertNotNull(inventory, "Inventory pointer cannot be NULL."); - inventoryAdd(inventory, item, quantity); - return 0; -} - -int moduleInventoryRemove(lua_State *L) { - assertNotNull(L, "Lua state cannot be NULL"); - - // Requires inventory pointer and item ID - if(!lua_islightuserdata(L, 1)) { - luaL_error(L, "inventoryRemove: Expected inventory pointer as first argument"); - return 0; - } - - if(!lua_isnumber(L, 2)) { - luaL_error(L, "inventoryRemove: Expected item ID as second argument"); - return 0; - } - - inventory_t *inventory = (inventory_t *)lua_touserdata(L, 1); - itemid_t item = (itemid_t)lua_tonumber(L, 2); - assertNotNull(inventory, "Inventory pointer cannot be NULL."); - - // if there is a third argument (quantity), then we are actually doing a - // partial removal. - if(lua_gettop(L) >= 3) { - if(!lua_isnumber(L, 3)) { - luaL_error(L, "inventoryRemove: Expected quantity as third argument"); - return 0; - } - uint8_t amount = (uint8_t)lua_tonumber(L, 3); - uint8_t currentQuantity = inventoryGetCount(inventory, item); - if(amount >= currentQuantity) { - // Remove entire stack - inventoryRemove(inventory, item); - return 0; - } - - // Set new quantity - inventorySet(inventory, item, currentQuantity - amount); - return 0; - } - - inventoryRemove(inventory, item); - return 0; -} - -int moduleInventoryGetCount(lua_State *L) { - assertNotNull(L, "Lua state cannot be NULL"); - - // Requires inventory pointer and item ID - if(!lua_islightuserdata(L, 1)) { - luaL_error(L, "inventoryGetCount: Expected inventory pointer as first argument"); - return 0; - } - - if(!lua_isnumber(L, 2)) { - luaL_error(L, "inventoryGetCount: Expected item ID as second argument"); - return 0; - } - - inventory_t *inventory = (inventory_t *)lua_touserdata(L, 1); - itemid_t item = (itemid_t)lua_tonumber(L, 2); - - assertNotNull(inventory, "Inventory pointer cannot be NULL."); - - uint8_t count = inventoryGetCount(inventory, item); - lua_pushnumber(L, count); - return 1; -} - -int moduleInventoryIsFull(lua_State *L) { - assertNotNull(L, "Lua state cannot be NULL"); - - // Requires inventory pointer - if(!lua_islightuserdata(L, 1)) { - luaL_error(L, "inventoryIsFull: Expected inventory pointer as first argument"); - return 0; - } - - inventory_t *inventory = (inventory_t *)lua_touserdata(L, 1); - - assertNotNull(inventory, "Inventory pointer cannot be NULL."); - - bool_t isFull = inventoryIsFull(inventory); - lua_pushboolean(L, isFull); - return 1; -} - -int moduleInventoryItemFull(lua_State *L) { - assertNotNull(L, "Lua state cannot be NULL"); - - // Requires inventory pointer and item ID - if(!lua_islightuserdata(L, 1)) { - luaL_error(L, "inventoryItemFull: Expected inventory pointer as first argument"); - return 0; - } - - if(!lua_isnumber(L, 2)) { - luaL_error(L, "inventoryItemFull: Expected item ID as second argument"); - return 0; - } - - inventory_t *inventory = (inventory_t *)lua_touserdata(L, 1); - itemid_t item = (itemid_t)lua_tonumber(L, 2); - - assertNotNull(inventory, "Inventory pointer cannot be NULL."); - - bool_t isFull = inventoryItemFull(inventory, item); - lua_pushboolean(L, isFull); - return 1; -} - -int moduleInventorySort(lua_State *L) { - assertNotNull(L, "Lua state cannot be NULL"); - - // Requires inventory pointer, sort type and reverse flag - if(!lua_islightuserdata(L, 1)) { - luaL_error(L, "inventorySort: Expected inventory pointer as first argument"); - return 0; - } - - if(!lua_isnumber(L, 2)) { - luaL_error(L, "inventorySort: Expected sort type as second argument"); - return 0; - } - - // Optional, reverse - bool_t reverse = false; - if(lua_gettop(L) >= 3) { - if(!lua_isboolean(L, 3)) { - luaL_error(L, "inventorySort: Expected reverse flag as third argument"); - return 0; - } - - reverse = (bool_t)lua_toboolean(L, 3); - } - - inventory_t *inventory = (inventory_t *)lua_touserdata(L, 1); - inventorysort_t sortBy = (inventorysort_t)lua_tonumber(L, 2); - - assertNotNull(inventory, "Inventory pointer cannot be NULL."); - inventorySort(inventory, sortBy, reverse); - return 0; -} - diff --git a/src/duskrpg/script/module/item/moduleitem.h b/src/duskrpg/script/module/item/moduleitem.h index 91b0ac97..f7cf67db 100644 --- a/src/duskrpg/script/module/item/moduleitem.h +++ b/src/duskrpg/script/module/item/moduleitem.h @@ -1,80 +1,241 @@ /** * Copyright (c) 2026 Dominic Masters - * + * * This software is released under the MIT License. * https://opensource.org/licenses/MIT */ #pragma once #include "script/scriptcontext.h" +#include "item/inventory.h" +#include "item/backpack.h" +#include "assert/assert.h" -/** - * Register item functions to the given script context. - * - * @param context The script context to register item functions to. - */ -void moduleItem(scriptcontext_t *context); +static int moduleInventoryItemExists(lua_State *L) { + assertNotNull(L, "Lua state cannot be NULL"); -/** - * Script binding for checking if an item exists in an inventory. - * - * @param L The Lua state. - * @return Number of return values on the Lua stack. - */ -int moduleInventoryItemExists(lua_State *L); + if(!lua_islightuserdata(L, 1)) { + luaL_error(L, "inventoryItemExists: Expected inventory pointer as first argument"); + return 0; + } -/** - * Script binding for adding an item to an inventory. - * - * @param L The Lua state. - * @return Number of return values on the Lua stack. - */ -int moduleInventorySet(lua_State *L); + if(!lua_isnumber(L, 2)) { + luaL_error(L, "inventoryItemExists: Expected item ID as second argument"); + return 0; + } -/** - * Script binding for setting the quantity of an item in an inventory. - * - * @param L The Lua state. - * @return Number of return values on the Lua stack. - */ -int moduleInventoryAdd(lua_State *L); + inventory_t *inventory = (inventory_t *)lua_touserdata(L, 1); + itemid_t item = (itemid_t)lua_tonumber(L, 2); -/** - * Script binding for removing an item from an inventory. - * - * @param L The Lua state. - * @return Number of return values on the Lua stack. - */ -int moduleInventoryRemove(lua_State *L); + assertNotNull(inventory, "Inventory pointer cannot be NULL."); -/** - * Script binding for getting the count of an item in an inventory. - * - * @param L The Lua state. - * @return Number of return values on the Lua stack. - */ -int moduleInventoryGetCount(lua_State *L); + if(item == ITEM_ID_NULL) { + luaL_error(L, "inventoryItemExists: Item ID cannot be ITEM_ID_NULL"); + return 0; + } -/** - * Script binding for checking if an inventory is full. - * - * @param L The Lua state. - * @return Number of return values on the Lua stack. - */ -int moduleInventoryIsFull(lua_State *L); + bool_t hasItem = inventoryItemExists(inventory, item); + lua_pushboolean(L, hasItem); + return 1; +} -/** - * Script binding for checking if an item stack in an inventory is full. - * - * @param L The Lua state. - * @return Number of return values on the Lua stack. - */ -int moduleInventoryItemFull(lua_State *L); +static int moduleInventorySet(lua_State *L) { + assertNotNull(L, "Lua state cannot be NULL"); -/** - * Script binding for sorting an inventory. - * - * @param L The Lua state. - * @return Number of return values on the Lua stack. - */ -int moduleInventorySort(lua_State *L); + if(!lua_islightuserdata(L, 1)) { + luaL_error(L, "inventorySet: Expected inventory pointer as first argument"); + return 0; + } + + if(!lua_isnumber(L, 2)) { + luaL_error(L, "inventorySet: Expected item ID as second argument"); + return 0; + } + + if(!lua_isnumber(L, 3)) { + luaL_error(L, "inventorySet: Expected quantity as third argument"); + return 0; + } + + inventory_t *inventory = (inventory_t *)lua_touserdata(L, 1); + itemid_t item = (itemid_t)lua_tonumber(L, 2); + uint8_t quantity = (uint8_t)lua_tonumber(L, 3); + + assertNotNull(inventory, "Inventory pointer cannot be NULL."); + inventorySet(inventory, item, quantity); + return 0; +} + +static int moduleInventoryAdd(lua_State *L) { + assertNotNull(L, "Lua state cannot be NULL"); + + if(!lua_islightuserdata(L, 1)) { + luaL_error(L, "inventoryAdd: Expected inventory pointer as first argument"); + return 0; + } + + if(!lua_isnumber(L, 2)) { + luaL_error(L, "inventoryAdd: Expected item ID as second argument"); + return 0; + } + + if(!lua_isnumber(L, 3)) { + luaL_error(L, "inventoryAdd: Expected quantity as third argument"); + return 0; + } + + inventory_t *inventory = (inventory_t *)lua_touserdata(L, 1); + itemid_t item = (itemid_t)lua_tonumber(L, 2); + uint8_t quantity = (uint8_t)lua_tonumber(L, 3); + + assertNotNull(inventory, "Inventory pointer cannot be NULL."); + inventoryAdd(inventory, item, quantity); + return 0; +} + +static int moduleInventoryRemove(lua_State *L) { + assertNotNull(L, "Lua state cannot be NULL"); + + if(!lua_islightuserdata(L, 1)) { + luaL_error(L, "inventoryRemove: Expected inventory pointer as first argument"); + return 0; + } + + if(!lua_isnumber(L, 2)) { + luaL_error(L, "inventoryRemove: Expected item ID as second argument"); + return 0; + } + + inventory_t *inventory = (inventory_t *)lua_touserdata(L, 1); + itemid_t item = (itemid_t)lua_tonumber(L, 2); + assertNotNull(inventory, "Inventory pointer cannot be NULL."); + + if(lua_gettop(L) >= 3) { + if(!lua_isnumber(L, 3)) { + luaL_error(L, "inventoryRemove: Expected quantity as third argument"); + return 0; + } + uint8_t amount = (uint8_t)lua_tonumber(L, 3); + uint8_t currentQuantity = inventoryGetCount(inventory, item); + if(amount >= currentQuantity) { + inventoryRemove(inventory, item); + return 0; + } + inventorySet(inventory, item, currentQuantity - amount); + return 0; + } + + inventoryRemove(inventory, item); + return 0; +} + +static int moduleInventoryGetCount(lua_State *L) { + assertNotNull(L, "Lua state cannot be NULL"); + + if(!lua_islightuserdata(L, 1)) { + luaL_error(L, "inventoryGetCount: Expected inventory pointer as first argument"); + return 0; + } + + if(!lua_isnumber(L, 2)) { + luaL_error(L, "inventoryGetCount: Expected item ID as second argument"); + return 0; + } + + inventory_t *inventory = (inventory_t *)lua_touserdata(L, 1); + itemid_t item = (itemid_t)lua_tonumber(L, 2); + + assertNotNull(inventory, "Inventory pointer cannot be NULL."); + + uint8_t count = inventoryGetCount(inventory, item); + lua_pushnumber(L, count); + return 1; +} + +static int moduleInventoryIsFull(lua_State *L) { + assertNotNull(L, "Lua state cannot be NULL"); + + if(!lua_islightuserdata(L, 1)) { + luaL_error(L, "inventoryIsFull: Expected inventory pointer as first argument"); + return 0; + } + + inventory_t *inventory = (inventory_t *)lua_touserdata(L, 1); + + assertNotNull(inventory, "Inventory pointer cannot be NULL."); + + bool_t isFull = inventoryIsFull(inventory); + lua_pushboolean(L, isFull); + return 1; +} + +static int moduleInventoryItemFull(lua_State *L) { + assertNotNull(L, "Lua state cannot be NULL"); + + if(!lua_islightuserdata(L, 1)) { + luaL_error(L, "inventoryItemFull: Expected inventory pointer as first argument"); + return 0; + } + + if(!lua_isnumber(L, 2)) { + luaL_error(L, "inventoryItemFull: Expected item ID as second argument"); + return 0; + } + + inventory_t *inventory = (inventory_t *)lua_touserdata(L, 1); + itemid_t item = (itemid_t)lua_tonumber(L, 2); + + assertNotNull(inventory, "Inventory pointer cannot be NULL."); + + bool_t isFull = inventoryItemFull(inventory, item); + lua_pushboolean(L, isFull); + return 1; +} + +static int moduleInventorySort(lua_State *L) { + assertNotNull(L, "Lua state cannot be NULL"); + + if(!lua_islightuserdata(L, 1)) { + luaL_error(L, "inventorySort: Expected inventory pointer as first argument"); + return 0; + } + + if(!lua_isnumber(L, 2)) { + luaL_error(L, "inventorySort: Expected sort type as second argument"); + return 0; + } + + bool_t reverse = false; + if(lua_gettop(L) >= 3) { + if(!lua_isboolean(L, 3)) { + luaL_error(L, "inventorySort: Expected reverse flag as third argument"); + return 0; + } + reverse = (bool_t)lua_toboolean(L, 3); + } + + inventory_t *inventory = (inventory_t *)lua_touserdata(L, 1); + inventorysort_t sortBy = (inventorysort_t)lua_tonumber(L, 2); + + assertNotNull(inventory, "Inventory pointer cannot be NULL."); + inventorySort(inventory, sortBy, reverse); + return 0; +} + +static void moduleItem(lua_State *L) { + assertNotNull(L, "Lua state cannot be NULL"); + + luaL_dostring(L, ITEM_SCRIPT); + + lua_pushlightuserdata(L, &BACKPACK); + lua_setglobal(L, "BACKPACK"); + + lua_register(L, "inventoryItemExists", moduleInventoryItemExists); + lua_register(L, "inventoryAdd", moduleInventoryAdd); + lua_register(L, "inventorySet", moduleInventorySet); + lua_register(L, "inventoryRemove", moduleInventoryRemove); + lua_register(L, "inventoryGetCount", moduleInventoryGetCount); + lua_register(L, "inventoryIsFull", moduleInventoryIsFull); + lua_register(L, "inventoryItemFull", moduleInventoryItemFull); + lua_register(L, "inventorySort", moduleInventorySort); +} diff --git a/src/duskrpg/script/module/story/CMakeLists.txt b/src/duskrpg/script/module/story/CMakeLists.txt index 6496420c..84f36e34 100644 --- a/src/duskrpg/script/module/story/CMakeLists.txt +++ b/src/duskrpg/script/module/story/CMakeLists.txt @@ -3,8 +3,3 @@ # This software is released under the MIT License. # https://opensource.org/licenses/MIT -# Sources -target_sources(${DUSK_LIBRARY_TARGET_NAME} - PUBLIC - modulestoryflag.c -) \ No newline at end of file diff --git a/src/duskrpg/script/module/story/modulestoryflag.c b/src/duskrpg/script/module/story/modulestoryflag.c deleted file mode 100644 index c0dc6659..00000000 --- a/src/duskrpg/script/module/story/modulestoryflag.c +++ /dev/null @@ -1,109 +0,0 @@ -/** - * Copyright (c) 2025 Dominic Masters - * - * This software is released under the MIT License. - * https://opensource.org/licenses/MIT - */ - -#include "modulestoryflag.h" -#include "assert/assert.h" -#include "story/storyflag.h" - -void moduleStoryFlag(scriptcontext_t *context) { - assertNotNull(context, "Script context cannot be NULL"); - - lua_register(context->luaState, "storyFlagGet", moduleStoryFlagGet); - lua_register(context->luaState, "storyFlagSet", moduleStoryFlagSet); - lua_register( - context->luaState, "storyFlagIncrement", moduleStoryFlagIncrement - ); - lua_register( - context->luaState, "storyFlagDecrement", moduleStoryFlagDecrement - ); -} - -int moduleStoryFlagGet(lua_State *L) { - assertNotNull(L, "Lua state cannot be NULL"); - - // Require story flag ID argument - if(!lua_isnumber(L, 1)) { - luaL_error(L, "Expected flag ID."); - return 0; - } - - storyflag_t flag = (storyflag_t)lua_tonumber(L, 1); - if(flag <= STORY_FLAG_NULL || flag >= STORY_FLAG_COUNT) { - luaL_error(L, "Invalid flag ID %d", flag); - return 0; - } - - storyflagvalue_t value = storyFlagGet(flag); - lua_pushnumber(L, value); - return 1; -} - -int moduleStoryFlagSet(lua_State *L) { - assertNotNull(L, "Lua state cannot be NULL"); - - // Require story flag ID argument - if(!lua_isnumber(L, 1)) { - luaL_error(L, "Expected flag ID."); - return 0; - } - - // Require story flag value argument - if(!lua_isnumber(L, 2)) { - luaL_error(L, "Expected flag value."); - return 0; - } - - storyflag_t flag = (storyflag_t)lua_tonumber(L, 1); - if(flag <= STORY_FLAG_NULL || flag >= STORY_FLAG_COUNT) { - luaL_error(L, "Invalid flag ID %d", flag); - return 0; - } - - storyflagvalue_t value = (storyflagvalue_t)lua_tonumber(L, 2); - storyFlagSet(flag, value); - return 0; -} - -int moduleStoryFlagIncrement(lua_State *L) { - assertNotNull(L, "Lua state cannot be NULL"); - - // Require story flag ID argument - if(!lua_isnumber(L, 1)) { - luaL_error(L, "Expected flag ID."); - return 0; - } - - storyflag_t flag = (storyflag_t)lua_tonumber(L, 1); - if(flag <= STORY_FLAG_NULL || flag >= STORY_FLAG_COUNT) { - luaL_error(L, "Invalid flag ID %d", flag); - return 0; - } - - storyflagvalue_t value = storyFlagGet(flag); - storyFlagSet(flag, value + 1); - return 0; -} - -int moduleStoryFlagDecrement(lua_State *L) { - assertNotNull(L, "Lua state cannot be NULL"); - - // Require story flag ID argument - if(!lua_isnumber(L, 1)) { - luaL_error(L, "Expected flag ID."); - return 0; - } - - storyflag_t flag = (storyflag_t)lua_tonumber(L, 1); - if(flag <= STORY_FLAG_NULL || flag >= STORY_FLAG_COUNT) { - luaL_error(L, "Invalid flag ID %d", flag); - return 0; - } - - storyflagvalue_t value = storyFlagGet(flag); - storyFlagSet(flag, value - 1); - return 0; -} \ No newline at end of file diff --git a/src/duskrpg/script/module/story/modulestoryflag.h b/src/duskrpg/script/module/story/modulestoryflag.h index c398c3e3..9218a2b2 100644 --- a/src/duskrpg/script/module/story/modulestoryflag.h +++ b/src/duskrpg/script/module/story/modulestoryflag.h @@ -1,48 +1,101 @@ /** * Copyright (c) 2025 Dominic Masters - * + * * This software is released under the MIT License. * https://opensource.org/licenses/MIT */ #pragma once #include "script/scriptcontext.h" +#include "assert/assert.h" +#include "story/storyflag.h" -/** - * Register story flag module functions to the given script context. - * - * @param context The script context to register story flag module functions to. - */ -void moduleStoryFlag(scriptcontext_t *context); +static int moduleStoryFlagGet(lua_State *L) { + assertNotNull(L, "Lua state cannot be NULL"); -/** - * Script binding for getting the value of a story flag. - * - * @param L The Lua state. - * @return Number of return values on the Lua stack. - */ -int moduleStoryFlagGet(lua_State *L); + if(!lua_isnumber(L, 1)) { + luaL_error(L, "Expected flag ID."); + return 0; + } -/** - * Script binding for setting the value of a story flag. - * - * @param L The Lua state. - * @return Number of return values on the Lua stack. - */ -int moduleStoryFlagSet(lua_State *L); + storyflag_t flag = (storyflag_t)lua_tonumber(L, 1); + if(flag <= STORY_FLAG_NULL || flag >= STORY_FLAG_COUNT) { + luaL_error(L, "Invalid flag ID %d", flag); + return 0; + } -/** - * Script binding for incrementing a story flag. - * - * @param L The Lua state. - * @return Number of return values on the Lua stack. - */ -int moduleStoryFlagIncrement(lua_State *L); + storyflagvalue_t value = storyFlagGet(flag); + lua_pushnumber(L, value); + return 1; +} -/** - * Script binding for decrementing a story flag. - * - * @param L The Lua state. - * @return Number of return values on the Lua stack. - */ -int moduleStoryFlagDecrement(lua_State *L); \ No newline at end of file +static int moduleStoryFlagSet(lua_State *L) { + assertNotNull(L, "Lua state cannot be NULL"); + + if(!lua_isnumber(L, 1)) { + luaL_error(L, "Expected flag ID."); + return 0; + } + + if(!lua_isnumber(L, 2)) { + luaL_error(L, "Expected flag value."); + return 0; + } + + storyflag_t flag = (storyflag_t)lua_tonumber(L, 1); + if(flag <= STORY_FLAG_NULL || flag >= STORY_FLAG_COUNT) { + luaL_error(L, "Invalid flag ID %d", flag); + return 0; + } + + storyflagvalue_t value = (storyflagvalue_t)lua_tonumber(L, 2); + storyFlagSet(flag, value); + return 0; +} + +static int moduleStoryFlagIncrement(lua_State *L) { + assertNotNull(L, "Lua state cannot be NULL"); + + if(!lua_isnumber(L, 1)) { + luaL_error(L, "Expected flag ID."); + return 0; + } + + storyflag_t flag = (storyflag_t)lua_tonumber(L, 1); + if(flag <= STORY_FLAG_NULL || flag >= STORY_FLAG_COUNT) { + luaL_error(L, "Invalid flag ID %d", flag); + return 0; + } + + storyflagvalue_t value = storyFlagGet(flag); + storyFlagSet(flag, value + 1); + return 0; +} + +static int moduleStoryFlagDecrement(lua_State *L) { + assertNotNull(L, "Lua state cannot be NULL"); + + if(!lua_isnumber(L, 1)) { + luaL_error(L, "Expected flag ID."); + return 0; + } + + storyflag_t flag = (storyflag_t)lua_tonumber(L, 1); + if(flag <= STORY_FLAG_NULL || flag >= STORY_FLAG_COUNT) { + luaL_error(L, "Invalid flag ID %d", flag); + return 0; + } + + storyflagvalue_t value = storyFlagGet(flag); + storyFlagSet(flag, value - 1); + return 0; +} + +static void moduleStoryFlag(lua_State *L) { + assertNotNull(L, "Lua state cannot be NULL"); + + lua_register(L, "storyFlagGet", moduleStoryFlagGet); + lua_register(L, "storyFlagSet", moduleStoryFlagSet); + lua_register(L, "storyFlagIncrement", moduleStoryFlagIncrement); + lua_register(L, "storyFlagDecrement", moduleStoryFlagDecrement); +} diff --git a/src/duskrpg/script/scriptgame.h b/src/duskrpg/script/scriptgame.h index de516489..16094648 100644 --- a/src/duskrpg/script/scriptgame.h +++ b/src/duskrpg/script/scriptgame.h @@ -9,6 +9,6 @@ #include "script/module/item/moduleitem.h" #include "script/module/story/modulestoryflag.h" -#define SCRIPT_GAME_LIST \ - { .name = "item", .callback = moduleItem }, \ - { .name = "storyflag", .callback = moduleStoryFlag }, \ No newline at end of file +#define SCRIPT_GAME_INIT(L) \ + moduleItem(L); \ + moduleStoryFlag(L); \ No newline at end of file