You cannot select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

325 lines
8.4 KiB
C

/* The MIT License (MIT)
*
* Copyright (c) 2021 Stefano Trettel
*
* Software repository: MoonCCD, https://github.com/stetre/moonccd
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in all
* copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
* SOFTWARE.
*/
#include "internal.h"
#define GLMATH_COMPAT (tovec3 != LUA_NOREF)
/* References to the MoonGLMATH functions used to convert pushed values to glmath objects. */
static int tovec3 = LUA_NOREF;
static int toquat = LUA_NOREF;
int isglmathcompat(void)
{
return GLMATH_COMPAT;
}
int glmathcompat(lua_State *L, int on)
{
if (on)
{
if (GLMATH_COMPAT)
return 0; /* already enabled */
if (luaL_dostring(L, "return require('moonglmath').tovec3") != 0)
lua_error(L);
tovec3 = luaL_ref(L, LUA_REGISTRYINDEX);
if (luaL_dostring(L, "return require('moonglmath').toquat") != 0)
lua_error(L);
toquat = luaL_ref(L, LUA_REGISTRYINDEX);
}
else
{
if (!GLMATH_COMPAT)
return 0; /* already disabled */
luaL_unref(L, LUA_REGISTRYINDEX, tovec3);
tovec3 = LUA_NOREF;
luaL_unref(L, LUA_REGISTRYINDEX, toquat);
toquat = LUA_NOREF;
}
return 0;
}
/* vec3_t ----------------------------------------------------------*/
int testvec3(lua_State *L, int arg, vec3_t *dst)
{
int isnum;
int t = lua_type(L, arg);
switch (t)
{
case LUA_TNONE:
case LUA_TNIL:
return ERR_NOTPRESENT;
case LUA_TTABLE:
break;
default:
return ERR_TABLE;
}
#define POP \
if (!isnum) \
{ \
lua_pop(L, 1); \
return ERR_VALUE; \
} \
lua_pop(L, 1);
lua_rawgeti(L, arg, 1);
dst->v[0] = lua_tonumberx(L, -1, &isnum);
POP
lua_rawgeti(L, arg, 2);
dst->v[1] = lua_tonumberx(L, -1, &isnum);
POP
lua_rawgeti(L, arg, 3);
dst->v[2] = lua_tonumberx(L, -1, &isnum);
POP
#undef POP
return 0;
}
int optvec3(lua_State *L, int arg, vec3_t *dst)
{
int ec = testvec3(L, arg, dst);
if (ec < 0)
return argerror(L, arg, ec);
return ec;
}
int checkvec3(lua_State *L, int arg, vec3_t *dst)
{
int ec = testvec3(L, arg, dst);
if (ec)
return argerror(L, arg, ec);
return ec;
}
void pushvec3(lua_State *L, const vec3_t *val)
{
if (GLMATH_COMPAT)
lua_rawgeti(L, LUA_REGISTRYINDEX, tovec3);
lua_newtable(L);
lua_pushnumber(L, val->v[0]);
lua_rawseti(L, -2, 1);
lua_pushnumber(L, val->v[1]);
lua_rawseti(L, -2, 2);
lua_pushnumber(L, val->v[2]);
lua_rawseti(L, -2, 3);
if (GLMATH_COMPAT && lua_pcall(L, 1, 1, 0) != LUA_OK)
{
unexpected(L);
return;
}
}
vec3_t *checkvec3list(lua_State *L, int arg, int *countp, int *err)
/* Check if the value at arg is a table of vecs and returns the corresponding
* array of vec3_t, stroing the size in *countp. The array is Malloc()'d and the
* caller is in charge of Free()ing it.
* If err=NULL, raises an error on failure, otherwise returns NULL and stores
* the ERR_XXX code in *err.
*/
{
int count, i;
vec3_t *dst = NULL;
*countp = 0;
#define ERR(ec) \
do \
{ \
if (err) \
*err = (ec); \
else \
argerror(L, arg, (ec)); \
return NULL; \
} while (0)
if (lua_isnoneornil(L, arg))
ERR(ERR_NOTPRESENT);
if (lua_type(L, arg) != LUA_TTABLE)
ERR(ERR_TABLE);
count = luaL_len(L, arg);
if (count == 0)
ERR(ERR_EMPTY);
dst = MallocNoErr(L, count * sizeof(vec3_t));
if (!dst)
ERR(ERR_MEMORY);
for (i = 0; i < count; i++)
{
lua_rawgeti(L, arg, i + 1);
if (testvec3(L, -1, &dst[i]) != 0)
{
Free(L, dst);
ERR(ERR_TYPE);
}
lua_pop(L, 1);
}
#undef ERR
*countp = count;
if (err)
*err = 0;
return dst;
}
void pushvec3list(lua_State *L, const vec3_t *vecs, int count)
{
int i;
lua_newtable(L);
for (i = 0; i < count; i++)
{
pushvec3(L, &vecs[i]);
lua_rawseti(L, -2, i + 1);
}
}
/* quat_t ----------------------------------------------------------*/
int testquat(lua_State *L, int arg, quat_t *dst)
{
int isnum;
int t = lua_type(L, arg);
switch (t)
{
case LUA_TNONE:
case LUA_TNIL:
return ERR_NOTPRESENT;
case LUA_TTABLE:
break;
default:
return ERR_TABLE;
}
#define POP \
if (!isnum) \
{ \
lua_pop(L, 1); \
return ERR_VALUE; \
} \
lua_pop(L, 1);
lua_rawgeti(L, arg, 1);
dst->q[3] = lua_tonumberx(L, -1, &isnum);
POP // w
lua_rawgeti(L, arg, 2);
dst->q[0] = lua_tonumberx(L, -1, &isnum);
POP // x
lua_rawgeti(L, arg, 3);
dst->q[1] = lua_tonumberx(L, -1, &isnum);
POP // y
lua_rawgeti(L, arg, 4);
dst->q[2] = lua_tonumberx(L, -1, &isnum);
POP // z
#undef POP
return 0;
}
int optquat(lua_State *L, int arg, quat_t *dst)
{
int ec = testquat(L, arg, dst);
if (ec < 0)
return argerror(L, arg, ec);
return ec;
}
int checkquat(lua_State *L, int arg, quat_t *dst)
{
int ec = testquat(L, arg, dst);
if (ec)
return argerror(L, arg, ec);
return ec;
}
void pushquat(lua_State *L, const quat_t *val)
{
if (GLMATH_COMPAT)
lua_rawgeti(L, LUA_REGISTRYINDEX, toquat);
lua_newtable(L);
lua_pushnumber(L, val->q[3]);
lua_rawseti(L, -2, 1); // w
lua_pushnumber(L, val->q[0]);
lua_rawseti(L, -2, 2); // x
lua_pushnumber(L, val->q[1]);
lua_rawseti(L, -2, 3); // y
lua_pushnumber(L, val->q[2]);
lua_rawseti(L, -2, 4); // z
if (GLMATH_COMPAT && lua_pcall(L, 1, 1, 0) != LUA_OK)
{
unexpected(L);
return;
}
}
quat_t *checkquatlist(lua_State *L, int arg, int *countp, int *err)
/* Check if the value at arg is a table of vecs and returns the corresponding
* array of quat_t, stroing the size in *countp. The array is Malloc()'d and the
* caller is in charge of Free()ing it.
* If err=NULL, raises an error on failure, otherwise returns NULL and stores
* the ERR_XXX code in *err.
*/
{
int count, i;
quat_t *dst = NULL;
*countp = 0;
#define ERR(ec) \
do \
{ \
if (err) \
*err = (ec); \
else \
argerror(L, arg, (ec)); \
return NULL; \
} while (0)
if (lua_isnoneornil(L, arg))
ERR(ERR_NOTPRESENT);
if (lua_type(L, arg) != LUA_TTABLE)
ERR(ERR_TABLE);
count = luaL_len(L, arg);
if (count == 0)
ERR(ERR_EMPTY);
dst = MallocNoErr(L, count * sizeof(quat_t));
if (!dst)
ERR(ERR_MEMORY);
for (i = 0; i < count; i++)
{
lua_rawgeti(L, arg, i + 1);
if (testquat(L, -1, &dst[i]) != 0)
{
Free(L, dst);
ERR(ERR_TYPE);
}
lua_pop(L, 1);
}
#undef ERR
*countp = count;
if (err)
*err = 0;
return dst;
}
void pushquatlist(lua_State *L, const quat_t *vecs, int count)
{
int i;
lua_newtable(L);
for (i = 0; i < count; i++)
{
pushquat(L, &vecs[i]);
lua_rawseti(L, -2, i + 1);
}
}