// SONIC ROBO BLAST 2 //----------------------------------------------------------------------------- // Copyright (C) 2025 by LJ Sonic // // This program is free software distributed under the // terms of the GNU General Public License, version 2. // See the 'LICENSE' file for more details. //----------------------------------------------------------------------------- /// \file lua_matrixlib.c /// \brief matrix library for Lua scripting #include "m_fixed.h" #include "lua_script.h" #include "lua_libs.h" static vector3_t *GetVector(lua_State *L, int index) { vector3_t *vec = lua_touserdata(L, index); if (!vec) return NULL; if (!lua_getmetatable(L, index)) return NULL; lua_getfield(L, LUA_REGISTRYINDEX, META_VECTOR3); if (!lua_rawequal(L, -1, -2)) return NULL; lua_pop(L, 2); return vec; } static void GetVectorOrXYZ(lua_State *L, int index, vector3_t *result) { vector3_t *vec = GetVector(L, index); if (vec) { *result = *vec; } else { result->x = luaL_checkfixed(L, 1); result->y = luaL_checkfixed(L, 2); result->z = luaL_checkfixed(L, 3); } } static matrix_t *NewMatrix(lua_State *L) { matrix_t *mat = lua_newuserdata(L, sizeof(*mat)); luaL_getmetatable(L, META_MATRIX); lua_setmetatable(L, -2); return mat; } //////////////////// // STATIC MEMBERS // //////////////////// static int matrix_new(lua_State *L) { FM_LoadIdentity(NewMatrix(L)); return 1; } static int matrix_translation(lua_State *L) { vector3_t translation; GetVectorOrXYZ(L, 1, &translation); matrix_t *mat = NewMatrix(L); FM_LoadIdentity(mat); FM_Translate(mat, translation.x, translation.y, translation.z); return 1; } static int matrix_scaling(lua_State *L) { vector3_t scaling; GetVectorOrXYZ(L, 1, &scaling); FM_Scale(NewMatrix(L), scaling.x, scaling.y, scaling.z); return 1; } static luaL_Reg matrix[] = { {"new", matrix_new}, {"translation", matrix_translation}, {"scaling", matrix_scaling}, {NULL, NULL} }; ///////////// // MEMBERS // ///////////// enum matrixfield_e { matrixfield_clone = 0, matrixfield_getvalue, matrixfield_setvalue, matrixfield_mulXYZ, }; static const char *const matrixfield_opt[] = { "clone", "get", "set", "mulXYZ", NULL}; static int matrix_clone(lua_State *L) { matrix_t *mat = luaL_checkudata(L, 1, META_MATRIX); memcpy(NewMatrix(L), mat, sizeof(matrix_t)); return 1; } static int matrix_getvalue(lua_State *L) { matrix_t *mat = luaL_checkudata(L, 1, META_MATRIX); INT32 row = luaL_checkinteger(L, 2); INT32 col = luaL_checkinteger(L, 3); if (row < 1 || row > 4) return luaL_error(L, "matrix row %d out of range (1 - 4)", row); if (col < 1 || col > 4) return luaL_error(L, "matrix column %d out of range (1 - 4)", col); lua_pushfixed(L, mat->m[(col - 1) * 4 + row - 1]); return 1; } static int matrix_setvalue(lua_State *L) { matrix_t *mat = luaL_checkudata(L, 1, META_MATRIX); INT32 row = luaL_checkinteger(L, 2); INT32 col = luaL_checkinteger(L, 3); fixed_t value = luaL_checkfixed(L, 4); if (row < 1 || row > 4) return luaL_error(L, "matrix row %d out of range (1 - 4)", row); if (col < 1 || col > 4) return luaL_error(L, "matrix column %d out of range (1 - 4)", col); mat->m[(col - 1) * 4 + row - 1] = value; return 0; } static int matrix_mulXYZ(lua_State *L) { matrix_t *mat = luaL_checkudata(L, 1, META_MATRIX); fixed_t x = luaL_checkfixed(L, 2); fixed_t y = luaL_checkfixed(L, 3); fixed_t z = luaL_checkfixed(L, 4); vector3_t vec; vector3_t result; FV3_Load(&vec, x, y, z); FM_MultMatrixVec3(mat, &vec, &result); lua_pushfixed(L, result.x); lua_pushfixed(L, result.y); lua_pushfixed(L, result.z); return 3; } static int matrix_get(lua_State *L) { enum matrixfield_e field = luaL_checkoption(L, 2, matrixfield_opt[0], matrixfield_opt); switch(field) { case matrixfield_clone: lua_pushcfunction(L, matrix_clone); return 1; case matrixfield_getvalue: lua_pushcfunction(L, matrix_getvalue); return 1; case matrixfield_setvalue: lua_pushcfunction(L, matrix_setvalue); return 1; case matrixfield_mulXYZ: lua_pushcfunction(L, matrix_mulXYZ); return 1; default: break; } return 0; } /////////////// // OPERATORS // /////////////// static int matrix_mul(lua_State *L) { matrix_t *mat1 = luaL_checkudata(L, 1, META_MATRIX); vector3_t *vec2 = GetVector(L, 2); if (vec2) { vector3_t *result = lua_newuserdata(L, sizeof(*result)); luaL_getmetatable(L, META_VECTOR3); lua_setmetatable(L, -2); FM_MultMatrixVec3(mat1, vec2, result); } else { matrix_t *mat2 = luaL_checkudata(L, 2, META_MATRIX); FM_MultMatrixEx(mat1, mat2, NewMatrix(L)); } return 1; } int LUA_MatrixLib(lua_State *L) { luaL_newmetatable(L, META_MATRIX); LUA_SetCFunctionField(L, "__index", matrix_get); LUA_SetCFunctionField(L, "__mul", matrix_mul); lua_pop(L, 1); luaL_register(L, "Matrix", matrix); return 0; }