// 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_vectorlib.c /// \brief vector library for Lua scripting #include "m_fixed.h" #include "lua_script.h" #include "lua_libs.h" // shared by both Vector2D and Vector3D enum vectorfield_e { vectorfield_clone = 0, vectorfield_opposite, vectorfield_x, vectorfield_y, vectorfield_z, vectorfield_length, vectorfield_normalized, }; static const char *const vectorfield_opt[] = { "vector_clone", "vector_opposite", "x", "y", "z", "vector_length", "vector_normalized", NULL}; //////////////////////////// // VECTOR2 STATIC MEMBERS // //////////////////////////// ///////////////////// // VECTOR2 MEMBERS // ///////////////////// static int vector2d_get(lua_State *L) { vector2_t *vec = luaL_checkudata(L, 1, META_VECTOR2); enum vectorfield_e field = luaL_checkoption(L, 2, vectorfield_opt[0], vectorfield_opt); switch(field) { case vectorfield_x: lua_pushfixed(L, vec->x); return 1; case vectorfield_y: lua_pushfixed(L, vec->y); return 1; default: break; } return 0; } ///////////// // VECTOR3 // ///////////// static vector3_t *NewVector3(lua_State *L) { vector3_t *vec = lua_newuserdata(L, sizeof(*vec)); luaL_getmetatable(L, META_VECTOR3); lua_setmetatable(L, -2); return vec; } //////////////////////////// // VECTOR3 STATIC MEMBERS // //////////////////////////// static int vector3d_new(lua_State *L) { fixed_t x = luaL_checkfixed(L, 1); fixed_t y = luaL_checkfixed(L, 2); fixed_t z = luaL_optfixed(L, 3, 0); FV3_Load(NewVector3(L), x, y, z); return 1; } static luaL_Reg vector3d[] = { {"new", vector3d_new}, {NULL, NULL} }; ///////////////////// // VECTOR3 MEMBERS // ///////////////////// static int vector3d_clone(lua_State *L) { vector3_t *vec = luaL_checkudata(L, 1, META_VECTOR3); FV3_Copy(NewVector3(L), vec); return 1; } static int vector3d_opposite(lua_State *L) { vector3_t *vec = luaL_checkudata(L, 1, META_VECTOR3); FV3_NegateEx(vec, NewVector3(L)); return 1; } static int vector3d_get(lua_State *L) { vector3_t *vec = luaL_checkudata(L, 1, META_VECTOR3); enum vectorfield_e field = luaL_checkoption(L, 2, vectorfield_opt[0], vectorfield_opt); if (!vec) return luaL_error(L, "accessed vector3_t doesn't exist anymore."); vector3_t unit = { 0, 0, 0 }; switch(field) { case vectorfield_clone: lua_pushcfunction(L, vector3d_clone); return 1; case vectorfield_opposite: lua_pushcfunction(L, vector3d_opposite); return 1; case vectorfield_x: lua_pushfixed(L, vec->x); return 1; case vectorfield_y: lua_pushfixed(L, vec->y); return 1; case vectorfield_z: lua_pushfixed(L, vec->z); return 1; case vectorfield_length: lua_pushfixed(L, FV3_Distance(&unit, vec)); return 1; case vectorfield_normalized: FV3_NormalizeEx(vec, NewVector3(L)); return 1; default: break; } return 0; } /////////////////////// // VECTOR3 OPERATORS // /////////////////////// static int vector3d_eq(lua_State *L) { vector3_t *vec1 = luaL_checkudata(L, 1, META_VECTOR3); vector3_t *vec2 = luaL_checkudata(L, 2, META_VECTOR3); lua_pushboolean(L, FV3_Equal(vec1, vec2)); return 1; } static int vector3d_op( lua_State *L, vector3_t *(*opvector)(const vector3_t*, const vector3_t*, vector3_t*) ) { if (lua_isnumber(L, 1) && (opvector == FV3_AddEx || opvector == FV3_MulEx)) { fixed_t n1 = lua_tofixed(L, 1); vector3_t vec1 = { n1, n1, n1 }; vector3_t *vec2 = luaL_checkudata(L, 2, META_VECTOR3); opvector(NewVector3(L), vec2, &vec1); } else if (lua_isnumber(L, 2)) { vector3_t *vec1 = luaL_checkudata(L, 1, META_VECTOR3); fixed_t n2 = lua_tofixed(L, 2); vector3_t vec2 = { n2, n2, n2 }; opvector(NewVector3(L), vec1, &vec2); } else { vector3_t *vec1 = luaL_checkudata(L, 1, META_VECTOR3); vector3_t *vec2 = luaL_checkudata(L, 2, META_VECTOR3); opvector(NewVector3(L), vec1, vec2); } return 1; } static int vector3d_add(lua_State *L) { return vector3d_op(L, FV3_AddEx); } static int vector3d_sub(lua_State *L) { return vector3d_op(L, FV3_SubEx); } static int vector3d_mul(lua_State *L) { return vector3d_op(L, FV3_MulEx); } static int vector3d_div(lua_State *L) { return vector3d_op(L, FV3_DivideEx); } static int vector3d_unm(lua_State *L) { vector3_t *vec = luaL_checkudata(L, 1, META_VECTOR3); FV3_NegateEx(vec, NewVector3(L)); return 1; } int LUA_VectorLib(lua_State *L) { LUA_RegisterUserdataMetatable(L, META_VECTOR2, vector2d_get, NULL, NULL); luaL_newmetatable(L, META_VECTOR3); LUA_SetCFunctionField(L, "__index", vector3d_get); LUA_SetCFunctionField(L, "__eq", vector3d_eq); LUA_SetCFunctionField(L, "__add", vector3d_add); LUA_SetCFunctionField(L, "__sub", vector3d_sub); LUA_SetCFunctionField(L, "__mul", vector3d_mul); LUA_SetCFunctionField(L, "__div", vector3d_div); LUA_SetCFunctionField(L, "__unm", vector3d_unm); lua_pop(L, 1); luaL_register(L, "Vector3D", vector3d); return 0; }