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.
318 lines
8.3 KiB
C
318 lines
8.3 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"
|
|
|
|
static ud_t *Ud = NULL;
|
|
#define PAR 1
|
|
#define OBJ1 2
|
|
#define OBJ2 3
|
|
static void FirstDir(const void *obj1, const void *obj2, vec3_t *dir);
|
|
static void Support(const void *obj_, const vec3_t *dir, vec3_t *vec);
|
|
static void Center(const void *obj_, vec3_t *center);
|
|
|
|
static int freeccd(lua_State *L, ud_t *ud)
|
|
{
|
|
ccd_t *ccd = (ccd_t *)ud->handle;
|
|
if (!freeuserdata(L, ud, "ccdpar"))
|
|
return 0;
|
|
Free(L, ccd);
|
|
return 0;
|
|
}
|
|
|
|
static int newccd(lua_State *L, ccd_t *ccd, int ref[6])
|
|
{
|
|
ud_t *ud;
|
|
ud = newuserdata(L, ccd, CCDPAR_MT, "ccdpar");
|
|
ud->parent_ud = NULL;
|
|
ud->destructor = freeccd;
|
|
memcpy(ud->ref, ref, 6 * sizeof(int));
|
|
return 1;
|
|
}
|
|
|
|
static int New(lua_State *L)
|
|
{
|
|
ccd_t ccd, *ccdp;
|
|
int ref[6];
|
|
int t = lua_type(L, 1);
|
|
CCD_INIT(&ccd);
|
|
memset(ref, 0, 6 * sizeof(int));
|
|
switch (t)
|
|
{
|
|
case LUA_TNONE:
|
|
case LUA_TNIL:
|
|
return argerror(L, 1, ERR_NOTPRESENT);
|
|
case LUA_TTABLE:
|
|
break;
|
|
default:
|
|
return argerror(L, 1, ERR_TABLE);
|
|
}
|
|
#define checkfn(name, ccdfield, Func, ref) \
|
|
do \
|
|
{ \
|
|
lua_getfield(L, 1, name); \
|
|
if (lua_isfunction(L, -1)) \
|
|
/* this also unfererences any previous ref: */ \
|
|
{ \
|
|
Reference(L, -1, ref); \
|
|
ccd.ccdfield = Func; \
|
|
} \
|
|
else if (!lua_isnoneornil(L, -1)) \
|
|
return argerror(L, 1, ERR_FUNCTION); \
|
|
lua_pop(L, 1); \
|
|
} while (0)
|
|
checkfn("first_dir", first_dir, FirstDir, ref[0]);
|
|
checkfn("support1", support1, Support, ref[1]);
|
|
checkfn("support2", support2, Support, ref[2]);
|
|
checkfn("center1", center1, Center, ref[3]);
|
|
checkfn("center2", center2, Center, ref[4]);
|
|
#undef checkfn
|
|
lua_getfield(L, 1, "max_iterations");
|
|
ccd.max_iterations = luaL_optinteger(L, -1, ccd.max_iterations);
|
|
lua_pop(L, 1);
|
|
lua_getfield(L, 1, "epa_tolerance");
|
|
ccd.epa_tolerance = luaL_optnumber(L, -1, ccd.epa_tolerance);
|
|
lua_pop(L, 1);
|
|
lua_getfield(L, 1, "mpr_tolerance");
|
|
ccd.mpr_tolerance = luaL_optnumber(L, -1, ccd.mpr_tolerance);
|
|
lua_pop(L, 1);
|
|
lua_getfield(L, 1, "dist_tolerance");
|
|
ccd.dist_tolerance = luaL_optnumber(L, -1, ccd.dist_tolerance);
|
|
lua_pop(L, 1);
|
|
ccdp = Malloc(L, sizeof(ccd_t));
|
|
memcpy(ccdp, &ccd, sizeof(ccd_t));
|
|
return newccd(L, ccdp, ref);
|
|
}
|
|
|
|
static void FirstDir(const void *obj1, const void *obj2, vec3_t *dir)
|
|
{
|
|
#define L moonccd_L
|
|
int rc;
|
|
int t = lua_gettop(L);
|
|
(void)obj1;
|
|
(void)obj2;
|
|
lua_rawgeti(L, LUA_REGISTRYINDEX, Ud->ref[0]);
|
|
lua_pushvalue(L, OBJ1);
|
|
lua_pushvalue(L, OBJ2);
|
|
rc = lua_pcall(L, 2, 1, 0);
|
|
if (rc != LUA_OK)
|
|
lua_error(L);
|
|
checkvec3(L, -1, dir);
|
|
lua_settop(L, t);
|
|
#undef L
|
|
}
|
|
|
|
static void Support(const void *obj_, const vec3_t *dir, vec3_t *vec)
|
|
{
|
|
#define L moonccd_L
|
|
int ref, rc;
|
|
int obj = (ptrdiff_t)obj_;
|
|
int t = lua_gettop(L);
|
|
switch (obj)
|
|
{
|
|
case OBJ1:
|
|
ref = Ud->ref[1];
|
|
break;
|
|
case OBJ2:
|
|
ref = Ud->ref[2];
|
|
break;
|
|
default:
|
|
unexpected(L);
|
|
return;
|
|
}
|
|
lua_rawgeti(L, LUA_REGISTRYINDEX, ref);
|
|
lua_pushvalue(L, obj);
|
|
pushvec3(L, dir);
|
|
rc = lua_pcall(L, 2, 1, 0);
|
|
if (rc != LUA_OK)
|
|
lua_error(L);
|
|
checkvec3(L, -1, vec);
|
|
lua_settop(L, t);
|
|
#undef L
|
|
}
|
|
|
|
static void Center(const void *obj_, vec3_t *center)
|
|
{
|
|
#define L moonccd_L
|
|
int ref, rc;
|
|
int obj = (ptrdiff_t)obj_;
|
|
int t = lua_gettop(L);
|
|
switch (obj)
|
|
{
|
|
case OBJ1:
|
|
ref = Ud->ref[3];
|
|
break;
|
|
case OBJ2:
|
|
ref = Ud->ref[4];
|
|
break;
|
|
default:
|
|
unexpected(L);
|
|
return;
|
|
}
|
|
lua_rawgeti(L, LUA_REGISTRYINDEX, ref);
|
|
lua_pushvalue(L, obj);
|
|
rc = lua_pcall(L, 1, 1, 0);
|
|
if (rc != LUA_OK)
|
|
lua_error(L);
|
|
checkvec3(L, -1, center);
|
|
lua_settop(L, t);
|
|
#undef L
|
|
}
|
|
|
|
static int GJKIntersect(lua_State *L)
|
|
{
|
|
ccd_t *ccd = checkccd(L, PAR, &Ud);
|
|
luaL_checkany(L, OBJ1);
|
|
luaL_checkany(L, OBJ2);
|
|
lua_pushboolean(L, ccdGJKIntersect((void *)OBJ1, (void *)OBJ2, ccd));
|
|
return 1;
|
|
}
|
|
|
|
static int GJKSeparate(lua_State *L)
|
|
{
|
|
int rc;
|
|
vec3_t sep;
|
|
ccd_t *ccd = checkccd(L, PAR, &Ud);
|
|
luaL_checkany(L, OBJ1);
|
|
luaL_checkany(L, OBJ2);
|
|
rc = ccdGJKSeparate((void *)OBJ1, (void *)OBJ2, ccd, &sep);
|
|
switch (rc)
|
|
{
|
|
case 0:
|
|
lua_pushboolean(L, 1);
|
|
pushvec3(L, &sep);
|
|
return 2;
|
|
case -1:
|
|
lua_pushboolean(L, 0);
|
|
return 1;
|
|
case -2:
|
|
return errmemory(L);
|
|
default:
|
|
break;
|
|
}
|
|
return unexpected(L);
|
|
}
|
|
|
|
static int GJKPenetration(lua_State *L)
|
|
{
|
|
int rc;
|
|
double depth;
|
|
vec3_t dir, pos;
|
|
ccd_t *ccd = checkccd(L, PAR, &Ud);
|
|
luaL_checkany(L, OBJ1);
|
|
luaL_checkany(L, OBJ2);
|
|
rc = ccdGJKPenetration((void *)OBJ1, (void *)OBJ2, ccd, &depth, &dir, &pos);
|
|
switch (rc)
|
|
{
|
|
case 0:
|
|
lua_pushboolean(L, 1);
|
|
lua_pushnumber(L, depth);
|
|
pushvec3(L, &dir);
|
|
pushvec3(L, &pos);
|
|
return 4;
|
|
case -1:
|
|
lua_pushboolean(L, 0);
|
|
return 1;
|
|
case -2:
|
|
return errmemory(L);
|
|
default:
|
|
break;
|
|
}
|
|
return unexpected(L);
|
|
}
|
|
|
|
static int MPRIntersect(lua_State *L)
|
|
{
|
|
ccd_t *ccd = checkccd(L, PAR, &Ud);
|
|
luaL_checkany(L, OBJ1);
|
|
luaL_checkany(L, OBJ2);
|
|
lua_pushboolean(L, ccdMPRIntersect((void *)OBJ1, (void *)OBJ2, ccd));
|
|
return 1;
|
|
}
|
|
|
|
static int MPRPenetration(lua_State *L)
|
|
{
|
|
int rc;
|
|
double depth;
|
|
vec3_t dir, pos;
|
|
ccd_t *ccd = checkccd(L, PAR, &Ud);
|
|
luaL_checkany(L, OBJ1);
|
|
luaL_checkany(L, OBJ2);
|
|
rc = ccdMPRPenetration((void *)OBJ1, (void *)OBJ2, ccd, &depth, &dir, &pos);
|
|
switch (rc)
|
|
{
|
|
case 0:
|
|
lua_pushboolean(L, 1);
|
|
lua_pushnumber(L, depth);
|
|
pushvec3(L, &dir);
|
|
pushvec3(L, &pos);
|
|
return 4;
|
|
case -1:
|
|
lua_pushboolean(L, 0);
|
|
return 1;
|
|
case -2:
|
|
return errmemory(L);
|
|
default:
|
|
break;
|
|
}
|
|
return unexpected(L);
|
|
}
|
|
|
|
DESTROY_FUNC(ccd)
|
|
|
|
static const struct luaL_Reg Methods[] =
|
|
{
|
|
{"free", Destroy},
|
|
{"gjk_intersect", GJKIntersect},
|
|
{"gjk_separate", GJKSeparate},
|
|
{"gjk_penetration", GJKPenetration},
|
|
{"mpr_intersect", MPRIntersect},
|
|
{NULL, NULL} /* sentinel */
|
|
};
|
|
|
|
static const struct luaL_Reg MetaMethods[] =
|
|
{
|
|
{"__gc", Destroy},
|
|
{NULL, NULL} /* sentinel */
|
|
};
|
|
|
|
static const struct luaL_Reg Functions[] =
|
|
{
|
|
{"new", New},
|
|
{"free", Destroy},
|
|
{"gjk_intersect", GJKIntersect},
|
|
{"gjk_separate", GJKSeparate},
|
|
{"gjk_penetration", GJKPenetration},
|
|
{"mpr_intersect", MPRIntersect},
|
|
{"mpr_penetration", MPRPenetration},
|
|
{NULL, NULL} /* sentinel */
|
|
};
|
|
|
|
void moonccd_open_ccd(lua_State *L)
|
|
{
|
|
udata_define(L, CCDPAR_MT, Methods, MetaMethods);
|
|
luaL_setfuncs(L, Functions, 0);
|
|
}
|