Refactored and simplified lua stuff a lot.
Build Dusk / run-tests (push) Failing after 1m23s
Build Dusk / build-linux (push) Failing after 1m47s
Build Dusk / build-psp (push) Failing after 1m41s

This commit is contained in:
YourWishes committed 2026-02-01 21:28:21 -06:00
1 parent 78e1ae885a
commit 053778a502
53 files changed
+638 -804

No files matched your search

+1 -1
View File
@@ -45,5 +45,5 @@ int moduleMapLoad(lua_State *L) {
void moduleMapSystem(scriptcontext_t *context) { void moduleMapSystem(scriptcontext_t *context) {
assertNotNull(context, "Script context cannot be NULL"); assertNotNull(context, "Script context cannot be NULL");
scriptContextRegFunc(context, "mapLoad", moduleMapLoad); lua_register(context->luaState, "mapLoad", moduleMapLoad);
} }
+4 -4
View File
@@ -128,8 +128,8 @@ int scriptFuncEntitySetZ(lua_State *L) {
void scriptFuncEntity(scriptcontext_t *context) { void scriptFuncEntity(scriptcontext_t *context) {
assertNotNull(context, "Script context cannot be NULL"); assertNotNull(context, "Script context cannot be NULL");
scriptContextRegFunc(context, "entityAdd", scriptFuncEntityAdd); lua_register(context->luaState, "entityAdd", scriptFuncEntityAdd);
scriptContextRegFunc(context, "entitySetX", scriptFuncEntitySetX); lua_register(context->luaState, "entitySetX", scriptFuncEntitySetX);
scriptContextRegFunc(context, "entitySetY", scriptFuncEntitySetY); lua_register(context->luaState, "entitySetY", scriptFuncEntitySetY);
scriptContextRegFunc(context, "entitySetZ", scriptFuncEntitySetZ); lua_register(context->luaState, "entitySetZ", scriptFuncEntitySetZ);
} }
@@ -1,10 +1,17 @@
# Copyright (c) 2026 Dominic Masters # Copyright (c) 2025 Dominic Masters
# #
# This software is released under the MIT License. # This software is released under the MIT License.
# https://opensource.org/licenses/MIT # https://opensource.org/licenses/MIT
# Sources # Sources
target_sources(${DUSK_LIBRARY_TARGET_NAME} target_sources(${DUSK_LIBRARY_TARGET_NAME}
PUBLIC PUBLIC
scriptstruct.c ui.c
) uitext.c
uidebug.c
uiframe.c
uitextbox.c
)
# Subdirs
add_subdirectory(element)
File renamed without changes.
File renamed without changes.
+67
View File
@@ -0,0 +1,67 @@
/**
* Copyright (c) 2025 Dominic Masters
*
* This software is released under the MIT License.
* https://opensource.org/licenses/MIT
*/
#include "ui.h"
#include "assert/assert.h"
#include "ui/uidebug.h"
#include "util/memory.h"
#include "display/tileset/tileset_minogram.h"
#include "display/screen.h"
// #include "ui/uitextbox.h"
ui_t UI;
errorret_t uiInit(void) {
memoryZero(&UI, sizeof(ui_t));
cameraInitOrthographic(&UI.camera);
// Initialize UI components here
uiSetFont(&TILESET_MINOGRAM);
errorOk();
}
void uiUpdate(void) {
// Update UI state here
UI.camera.orthographic.left = 0;
UI.camera.orthographic.right = SCREEN.width;
UI.camera.orthographic.top = 0;
UI.camera.orthographic.bottom = SCREEN.height;
// uiTextboxUpdate();
}
void uiRender(void) {
cameraPushMatrix(&UI.camera);
// Render UI elements here
if(UI.fontTexture.width > 0) {
uiDebugRender(UI.fontTileset, &UI.fontTexture);
}
cameraPopMatrix();
}
errorret_t uiSetFont(const tileset_t *fontTileset) {
if(UI.fontTexture.width > 0) {
textureDispose(&UI.fontTexture);
UI.fontTexture.width = -1;
}
assertNotNull(fontTileset, "Font tileset cannot be NULL.");
UI.fontTileset = fontTileset;
errorChain(assetLoad(UI.fontTileset->image, &UI.fontTexture));
errorOk();
}
void uiDispose(void) {
if(UI.fontTexture.width > 0) {
textureDispose(&UI.fontTexture);
UI.fontTexture.width = -1;
}
}
+51
View File
@@ -0,0 +1,51 @@
/**
* Copyright (c) 2025 Dominic Masters
*
* This software is released under the MIT License.
* https://opensource.org/licenses/MIT
*/
#pragma once
#include "asset/asset.h"
#include "display/texture.h"
#include "display/tileset/tileset.h"
#include "display/camera/camera.h"
typedef struct {
camera_t camera;
texture_t fontTexture;
const tileset_t *fontTileset;
} ui_t;
extern ui_t UI;
/**
* Initializes the UI system, loading necessary resources.
*
* @return An errorret_t indicating success or failure.
*/
errorret_t uiInit(void);
/**
* Updates the UI state, handling user interactions and animations.
*/
void uiUpdate(void);
/**
* Renders the UI elements to the screen.
*/
void uiRender(void);
/**
* Sets the font tileset for UI text rendering.
*
* @param fontTileset Pointer to the tileset to use for UI fonts.
*
* @return An errorret_t indicating success or failure.
*/
errorret_t uiSetFont(const tileset_t *fontTileset);
/**
* Cleans up and frees all UI resources.
*/
void uiDispose(void);
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
View File
File renamed without changes.
View File
File renamed without changes.
+4 -8
View File
@@ -1,21 +1,17 @@
module('spritebatch') module('spritebatch')
module('time') -- module('time')
module('camera') module('camera')
module('glm') -- module('glm')
module('color') module('color')
camera = cameraCreate(CAMERA_PROJECTION_TYPE_PERSPECTIVE) camera = cameraCreate(CAMERA_PROJECTION_TYPE_PERSPECTIVE)
color = colorBlue()
function sceneDispose() function sceneDispose()
-- print('Disposing initial scene') -- print('Disposing initial scene')
end end
function sceneUpdate() function sceneUpdate()
color.r = 255 * (math.sin(TIME.time) + 1) * 0.5
color.g = 255 * (math.sin(TIME.time + 2) + 1) * 0.5
color.b = 255 * (math.sin(TIME.time + 4) + 1) * 0.5
end end
function sceneRender() function sceneRender()
@@ -25,7 +21,7 @@ function sceneRender()
nil, nil,
0, 0, 0, 0,
1, 2, 1, 2,
color colorBlue()
) )
spriteBatchFlush() spriteBatchFlush()
+2 -1
View File
@@ -3,4 +3,5 @@
# This software is released under the MIT License. # This software is released under the MIT License.
# https://opensource.org/licenses/MIT # https://opensource.org/licenses/MIT
add_asset(TILESET minogram.png type=PALETTIZED tileWidth=6 tileHeight=10 columns=16 rows=6)# Fixes PSP rendering add_asset(TILESET minogram.png type=PALETTIZED tileWidth=6 tileHeight=10 columns=16 rows=6)# Fixes PSP rendering
add_asset(SCRIPT test.lua)
+7 -4
View File
@@ -1,6 +1,9 @@
module('ui') module('spritebatch')
module('color')
function draw(x, y) function render(x, y, w, h)
uiDrawRect(COLOR_WHITE, x, y, 32, 32) spriteBatchPush(
nil,
x, y,
w, h
)
end end
-1
View File
@@ -65,5 +65,4 @@ add_subdirectory(script)
add_subdirectory(thread) add_subdirectory(thread)
add_subdirectory(time) add_subdirectory(time)
add_subdirectory(ui) add_subdirectory(ui)
add_subdirectory(ui2)
add_subdirectory(util) add_subdirectory(util)
+3 -2
View File
@@ -23,8 +23,6 @@ typedef enum {
} cameraviewtype_t; } cameraviewtype_t;
typedef struct { typedef struct {
cameraprojectiontype_t projType;
cameraviewtype_t viewType;
union { union {
mat4 view; mat4 view;
@@ -63,6 +61,9 @@ typedef struct {
float_t nearClip; float_t nearClip;
float_t farClip; float_t farClip;
cameraprojectiontype_t projType;
cameraviewtype_t viewType;
} camera_t; } camera_t;
/** /**
+5 -5
View File
@@ -8,7 +8,6 @@
#include "event.h" #include "event.h"
#include "assert/assert.h" #include "assert/assert.h"
#include "util/memory.h" #include "util/memory.h"
#include "script/struct/scriptstruct.h"
void eventInit( void eventInit(
event_t *event, event_t *event,
@@ -228,10 +227,11 @@ void eventInvoke(
lua_rawgeti(L, LUA_REGISTRYINDEX, listener->user.script.luaFunctionRef); lua_rawgeti(L, LUA_REGISTRYINDEX, listener->user.script.luaFunctionRef);
if(eventParams != NULL && metatableName != NULL) { if(eventParams != NULL && metatableName != NULL) {
scriptStructPushMetatable( lua_getmetatable(L, -1);
listener->user.script.context, luaL_getmetatable(L, metatableName);
metatableName, assertTrue(
(void *)eventParams lua_rawequal(L, -1, -2),
"Event parameter metatable does not match expected type"
); );
} }
+1 -2
View File
@@ -12,5 +12,4 @@ target_sources(${DUSK_LIBRARY_TARGET_NAME}
) )
# Subdirectories # Subdirectories
add_subdirectory(module) add_subdirectory(module)
add_subdirectory(struct)
+103 -127
View File
@@ -9,19 +9,20 @@
#include "assert/assert.h" #include "assert/assert.h"
#include "display/camera/camera.h" #include "display/camera/camera.h"
#include "util/memory.h" #include "util/memory.h"
#include "script/struct/scriptstruct.h"
#include "util/string.h" #include "util/string.h"
void moduleCamera(scriptcontext_t *context) { void moduleCamera(scriptcontext_t *context) {
assertNotNull(context, "Context cannot be NULL."); assertNotNull(context, "Context cannot be NULL.");
// Structure // Create metatable for camera structure.
scriptStructRegister( if(luaL_newmetatable(context->luaState, "camera_mt")) {
context, // Metatable methods
"camera_mt", lua_pushcfunction(context->luaState, moduleCameraIndex);
moduleCameraGetter, lua_setfield(context->luaState, -2, "__index");
moduleCameraSetter lua_pushcfunction(context->luaState, moduleCameraNewIndex);
); lua_setfield(context->luaState, -2, "__newindex");
lua_pop(context->luaState, 1);
}
// Definitions // Definitions
#define MODULE_CAMERA_SCRIPT_LEN 64 #define MODULE_CAMERA_SCRIPT_LEN 64
@@ -67,9 +68,9 @@ void moduleCamera(scriptcontext_t *context) {
); );
// Methods // Methods
scriptContextRegFunc(context, "cameraCreate", moduleCameraCreate); lua_register(context->luaState, "cameraCreate", moduleCameraCreate);
scriptContextRegFunc(context, "cameraPushMatrix", moduleCameraPushMatrix); lua_register(context->luaState, "cameraPushMatrix", moduleCameraPushMatrix);
scriptContextRegFunc(context, "cameraPopMatrix", moduleCameraPopMatrix); lua_register(context->luaState, "cameraPopMatrix", moduleCameraPopMatrix);
} }
int moduleCameraCreate(lua_State *L) { int moduleCameraCreate(lua_State *L) {
@@ -84,12 +85,13 @@ int moduleCameraCreate(lua_State *L) {
projType = (cameraprojectiontype_t)luaL_checkinteger(L, 1); projType = (cameraprojectiontype_t)luaL_checkinteger(L, 1);
} }
// Create camera. // Create camera that Lua will own
camera_t *cam = (camera_t *)lua_newuserdata(L, sizeof(camera_t)); camera_t *cam = (camera_t *)lua_newuserdata(L, sizeof(camera_t));
memoryZero(cam, sizeof(camera_t)); memoryZero(cam, sizeof(camera_t));
// Push metatable. // Set metatable
scriptStructPushMetatable(context, "camera_mt", cam); luaL_getmetatable(L, "camera_mt");
lua_setmetatable(L, -2);
// Init camera // Init camera
switch(projType) { switch(projType) {
@@ -114,9 +116,11 @@ int moduleCameraCreate(lua_State *L) {
int moduleCameraPushMatrix(lua_State *L) { int moduleCameraPushMatrix(lua_State *L) {
assertNotNull(L, "Lua state cannot be NULL."); assertNotNull(L, "Lua state cannot be NULL.");
assertTrue(lua_gettop(L) >= 1, "cameraPushMatrix requires 1 arg.");
assertTrue(lua_isuserdata(L, 1), "cameraPushMatrix arg must be userdata.");
// Camera should be provided (pointer to camera_t). // Camera should be provided (pointer to camera_t).
camera_t *cam = *(camera_t **)lua_touserdata(L, 1); camera_t *cam = (camera_t *)luaL_checkudata(L, 1, "camera_mt");
assertNotNull(cam, "Camera pointer cannot be NULL."); assertNotNull(cam, "Camera pointer cannot be NULL.");
cameraPushMatrix(cam); cameraPushMatrix(cam);
@@ -129,64 +133,51 @@ int moduleCameraPopMatrix(lua_State *L) {
return 0; return 0;
} }
void moduleCameraGetter( int moduleCameraIndex(lua_State *l) {
const scriptcontext_t *context, assertNotNull(l, "Lua state cannot be NULL.");
const char_t *key,
const void *structPtr,
scriptvalue_t *outValue
) {
assertNotNull(context, "Script context cannot be NULL.");
assertNotNull(key, "Key cannot be NULL.");
assertNotNull(structPtr, "Structure pointer cannot be NULL.");
assertNotNull(outValue, "Output value cannot be NULL.");
camera_t *cam = (camera_t *)structPtr; const char_t *key = luaL_checkstring(l, 2);
assertStrLenMin(key, 1, "Key cannot be empty.");
camera_t *cam = (camera_t *)luaL_checkudata(l, 1, "camera_mt");
assertNotNull(cam, "Camera pointer cannot be NULL.");
if(stringCompare(key, "near") == 0) { if(stringCompare(key, "near") == 0) {
outValue->type = SCRIPT_VALUE_TYPE_FLOAT; lua_pushnumber(l, cam->nearClip);
outValue->value.floatValue = cam->nearClip; return 1;
return;
} else if(stringCompare(key, "far") == 0) { } else if(stringCompare(key, "far") == 0) {
outValue->type = SCRIPT_VALUE_TYPE_FLOAT; lua_pushnumber(l, cam->farClip);
outValue->value.floatValue = cam->farClip; return 1;
return;
} else if(stringCompare(key, "nearClip") == 0) { } else if(stringCompare(key, "nearClip") == 0) {
outValue->type = SCRIPT_VALUE_TYPE_FLOAT; lua_pushnumber(l, cam->nearClip);
outValue->value.floatValue = cam->nearClip; return 1;
return;
} else if(stringCompare(key, "farClip") == 0) { } else if(stringCompare(key, "farClip") == 0) {
outValue->type = SCRIPT_VALUE_TYPE_FLOAT; lua_pushnumber(l, cam->farClip);
outValue->value.floatValue = cam->farClip; return 1;
return;
} }
// Perspective relative values // Perspective relative values
if(cam->projType == CAMERA_PROJECTION_TYPE_ORTHOGRAPHIC) { if(cam->projType == CAMERA_PROJECTION_TYPE_ORTHOGRAPHIC) {
if(stringCompare(key, "left") == 0) { if(stringCompare(key, "left") == 0) {
outValue->type = SCRIPT_VALUE_TYPE_FLOAT; lua_pushnumber(l, cam->orthographic.left);
outValue->value.floatValue = cam->orthographic.left; return 1;
return;
} else if(stringCompare(key, "right") == 0) { } else if(stringCompare(key, "right") == 0) {
outValue->type = SCRIPT_VALUE_TYPE_FLOAT; lua_pushnumber(l, cam->orthographic.right);
outValue->value.floatValue = cam->orthographic.right; return 1;
return;
} else if(stringCompare(key, "top") == 0) { } else if(stringCompare(key, "top") == 0) {
outValue->type = SCRIPT_VALUE_TYPE_FLOAT; lua_pushnumber(l, cam->orthographic.top);
outValue->value.floatValue = cam->orthographic.top; return 1;
return;
} else if(stringCompare(key, "bottom") == 0) { } else if(stringCompare(key, "bottom") == 0) {
outValue->type = SCRIPT_VALUE_TYPE_FLOAT; lua_pushnumber(l, cam->orthographic.bottom);
outValue->value.floatValue = cam->orthographic.bottom; return 1;
return;
} }
} else if( } else if(
cam->projType == CAMERA_PROJECTION_TYPE_PERSPECTIVE || cam->projType == CAMERA_PROJECTION_TYPE_PERSPECTIVE ||
cam->projType == CAMERA_PROJECTION_TYPE_PERSPECTIVE_FLIPPED cam->projType == CAMERA_PROJECTION_TYPE_PERSPECTIVE_FLIPPED
) { ) {
if(stringCompare(key, "fov") == 0) { if(stringCompare(key, "fov") == 0) {
outValue->type = SCRIPT_VALUE_TYPE_FLOAT; lua_pushnumber(l, cam->perspective.fov);
outValue->value.floatValue = cam->perspective.fov; return 1;
return;
} }
} }
@@ -194,107 +185,92 @@ void moduleCameraGetter(
if(cam->viewType == CAMERA_VIEW_TYPE_MATRIX) { if(cam->viewType == CAMERA_VIEW_TYPE_MATRIX) {
} else if(cam->viewType == CAMERA_VIEW_TYPE_LOOKAT) { } else if(cam->viewType == CAMERA_VIEW_TYPE_LOOKAT) {
if(stringCompare(key, "position") == 0) { // TODO: Push vec3
scriptStructPushMetatable(
context,
"vec3_mt",
(void*)&cam->lookat.position
);
outValue->type = SCRIPT_VALUE_TYPE_USERDATA;
return;
}
} else if(cam->viewType == CAMERA_VIEW_TYPE_LOOKAT_PIXEL_PERFECT) { } else if(cam->viewType == CAMERA_VIEW_TYPE_LOOKAT_PIXEL_PERFECT) {
} else if(cam->viewType == CAMERA_VIEW_TYPE_2D) { } else if(cam->viewType == CAMERA_VIEW_TYPE_2D) {
} }
lua_pushnil(l);
return 1;
} }
void moduleCameraSetter( int moduleCameraNewIndex(lua_State *l) {
const scriptcontext_t *context, assertNotNull(l, "Lua state cannot be NULL.");
const char_t *key,
void *structPtr, const char_t *key = luaL_checkstring(l, 2);
const scriptvalue_t *inValue assertStrLenMin(key, 1, "Key cannot be empty.");
) {
assertNotNull(context, "Script context cannot be NULL.");
assertNotNull(key, "Key cannot be NULL.");
assertNotNull(structPtr, "Structure pointer cannot be NULL.");
assertNotNull(inValue, "Input value cannot be NULL.");
camera_t *cam = (camera_t *)structPtr; camera_t *cam = (camera_t *)luaL_checkudata(l, 1, "camera_mt");
assertNotNull(cam, "Camera pointer cannot be NULL.");
if(stringCompare(key, "near") == 0) { if(stringCompare(key, "near") == 0 || stringCompare(key, "nearClip") == 0) {
if(inValue->type == SCRIPT_VALUE_TYPE_FLOAT) { if(!lua_isnumber(l, 3)) {
cam->nearClip = inValue->value.floatValue; luaL_error(l, "Camera near clip must be a number.");
} else if(inValue->type == SCRIPT_VALUE_TYPE_INT) {
cam->nearClip = (float_t)inValue->value.intValue;
} }
return; cam->nearClip = (float_t)lua_tonumber(l, 3);
} else if(stringCompare(key, "far") == 0) { return 0;
if(inValue->type == SCRIPT_VALUE_TYPE_FLOAT) { }
cam->farClip = inValue->value.floatValue;
} else if(inValue->type == SCRIPT_VALUE_TYPE_INT) { if(stringCompare(key, "far") == 0 || stringCompare(key, "farClip") == 0) {
cam->farClip = (float_t)inValue->value.intValue; if(!lua_isnumber(l, 3)) {
luaL_error(l, "Camera far clip must be a number.");
} }
return; cam->farClip = (float_t)lua_tonumber(l, 3);
} else if(stringCompare(key, "nearClip") == 0) { return 0;
if(inValue->type == SCRIPT_VALUE_TYPE_FLOAT) {
cam->nearClip = inValue->value.floatValue;
} else if(inValue->type == SCRIPT_VALUE_TYPE_INT) {
cam->nearClip = (float_t)inValue->value.intValue;
}
return;
} else if(stringCompare(key, "farClip") == 0) {
if(inValue->type == SCRIPT_VALUE_TYPE_FLOAT) {
cam->farClip = inValue->value.floatValue;
} else if(inValue->type == SCRIPT_VALUE_TYPE_INT) {
cam->farClip = (float_t)inValue->value.intValue;
}
return;
} }
// Perspective relative values // Perspective relative values
if(cam->projType == CAMERA_PROJECTION_TYPE_ORTHOGRAPHIC) { if(cam->projType == CAMERA_PROJECTION_TYPE_ORTHOGRAPHIC) {
if(stringCompare(key, "left") == 0) { if(stringCompare(key, "left") == 0) {
if(inValue->type == SCRIPT_VALUE_TYPE_FLOAT) { if(!lua_isnumber(l, 3)) {
cam->orthographic.left = inValue->value.floatValue; luaL_error(l, "Camera orthographic left must be a number.");
} else if(inValue->type == SCRIPT_VALUE_TYPE_INT) {
cam->orthographic.left = (float_t)inValue->value.intValue;
} }
return; cam->orthographic.left = (float_t)lua_tonumber(l, 3);
} else if(stringCompare(key, "right") == 0) { return 0;
if(inValue->type == SCRIPT_VALUE_TYPE_FLOAT) { }
cam->orthographic.right = inValue->value.floatValue;
} else if(inValue->type == SCRIPT_VALUE_TYPE_INT) { if(stringCompare(key, "right") == 0) {
cam->orthographic.right = (float_t)inValue->value.intValue; if(!lua_isnumber(l, 3)) {
luaL_error(l, "Camera orthographic right must be a number.");
} }
return; cam->orthographic.right = (float_t)lua_tonumber(l, 3);
} else if(stringCompare(key, "top") == 0) { return 0;
if(inValue->type == SCRIPT_VALUE_TYPE_FLOAT) { }
cam->orthographic.top = inValue->value.floatValue;
} else if(inValue->type == SCRIPT_VALUE_TYPE_INT) { if(stringCompare(key, "top") == 0) {
cam->orthographic.top = (float_t)inValue->value.intValue; if(!lua_isnumber(l, 3)) {
luaL_error(l, "Camera orthographic top must be a number.");
} }
return; cam->orthographic.top = (float_t)lua_tonumber(l, 3);
} else if(stringCompare(key, "bottom") == 0) { return 0;
if(inValue->type == SCRIPT_VALUE_TYPE_FLOAT) { }
cam->orthographic.bottom = inValue->value.floatValue;
} else if(inValue->type == SCRIPT_VALUE_TYPE_INT) { if(stringCompare(key, "bottom") == 0) {
cam->orthographic.bottom = (float_t)inValue->value.intValue; if(!lua_isnumber(l, 3)) {
luaL_error(l, "Camera orthographic bottom must be a number.");
} }
return; cam->orthographic.bottom = (float_t)lua_tonumber(l, 3);
return 0;
} }
} else if( } else if(
cam->projType == CAMERA_PROJECTION_TYPE_PERSPECTIVE || cam->projType == CAMERA_PROJECTION_TYPE_PERSPECTIVE ||
cam->projType == CAMERA_PROJECTION_TYPE_PERSPECTIVE_FLIPPED cam->projType == CAMERA_PROJECTION_TYPE_PERSPECTIVE_FLIPPED
) { ) {
if(stringCompare(key, "fov") == 0) { if(stringCompare(key, "fov") == 0) {
if(inValue->type == SCRIPT_VALUE_TYPE_FLOAT) { if(!lua_isnumber(l, 3)) {
cam->perspective.fov = inValue->value.floatValue; luaL_error(l, "Camera perspective FOV must be a number.");
} else if(inValue->type == SCRIPT_VALUE_TYPE_INT) {
cam->perspective.fov = (float_t)inValue->value.intValue;
} }
return; cam->perspective.fov = (float_t)lua_tonumber(l, 3);
return 0;
} }
} }
luaL_error(
l,
"Attempted to set unknown or read-only camera field '%s'.",
key
);
return 0;
} }
+5 -21
View File
@@ -42,29 +42,13 @@ int moduleCameraPopMatrix(lua_State *L);
/** /**
* Getter for camera structure fields. * Getter for camera structure fields.
* *
* @param context The script context. * @param l The Lua state.
* @param key The field key.
* @param structPtr Pointer to the camera structure.
* @param outValue Output script value.
*/ */
void moduleCameraGetter( int moduleCameraIndex(lua_State *l);
const scriptcontext_t *context,
const char_t *key,
const void *structPtr,
scriptvalue_t *outValue
);
/** /**
* Setter for camera structure fields. * Setter for camera structure fields.
* *
* @param context The script context. * @param l The Lua state.
* @param key The field key.
* @param structPtr Pointer to the camera structure.
* @param inValue Input script value.
*/ */
void moduleCameraSetter( int moduleCameraNewIndex(lua_State *l);
const scriptcontext_t *context,
const char_t *key,
void *structPtr,
const scriptvalue_t *inValue
);
+65 -64
View File
@@ -8,17 +8,25 @@
#include "modulecolor.h" #include "modulecolor.h"
#include "display/color.h" #include "display/color.h"
#include "assert/assert.h" #include "assert/assert.h"
#include "script/struct/scriptstruct.h"
#include "util/string.h" #include "util/string.h"
void moduleColor(scriptcontext_t *context) { void moduleColor(scriptcontext_t *context) {
assertNotNull(context, "Context cannot be NULL."); assertNotNull(context, "Context cannot be NULL.");
scriptStructRegister( if(luaL_newmetatable(context->luaState, "color_mt")) {
context, "color_mt", moduleColorGetter, moduleColorSetter // Metatable is new, set __index and __newindex
); lua_pushstring(context->luaState, "__index");
lua_pushcfunction(context->luaState, moduleColorIndex);
lua_settable(context->luaState, -3);
scriptContextRegFunc(context, "color", moduleColorFuncColor); lua_pushstring(context->luaState, "__newindex");
lua_pushcfunction(context->luaState, moduleColorNewIndex);
lua_settable(context->luaState, -3);
lua_pop(context->luaState, 1);
}
lua_register(context->luaState, "color", moduleColorFuncColor);
scriptContextExec(context, COLOR_SCRIPT); scriptContextExec(context, COLOR_SCRIPT);
} }
@@ -42,92 +50,85 @@ int moduleColorFuncColor(lua_State *L) {
colorchannel8_t b = (colorchannel8_t)lua_tonumber(L, 3); colorchannel8_t b = (colorchannel8_t)lua_tonumber(L, 3);
colorchannel8_t a = (colorchannel8_t)lua_tonumber(L, 4); colorchannel8_t a = (colorchannel8_t)lua_tonumber(L, 4);
// Create color_t as lua memory // Create color_t as lua memory, and push metatable
color_t *color = (color_t*)lua_newuserdata(L, sizeof(color_t)); 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->r = r;
color->g = g; color->g = g;
color->b = b; color->b = b;
color->a = a; color->a = a;
// Push color struct
scriptStructPushMetatable(context, "color_mt", color);
return 1; return 1;
} }
void moduleColorGetter( int moduleColorIndex(lua_State *L) {
const scriptcontext_t *context, assertNotNull(L, "Lua state cannot be NULL.");
const char_t *key,
const void *structPtr, const char_t *key = lua_tostring(L, 2);
scriptvalue_t *outValue assertStrLenMin(key, 1, "Key cannot be empty.");
) {
const color_t *color = (color_t*)structPtr; 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) { if(stringCompare(key, "r") == 0) {
outValue->type = SCRIPT_VALUE_TYPE_INT; lua_pushinteger(L, color->r);
outValue->value.intValue = color->r; return 1;
return;
} }
if(stringCompare(key, "g") == 0) { if(stringCompare(key, "g") == 0) {
outValue->type = SCRIPT_VALUE_TYPE_INT; lua_pushinteger(L, color->g);
outValue->value.intValue = color->g; return 1;
return;
} }
if(stringCompare(key, "b") == 0) { if(stringCompare(key, "b") == 0) {
outValue->type = SCRIPT_VALUE_TYPE_INT; lua_pushinteger(L, color->b);
outValue->value.intValue = color->b; return 1;
return;
} }
if(stringCompare(key, "a") == 0) { if(stringCompare(key, "a") == 0) {
outValue->type = SCRIPT_VALUE_TYPE_INT; lua_pushinteger(L, color->a);
outValue->value.intValue = color->a; return 1;
return;
} }
lua_pushnil(L);
return 1;
} }
void moduleColorSetter( int moduleColorNewIndex(lua_State *L) {
const scriptcontext_t *context, assertNotNull(L, "Lua state cannot be NULL.");
const char_t *key,
void *structPtr, const char_t *key = lua_tostring(L, 2);
const scriptvalue_t *inValue assertStrLenMin(key, 1, "Key cannot be empty.");
) {
color_t *color = (color_t*)structPtr; color_t *color = (color_t*)luaL_checkudata(L, 1, "color_mt");
assertNotNull(color, "Color struct cannot be NULL.");
if(stringCompare(key, "r") == 0) { if(stringCompare(key, "r") == 0) {
if(inValue->type == SCRIPT_VALUE_TYPE_INT) { if(!lua_isnumber(L, 3)) {
color->r = (colorchannel8_t)inValue->value.intValue; return luaL_error(L, "color channel r must be a number.");
} else if(inValue->type == SCRIPT_VALUE_TYPE_FLOAT) {
color->r = (colorchannel8_t)(inValue->value.floatValue);
} else {
assertUnreachable("Invalid type for color channel r");
} }
return; color->r = (colorchannel8_t)lua_tonumber(L, 3);
return 0;
} else if(stringCompare(key, "g") == 0) { } else if(stringCompare(key, "g") == 0) {
if(inValue->type == SCRIPT_VALUE_TYPE_INT) { if(!lua_isnumber(L, 3)) {
color->g = (colorchannel8_t)inValue->value.intValue; return luaL_error(L, "color channel g must be a number.");
} else if(inValue->type == SCRIPT_VALUE_TYPE_FLOAT) {
color->g = (colorchannel8_t)(inValue->value.floatValue);
} else {
assertUnreachable("Invalid type for color channel g");
} }
return; color->g = (colorchannel8_t)lua_tonumber(L, 3);
return 0;
} else if(stringCompare(key, "b") == 0) { } else if(stringCompare(key, "b") == 0) {
if(inValue->type == SCRIPT_VALUE_TYPE_INT) { if(!lua_isnumber(L, 3)) {
color->b = (colorchannel8_t)inValue->value.intValue; return luaL_error(L, "color channel b must be a number.");
} else if(inValue->type == SCRIPT_VALUE_TYPE_FLOAT) {
color->b = (colorchannel8_t)(inValue->value.floatValue);
} else {
assertUnreachable("Invalid type for color channel b");
} }
return; color->b = (colorchannel8_t)lua_tonumber(L, 3);
return 0;
} else if(stringCompare(key, "a") == 0) { } else if(stringCompare(key, "a") == 0) {
if(inValue->type == SCRIPT_VALUE_TYPE_INT) { if(!lua_isnumber(L, 3)) {
color->a = (colorchannel8_t)inValue->value.intValue; return luaL_error(L, "color channel a must be a number.");
} else if(inValue->type == SCRIPT_VALUE_TYPE_FLOAT) {
color->a = (colorchannel8_t)(inValue->value.floatValue);
} else {
assertUnreachable("Invalid type for color channel a");
} }
return; color->a = (colorchannel8_t)lua_tonumber(L, 3);
return 0;
} }
luaL_error(L, "Invalid color channel key.");
return 0;
} }
+8 -23
View File
@@ -24,31 +24,16 @@ void moduleColor(scriptcontext_t *context);
int moduleColorFuncColor(lua_State *L); int moduleColorFuncColor(lua_State *L);
/** /**
* Getter function for the color structure. * Index function for the color structure.
* * @param L The Lua state.
* @param context The script context. * @return Number of return values.
* @param key The key to get.
* @param structPtr Pointer to the color structure.
* @param outValue Output value.
*/ */
void moduleColorGetter( int moduleColorIndex(lua_State *L);
const scriptcontext_t *context,
const char_t *key,
const void *structPtr,
scriptvalue_t *outValue
);
/** /**
* Setter function for the color structure. * New index function for the color structure.
* *
* @param context The script context. * @param L The Lua state.
* @param key The key to set. * @return Number of return values.
* @param structPtr Pointer to the color structure.
* @param inValue Input value.
*/ */
void moduleColorSetter( int moduleColorNewIndex(lua_State *L);
const scriptcontext_t *context,
const char_t *key,
void *structPtr,
const scriptvalue_t *inValue
);
+32 -33
View File
@@ -7,46 +7,45 @@
#include "moduleglm.h" #include "moduleglm.h"
#include "assert/assert.h" #include "assert/assert.h"
#include "script/struct/scriptstruct.h"
#include "util/string.h" #include "util/string.h"
#include "util/memory.h" #include "util/memory.h"
void moduleGLM(scriptcontext_t *context) { void moduleGLM(scriptcontext_t *context) {
assertNotNull(context, "Context cannot be NULL."); assertNotNull(context, "Context cannot be NULL.");
scriptStructRegister( // scriptStructRegister(
context, // context,
"vec3_mt", // "vec3_mt",
moduleGLMVec3Getter, // moduleGLMVec3Getter,
NULL // NULL
); // );
} }
void moduleGLMVec3Getter( // void moduleGLMVec3Getter(
const scriptcontext_t *context, // const scriptcontext_t *context,
const char_t *key, // const char_t *key,
const void *structPtr, // const void *structPtr,
scriptvalue_t *outValue // scriptvalue_t *outValue
) { // ) {
assertNotNull(context, "Script context cannot be NULL."); // assertNotNull(context, "Script context cannot be NULL.");
assertNotNull(key, "Key cannot be NULL."); // assertNotNull(key, "Key cannot be NULL.");
assertNotNull(structPtr, "Structure pointer cannot be NULL."); // assertNotNull(structPtr, "Structure pointer cannot be NULL.");
assertNotNull(outValue, "Output value cannot be NULL."); // assertNotNull(outValue, "Output value cannot be NULL.");
printf("Getting vec3 field %s\n", key); // printf("Getting vec3 field %s\n", key);
vec3 *v = (vec3 *)structPtr; // vec3 *v = (vec3 *)structPtr;
if(stringCompare(key, "x") == 0) { // if(stringCompare(key, "x") == 0) {
outValue->type = SCRIPT_VALUE_TYPE_FLOAT; // outValue->type = SCRIPT_VALUE_TYPE_FLOAT;
outValue->value.floatValue = (*v)[0]; // outValue->value.floatValue = (*v)[0];
return; // return;
} else if(stringCompare(key, "y") == 0) { // } else if(stringCompare(key, "y") == 0) {
outValue->type = SCRIPT_VALUE_TYPE_FLOAT; // outValue->type = SCRIPT_VALUE_TYPE_FLOAT;
outValue->value.floatValue = (*v)[1]; // outValue->value.floatValue = (*v)[1];
return; // return;
} else if(stringCompare(key, "z") == 0) { // } else if(stringCompare(key, "z") == 0) {
outValue->type = SCRIPT_VALUE_TYPE_FLOAT; // outValue->type = SCRIPT_VALUE_TYPE_FLOAT;
outValue->value.floatValue = (*v)[2]; // outValue->value.floatValue = (*v)[2];
return; // return;
} // }
} // }
@@ -10,9 +10,9 @@
#include "assert/assert.h" #include "assert/assert.h"
void moduleSpriteBatch(scriptcontext_t *context) { void moduleSpriteBatch(scriptcontext_t *context) {
scriptContextRegFunc(context, "spriteBatchFlush", moduleSpriteBatchFlush); lua_register(context->luaState, "spriteBatchFlush", moduleSpriteBatchFlush);
scriptContextRegFunc(context, "spriteBatchClear", moduleSpriteBatchClear); lua_register(context->luaState, "spriteBatchClear", moduleSpriteBatchClear);
scriptContextRegFunc(context, "spriteBatchPush", moduleSpriteBatchPush); lua_register(context->luaState, "spriteBatchPush", moduleSpriteBatchPush);
} }
int moduleSpriteBatchFlush(lua_State *L) { int moduleSpriteBatchFlush(lua_State *L) {
@@ -47,11 +47,10 @@ int moduleSpriteBatchPush(lua_State *L) {
// Color (struct) or nil for white // Color (struct) or nil for white
color_t *color = NULL; color_t *color = NULL;
if(lua_isuserdata(L, 6)) { if(lua_gettop(L) < 6 || lua_isnil(L, 6)) {
color = *(color_t**)lua_touserdata(L, 6); // Allow NULL
assertNotNull(color, "Color struct cannot be NULL"); } else if(lua_isuserdata(L, 6)) {
} else if(lua_isnil(L, 6)) { color = (color_t*)luaL_checkudata(L, 6, "color_mt");
// Extrapolate later.
} else { } else {
return luaL_error(L, "Sprite color must be a color struct or nil"); return luaL_error(L, "Sprite color must be a color struct or nil");
} }
+1 -1
View File
@@ -41,5 +41,5 @@ int moduleEventSubscribe(lua_State *L) {
void moduleEvent(scriptcontext_t *context) { void moduleEvent(scriptcontext_t *context) {
// Reg functions // Reg functions
scriptContextRegFunc(context, "eventSubscribe", moduleEventSubscribe); lua_register(context->luaState, "eventSubscribe", moduleEventSubscribe);
} }
+25 -14
View File
@@ -9,7 +9,6 @@
#include "input/input.h" #include "input/input.h"
#include "assert/assert.h" #include "assert/assert.h"
#include "util/string.h" #include "util/string.h"
#include "script/struct/scriptstruct.h"
void moduleInput(scriptcontext_t *context) { void moduleInput(scriptcontext_t *context) {
assertNotNull(context, "Script context cannot be NULL"); assertNotNull(context, "Script context cannot be NULL");
@@ -37,27 +36,39 @@ void moduleInput(scriptcontext_t *context) {
); );
// Script structure // Script structure
scriptStructRegister(context, "input_mt", &moduleInputEventGetter, NULL); if(luaL_newmetatable(context->luaState, "input_mt")) {
// Metatable methods
lua_pushcfunction(context->luaState, moduleInputIndex);
lua_setfield(context->luaState, -2, "__index");
}
// Events // Events
scriptContextRegPointer(context,"INPUT_EVENT_PRESSED",&INPUT.eventPressed); lua_pushlightuserdata(context->luaState, &INPUT.eventPressed);
scriptContextRegPointer(context,"INPUT_EVENT_RELEASED",&INPUT.eventReleased); lua_setglobal(context->luaState, "INPUT_EVENT_PRESSED");
lua_pushlightuserdata(context->luaState, &INPUT.eventReleased);
lua_setglobal(context->luaState, "INPUT_EVENT_RELEASED");
// Bind methods // Bind methods
scriptContextRegFunc(context, "inputBind", moduleInputBind); lua_register(context->luaState, "inputBind", moduleInputBind);
} }
void moduleInputEventGetter( int moduleInputIndex(lua_State *l) {
const scriptcontext_t *context, assertNotNull(l, "Lua state cannot be NULL");
const char_t *key,
const void *structPtr, const char_t *key = luaL_checkstring(l, 2);
scriptvalue_t *outValue assertStrLenMin(key, 1, "Key cannot be empty.");
) {
if(stringCompare(key, "action") == 0) { if(stringCompare(key, "action") == 0) {
outValue->type = SCRIPT_VALUE_TYPE_INT; lua_pushinteger(
outValue->value.intValue = ((const inputevent_t*)structPtr)->action; l,
return; ((const inputevent_t*)lua_touserdata(l, 1))->action
);
return 1;
} }
return 0;
} }
int moduleInputBind(lua_State *L) { int moduleInputBind(lua_State *L) {
+3 -11
View File
@@ -16,19 +16,11 @@
void moduleInput(scriptcontext_t *context); void moduleInput(scriptcontext_t *context);
/** /**
* Script event getter for input events. * Getter for input structure fields.
* *
* @param context The script context. * @param l The Lua state.
* @param key The key to get.
* @param structPtr Pointer to the input event struct.
* @param outValue Output script value.
*/ */
void moduleInputEventGetter( int moduleInputIndex(lua_State *l);
const scriptcontext_t *context,
const char_t *key,
const void *structPtr,
scriptvalue_t *outValue
);
/** /**
* Script binding for binding an input button to an action. * Script binding for binding an input button to an action.
+11 -10
View File
@@ -17,19 +17,20 @@ void moduleItem(scriptcontext_t *context) {
scriptContextExec(context, ITEM_SCRIPT); scriptContextExec(context, ITEM_SCRIPT);
// Bind BACKPACK const pointer // Bind BACKPACK const pointer
scriptContextRegPointer(context, "BACKPACK", (void *)&BACKPACK); lua_pushlightuserdata(context->luaState, &BACKPACK);
lua_setglobal(context->luaState, "BACKPACK");
// Bind Methods // Bind Methods
scriptContextRegFunc( lua_register(
context, "inventoryItemExists", moduleInventoryItemExists context->luaState, "inventoryItemExists", moduleInventoryItemExists
); );
scriptContextRegFunc(context, "inventoryAdd", moduleInventoryAdd); lua_register(context->luaState, "inventoryAdd", moduleInventoryAdd);
scriptContextRegFunc(context, "inventorySet", moduleInventorySet); lua_register(context->luaState, "inventorySet", moduleInventorySet);
scriptContextRegFunc(context, "inventoryRemove", moduleInventoryRemove); lua_register(context->luaState, "inventoryRemove", moduleInventoryRemove);
scriptContextRegFunc(context, "inventoryGetCount", moduleInventoryGetCount); lua_register(context->luaState, "inventoryGetCount", moduleInventoryGetCount);
scriptContextRegFunc(context, "inventoryIsFull", moduleInventoryIsFull); lua_register(context->luaState, "inventoryIsFull", moduleInventoryIsFull);
scriptContextRegFunc(context, "inventoryItemFull", moduleInventoryItemFull); lua_register(context->luaState, "inventoryItemFull", moduleInventoryItemFull);
scriptContextRegFunc(context, "inventorySort", moduleInventorySort); lua_register(context->luaState, "inventorySort", moduleInventorySort);
} }
int moduleInventoryItemExists(lua_State *L) { int moduleInventoryItemExists(lua_State *L) {
+3 -3
View File
@@ -15,9 +15,9 @@ void moduleLocale(scriptcontext_t *context) {
// Execute the locale script definitions. // Execute the locale script definitions.
scriptContextExec(context, LOCALE_SCRIPT); scriptContextExec(context, LOCALE_SCRIPT);
scriptContextRegFunc(context, "localeGet", moduleLocaleGet); lua_register(context->luaState, "localeGet", moduleLocaleGet);
scriptContextRegFunc(context, "localeSet", moduleLocaleSet); lua_register(context->luaState, "localeSet", moduleLocaleSet);
scriptContextRegFunc(context, "localeGetName", moduleLocaleGetName); lua_register(context->luaState, "localeGetName", moduleLocaleGetName);
} }
int moduleLocaleGet(lua_State *L) { int moduleLocaleGet(lua_State *L) {
+1 -1
View File
@@ -12,7 +12,7 @@
void moduleScene(scriptcontext_t *ctx) { void moduleScene(scriptcontext_t *ctx) {
assertNotNull(ctx, "Script context cannot be NULL"); assertNotNull(ctx, "Script context cannot be NULL");
scriptContextRegFunc(ctx, "sceneSet", moduleSceneSet); lua_register(ctx->luaState, "sceneSet", moduleSceneSet);
} }
int moduleSceneSet(lua_State *L) { int moduleSceneSet(lua_State *L) {
+3 -3
View File
@@ -14,9 +14,9 @@
void moduleSystem(scriptcontext_t *context) { void moduleSystem(scriptcontext_t *context) {
assertNotNull(context, "Script context cannot be NULL"); assertNotNull(context, "Script context cannot be NULL");
scriptContextRegFunc(context, "print", moduleSysPrint); lua_register(context->luaState, "print", moduleSysPrint);
scriptContextRegFunc(context, "include", moduleSysInclude); lua_register(context->luaState, "include", moduleSysInclude);
scriptContextRegFunc(context, "module", moduleSysModule); lua_register(context->luaState, "module", moduleSysModule);
} }
int moduleSysPrint(lua_State *L) { int moduleSysPrint(lua_State *L) {
+16 -17
View File
@@ -7,31 +7,30 @@
#include "moduletime.h" #include "moduletime.h"
#include "assert/assert.h" #include "assert/assert.h"
#include "script/struct/scriptstruct.h"
void moduleTime(scriptcontext_t *ctx) { void moduleTime(scriptcontext_t *ctx) {
assertNotNull(ctx, "Script context cannot be NULL"); assertNotNull(ctx, "Script context cannot be NULL");
// Script structure // Script structure
scriptStructRegister(ctx, "time_mt", moduleTimeGetter, NULL); if(luaL_newmetatable(ctx->luaState, "time_mt")) {
// Metatable is new, set __index
// Register struct lua_pushstring(ctx->luaState, "__index");
scriptStructPush(ctx, "time_mt", "TIME", &TIME); lua_pushcfunction(ctx->luaState, moduleTimeIndex);
lua_settable(ctx->luaState, -3);
}
} }
void moduleTimeGetter( int moduleTimeIndex(lua_State *L) {
const scriptcontext_t *context, assertNotNull(L, "Lua state cannot be NULL.");
const char_t *key,
const void *structPtr, const char_t *key = lua_tostring(L, 2);
scriptvalue_t *outValue assertStrLenMin(key, 1, "Key cannot be empty.");
) {
if(stringCompare(key, "delta") == 0) { if(stringCompare(key, "delta") == 0) {
outValue->type = SCRIPT_VALUE_TYPE_FLOAT; lua_pushnumber(L, TIME.delta);
outValue->value.floatValue = TIME.delta; return 1;
return;
} else if(stringCompare(key, "time") == 0) { } else if(stringCompare(key, "time") == 0) {
outValue->type = SCRIPT_VALUE_TYPE_FLOAT; lua_pushnumber(L, TIME.time);
outValue->value.floatValue = TIME.time; return 1;
return;
} }
} }
+4 -12
View File
@@ -18,16 +18,8 @@
void moduleTime(scriptcontext_t *ctx); void moduleTime(scriptcontext_t *ctx);
/** /**
* Getter function for the TIME struct in scripts. * Index function for the time structure.
* * @param L The Lua state.
* @param context The script context. * @return Number of return values.
* @param key The key being accessed.
* @param structPtr Pointer to the struct instance.
* @param outValue Output parameter to store the retrieved value.
*/ */
void moduleTimeGetter( int moduleTimeIndex(lua_State *L);
const scriptcontext_t *context,
const char_t *key,
const void *structPtr,
scriptvalue_t *outValue
);
+22 -1
View File
@@ -7,9 +7,30 @@
#include "moduleui.h" #include "moduleui.h"
#include "assert/assert.h" #include "assert/assert.h"
#include "ui/ui.h"
void moduleUi(scriptcontext_t *ctx) { void moduleUi(scriptcontext_t *ctx) {
assertNotNull(ctx, "Script context cannot be NULL"); assertNotNull(ctx, "Script context cannot be NULL");
lua_register(ctx->luaState, "uiPush", moduleUiPush);
}
int moduleUiPush(lua_State *L) {
assertNotNull(L, "Lua state cannot be NULL");
// Expect path string. TODO Support non scripted ui elements.
if(!lua_isstring(L, 1)) {
return luaL_error(L, "uiPush expects a string path as the first argument");
}
const char_t *path = lua_tostring(L, 1);
printf("Pushing UI from script: %s\n", path);
errorret_t err = uiPushScript(path);
if(err.code != ERROR_OK) {
errorCatch(errorPrint(err));
return luaL_error(L, "uiPush failed for path: %s", path);
}
return 0;
} }
+11 -1
View File
@@ -13,4 +13,14 @@
* *
* @param ctx The script context to register the module in. * @param ctx The script context to register the module in.
*/ */
void moduleUi(scriptcontext_t *ctx); void moduleUi(scriptcontext_t *ctx);
/**
* Lua binding for uiPush function.
*
* Expects a string path to the UI script as the first argument.
*
* @param L The Lua state.
* @return Number of return values on the Lua stack.
*/
int moduleUiPush(lua_State *L);
-25
View File
@@ -38,31 +38,6 @@ errorret_t scriptContextInit(scriptcontext_t *context) {
errorOk(); errorOk();
} }
void scriptContextRegFunc(
scriptcontext_t *context,
const char_t *fnName,
lua_CFunction function
) {
assertNotNull(context, "Script context cannot be NULL");
assertNotNull(fnName, "Function name cannot be NULL");
assertNotNull(function, "Function cannot be NULL");
lua_register(context->luaState, fnName, function);
}
void scriptContextRegPointer(
scriptcontext_t *context,
const char_t *name,
void *pointer
) {
assertNotNull(context, "Script context cannot be NULL");
assertNotNull(name, "Name cannot be NULL");
assertNotNull(pointer, "Pointer cannot be NULL");
lua_pushlightuserdata(context->luaState, pointer);
lua_setglobal(context->luaState, name);
}
errorret_t scriptContextCallFunc( errorret_t scriptContextCallFunc(
scriptcontext_t *context, scriptcontext_t *context,
const char_t *fnName, const char_t *fnName,
-26
View File
@@ -29,32 +29,6 @@ typedef struct scriptcontext_s {
*/ */
errorret_t scriptContextInit(scriptcontext_t *context); errorret_t scriptContextInit(scriptcontext_t *context);
/**
* Register a C function within a script context.
*
* @param context The script context to use.
* @param fnName The name of the function in Lua.
* @param function The C function to register.
*/
void scriptContextRegFunc(
scriptcontext_t *context,
const char_t *fnName,
lua_CFunction function
);
/**
* Register a pointer within a script context.
*
* @param context The script context to use.
* @param name The name of the pointer in Lua.
* @param pointer The pointer to register.
*/
void scriptContextRegPointer(
scriptcontext_t *context,
const char_t *name,
void *pointer
);
/** /**
* Call a Lua function within a script context. * Call a Lua function within a script context.
* *
-191
View File
@@ -1,191 +0,0 @@
/**
* Copyright (c) 2026 Dominic Masters
*
* This software is released under the MIT License.
* https://opensource.org/licenses/MIT
*/
#include "scriptstruct.h"
#include "assert/assert.h"
#include "util/memory.h"
void scriptStructRegister(
scriptcontext_t *context,
const char_t *metatableName,
const scriptstructgetter_t getter,
const scriptstructsetter_t setter
) {
assertNotNull(context, "Script context cannot be NULL");
assertNotNull(metatableName, "Metatable name cannot be NULL");
// Create metatable
if(!luaL_newmetatable(context->luaState, metatableName)) return;
// Create a Lua owned structure for holding the metatable context.
structmetatablecontext_t *metaContext = lua_newuserdata(
context->luaState,
sizeof(structmetatablecontext_t)
);
metaContext->context = context;
metaContext->getter = getter;
metaContext->setter = setter;
// Store in the metatable.
lua_setfield(context->luaState, -2, "__structmetatablecontext");
// Set __index and __newindex metamethods for Lua.
lua_pushcfunction(context->luaState, scriptStructIndex);
lua_setfield(context->luaState, -2, "__index");
lua_pushcfunction(context->luaState, scriptStructNewIndex);
lua_setfield(context->luaState, -2, "__newindex");
}
int scriptStructIndex(lua_State *l) {
structmetatablecontext_t *ctx = scriptStructGetMetatableContext(l);
if(!ctx->getter) {
luaL_error(l, "Attempt to read from write-only structure field");
return 0;
}
const char_t *key = lua_tostring(l, 2);
void *structPtr = *(void **)lua_touserdata(l, 1);
assertNotNull(structPtr, "Structure pointer cannot be NULL");
scriptvalue_t outValue = { .type = SCRIPT_VALUE_TYPE_NIL };
ctx->getter(ctx->context, key, structPtr, &outValue);
switch(outValue.type) {
case SCRIPT_VALUE_TYPE_INT:
lua_pushinteger(l, outValue.value.intValue);
break;
case SCRIPT_VALUE_TYPE_FLOAT:
lua_pushnumber(l, outValue.value.floatValue);
break;
case SCRIPT_VALUE_TYPE_STRING:
assertNotNull(outValue.value.strValue, "String value cannot be NULL");
lua_pushstring(l, outValue.value.strValue);
memoryFree((void *)outValue.value.strValue);
break;
case SCRIPT_VALUE_TYPE_BOOL:
lua_pushboolean(l, outValue.value.boolValue);
break;
case SCRIPT_VALUE_TYPE_NIL:
lua_pushnil(l);
break;
case SCRIPT_VALUE_TYPE_USERDATA:
break;
default:
assertUnreachable("Unsupported value type for struct field retrieval");
break;
}
return 1;
}
int scriptStructNewIndex(lua_State *l) {
structmetatablecontext_t *ctx = scriptStructGetMetatableContext(l);
if(ctx->setter == NULL) {
luaL_error(l, "Attempt to set read-only structure field");
return 0;
}
const char_t *key = lua_tostring(l, 2);
void *structPtr = *(void **)lua_touserdata(l, 1);
assertNotNull(structPtr, "Structure pointer cannot be NULL");
scriptvalue_t inValue;
int t = lua_type(l, 3);
switch(t) {
case LUA_TNUMBER:
if(lua_isinteger(l, 3)) {
inValue.type = SCRIPT_VALUE_TYPE_INT;
inValue.value.intValue = (int32_t)lua_tointeger(l, 3);
} else {
inValue.type = SCRIPT_VALUE_TYPE_FLOAT;
inValue.value.floatValue = (float)lua_tonumber(l, 3);
}
break;
case LUA_TSTRING:
inValue.type = SCRIPT_VALUE_TYPE_STRING;
inValue.value.strValue = lua_tostring(l, 3);
break;
case LUA_TBOOLEAN:
inValue.type = SCRIPT_VALUE_TYPE_BOOL;
inValue.value.boolValue = lua_toboolean(l, 3);
break;
case LUA_TNIL:
inValue.type = SCRIPT_VALUE_TYPE_NIL;
break;
default:
assertUnreachable("Unsupported value type for struct field assignment");
break;
}
ctx->setter(ctx->context, key, structPtr, &inValue);
lua_pushnil(l);
return 1;
}
structmetatablecontext_t * scriptStructGetMetatableContext(lua_State *L) {
assertNotNull(L, "Lua state cannot be NULL");
if(!lua_getmetatable(L, 1)) {
assertUnreachable("Expected metatable on structure");
}
lua_getfield(L, -1, "__structmetatablecontext");
structmetatablecontext_t *metaContext = (
(structmetatablecontext_t *)lua_touserdata(L, -1)
);
assertNotNull(metaContext, "Metatable context userdata cannot be NULL");
lua_pop(L, 2);
return metaContext;
}
void scriptStructPushMetatable(
const scriptcontext_t *context,
const char_t *metatableName,
void *structPtr
) {
assertNotNull(context, "Script context cannot be NULL");
assertNotNull(metatableName, "Metatable name cannot be NULL");
assertNotNull(structPtr, "Structure pointer cannot be NULL");
// Create userdata
void **ud = (void **)lua_newuserdata(context->luaState, sizeof(void *));
*ud = structPtr;
// Set metatable
luaL_getmetatable(context->luaState, metatableName);
lua_setmetatable(context->luaState, -2);
}
void scriptStructPush(
scriptcontext_t *context,
const char_t *metatableName,
const char_t *variableName,
void *structPtr
) {
assertNotNull(context, "Script context cannot be NULL");
assertNotNull(metatableName, "Metatable name cannot be NULL");
assertNotNull(variableName, "Variable name cannot be NULL");
assertNotNull(structPtr, "Structure pointer cannot be NULL");
scriptStructPushMetatable(context, metatableName, structPtr);
lua_setglobal(context->luaState, variableName);
}
-86
View File
@@ -1,86 +0,0 @@
/**
* Copyright (c) 2026 Dominic Masters
*
* This software is released under the MIT License.
* https://opensource.org/licenses/MIT
*/
#pragma once
#include "scriptstructgetter.h"
#include "scriptstructsetter.h"
typedef struct {
scriptcontext_t *context;
scriptstructgetter_t getter;
scriptstructsetter_t setter;
} structmetatablecontext_t;
/**
* Registers a script structure to allow a script to access its fields. You will
* be creating a new metatable in Lua with the given name, so Ideally use a name
* like Ideally struct_mt e.g. player_t or entity_t.
*
* @param context The script context.
* @param metatableName The name of the metatable to register
* @param getter The getter function for retrieving field values.
* @param setter The setter function for setting field values.
*/
void scriptStructRegister(
scriptcontext_t *context,
const char_t *metatableName,
const scriptstructgetter_t getter,
const scriptstructsetter_t setter
);
/**
* Callback received from Lua to index (get) a structure field.
*
* @param l The Lua state.
* @return The number of return values.
*/
int scriptStructIndex(lua_State *l);
/**
* Callback received from Lua to newindex (set) a structure field.
*
* @param l The Lua state.
* @return The number of return values.
*/
int scriptStructNewIndex(lua_State *l);
/**
* Pops the metatable context from the given Lua state. This is only valid from
* within the index or newindex methods.
*
* @param l The Lua state.
* @return The metatable context.
*/
structmetatablecontext_t *scriptStructGetMetatableContext(lua_State *l);
/**
* Pushes a structure metatable onto the Lua stack.
*
* @param context The script context.
* @param metatableName The name of the metatable to associate with.
* @param structPtr Pointer to the structure to push.
*/
void scriptStructPushMetatable(
const scriptcontext_t *context,
const char_t *metatableName,
void *structPtr
);
/**
* Pushes a structure onto the Lua stack and assigns it to a global variable.
*
* @param context The script context.
* @param metatableName The name of the metatable to associate with.
* @param variableName The name of the global variable to assign to.
* @param structPtr Pointer to the structure to push.
*/
void scriptStructPush(
scriptcontext_t *context,
const char_t *metatableName,
const char_t *variableName,
void *structPtr
);
-16
View File
@@ -1,16 +0,0 @@
/**
* Copyright (c) 2026 Dominic Masters
*
* This software is released under the MIT License.
* https://opensource.org/licenses/MIT
*/
#pragma once
#include "script/scriptcontext.h"
typedef void (*scriptstructgetter_t)(
const scriptcontext_t *context,
const char_t *key,
const void *structPtr,
scriptvalue_t *outValue
);
-16
View File
@@ -1,16 +0,0 @@
/**
* Copyright (c) 2026 Dominic Masters
*
* This software is released under the MIT License.
* https://opensource.org/licenses/MIT
*/
#pragma once
#include "script/scriptcontext.h"
typedef void (*scriptstructsetter_t)(
const scriptcontext_t *context,
const char_t *key,
void *structPtr,
const scriptvalue_t *inValue
);
+4 -10
View File
@@ -1,5 +1,5 @@
# Copyright (c) 2025 Dominic Masters # Copyright (c) 2026 Dominic Masters
# #
# This software is released under the MIT License. # This software is released under the MIT License.
# https://opensource.org/licenses/MIT # https://opensource.org/licenses/MIT
@@ -7,11 +7,5 @@
target_sources(${DUSK_LIBRARY_TARGET_NAME} target_sources(${DUSK_LIBRARY_TARGET_NAME}
PUBLIC PUBLIC
ui.c ui.c
uitext.c uielement.c
uidebug.c )
uiframe.c
uitextbox.c
)
# Subdirs
add_subdirectory(element)
+36 -35
View File
@@ -1,67 +1,68 @@
/** /**
* Copyright (c) 2025 Dominic Masters * Copyright (c) 2026 Dominic Masters
* *
* This software is released under the MIT License. * This software is released under the MIT License.
* https://opensource.org/licenses/MIT * https://opensource.org/licenses/MIT
*/ */
#include "ui.h" #include "ui.h"
#include "assert/assert.h"
#include "ui/uidebug.h"
#include "util/memory.h" #include "util/memory.h"
#include "display/tileset/tileset_minogram.h" #include "assert/assert.h"
#include "display/screen.h" #include "display/spritebatch.h"
// #include "ui/uitextbox.h"
ui_t UI; ui_t UI;
errorret_t uiInit(void) { errorret_t uiInit(void) {
memoryZero(&UI, sizeof(ui_t)); memoryZero(&UI, sizeof(ui_t));
cameraInitOrthographic(&UI.camera); cameraInitOrthographic(&UI.camera);
// Initialize UI components here
uiSetFont(&TILESET_MINOGRAM);
errorOk(); errorOk();
} }
void uiUpdate(void) { void uiUpdate(void) {
// Update UI state here uint_fast8_t i = 0;
UI.camera.orthographic.left = 0; while(i < UI.stackSize) {
UI.camera.orthographic.right = SCREEN.width; errorCatch(errorPrint(uiElementUpdate(&UI.stack[i])));
UI.camera.orthographic.top = 0; i++;
UI.camera.orthographic.bottom = SCREEN.height; }
// uiTextboxUpdate();
} }
void uiRender(void) { void uiRender(void) {
cameraPushMatrix(&UI.camera); cameraPushMatrix(&UI.camera);
spriteBatchClear();
// Render UI elements here
if(UI.fontTexture.width > 0) { uint_fast8_t i = 0;
uiDebugRender(UI.fontTileset, &UI.fontTexture); while(i < UI.stackSize) {
errorCatch(errorPrint(uiElementRender(&UI.stack[i])));
i++;
} }
// spriteBatchPush(
// NULL,
// 0, 0, 32, 32, COLOR_RED, 0, 0, 1, 1
// );
spriteBatchFlush();
cameraPopMatrix(); cameraPopMatrix();
} }
errorret_t uiSetFont(const tileset_t *fontTileset) { errorret_t uiPushScript(const char_t *path) {
if(UI.fontTexture.width > 0) { assertTrue(UI.stackSize < UI_STACK_SIZE, "UI stack overflow");
textureDispose(&UI.fontTexture); uielement_t *element = &UI.stack[UI.stackSize];
UI.fontTexture.width = -1; errorChain(uiElementInitScript(element, path));
} UI.stackSize++;
// Ret Id or something?
assertNotNull(fontTileset, "Font tileset cannot be NULL.");
UI.fontTileset = fontTileset;
errorChain(assetLoad(UI.fontTileset->image, &UI.fontTexture));
errorOk(); errorOk();
} }
void uiPop(void) {
assertTrue(UI.stackSize > 0, "UI stack underflow");
UI.stackSize--;
uielement_t *element = &UI.stack[UI.stackSize];
uiElementDispose(element);
}
void uiDispose(void) { void uiDispose(void) {
if(UI.fontTexture.width > 0) { while(UI.stackSize > 0) {
textureDispose(&UI.fontTexture); uiPop();
UI.fontTexture.width = -1;
} }
} }
+19 -17
View File
@@ -1,51 +1,53 @@
/** /**
* Copyright (c) 2025 Dominic Masters * Copyright (c) 2026 Dominic Masters
* *
* This software is released under the MIT License. * This software is released under the MIT License.
* https://opensource.org/licenses/MIT * https://opensource.org/licenses/MIT
*/ */
#pragma once #pragma once
#include "asset/asset.h"
#include "display/texture.h"
#include "display/tileset/tileset.h"
#include "display/camera/camera.h" #include "display/camera/camera.h"
#include "ui/uielement.h"
#define UI_STACK_SIZE 64
typedef struct { typedef struct {
camera_t camera; camera_t camera;
texture_t fontTexture;
const tileset_t *fontTileset; uielement_t stack[UI_STACK_SIZE];
uint_fast8_t stackSize;
} ui_t; } ui_t;
extern ui_t UI; extern ui_t UI;
/** /**
* Initializes the UI system, loading necessary resources. * Initializes the UI system.
*
* @return An errorret_t indicating success or failure.
*/ */
errorret_t uiInit(void); errorret_t uiInit(void);
/** /**
* Updates the UI state, handling user interactions and animations. * Updates the UI system.
*/ */
void uiUpdate(void); void uiUpdate(void);
/** /**
* Renders the UI elements to the screen. * Renders the UI system.
*/ */
void uiRender(void); void uiRender(void);
/** /**
* Sets the font tileset for UI text rendering. * Pushes a new UI element onto the UI stack from a script file.
* *
* @param fontTileset Pointer to the tileset to use for UI fonts. * @param path Path to the UI script file.
*
* @return An errorret_t indicating success or failure.
*/ */
errorret_t uiSetFont(const tileset_t *fontTileset); errorret_t uiPushScript(const char_t *path);
/** /**
* Cleans up and frees all UI resources. * Pops the top UI element from the UI stack.
*/
void uiPop(void);
/**
* Disposes of the UI system.
*/ */
void uiDispose(void); void uiDispose(void);
+57
View File
@@ -0,0 +1,57 @@
/**
* Copyright (c) 2026 Dominic Masters
*
* This software is released under the MIT License.
* https://opensource.org/licenses/MIT
*/
#include "uielement.h"
#include "display/screen.h"
errorret_t uiElementInitScript(
uielement_t *element,
const char_t *path
) {
errorChain(scriptContextInit(&element->ctx));
errorChain(scriptContextExecFile(&element->ctx, path));
errorOk();
}
errorret_t uiElementUpdate(uielement_t *element) {
if(!scriptContextHasFunc(&element->ctx, "update")) errorOk();
errorChain(scriptContextCallFunc(
&element->ctx,
"update",
NULL,
0,
NULL
));
errorOk();
}
errorret_t uiElementRender(uielement_t *element) {
if(!scriptContextHasFunc(&element->ctx, "render")) errorOk();
// scriptvalue_t args[4] = {
// { .type = SCRIPT_VALUE_TYPE_FLOAT, .value.floatValue = 0.0f },
// { .type = SCRIPT_VALUE_TYPE_FLOAT, .value.floatValue = 0.0f },
// { .type = SCRIPT_VALUE_TYPE_FLOAT, .value.floatValue = SCREEN.width },
// { .type = SCRIPT_VALUE_TYPE_FLOAT, .value.floatValue = SCREEN.height },
// };
// errorChain(scriptContextCallFunc(
// &element->ctx,
// "render",
// args,
// 4,
// NULL
// ));
errorOk();
}
void uiElementDispose(uielement_t *element) {
scriptContextDispose(&element->ctx);
}
+46
View File
@@ -0,0 +1,46 @@
/**
* Copyright (c) 2026 Dominic Masters
*
* This software is released under the MIT License.
* https://opensource.org/licenses/MIT
*/
#pragma once
#include "script/scriptcontext.h"
// TODO: Support both scripted and native UI elements.
typedef struct {
scriptcontext_t ctx;
} uielement_t;
/**
* Initializes a scripted UI Element.
*
* @param element The UI element to initialize.
* @param path Path to the UI script file.
*/
errorret_t uiElementInitScript(
uielement_t *element,
const char_t *path
);
/**
* Updates/ticks a UI element's logic.
*
* @param element The UI element to tick.
*/
errorret_t uiElementUpdate(uielement_t *element);
/**
* Renders a UI element.
*
* @param element The UI element to render.
*/
errorret_t uiElementRender(uielement_t *element);
/**
* Disposes of a UI element.
*
* @param element The UI element to dispose of.
*/
void uiElementDispose(uielement_t *element);