Compare commits

...

24 Commits

Author SHA1 Message Date
bjorn 5b4ee30187 newCollider takes optional Shape as first arg; 2024-04-05 18:44:04 -07:00
bjorn e24ba87bb4 Shape fixes;
- Collider always has Shape now.  When left off or set to null, it's a
  tiny sphere (representing a point).
- Preserve shape offset when changing shape.
2024-04-05 18:41:50 -07:00
bjorn 23895ba8a0 lovrColliderCreate takes shape;
Jolt requires a shape, also it saves a bit of work.
2024-04-05 18:09:55 -07:00
bjorn 726e00cf60 Add Collider:getShapes for backcompat; 2024-04-05 18:08:54 -07:00
bjorn dba9c28cde rm unused shape prototypes; 2024-04-05 18:08:28 -07:00
bjorn d2002711f0 ODE compatibility; 2024-04-05 18:08:28 -07:00
bjorn f30f3c7944 Collider shape is required I think;
Jolt doesn't really support bodies without shapes.
2024-04-05 18:08:28 -07:00
bjorn d5b69ed135 Add Collider:get/setShapeOffset; 2024-04-05 18:08:28 -07:00
bjorn df43f4b4b4 World queries return collider/shapeindex instead of Shape; 2024-04-05 18:08:27 -07:00
bjorn fd4207a40f Require frozen CompoundShapes to have at least 2 children;
If you create a StaticCompoundShape with 1 child, Jolt creates a
RotatedTranslatedShape.  It would be a pain to have to branch on that,
so let's just require 2 children.
2024-04-05 18:06:34 -07:00
bjorn 2880f1f6bf rm Shape setters;
Jolt doesn't support this and requires you to recreate the shape.  Since
the shape -> collider relationship is 1:N, we can't really create a new
shape because we'd have to figure out which colliders/compoundshapes to
assign it to, which isn't feasible.
2024-04-05 18:06:34 -07:00
bjorn 0061bdb98d CompoundShape fixes; 2024-04-05 18:06:34 -07:00
bjorn a7c5151200 Shapes set their userdata; 2024-04-05 18:06:34 -07:00
bjorn 98a75410a3 CompoundShape API; 2024-04-05 18:06:34 -07:00
bjorn 5312acaaf9 Start CompoundShape; 2024-04-05 18:06:34 -07:00
bjorn 9389ac0b97 Colliders can only have 1 shape; rm shape pose; 2024-04-05 18:06:33 -07:00
bjorn 9e12c89b20 Update Jolt; 2024-04-05 18:05:15 -07:00
bjorn e9fe088521 Add Collider:get/setGravityScale; Deprecate Collider:get/setGravityIgnored; 2024-04-05 14:22:02 -07:00
bjorn 01194a80c7 Deprecate several World methods;
They still work on ODE, and Jolt makes a best-effort attempt to support
them, but they will be removed in a future version.

- Damping should be set explicitly on colliders.
- Tightness and response time will be supported via spring forces, and
  also some global settings in newWorld will affect joints too.
- Step count will be added to :update soon.  Since the correct value is
  dt-dependent in Jolt, a persistent accessor doesn't make sense.
- Sleeping allowed will be an immutable setting in newWorld soon, but
  otherwise should be changed per-collider.
2024-04-05 14:07:56 -07:00
bjorn ffc23497a9 Details; 2024-04-05 13:58:28 -07:00
bjorn d756cc2b1d Add variant of newWorld that takes an options table; 2024-04-05 13:25:32 -07:00
bjorn 77abad4e21 Merge branch 'stable' into dev 2024-04-05 11:42:18 -07:00
bjorn 40879f383a Fix possible crash when using math module in multiple threads; 2024-04-05 11:41:51 -07:00
bjorn 8596bb06a0 Fix OBJ triangulation for faces with more than 4 vertices; 2024-04-04 17:34:04 -07:00
10 changed files with 942 additions and 756 deletions

@ -1 +1 @@
Subproject commit 29fe07e8088279c47d7108107856ec3c826d1817
Subproject commit 22a062b3729f72eaaa24148195368e8b564ecfd1

View File

@ -203,4 +203,5 @@ struct Shape* luax_newcapsuleshape(lua_State* L, int index);
struct Shape* luax_newcylindershape(lua_State* L, int index);
struct Shape* luax_newmeshshape(lua_State* L, int index);
struct Shape* luax_newterrainshape(lua_State* L, int index);
struct Shape* luax_newcompoundshape(lua_State* L, int index);
#endif

View File

