blankart/src/lua_vectorlib.c
2025-11-17 12:29:27 -05:00

219 lines
5.1 KiB
C

// BLANKART
//-----------------------------------------------------------------------------
// 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;
}