Playertest: scene/script system refactor and Wii ABI fix
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
This commit is contained in:
@@ -0,0 +1,25 @@
|
|||||||
|
local Cube = setmetatable({}, { __index = Entity })
|
||||||
|
Cube.__index = Cube
|
||||||
|
|
||||||
|
function Cube.new()
|
||||||
|
local self = Entity.new()
|
||||||
|
setmetatable(self, Cube)
|
||||||
|
self:add(Entity.POSITION)
|
||||||
|
self.position.x = 0
|
||||||
|
self.position.y = 0
|
||||||
|
self.position.z = 0
|
||||||
|
self:add(Entity.MESH)
|
||||||
|
self:add(Entity.MATERIAL)
|
||||||
|
self.material.color = colorRed()
|
||||||
|
return self
|
||||||
|
end
|
||||||
|
|
||||||
|
function Cube:update()
|
||||||
|
local speed = 3.0
|
||||||
|
local dx = inputAxis(INPUT_ACTION_LEFT, INPUT_ACTION_RIGHT)
|
||||||
|
local dz = inputAxis(INPUT_ACTION_UP, INPUT_ACTION_DOWN)
|
||||||
|
self.position.x = self.position.x + dx * speed * TIME.delta
|
||||||
|
self.position.z = self.position.z + dz * speed * TIME.delta
|
||||||
|
end
|
||||||
|
|
||||||
|
return Cube
|
||||||
+1
-7
@@ -1,8 +1,3 @@
|
|||||||
module('input')
|
|
||||||
module('platform')
|
|
||||||
module('scene')
|
|
||||||
module('locale')
|
|
||||||
|
|
||||||
-- Default Input bindings.
|
-- Default Input bindings.
|
||||||
if PSP then
|
if PSP then
|
||||||
inputBind("up", INPUT_ACTION_UP)
|
inputBind("up", INPUT_ACTION_UP)
|
||||||
@@ -77,5 +72,4 @@ else
|
|||||||
print("Unknown platform, no default input bindings set.")
|
print("Unknown platform, no default input bindings set.")
|
||||||
end
|
end
|
||||||
|
|
||||||
-- Hand off to initial scene.
|
Scene.set('scenes/cube.lua')
|
||||||
sceneSet('test/scene.lua')
|
|
||||||
@@ -0,0 +1,30 @@
|
|||||||
|
local Cube = include('entities/cube.lua')
|
||||||
|
|
||||||
|
local SceneCube = {}
|
||||||
|
SceneCube.__index = SceneCube
|
||||||
|
|
||||||
|
local cam
|
||||||
|
local cube
|
||||||
|
|
||||||
|
function SceneCube:init()
|
||||||
|
cam = Entity.new()
|
||||||
|
cam:add(Entity.POSITION)
|
||||||
|
cam.position.x = 3
|
||||||
|
cam.position.y = 3
|
||||||
|
cam.position.z = 3
|
||||||
|
cam.position:lookAt(0, 0, 0)
|
||||||
|
cam:add(Entity.CAMERA)
|
||||||
|
|
||||||
|
cube = Cube.new()
|
||||||
|
end
|
||||||
|
|
||||||
|
function SceneCube:update()
|
||||||
|
cube:update()
|
||||||
|
end
|
||||||
|
|
||||||
|
function SceneCube:dispose()
|
||||||
|
cam:dispose()
|
||||||
|
cube:dispose()
|
||||||
|
end
|
||||||
|
|
||||||
|
return SceneCube
|
||||||
@@ -39,7 +39,7 @@ set(LUA_C_FILES
|
|||||||
list(TRANSFORM LUA_C_FILES PREPEND "${LUA_SRC_DIR}/")
|
list(TRANSFORM LUA_C_FILES PREPEND "${LUA_SRC_DIR}/")
|
||||||
add_library(liblua STATIC ${LUA_C_FILES})
|
add_library(liblua STATIC ${LUA_C_FILES})
|
||||||
target_include_directories(liblua PUBLIC "${LUA_SRC_DIR}")
|
target_include_directories(liblua PUBLIC "${LUA_SRC_DIR}")
|
||||||
target_compile_definitions(liblua PRIVATE LUA_USE_C89)
|
target_compile_definitions(liblua PUBLIC LUA_USE_C89)
|
||||||
add_library(lua::lua ALIAS liblua)
|
add_library(lua::lua ALIAS liblua)
|
||||||
set(Lua_FOUND TRUE CACHE BOOL "Lua found" FORCE)
|
set(Lua_FOUND TRUE CACHE BOOL "Lua found" FORCE)
|
||||||
|
|
||||||
|
|||||||
@@ -19,13 +19,13 @@ errorret_t assetScriptLoader(assetfile_t *file) {
|
|||||||
errorChain(assetFileOpen(file));
|
errorChain(assetFileOpen(file));
|
||||||
|
|
||||||
// Request loading
|
// Request loading
|
||||||
if(!lua_load(
|
if(lua_load(
|
||||||
script->ctx->luaState,
|
script->ctx->luaState,
|
||||||
assetScriptReader,
|
assetScriptReader,
|
||||||
file,
|
file,
|
||||||
file->filename,
|
file->filename,
|
||||||
NULL
|
NULL
|
||||||
) == LUA_OK) {
|
) != LUA_OK) {
|
||||||
const char_t *strErr = lua_tostring(script->ctx->luaState, -1);
|
const char_t *strErr = lua_tostring(script->ctx->luaState, -1);
|
||||||
lua_pop(script->ctx->luaState, 1);
|
lua_pop(script->ctx->luaState, 1);
|
||||||
errorThrow("Failed to load Lua script: %s", strErr);
|
errorThrow("Failed to load Lua script: %s", strErr);
|
||||||
|
|||||||
@@ -47,13 +47,10 @@ errorret_t engineInit(const int32_t argc, const char_t **argv) {
|
|||||||
physicsManagerInit();
|
physicsManagerInit();
|
||||||
errorChain(networkInit());
|
errorChain(networkInit());
|
||||||
errorChain(gameInit());
|
errorChain(gameInit());
|
||||||
consolePrint("Engine initialized");
|
|
||||||
|
|
||||||
/* Run the init script. */
|
/* Run the init script. */
|
||||||
scriptcontext_t ctx;
|
consolePrint("Engine initialized");
|
||||||
errorChain(scriptContextInit(&ctx));
|
errorChain(scriptContextExecFile(&SCRIPT_MANAGER.mainContext, "init.lua"));
|
||||||
errorChain(scriptContextExecFile(&ctx, "init.lua"));
|
|
||||||
scriptContextDispose(&ctx);
|
|
||||||
|
|
||||||
errorOk();
|
errorOk();
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -6,6 +6,8 @@
|
|||||||
*/
|
*/
|
||||||
|
|
||||||
#include "entity/entitymanager.h"
|
#include "entity/entitymanager.h"
|
||||||
|
#include "entity/entity.h"
|
||||||
|
#include "entity/component/display/entityposition.h"
|
||||||
#include "display/framebuffer/framebuffer.h"
|
#include "display/framebuffer/framebuffer.h"
|
||||||
#include "display/screen/screen.h"
|
#include "display/screen/screen.h"
|
||||||
|
|
||||||
@@ -92,4 +94,38 @@ void entityCameraGetProjection(
|
|||||||
out
|
out
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
entityid_t entityCameraGetCurrent(void) {
|
||||||
|
entityid_t camEnts[ENTITY_COUNT_MAX];
|
||||||
|
componentid_t camComps[ENTITY_COUNT_MAX];
|
||||||
|
entityid_t count = componentGetEntitiesWithComponent(
|
||||||
|
COMPONENT_TYPE_CAMERA, camEnts, camComps
|
||||||
|
);
|
||||||
|
if(count == 0) return ENTITY_COUNT_MAX;
|
||||||
|
return camEnts[0];
|
||||||
|
}
|
||||||
|
|
||||||
|
void entityCameraGetForward(const entityid_t entityId, vec2 out) {
|
||||||
|
componentid_t posComp = entityGetComponent(entityId, COMPONENT_TYPE_POSITION);
|
||||||
|
entityposition_t *pos = entityPositionGet(entityId, posComp);
|
||||||
|
// View matrix column layout: M[col][row], forward = {-M[0][2], -M[1][2], -M[2][2]}
|
||||||
|
float_t fx = -pos->transform[0][2];
|
||||||
|
float_t fz = -pos->transform[2][2];
|
||||||
|
float_t len = sqrtf(fx * fx + fz * fz);
|
||||||
|
if(len > 1e-6f) { fx /= len; fz /= len; }
|
||||||
|
out[0] = fx;
|
||||||
|
out[1] = fz;
|
||||||
|
}
|
||||||
|
|
||||||
|
void entityCameraGetRight(const entityid_t entityId, vec2 out) {
|
||||||
|
componentid_t posComp = entityGetComponent(entityId, COMPONENT_TYPE_POSITION);
|
||||||
|
entityposition_t *pos = entityPositionGet(entityId, posComp);
|
||||||
|
// View matrix column layout: right = {M[0][0], M[1][0], M[2][0]}
|
||||||
|
float_t rx = pos->transform[0][0];
|
||||||
|
float_t rz = pos->transform[2][0];
|
||||||
|
float_t len = sqrtf(rx * rx + rz * rz);
|
||||||
|
if(len > 1e-6f) { rx /= len; rz /= len; }
|
||||||
|
out[0] = rx;
|
||||||
|
out[1] = rz;
|
||||||
}
|
}
|
||||||
@@ -96,4 +96,27 @@ void entityCameraSetZFar(
|
|||||||
const entityid_t ent,
|
const entityid_t ent,
|
||||||
const componentid_t comp,
|
const componentid_t comp,
|
||||||
const float_t zFar
|
const float_t zFar
|
||||||
);
|
);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns the entity ID of the first active camera, or ENTITY_COUNT_MAX if none.
|
||||||
|
*/
|
||||||
|
entityid_t entityCameraGetCurrent(void);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Gets the camera's horizontal forward direction (XZ plane) from its position
|
||||||
|
* component. Automatically finds the position component on the entity.
|
||||||
|
*
|
||||||
|
* @param entityId The camera entity ID.
|
||||||
|
* @param out Output vec2: {forwardX, forwardZ} normalized.
|
||||||
|
*/
|
||||||
|
void entityCameraGetForward(const entityid_t entityId, vec2 out);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Gets the camera's horizontal right direction (XZ plane) from its position
|
||||||
|
* component. Automatically finds the position component on the entity.
|
||||||
|
*
|
||||||
|
* @param entityId The camera entity ID.
|
||||||
|
* @param out Output vec2: {rightX, rightZ} normalized.
|
||||||
|
*/
|
||||||
|
void entityCameraGetRight(const entityid_t entityId, vec2 out);
|
||||||
@@ -48,4 +48,15 @@ void entityMaterialSetShader(
|
|||||||
entityId, componentId, COMPONENT_TYPE_MATERIAL
|
entityId, componentId, COMPONENT_TYPE_MATERIAL
|
||||||
);
|
);
|
||||||
mat->shader = shader;
|
mat->shader = shader;
|
||||||
|
}
|
||||||
|
|
||||||
|
void entityMaterialSetColor(
|
||||||
|
const entityid_t entityId,
|
||||||
|
const componentid_t componentId,
|
||||||
|
const color_t color
|
||||||
|
) {
|
||||||
|
entitymaterial_t *mat = componentGetData(
|
||||||
|
entityId, componentId, COMPONENT_TYPE_MATERIAL
|
||||||
|
);
|
||||||
|
mat->material.unlit.color = color;
|
||||||
}
|
}
|
||||||
@@ -60,4 +60,17 @@ void entityMaterialSetShader(
|
|||||||
const entityid_t entityId,
|
const entityid_t entityId,
|
||||||
const componentid_t componentId,
|
const componentid_t componentId,
|
||||||
shader_t *shader
|
shader_t *shader
|
||||||
|
);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Sets the unlit color for the given entity and component.
|
||||||
|
*
|
||||||
|
* @param entityId The entity ID.
|
||||||
|
* @param componentId The component ID.
|
||||||
|
* @param color The color to set.
|
||||||
|
*/
|
||||||
|
void entityMaterialSetColor(
|
||||||
|
const entityid_t entityId,
|
||||||
|
const componentid_t componentId,
|
||||||
|
const color_t color
|
||||||
);
|
);
|
||||||
@@ -5,9 +5,13 @@
|
|||||||
* https://opensource.org/licenses/MIT
|
* https://opensource.org/licenses/MIT
|
||||||
*/
|
*/
|
||||||
|
|
||||||
|
#include "entitymesh.h"
|
||||||
#include "entity/entitymanager.h"
|
#include "entity/entitymanager.h"
|
||||||
|
#include "assert/assert.h"
|
||||||
|
#include "util/memory.h"
|
||||||
#include "display/mesh/cube.h"
|
#include "display/mesh/cube.h"
|
||||||
|
#include "display/mesh/plane.h"
|
||||||
|
#include "display/mesh/capsule.h"
|
||||||
|
|
||||||
void entityMeshInit(
|
void entityMeshInit(
|
||||||
const entityid_t entityId,
|
const entityid_t entityId,
|
||||||
@@ -17,6 +21,8 @@ void entityMeshInit(
|
|||||||
entityId, componentId, COMPONENT_TYPE_MESH
|
entityId, componentId, COMPONENT_TYPE_MESH
|
||||||
);
|
);
|
||||||
comp->mesh = &CUBE_MESH_SIMPLE;
|
comp->mesh = &CUBE_MESH_SIMPLE;
|
||||||
|
comp->ownedVertices = NULL;
|
||||||
|
comp->ownsData = false;
|
||||||
}
|
}
|
||||||
|
|
||||||
mesh_t * entityMeshGetMesh(
|
mesh_t * entityMeshGetMesh(
|
||||||
@@ -38,4 +44,100 @@ void entityMeshSetMesh(
|
|||||||
entityId, componentId, COMPONENT_TYPE_MESH
|
entityId, componentId, COMPONENT_TYPE_MESH
|
||||||
);
|
);
|
||||||
comp->mesh = mesh;
|
comp->mesh = mesh;
|
||||||
|
}
|
||||||
|
|
||||||
|
void entityMeshDispose(
|
||||||
|
const entityid_t entityId,
|
||||||
|
const componentid_t componentId
|
||||||
|
) {
|
||||||
|
entitymesh_t *comp = componentGetData(
|
||||||
|
entityId, componentId, COMPONENT_TYPE_MESH
|
||||||
|
);
|
||||||
|
if(!comp->ownsData) return;
|
||||||
|
(void)meshDispose(&comp->ownedMesh);
|
||||||
|
memoryFree(comp->ownedVertices);
|
||||||
|
comp->ownedVertices = NULL;
|
||||||
|
comp->ownsData = false;
|
||||||
|
comp->mesh = NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
errorret_t entityMeshGeneratePlane(
|
||||||
|
const entityid_t entityId,
|
||||||
|
const componentid_t componentId,
|
||||||
|
const float_t width,
|
||||||
|
const float_t height
|
||||||
|
) {
|
||||||
|
entitymesh_t *comp = componentGetData(
|
||||||
|
entityId, componentId, COMPONENT_TYPE_MESH
|
||||||
|
);
|
||||||
|
entityMeshDispose(entityId, componentId);
|
||||||
|
|
||||||
|
comp->ownedVertices = memoryAllocate(PLANE_VERTEX_COUNT * sizeof(meshvertex_t));
|
||||||
|
assertNotNull(comp->ownedVertices, "Failed to allocate plane vertices");
|
||||||
|
|
||||||
|
vec3 min = { -width * 0.5f, 0.0f, -height * 0.5f };
|
||||||
|
vec3 max = { width * 0.5f, 0.0f, height * 0.5f };
|
||||||
|
vec2 uvMin = { 0.0f, 0.0f };
|
||||||
|
vec2 uvMax = { 1.0f, 1.0f };
|
||||||
|
planeBuffer(
|
||||||
|
comp->ownedVertices,
|
||||||
|
PLANE_AXIS_XZ,
|
||||||
|
min,
|
||||||
|
max
|
||||||
|
#if MESH_ENABLE_COLOR
|
||||||
|
, COLOR_WHITE_4B
|
||||||
|
#endif
|
||||||
|
, uvMin,
|
||||||
|
uvMax
|
||||||
|
);
|
||||||
|
|
||||||
|
errorChain(meshInit(
|
||||||
|
&comp->ownedMesh,
|
||||||
|
PLANE_PRIMITIVE_TYPE,
|
||||||
|
PLANE_VERTEX_COUNT,
|
||||||
|
comp->ownedVertices
|
||||||
|
));
|
||||||
|
|
||||||
|
comp->mesh = &comp->ownedMesh;
|
||||||
|
comp->ownsData = true;
|
||||||
|
errorOk();
|
||||||
|
}
|
||||||
|
|
||||||
|
errorret_t entityMeshGenerateCapsule(
|
||||||
|
const entityid_t entityId,
|
||||||
|
const componentid_t componentId,
|
||||||
|
const float_t radius,
|
||||||
|
const float_t halfHeight
|
||||||
|
) {
|
||||||
|
entitymesh_t *comp = componentGetData(
|
||||||
|
entityId, componentId, COMPONENT_TYPE_MESH
|
||||||
|
);
|
||||||
|
entityMeshDispose(entityId, componentId);
|
||||||
|
|
||||||
|
comp->ownedVertices = memoryAllocate(CAPSULE_VERTEX_COUNT * sizeof(meshvertex_t));
|
||||||
|
assertNotNull(comp->ownedVertices, "Failed to allocate capsule vertices");
|
||||||
|
|
||||||
|
vec3 center = { 0.0f, 0.0f, 0.0f };
|
||||||
|
capsuleBuffer(
|
||||||
|
comp->ownedVertices,
|
||||||
|
center,
|
||||||
|
radius,
|
||||||
|
halfHeight,
|
||||||
|
CAPSULE_CAP_RINGS,
|
||||||
|
CAPSULE_SECTORS
|
||||||
|
#if MESH_ENABLE_COLOR
|
||||||
|
, COLOR_WHITE_4B
|
||||||
|
#endif
|
||||||
|
);
|
||||||
|
|
||||||
|
errorChain(meshInit(
|
||||||
|
&comp->ownedMesh,
|
||||||
|
CAPSULE_PRIMITIVE_TYPE,
|
||||||
|
CAPSULE_VERTEX_COUNT,
|
||||||
|
comp->ownedVertices
|
||||||
|
));
|
||||||
|
|
||||||
|
comp->mesh = &comp->ownedMesh;
|
||||||
|
comp->ownsData = true;
|
||||||
|
errorOk();
|
||||||
}
|
}
|
||||||
@@ -11,6 +11,9 @@
|
|||||||
|
|
||||||
typedef struct {
|
typedef struct {
|
||||||
mesh_t *mesh;
|
mesh_t *mesh;
|
||||||
|
mesh_t ownedMesh;
|
||||||
|
meshvertex_t *ownedVertices;
|
||||||
|
bool_t ownsData;
|
||||||
} entitymesh_t;
|
} entitymesh_t;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -47,4 +50,47 @@ void entityMeshSetMesh(
|
|||||||
const entityid_t entityId,
|
const entityid_t entityId,
|
||||||
const componentid_t componentId,
|
const componentid_t componentId,
|
||||||
mesh_t *mesh
|
mesh_t *mesh
|
||||||
|
);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Disposes the entity mesh component, freeing any owned mesh data.
|
||||||
|
*
|
||||||
|
* @param entityId The entity ID.
|
||||||
|
* @param componentId The component ID.
|
||||||
|
*/
|
||||||
|
void entityMeshDispose(
|
||||||
|
const entityid_t entityId,
|
||||||
|
const componentid_t componentId
|
||||||
|
);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Generates an XZ-aligned plane mesh owned by the component.
|
||||||
|
*
|
||||||
|
* @param entityId The entity ID.
|
||||||
|
* @param componentId The component ID.
|
||||||
|
* @param width Width of the plane along the X axis.
|
||||||
|
* @param height Height of the plane along the Z axis.
|
||||||
|
* @return Error return value.
|
||||||
|
*/
|
||||||
|
errorret_t entityMeshGeneratePlane(
|
||||||
|
const entityid_t entityId,
|
||||||
|
const componentid_t componentId,
|
||||||
|
const float_t width,
|
||||||
|
const float_t height
|
||||||
|
);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Generates a Y-axis capsule mesh owned by the component.
|
||||||
|
*
|
||||||
|
* @param entityId The entity ID.
|
||||||
|
* @param componentId The component ID.
|
||||||
|
* @param radius Radius of the cylinder and hemisphere caps.
|
||||||
|
* @param halfHeight Half-height of the cylindrical section.
|
||||||
|
* @return Error return value.
|
||||||
|
*/
|
||||||
|
errorret_t entityMeshGenerateCapsule(
|
||||||
|
const entityid_t entityId,
|
||||||
|
const componentid_t componentId,
|
||||||
|
const float_t radius,
|
||||||
|
const float_t halfHeight
|
||||||
);
|
);
|
||||||
@@ -100,6 +100,25 @@ bool_t entityPhysicsIsOnGround(
|
|||||||
return phys->onGround;
|
return phys->onGround;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void entityPhysicsSetBodyType(
|
||||||
|
const entityid_t entityId,
|
||||||
|
const componentid_t componentId,
|
||||||
|
const physicsbodytype_t type
|
||||||
|
) {
|
||||||
|
entityphysics_t *phys = entityPhysicsGet(entityId, componentId);
|
||||||
|
assertNotNull(phys, "Failed to get physics component data");
|
||||||
|
phys->type = type;
|
||||||
|
}
|
||||||
|
|
||||||
|
physicsbodytype_t entityPhysicsGetBodyType(
|
||||||
|
const entityid_t entityId,
|
||||||
|
const componentid_t componentId
|
||||||
|
) {
|
||||||
|
entityphysics_t *phys = entityPhysicsGet(entityId, componentId);
|
||||||
|
assertNotNull(phys, "Failed to get physics component data");
|
||||||
|
return phys->type;
|
||||||
|
}
|
||||||
|
|
||||||
void entityPhysicsDispose(
|
void entityPhysicsDispose(
|
||||||
const entityid_t entityId,
|
const entityid_t entityId,
|
||||||
const componentid_t componentId
|
const componentid_t componentId
|
||||||
|
|||||||
@@ -122,6 +122,31 @@ bool_t entityPhysicsIsOnGround(
|
|||||||
const componentid_t componentId
|
const componentid_t componentId
|
||||||
);
|
);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Sets the body type of the entity's physics body.
|
||||||
|
*
|
||||||
|
* @param entityId The entity ID.
|
||||||
|
* @param componentId The component ID.
|
||||||
|
* @param type The body type to set.
|
||||||
|
*/
|
||||||
|
void entityPhysicsSetBodyType(
|
||||||
|
const entityid_t entityId,
|
||||||
|
const componentid_t componentId,
|
||||||
|
const physicsbodytype_t type
|
||||||
|
);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Gets the body type of the entity's physics body.
|
||||||
|
*
|
||||||
|
* @param entityId The entity ID.
|
||||||
|
* @param componentId The component ID.
|
||||||
|
* @return The body type of the physics body.
|
||||||
|
*/
|
||||||
|
physicsbodytype_t entityPhysicsGetBodyType(
|
||||||
|
const entityid_t entityId,
|
||||||
|
const componentid_t componentId
|
||||||
|
);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Releases the body slot back to PHYSICS_WORLD. Called automatically when
|
* Releases the body slot back to PHYSICS_WORLD. Called automatically when
|
||||||
* the component is disposed via the component system.
|
* the component is disposed via the component system.
|
||||||
|
|||||||
@@ -3,7 +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
|
||||||
|
|
||||||
target_sources(${DUSK_LIBRARY_TARGET_NAME}
|
|
||||||
PUBLIC
|
|
||||||
entityscript.c
|
|
||||||
)
|
|
||||||
|
|||||||
@@ -1,115 +0,0 @@
|
|||||||
/**
|
|
||||||
* Copyright (c) 2026 Dominic Masters
|
|
||||||
*
|
|
||||||
* This software is released under the MIT License.
|
|
||||||
* https://opensource.org/licenses/MIT
|
|
||||||
*/
|
|
||||||
|
|
||||||
#include "entityscript.h"
|
|
||||||
#include "entity/entitymanager.h"
|
|
||||||
#include "assert/assert.h"
|
|
||||||
#include "util/memory.h"
|
|
||||||
|
|
||||||
void entityScriptInit(
|
|
||||||
const entityid_t entityId,
|
|
||||||
const componentid_t compId
|
|
||||||
) {
|
|
||||||
entityscript_t *data = componentGetData(
|
|
||||||
entityId, compId, COMPONENT_TYPE_ENTITYSCRIPT
|
|
||||||
);
|
|
||||||
memoryZero(data, sizeof(entityscript_t));
|
|
||||||
}
|
|
||||||
|
|
||||||
void entityScriptUnload(
|
|
||||||
const entityid_t entityId,
|
|
||||||
const componentid_t compId
|
|
||||||
) {
|
|
||||||
entityscript_t *data = componentGetData(
|
|
||||||
entityId, compId, COMPONENT_TYPE_ENTITYSCRIPT
|
|
||||||
);
|
|
||||||
|
|
||||||
if(!data->active) return;
|
|
||||||
|
|
||||||
lua_getglobal(data->context.luaState, "entityDispose");
|
|
||||||
if(lua_isfunction(data->context.luaState, -1)) {
|
|
||||||
if(lua_pcall(data->context.luaState, 0, 0, 0) != LUA_OK) {
|
|
||||||
lua_pop(data->context.luaState, 1);
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
lua_pop(data->context.luaState, 1);
|
|
||||||
}
|
|
||||||
|
|
||||||
scriptContextDispose(&data->context);
|
|
||||||
data->active = false;
|
|
||||||
}
|
|
||||||
|
|
||||||
errorret_t entityScriptSetScript(
|
|
||||||
const entityid_t entityId,
|
|
||||||
const componentid_t compId,
|
|
||||||
const char_t *filename
|
|
||||||
) {
|
|
||||||
assertNotNull(filename, "Entity script filename cannot be NULL");
|
|
||||||
|
|
||||||
entityScriptUnload(entityId, compId);
|
|
||||||
|
|
||||||
entityscript_t *data = componentGetData(
|
|
||||||
entityId, compId, COMPONENT_TYPE_ENTITYSCRIPT
|
|
||||||
);
|
|
||||||
|
|
||||||
errorChain(scriptContextInit(&data->context));
|
|
||||||
data->active = true;
|
|
||||||
|
|
||||||
// Expose entity identity to the script as globals
|
|
||||||
lua_pushnumber(data->context.luaState, (lua_Number)entityId);
|
|
||||||
lua_setglobal(data->context.luaState, "ENTITY_ID");
|
|
||||||
lua_pushnumber(data->context.luaState, (lua_Number)compId);
|
|
||||||
lua_setglobal(data->context.luaState, "ENTITY_COMPONENT_ID");
|
|
||||||
|
|
||||||
errorChain(scriptContextExecFile(&data->context, filename));
|
|
||||||
|
|
||||||
lua_getglobal(data->context.luaState, "entityInit");
|
|
||||||
if(lua_isfunction(data->context.luaState, -1)) {
|
|
||||||
if(lua_pcall(data->context.luaState, 0, 0, 0) != LUA_OK) {
|
|
||||||
errorThrow(
|
|
||||||
"Failed to call entityInit: %s",
|
|
||||||
lua_tostring(data->context.luaState, -1)
|
|
||||||
);
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
lua_pop(data->context.luaState, 1);
|
|
||||||
}
|
|
||||||
|
|
||||||
errorOk();
|
|
||||||
}
|
|
||||||
|
|
||||||
errorret_t entityScriptUpdate(
|
|
||||||
const entityid_t entityId,
|
|
||||||
const componentid_t compId
|
|
||||||
) {
|
|
||||||
entityscript_t *data = componentGetData(
|
|
||||||
entityId, compId, COMPONENT_TYPE_ENTITYSCRIPT
|
|
||||||
);
|
|
||||||
|
|
||||||
if(!data->active) errorOk();
|
|
||||||
|
|
||||||
lua_getglobal(data->context.luaState, "entityUpdate");
|
|
||||||
if(lua_isfunction(data->context.luaState, -1)) {
|
|
||||||
if(lua_pcall(data->context.luaState, 0, 0, 0) != LUA_OK) {
|
|
||||||
errorThrow(
|
|
||||||
"Failed to call entityUpdate: %s",
|
|
||||||
lua_tostring(data->context.luaState, -1)
|
|
||||||
);
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
lua_pop(data->context.luaState, 1);
|
|
||||||
}
|
|
||||||
|
|
||||||
errorOk();
|
|
||||||
}
|
|
||||||
|
|
||||||
void entityScriptDispose(
|
|
||||||
const entityid_t entityId,
|
|
||||||
const componentid_t compId
|
|
||||||
) {
|
|
||||||
entityScriptUnload(entityId, compId);
|
|
||||||
}
|
|
||||||
@@ -1,77 +0,0 @@
|
|||||||
/**
|
|
||||||
* Copyright (c) 2026 Dominic Masters
|
|
||||||
*
|
|
||||||
* This software is released under the MIT License.
|
|
||||||
* https://opensource.org/licenses/MIT
|
|
||||||
*/
|
|
||||||
|
|
||||||
#pragma once
|
|
||||||
#include "entity/entitybase.h"
|
|
||||||
#include "script/scriptcontext.h"
|
|
||||||
|
|
||||||
typedef struct {
|
|
||||||
scriptcontext_t context;
|
|
||||||
bool_t active;
|
|
||||||
} entityscript_t;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Initializes the entity script component (empty context, not yet loaded).
|
|
||||||
*
|
|
||||||
* @param entityId The entity ID.
|
|
||||||
* @param compId The component ID.
|
|
||||||
*/
|
|
||||||
void entityScriptInit(
|
|
||||||
const entityid_t entityId,
|
|
||||||
const componentid_t compId
|
|
||||||
);
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Unloads the currently active script: calls entityDispose if defined and
|
|
||||||
* disposes the context. No-op if no script is loaded.
|
|
||||||
*
|
|
||||||
* @param entityId The entity ID.
|
|
||||||
* @param compId The component ID.
|
|
||||||
*/
|
|
||||||
void entityScriptUnload(
|
|
||||||
const entityid_t entityId,
|
|
||||||
const componentid_t compId
|
|
||||||
);
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Sets the script for this component. If a script is already loaded it is
|
|
||||||
* unloaded first. Then loads and executes the new file, sets entityId and
|
|
||||||
* entityScriptId as Lua globals, and calls entityInit if defined.
|
|
||||||
*
|
|
||||||
* @param entityId The entity ID.
|
|
||||||
* @param compId The component ID.
|
|
||||||
* @param filename The script file to load.
|
|
||||||
* @return The error return value.
|
|
||||||
*/
|
|
||||||
errorret_t entityScriptSetScript(
|
|
||||||
const entityid_t entityId,
|
|
||||||
const componentid_t compId,
|
|
||||||
const char_t *filename
|
|
||||||
);
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Calls the entityUpdate Lua function in the entity script context, if defined.
|
|
||||||
*
|
|
||||||
* @param entityId The entity ID.
|
|
||||||
* @param compId The component ID.
|
|
||||||
* @return The error return value.
|
|
||||||
*/
|
|
||||||
errorret_t entityScriptUpdate(
|
|
||||||
const entityid_t entityId,
|
|
||||||
const componentid_t compId
|
|
||||||
);
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Unloads the script if one is active, then disposes the component.
|
|
||||||
*
|
|
||||||
* @param entityId The entity ID.
|
|
||||||
* @param compId The component ID.
|
|
||||||
*/
|
|
||||||
void entityScriptDispose(
|
|
||||||
const entityid_t entityId,
|
|
||||||
const componentid_t compId
|
|
||||||
);
|
|
||||||
@@ -10,11 +10,9 @@
|
|||||||
#include "entity/component/display/entitymesh.h"
|
#include "entity/component/display/entitymesh.h"
|
||||||
#include "entity/component/display/entitymaterial.h"
|
#include "entity/component/display/entitymaterial.h"
|
||||||
#include "entity/component/physics/entityphysics.h"
|
#include "entity/component/physics/entityphysics.h"
|
||||||
#include "entity/component/script/entityscript.h"
|
|
||||||
|
|
||||||
X(POSITION, entityposition_t, position, entityPositionInit, NULL)
|
X(POSITION, entityposition_t, position, entityPositionInit, NULL)
|
||||||
X(CAMERA, entitycamera_t, camera, entityCameraInit, NULL)
|
X(CAMERA, entitycamera_t, camera, entityCameraInit, NULL)
|
||||||
X(MESH, entitymesh_t, mesh, entityMeshInit, NULL)
|
X(MESH, entitymesh_t, mesh, entityMeshInit, entityMeshDispose)
|
||||||
X(MATERIAL, entitymaterial_t, material, entityMaterialInit, NULL)
|
X(MATERIAL, entitymaterial_t, material, entityMaterialInit, NULL)
|
||||||
X(PHYSICS, entityphysics_t, physics, entityPhysicsInit, entityPhysicsDispose)
|
X(PHYSICS, entityphysics_t, physics, entityPhysicsInit, entityPhysicsDispose)
|
||||||
X(ENTITYSCRIPT, entityscript_t, entityscript, entityScriptInit, entityScriptDispose)
|
|
||||||
+43
-34
@@ -8,6 +8,17 @@
|
|||||||
#include "event.h"
|
#include "event.h"
|
||||||
#include "assert/assert.h"
|
#include "assert/assert.h"
|
||||||
#include "util/memory.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(
|
void eventInit(
|
||||||
event_t *event,
|
event_t *event,
|
||||||
@@ -73,7 +84,7 @@ eventsub_t eventSubscribe(
|
|||||||
const eventcallback_t callback,
|
const eventcallback_t callback,
|
||||||
const void *user
|
const void *user
|
||||||
) {
|
) {
|
||||||
eventSubscribeUser(
|
return eventSubscribeUser(
|
||||||
event,
|
event,
|
||||||
EVENT_TYPE_C,
|
EVENT_TYPE_C,
|
||||||
(eventuserdata_t){ .c = { .callback = callback, .user = (void *)user } }
|
(eventuserdata_t){ .c = { .callback = callback, .user = (void *)user } }
|
||||||
@@ -147,30 +158,29 @@ void eventUnsubscribe(event_t *event, const eventsub_t id) {
|
|||||||
|
|
||||||
if(event->listenerCount == 0) return;
|
if(event->listenerCount == 0) return;
|
||||||
|
|
||||||
// Find listener
|
|
||||||
uint16_t index = 0;
|
uint16_t index = 0;
|
||||||
do {
|
do {
|
||||||
if(event->listenerArray[index].id == id) {
|
if(event->listenerArray[index].id != id) {
|
||||||
// Found it, remove by swapping with last and reducing count
|
index++;
|
||||||
event->listenerArray[index] = event->listenerArray[--event->listenerCount];
|
continue;
|
||||||
return;
|
|
||||||
}
|
}
|
||||||
index++;
|
|
||||||
|
// Release Lua registry reference before the slot is overwritten
|
||||||
|
if(event->listenerArray[index].type == EVENT_TYPE_SCRIPT) {
|
||||||
|
scriptcontext_t *ctx = event->listenerArray[index].user.script.context;
|
||||||
|
if(ctx != NULL && ctx->luaState != NULL) {
|
||||||
|
luaL_unref(
|
||||||
|
ctx->luaState,
|
||||||
|
LUA_REGISTRYINDEX,
|
||||||
|
event->listenerArray[index].user.script.luaFunctionRef
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Swap with last and shrink
|
||||||
|
event->listenerArray[index] = event->listenerArray[--event->listenerCount];
|
||||||
|
return;
|
||||||
} while(index < event->listenerCount);
|
} while(index < event->listenerCount);
|
||||||
|
|
||||||
// Did we find it?
|
|
||||||
if(index == event->listenerCount) return;
|
|
||||||
|
|
||||||
// Shift remaining listeners down (if any)
|
|
||||||
if(index < event->listenerCount - 1) {
|
|
||||||
memoryMove(
|
|
||||||
&event->listenerArray[index],
|
|
||||||
&event->listenerArray[index + 1],
|
|
||||||
sizeof(eventlistener_t) * (event->listenerCount - index - 1)
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
event->listenerCount--;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void eventUnsubscribeScriptContext(event_t *event, const scriptcontext_t *ctx) {
|
void eventUnsubscribeScriptContext(event_t *event, const scriptcontext_t *ctx) {
|
||||||
@@ -219,29 +229,28 @@ void eventInvoke(
|
|||||||
if(listener->type == EVENT_TYPE_C) {
|
if(listener->type == EVENT_TYPE_C) {
|
||||||
listener->user.c.callback(&data, listener->user.c);
|
listener->user.c.callback(&data, listener->user.c);
|
||||||
} else if(listener->type == EVENT_TYPE_SCRIPT) {
|
} else if(listener->type == EVENT_TYPE_SCRIPT) {
|
||||||
// Call Lua function
|
|
||||||
lua_State *L = listener->user.script.context->luaState;
|
lua_State *L = listener->user.script.context->luaState;
|
||||||
assertNotNull(L, "Lua state in event listener cannot be NULL");
|
assertNotNull(L, "Lua state in event listener cannot be NULL");
|
||||||
|
|
||||||
// Push function
|
lua_pushcfunction(L, eventLuaTraceback);
|
||||||
|
int handlerIdx = lua_gettop(L);
|
||||||
lua_rawgeti(L, LUA_REGISTRYINDEX, listener->user.script.luaFunctionRef);
|
lua_rawgeti(L, LUA_REGISTRYINDEX, listener->user.script.luaFunctionRef);
|
||||||
|
|
||||||
if(eventParams != NULL && metatableName != NULL) {
|
int numArgs = 0;
|
||||||
lua_getmetatable(L, -1);
|
if(eventParams != NULL) {
|
||||||
luaL_getmetatable(L, metatableName);
|
lua_pushlightuserdata(L, (void *)eventParams);
|
||||||
assertTrue(
|
numArgs = 1;
|
||||||
lua_rawequal(L, -1, -2),
|
|
||||||
"Event parameter metatable does not match expected type"
|
|
||||||
);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// Call function with 1 arg, 0 return values
|
printf("Invoking Lua event listener with %d argument(s)\n", numArgs);
|
||||||
if(lua_pcall(L, 1, 0, 0) != LUA_OK) {
|
|
||||||
|
if(lua_pcall(L, numArgs, 0, handlerIdx) != LUA_OK) {
|
||||||
const char_t *strErr = lua_tostring(L, -1);
|
const char_t *strErr = lua_tostring(L, -1);
|
||||||
|
consolePrint("Error invoking Lua event listener:\n%s\n", strErr);
|
||||||
lua_pop(L, 1);
|
lua_pop(L, 1);
|
||||||
// Log error but continue
|
|
||||||
printf("Error invoking Lua event listener: %s\n", strErr);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
lua_pop(L, 1);
|
||||||
} else {
|
} else {
|
||||||
assertUnreachable("Unknown event listener type");
|
assertUnreachable("Unknown event listener type");
|
||||||
}
|
}
|
||||||
|
|||||||
+20
-20
@@ -95,27 +95,27 @@ void inputUpdate(void) {
|
|||||||
if(TIME.dynamicUpdate) return;
|
if(TIME.dynamicUpdate) return;
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
if(INPUT.eventPressed.listenerCount > 0) {
|
// if(INPUT.eventPressed.listenerCount > 0) {
|
||||||
action = &INPUT.actions[0];
|
// action = &INPUT.actions[0];
|
||||||
do {
|
// do {
|
||||||
if(inputPressed(action->action)) {
|
// if(inputPressed(action->action)) {
|
||||||
inputevent_t inputEvent = { .action = action->action };
|
// inputevent_t inputEvent = { .action = action->action };
|
||||||
eventInvoke(&INPUT.eventPressed, &inputEvent, "input_mt");
|
// eventInvoke(&INPUT.eventPressed, &inputEvent, "input_mt");
|
||||||
}
|
// }
|
||||||
action++;
|
// action++;
|
||||||
} while(action < &INPUT.actions[INPUT_ACTION_COUNT]);
|
// } while(action < &INPUT.actions[INPUT_ACTION_COUNT]);
|
||||||
}
|
// }
|
||||||
|
|
||||||
if(INPUT.eventReleased.listenerCount > 0) {
|
// if(INPUT.eventReleased.listenerCount > 0) {
|
||||||
action = &INPUT.actions[0];
|
// action = &INPUT.actions[0];
|
||||||
do {
|
// do {
|
||||||
if(inputReleased(action->action)) {
|
// if(inputReleased(action->action)) {
|
||||||
inputevent_t inputEvent = { .action = action->action };
|
// inputevent_t inputEvent = { .action = action->action };
|
||||||
eventInvoke(&INPUT.eventReleased, &inputEvent, "input_mt");
|
// eventInvoke(&INPUT.eventReleased, &inputEvent, "input_mt");
|
||||||
}
|
// }
|
||||||
action++;
|
// action++;
|
||||||
} while(action < &INPUT.actions[INPUT_ACTION_COUNT]);
|
// } while(action < &INPUT.actions[INPUT_ACTION_COUNT]);
|
||||||
}
|
// }
|
||||||
}
|
}
|
||||||
|
|
||||||
float_t inputGetCurrentValue(const inputaction_t action) {
|
float_t inputGetCurrentValue(const inputaction_t action) {
|
||||||
|
|||||||
+93
-67
@@ -1,5 +1,5 @@
|
|||||||
// Copyright (c) 2026 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
|
||||||
|
|
||||||
@@ -17,11 +17,61 @@
|
|||||||
#include "display/screen/screen.h"
|
#include "display/screen/screen.h"
|
||||||
#include "console/console.h"
|
#include "console/console.h"
|
||||||
#include "util/string.h"
|
#include "util/string.h"
|
||||||
|
#include "script/scriptmanager.h"
|
||||||
|
|
||||||
scene_t SCENE;
|
scene_t SCENE;
|
||||||
|
|
||||||
|
// Releases the current scene class ref and rebuilds Scene.set global.
|
||||||
|
static void sceneReset(void) {
|
||||||
|
lua_State *L = SCRIPT_MANAGER.mainContext.luaState;
|
||||||
|
if(SCENE.scriptRef != LUA_NOREF) {
|
||||||
|
luaL_unref(L, LUA_REGISTRYINDEX, SCENE.scriptRef);
|
||||||
|
SCENE.scriptRef = LUA_NOREF;
|
||||||
|
}
|
||||||
|
lua_newtable(L);
|
||||||
|
lua_pushcfunction(L, sceneSetLua);
|
||||||
|
lua_setfield(L, -2, "set");
|
||||||
|
lua_setglobal(L, "Scene");
|
||||||
|
}
|
||||||
|
|
||||||
|
// Calls sceneClass:method() if it exists. Returns an error if the call fails.
|
||||||
|
static errorret_t sceneCall(const char_t *method) {
|
||||||
|
lua_State *L = SCRIPT_MANAGER.mainContext.luaState;
|
||||||
|
|
||||||
|
if(SCENE.scriptRef == LUA_NOREF || SCENE.scriptRef == LUA_REFNIL) {
|
||||||
|
errorOk();
|
||||||
|
}
|
||||||
|
|
||||||
|
lua_rawgeti(L, LUA_REGISTRYINDEX, SCENE.scriptRef);
|
||||||
|
|
||||||
|
if(!lua_istable(L, -1)) {
|
||||||
|
lua_pop(L, 1);
|
||||||
|
errorThrow("Scene script ref %d is not a table", SCENE.scriptRef);
|
||||||
|
}
|
||||||
|
|
||||||
|
lua_getfield(L, -1, method);
|
||||||
|
|
||||||
|
if(!lua_isfunction(L, -1)) {
|
||||||
|
lua_pop(L, 2);
|
||||||
|
errorOk();
|
||||||
|
}
|
||||||
|
|
||||||
|
lua_pushvalue(L, -2); // self
|
||||||
|
|
||||||
|
if(lua_pcall(L, 1, 0, 0) != LUA_OK) {
|
||||||
|
const char_t *err = lua_tostring(L, -1);
|
||||||
|
lua_pop(L, 2); // error + scene table
|
||||||
|
errorThrow("Scene:%s failed: %s", method, err);
|
||||||
|
}
|
||||||
|
|
||||||
|
lua_pop(L, 1); // scene table
|
||||||
|
errorOk();
|
||||||
|
}
|
||||||
|
|
||||||
errorret_t sceneInit(void) {
|
errorret_t sceneInit(void) {
|
||||||
memoryZero(&SCENE, sizeof(scene_t));
|
memoryZero(&SCENE, sizeof(scene_t));
|
||||||
|
SCENE.scriptRef = LUA_NOREF;
|
||||||
|
sceneReset();
|
||||||
errorOk();
|
errorOk();
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -32,27 +82,14 @@ errorret_t sceneUpdate(void) {
|
|||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
// Is the scene changing?
|
|
||||||
if(stringCompare(SCENE.sceneNext, SCENE.sceneCurrent) != 0) {
|
if(stringCompare(SCENE.sceneNext, SCENE.sceneCurrent) != 0) {
|
||||||
errorChain(sceneSetImmediate(SCENE.sceneNext));
|
errorChain(sceneSetImmediate(SCENE.sceneNext));
|
||||||
}
|
}
|
||||||
|
|
||||||
// Call scene update function if script loaded
|
if(SCENE.scriptActive) {
|
||||||
if(!SCENE.scriptActive) {
|
errorChain(sceneCall("update"));
|
||||||
errorOk();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
assertNotNull(SCENE.script.luaState, "Script context null?");
|
|
||||||
lua_getglobal(SCENE.script.luaState, "sceneUpdate");
|
|
||||||
if(lua_isfunction(SCENE.script.luaState, -1)) {
|
|
||||||
if(lua_pcall(SCENE.script.luaState, 0, 0, 0) != LUA_OK) {
|
|
||||||
errorThrow(
|
|
||||||
"Failed to call sceneUpdate function in script: %s\n",
|
|
||||||
lua_tostring(SCENE.script.luaState, -1)
|
|
||||||
);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
errorOk();
|
errorOk();
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -163,80 +200,57 @@ errorret_t sceneRender(void) {
|
|||||||
errorOk();
|
errorOk();
|
||||||
}
|
}
|
||||||
|
|
||||||
errorret_t sceneSetImmediate(const char_t *script) {
|
errorret_t sceneSetImmediate(const char_t *scene) {
|
||||||
// Update the next scene name (shouldn't really happen but its for safety).
|
if(scene != SCENE.sceneNext) {
|
||||||
if(script != SCENE.sceneNext) {
|
|
||||||
stringCopy(
|
stringCopy(
|
||||||
SCENE.sceneNext,
|
SCENE.sceneNext,
|
||||||
script == NULL ? "" : script,
|
scene == NULL ? "" : scene,
|
||||||
ASSET_FILE_PATH_MAX
|
ASSET_FILE_PATH_MAX
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
// If there's currently a scene active, dispose of it first.
|
|
||||||
if(SCENE.scriptActive) {
|
if(SCENE.scriptActive) {
|
||||||
assertNotNull(SCENE.script.luaState, "Script context null?");
|
errorChain(sceneCall("dispose"));
|
||||||
|
|
||||||
// Call sceneDispose function
|
|
||||||
lua_getglobal(SCENE.script.luaState, "sceneDispose");
|
|
||||||
if(lua_isfunction(SCENE.script.luaState, -1)) {
|
|
||||||
if(lua_pcall(SCENE.script.luaState, 0, 0, 0) != LUA_OK) {
|
|
||||||
errorThrow(
|
|
||||||
"Failed to call sceneDispose function in script: %s\n",
|
|
||||||
lua_tostring(SCENE.script.luaState, -1)
|
|
||||||
);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// Scenes should ideally clean themselves up, this is just a warning because
|
|
||||||
// you can technically move entities between scenes, but it's messy.
|
|
||||||
for(entityid_t i = 0; i < ENTITY_COUNT_MAX; i++) {
|
|
||||||
if(ENTITY_MANAGER.entities[i].state & ENTITY_STATE_ACTIVE) {
|
|
||||||
consolePrint(
|
|
||||||
"Entity %d is active after scene dispose\n", i
|
|
||||||
);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// Unload script context.
|
|
||||||
scriptContextDispose(&SCENE.script);
|
|
||||||
SCENE.scriptActive = false;
|
SCENE.scriptActive = false;
|
||||||
}
|
}
|
||||||
|
|
||||||
// At this point the existing scene is unloaded, update the current scene.
|
// Wipe Scene back to a clean table before loading the next file so custom
|
||||||
|
// methods from the previous scene (e.g. Scene.doThing) cannot bleed through.
|
||||||
|
sceneReset();
|
||||||
|
|
||||||
stringCopy(
|
stringCopy(
|
||||||
SCENE.sceneCurrent,
|
SCENE.sceneCurrent,
|
||||||
script == NULL ? "" : script,
|
scene == NULL ? "" : scene,
|
||||||
ASSET_FILE_PATH_MAX
|
ASSET_FILE_PATH_MAX
|
||||||
);
|
);
|
||||||
|
|
||||||
// If we have a new scene, execute it.
|
if(scene != NULL) {
|
||||||
if(script != NULL) {
|
lua_State *L = SCRIPT_MANAGER.mainContext.luaState;
|
||||||
errorChain(scriptContextInit(&SCENE.script));
|
|
||||||
SCENE.scriptActive = true;
|
|
||||||
errorChain(scriptContextExecFile(&SCENE.script, script));
|
|
||||||
|
|
||||||
// Call the init function.
|
int32_t stackBase = lua_gettop(L);
|
||||||
lua_getglobal(SCENE.script.luaState, "sceneInit");
|
|
||||||
if(lua_isfunction(SCENE.script.luaState, -1)) {
|
errorChain(scriptContextExecFile(&SCRIPT_MANAGER.mainContext, scene));
|
||||||
if(lua_pcall(SCENE.script.luaState, 0, 0, 0) != LUA_OK) {
|
|
||||||
errorThrow(
|
int32_t nReturns = lua_gettop(L) - stackBase;
|
||||||
"Failed to call sceneInit function in script: %s\n",
|
if(nReturns < 1 || !lua_istable(L, stackBase + 1)) {
|
||||||
lua_tostring(SCENE.script.luaState, -1)
|
lua_settop(L, stackBase);
|
||||||
);
|
errorThrow("Scene '%s' must return a table", scene);
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
lua_settop(L, stackBase + 1);
|
||||||
|
|
||||||
|
SCENE.scriptRef = luaL_ref(L, LUA_REGISTRYINDEX);
|
||||||
|
|
||||||
|
errorChain(sceneCall("init"));
|
||||||
|
SCENE.scriptActive = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
errorOk();
|
errorOk();
|
||||||
}
|
}
|
||||||
|
|
||||||
void sceneSet(const char_t *script) {
|
void sceneSet(const char_t *scene) {
|
||||||
// Tell the scene that next update it needs to change scenes. This will always
|
|
||||||
// occur on the NEXT frame.
|
|
||||||
stringCopy(
|
stringCopy(
|
||||||
SCENE.sceneNext,
|
SCENE.sceneNext,
|
||||||
script == NULL ? "" : script,
|
scene == NULL ? "" : scene,
|
||||||
ASSET_FILE_PATH_MAX
|
ASSET_FILE_PATH_MAX
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
@@ -244,4 +258,16 @@ void sceneSet(const char_t *script) {
|
|||||||
errorret_t sceneDispose(void) {
|
errorret_t sceneDispose(void) {
|
||||||
errorChain(sceneSetImmediate(NULL));
|
errorChain(sceneSetImmediate(NULL));
|
||||||
errorOk();
|
errorOk();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
int sceneSetLua(lua_State *L) {
|
||||||
|
assertNotNull(L, "Lua state cannot be NULL");
|
||||||
|
|
||||||
|
if(!lua_isstring(L, 1)) {
|
||||||
|
luaL_error(L, "Scene.set requires a string argument");
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
sceneSet(lua_tostring(L, 1));
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|||||||
+9
-40
@@ -1,6 +1,6 @@
|
|||||||
/**
|
/**
|
||||||
* Copyright (c) 2026 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
|
||||||
*/
|
*/
|
||||||
@@ -8,54 +8,23 @@
|
|||||||
#pragma once
|
#pragma once
|
||||||
#include "script/scriptcontext.h"
|
#include "script/scriptcontext.h"
|
||||||
#include "asset/assetfile.h"
|
#include "asset/assetfile.h"
|
||||||
|
#include "event/event.h"
|
||||||
|
|
||||||
|
#define SCENE_EVENT_UPDATE_MAX 16
|
||||||
|
|
||||||
typedef struct {
|
typedef struct {
|
||||||
scriptcontext_t script;
|
|
||||||
bool_t scriptActive;
|
bool_t scriptActive;
|
||||||
|
int scriptRef;
|
||||||
char_t sceneCurrent[ASSET_FILE_PATH_MAX];
|
char_t sceneCurrent[ASSET_FILE_PATH_MAX];
|
||||||
char_t sceneNext[ASSET_FILE_PATH_MAX];
|
char_t sceneNext[ASSET_FILE_PATH_MAX];
|
||||||
} scene_t;
|
} scene_t;
|
||||||
|
|
||||||
extern scene_t SCENE;
|
extern scene_t SCENE;
|
||||||
|
|
||||||
/**
|
|
||||||
* Initialize the scene subsystem.
|
|
||||||
*
|
|
||||||
* @return The error return value.
|
|
||||||
*/
|
|
||||||
errorret_t sceneInit(void);
|
errorret_t sceneInit(void);
|
||||||
|
|
||||||
/**
|
|
||||||
* Update the current scene.
|
|
||||||
*
|
|
||||||
* @return The error return value.
|
|
||||||
*/
|
|
||||||
errorret_t sceneUpdate(void);
|
errorret_t sceneUpdate(void);
|
||||||
|
|
||||||
/**
|
|
||||||
* Render the current scene.
|
|
||||||
*
|
|
||||||
* @return The error return value.
|
|
||||||
*/
|
|
||||||
errorret_t sceneRender(void);
|
errorret_t sceneRender(void);
|
||||||
|
errorret_t sceneSetImmediate(const char_t *scene);
|
||||||
/**
|
void sceneSet(const char_t *scene);
|
||||||
* Internal only method, immediately sets the scene. This will basically crash
|
errorret_t sceneDispose(void);
|
||||||
* Lua if called from its tree.
|
int sceneSetLua(lua_State *L);
|
||||||
*/
|
|
||||||
errorret_t sceneSetImmediate(const char_t *script);
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Set the current scene by script name.
|
|
||||||
*
|
|
||||||
* @param script The script name of the scene to set.
|
|
||||||
* @return The error return value.
|
|
||||||
*/
|
|
||||||
void sceneSet(const char_t *script);
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Dispose of the scene subsystem.
|
|
||||||
*
|
|
||||||
* @return The error return value.
|
|
||||||
*/
|
|
||||||
errorret_t sceneDispose(void);
|
|
||||||
|
|||||||
@@ -8,8 +8,6 @@ target_sources(${DUSK_LIBRARY_TARGET_NAME}
|
|||||||
PUBLIC
|
PUBLIC
|
||||||
scriptmanager.c
|
scriptmanager.c
|
||||||
scriptcontext.c
|
scriptcontext.c
|
||||||
scriptmodule.c
|
|
||||||
)
|
)
|
||||||
|
|
||||||
# Subdirectories
|
# Subdirectories
|
||||||
add_subdirectory(module)
|
|
||||||
@@ -1,15 +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(system)
|
|
||||||
add_subdirectory(scene)
|
|
||||||
add_subdirectory(time)
|
|
||||||
add_subdirectory(ui)
|
|
||||||
@@ -1,18 +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
|
|
||||||
moduleglm.c
|
|
||||||
modulecolor.c
|
|
||||||
moduletext.c
|
|
||||||
modulescreen.c
|
|
||||||
moduletileset.c
|
|
||||||
moduletexture.c
|
|
||||||
moduleshader.c
|
|
||||||
)
|
|
||||||
@@ -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;
|
|
||||||
}
|
|
||||||
@@ -1,55 +1,121 @@
|
|||||||
/**
|
/**
|
||||||
* Copyright (c) 2026 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 "script/scriptcontext.h"
|
#include "script/module/modulebase.h"
|
||||||
|
#include "display/color.h"
|
||||||
|
#include "time/time.h"
|
||||||
|
|
||||||
/**
|
static int moduleColorIndex(lua_State *L) {
|
||||||
* Registers the color module with the given script context.
|
const color_t *color = (const color_t *)luaL_checkudata(L, 1, "color_mt");
|
||||||
*
|
assertNotNull(color, "Color struct cannot be NULL.");
|
||||||
* @param context The script context to register the module with.
|
const char_t *key = luaL_checkstring(L, 2);
|
||||||
*/
|
|
||||||
void moduleColor(scriptcontext_t *context);
|
|
||||||
|
|
||||||
/**
|
if(stringCompare(key, "r") == 0) { lua_pushnumber(L, color->r); return 1; }
|
||||||
* Lua function to create a color.
|
if(stringCompare(key, "g") == 0) { lua_pushnumber(L, color->g); return 1; }
|
||||||
*
|
if(stringCompare(key, "b") == 0) { lua_pushnumber(L, color->b); return 1; }
|
||||||
* @param L The Lua state.
|
if(stringCompare(key, "a") == 0) { lua_pushnumber(L, color->a); return 1; }
|
||||||
* @return Number of return values.
|
|
||||||
*/
|
|
||||||
int moduleColorFuncColor(lua_State *L);
|
|
||||||
|
|
||||||
/**
|
lua_getmetatable(L, 1);
|
||||||
* Index function for the color structure.
|
lua_getfield(L, -1, key);
|
||||||
* @param L The Lua state.
|
return 1;
|
||||||
* @return Number of return values.
|
}
|
||||||
*/
|
|
||||||
int moduleColorIndex(lua_State *L);
|
|
||||||
|
|
||||||
/**
|
static int moduleColorNewIndex(lua_State *L) {
|
||||||
* New index function for the color structure.
|
color_t *color = (color_t *)luaL_checkudata(L, 1, "color_mt");
|
||||||
*
|
assertNotNull(color, "Color struct cannot be NULL.");
|
||||||
* @param L The Lua state.
|
const char_t *key = luaL_checkstring(L, 2);
|
||||||
* @return Number of return values.
|
|
||||||
*/
|
|
||||||
int moduleColorNewIndex(lua_State *L);
|
|
||||||
|
|
||||||
/**
|
if(stringCompare(key, "r") == 0) {
|
||||||
* Color to string method for script
|
color->r = (colorchannel8_t)luaL_checknumber(L, 3); return 0;
|
||||||
*
|
} else if(stringCompare(key, "g") == 0) {
|
||||||
* @param L The Lua state.
|
color->g = (colorchannel8_t)luaL_checknumber(L, 3); return 0;
|
||||||
* @return Number of return values.
|
} else if(stringCompare(key, "b") == 0) {
|
||||||
*/
|
color->b = (colorchannel8_t)luaL_checknumber(L, 3); return 0;
|
||||||
int moduleColorToString(lua_State *L);
|
} else if(stringCompare(key, "a") == 0) {
|
||||||
|
color->a = (colorchannel8_t)luaL_checknumber(L, 3); return 0;
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
luaL_error(L, "color: unknown property '%s'", key);
|
||||||
* Lua function to create a rainbow color based on time.
|
return 0;
|
||||||
*
|
}
|
||||||
* @param L The Lua state.
|
|
||||||
* @return Number of return values.
|
static int moduleColorToString(lua_State *L) {
|
||||||
*/
|
const color_t *color = (const color_t *)luaL_checkudata(L, 1, "color_mt");
|
||||||
int moduleColorRainbow(lua_State *L);
|
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);
|
||||||
|
}
|
||||||
|
|||||||
@@ -1,283 +0,0 @@
|
|||||||
/**
|
|
||||||
* Copyright (c) 2026 Dominic Masters
|
|
||||||
*
|
|
||||||
* This software is released under the MIT License.
|
|
||||||
* https://opensource.org/licenses/MIT
|
|
||||||
*/
|
|
||||||
|
|
||||||
#include "moduleglm.h"
|
|
||||||
#include "assert/assert.h"
|
|
||||||
#include "util/string.h"
|
|
||||||
#include "util/memory.h"
|
|
||||||
|
|
||||||
void moduleGLM(scriptcontext_t *context) {
|
|
||||||
assertNotNull(context, "Context cannot be NULL.");
|
|
||||||
|
|
||||||
// Create metatable for vec3 structure.
|
|
||||||
if(luaL_newmetatable(context->luaState, "vec3_mt")) {
|
|
||||||
// Metatable methods
|
|
||||||
lua_pushcfunction(context->luaState, moduleVec3Index);
|
|
||||||
lua_setfield(context->luaState, -2, "__index");
|
|
||||||
lua_pushcfunction(context->luaState, moduleVec3NewIndex);
|
|
||||||
lua_setfield(context->luaState, -2, "__newindex");
|
|
||||||
lua_pushcfunction(context->luaState, moduleVec3ToString);
|
|
||||||
lua_setfield(context->luaState, -2, "__tostring");
|
|
||||||
}
|
|
||||||
lua_pop(context->luaState, 1);
|
|
||||||
|
|
||||||
if(luaL_newmetatable(context->luaState, "vec4_mt")) {
|
|
||||||
// Metatable methods
|
|
||||||
lua_pushcfunction(context->luaState, moduleVec4Index);
|
|
||||||
lua_setfield(context->luaState, -2, "__index");
|
|
||||||
lua_pushcfunction(context->luaState, moduleVec4NewIndex);
|
|
||||||
lua_setfield(context->luaState, -2, "__newindex");
|
|
||||||
lua_pushcfunction(context->luaState, moduleVec4ToString);
|
|
||||||
lua_setfield(context->luaState, -2, "__tostring");
|
|
||||||
}
|
|
||||||
lua_pop(context->luaState, 1);
|
|
||||||
|
|
||||||
lua_register(context->luaState, "vec3", moduleVec3Create);
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
int moduleVec3Create(lua_State *l) {
|
|
||||||
assertNotNull(l, "Lua state cannot be NULL.");
|
|
||||||
|
|
||||||
vec3 *v = (vec3 *)lua_newuserdata(l, sizeof(vec3));
|
|
||||||
memoryZero(v, sizeof(vec3));
|
|
||||||
|
|
||||||
// May be expecting between 1 and 3 values.
|
|
||||||
int top = lua_gettop(l);
|
|
||||||
if(top >= 1) {
|
|
||||||
if(!lua_isnumber(l, 1)) {
|
|
||||||
luaL_error(l, "Vec3 x component must be a number.");
|
|
||||||
}
|
|
||||||
(*v)[0] = (float_t)lua_tonumber(l, 1);
|
|
||||||
}
|
|
||||||
if(top >= 2) {
|
|
||||||
if(!lua_isnumber(l, 2)) {
|
|
||||||
luaL_error(l, "Vec3 y component must be a number.");
|
|
||||||
}
|
|
||||||
(*v)[1] = (float_t)lua_tonumber(l, 2);
|
|
||||||
}
|
|
||||||
if(top >= 3) {
|
|
||||||
if(!lua_isnumber(l, 3)) {
|
|
||||||
luaL_error(l, "Vec3 z component must be a number.");
|
|
||||||
}
|
|
||||||
(*v)[2] = (float_t)lua_tonumber(l, 3);
|
|
||||||
}
|
|
||||||
|
|
||||||
// Set metatable
|
|
||||||
luaL_getmetatable(l, "vec3_mt");
|
|
||||||
lua_setmetatable(l, -2);
|
|
||||||
|
|
||||||
return 1;
|
|
||||||
}
|
|
||||||
|
|
||||||
int moduleVec3Index(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.");
|
|
||||||
|
|
||||||
vec3 *vec = (vec3 *)luaL_checkudata(l, 1, "vec3_mt");
|
|
||||||
assertNotNull(vec, "Vec3 pointer cannot be NULL.");
|
|
||||||
|
|
||||||
if(stringCompare(key, "x") == 0) {
|
|
||||||
lua_pushnumber(l, (*vec)[0]);
|
|
||||||
return 1;
|
|
||||||
} else if(stringCompare(key, "y") == 0) {
|
|
||||||
lua_pushnumber(l, (*vec)[1]);
|
|
||||||
return 1;
|
|
||||||
} else if(stringCompare(key, "z") == 0) {
|
|
||||||
lua_pushnumber(l, (*vec)[2]);
|
|
||||||
return 1;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
int moduleVec3NewIndex(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.");
|
|
||||||
|
|
||||||
vec3 *vec = (vec3 *)luaL_checkudata(l, 1, "vec3_mt");
|
|
||||||
assertNotNull(vec, "Vec3 pointer cannot be NULL.");
|
|
||||||
|
|
||||||
if(stringCompare(key, "x") == 0) {
|
|
||||||
if(!lua_isnumber(l, 3)) {
|
|
||||||
luaL_error(l, "Vec3 x component must be a number.");
|
|
||||||
}
|
|
||||||
(*vec)[0] = (float_t)lua_tonumber(l, 3);
|
|
||||||
return 0;
|
|
||||||
} else if(stringCompare(key, "y") == 0) {
|
|
||||||
if(!lua_isnumber(l, 3)) {
|
|
||||||
luaL_error(l, "Vec3 y component must be a number.");
|
|
||||||
}
|
|
||||||
(*vec)[1] = (float_t)lua_tonumber(l, 3);
|
|
||||||
return 0;
|
|
||||||
} else if(stringCompare(key, "z") == 0) {
|
|
||||||
if(!lua_isnumber(l, 3)) {
|
|
||||||
luaL_error(l, "Vec3 z component must be a number.");
|
|
||||||
}
|
|
||||||
(*vec)[2] = (float_t)lua_tonumber(l, 3);
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
luaL_error(l, "Invalid key for vec3: %s", key);
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
int moduleVec3ToString(lua_State *l) {
|
|
||||||
assertNotNull(l, "Lua state cannot be NULL.");
|
|
||||||
|
|
||||||
vec3 *vec = (vec3 *)luaL_checkudata(l, 1, "vec3_mt");
|
|
||||||
assertNotNull(vec, "Vec3 pointer cannot be NULL.");
|
|
||||||
|
|
||||||
char buf[128];
|
|
||||||
snprintf(
|
|
||||||
buf, sizeof(buf),
|
|
||||||
"vec3(%.3f, %.3f, %.3f)",
|
|
||||||
(*vec)[0], (*vec)[1], (*vec)[2]
|
|
||||||
);
|
|
||||||
lua_pushstring(l, buf);
|
|
||||||
|
|
||||||
return 1;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
int moduleVec4Create(lua_State *l) {
|
|
||||||
assertNotNull(l, "Lua state cannot be NULL.");
|
|
||||||
|
|
||||||
vec4 *v = (vec4 *)lua_newuserdata(l, sizeof(vec4));
|
|
||||||
memoryZero(v, sizeof(vec4));
|
|
||||||
|
|
||||||
// May be expecting between 1 and 4 values.
|
|
||||||
int top = lua_gettop(l);
|
|
||||||
if(top >= 1) {
|
|
||||||
if(!lua_isnumber(l, 1)) {
|
|
||||||
luaL_error(l, "Vec4 x component must be a number.");
|
|
||||||
}
|
|
||||||
(*v)[0] = (float_t)lua_tonumber(l, 1);
|
|
||||||
}
|
|
||||||
if(top >= 2) {
|
|
||||||
if(!lua_isnumber(l, 2)) {
|
|
||||||
luaL_error(l, "Vec4 y component must be a number.");
|
|
||||||
}
|
|
||||||
(*v)[1] = (float_t)lua_tonumber(l, 2);
|
|
||||||
}
|
|
||||||
if(top >= 3) {
|
|
||||||
if(!lua_isnumber(l, 3)) {
|
|
||||||
luaL_error(l, "Vec4 z component must be a number.");
|
|
||||||
}
|
|
||||||
(*v)[2] = (float_t)lua_tonumber(l, 3);
|
|
||||||
}
|
|
||||||
if(top >= 4) {
|
|
||||||
if(!lua_isnumber(l, 4)) {
|
|
||||||
luaL_error(l, "Vec4 w component must be a number.");
|
|
||||||
}
|
|
||||||
(*v)[3] = (float_t)lua_tonumber(l, 4);
|
|
||||||
}
|
|
||||||
|
|
||||||
// Set metatable
|
|
||||||
luaL_getmetatable(l, "vec4_mt");
|
|
||||||
lua_setmetatable(l, -2);
|
|
||||||
|
|
||||||
return 1;
|
|
||||||
}
|
|
||||||
|
|
||||||
int moduleVec4Index(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.");
|
|
||||||
|
|
||||||
vec4 *vec = (vec4 *)luaL_checkudata(l, 1, "vec4_mt");
|
|
||||||
assertNotNull(vec, "Vec4 pointer cannot be NULL.");
|
|
||||||
|
|
||||||
if(stringCompare(key, "x") == 0) {
|
|
||||||
lua_pushnumber(l, (*vec)[0]);
|
|
||||||
return 1;
|
|
||||||
} else if(stringCompare(key, "y") == 0) {
|
|
||||||
lua_pushnumber(l, (*vec)[1]);
|
|
||||||
return 1;
|
|
||||||
} else if(stringCompare(key, "z") == 0) {
|
|
||||||
lua_pushnumber(l, (*vec)[2]);
|
|
||||||
return 1;
|
|
||||||
} else if(stringCompare(key, "w") == 0) {
|
|
||||||
lua_pushnumber(l, (*vec)[3]);
|
|
||||||
return 1;
|
|
||||||
} else if(stringCompare(key, "u0") == 0) {
|
|
||||||
lua_pushnumber(l, (*vec)[0]);
|
|
||||||
return 1;
|
|
||||||
} else if(stringCompare(key, "v0") == 0) {
|
|
||||||
lua_pushnumber(l, (*vec)[1]);
|
|
||||||
return 1;
|
|
||||||
} else if(stringCompare(key, "u1") == 0) {
|
|
||||||
lua_pushnumber(l, (*vec)[2]);
|
|
||||||
return 1;
|
|
||||||
} else if(stringCompare(key, "v1") == 0) {
|
|
||||||
lua_pushnumber(l, (*vec)[3]);
|
|
||||||
return 1;
|
|
||||||
}
|
|
||||||
|
|
||||||
lua_pushnil(l);
|
|
||||||
return 1;
|
|
||||||
}
|
|
||||||
|
|
||||||
int moduleVec4NewIndex(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.");
|
|
||||||
|
|
||||||
vec4 *vec = (vec4 *)luaL_checkudata(l, 1, "vec4_mt");
|
|
||||||
assertNotNull(vec, "Vec4 pointer cannot be NULL.");
|
|
||||||
|
|
||||||
if(stringCompare(key, "x") == 0) {
|
|
||||||
if(!lua_isnumber(l, 3)) {
|
|
||||||
luaL_error(l, "Vec4 x component must be a number.");
|
|
||||||
}
|
|
||||||
(*vec)[0] = (float_t)lua_tonumber(l, 3);
|
|
||||||
return 0;
|
|
||||||
} else if(stringCompare(key, "y") == 0) {
|
|
||||||
if(!lua_isnumber(l, 3)) {
|
|
||||||
luaL_error(l, "Vec4 y component must be a number.");
|
|
||||||
}
|
|
||||||
(*vec)[1] = (float_t)lua_tonumber(l, 3);
|
|
||||||
return 0;
|
|
||||||
} else if(stringCompare(key, "z") == 0) {
|
|
||||||
if(!lua_isnumber(l, 3)) {
|
|
||||||
luaL_error(l, "Vec4 z component must be a number.");
|
|
||||||
}
|
|
||||||
(*vec)[2] = (float_t)lua_tonumber(l, 3);
|
|
||||||
return 0;
|
|
||||||
} else if(stringCompare(key, "w") == 0) {
|
|
||||||
if(!lua_isnumber(l, 3)) {
|
|
||||||
luaL_error(l, "Vec4 w component must be a number.");
|
|
||||||
}
|
|
||||||
(*vec)[3] = (float_t)lua_tonumber(l, 3);
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
luaL_error(l, "Invalid key for vec4: %s", key);
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
int moduleVec4ToString(lua_State *l) {
|
|
||||||
assertNotNull(l, "Lua state cannot be NULL.");
|
|
||||||
|
|
||||||
vec4 *vec = (vec4 *)luaL_checkudata(l, 1, "vec4_mt");
|
|
||||||
assertNotNull(vec, "Vec4 pointer cannot be NULL.");
|
|
||||||
|
|
||||||
char buf[128];
|
|
||||||
snprintf(
|
|
||||||
buf, sizeof(buf),
|
|
||||||
"vec4(%.3f, %.3f, %.3f, %.3f)",
|
|
||||||
(*vec)[0], (*vec)[1], (*vec)[2], (*vec)[3]
|
|
||||||
);
|
|
||||||
lua_pushstring(l, buf);
|
|
||||||
|
|
||||||
return 1;
|
|
||||||
}
|
|
||||||
@@ -1,80 +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"
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Registers the GLM module with the given script context.
|
|
||||||
*
|
|
||||||
* @param context The script context to register the module with.
|
|
||||||
*/
|
|
||||||
void moduleGLM(scriptcontext_t *context);
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Creates a new vec3 structure in Lua.
|
|
||||||
*
|
|
||||||
* @param l The Lua state.
|
|
||||||
* @return Number of return values on the Lua stack.
|
|
||||||
*/
|
|
||||||
int moduleVec3Create(lua_State *l);
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Lua __index metamethod for vec3 structure.
|
|
||||||
*
|
|
||||||
* @param l The Lua state.
|
|
||||||
* @return Number of return values on the Lua stack.
|
|
||||||
*/
|
|
||||||
int moduleVec3Index(lua_State *l);
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Lua __newindex metamethod for vec3 structure.
|
|
||||||
*
|
|
||||||
* @param l The Lua state.
|
|
||||||
* @return Number of return values on the Lua stack.
|
|
||||||
*/
|
|
||||||
int moduleVec3NewIndex(lua_State *l);
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Lua __tostring metamethod for vec3 structure.
|
|
||||||
*
|
|
||||||
* @param l The Lua state.
|
|
||||||
* @return Number of return values on the Lua stack.
|
|
||||||
*/
|
|
||||||
int moduleVec3ToString(lua_State *l);
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Creates a new vec4 structure in Lua.
|
|
||||||
*
|
|
||||||
* @param l The Lua state.
|
|
||||||
* @return Number of return values on the Lua stack.
|
|
||||||
*/
|
|
||||||
int moduleVec4Create(lua_State *l);
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Lua __index metamethod for vec4 structure.
|
|
||||||
*
|
|
||||||
* @param l The Lua state.
|
|
||||||
* @return Number of return values on the Lua stack.
|
|
||||||
*/
|
|
||||||
int moduleVec4Index(lua_State *l);
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Lua __newindex metamethod for vec4 structure.
|
|
||||||
*
|
|
||||||
* @param l The Lua state.
|
|
||||||
* @return Number of return values on the Lua stack.
|
|
||||||
*/
|
|
||||||
int moduleVec4NewIndex(lua_State *l);
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Lua __tostring metamethod for vec4 structure.
|
|
||||||
*
|
|
||||||
* @param l The Lua state.
|
|
||||||
* @return Number of return values on the Lua stack.
|
|
||||||
*/
|
|
||||||
int moduleVec4ToString(lua_State *l);
|
|
||||||
@@ -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;
|
|
||||||
}
|
|
||||||
@@ -1,40 +1,42 @@
|
|||||||
/**
|
/**
|
||||||
* Copyright (c) 2026 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 "script/scriptcontext.h"
|
#include "script/module/modulebase.h"
|
||||||
|
#include "display/screen/screen.h"
|
||||||
|
|
||||||
/**
|
static int moduleScreenGetWidth(lua_State *L) {
|
||||||
* Registers the Screen module with the given script context.
|
assertNotNull(L, "Lua state is null");
|
||||||
*
|
lua_pushnumber(L, SCREEN.width);
|
||||||
* @param context The script context to register the module with.
|
return 1;
|
||||||
*/
|
}
|
||||||
void moduleScreen(scriptcontext_t *context);
|
|
||||||
|
|
||||||
/**
|
static int moduleScreenGetHeight(lua_State *L) {
|
||||||
* Gets the current screen width.
|
assertNotNull(L, "Lua state is null");
|
||||||
*
|
lua_pushnumber(L, SCREEN.height);
|
||||||
* @param L The Lua state.
|
return 1;
|
||||||
* @return Count of return values.
|
}
|
||||||
*/
|
|
||||||
int moduleScreenGetWidth(lua_State *L);
|
|
||||||
|
|
||||||
/**
|
static int moduleScreenSetBackground(lua_State *L) {
|
||||||
* Gets the current screen height.
|
assertNotNull(L, "Lua state is null");
|
||||||
*
|
|
||||||
* @param L The Lua state.
|
|
||||||
* @return Count of return values.
|
|
||||||
*/
|
|
||||||
int moduleScreenGetHeight(lua_State *L);
|
|
||||||
|
|
||||||
/**
|
if(!lua_isuserdata(L, 1)) {
|
||||||
* Sets the screen background color.
|
luaL_error(L, "Screen background color must be a color struct");
|
||||||
*
|
return 0;
|
||||||
* @param L The Lua state.
|
}
|
||||||
* @return Count of return values.
|
|
||||||
*/
|
color_t *color = (color_t*)luaL_checkudata(L, 1, "color_mt");
|
||||||
int moduleScreenSetBackground(lua_State *L);
|
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);
|
||||||
|
}
|
||||||
|
|||||||
@@ -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;
|
|
||||||
}
|
|
||||||
@@ -1,42 +1,90 @@
|
|||||||
/**
|
/**
|
||||||
* Copyright (c) 2026 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 "script/scriptcontext.h"
|
#include "script/module/modulebase.h"
|
||||||
|
#include "display/shader/shader.h"
|
||||||
|
#include "display/shader/shaderunlit.h"
|
||||||
|
#include "script/module/math/modulemat4.h"
|
||||||
|
|
||||||
/**
|
static int moduleShaderBind(lua_State *l) {
|
||||||
* Register shader functions to the given script context.
|
assertNotNull(l, "Lua state cannot be NULL.");
|
||||||
*
|
shader_t *shader = (shader_t *)lua_touserdata(l, 1);
|
||||||
* @param context The script context to register shader functions to.
|
assertNotNull(shader, "Shader pointer cannot be NULL.");
|
||||||
*/
|
|
||||||
void moduleShader(scriptcontext_t *context);
|
|
||||||
|
|
||||||
/**
|
errorret_t ret = shaderBind(shader);
|
||||||
* Script binding for binding a shader.
|
if(ret.code != ERROR_OK) {
|
||||||
*
|
luaL_error(l, "Failed to bind shader: %s", ret.state->message);
|
||||||
* @param l The Lua state.
|
errorCatch(errorPrint(ret));
|
||||||
* @return Number of return values on the Lua stack.
|
return 0;
|
||||||
*/
|
}
|
||||||
int moduleShaderBind(lua_State *l);
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
static int moduleShaderSetMatrix(lua_State *l) {
|
||||||
* Script binding for setting a matrix uniform in a shader.
|
assertNotNull(l, "Lua state cannot be NULL.");
|
||||||
*
|
shader_t *shader = (shader_t *)lua_touserdata(l, 1);
|
||||||
* @param l The Lua state.
|
assertNotNull(shader, "Shader pointer cannot be NULL.");
|
||||||
* @return Number of return values on the Lua stack.
|
const char_t *uniformName = luaL_checkstring(l, 2);
|
||||||
*/
|
mat4 *mat = (mat4 *)luaL_checkudata(l, 3, "mat4_mt");
|
||||||
int moduleShaderSetMatrix(lua_State *l);
|
assertNotNull(mat, "Matrix pointer cannot be NULL.");
|
||||||
|
|
||||||
/**
|
errorret_t ret = shaderSetMatrix(shader, uniformName, *mat);
|
||||||
* Script binding for setting a texture uniform in a shader.
|
if(ret.code != ERROR_OK) {
|
||||||
*
|
luaL_error(l, "Failed to set shader matrix: %s", ret.state->message);
|
||||||
* @param l The Lua state.
|
errorCatch(errorPrint(ret));
|
||||||
* @return Number of return values on the Lua stack.
|
return 0;
|
||||||
*/
|
}
|
||||||
int moduleShaderSetTexture(lua_State *l);
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
errorret_t doThing();
|
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);
|
||||||
|
}
|
||||||
|
|||||||
@@ -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;
|
|
||||||
}
|
|
||||||
@@ -1,40 +1,71 @@
|
|||||||
/**
|
/**
|
||||||
* Copyright (c) 2026 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 "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"
|
||||||
|
|
||||||
/**
|
static int moduleSpriteBatchFlush(lua_State *L) {
|
||||||
* Register sprite batch functions to the given script context.
|
assertNotNull(L, "Lua state is null");
|
||||||
*
|
spriteBatchFlush();
|
||||||
* @param context The script context to register sprite batch functions to.
|
return 0;
|
||||||
*/
|
}
|
||||||
void moduleSpriteBatch(scriptcontext_t *context);
|
|
||||||
|
|
||||||
/**
|
static int moduleSpriteBatchClear(lua_State *L) {
|
||||||
* Script binding for flushing the sprite batch.
|
assertNotNull(L, "Lua state is null");
|
||||||
*
|
spriteBatchClear();
|
||||||
* @param L The Lua state.
|
return 0;
|
||||||
* @return Number of return values on the Lua stack.
|
}
|
||||||
*/
|
|
||||||
int moduleSpriteBatchFlush(lua_State *L);
|
|
||||||
|
|
||||||
/**
|
static int moduleSpriteBatchPush(lua_State *L) {
|
||||||
* Script binding for clearing the sprite batch.
|
assertNotNull(L, "Lua state is null");
|
||||||
*
|
|
||||||
* @param L The Lua state.
|
|
||||||
* @return Number of return values on the Lua stack.
|
|
||||||
*/
|
|
||||||
int moduleSpriteBatchClear(lua_State *L);
|
|
||||||
|
|
||||||
/**
|
vec2 min, max;
|
||||||
* Script binding for pushing a sprite to the sprite batch.
|
luaVec2Check(L, 1, min);
|
||||||
*
|
luaVec2Check(L, 2, max);
|
||||||
* @param L The Lua state.
|
|
||||||
* @return Number of return values on the Lua stack.
|
color_t *color = NULL;
|
||||||
*/
|
if(lua_gettop(L) < 3 || lua_isnil(L, 3)) {
|
||||||
int moduleSpriteBatchPush(lua_State *L);
|
// 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);
|
||||||
|
}
|
||||||
|
|||||||
@@ -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;
|
|
||||||
}
|
|
||||||
@@ -1,32 +1,72 @@
|
|||||||
/**
|
/**
|
||||||
* Copyright (c) 2026 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 "script/scriptcontext.h"
|
#include "script/module/modulebase.h"
|
||||||
|
#include "display/text/text.h"
|
||||||
|
#include "display/spritebatch/spritebatch.h"
|
||||||
|
#include "script/module/math/modulevec2.h"
|
||||||
|
|
||||||
/**
|
static int moduleTextDraw(lua_State *L) {
|
||||||
* Register text rendering functions to the given script context.
|
assertNotNull(L, "Lua state is null");
|
||||||
*
|
|
||||||
* @param context The script context to register text functions to.
|
|
||||||
*/
|
|
||||||
void moduleText(scriptcontext_t *context);
|
|
||||||
|
|
||||||
/**
|
vec2 pos; luaVec2Check(L, 1, pos);
|
||||||
* Script binding for drawing text.
|
|
||||||
*
|
|
||||||
* @param L The Lua state.
|
|
||||||
* @return Number of return values on the Lua stack.
|
|
||||||
*/
|
|
||||||
int moduleTextDraw(lua_State *L);
|
|
||||||
|
|
||||||
/**
|
if(!lua_isstring(L, 2)) {
|
||||||
* Script binding for measuring text dimensions.
|
return luaL_error(L, "Text to draw must be a string");
|
||||||
*
|
}
|
||||||
* @param L The Lua state.
|
const char_t *text = (const char_t *)lua_tostring(L, 2);
|
||||||
* @return Number of return values on the Lua stack.
|
|
||||||
*/
|
color_t *color = NULL;
|
||||||
int moduleTextMeasure(lua_State *L);
|
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);
|
||||||
|
}
|
||||||
|
|||||||
@@ -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;
|
|
||||||
}
|
|
||||||
@@ -1,15 +1,98 @@
|
|||||||
/**
|
/**
|
||||||
* Copyright (c) 2026 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 "script/scriptcontext.h"
|
#include "script/module/modulebase.h"
|
||||||
|
#include "display/texture/texture.h"
|
||||||
|
#include "asset/loader/display/assettextureloader.h"
|
||||||
|
|
||||||
void moduleTexture(scriptcontext_t *ctx);
|
static int moduleTextureIndex(lua_State *l) {
|
||||||
int moduleTextureIndex(lua_State *l);
|
assertNotNull(l, "Lua state cannot be NULL.");
|
||||||
int moduleTextureToString(lua_State *l);
|
|
||||||
int moduleTextureGC(lua_State *l);
|
texture_t *tex = (texture_t *)luaL_checkudata(l, 1, "texture_mt");
|
||||||
int moduleTextureLoad(lua_State *l);
|
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")) {
|
||||||
|
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_pop(L, 1);
|
||||||
|
|
||||||
|
lua_pushnumber(L, TEXTURE_FORMAT_RGBA);
|
||||||
|
lua_setglobal(L, "TEXTURE_FORMAT_RGBA");
|
||||||
|
|
||||||
|
lua_register(L, "textureLoad", moduleTextureLoad);
|
||||||
|
}
|
||||||
|
|||||||
@@ -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;
|
|
||||||
}
|
|
||||||
@@ -1,56 +1,108 @@
|
|||||||
/**
|
/**
|
||||||
* Copyright (c) 2026 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 "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"
|
||||||
|
|
||||||
/**
|
static int moduleTilesetIndex(lua_State *l) {
|
||||||
* Registers the tileset module in the scripting context.
|
assertNotNull(l, "Lua state cannot be NULL.");
|
||||||
*
|
const char_t *key = luaL_checkstring(l, 2);
|
||||||
* @param ctx The scripting context to register the module in.
|
assertNotNull(key, "Key cannot be NULL.");
|
||||||
*/
|
tileset_t *ts = (tileset_t *)luaL_checkudata(l, 1, "tileset_mt");
|
||||||
void moduleTileset(scriptcontext_t *ctx);
|
assertNotNull(ts, "Tileset pointer cannot be NULL.");
|
||||||
|
|
||||||
/**
|
if(stringCompare(key, "tileWidth") == 0) {
|
||||||
* __index metamethod for tileset userdata.
|
lua_pushnumber(l, ts->tileWidth); return 1;
|
||||||
*
|
} else if(stringCompare(key, "tileHeight") == 0) {
|
||||||
* @param l The Lua state.
|
lua_pushnumber(l, ts->tileHeight); return 1;
|
||||||
* @return The number of return values on the Lua stack.
|
} else if(stringCompare(key, "tileCount") == 0) {
|
||||||
*/
|
lua_pushnumber(l, ts->tileCount); return 1;
|
||||||
int moduleTilesetIndex(lua_State *l);
|
} 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);
|
||||||
* __tostring metamethod for tileset userdata.
|
return 1;
|
||||||
*
|
}
|
||||||
* @param l The Lua state.
|
|
||||||
* @return The number of return values on the Lua stack.
|
|
||||||
*/
|
|
||||||
int moduleTilesetToString(lua_State *l);
|
|
||||||
|
|
||||||
/**
|
static int moduleTilesetToString(lua_State *l) {
|
||||||
* Lua function to get the UV coordinates for a tile index in a tileset.
|
tileset_t *ts = (tileset_t *)luaL_checkudata(l, 1, "tileset_mt");
|
||||||
*
|
assertNotNull(ts, "Tileset pointer cannot be NULL.");
|
||||||
* @param l The Lua state.
|
lua_pushfstring(l, "Tileset: %dx%d tile, %d columns, %d rows",
|
||||||
* @return The number of return values on the Lua stack.
|
ts->tileWidth, ts->tileHeight, ts->columns, ts->rows
|
||||||
*/
|
);
|
||||||
int moduleTilesetTileGetUV(lua_State *l);
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
static int moduleTilesetTileGetUV(lua_State *l) {
|
||||||
* Lua function to get the UV coordinates for a tile position in a tileset.
|
assertNotNull(l, "Lua state cannot be NULL.");
|
||||||
*
|
tileset_t *ts = (tileset_t *)luaL_checkudata(l, 1, "tileset_mt");
|
||||||
* @param l The Lua state.
|
assertNotNull(ts, "Tileset pointer cannot be NULL.");
|
||||||
* @return The number of return values on the Lua stack.
|
uint16_t tileIndex = (uint16_t)luaL_checknumber(l, 2);
|
||||||
*/
|
vec4 uv; tilesetTileGetUV(ts, tileIndex, uv);
|
||||||
int moduleTilesetPositionGetUV(lua_State *l);
|
luaVec4Push(l, uv);
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
static int moduleTilesetPositionGetUV(lua_State *l) {
|
||||||
* Lua function to load a tileset from a texture and tile dimensions.
|
assertNotNull(l, "Lua state cannot be NULL.");
|
||||||
*
|
tileset_t *ts = (tileset_t *)luaL_checkudata(l, 1, "tileset_mt");
|
||||||
* @param l The Lua state.
|
assertNotNull(ts, "Tileset pointer cannot be NULL.");
|
||||||
* @return The number of return values on the Lua stack.
|
uint16_t column = (uint16_t)luaL_checknumber(l, 2);
|
||||||
*/
|
uint16_t row = (uint16_t)luaL_checknumber(l, 3);
|
||||||
int moduleTilesetLoad(lua_State *l);
|
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);
|
||||||
|
}
|
||||||
|
|||||||
@@ -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)
|
|
||||||
@@ -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
|
|
||||||
)
|
|
||||||
@@ -1,70 +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"
|
|
||||||
|
|
||||||
void moduleEntityCamera(scriptcontext_t *ctx) {
|
|
||||||
assertNotNull(ctx, "Script context cannot be NULL");
|
|
||||||
|
|
||||||
#define REG(name, func) lua_register(ctx->luaState, name, func)
|
|
||||||
REG("entityCameraAdd", moduleEntityCameraAdd);
|
|
||||||
REG("entityCameraGetZNear", moduleEntityCameraGetZNear);
|
|
||||||
REG("entityCameraSetZNear", moduleEntityCameraSetZNear);
|
|
||||||
REG("entityCameraGetZFar", moduleEntityCameraGetZFar);
|
|
||||||
REG("entityCameraSetZFar", moduleEntityCameraSetZFar);
|
|
||||||
#undef REG
|
|
||||||
}
|
|
||||||
|
|
||||||
int moduleEntityCameraAdd(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);
|
|
||||||
lua_pushnumber(L, (lua_Number)compId);
|
|
||||||
return 1;
|
|
||||||
}
|
|
||||||
|
|
||||||
int moduleEntityCameraGetZNear(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);
|
|
||||||
lua_pushnumber(L, (lua_Number)entityCameraGetZNear(entityId, compId));
|
|
||||||
return 1;
|
|
||||||
}
|
|
||||||
|
|
||||||
int moduleEntityCameraSetZNear(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);
|
|
||||||
float_t zNear = (float_t)luaL_checknumber(L, 3);
|
|
||||||
entityCameraSetZNear(entityId, compId, zNear);
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
int moduleEntityCameraGetZFar(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);
|
|
||||||
lua_pushnumber(L, (lua_Number)entityCameraGetZFar(entityId, compId));
|
|
||||||
return 1;
|
|
||||||
}
|
|
||||||
|
|
||||||
int moduleEntityCameraSetZFar(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);
|
|
||||||
float_t zFar = (float_t)luaL_checknumber(L, 3);
|
|
||||||
entityCameraSetZFar(entityId, compId, zFar);
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
@@ -1,17 +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"
|
|
||||||
|
|
||||||
void moduleEntityCamera(scriptcontext_t *ctx);
|
|
||||||
|
|
||||||
int moduleEntityCameraAdd(lua_State *L);
|
|
||||||
int moduleEntityCameraGetZNear(lua_State *L);
|
|
||||||
int moduleEntityCameraSetZNear(lua_State *L);
|
|
||||||
int moduleEntityCameraGetZFar(lua_State *L);
|
|
||||||
int moduleEntityCameraSetZFar(lua_State *L);
|
|
||||||
@@ -1,26 +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"
|
|
||||||
|
|
||||||
void moduleEntityMaterial(scriptcontext_t *ctx) {
|
|
||||||
assertNotNull(ctx, "Script context cannot be NULL");
|
|
||||||
|
|
||||||
lua_register(ctx->luaState, "entityMaterialAdd", moduleEntityMaterialAdd);
|
|
||||||
}
|
|
||||||
|
|
||||||
int moduleEntityMaterialAdd(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);
|
|
||||||
lua_pushnumber(L, (lua_Number)compId);
|
|
||||||
return 1;
|
|
||||||
}
|
|
||||||
@@ -1,13 +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"
|
|
||||||
|
|
||||||
void moduleEntityMaterial(scriptcontext_t *ctx);
|
|
||||||
|
|
||||||
int moduleEntityMaterialAdd(lua_State *L);
|
|
||||||
@@ -1,26 +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"
|
|
||||||
|
|
||||||
void moduleEntityMesh(scriptcontext_t *ctx) {
|
|
||||||
assertNotNull(ctx, "Script context cannot be NULL");
|
|
||||||
|
|
||||||
lua_register(ctx->luaState, "entityMeshAdd", moduleEntityMeshAdd);
|
|
||||||
}
|
|
||||||
|
|
||||||
int moduleEntityMeshAdd(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);
|
|
||||||
lua_pushnumber(L, (lua_Number)compId);
|
|
||||||
return 1;
|
|
||||||
}
|
|
||||||
@@ -1,140 +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"
|
|
||||||
|
|
||||||
void moduleEntityPosition(scriptcontext_t *ctx) {
|
|
||||||
assertNotNull(ctx, "Script context cannot be NULL");
|
|
||||||
|
|
||||||
#define REG(name, func) lua_register(ctx->luaState, name, func)
|
|
||||||
REG("entityPositionAdd", moduleEntityPositionAdd);
|
|
||||||
REG("entityPositionSetPosition", moduleEntityPositionSetPosition);
|
|
||||||
REG("entityPositionGetPosition", moduleEntityPositionGetPosition);
|
|
||||||
REG("entityPositionSetRotation", moduleEntityPositionSetRotation);
|
|
||||||
REG("entityPositionGetRotation", moduleEntityPositionGetRotation);
|
|
||||||
REG("entityPositionSetScale", moduleEntityPositionSetScale);
|
|
||||||
REG("entityPositionGetScale", moduleEntityPositionGetScale);
|
|
||||||
REG("entityPositionLookAt", moduleEntityPositionLookAt);
|
|
||||||
#undef REG
|
|
||||||
}
|
|
||||||
|
|
||||||
int moduleEntityPositionAdd(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);
|
|
||||||
lua_pushnumber(L, (lua_Number)compId);
|
|
||||||
return 1;
|
|
||||||
}
|
|
||||||
|
|
||||||
int moduleEntityPositionSetPosition(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);
|
|
||||||
vec3 pos = {
|
|
||||||
(float_t)luaL_checknumber(L, 3),
|
|
||||||
(float_t)luaL_checknumber(L, 4),
|
|
||||||
(float_t)luaL_checknumber(L, 5)
|
|
||||||
};
|
|
||||||
entityPositionSetPosition(entityId, compId, pos);
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
int moduleEntityPositionGetPosition(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);
|
|
||||||
vec3 pos;
|
|
||||||
entityPositionGetPosition(entityId, compId, pos);
|
|
||||||
lua_pushnumber(L, pos[0]);
|
|
||||||
lua_pushnumber(L, pos[1]);
|
|
||||||
lua_pushnumber(L, pos[2]);
|
|
||||||
return 3;
|
|
||||||
}
|
|
||||||
|
|
||||||
int moduleEntityPositionSetRotation(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);
|
|
||||||
vec3 rot = {
|
|
||||||
(float_t)luaL_checknumber(L, 3),
|
|
||||||
(float_t)luaL_checknumber(L, 4),
|
|
||||||
(float_t)luaL_checknumber(L, 5)
|
|
||||||
};
|
|
||||||
entityPositionSetRotation(entityId, compId, rot);
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
int moduleEntityPositionGetRotation(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);
|
|
||||||
vec3 rot;
|
|
||||||
entityPositionGetRotation(entityId, compId, rot);
|
|
||||||
lua_pushnumber(L, rot[0]);
|
|
||||||
lua_pushnumber(L, rot[1]);
|
|
||||||
lua_pushnumber(L, rot[2]);
|
|
||||||
return 3;
|
|
||||||
}
|
|
||||||
|
|
||||||
int moduleEntityPositionSetScale(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);
|
|
||||||
vec3 scale = {
|
|
||||||
(float_t)luaL_checknumber(L, 3),
|
|
||||||
(float_t)luaL_checknumber(L, 4),
|
|
||||||
(float_t)luaL_checknumber(L, 5)
|
|
||||||
};
|
|
||||||
entityPositionSetScale(entityId, compId, scale);
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
int moduleEntityPositionGetScale(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);
|
|
||||||
vec3 scale;
|
|
||||||
entityPositionGetScale(entityId, compId, scale);
|
|
||||||
lua_pushnumber(L, scale[0]);
|
|
||||||
lua_pushnumber(L, scale[1]);
|
|
||||||
lua_pushnumber(L, scale[2]);
|
|
||||||
return 3;
|
|
||||||
}
|
|
||||||
|
|
||||||
int moduleEntityPositionLookAt(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);
|
|
||||||
vec3 target = {
|
|
||||||
(float_t)luaL_checknumber(L, 3),
|
|
||||||
(float_t)luaL_checknumber(L, 4),
|
|
||||||
(float_t)luaL_checknumber(L, 5)
|
|
||||||
};
|
|
||||||
vec3 up = {
|
|
||||||
(float_t)luaL_checknumber(L, 6),
|
|
||||||
(float_t)luaL_checknumber(L, 7),
|
|
||||||
(float_t)luaL_checknumber(L, 8)
|
|
||||||
};
|
|
||||||
vec3 eye = {
|
|
||||||
(float_t)luaL_checknumber(L, 9),
|
|
||||||
(float_t)luaL_checknumber(L, 10),
|
|
||||||
(float_t)luaL_checknumber(L, 11)
|
|
||||||
};
|
|
||||||
entityPositionLookAt(entityId, compId, target, up, eye);
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
@@ -1,20 +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"
|
|
||||||
|
|
||||||
void moduleEntityPosition(scriptcontext_t *ctx);
|
|
||||||
|
|
||||||
int moduleEntityPositionAdd(lua_State *L);
|
|
||||||
int moduleEntityPositionSetPosition(lua_State *L);
|
|
||||||
int moduleEntityPositionGetPosition(lua_State *L);
|
|
||||||
int moduleEntityPositionSetRotation(lua_State *L);
|
|
||||||
int moduleEntityPositionGetRotation(lua_State *L);
|
|
||||||
int moduleEntityPositionSetScale(lua_State *L);
|
|
||||||
int moduleEntityPositionGetScale(lua_State *L);
|
|
||||||
int moduleEntityPositionLookAt(lua_State *L);
|
|
||||||
@@ -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;
|
|
||||||
}
|
|
||||||
@@ -6,27 +6,337 @@
|
|||||||
*/
|
*/
|
||||||
|
|
||||||
#pragma once
|
#pragma once
|
||||||
#include "script/scriptcontext.h"
|
#include "script/module/modulebase.h"
|
||||||
|
#include "entity/entity.h"
|
||||||
|
#include "entity/entitymanager.h"
|
||||||
|
#include "entity/component/display/entityposition.h"
|
||||||
|
#include "entity/component/display/entitycamera.h"
|
||||||
|
#include "entity/component/display/entitymesh.h"
|
||||||
|
#include "entity/component/display/entitymaterial.h"
|
||||||
|
|
||||||
/**
|
// ============================================================================
|
||||||
* Register the entity module within the given script context.
|
// Handles
|
||||||
*
|
// ============================================================================
|
||||||
* @param ctx The script context to register the module in.
|
|
||||||
*/
|
|
||||||
void moduleEntity(scriptcontext_t *ctx);
|
|
||||||
|
|
||||||
/**
|
typedef struct { entityid_t entityId; componentid_t compId; } entitypos_handle_t;
|
||||||
* Lua binding for entityManagerAdd - creates a new entity and returns its ID.
|
typedef struct { entityid_t entityId; componentid_t compId; } entitycam_handle_t;
|
||||||
*
|
typedef struct { entityid_t entityId; componentid_t compId; } entitymesh_handle_t;
|
||||||
* @param L The Lua state.
|
typedef struct { entityid_t entityId; componentid_t compId; } entitymat_handle_t;
|
||||||
* @return int Number of return values on the Lua stack.
|
|
||||||
*/
|
|
||||||
int moduleEntityAdd(lua_State *L);
|
|
||||||
|
|
||||||
/**
|
// ============================================================================
|
||||||
* Lua binding for entityDispose - disposes of an entity by its ID.
|
// entityPosition
|
||||||
*
|
// ============================================================================
|
||||||
* @param L The Lua state.
|
|
||||||
* @return int Number of return values on the Lua stack.
|
static int _posIndex(lua_State *L) {
|
||||||
*/
|
entitypos_handle_t *h = luaL_checkudata(L, 1, "entitypos_mt");
|
||||||
int moduleEntityRemove(lua_State *L);
|
const char *k = luaL_checkstring(L, 2);
|
||||||
|
vec3 v;
|
||||||
|
if(stringCompare(k, "x") == 0) {
|
||||||
|
entityPositionGetPosition(h->entityId, h->compId, v);
|
||||||
|
lua_pushnumber(L, v[0]); return 1;
|
||||||
|
} else if(stringCompare(k, "y") == 0) {
|
||||||
|
entityPositionGetPosition(h->entityId, h->compId, v);
|
||||||
|
lua_pushnumber(L, v[1]); return 1;
|
||||||
|
} else if(stringCompare(k, "z") == 0) {
|
||||||
|
entityPositionGetPosition(h->entityId, h->compId, v);
|
||||||
|
lua_pushnumber(L, v[2]); return 1;
|
||||||
|
} else if(stringCompare(k, "rotX") == 0) {
|
||||||
|
entityPositionGetRotation(h->entityId, h->compId, v);
|
||||||
|
lua_pushnumber(L, v[0]); return 1;
|
||||||
|
} else if(stringCompare(k, "rotY") == 0) {
|
||||||
|
entityPositionGetRotation(h->entityId, h->compId, v);
|
||||||
|
lua_pushnumber(L, v[1]); return 1;
|
||||||
|
} else if(stringCompare(k, "rotZ") == 0) {
|
||||||
|
entityPositionGetRotation(h->entityId, h->compId, v);
|
||||||
|
lua_pushnumber(L, v[2]); return 1;
|
||||||
|
} else if(stringCompare(k, "scaleX") == 0) {
|
||||||
|
entityPositionGetScale(h->entityId, h->compId, v);
|
||||||
|
lua_pushnumber(L, v[0]); return 1;
|
||||||
|
} else if(stringCompare(k, "scaleY") == 0) {
|
||||||
|
entityPositionGetScale(h->entityId, h->compId, v);
|
||||||
|
lua_pushnumber(L, v[1]); return 1;
|
||||||
|
} else if(stringCompare(k, "scaleZ") == 0) {
|
||||||
|
entityPositionGetScale(h->entityId, h->compId, v);
|
||||||
|
lua_pushnumber(L, v[2]); return 1;
|
||||||
|
}
|
||||||
|
lua_getmetatable(L, 1);
|
||||||
|
lua_getfield(L, -1, k);
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int _posNewindex(lua_State *L) {
|
||||||
|
entitypos_handle_t *h = luaL_checkudata(L, 1, "entitypos_mt");
|
||||||
|
const char *k = luaL_checkstring(L, 2);
|
||||||
|
vec3 v;
|
||||||
|
if(stringCompare(k, "x") == 0) {
|
||||||
|
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(k, "y") == 0) {
|
||||||
|
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(k, "z") == 0) {
|
||||||
|
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(k, "rotX") == 0) {
|
||||||
|
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(k, "rotY") == 0) {
|
||||||
|
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(k, "rotZ") == 0) {
|
||||||
|
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(k, "scaleX") == 0) {
|
||||||
|
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(k, "scaleY") == 0) {
|
||||||
|
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(k, "scaleZ") == 0) {
|
||||||
|
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, "entitypos: unknown property '%s'", k);
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int _posLookAt(lua_State *L) {
|
||||||
|
entitypos_handle_t *h = luaL_checkudata(L, 1, "entitypos_mt");
|
||||||
|
vec3 target = {
|
||||||
|
(float_t)luaL_checknumber(L, 2),
|
||||||
|
(float_t)luaL_checknumber(L, 3),
|
||||||
|
(float_t)luaL_checknumber(L, 4)
|
||||||
|
};
|
||||||
|
vec3 up = { 0.0f, 1.0f, 0.0f };
|
||||||
|
if(lua_gettop(L) >= 7) {
|
||||||
|
up[0] = (float_t)luaL_checknumber(L, 5);
|
||||||
|
up[1] = (float_t)luaL_checknumber(L, 6);
|
||||||
|
up[2] = (float_t)luaL_checknumber(L, 7);
|
||||||
|
}
|
||||||
|
vec3 eye;
|
||||||
|
entityPositionGetPosition(h->entityId, h->compId, eye);
|
||||||
|
entityPositionLookAt(h->entityId, h->compId, target, up, eye);
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int _entityPositionAdd(lua_State *L) {
|
||||||
|
entityid_t id = (entityid_t)luaL_checknumber(L, 1);
|
||||||
|
componentid_t comp = entityAddComponent(id, COMPONENT_TYPE_POSITION);
|
||||||
|
entitypos_handle_t *h = lua_newuserdata(L, sizeof(entitypos_handle_t));
|
||||||
|
h->entityId = id;
|
||||||
|
h->compId = comp;
|
||||||
|
luaL_getmetatable(L, "entitypos_mt");
|
||||||
|
lua_setmetatable(L, -2);
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
// ============================================================================
|
||||||
|
// entityCamera
|
||||||
|
// ============================================================================
|
||||||
|
|
||||||
|
static int _camIndex(lua_State *L) {
|
||||||
|
entitycam_handle_t *h = luaL_checkudata(L, 1, "entitycam_mt");
|
||||||
|
const char *k = luaL_checkstring(L, 2);
|
||||||
|
if(stringCompare(k, "zNear") == 0) {
|
||||||
|
lua_pushnumber(L, entityCameraGetZNear(h->entityId, h->compId)); return 1;
|
||||||
|
} else if(stringCompare(k, "zFar") == 0) {
|
||||||
|
lua_pushnumber(L, entityCameraGetZFar(h->entityId, h->compId)); return 1;
|
||||||
|
}
|
||||||
|
lua_getmetatable(L, 1); lua_getfield(L, -1, k); return 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int _camNewindex(lua_State *L) {
|
||||||
|
entitycam_handle_t *h = luaL_checkudata(L, 1, "entitycam_mt");
|
||||||
|
const char *k = luaL_checkstring(L, 2);
|
||||||
|
if(stringCompare(k, "zNear") == 0) {
|
||||||
|
entityCameraSetZNear(h->entityId, h->compId, (float_t)luaL_checknumber(L, 3));
|
||||||
|
return 0;
|
||||||
|
} else if(stringCompare(k, "zFar") == 0) {
|
||||||
|
entityCameraSetZFar(h->entityId, h->compId, (float_t)luaL_checknumber(L, 3));
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
luaL_error(L, "entitycam: unknown property '%s'", k); return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int _entityCameraAdd(lua_State *L) {
|
||||||
|
entityid_t id = (entityid_t)luaL_checknumber(L, 1);
|
||||||
|
componentid_t comp = entityAddComponent(id, COMPONENT_TYPE_CAMERA);
|
||||||
|
entitycam_handle_t *h = lua_newuserdata(L, sizeof(entitycam_handle_t));
|
||||||
|
h->entityId = id; h->compId = comp;
|
||||||
|
luaL_getmetatable(L, "entitycam_mt"); lua_setmetatable(L, -2);
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
// ============================================================================
|
||||||
|
// entityMesh
|
||||||
|
// ============================================================================
|
||||||
|
|
||||||
|
static int _meshIndex(lua_State *L) {
|
||||||
|
lua_getmetatable(L, 1); lua_getfield(L, -1, luaL_checkstring(L, 2)); return 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int _meshGeneratePlane(lua_State *L) {
|
||||||
|
entitymesh_handle_t *h = luaL_checkudata(L, 1, "entitymesh_mt");
|
||||||
|
float_t w = (float_t)luaL_checknumber(L, 2);
|
||||||
|
float_t d = (float_t)luaL_checknumber(L, 3);
|
||||||
|
errorret_t err = entityMeshGeneratePlane(h->entityId, h->compId, w, d);
|
||||||
|
if(err.code != ERROR_OK) luaL_error(L, "entityMesh: generatePlane failed");
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int _meshGenerateCapsule(lua_State *L) {
|
||||||
|
entitymesh_handle_t *h = luaL_checkudata(L, 1, "entitymesh_mt");
|
||||||
|
float_t r = (float_t)luaL_checknumber(L, 2);
|
||||||
|
float_t hh = (float_t)luaL_checknumber(L, 3);
|
||||||
|
errorret_t err = entityMeshGenerateCapsule(h->entityId, h->compId, r, hh);
|
||||||
|
if(err.code != ERROR_OK) luaL_error(L, "entityMesh: generateCapsule failed");
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int _entityMeshAdd(lua_State *L) {
|
||||||
|
entityid_t id = (entityid_t)luaL_checknumber(L, 1);
|
||||||
|
componentid_t comp = entityAddComponent(id, COMPONENT_TYPE_MESH);
|
||||||
|
entitymesh_handle_t *h = lua_newuserdata(L, sizeof(entitymesh_handle_t));
|
||||||
|
h->entityId = id; h->compId = comp;
|
||||||
|
luaL_getmetatable(L, "entitymesh_mt"); lua_setmetatable(L, -2);
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
// ============================================================================
|
||||||
|
// entityMaterial
|
||||||
|
// ============================================================================
|
||||||
|
|
||||||
|
static int _matIndex(lua_State *L) {
|
||||||
|
lua_getmetatable(L, 1); lua_getfield(L, -1, luaL_checkstring(L, 2)); return 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int _matNewindex(lua_State *L) {
|
||||||
|
entitymat_handle_t *h = luaL_checkudata(L, 1, "entitymat_mt");
|
||||||
|
const char *k = luaL_checkstring(L, 2);
|
||||||
|
if(stringCompare(k, "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, "entitymat: unknown property '%s'", k); return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int _entityMaterialAdd(lua_State *L) {
|
||||||
|
entityid_t id = (entityid_t)luaL_checknumber(L, 1);
|
||||||
|
componentid_t comp = entityAddComponent(id, COMPONENT_TYPE_MATERIAL);
|
||||||
|
entitymat_handle_t *h = lua_newuserdata(L, sizeof(entitymat_handle_t));
|
||||||
|
h->entityId = id; h->compId = comp;
|
||||||
|
luaL_getmetatable(L, "entitymat_mt"); lua_setmetatable(L, -2);
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
// ============================================================================
|
||||||
|
// Component type Lua constants (auto-generated from componentlist.h)
|
||||||
|
// ============================================================================
|
||||||
|
|
||||||
|
#define X(enumName, type, field, init, dispose) \
|
||||||
|
"COMPONENT_TYPE_" #enumName " = \"" #field "\"\n"
|
||||||
|
static const char_t *COMPONENT_TYPE_SCRIPT =
|
||||||
|
#include "entity/componentlist.h"
|
||||||
|
;
|
||||||
|
#undef X
|
||||||
|
|
||||||
|
// ============================================================================
|
||||||
|
// Entity base class Lua script
|
||||||
|
// ============================================================================
|
||||||
|
|
||||||
|
static const char_t *ENTITY_SCRIPT =
|
||||||
|
"Entity = {}\n"
|
||||||
|
"Entity.__index = Entity\n"
|
||||||
|
"\n"
|
||||||
|
"Entity.POSITION = COMPONENT_TYPE_POSITION\n"
|
||||||
|
"Entity.CAMERA = COMPONENT_TYPE_CAMERA\n"
|
||||||
|
"Entity.MESH = COMPONENT_TYPE_MESH\n"
|
||||||
|
"Entity.MATERIAL = COMPONENT_TYPE_MATERIAL\n"
|
||||||
|
"Entity.PHYSICS = COMPONENT_TYPE_PHYSICS\n"
|
||||||
|
"\n"
|
||||||
|
"local _addFns = {\n"
|
||||||
|
" [COMPONENT_TYPE_POSITION] = entityPositionAdd,\n"
|
||||||
|
" [COMPONENT_TYPE_CAMERA] = entityCameraAdd,\n"
|
||||||
|
" [COMPONENT_TYPE_MESH] = entityMeshAdd,\n"
|
||||||
|
" [COMPONENT_TYPE_MATERIAL] = entityMaterialAdd,\n"
|
||||||
|
"}\n"
|
||||||
|
"\n"
|
||||||
|
"function Entity.new()\n"
|
||||||
|
" return setmetatable({ id = entityAdd() }, Entity)\n"
|
||||||
|
"end\n"
|
||||||
|
"\n"
|
||||||
|
"function Entity:add(componentType)\n"
|
||||||
|
" local fn = _addFns[componentType]\n"
|
||||||
|
" if not fn then error('unknown component type: ' .. tostring(componentType)) end\n"
|
||||||
|
" self[componentType] = fn(self.id)\n"
|
||||||
|
" return self[componentType]\n"
|
||||||
|
"end\n"
|
||||||
|
"\n"
|
||||||
|
"function Entity:dispose()\n"
|
||||||
|
" entityRemove(self.id)\n"
|
||||||
|
"end\n"
|
||||||
|
;
|
||||||
|
|
||||||
|
// ============================================================================
|
||||||
|
// entityAdd / entityRemove
|
||||||
|
// ============================================================================
|
||||||
|
|
||||||
|
static int _entityAdd(lua_State *L) {
|
||||||
|
lua_pushnumber(L, (lua_Number)entityManagerAdd());
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int _entityRemove(lua_State *L) {
|
||||||
|
entityDispose((entityid_t)luaL_checknumber(L, 1));
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
// ============================================================================
|
||||||
|
// Register
|
||||||
|
// ============================================================================
|
||||||
|
|
||||||
|
static void moduleEntity(lua_State *L) {
|
||||||
|
assertNotNull(L, "Lua state cannot be NULL");
|
||||||
|
|
||||||
|
luaL_newmetatable(L, "entitypos_mt");
|
||||||
|
lua_pushcfunction(L, _posIndex); lua_setfield(L, -2, "__index");
|
||||||
|
lua_pushcfunction(L, _posNewindex); lua_setfield(L, -2, "__newindex");
|
||||||
|
lua_pushcfunction(L, _posLookAt); lua_setfield(L, -2, "lookAt");
|
||||||
|
lua_pop(L, 1);
|
||||||
|
|
||||||
|
luaL_newmetatable(L, "entitycam_mt");
|
||||||
|
lua_pushcfunction(L, _camIndex); lua_setfield(L, -2, "__index");
|
||||||
|
lua_pushcfunction(L, _camNewindex); lua_setfield(L, -2, "__newindex");
|
||||||
|
lua_pop(L, 1);
|
||||||
|
|
||||||
|
luaL_newmetatable(L, "entitymesh_mt");
|
||||||
|
lua_pushcfunction(L, _meshIndex); lua_setfield(L, -2, "__index");
|
||||||
|
lua_pushcfunction(L, _meshGeneratePlane); lua_setfield(L, -2, "generatePlane");
|
||||||
|
lua_pushcfunction(L, _meshGenerateCapsule); lua_setfield(L, -2, "generateCapsule");
|
||||||
|
lua_pop(L, 1);
|
||||||
|
|
||||||
|
luaL_newmetatable(L, "entitymat_mt");
|
||||||
|
lua_pushcfunction(L, _matIndex); lua_setfield(L, -2, "__index");
|
||||||
|
lua_pushcfunction(L, _matNewindex); lua_setfield(L, -2, "__newindex");
|
||||||
|
lua_pop(L, 1);
|
||||||
|
|
||||||
|
lua_register(L, "entityAdd", _entityAdd);
|
||||||
|
lua_register(L, "entityRemove", _entityRemove);
|
||||||
|
lua_register(L, "entityPositionAdd", _entityPositionAdd);
|
||||||
|
lua_register(L, "entityCameraAdd", _entityCameraAdd);
|
||||||
|
lua_register(L, "entityMeshAdd", _entityMeshAdd);
|
||||||
|
lua_register(L, "entityMaterialAdd", _entityMaterialAdd);
|
||||||
|
|
||||||
|
luaL_dostring(L, COMPONENT_TYPE_SCRIPT);
|
||||||
|
luaL_dostring(L, ENTITY_SCRIPT);
|
||||||
|
}
|
||||||
|
|||||||
@@ -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
|
|
||||||
)
|
|
||||||
@@ -1,140 +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"
|
|
||||||
|
|
||||||
void moduleEntityPhysics(scriptcontext_t *ctx) {
|
|
||||||
assertNotNull(ctx, "Script context cannot be NULL");
|
|
||||||
|
|
||||||
#define REG(name, func) lua_register(ctx->luaState, name, func)
|
|
||||||
REG("entityPhysicsAdd", moduleEntityPhysicsAdd);
|
|
||||||
REG("entityPhysicsSetVelocity", moduleEntityPhysicsSetVelocity);
|
|
||||||
REG("entityPhysicsGetVelocity", moduleEntityPhysicsGetVelocity);
|
|
||||||
REG("entityPhysicsApplyImpulse", moduleEntityPhysicsApplyImpulse);
|
|
||||||
REG("entityPhysicsIsOnGround", moduleEntityPhysicsIsOnGround);
|
|
||||||
REG("entityPhysicsSetShapeCube", moduleEntityPhysicsSetShapeCube);
|
|
||||||
REG("entityPhysicsSetShapeSphere", moduleEntityPhysicsSetShapeSphere);
|
|
||||||
REG("entityPhysicsSetShapeCapsule", moduleEntityPhysicsSetShapeCapsule);
|
|
||||||
REG("entityPhysicsSetShapePlane", moduleEntityPhysicsSetShapePlane);
|
|
||||||
#undef REG
|
|
||||||
}
|
|
||||||
|
|
||||||
int moduleEntityPhysicsAdd(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);
|
|
||||||
lua_pushnumber(L, (lua_Number)compId);
|
|
||||||
return 1;
|
|
||||||
}
|
|
||||||
|
|
||||||
int moduleEntityPhysicsSetVelocity(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);
|
|
||||||
vec3 vel = {
|
|
||||||
(float_t)luaL_checknumber(L, 3),
|
|
||||||
(float_t)luaL_checknumber(L, 4),
|
|
||||||
(float_t)luaL_checknumber(L, 5)
|
|
||||||
};
|
|
||||||
entityPhysicsSetVelocity(entityId, compId, vel);
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
int moduleEntityPhysicsGetVelocity(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);
|
|
||||||
vec3 vel;
|
|
||||||
entityPhysicsGetVelocity(entityId, compId, vel);
|
|
||||||
lua_pushnumber(L, vel[0]);
|
|
||||||
lua_pushnumber(L, vel[1]);
|
|
||||||
lua_pushnumber(L, vel[2]);
|
|
||||||
return 3;
|
|
||||||
}
|
|
||||||
|
|
||||||
int moduleEntityPhysicsApplyImpulse(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);
|
|
||||||
vec3 impulse = {
|
|
||||||
(float_t)luaL_checknumber(L, 3),
|
|
||||||
(float_t)luaL_checknumber(L, 4),
|
|
||||||
(float_t)luaL_checknumber(L, 5)
|
|
||||||
};
|
|
||||||
entityPhysicsApplyImpulse(entityId, compId, impulse);
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
int moduleEntityPhysicsIsOnGround(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);
|
|
||||||
lua_pushboolean(L, (int)entityPhysicsIsOnGround(entityId, compId));
|
|
||||||
return 1;
|
|
||||||
}
|
|
||||||
|
|
||||||
int moduleEntityPhysicsSetShapeCube(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);
|
|
||||||
physicsshape_t shape;
|
|
||||||
shape.type = PHYSICS_SHAPE_CUBE;
|
|
||||||
shape.data.cube.halfExtents[0] = (float_t)luaL_checknumber(L, 3);
|
|
||||||
shape.data.cube.halfExtents[1] = (float_t)luaL_checknumber(L, 4);
|
|
||||||
shape.data.cube.halfExtents[2] = (float_t)luaL_checknumber(L, 5);
|
|
||||||
entityPhysicsSetShape(entityId, compId, shape);
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
int moduleEntityPhysicsSetShapeSphere(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);
|
|
||||||
physicsshape_t shape;
|
|
||||||
shape.type = PHYSICS_SHAPE_SPHERE;
|
|
||||||
shape.data.sphere.radius = (float_t)luaL_checknumber(L, 3);
|
|
||||||
entityPhysicsSetShape(entityId, compId, shape);
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
int moduleEntityPhysicsSetShapeCapsule(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);
|
|
||||||
physicsshape_t shape;
|
|
||||||
shape.type = PHYSICS_SHAPE_CAPSULE;
|
|
||||||
shape.data.capsule.radius = (float_t)luaL_checknumber(L, 3);
|
|
||||||
shape.data.capsule.halfHeight = (float_t)luaL_checknumber(L, 4);
|
|
||||||
entityPhysicsSetShape(entityId, compId, shape);
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
int moduleEntityPhysicsSetShapePlane(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);
|
|
||||||
physicsshape_t shape;
|
|
||||||
shape.type = PHYSICS_SHAPE_PLANE;
|
|
||||||
shape.data.plane.normal[0] = (float_t)luaL_checknumber(L, 3);
|
|
||||||
shape.data.plane.normal[1] = (float_t)luaL_checknumber(L, 4);
|
|
||||||
shape.data.plane.normal[2] = (float_t)luaL_checknumber(L, 5);
|
|
||||||
shape.data.plane.distance = (float_t)luaL_checknumber(L, 6);
|
|
||||||
entityPhysicsSetShape(entityId, compId, shape);
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
@@ -1,21 +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"
|
|
||||||
|
|
||||||
void moduleEntityPhysics(scriptcontext_t *ctx);
|
|
||||||
|
|
||||||
int moduleEntityPhysicsAdd(lua_State *L);
|
|
||||||
int moduleEntityPhysicsSetVelocity(lua_State *L);
|
|
||||||
int moduleEntityPhysicsGetVelocity(lua_State *L);
|
|
||||||
int moduleEntityPhysicsApplyImpulse(lua_State *L);
|
|
||||||
int moduleEntityPhysicsIsOnGround(lua_State *L);
|
|
||||||
int moduleEntityPhysicsSetShapeCube(lua_State *L);
|
|
||||||
int moduleEntityPhysicsSetShapeSphere(lua_State *L);
|
|
||||||
int moduleEntityPhysicsSetShapeCapsule(lua_State *L);
|
|
||||||
int moduleEntityPhysicsSetShapePlane(lua_State *L);
|
|
||||||
@@ -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
|
|
||||||
)
|
|
||||||
@@ -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;
|
|
||||||
}
|
|
||||||
@@ -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"
|
|
||||||
|
|
||||||
void moduleEntityScript(scriptcontext_t *ctx);
|
|
||||||
|
|
||||||
int moduleEntityScriptAdd(lua_State *L);
|
|
||||||
int moduleEntityScriptSetScript(lua_State *L);
|
|
||||||
int moduleEntityScriptUpdate(lua_State *L);
|
|
||||||
int moduleEntityAddScripted(lua_State *L);
|
|
||||||
@@ -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
|
|
||||||
)
|
|
||||||
@@ -1,45 +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;
|
|
||||||
}
|
|
||||||
|
|
||||||
void moduleEvent(scriptcontext_t *context) {
|
|
||||||
// Reg functions
|
|
||||||
lua_register(context->luaState, "eventSubscribe", moduleEventSubscribe);
|
|
||||||
}
|
|
||||||
@@ -1,21 +1,58 @@
|
|||||||
/**
|
/**
|
||||||
* Copyright (c) 2026 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 "script/scriptcontext.h"
|
#include "script/module/modulebase.h"
|
||||||
|
#include "event/event.h"
|
||||||
|
|
||||||
/**
|
static int moduleEventSubscribe(lua_State *L) {
|
||||||
* Register event functions to the given script context.
|
assertNotNull(L, "Lua state cannot be NULL");
|
||||||
*
|
|
||||||
* @param context The script context to register event functions to.
|
|
||||||
*/
|
|
||||||
void moduleEvent(scriptcontext_t *context);
|
|
||||||
|
|
||||||
/**
|
scriptcontext_t *context = *(scriptcontext_t **)lua_getextraspace(L);
|
||||||
* Script binding for subscribing to an event.
|
assertNotNull(context, "Script context cannot be NULL");
|
||||||
*/
|
|
||||||
int moduleEventSubscribe(lua_State *L);
|
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);
|
||||||
|
}
|
||||||
|
|||||||
@@ -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
|
|
||||||
)
|
|
||||||
@@ -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;
|
|
||||||
}
|
|
||||||
@@ -1,71 +1,206 @@
|
|||||||
/**
|
/**
|
||||||
* Copyright (c) 2025 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
|
||||||
*/
|
*/
|
||||||
|
|
||||||
#pragma once
|
#pragma once
|
||||||
#include "script/scriptcontext.h"
|
#include "script/module/modulebase.h"
|
||||||
|
#include "input/input.h"
|
||||||
|
|
||||||
/**
|
static int moduleInputIndex(lua_State *l) {
|
||||||
* Register input functions to the given script context.
|
assertNotNull(l, "Lua state cannot be NULL");
|
||||||
*
|
|
||||||
* @param context The script context to register input functions to.
|
|
||||||
*/
|
|
||||||
void moduleInput(scriptcontext_t *context);
|
|
||||||
|
|
||||||
/**
|
const char_t *key = luaL_checkstring(l, 2);
|
||||||
* Getter for input structure fields.
|
assertStrLenMin(key, 1, "Key cannot be empty.");
|
||||||
*
|
|
||||||
* @param l The Lua state.
|
|
||||||
*/
|
|
||||||
int moduleInputIndex(lua_State *l);
|
|
||||||
|
|
||||||
/**
|
if(stringCompare(key, "action") == 0) {
|
||||||
* Script binding for binding an input button to an action.
|
const inputevent_t *event = (const inputevent_t*)lua_touserdata(l, 1);
|
||||||
*
|
if(event == NULL) {
|
||||||
* @param L The Lua state.
|
luaL_error(l, "Expected input event as first argument");
|
||||||
* @return Number of return values on the Lua stack.
|
return 0;
|
||||||
*/
|
}
|
||||||
int moduleInputBind(lua_State *L);
|
lua_pushnumber(l, event->action);
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
lua_pushnil(l);
|
||||||
* Script binding for checking if an input action is currently pressed.
|
return 1;
|
||||||
*
|
}
|
||||||
* @param L The Lua state.
|
|
||||||
* @return Number of return values on the Lua stack.
|
|
||||||
*/
|
|
||||||
int moduleInputIsDown(lua_State *L);
|
|
||||||
|
|
||||||
/**
|
static int moduleInputBind(lua_State *L) {
|
||||||
* Script binding for checking if an input action was pressed this frame.
|
assertNotNull(L, "Lua state cannot be NULL");
|
||||||
*
|
|
||||||
* @param L The Lua state.
|
|
||||||
* @return Number of return values on the Lua stack.
|
|
||||||
*/
|
|
||||||
int moduleInputPressed(lua_State *L);
|
|
||||||
|
|
||||||
/**
|
if(!lua_isstring(L, 1)) {
|
||||||
* Script binding for checking if an input action was released this frame.
|
luaL_error(L, "inputBind: Expected button name as first argument");
|
||||||
*
|
return 0;
|
||||||
* @param L The Lua state.
|
}
|
||||||
* @return Number of return values on the Lua stack.
|
|
||||||
*/
|
|
||||||
int moduleInputReleased(lua_State *L);
|
|
||||||
|
|
||||||
/**
|
if(!lua_isnumber(L, 2)) {
|
||||||
* Script binding for getting the value of an input axis.
|
luaL_error(L, "inputBind: Expected action ID as second argument");
|
||||||
*
|
return 0;
|
||||||
* @param L The Lua state.
|
}
|
||||||
* @return Number of return values on the Lua stack.
|
|
||||||
*/
|
|
||||||
int moduleInputGetValue(lua_State *L);
|
|
||||||
|
|
||||||
/**
|
const char_t *strBtn = lua_tostring(L, 1);
|
||||||
* Script binding for inputAxis.
|
const inputaction_t action = (inputaction_t)lua_tonumber(L, 2);
|
||||||
*
|
|
||||||
* @param L The Lua state.
|
if(strBtn == NULL || strlen(strBtn) == 0) {
|
||||||
* @return Number of return values on the Lua stack.
|
luaL_error(L, "inputBind: Button name cannot be NULL or empty");
|
||||||
*/
|
return 0;
|
||||||
int moduleInputAxis(lua_State *L);
|
}
|
||||||
|
|
||||||
|
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);
|
||||||
|
}
|
||||||
|
|||||||
@@ -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
|
|
||||||
)
|
|
||||||
@@ -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;
|
|
||||||
}
|
|
||||||
@@ -1,24 +1,85 @@
|
|||||||
/**
|
/**
|
||||||
* Copyright (c) 2026 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 "script/scriptcontext.h"
|
#include "script/module/modulebase.h"
|
||||||
|
#include "locale/localemanager.h"
|
||||||
|
|
||||||
/**
|
static int moduleLocaleGetText(lua_State *L) {
|
||||||
* Register locale functions to the given script context.
|
if(!lua_isstring(L, 1)) {
|
||||||
*
|
luaL_error(L, "Expected message ID as first argument");
|
||||||
* @param context The script context to register locale functions to.
|
return 0;
|
||||||
*/
|
}
|
||||||
void moduleLocale(scriptcontext_t *context);
|
|
||||||
|
|
||||||
/**
|
const char_t *id = lua_tostring(L, 1);
|
||||||
* Script binding for getting a localized string.
|
if(id == NULL || strlen(id) == 0) {
|
||||||
*
|
luaL_error(L, "Message ID cannot be NULL or empty");
|
||||||
* @param L The Lua state.
|
return 0;
|
||||||
* @return The number of return values on the Lua stack.
|
}
|
||||||
*/
|
|
||||||
int moduleLocaleGetText(lua_State *L);
|
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_tonumber(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);
|
||||||
|
}
|
||||||
|
|||||||
@@ -0,0 +1,117 @@
|
|||||||
|
/**
|
||||||
|
* Copyright (c) 2026 Dominic Masters
|
||||||
|
*
|
||||||
|
* This software is released under the MIT License.
|
||||||
|
* https://opensource.org/licenses/MIT
|
||||||
|
*/
|
||||||
|
|
||||||
|
#pragma once
|
||||||
|
#include "script/module/modulebase.h"
|
||||||
|
#include "modulevec3.h"
|
||||||
|
#include "modulevec4.h"
|
||||||
|
|
||||||
|
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);
|
||||||
|
}
|
||||||
@@ -0,0 +1,21 @@
|
|||||||
|
/**
|
||||||
|
* Copyright (c) 2026 Dominic Masters
|
||||||
|
*
|
||||||
|
* This software is released under the MIT License.
|
||||||
|
* https://opensource.org/licenses/MIT
|
||||||
|
*/
|
||||||
|
|
||||||
|
#pragma once
|
||||||
|
#include "script/module/modulebase.h"
|
||||||
|
#include "modulevec2.h"
|
||||||
|
#include "modulevec3.h"
|
||||||
|
#include "modulevec4.h"
|
||||||
|
#include "modulemat4.h"
|
||||||
|
|
||||||
|
static void moduleMath(lua_State *L) {
|
||||||
|
assertNotNull(L, "Lua state cannot be NULL");
|
||||||
|
moduleMathVec2(L);
|
||||||
|
moduleMathVec3(L);
|
||||||
|
moduleMathVec4(L);
|
||||||
|
moduleMathMat4(L);
|
||||||
|
}
|
||||||
@@ -0,0 +1,169 @@
|
|||||||
|
/**
|
||||||
|
* Copyright (c) 2026 Dominic Masters
|
||||||
|
*
|
||||||
|
* This software is released under the MIT License.
|
||||||
|
* https://opensource.org/licenses/MIT
|
||||||
|
*/
|
||||||
|
|
||||||
|
#pragma once
|
||||||
|
#include "script/module/modulebase.h"
|
||||||
|
|
||||||
|
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);
|
||||||
|
}
|
||||||
@@ -0,0 +1,180 @@
|
|||||||
|
/**
|
||||||
|
* Copyright (c) 2026 Dominic Masters
|
||||||
|
*
|
||||||
|
* This software is released under the MIT License.
|
||||||
|
* https://opensource.org/licenses/MIT
|
||||||
|
*/
|
||||||
|
|
||||||
|
#pragma once
|
||||||
|
#include "script/module/modulebase.h"
|
||||||
|
|
||||||
|
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);
|
||||||
|
}
|
||||||
@@ -0,0 +1,168 @@
|
|||||||
|
/**
|
||||||
|
* Copyright (c) 2026 Dominic Masters
|
||||||
|
*
|
||||||
|
* This software is released under the MIT License.
|
||||||
|
* https://opensource.org/licenses/MIT
|
||||||
|
*/
|
||||||
|
|
||||||
|
#pragma once
|
||||||
|
#include "script/module/modulebase.h"
|
||||||
|
|
||||||
|
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);
|
||||||
|
}
|
||||||
@@ -0,0 +1,45 @@
|
|||||||
|
/**
|
||||||
|
* 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/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);
|
||||||
|
moduleLocale(L);
|
||||||
|
moduleTime(L);
|
||||||
|
moduleEvent(L);
|
||||||
|
moduleColor(L);
|
||||||
|
moduleSpriteBatch(L);
|
||||||
|
moduleMath(L);
|
||||||
|
moduleShader(L);
|
||||||
|
moduleUi(L);
|
||||||
|
moduleText(L);
|
||||||
|
moduleScreen(L);
|
||||||
|
moduleTexture(L);
|
||||||
|
moduleTileset(L);
|
||||||
|
}
|
||||||
+4
-5
@@ -1,13 +1,12 @@
|
|||||||
/**
|
/**
|
||||||
* Copyright (c) 2026 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 "script/scriptcontext.h"
|
#include "script/scriptcontext.h"
|
||||||
|
#include "assert/assert.h"
|
||||||
void moduleEntityMesh(scriptcontext_t *ctx);
|
#include "util/string.h"
|
||||||
|
#include "util/memory.h"
|
||||||
int moduleEntityMeshAdd(lua_State *L);
|
|
||||||
@@ -16,12 +16,12 @@
|
|||||||
|
|
||||||
#define MODULE_PLATFORM_VALUE "PLATFORM = '" DUSK_TARGET_SYSTEM "'\n"
|
#define MODULE_PLATFORM_VALUE "PLATFORM = '" DUSK_TARGET_SYSTEM "'\n"
|
||||||
|
|
||||||
void modulePlatform(scriptcontext_t *ctx) {
|
static void modulePlatform(lua_State *L) {
|
||||||
assertNotNull(ctx, "Script context cannot be NULL");
|
assertNotNull(L, "Lua state cannot be NULL");
|
||||||
|
|
||||||
scriptContextExec(ctx, MODULE_PLATFORM_VALUE);
|
luaL_dostring(L, MODULE_PLATFORM_VALUE);
|
||||||
|
|
||||||
#ifdef modulePlatformPlatform
|
#ifdef modulePlatformPlatform
|
||||||
modulePlatformPlatform(ctx);
|
modulePlatformPlatform(L);
|
||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
@@ -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
|
|
||||||
)
|
|
||||||
@@ -1,32 +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);
|
|
||||||
}
|
|
||||||
|
|
||||||
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;
|
|
||||||
}
|
|
||||||
@@ -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 "script/scriptcontext.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);
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 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);
|
|
||||||
@@ -0,0 +1,82 @@
|
|||||||
|
/**
|
||||||
|
* Copyright (c) 2025 Dominic Masters
|
||||||
|
*
|
||||||
|
* This software is released under the MIT License.
|
||||||
|
* https://opensource.org/licenses/MIT
|
||||||
|
*/
|
||||||
|
|
||||||
|
#pragma once
|
||||||
|
#include "script/module/modulebase.h"
|
||||||
|
#include "console/console.h"
|
||||||
|
|
||||||
|
static int moduleScriptPrint(lua_State *L) {
|
||||||
|
assertNotNull(L, "Lua state cannot be NULL");
|
||||||
|
|
||||||
|
int n = lua_gettop(L);
|
||||||
|
luaL_Buffer b;
|
||||||
|
luaL_buffinit(L, &b);
|
||||||
|
|
||||||
|
for(int i = 1; i <= n; ++i) {
|
||||||
|
size_t len;
|
||||||
|
const char *s = luaL_tolstring(L, i, &len);
|
||||||
|
luaL_addlstring(&b, s, len);
|
||||||
|
lua_pop(L, 1);
|
||||||
|
if(i < n) luaL_addlstring(&b, "\t", 1);
|
||||||
|
}
|
||||||
|
|
||||||
|
luaL_pushresult(&b);
|
||||||
|
const char *msg = lua_tostring(L, -1);
|
||||||
|
consolePrint("%s", msg);
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int moduleScriptInclude(lua_State *L) {
|
||||||
|
assertNotNull(L, "Lua state cannot be NULL");
|
||||||
|
|
||||||
|
if(!lua_isstring(L, 1)) {
|
||||||
|
luaL_error(L, "Expected string filename");
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
scriptcontext_t* ctx = *(scriptcontext_t**)lua_getextraspace(L);
|
||||||
|
if(ctx == NULL) {
|
||||||
|
luaL_error(L, "Script context is NULL");
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
const char_t *filename = luaL_checkstring(L, 1);
|
||||||
|
if(filename == NULL || filename[0] == '\0') {
|
||||||
|
luaL_error(L, "Filename cannot be NULL");
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
char_t buffer[1024];
|
||||||
|
stringCopy(buffer, filename, 1024);
|
||||||
|
|
||||||
|
size_t len = strlen(buffer);
|
||||||
|
if(len < 4 || stringCompare(&buffer[len - 4], ".lua") != 0) {
|
||||||
|
if(len + 4 >= 1024) {
|
||||||
|
luaL_error(L, "Filename too long to append .lua");
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
stringCopy(&buffer[len], ".lua", 5);
|
||||||
|
}
|
||||||
|
|
||||||
|
int32_t stackBase = lua_gettop(L);
|
||||||
|
|
||||||
|
errorret_t err = scriptContextExecFile(ctx, buffer);
|
||||||
|
if(err.code != ERROR_OK) {
|
||||||
|
luaL_error(L, "Failed to include script file: %s", buffer);
|
||||||
|
errorCatch(errorPrint(err));
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
return lua_gettop(L) - stackBase;
|
||||||
|
}
|
||||||
|
|
||||||
|
static void moduleScript(lua_State *L) {
|
||||||
|
assertNotNull(L, "Lua state cannot be NULL");
|
||||||
|
|
||||||
|
lua_register(L, "print", moduleScriptPrint);
|
||||||
|
lua_register(L, "include", moduleScriptInclude);
|
||||||
|
}
|
||||||
@@ -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
|
|
||||||
)
|
|
||||||
@@ -1,121 +0,0 @@
|
|||||||
/**
|
|
||||||
* Copyright (c) 2025 Dominic Masters
|
|
||||||
*
|
|
||||||
* This software is released under the MIT License.
|
|
||||||
* https://opensource.org/licenses/MIT
|
|
||||||
*/
|
|
||||||
|
|
||||||
#include "modulescript.h"
|
|
||||||
#include "assert/assert.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) {
|
|
||||||
assertNotNull(L, "Lua state cannot be NULL");
|
|
||||||
|
|
||||||
int n = lua_gettop(L);
|
|
||||||
luaL_Buffer b;
|
|
||||||
luaL_buffinit(L, &b);
|
|
||||||
|
|
||||||
for(int i = 1; i <= n; ++i) {
|
|
||||||
size_t len;
|
|
||||||
const char *s = luaL_tolstring(L, i, &len);
|
|
||||||
luaL_addlstring(&b, s, len);
|
|
||||||
lua_pop(L, 1);
|
|
||||||
if(i < n) luaL_addlstring(&b, "\t", 1);
|
|
||||||
}
|
|
||||||
|
|
||||||
luaL_pushresult(&b);
|
|
||||||
const char *msg = lua_tostring(L, -1);
|
|
||||||
consolePrint("%s", msg);
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
int moduleScriptInclude(lua_State *L) {
|
|
||||||
assertNotNull(L, "Lua state cannot be NULL");
|
|
||||||
|
|
||||||
if(!lua_isstring(L, 1)) {
|
|
||||||
luaL_error(L, "Expected string filename");
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
scriptcontext_t* ctx = *(scriptcontext_t**)lua_getextraspace(L);
|
|
||||||
if(ctx == NULL) {
|
|
||||||
luaL_error(L, "Script context is NULL");
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
const char_t *filename = luaL_checkstring(L, 1);
|
|
||||||
if(filename == NULL || filename[0] == '\0') {
|
|
||||||
luaL_error(L, "Filename cannot be NULL");
|
|
||||||
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 >= 1024) {
|
|
||||||
luaL_error(L, "Filename too long to append .lua");
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
stringCopy(&buffer[len], ".lua", 5);
|
|
||||||
}
|
|
||||||
|
|
||||||
// Execute the script file
|
|
||||||
errorret_t err = scriptContextExecFile(
|
|
||||||
ctx,
|
|
||||||
buffer
|
|
||||||
);
|
|
||||||
if(err.code != ERROR_OK) {
|
|
||||||
luaL_error(L, "Failed to include script file");
|
|
||||||
errorCatch(errorPrint(err));
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
int moduleScriptModule(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;
|
|
||||||
}
|
|
||||||
@@ -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);
|
|
||||||
@@ -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
|
|
||||||
)
|
|
||||||
@@ -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;
|
|
||||||
}
|
|
||||||
@@ -1,25 +1,41 @@
|
|||||||
/**
|
/**
|
||||||
* Copyright (c) 2026 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 "script/scriptcontext.h"
|
#include "script/module/modulebase.h"
|
||||||
#include "time/time.h"
|
#include "time/time.h"
|
||||||
#include "util/string.h"
|
|
||||||
|
|
||||||
/**
|
static int moduleTimeIndex(lua_State *L) {
|
||||||
* Registers the time module within the given script context.
|
const char_t *key = lua_tostring(L, 2);
|
||||||
*
|
assertStrLenMin(key, 1, "Key cannot be empty.");
|
||||||
* @param ctx The script context to register the module in.
|
|
||||||
*/
|
|
||||||
void moduleTime(scriptcontext_t *ctx);
|
|
||||||
|
|
||||||
/**
|
if(stringCompare(key, "delta") == 0) {
|
||||||
* Index function for the time structure.
|
lua_pushnumber(L, TIME.delta);
|
||||||
* @param L The Lua state.
|
return 1;
|
||||||
* @return Number of return values.
|
} else if(stringCompare(key, "time") == 0) {
|
||||||
*/
|
lua_pushnumber(L, TIME.time);
|
||||||
int moduleTimeIndex(lua_State *L);
|
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");
|
||||||
|
}
|
||||||
|
|||||||
@@ -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
|
|
||||||
)
|
|
||||||
@@ -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");
|
|
||||||
|
|
||||||
}
|
|
||||||
@@ -1,17 +1,13 @@
|
|||||||
/**
|
/**
|
||||||
* Copyright (c) 2026 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 "script/scriptcontext.h"
|
#include "script/module/modulebase.h"
|
||||||
#include "error/error.h"
|
|
||||||
|
|
||||||
/**
|
static void moduleUi(lua_State *L) {
|
||||||
* Registers the ui module within the given script context.
|
assertNotNull(L, "Lua state cannot be NULL");
|
||||||
*
|
}
|
||||||
* @param ctx The script context to register the module in.
|
|
||||||
*/
|
|
||||||
void moduleUi(scriptcontext_t *ctx);
|
|
||||||
|
|||||||
@@ -9,9 +9,13 @@
|
|||||||
#include "assert/assert.h"
|
#include "assert/assert.h"
|
||||||
#include "asset/asset.h"
|
#include "asset/asset.h"
|
||||||
#include "util/memory.h"
|
#include "util/memory.h"
|
||||||
#include "script/scriptmodule.h"
|
|
||||||
#include "event/event.h"
|
#include "event/event.h"
|
||||||
#include "asset/loader/script/assetscriptloader.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) {
|
errorret_t scriptContextInit(scriptcontext_t *context) {
|
||||||
assertNotNull(context, "Script context cannot be NULL");
|
assertNotNull(context, "Script context cannot be NULL");
|
||||||
@@ -27,13 +31,14 @@ errorret_t scriptContextInit(scriptcontext_t *context) {
|
|||||||
|
|
||||||
// Store context in Lua extraspace
|
// Store context in Lua extraspace
|
||||||
*(scriptcontext_t**)lua_getextraspace(context->luaState) = context;
|
*(scriptcontext_t**)lua_getextraspace(context->luaState) = context;
|
||||||
|
|
||||||
// All scripts get the script module
|
// Register built-in script modules.
|
||||||
const scriptmodule_t *sysScript = scriptModuleGetByName("script");
|
moduleRegister(context->luaState);
|
||||||
if(sysScript == NULL) {
|
|
||||||
errorThrow("Failed to find system script module");
|
// Fire any game script init function if defined.
|
||||||
}
|
#ifdef SCRIPT_GAME_INIT
|
||||||
sysScript->callback(context);
|
SCRIPT_GAME_INIT(L);
|
||||||
|
#endif
|
||||||
|
|
||||||
errorOk();
|
errorOk();
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -14,9 +14,13 @@ scriptmanager_t SCRIPT_MANAGER;
|
|||||||
|
|
||||||
errorret_t scriptManagerInit() {
|
errorret_t scriptManagerInit() {
|
||||||
memoryZero(&SCRIPT_MANAGER, sizeof(scriptmanager_t));
|
memoryZero(&SCRIPT_MANAGER, sizeof(scriptmanager_t));
|
||||||
|
|
||||||
|
errorChain(scriptContextInit(&SCRIPT_MANAGER.mainContext));
|
||||||
|
|
||||||
errorOk();
|
errorOk();
|
||||||
}
|
}
|
||||||
|
|
||||||
errorret_t scriptManagerDispose() {
|
errorret_t scriptManagerDispose() {
|
||||||
|
scriptContextDispose(&SCRIPT_MANAGER.mainContext);
|
||||||
errorOk();
|
errorOk();
|
||||||
}
|
}
|
||||||
@@ -1,79 +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/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("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;
|
|
||||||
}
|
|
||||||
@@ -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);
|
|
||||||
@@ -8,6 +8,6 @@
|
|||||||
#pragma once
|
#pragma once
|
||||||
#include "script/scriptcontext.h"
|
#include "script/scriptcontext.h"
|
||||||
|
|
||||||
void modulePlatformDolphin(scriptcontext_t *ctx) {
|
static void modulePlatformDolphin(lua_State *L) {
|
||||||
scriptContextExec(ctx, "DOLPHIN = true\n");
|
luaL_dostring(L, "DOLPHIN = true\n");
|
||||||
}
|
}
|
||||||
@@ -50,12 +50,20 @@ errorret_t assetInitLinux(void) {
|
|||||||
const char_t **path = ASSET_LINUX_SEARCH_PATHS;
|
const char_t **path = ASSET_LINUX_SEARCH_PATHS;
|
||||||
int32_t error;
|
int32_t error;
|
||||||
do {
|
do {
|
||||||
sprintf(
|
char_t temp[ASSET_FILE_PATH_MAX];
|
||||||
searchPath,
|
snprintf(
|
||||||
|
temp,
|
||||||
|
ASSET_FILE_PATH_MAX,
|
||||||
*path,
|
*path,
|
||||||
ASSET.platform.systemPath,
|
|
||||||
ASSET_FILE_NAME
|
ASSET_FILE_NAME
|
||||||
);
|
);
|
||||||
|
snprintf(
|
||||||
|
searchPath,
|
||||||
|
ASSET_FILE_PATH_MAX,
|
||||||
|
"%s/%s",
|
||||||
|
ASSET.platform.systemPath,
|
||||||
|
temp
|
||||||
|
);
|
||||||
|
|
||||||
// Try open
|
// Try open
|
||||||
ASSET.zip = zip_open(searchPath, ZIP_RDONLY, &error);
|
ASSET.zip = zip_open(searchPath, ZIP_RDONLY, &error);
|
||||||
|
|||||||
@@ -10,7 +10,6 @@
|
|||||||
#include "asset/assetfile.h"
|
#include "asset/assetfile.h"
|
||||||
|
|
||||||
static const char_t *ASSET_LINUX_SEARCH_PATHS[] = {
|
static const char_t *ASSET_LINUX_SEARCH_PATHS[] = {
|
||||||
"%s/%s",
|
|
||||||
"%s",
|
"%s",
|
||||||
"../%s",
|
"../%s",
|
||||||
"../../%s",
|
"../../%s",
|
||||||
|
|||||||
@@ -8,6 +8,6 @@
|
|||||||
#pragma once
|
#pragma once
|
||||||
#include "script/scriptcontext.h"
|
#include "script/scriptcontext.h"
|
||||||
|
|
||||||
void modulePlatformLinux(scriptcontext_t *ctx) {
|
static void modulePlatformLinux(lua_State *L) {
|
||||||
scriptContextExec(ctx, "LINUX = true\n");
|
luaL_dostring(L, "LINUX = true\n");
|
||||||
}
|
}
|
||||||
@@ -8,6 +8,6 @@
|
|||||||
#pragma once
|
#pragma once
|
||||||
#include "script/scriptcontext.h"
|
#include "script/scriptcontext.h"
|
||||||
|
|
||||||
void modulePlatformPSP(scriptcontext_t *ctx) {
|
void modulePlatformPSP(lua_State *L) {
|
||||||
scriptContextExec(ctx, "PSP = true\n");
|
luaL_dostring(L, "PSP = true\n");
|
||||||
}
|
}
|
||||||
@@ -3,8 +3,3 @@
|
|||||||
# 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
|
|
||||||
target_sources(${DUSK_LIBRARY_TARGET_NAME}
|
|
||||||
PUBLIC
|
|
||||||
moduleitem.c
|
|
||||||
)
|
|
||||||
@@ -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;
|
|
||||||
}
|
|
||||||
|
|
||||||
@@ -1,80 +1,241 @@
|
|||||||
/**
|
/**
|
||||||
* Copyright (c) 2026 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 "script/scriptcontext.h"
|
#include "script/scriptcontext.h"
|
||||||
|
#include "item/inventory.h"
|
||||||
|
#include "item/backpack.h"
|
||||||
|
#include "assert/assert.h"
|
||||||
|
|
||||||
/**
|
static int moduleInventoryItemExists(lua_State *L) {
|
||||||
* Register item functions to the given script context.
|
assertNotNull(L, "Lua state cannot be NULL");
|
||||||
*
|
|
||||||
* @param context The script context to register item functions to.
|
|
||||||
*/
|
|
||||||
void moduleItem(scriptcontext_t *context);
|
|
||||||
|
|
||||||
/**
|
if(!lua_islightuserdata(L, 1)) {
|
||||||
* Script binding for checking if an item exists in an inventory.
|
luaL_error(L, "inventoryItemExists: Expected inventory pointer as first argument");
|
||||||
*
|
return 0;
|
||||||
* @param L The Lua state.
|
}
|
||||||
* @return Number of return values on the Lua stack.
|
|
||||||
*/
|
|
||||||
int moduleInventoryItemExists(lua_State *L);
|
|
||||||
|
|
||||||
/**
|
if(!lua_isnumber(L, 2)) {
|
||||||
* Script binding for adding an item to an inventory.
|
luaL_error(L, "inventoryItemExists: Expected item ID as second argument");
|
||||||
*
|
return 0;
|
||||||
* @param L The Lua state.
|
}
|
||||||
* @return Number of return values on the Lua stack.
|
|
||||||
*/
|
|
||||||
int moduleInventorySet(lua_State *L);
|
|
||||||
|
|
||||||
/**
|
inventory_t *inventory = (inventory_t *)lua_touserdata(L, 1);
|
||||||
* Script binding for setting the quantity of an item in an inventory.
|
itemid_t item = (itemid_t)lua_tonumber(L, 2);
|
||||||
*
|
|
||||||
* @param L The Lua state.
|
|
||||||
* @return Number of return values on the Lua stack.
|
|
||||||
*/
|
|
||||||
int moduleInventoryAdd(lua_State *L);
|
|
||||||
|
|
||||||
/**
|
assertNotNull(inventory, "Inventory pointer cannot be NULL.");
|
||||||
* 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);
|
|
||||||
|
|
||||||
/**
|
if(item == ITEM_ID_NULL) {
|
||||||
* Script binding for getting the count of an item in an inventory.
|
luaL_error(L, "inventoryItemExists: Item ID cannot be ITEM_ID_NULL");
|
||||||
*
|
return 0;
|
||||||
* @param L The Lua state.
|
}
|
||||||
* @return Number of return values on the Lua stack.
|
|
||||||
*/
|
|
||||||
int moduleInventoryGetCount(lua_State *L);
|
|
||||||
|
|
||||||
/**
|
bool_t hasItem = inventoryItemExists(inventory, item);
|
||||||
* Script binding for checking if an inventory is full.
|
lua_pushboolean(L, hasItem);
|
||||||
*
|
return 1;
|
||||||
* @param L The Lua state.
|
}
|
||||||
* @return Number of return values on the Lua stack.
|
|
||||||
*/
|
|
||||||
int moduleInventoryIsFull(lua_State *L);
|
|
||||||
|
|
||||||
/**
|
static int moduleInventorySet(lua_State *L) {
|
||||||
* Script binding for checking if an item stack in an inventory is full.
|
assertNotNull(L, "Lua state cannot be NULL");
|
||||||
*
|
|
||||||
* @param L The Lua state.
|
|
||||||
* @return Number of return values on the Lua stack.
|
|
||||||
*/
|
|
||||||
int moduleInventoryItemFull(lua_State *L);
|
|
||||||
|
|
||||||
/**
|
if(!lua_islightuserdata(L, 1)) {
|
||||||
* Script binding for sorting an inventory.
|
luaL_error(L, "inventorySet: Expected inventory pointer as first argument");
|
||||||
*
|
return 0;
|
||||||
* @param L The Lua state.
|
}
|
||||||
* @return Number of return values on the Lua stack.
|
|
||||||
*/
|
if(!lua_isnumber(L, 2)) {
|
||||||
int moduleInventorySort(lua_State *L);
|
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);
|
||||||
|
}
|
||||||
|
|||||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user