@ -32,13 +32,14 @@ extern const luaL_Reg lovrQuat[];
extern const luaL_Reg lovrMat4[];
static LOVR_THREAD_LOCAL Pool* pool;
static LOVR_THREAD_LOCAL int metaref[MAX_VECTOR_TYPES];
static struct { const char* name; lua_CFunction constructor, indexer; const luaL_Reg* api; int metaref; } lovrVectorInfo[] = {
[V_VEC2] = { "vec2", l_lovrMathVec2, l_lovrVec2__metaindex, lovrVec2, LUA_REFNIL },
[V_VEC3] = { "vec3", l_lovrMathVec3, l_lovrVec3__metaindex, lovrVec3, LUA_REFNIL },
[V_VEC4] = { "vec4", l_lovrMathVec4, l_lovrVec4__metaindex, lovrVec4, LUA_REFNIL },
[V_QUAT] = { "quat", l_lovrMathQuat, l_lovrQuat__metaindex, lovrQuat, LUA_REFNIL },
[V_MAT4] = { "mat4", l_lovrMathMat4, l_lovrMat4__metaindex, lovrMat4, LUA_REFNIL }
static struct { const char* name; lua_CFunction constructor, indexer; const luaL_Reg* api; } lovrVectorInfo[] = {
[V_VEC2] = { "vec2", l_lovrMathVec2, l_lovrVec2__metaindex, lovrVec2 },
[V_VEC3] = { "vec3", l_lovrMathVec3, l_lovrVec3__metaindex, lovrVec3 },
[V_VEC4] = { "vec4", l_lovrMathVec4, l_lovrVec4__metaindex, lovrVec4 },
[V_QUAT] = { "quat", l_lovrMathQuat, l_lovrQuat__metaindex, lovrQuat },
[V_MAT4] = { "mat4", l_lovrMathMat4, l_lovrMat4__metaindex, lovrMat4 }
};
static void luax_destroypool(void) {
@ -78,7 +79,7 @@ float* luax_checkvector(lua_State* L, int index, VectorType type, const char* ex
static float* luax_newvector(lua_State* L, VectorType type, size_t components) {
VectorType* p = lua_newuserdata(L, sizeof(VectorType) + components * sizeof(float));
*p = type;
lua_rawgeti(L, LUA_REGISTRYINDEX, lovrVectorInfo[type].metaref);
lua_rawgeti(L, LUA_REGISTRYINDEX, metaref[type]);
lua_setmetatable(L, -2);
return (float*) (p + 1);
}
@ -302,7 +303,7 @@ static int l_lovrLightUserdata__index(lua_State* L) {
return 0;
}
lua_rawgeti(L, LUA_REGISTRYINDEX, lovrVectorInfo[type].metaref);
lua_rawgeti(L, LUA_REGISTRYINDEX, metaref[type]);
lua_pushvalue(L, 2);
lua_rawget(L, -2);
if (lua_isnil(L, -1)) {
@ -334,7 +335,7 @@ static int l_lovrLightUserdataOp(lua_State* L) {
return luaL_error(L, "Unsupported lightuserdata operator %q", lua_tostring(L, lua_upvalueindex(1)));
}
lua_rawgeti(L, LUA_REGISTRYINDEX, lovrVectorInfo[type].metaref);
lua_rawgeti(L, LUA_REGISTRYINDEX, metaref[type]);
lua_pushvalue(L, lua_upvalueindex(1));
lua_gettable(L, -2);
lua_pushvalue(L, 1);
@ -369,7 +370,7 @@ int luaopen_lovr_math(lua_State* L) {
lua_settable(L, -4);
luax_register(L, lovrVectorInfo[i].api);
lovrVectorInfo[i].metaref = luaL_ref(L, LUA_REGISTRYINDEX);
metaref[i] = luaL_ref(L, LUA_REGISTRYINDEX);
}
// Global lightuserdata metatable

View File

@ -9,6 +9,7 @@ StringEntry lovrShapeType[] = {
[SHAPE_CYLINDER] = ENTRY("cylinder"),
[SHAPE_MESH] = ENTRY("mesh"),
[SHAPE_TERRAIN] = ENTRY("terrain"),
[SHAPE_COMPOUND] = ENTRY("compound"),
{ 0 }
};
@ -21,28 +22,70 @@ StringEntry lovrJointType[] = {
};
static int l_lovrPhysicsNewWorld(lua_State* L) {
float xg = luax_optfloat(L, 1, 0.f);
float yg = luax_optfloat(L, 2, -9.81f);
float zg = luax_optfloat(L, 3, 0.f);
bool allowSleep = lua_gettop(L) < 4 || lua_toboolean(L, 4);
const char* tags[MAX_TAGS];
int tagCount;
if (lua_type(L, 5) == LUA_TTABLE) {
tagCount = luax_len(L, 5);
lovrCheck(tagCount <= MAX_TAGS, "Max number of world tags is %d", MAX_TAGS);
for (int i = 0; i < tagCount; i++) {
lua_rawgeti(L, -1, i + 1);
if (lua_isstring(L, -1)) {
tags[i] = lua_tostring(L, -1);
} else {
return luaL_error(L, "World tags must be a table of strings");
WorldInfo info = {
.maxColliders = 65536,
.maxColliderPairs = 65536,
.maxContacts = 16384,
.allowSleep = true,
.gravity = { 0.f, -9.81f, 0.f }
};
if (lua_istable(L, 1)) {
lua_getfield(L, 1, "maxColliders");
if (!lua_isnil(L, -1)) info.maxColliders = luax_checku32(L, -1);
lua_pop(L, 1);
lua_getfield(L, 1, "maxColliderPairs");
if (!lua_isnil(L, -1)) info.maxColliderPairs = luax_checku32(L, -1);
lua_pop(L, 1);
lua_getfield(L, 1, "maxContacts");
if (!lua_isnil(L, -1)) info.maxContacts = luax_checku32(L, -1);
lua_pop(L, 1);
lua_getfield(L, 1, "allowSleep");
if (!lua_isnil(L, -1)) info.allowSleep = lua_toboolean(L, -1);
lua_pop(L, 1);
lua_getfield(L, 1, "tags");
if (!lua_isnil(L, -1)) {
lovrCheck(lua_istable(L, -1), "World tag list should be a table");
lovrCheck(info.tagCount <= MAX_TAGS, "Max number of world tags is %d", MAX_TAGS);
info.tagCount = luax_len(L, 5);
for (uint32_t i = 0; i < info.tagCount; i++) {
lua_rawgeti(L, -1, (int) i + 1);
if (lua_isstring(L, -1)) {
info.tags[i] = lua_tostring(L, -1);
} else {
return luaL_error(L, "World tags must be a table of strings");
}
lua_pop(L, 1);
}
lua_pop(L, 1);
}
} else {
tagCount = 0;
lua_pop(L, 1);
} else { // Deprecated
info.gravity[0] = luax_optfloat(L, 1, 0.f);
info.gravity[1] = luax_optfloat(L, 2, -9.81f);
info.gravity[2] = luax_optfloat(L, 3, 0.f);
info.allowSleep = lua_gettop(L) < 4 || lua_toboolean(L, 4);
if (lua_type(L, 5) == LUA_TTABLE) {
info.tagCount = luax_len(L, 5);
lovrCheck(info.tagCount <= MAX_TAGS, "Max number of world tags is %d", MAX_TAGS);
for (uint32_t i = 0; i < info.tagCount; i++) {
lua_rawgeti(L, -1, (int) i + 1);
if (lua_isstring(L, -1)) {
info.tags[i] = lua_tostring(L, -1);
} else {
return luaL_error(L, "World tags must be a table of strings");
}
lua_pop(L, 1);
}
} else {
info.tagCount = 0;
}
}
World* world = lovrWorldCreate(xg, yg, zg, allowSleep, tags, tagCount);
World* world = lovrWorldCreate(&info);
luax_pushtype(L, World, world);
lovrRelease(world, lovrWorldDestroy);
return 1;
@ -136,6 +179,13 @@ static int l_lovrPhysicsNewTerrainShape(lua_State* L) {
return 1;
}
static int l_lovrPhysicsNewCompoundShape(lua_State* L) {
CompoundShape* shape = luax_newcompoundshape(L, 1);
luax_pushtype(L, CompoundShape, shape);
lovrRelease(shape, lovrShapeDestroy);
return 1;
}
static const luaL_Reg lovrPhysics[] = {
{ "newWorld", l_lovrPhysicsNewWorld },
{ "newBallJoint", l_lovrPhysicsNewBallJoint },
@ -148,6 +198,7 @@ static const luaL_Reg lovrPhysics[] = {
{ "newSliderJoint", l_lovrPhysicsNewSliderJoint },
{ "newSphereShape", l_lovrPhysicsNewSphereShape },
{ "newTerrainShape", l_lovrPhysicsNewTerrainShape },
{ "newCompoundShape", l_lovrPhysicsNewCompoundShape },
{ NULL, NULL }
};
@ -163,6 +214,7 @@ extern const luaL_Reg lovrCapsuleShape[];
extern const luaL_Reg lovrCylinderShape[];
extern const luaL_Reg lovrMeshShape[];
extern const luaL_Reg lovrTerrainShape[];
extern const luaL_Reg lovrCompoundShape[];
int luaopen_lovr_physics(lua_State* L) {
lua_newtable(L);
@ -179,6 +231,7 @@ int luaopen_lovr_physics(lua_State* L) {
luax_registertype(L, CylinderShape);
luax_registertype(L, MeshShape);
luax_registertype(L, TerrainShape);
luax_registertype(L, CompoundShape);
lovrPhysicsInit();
luax_atexit(L, lovrPhysicsDestroy);
return 1;

View File

@ -24,32 +24,45 @@ static int l_lovrColliderGetWorld(lua_State* L) {
return 1;
}
static int l_lovrColliderAddShape(lua_State* L) {
static int l_lovrColliderGetShape(lua_State* L) {
Collider* collider = luax_checktype(L, 1, Collider);
Shape* shape = luax_checkshape(L, 2);
lovrColliderAddShape(collider, shape);
return 0;
}
static int l_lovrColliderRemoveShape(lua_State* L) {
Collider* collider = luax_checktype(L, 1, Collider);
Shape* shape = luax_checkshape(L, 2);
lovrColliderRemoveShape(collider, shape);
return 0;
}
static int l_lovrColliderGetShapes(lua_State* L) {
Collider* collider = luax_checktype(L, 1, Collider);
size_t count;
Shape** shapes = lovrColliderGetShapes(collider, &count);
lua_createtable(L, (int) count, 0);
for (size_t i = 0; i < count; i++) {
luax_pushshape(L, shapes[i]);
lua_rawseti(L, -2, (int) i + 1);
}
Shape* shape = lovrColliderGetShape(collider);
luax_pushshape(L, shape);
return 1;
}
static int l_lovrColliderSetShape(lua_State* L) {
Collider* collider = luax_checktype(L, 1, Collider);
Shape* shape = luax_checkshape(L, 2);
lovrColliderSetShape(collider, shape);
return 0;
}
static int l_lovrColliderGetShapeOffset(lua_State* L) {
Collider* collider = luax_checktype(L, 1, Collider);
float position[3], orientation[4], angle, ax, ay, az;
lovrColliderGetShapeOffset(collider, position, orientation);
quat_getAngleAxis(orientation, &angle, &ax, &ay, &az);
lua_pushnumber(L, position[0]);
lua_pushnumber(L, position[1]);
lua_pushnumber(L, position[2]);
lua_pushnumber(L, angle);
lua_pushnumber(L, ax);
lua_pushnumber(L, ay);
lua_pushnumber(L, az);
return 7;
}
static int l_lovrColliderSetShapeOffset(lua_State* L) {
Collider* collider = luax_checktype(L, 1, Collider);
int index = 2;
float position[3], orientation[4];
index = luax_readvec3(L, index, position, NULL);
index = luax_readquat(L, index, orientation, NULL);
lovrColliderSetShapeOffset(collider, position, orientation);
return 0;
}
static int l_lovrColliderGetJoints(lua_State* L) {
Collider* collider = luax_checktype(L, 1, Collider);
size_t count;
@ -110,16 +123,17 @@ static int l_lovrColliderSetKinematic(lua_State* L) {
return 0;
}
static int l_lovrColliderIsGravityIgnored(lua_State* L) {
static int l_lovrColliderGetGravityScale(lua_State* L) {
Collider* collider = luax_checktype(L, 1, Collider);
lua_pushboolean(L, lovrColliderIsGravityIgnored(collider));
float scale = lovrColliderGetGravityScale(collider);
lua_pushnumber(L, scale);
return 1;
}
static int l_lovrColliderSetGravityIgnored(lua_State* L) {
static int l_lovrColliderSetGravityScale(lua_State* L) {
Collider* collider = luax_checktype(L, 1, Collider);
bool ignored = lua_toboolean(L, 2);
lovrColliderSetGravityIgnored(collider, ignored);
float scale = luax_checkfloat(L, 2);
lovrColliderSetGravityScale(collider, scale);
return 0;
}
@ -507,20 +521,46 @@ static int l_lovrColliderSetTag(lua_State* L) {
return 0;
}
// Deprecated
static int l_lovrColliderGetShapes(lua_State* L) {
Collider* collider = luax_checktype(L, 1, Collider);
Shape* shape = lovrColliderGetShape(collider);
lua_createtable(L, 1, 0);
luax_pushshape(L, shape);
lua_rawseti(L, -2, 1);
return 1;
}
// Deprecated
static int l_lovrColliderIsGravityIgnored(lua_State* L) {
Collider* collider = luax_checktype(L, 1, Collider);
lua_pushboolean(L, lovrColliderGetGravityScale(collider) == 0.f);
return 1;
}
// Deprecated
static int l_lovrColliderSetGravityIgnored(lua_State* L) {
Collider* collider = luax_checktype(L, 1, Collider);
bool ignored = lua_toboolean(L, 2);
lovrColliderSetGravityScale(collider, ignored ? 0.f : 1.f);
return 0;
}
const luaL_Reg lovrCollider[] = {
{ "destroy", l_lovrColliderDestroy },
{ "isDestroyed", l_lovrColliderIsDestroyed },
{ "getWorld", l_lovrColliderGetWorld },
{ "addShape", l_lovrColliderAddShape },
{ "removeShape", l_lovrColliderRemoveShape },
{ "getShapes", l_lovrColliderGetShapes },
{ "getShape", l_lovrColliderGetShape },
{ "setShape", l_lovrColliderSetShape },
{ "getShapeOffset", l_lovrColliderGetShapeOffset },
{ "setShapeOffset", l_lovrColliderSetShapeOffset },
{ "getJoints", l_lovrColliderGetJoints },
{ "getUserData", l_lovrColliderGetUserData },
{ "setUserData", l_lovrColliderSetUserData },
{ "isKinematic", l_lovrColliderIsKinematic },
{ "setKinematic", l_lovrColliderSetKinematic },
{ "isGravityIgnored", l_lovrColliderIsGravityIgnored },
{ "setGravityIgnored", l_lovrColliderSetGravityIgnored },
{ "getGravityScale", l_lovrColliderGetGravityScale },
{ "setGravityScale", l_lovrColliderSetGravityScale },
{ "isSleepingAllowed", l_lovrColliderIsSleepingAllowed },
{ "setSleepingAllowed", l_lovrColliderSetSleepingAllowed },
{ "isAwake", l_lovrColliderIsAwake },
@ -559,5 +599,11 @@ const luaL_Reg lovrCollider[] = {
{ "setRestitution", l_lovrColliderSetRestitution },
{ "getTag", l_lovrColliderGetTag },
{ "setTag", l_lovrColliderSetTag },
// Deprecated
{ "getShapes", l_lovrColliderGetShapes },
{ "isGravityIgnored", l_lovrColliderIsGravityIgnored },
{ "setGravityIgnored", l_lovrColliderSetGravityIgnored },
{ NULL, NULL }
};

View File

@ -14,6 +14,7 @@ void luax_pushshape(lua_State* L, Shape* shape) {
case SHAPE_CYLINDER: luax_pushtype(L, CylinderShape, shape); break;
case SHAPE_MESH: luax_pushtype(L, MeshShape, shape); break;
case SHAPE_TERRAIN: luax_pushtype(L, TerrainShape, shape); break;
case SHAPE_COMPOUND: luax_pushtype(L, CompoundShape, shape); break;
default: lovrUnreachable();
}
}
@ -28,7 +29,8 @@ Shape* luax_checkshape(lua_State* L, int index) {
hash64("CapsuleShape", strlen("CapsuleShape")),
hash64("CylinderShape", strlen("CylinderShape")),
hash64("MeshShape", strlen("MeshShape")),
hash64("TerrainShape", strlen("TerrainShape"))
hash64("TerrainShape", strlen("TerrainShape")),
hash64("CompoundShape", strlen("CompoundShape"))
};
for (size_t i = 0; i < COUNTOF(hashes); i++) {
@ -135,6 +137,86 @@ Shape* luax_newterrainshape(lua_State* L, int index) {
}
}
Shape* luax_newcompoundshape(lua_State* L, int index) {
if (lua_isnoneornil(L, index)) {
return lovrCompoundShapeCreate(NULL, NULL, NULL, 0, false);
}
luaL_checktype(L, index, LUA_TTABLE);
int length = luax_len(L, index);
uint32_t defer = lovrDeferPush();
Shape** shapes = lovrMalloc(length * sizeof(Shape*));
float* positions = lovrMalloc(length * 3 * sizeof(float));
float* orientations = lovrMalloc(length * 4 * sizeof(float));
lovrDefer(lovrFree, shapes);
lovrDefer(lovrFree, positions);
lovrDefer(lovrFree, orientations);
for (int i = 0; i < length; i++) {
lua_rawgeti(L, index, i + 1);
lovrCheck(lua_istable(L, -1), "Expected table of tables for compound shape");
lua_rawgeti(L, -1, 1);
shapes[i] = luax_checkshape(L, -1);
lovrCheck(shapes[i], "Expected a Shape for CompoundShape entry #%d", i + 1);
lua_pop(L, 1);
int index = 2;
lua_rawgeti(L, -1, index);
switch (lua_type(L, -1)) {
case LUA_TNIL:
vec3_set(&positions[3 * i], 0.f, 0.f, 0.f);
lua_pop(L, 1);
break;
case LUA_TNUMBER:
lua_rawgeti(L, -2, index + 1);
lua_rawgeti(L, -3, index + 2);
vec3_set(&positions[3 * i], luax_tofloat(L, -3), luax_tofloat(L, -2), luax_tofloat(L, -1));
lua_pop(L, 3);
index += 3;
break;
default: {
float* v = luax_checkvector(L, -1, V_VEC3, "nil, number, or vec3");
vec3_init(&positions[3 * i], v);
lua_pop(L, 1);
break;
}
}
lua_rawgeti(L, -1, index);
switch (lua_type(L, -1)) {
case LUA_TNIL:
quat_identity(&orientations[4 * i]);
lua_pop(L, 1);
break;
case LUA_TNUMBER:
lua_rawgeti(L, -2, index);
lua_rawgeti(L, -3, index);
lua_rawgeti(L, -4, index);
quat_set(&orientations[4 * i], luax_tofloat(L, -4), luax_tofloat(L, -3), luax_tofloat(L, -2), luax_tofloat(L, -1));
lua_pop(L, 4);
break;
default: {
float* q = luax_checkvector(L, -1, V_QUAT, "nil, number, or quat");
quat_init(&positions[4 * i], q);
lua_pop(L, 1);
break;
}
}
lua_pop(L, 1);
}
lua_getfield(L, index, "freeze");
bool freeze = lua_toboolean(L, -1);
lua_pop(L, 1);
CompoundShape* shape = lovrCompoundShapeCreate(shapes, positions, orientations, length, freeze);
lovrDeferPop(defer);
return shape;
}
static int l_lovrShapeDestroy(lua_State* L) {
Shape* shape = luax_checkshape(L, 1);
lovrShapeDestroyData(shape);
@ -147,12 +229,6 @@ static int l_lovrShapeGetType(lua_State* L) {
return 1;
}
static int l_lovrShapeGetCollider(lua_State* L) {
Shape* shape = luax_checkshape(L, 1);
luax_pushtype(L, Collider, lovrShapeGetCollider(shape));
return 1;
}
static int l_lovrShapeIsEnabled(lua_State* L) {
Shape* shape = luax_checkshape(L, 1);
lua_pushboolean(L, lovrShapeIsEnabled(shape));
@ -214,74 +290,6 @@ static int l_lovrShapeSetUserData(lua_State* L) {
return 0;
}
static int l_lovrShapeGetPosition(lua_State* L) {
Shape* shape = luax_checkshape(L, 1);
float x, y, z;
lovrShapeGetPosition(shape, &x, &y, &z);
lua_pushnumber(L, x);
lua_pushnumber(L, y);
lua_pushnumber(L, z);
return 3;
}
static int l_lovrShapeSetPosition(lua_State* L) {
Shape* shape = luax_checkshape(L, 1);
lovrCheck(lovrShapeGetCollider(shape) != NULL, "Shape must be attached to collider");
float position[3];
luax_readvec3(L, 2, position, NULL);
lovrShapeSetPosition(shape, position[0], position[1], position[2]);
return 0;
}
static int l_lovrShapeGetOrientation(lua_State* L) {
Shape* shape = luax_checkshape(L, 1);
float angle, x, y, z, orientation[4];
lovrShapeGetOrientation(shape, orientation);
quat_getAngleAxis(orientation, &angle, &x, &y, &z);
lua_pushnumber(L, angle);
lua_pushnumber(L, x);
lua_pushnumber(L, y);
lua_pushnumber(L, z);
return 4;
}
static int l_lovrShapeSetOrientation(lua_State* L) {
Shape* shape = luax_checkshape(L, 1);
lovrCheck(lovrShapeGetCollider(shape) != NULL, "Shape must be attached to collider");
float orientation[4];
luax_readquat(L, 2, orientation, NULL);
lovrShapeSetOrientation(shape, orientation);
return 0;
}
static int l_lovrShapeGetPose(lua_State* L) {
Shape* shape = luax_checkshape(L, 1);
float x, y, z;
lovrShapeGetPosition(shape, &x, &y, &z);
float angle, ax, ay, az, orientation[4];
lovrShapeGetOrientation(shape, orientation);
quat_getAngleAxis(orientation, &angle, &ax, &ay, &az);
lua_pushnumber(L, x);
lua_pushnumber(L, y);
lua_pushnumber(L, z);
lua_pushnumber(L, angle);
lua_pushnumber(L, ax);
lua_pushnumber(L, ay);
lua_pushnumber(L, az);
return 7;
}
static int l_lovrShapeSetPose(lua_State* L) {
Shape* shape = luax_checkshape(L, 1);
lovrCheck(lovrShapeGetCollider(shape) != NULL, "Shape must be attached to collider");
float position[3], orientation[4];
int index = luax_readvec3(L, 2, position, NULL);
luax_readquat(L, index, orientation, NULL);
lovrShapeSetPosition(shape, position[0], position[1], position[2]);
lovrShapeSetOrientation(shape, orientation);
return 0;
}
static int l_lovrShapeGetMass(lua_State* L) {
Shape* shape = luax_checkshape(L, 1);
float density = luax_checkfloat(L, 2);
@ -313,19 +321,12 @@ static int l_lovrShapeGetAABB(lua_State* L) {
#define lovrShape \
{ "destroy", l_lovrShapeDestroy }, \
{ "getType", l_lovrShapeGetType }, \
{ "getCollider", l_lovrShapeGetCollider }, \
{ "isEnabled", l_lovrShapeIsEnabled }, \
{ "setEnabled", l_lovrShapeSetEnabled }, \
{ "isSensor", l_lovrShapeIsSensor }, \
{ "setSensor", l_lovrShapeSetSensor }, \
{ "getUserData", l_lovrShapeGetUserData }, \
{ "setUserData", l_lovrShapeSetUserData }, \
{ "getPosition", l_lovrShapeGetPosition }, \
{ "setPosition", l_lovrShapeSetPosition }, \
{ "getOrientation", l_lovrShapeGetOrientation }, \
{ "setOrientation", l_lovrShapeSetOrientation }, \
{ "getPose", l_lovrShapeGetPose }, \
{ "setPose", l_lovrShapeSetPose }, \
{ "getMass", l_lovrShapeGetMass }, \
{ "getAABB", l_lovrShapeGetAABB }
@ -335,17 +336,9 @@ static int l_lovrSphereShapeGetRadius(lua_State* L) {
return 1;
}
static int l_lovrSphereShapeSetRadius(lua_State* L) {
SphereShape* sphere = luax_checktype(L, 1, SphereShape);
float radius = luax_checkfloat(L, 2);
lovrSphereShapeSetRadius(sphere, radius);
return 0;
}
const luaL_Reg lovrSphereShape[] = {
lovrShape,
{ "getRadius", l_lovrSphereShapeGetRadius },
{ "setRadius", l_lovrSphereShapeSetRadius },
{ NULL, NULL }
};
@ -359,18 +352,9 @@ static int l_lovrBoxShapeGetDimensions(lua_State* L) {
return 3;
}
static int l_lovrBoxShapeSetDimensions(lua_State* L) {
BoxShape* box = luax_checktype(L, 1, BoxShape);
float size[3];
luax_readscale(L, 2, size, 3, NULL);
lovrBoxShapeSetDimensions(box, size[0], size[1], size[2]);
return 0;
}
const luaL_Reg lovrBoxShape[] = {
lovrShape,
{ "getDimensions", l_lovrBoxShapeGetDimensions },
{ "setDimensions", l_lovrBoxShapeSetDimensions },
{ NULL, NULL }
};
@ -380,32 +364,16 @@ static int l_lovrCapsuleShapeGetRadius(lua_State* L) {
return 1;
}
static int l_lovrCapsuleShapeSetRadius(lua_State* L) {
CapsuleShape* capsule = luax_checktype(L, 1, CapsuleShape);
float radius = luax_checkfloat(L, 2);
lovrCapsuleShapeSetRadius(capsule, radius);
return 0;
}
static int l_lovrCapsuleShapeGetLength(lua_State* L) {
CapsuleShape* capsule = luax_checktype(L, 1, CapsuleShape);
lua_pushnumber(L, lovrCapsuleShapeGetLength(capsule));
return 1;
}
static int l_lovrCapsuleShapeSetLength(lua_State* L) {
CapsuleShape* capsule = luax_checktype(L, 1, CapsuleShape);
float length = luax_checkfloat(L, 2);
lovrCapsuleShapeSetLength(capsule, length);
return 0;
}
const luaL_Reg lovrCapsuleShape[] = {
lovrShape,
{ "getRadius", l_lovrCapsuleShapeGetRadius },
{ "setRadius", l_lovrCapsuleShapeSetRadius },
{ "getLength", l_lovrCapsuleShapeGetLength },
{ "setLength", l_lovrCapsuleShapeSetLength },
{ NULL, NULL }
};
@ -415,32 +383,16 @@ static int l_lovrCylinderShapeGetRadius(lua_State* L) {
return 1;
}
static int l_lovrCylinderShapeSetRadius(lua_State* L) {
CylinderShape* cylinder = luax_checktype(L, 1, CylinderShape);
float radius = luax_checkfloat(L, 2);
lovrCylinderShapeSetRadius(cylinder, radius);
return 0;
}
static int l_lovrCylinderShapeGetLength(lua_State* L) {
CylinderShape* cylinder = luax_checktype(L, 1, CylinderShape);
lua_pushnumber(L, lovrCylinderShapeGetLength(cylinder));
return 1;
}
static int l_lovrCylinderShapeSetLength(lua_State* L) {
CylinderShape* cylinder = luax_checktype(L, 1, CylinderShape);
float length = luax_checkfloat(L, 2);
lovrCylinderShapeSetLength(cylinder, length);
return 0;
}
const luaL_Reg lovrCylinderShape[] = {
lovrShape,
{ "getRadius", l_lovrCylinderShapeGetRadius },
{ "setRadius", l_lovrCylinderShapeSetRadius },
{ "getLength", l_lovrCylinderShapeGetLength },
{ "setLength", l_lovrCylinderShapeSetLength },
{ NULL, NULL }
};
@ -453,3 +405,109 @@ const luaL_Reg lovrTerrainShape[] = {
lovrShape,
{ NULL, NULL }
};
static int l_lovrCompoundShapeIsFrozen(lua_State* L) {
CompoundShape* shape = luax_checktype(L, 1, CompoundShape);
bool frozen = lovrCompoundShapeIsFrozen(shape);
lua_pushboolean(L, frozen);
return 1;
}
static int l_lovrCompoundShapeAddShape(lua_State* L) {
CompoundShape* shape = luax_checktype(L, 1, CompoundShape);
Shape* child = luax_checkshape(L, 2);
float position[3], orientation[4];
int index = 3;
index = luax_readvec3(L, index, position, NULL);
index = luax_readquat(L, index, orientation, NULL);
lovrCompoundShapeAddShape(shape, child, position, orientation);
return 0;
}
static int l_lovrCompoundShapeReplaceShape(lua_State* L) {
CompoundShape* shape = luax_checktype(L, 1, CompoundShape);
uint32_t index = luax_checku32(L, 2);
Shape* child = luax_checkshape(L, 3);
float position[3], orientation[4];
int i = 4;
i = luax_readvec3(L, i, position, NULL);
i = luax_readquat(L, i, orientation, NULL);
lovrCompoundShapeReplaceShape(shape, index, child, position, orientation);
return 0;
}
static int l_lovrCompoundShapeRemoveShape(lua_State* L) {
CompoundShape* shape = luax_checktype(L, 1, CompoundShape);
uint32_t index = luax_checku32(L, 2) - 1;
lovrCompoundShapeRemoveShape(shape, index);
return 0;
}
static int l_lovrCompoundShapeGetShape(lua_State* L) {
CompoundShape* shape = luax_checktype(L, 1, CompoundShape);
uint32_t index = luax_checku32(L, 2) - 1;
Shape* child = lovrCompoundShapeGetShape(shape, index);
luax_pushshape(L, child);
return 1;
}
static int l_lovrCompoundShapeGetShapes(lua_State* L) {
CompoundShape* shape = luax_checktype(L, 1, CompoundShape);
int count = (int) lovrCompoundShapeGetShapeCount(shape);
lua_createtable(L, count, 0);
for (int i = 0; i < count; i++) {
Shape* child = lovrCompoundShapeGetShape(shape, (uint32_t) i);
luax_pushshape(L, child);
lua_rawseti(L, -2, i + 1);
}
return 1;
}
static int l_lovrCompoundShapeGetShapeCount(lua_State* L) {
CompoundShape* shape = luax_checktype(L, 1, CompoundShape);
uint32_t count = lovrCompoundShapeGetShapeCount(shape);
lua_pushinteger(L, count);
return 1;
}
static int l_lovrCompoundShapeGetShapeOffset(lua_State* L) {
CompoundShape* shape = luax_checktype(L, 1, CompoundShape);
uint32_t index = luax_checku32(L, 2) - 1;
float position[3], orientation[4], angle, ax, ay, az;
lovrCompoundShapeGetShapeOffset(shape, index, position, orientation);
quat_getAngleAxis(orientation, &angle, &ax, &ay, &az);
lua_pushnumber(L, position[0]);
lua_pushnumber(L, position[1]);
lua_pushnumber(L, position[2]);
lua_pushnumber(L, angle);
lua_pushnumber(L, ax);
lua_pushnumber(L, ay);
lua_pushnumber(L, az);
return 7;
}
static int l_lovrCompoundShapeSetShapeOffset(lua_State* L) {
CompoundShape* shape = luax_checktype(L, 1, CompoundShape);
uint32_t index = luax_checku32(L, 2) - 1;
float position[3], orientation[4];
int i = 3;
i = luax_readvec3(L, i, position, NULL);
i = luax_readquat(L, i, orientation, NULL);
lovrCompoundShapeSetShapeOffset(shape, index, position, orientation);
return 0;
}
const luaL_Reg lovrCompoundShape[] = {
lovrShape,
{ "isFrozen", l_lovrCompoundShapeIsFrozen },
{ "addShape", l_lovrCompoundShapeAddShape },
{ "replaceShape", l_lovrCompoundShapeReplaceShape },
{ "removeShape", l_lovrCompoundShapeRemoveShape },
{ "getShape", l_lovrCompoundShapeGetShape },
{ "getShapes", l_lovrCompoundShapeGetShapes },
{ "getShapeCount", l_lovrCompoundShapeGetShapeCount },
{ "getShapeOffset", l_lovrCompoundShapeGetShapeOffset },
{ "setShapeOffset", l_lovrCompoundShapeSetShapeOffset },
{ "__len", l_lovrCompoundShapeGetShapeCount }, // :)
{ NULL, NULL }
};

View File

@ -27,17 +27,18 @@ static int nextOverlap(lua_State* L) {
}
}
static bool raycastCallback(Shape* shape, float x, float y, float z, float nx, float ny, float nz, void* userdata) {
static bool raycastCallback(Collider* collider, uint32_t shape, float position[3], float normal[3], void* userdata) {
lua_State* L = userdata;
lua_pushvalue(L, -1);
luax_pushshape(L, shape);
lua_pushnumber(L, x);
lua_pushnumber(L, y);
lua_pushnumber(L, z);
lua_pushnumber(L, nx);
lua_pushnumber(L, ny);
lua_pushnumber(L, nz);
lua_call(L, 7, 1);
luax_pushtype(L, Collider, collider);
lua_pushinteger(L, shape);
lua_pushnumber(L, position[0]);
lua_pushnumber(L, position[1]);
lua_pushnumber(L, position[2]);
lua_pushnumber(L, normal[0]);
lua_pushnumber(L, normal[1]);
lua_pushnumber(L, normal[2]);
lua_call(L, 8, 1);
bool shouldStop = lua_type(L, -1) == LUA_TBOOLEAN && !lua_toboolean(L, -1);
lua_pop(L, 1);
return shouldStop;
@ -45,53 +46,55 @@ static bool raycastCallback(Shape* shape, float x, float y, float z, float nx, f
typedef struct {
const char* tag;
Shape* shape;
Collider* collider;
uint32_t shape;
float distance;
float origin[3];
float position[3];
float normal[3];
} RaycastData;
static bool raycastAnyCallback(Shape* shape, float x, float y, float z, float nx, float ny, float nz, void* userdata) {
static bool raycastAnyCallback(Collider* collider, uint32_t shape, float position[3], float normal[3], void* userdata) {
RaycastData* data = userdata;
if (data->tag) {
const char* tag = lovrColliderGetTag(lovrShapeGetCollider(shape));
const char* tag = lovrColliderGetTag(collider);
if (!tag || strcmp(tag, data->tag)) {
return false;
}
}
data->collider = collider;
data->shape = shape;
vec3_set(data->position, x, y, z);
vec3_set(data->normal, nx, ny, nz);
vec3_init(data->position, position);
vec3_init(data->normal, normal);
data->distance = vec3_distance(data->origin, data->position);
return true;
}
static bool raycastClosestCallback(Shape* shape, float x, float y, float z, float nx, float ny, float nz, void* userdata) {
static bool raycastClosestCallback(Collider* collider, uint32_t shape, float position[3], float normal[3], void* userdata) {
RaycastData* data = userdata;
if (data->tag) {
const char* tag = lovrColliderGetTag(lovrShapeGetCollider(shape));
const char* tag = lovrColliderGetTag(collider);
if (!tag || strcmp(tag, data->tag)) {
return false;
}
}
float position[3];
vec3_set(position, x, y, z);
float distance = vec3_distance(data->origin, position);
if (distance < data->distance) {
vec3_init(data->position, position);
vec3_set(data->normal, nx, ny, nz);
vec3_init(data->normal, normal);
data->distance = distance;
data->collider = collider;
data->shape = shape;
}
return false;
}
static bool queryCallback(Shape* shape, void* userdata) {
static bool queryCallback(Collider* collider, uint32_t shape, void* userdata) {
lua_State* L = userdata;
lua_pushvalue(L, -1);
luax_pushshape(L, shape);
lua_call(L, 1, 1);
luax_pushtype(L, Collider, collider);
lua_pushinteger(L, shape);
lua_call(L, 2, 1);
bool shouldStop = lua_type(L, -1) == LUA_TBOOLEAN && !lua_toboolean(L, -1);
lua_pop(L, 1);
return shouldStop;
@ -99,9 +102,10 @@ static bool queryCallback(Shape* shape, void* userdata) {
static int l_lovrWorldNewCollider(lua_State* L) {
World* world = luax_checktype(L, 1, World);
Shape* shape = luax_totype(L, 2, Shape);
float position[3];
luax_readvec3(L, 2, position, NULL);
Collider* collider = lovrColliderCreate(world, position[0], position[1], position[2]);
luax_readvec3(L, 2 + !!shape, position, NULL);
Collider* collider = lovrColliderCreate(world, shape, position[0], position[1], position[2]);
luax_pushtype(L, Collider, collider);
lovrRelease(collider, lovrColliderDestroy);
return 1;
@ -111,9 +115,8 @@ static int l_lovrWorldNewBoxCollider(lua_State* L) {
World* world = luax_checktype(L, 1, World);
float position[3];
int index = luax_readvec3(L, 2, position, NULL);
Collider* collider = lovrColliderCreate(world, position[0], position[1], position[2]);
BoxShape* shape = luax_newboxshape(L, index);
lovrColliderAddShape(collider, shape);
Collider* collider = lovrColliderCreate(world, shape, position[0], position[1], position[2]);
lovrColliderInitInertia(collider, shape);
luax_pushtype(L, Collider, collider);
lovrRelease(collider, lovrColliderDestroy);
@ -125,9 +128,8 @@ static int l_lovrWorldNewCapsuleCollider(lua_State* L) {
World* world = luax_checktype(L, 1, World);
float position[3];
int index = luax_readvec3(L, 2, position, NULL);
Collider* collider = lovrColliderCreate(world, position[0], position[1], position[2]);
CapsuleShape* shape = luax_newcapsuleshape(L, index);
lovrColliderAddShape(collider, shape);
Collider* collider = lovrColliderCreate(world, shape, position[0], position[1], position[2]);
lovrColliderInitInertia(collider, shape);
luax_pushtype(L, Collider, collider);
lovrRelease(collider, lovrColliderDestroy);
@ -139,9 +141,8 @@ static int l_lovrWorldNewCylinderCollider(lua_State* L) {
World* world = luax_checktype(L, 1, World);
float position[3];
int index = luax_readvec3(L, 2, position, NULL);
Collider* collider = lovrColliderCreate(world, position[0], position[1], position[2]);
CylinderShape* shape = luax_newcylindershape(L, index);
lovrColliderAddShape(collider, shape);
Collider* collider = lovrColliderCreate(world, shape, position[0], position[1], position[2]);
lovrColliderInitInertia(collider, shape);
luax_pushtype(L, Collider, collider);
lovrRelease(collider, lovrColliderDestroy);
@ -153,9 +154,8 @@ static int l_lovrWorldNewSphereCollider(lua_State* L) {
World* world = luax_checktype(L, 1, World);
float position[3];
int index = luax_readvec3(L, 2, position, NULL);
Collider* collider = lovrColliderCreate(world, position[0], position[1], position[2]);
SphereShape* shape = luax_newsphereshape(L, index);
lovrColliderAddShape(collider, shape);
Collider* collider = lovrColliderCreate(world, shape, position[0], position[1], position[2]);
lovrColliderInitInertia(collider, shape);
luax_pushtype(L, Collider, collider);
lovrRelease(collider, lovrColliderDestroy);
@ -165,9 +165,8 @@ static int l_lovrWorldNewSphereCollider(lua_State* L) {
static int l_lovrWorldNewMeshCollider(lua_State* L) {
World* world = luax_checktype(L, 1, World);
Collider* collider = lovrColliderCreate(world, 0.f, 0.f, 0.f);
MeshShape* shape = luax_newmeshshape(L, 2);
lovrColliderAddShape(collider, shape);
Collider* collider = lovrColliderCreate(world, shape, 0.f, 0.f, 0.f);
lovrColliderInitInertia(collider, shape);
luax_pushtype(L, Collider, collider);
lovrRelease(collider, lovrColliderDestroy);
@ -177,9 +176,8 @@ static int l_lovrWorldNewMeshCollider(lua_State* L) {
static int l_lovrWorldNewTerrainCollider(lua_State* L) {
World* world = luax_checktype(L, 1, World);
Collider* collider = lovrColliderCreate(world, 0.f, 0.f, 0.f);
TerrainShape* shape = luax_newterrainshape(L, 2);
lovrColliderAddShape(collider, shape);
Collider* collider = lovrColliderCreate(world, shape, 0.f, 0.f, 0.f);
lovrColliderSetKinematic(collider, true);
luax_pushtype(L, Collider, collider);
lovrRelease(collider, lovrColliderDestroy);
@ -309,15 +307,16 @@ static int l_lovrWorldRaycastAny(lua_State* L) {
RaycastData data = { 0 };
data.tag = lua_tostring(L, index);
lovrWorldRaycast(world, start[0], start[1], start[2], end[0], end[1], end[2], raycastAnyCallback, &data);
if (data.shape) {
luax_pushshape(L, data.shape);
if (data.collider) {
luax_pushtype(L, Collider, data.collider);
lua_pushinteger(L, data.shape);
lua_pushnumber(L, data.position[0]);
lua_pushnumber(L, data.position[1]);
lua_pushnumber(L, data.position[2]);
lua_pushnumber(L, data.normal[0]);
lua_pushnumber(L, data.normal[1]);
lua_pushnumber(L, data.normal[2]);
return 7;
return 8;
} else {
lua_pushnil(L);
return 1;
@ -334,14 +333,15 @@ static int l_lovrWorldRaycastClosest(lua_State* L) {
data.tag = lua_tostring(L, index);
lovrWorldRaycast(world, start[0], start[1], start[2], end[0], end[1], end[2], raycastClosestCallback, &data);
if (data.shape) {
luax_pushshape(L, data.shape);
luax_pushtype(L, Collider, data.collider);
lua_pushinteger(L, data.shape);
lua_pushnumber(L, data.position[0]);
lua_pushnumber(L, data.position[1]);
lua_pushnumber(L, data.position[2]);
lua_pushnumber(L, data.normal[0]);
lua_pushnumber(L, data.normal[1]);
lua_pushnumber(L, data.normal[2]);
return 7;
return 8;
} else {
lua_pushnil(L);
return 1;
@ -375,11 +375,11 @@ static int l_lovrWorldQuerySphere(lua_State* L) {
static int l_lovrWorldGetGravity(lua_State* L) {
World* world = luax_checktype(L, 1, World);
float x, y, z;
lovrWorldGetGravity(world, &x, &y, &z);
lua_pushnumber(L, x);
lua_pushnumber(L, y);
lua_pushnumber(L, z);
float gravity[3];
lovrWorldGetGravity(world, gravity);
lua_pushnumber(L, gravity[0]);
lua_pushnumber(L, gravity[1]);
lua_pushnumber(L, gravity[2]);
return 3;
}
@ -387,7 +387,7 @@ static int l_lovrWorldSetGravity(lua_State* L) {
World* world = luax_checktype(L, 1, World);
float gravity[3];
luax_readvec3(L, 2, gravity, NULL);
lovrWorldSetGravity(world, gravity[0], gravity[1], gravity[2]);
lovrWorldSetGravity(world, gravity);
return 0;
}
@ -529,6 +529,11 @@ const luaL_Reg lovrWorld[] = {
{ "querySphere", l_lovrWorldQuerySphere },
{ "getGravity", l_lovrWorldGetGravity },
{ "setGravity", l_lovrWorldSetGravity },
{ "disableCollisionBetween", l_lovrWorldDisableCollisionBetween },
{ "enableCollisionBetween", l_lovrWorldEnableCollisionBetween },
{ "isCollisionEnabledBetween", l_lovrWorldIsCollisionEnabledBetween },
// Deprecated
{ "getTightness", l_lovrWorldGetTightness },
{ "setTightness", l_lovrWorldSetTightness },
{ "getResponseTime", l_lovrWorldGetResponseTime },
@ -539,10 +544,8 @@ const luaL_Reg lovrWorld[] = {
{ "setAngularDamping", l_lovrWorldSetAngularDamping },
{ "isSleepingAllowed", l_lovrWorldIsSleepingAllowed },
{ "setSleepingAllowed", l_lovrWorldSetSleepingAllowed },
{ "disableCollisionBetween", l_lovrWorldDisableCollisionBetween },
{ "enableCollisionBetween", l_lovrWorldEnableCollisionBetween },
{ "isCollisionEnabledBetween", l_lovrWorldIsCollisionEnabledBetween },
{ "getStepCount", l_lovrWorldGetStepCount },
{ "setStepCount", l_lovrWorldSetStepCount },
{ NULL, NULL }
};

View File

@ -19,6 +19,7 @@ typedef Shape CapsuleShape;
typedef Shape CylinderShape;
typedef Shape MeshShape;
typedef Shape TerrainShape;
typedef Shape CompoundShape;
typedef Joint BallJoint;
typedef Joint DistanceJoint;
@ -26,8 +27,8 @@ typedef Joint HingeJoint;
typedef Joint SliderJoint;
typedef void (*CollisionResolver)(World* world, void* userdata);
typedef bool (*RaycastCallback)(Shape* shape, float x, float y, float z, float nx, float ny, float nz, void* userdata);
typedef bool (*QueryCallback)(Shape* shape, void* userdata);
typedef bool (*RaycastCallback)(Collider* collider, uint32_t shape, float position[3], float normal[3], void* userdata);
typedef bool (*QueryCallback)(Collider* collider, uint32_t shape, void* userdata);
bool lovrPhysicsInit(void);
void lovrPhysicsDestroy(void);
@ -40,12 +41,20 @@ typedef struct {
float depth;
} Contact;
World* lovrWorldCreate(float xg, float yg, float zg, bool allowSleep, const char** tags, uint32_t tagCount);
typedef struct {
uint32_t maxColliders;
uint32_t maxColliderPairs;
uint32_t maxContacts;
bool allowSleep;
const char* tags[MAX_TAGS];
uint32_t tagCount;
float gravity[3]; // Deprecated
} WorldInfo;
World* lovrWorldCreate(WorldInfo* info);
void lovrWorldDestroy(void* ref);
void lovrWorldDestroyData(World* world);
void lovrWorldUpdate(World* world, float dt, CollisionResolver resolver, void* userdata);
int lovrWorldGetStepCount(World* world);
void lovrWorldSetStepCount(World* world, int iterations);
void lovrWorldComputeOverlaps(World* world);
int lovrWorldGetNextOverlap(World* world, Shape** a, Shape** b);
int lovrWorldCollide(World* world, Shape* a, Shape* b, float friction, float restitution);
@ -54,8 +63,16 @@ void lovrWorldRaycast(World* world, float x1, float y1, float z1, float x2, floa
bool lovrWorldQueryBox(World* world, float position[3], float size[3], QueryCallback callback, void* userdata);
bool lovrWorldQuerySphere(World* world, float position[3], float radius, QueryCallback callback, void* userdata);
Collider* lovrWorldGetFirstCollider(World* world);
void lovrWorldGetGravity(World* world, float* x, float* y, float* z);
void lovrWorldSetGravity(World* world, float x, float y, float z);
void lovrWorldGetGravity(World* world, float gravity[3]);
void lovrWorldSetGravity(World* world, float gravity[3]);
const char* lovrWorldGetTagName(World* world, uint32_t tag);
void lovrWorldDisableCollisionBetween(World* world, const char* tag1, const char* tag2);
void lovrWorldEnableCollisionBetween(World* world, const char* tag1, const char* tag2);
bool lovrWorldIsCollisionEnabledBetween(World* world, const char* tag1, const char* tag);
// Deprecated
int lovrWorldGetStepCount(World* world);
void lovrWorldSetStepCount(World* world, int iterations);
float lovrWorldGetResponseTime(World* world);
void lovrWorldSetResponseTime(World* world, float responseTime);
float lovrWorldGetTightness(World* world);
@ -66,23 +83,20 @@ void lovrWorldGetAngularDamping(World* world, float* damping, float* threshold);
void lovrWorldSetAngularDamping(World* world, float damping, float threshold);
bool lovrWorldIsSleepingAllowed(World* world);
void lovrWorldSetSleepingAllowed(World* world, bool allowed);
const char* lovrWorldGetTagName(World* world, uint32_t tag);
void lovrWorldDisableCollisionBetween(World* world, const char* tag1, const char* tag2);
void lovrWorldEnableCollisionBetween(World* world, const char* tag1, const char* tag2);
bool lovrWorldIsCollisionEnabledBetween(World* world, const char* tag1, const char* tag);
// Collider
Collider* lovrColliderCreate(World* world, float x, float y, float z);
Collider* lovrColliderCreate(World* world, Shape* shape, float x, float y, float z);
void lovrColliderDestroy(void* ref);
void lovrColliderDestroyData(Collider* collider);
bool lovrColliderIsDestroyed(Collider* collider);
void lovrColliderInitInertia(Collider* collider, Shape* shape);
World* lovrColliderGetWorld(Collider* collider);
Collider* lovrColliderGetNext(Collider* collider);
void lovrColliderAddShape(Collider* collider, Shape* shape);
void lovrColliderRemoveShape(Collider* collider, Shape* shape);
Shape** lovrColliderGetShapes(Collider* collider, size_t* count);
Shape* lovrColliderGetShape(Collider* collider);
void lovrColliderSetShape(Collider* collider, Shape* shape);
void lovrColliderGetShapeOffset(Collider* collider, float* position, float* orientation);
void lovrColliderSetShapeOffset(Collider* collider, float* position, float* orientation);
Joint** lovrColliderGetJoints(Collider* collider, size_t* count);
const char* lovrColliderGetTag(Collider* collider);
bool lovrColliderSetTag(Collider* collider, const char* tag);
@ -92,8 +106,8 @@ float lovrColliderGetRestitution(Collider* collider);
void lovrColliderSetRestitution(Collider* collider, float restitution);
bool lovrColliderIsKinematic(Collider* collider);
void lovrColliderSetKinematic(Collider* collider, bool kinematic);
bool lovrColliderIsGravityIgnored(Collider* collider);
void lovrColliderSetGravityIgnored(Collider* collider, bool ignored);
float lovrColliderGetGravityScale(Collider* collider);
void lovrColliderSetGravityScale(Collider* collider, float scale);
bool lovrColliderIsSleepingAllowed(Collider* collider);
void lovrColliderSetSleepingAllowed(Collider* collider, bool allowed);
bool lovrColliderIsAwake(Collider* collider);
@ -134,48 +148,48 @@ typedef enum {
SHAPE_CAPSULE,
SHAPE_CYLINDER,
SHAPE_MESH,
SHAPE_TERRAIN
SHAPE_TERRAIN,
SHAPE_COMPOUND
} ShapeType;
void lovrShapeDestroy(void* ref);
void lovrShapeDestroyData(Shape* shape);
ShapeType lovrShapeGetType(Shape* shape);
Collider* lovrShapeGetCollider(Shape* shape);
bool lovrShapeIsEnabled(Shape* shape);
void lovrShapeSetEnabled(Shape* shape, bool enabled);
bool lovrShapeIsSensor(Shape* shape);
void lovrShapeSetSensor(Shape* shape, bool sensor);
void lovrShapeGetPosition(Shape* shape, float* x, float* y, float* z);
void lovrShapeSetPosition(Shape* shape, float x, float y, float z);
void lovrShapeGetOrientation(Shape* shape, float* orientation);
void lovrShapeSetOrientation(Shape* shape, float* orientation);
void lovrShapeGetMass(Shape* shape, float density, float* cx, float* cy, float* cz, float* mass, float inertia[6]);
void lovrShapeGetAABB(Shape* shape, float aabb[6]);
SphereShape* lovrSphereShapeCreate(float radius);
float lovrSphereShapeGetRadius(SphereShape* sphere);
void lovrSphereShapeSetRadius(SphereShape* sphere, float radius);
BoxShape* lovrBoxShapeCreate(float w, float h, float d);
void lovrBoxShapeGetDimensions(BoxShape* box, float* w, float* h, float* d);
void lovrBoxShapeSetDimensions(BoxShape* box, float w, float h, float d);
CapsuleShape* lovrCapsuleShapeCreate(float radius, float length);
float lovrCapsuleShapeGetRadius(CapsuleShape* capsule);
void lovrCapsuleShapeSetRadius(CapsuleShape* capsule, float radius);
float lovrCapsuleShapeGetLength(CapsuleShape* capsule);
void lovrCapsuleShapeSetLength(CapsuleShape* capsule, float length);
CylinderShape* lovrCylinderShapeCreate(float radius, float length);
float lovrCylinderShapeGetRadius(CylinderShape* cylinder);
void lovrCylinderShapeSetRadius(CylinderShape* cylinder, float radius);
float lovrCylinderShapeGetLength(CylinderShape* cylinder);
void lovrCylinderShapeSetLength(CylinderShape* cylinder, float length);
MeshShape* lovrMeshShapeCreate(int vertexCount, float vertices[], int indexCount, uint32_t indices[]);
TerrainShape* lovrTerrainShapeCreate(float* vertices, uint32_t widthSamples, uint32_t depthSamples, float horizontalScale, float verticalScale);
CompoundShape* lovrCompoundShapeCreate(Shape** shapes, float* positions, float* orientations, uint32_t count, bool freeze);
bool lovrCompoundShapeIsFrozen(CompoundShape* shape);
void lovrCompoundShapeAddShape(CompoundShape* shape, Shape* child, float* position, float* orientation);
void lovrCompoundShapeReplaceShape(CompoundShape* shape, uint32_t index, Shape* child, float* position, float* orientation);
void lovrCompoundShapeRemoveShape(CompoundShape* shape, uint32_t index);
Shape* lovrCompoundShapeGetShape(CompoundShape* shape, uint32_t index);
uint32_t lovrCompoundShapeGetShapeCount(CompoundShape* shape);
void lovrCompoundShapeGetShapeOffset(CompoundShape* shape, uint32_t index, float* position, float* orientation);
void lovrCompoundShapeSetShapeOffset(CompoundShape* shape, uint32_t index, float* position, float* orientation);
// These tokens need to exist for Lua bindings
#define lovrSphereShapeDestroy lovrShapeDestroy
#define lovrBoxShapeDestroy lovrShapeDestroy
@ -183,6 +197,7 @@ TerrainShape* lovrTerrainShapeCreate(float* vertices, uint32_t widthSamples, uin
#define lovrCylinderShapeDestroy lovrShapeDestroy
#define lovrMeshShapeDestroy lovrShapeDestroy
#define lovrTerrainShapeDestroy lovrShapeDestroy
#define lovrCompoundShapeDestroy lovrShapeDestroy
// Joints

File diff suppressed because it is too large Load Diff

View File

@ -22,7 +22,7 @@ struct Collider {
Collider* prev;
Collider* next;
uint32_t tag;
arr_t(Shape*) shapes;
Shape* shape;
arr_t(Joint*) joints;
float friction;
float restitution;
@ -66,8 +66,9 @@ static void raycastCallback(void* d, dGeomID a, dGeomID b) {
RaycastCallback callback = data->callback;
void* userdata = data->userdata;
Shape* shape = dGeomGetData(b);
Collider* collider = dBodyGetData(dGeomGetBody(b));
if (!shape) {
if (!shape || !collider) {
return;
}
@ -75,9 +76,7 @@ static void raycastCallback(void* d, dGeomID a, dGeomID b) {
int count = dCollide(a, b, MAX_CONTACTS, &contact->geom, sizeof(dContact));
for (int i = 0; i < count; i++) {
dContactGeom g = contact[i].geom;
data->shouldStop = callback(
shape, g.pos[0], g.pos[1], g.pos[2], g.normal[0], g.normal[1], g.normal[2], userdata
);
data->shouldStop = callback(collider, 0, g.pos, g.normal, userdata);
}
}
@ -93,14 +92,15 @@ static void queryCallback(void* d, dGeomID a, dGeomID b) {
if (data->shouldStop) return;
Shape* shape = dGeomGetData(b);
if (!shape) {
Collider* collider = dBodyGetData(dGeomGetBody(b));
if (!shape || !collider) {
return;
}
dContactGeom contact;
if (dCollide(a, b, 1 | CONTACTS_UNIMPORTANT, &contact, sizeof(contact))) {
if (data->callback) {
data->shouldStop = data->callback(shape, data->userdata);
data->shouldStop = data->callback(collider, 0, data->userdata);
} else {
data->shouldStop = true;
}
@ -154,7 +154,7 @@ void lovrPhysicsDestroy(void) {
dCloseODE();
}
World* lovrWorldCreate(float xg, float yg, float zg, bool allowSleep, const char** tags, uint32_t tagCount) {
World* lovrWorldCreate(WorldInfo* info) {
World* world = lovrCalloc(sizeof(World));
world->ref = 1;
world->id = dWorldCreate();
@ -162,12 +162,12 @@ World* lovrWorldCreate(float xg, float yg, float zg, bool allowSleep, const char
dHashSpaceSetLevels(world->space, -4, 8);
world->contactGroup = dJointGroupCreate(0);
arr_init(&world->overlaps);
lovrWorldSetGravity(world, xg, yg, zg);
lovrWorldSetSleepingAllowed(world, allowSleep);
for (uint32_t i = 0; i < tagCount; i++) {
size_t size = strlen(tags[i]) + 1;
lovrWorldSetGravity(world, info->gravity);
lovrWorldSetSleepingAllowed(world, info->allowSleep);
for (uint32_t i = 0; i < info->tagCount; i++) {
size_t size = strlen(info->tags[i]) + 1;
world->tags[i] = lovrMalloc(size);
memcpy(world->tags[i], tags[i], size);
memcpy(world->tags[i], info->tags[i], size);
}
memset(world->masks, 0xff, sizeof(world->masks));
return world;
@ -339,16 +339,16 @@ Collider* lovrWorldGetFirstCollider(World* world) {
return world->head;
}
void lovrWorldGetGravity(World* world, float* x, float* y, float* z) {
dReal gravity[4];
dWorldGetGravity(world->id, gravity);
*x = gravity[0];
*y = gravity[1];
*z = gravity[2];
void lovrWorldGetGravity(World* world, float gravity[3]) {
dReal g[4];
dWorldGetGravity(world->id, g);
gravity[0] = g[0];
gravity[1] = g[1];
gravity[2] = g[2];
}
void lovrWorldSetGravity(World* world, float x, float y, float z) {
dWorldSetGravity(world->id, x, y, z);
void lovrWorldSetGravity(World* world, float gravity[3]) {
dWorldSetGravity(world->id, gravity[0], gravity[1], gravity[2]);
}
float lovrWorldGetResponseTime(World* world) {
@ -436,7 +436,7 @@ bool lovrWorldIsCollisionEnabledBetween(World* world, const char* tag1, const ch
return (world->masks[i] & (1 << j)) && (world->masks[j] & (1 << i));
}
Collider* lovrColliderCreate(World* world, float x, float y, float z) {
Collider* lovrColliderCreate(World* world, Shape* shape, float x, float y, float z) {
Collider* collider = lovrCalloc(sizeof(Collider));
collider->ref = 1;
collider->body = dBodyCreate(world->id);
@ -445,9 +445,9 @@ Collider* lovrColliderCreate(World* world, float x, float y, float z) {
collider->restitution = 0;
collider->tag = NO_TAG;
dBodySetData(collider->body, collider);
arr_init(&collider->shapes);
arr_init(&collider->joints);
lovrColliderSetShape(collider, shape);
lovrColliderSetPosition(collider, x, y, z);
// Adjust the world's collider list
@ -467,7 +467,6 @@ Collider* lovrColliderCreate(World* world, float x, float y, float z) {
void lovrColliderDestroy(void* ref) {
Collider* collider = ref;
lovrColliderDestroyData(collider);
arr_free(&collider->shapes);
arr_free(&collider->joints);
lovrFree(collider);
}
@ -477,13 +476,9 @@ void lovrColliderDestroyData(Collider* collider) {
return;
}
lovrColliderSetShape(collider, NULL);
size_t count;
Shape** shapes = lovrColliderGetShapes(collider, &count);
for (size_t i = 0; i < count; i++) {
lovrColliderRemoveShape(collider, shapes[i]);
}
Joint** joints = lovrColliderGetJoints(collider, &count);
for (size_t i = 0; i < count; i++) {
lovrRelease(joints[i], lovrJointDestroy);
@ -521,38 +516,50 @@ Collider* lovrColliderGetNext(Collider* collider) {
return collider->next;
}
void lovrColliderAddShape(Collider* collider, Shape* shape) {
lovrRetain(shape);
if (shape->collider) {
lovrColliderRemoveShape(shape->collider, shape);
}
shape->collider = collider;
dGeomSetBody(shape->id, collider->body);
dSpaceID newSpace = collider->world->space;
dSpaceAdd(newSpace, shape->id);
Shape* lovrColliderGetShape(Collider* collider) {
return collider->shape;
}
void lovrColliderRemoveShape(Collider* collider, Shape* shape) {
if (shape->collider == collider) {
dSpaceRemove(collider->world->space, shape->id);
dGeomSetBody(shape->id, 0);
shape->collider = NULL;
lovrRelease(shape, lovrShapeDestroy);
void lovrColliderSetShape(Collider* collider, Shape* shape) {
if (collider->shape) {
dSpaceRemove(collider->world->space, collider->shape->id);
dGeomSetBody(collider->shape->id, 0);
collider->shape->collider = NULL;
lovrRelease(collider->shape, lovrShapeDestroy);
}
}
Shape** lovrColliderGetShapes(Collider* collider, size_t* count) {
arr_clear(&collider->shapes);
for (dGeomID geom = dBodyGetFirstGeom(collider->body); geom; geom = dBodyGetNextGeom(geom)) {
Shape* shape = dGeomGetData(geom);
if (shape) {
arr_push(&collider->shapes, shape);
collider->shape = shape;
if (shape) {
if (shape->collider) {
lovrColliderSetShape(shape->collider, NULL);
}
shape->collider = collider;
dGeomSetBody(shape->id, collider->body);
dSpaceID newSpace = collider->world->space;
dSpaceAdd(newSpace, shape->id);
lovrRetain(shape);
}
*count = collider->shapes.length;
return collider->shapes.data;
}
void lovrColliderGetShapeOffset(Collider* collider, float* position, float* orientation) {
const dReal* p = dGeomGetOffsetPosition(collider->shape->id);
position[0] = p[0];
position[1] = p[1];
position[2] = p[2];
dReal q[4];
dGeomGetOffsetQuaternion(collider->shape->id, q);
orientation[0] = q[1];
orientation[1] = q[2];
orientation[2] = q[3];
orientation[3] = q[0];
}
void lovrColliderSetShapeOffset(Collider* collider, float* position, float* orientation) {
dGeomSetOffsetPosition(collider->shape->id, position[0], position[1], position[2]);
dReal q[4] = { orientation[3], orientation[0], orientation[1], orientation[2] };
dGeomSetOffsetQuaternion(collider->shape->id, q);
}
Joint** lovrColliderGetJoints(Collider* collider, size_t* count) {
@ -610,12 +617,12 @@ void lovrColliderSetKinematic(Collider* collider, bool kinematic) {
}
}
bool lovrColliderIsGravityIgnored(Collider* collider) {
return !dBodyGetGravityMode(collider->body);
float lovrColliderGetGravityScale(Collider* collider) {
return dBodyGetGravityMode(collider->body) ? 1.f : 0.f;
}
void lovrColliderSetGravityIgnored(Collider* collider, bool ignored) {
dBodySetGravityMode(collider->body, !ignored);
void lovrColliderSetGravityScale(Collider* collider, float scale) {
dBodySetGravityMode(collider->body, scale == 0.f ? false : true);
}
bool lovrColliderIsSleepingAllowed(Collider* collider) {
@ -888,31 +895,6 @@ void lovrShapeSetSensor(Shape* shape, bool sensor) {
shape->sensor = sensor;
}
void lovrShapeGetPosition(Shape* shape, float* x, float* y, float* z) {
const dReal* position = dGeomGetOffsetPosition(shape->id);
*x = position[0];
*y = position[1];
*z = position[2];
}
void lovrShapeSetPosition(Shape* shape, float x, float y, float z) {
dGeomSetOffsetPosition(shape->id, x, y, z);
}
void lovrShapeGetOrientation(Shape* shape, float* orientation) {
dReal q[4];
dGeomGetOffsetQuaternion(shape->id, q);
orientation[0] = q[1];
orientation[1] = q[2];
orientation[2] = q[3];
orientation[3] = q[0];
}
void lovrShapeSetOrientation(Shape* shape, float* orientation) {
dReal q[4] = { orientation[3], orientation[0], orientation[1], orientation[2] };
dGeomSetOffsetQuaternion(shape->id, q);
}
void lovrShapeGetMass(Shape* shape, float density, float* cx, float* cy, float* cz, float* mass, float inertia[6]) {
dMass m;
dMassSetZero(&m);
@ -953,6 +935,8 @@ void lovrShapeGetMass(Shape* shape, float density, float* cx, float* cy, float*
case SHAPE_TERRAIN: {
break;
}
default: break;
}
const dReal* position = dGeomGetOffsetPosition(shape->id);
@ -1112,6 +1096,42 @@ TerrainShape* lovrTerrainShapeCreate(float* vertices, uint32_t widthSamples, uin
return terrain;
}
CompoundShape* lovrCompoundShapeCreate(Shape** shapes, float* positions, float* orientations, uint32_t count, bool freeze) {
lovrThrow("ODE does not support compound shape");
}
bool lovrCompoundShapeIsFrozen(CompoundShape* shape) {
return false;
}
void lovrCompoundShapeAddShape(CompoundShape* shape, Shape* child, float* position, float* orientation) {
//
}
void lovrCompoundShapeReplaceShape(CompoundShape* shape, uint32_t index, Shape* child, float* position, float* orientation) {
//
}
void lovrCompoundShapeRemoveShape(CompoundShape* shape, uint32_t index) {
//
}
Shape* lovrCompoundShapeGetShape(CompoundShape* shape, uint32_t index) {
return NULL;
}
uint32_t lovrCompoundShapeGetShapeCount(CompoundShape* shape) {
return 0;
}
void lovrCompoundShapeGetShapeOffset(CompoundShape* shape, uint32_t index, float* position, float* orientation) {
//
}
void lovrCompoundShapeSetShapeOffset(CompoundShape* shape, uint32_t index, float* position, float* orientation) {
//
}
void lovrJointDestroy(void* ref) {
Joint* joint = ref;
lovrJointDestroyData(joint);