From f70d98714f007fbcbeea9067d28e6e3d9781a69b Mon Sep 17 00:00:00 2001 From: bjorn Date: Sun, 12 May 2024 15:10:06 -0700 Subject: [PATCH] Giant Shape rework!; --- CHANGES.md | 1 - deps/jolt-physics-sharp | 2 +- src/api/l_physics.c | 11 - src/api/l_physics_collider.c | 111 +++-- src/api/l_physics_shapes.c | 343 ++++++------- src/api/l_physics_world.c | 35 +- src/modules/physics/physics.h | 44 +- src/modules/physics/physics_jolt.c | 751 +++++++++++++++++++++-------- src/modules/physics/physics_ode.c | 106 ++-- 9 files changed, 823 insertions(+), 581 deletions(-) diff --git a/CHANGES.md b/CHANGES.md index d98a94348..9edfa87c6 100644 --- a/CHANGES.md +++ b/CHANGES.md @@ -41,7 +41,6 @@ dev - Add `Collider:get/setCenterOfMass`. - Add `Collider:resetMassData`. - Add `Collider:is/setEnabled`. -- Add `CompoundShape`. - Add `ConvexShape`. - Add `WeldJoint`. - Add `ConeJoint`. diff --git a/deps/jolt-physics-sharp b/deps/jolt-physics-sharp index 75c1f2623..1fead37b3 160000 --- a/deps/jolt-physics-sharp +++ b/deps/jolt-physics-sharp @@ -1 +1 @@ -Subproject commit 75c1f26235af213e7f1d3a30f5e10ca9749bf798 +Subproject commit 1fead37b3a6d73ff5a560c4c1a3d39067abfda60 diff --git a/src/api/l_physics.c b/src/api/l_physics.c index 9de894861..9572fed3b 100644 --- a/src/api/l_physics.c +++ b/src/api/l_physics.c @@ -11,7 +11,6 @@ StringEntry lovrShapeType[] = { [SHAPE_CONVEX] = ENTRY("convex"), [SHAPE_MESH] = ENTRY("mesh"), [SHAPE_TERRAIN] = ENTRY("terrain"), - [SHAPE_COMPOUND] = ENTRY("compound"), { 0 } }; @@ -212,13 +211,6 @@ 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 int l_lovrPhysicsNewWeldJoint(lua_State* L) { Collider* a = luax_totype(L, 1, Collider); Collider* b = luax_totype(L, 2, Collider); @@ -297,7 +289,6 @@ static const luaL_Reg lovrPhysics[] = { { "newConvexShape", l_lovrPhysicsNewConvexShape }, { "newMeshShape", l_lovrPhysicsNewMeshShape }, { "newTerrainShape", l_lovrPhysicsNewTerrainShape }, - { "newCompoundShape", l_lovrPhysicsNewCompoundShape }, { "newWeldJoint", l_lovrPhysicsNewWeldJoint }, { "newBallJoint", l_lovrPhysicsNewBallJoint }, { "newConeJoint", l_lovrPhysicsNewConeJoint }, @@ -317,7 +308,6 @@ extern const luaL_Reg lovrCylinderShape[]; extern const luaL_Reg lovrConvexShape[]; extern const luaL_Reg lovrMeshShape[]; extern const luaL_Reg lovrTerrainShape[]; -extern const luaL_Reg lovrCompoundShape[]; extern const luaL_Reg lovrWeldJoint[]; extern const luaL_Reg lovrBallJoint[]; extern const luaL_Reg lovrConeJoint[]; @@ -338,7 +328,6 @@ int luaopen_lovr_physics(lua_State* L) { luax_registertype(L, ConvexShape); luax_registertype(L, MeshShape); luax_registertype(L, TerrainShape); - luax_registertype(L, CompoundShape); luax_registertype(L, WeldJoint); luax_registertype(L, BallJoint); luax_registertype(L, ConeJoint); diff --git a/src/api/l_physics_collider.c b/src/api/l_physics_collider.c index 034aff5cb..33b024db1 100644 --- a/src/api/l_physics_collider.c +++ b/src/api/l_physics_collider.c @@ -38,9 +38,33 @@ static int l_lovrColliderGetWorld(lua_State* L) { return 1; } +static int l_lovrColliderGetJoints(lua_State* L) { + Collider* collider = luax_checktype(L, 1, Collider); + lua_newtable(L); + int index = 1; + Joint* joint = NULL; + while ((joint = lovrColliderGetJoints(collider, joint)) != NULL) { + luax_pushjoint(L, joint); + lua_rawseti(L, -2, index++); + } + return 1; +} + +static int l_lovrColliderGetShapes(lua_State* L) { + Collider* collider = luax_checktype(L, 1, Collider); + lua_newtable(L); + int index = 1; + Shape* shape = NULL; + while ((shape = lovrColliderGetShapes(collider, shape)) != NULL) { + luax_pushshape(L, shape); + lua_rawseti(L, -2, index++); + } + return 1; +} + static int l_lovrColliderGetShape(lua_State* L) { Collider* collider = luax_checktype(L, 1, Collider); - Shape* shape = lovrColliderGetShape(collider); + Shape* shape = lovrColliderGetShapes(collider, NULL); if (shape) { luax_pushshape(L, shape); } else { @@ -49,23 +73,19 @@ static int l_lovrColliderGetShape(lua_State* L) { return 1; } -static int l_lovrColliderSetShape(lua_State* L) { +static int l_lovrColliderAddShape(lua_State* L) { Collider* collider = luax_checktype(L, 1, Collider); - Shape* shape = lua_isnoneornil(L, 2) ? NULL : luax_checkshape(L, 2); - lovrColliderSetShape(collider, shape); - return 0; + Shape* shape = luax_checkshape(L, 2); + lovrColliderAddShape(collider, shape); + lua_settop(L, 2); + return 1; } -static int l_lovrColliderGetJoints(lua_State* L) { +static int l_lovrColliderRemoveShape(lua_State* L) { Collider* collider = luax_checktype(L, 1, Collider); - lua_newtable(L); - int index = 1; - Joint* joint = NULL; - while ((joint = lovrColliderGetJoints(collider, joint)) != NULL) { - luax_pushjoint(L, joint); - lua_rawseti(L, -2, index++); - } - return 1; + Shape* shape = luax_checkshape(L, 2); + lovrColliderRemoveShape(collider, shape); + return 0; } static int l_lovrColliderGetUserData(lua_State* L) { @@ -174,12 +194,8 @@ static int l_lovrColliderGetMass(lua_State* L) { static int l_lovrColliderSetMass(lua_State* L) { Collider* collider = luax_checktype(L, 1, Collider); - if (lua_isnoneornil(L, 2)) { - lovrColliderSetMass(collider, NULL); - } else { - float mass = luax_checkfloat(L, 2); - lovrColliderSetMass(collider, &mass); - } + float mass = luax_checkfloat(L, 2); + lovrColliderSetMass(collider, mass); return 0; } @@ -199,14 +215,10 @@ static int l_lovrColliderGetInertia(lua_State* L) { static int l_lovrColliderSetInertia(lua_State* L) { Collider* collider = luax_checktype(L, 1, Collider); - if (lua_isnoneornil(L, 2)) { - lovrColliderSetInertia(collider, NULL, NULL); - } else { - float diagonal[3], rotation[4]; - int index = luax_readvec3(L, 2, diagonal, NULL); - luax_readquat(L, index, rotation, NULL); - lovrColliderSetInertia(collider, diagonal, rotation); - } + float diagonal[3], rotation[4]; + int index = luax_readvec3(L, 2, diagonal, NULL); + luax_readquat(L, index, rotation, NULL); + lovrColliderSetInertia(collider, diagonal, rotation); return 0; } @@ -222,13 +234,23 @@ static int l_lovrColliderGetCenterOfMass(lua_State* L) { static int l_lovrColliderSetCenterOfMass(lua_State* L) { Collider* collider = luax_checktype(L, 1, Collider); - if (lua_isnoneornil(L, 2)) { - lovrColliderSetCenterOfMass(collider, NULL); - } else { - float center[3]; - luax_readvec3(L, 2, center, NULL); - lovrColliderSetCenterOfMass(collider, center); - } + float center[3]; + luax_readvec3(L, 2, center, NULL); + lovrColliderSetCenterOfMass(collider, center); + return 0; +} + +static int l_lovrColliderGetAutomaticMass(lua_State* L) { + Collider* collider = luax_checktype(L, 1, Collider); + bool enabled = lovrColliderGetAutomaticMass(collider); + lua_pushboolean(L, enabled); + return 1; +} + +static int l_lovrColliderSetAutomaticMass(lua_State* L) { + Collider* collider = luax_checktype(L, 1, Collider); + bool enable = lua_toboolean(L, 2); + lovrColliderSetAutomaticMass(collider, enable); return 0; } @@ -607,16 +629,6 @@ 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); @@ -638,9 +650,11 @@ const luaL_Reg lovrCollider[] = { { "isEnabled", l_lovrColliderIsEnabled }, { "setEnabled", l_lovrColliderSetEnabled }, { "getWorld", l_lovrColliderGetWorld }, - { "getShape", l_lovrColliderGetShape }, - { "setShape", l_lovrColliderSetShape }, { "getJoints", l_lovrColliderGetJoints }, + { "getShapes", l_lovrColliderGetShapes }, + { "getShape", l_lovrColliderGetShape }, + { "addShape", l_lovrColliderAddShape }, + { "removeShape", l_lovrColliderRemoveShape }, { "getUserData", l_lovrColliderGetUserData }, { "setUserData", l_lovrColliderSetUserData }, { "isKinematic", l_lovrColliderIsKinematic }, @@ -661,6 +675,8 @@ const luaL_Reg lovrCollider[] = { { "setInertia", l_lovrColliderSetInertia }, { "getCenterOfMass", l_lovrColliderGetCenterOfMass }, { "setCenterOfMass", l_lovrColliderSetCenterOfMass }, + { "getAutomaticMass", l_lovrColliderGetAutomaticMass }, + { "setAutomaticMass", l_lovrColliderSetAutomaticMass }, { "resetMassData", l_lovrColliderResetMassData }, { "getEnabledAxes", l_lovrColliderGetEnabledAxes }, { "setEnabledAxes", l_lovrColliderSetEnabledAxes }, @@ -699,7 +715,6 @@ const luaL_Reg lovrCollider[] = { { "setTag", l_lovrColliderSetTag }, // Deprecated - { "getShapes", l_lovrColliderGetShapes }, { "isGravityIgnored", l_lovrColliderIsGravityIgnored }, { "setGravityIgnored", l_lovrColliderSetGravityIgnored }, diff --git a/src/api/l_physics_shapes.c b/src/api/l_physics_shapes.c index 3ba5a04e3..b884a7826 100644 --- a/src/api/l_physics_shapes.c +++ b/src/api/l_physics_shapes.c @@ -15,7 +15,6 @@ void luax_pushshape(lua_State* L, Shape* shape) { case SHAPE_CONVEX: luax_pushtype(L, ConvexShape, 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(); } } @@ -31,8 +30,7 @@ Shape* luax_checkshape(lua_State* L, int index) { hash64("CylinderShape", strlen("CylinderShape")), hash64("ConvexShape", strlen("ConvexShape")), hash64("MeshShape", strlen("MeshShape")), - hash64("TerrainShape", strlen("TerrainShape")), - hash64("CompoundShape", strlen("CompoundShape")) + hash64("TerrainShape", strlen("TerrainShape")) }; for (size_t i = 0; i < COUNTOF(hashes); i++) { @@ -70,6 +68,9 @@ Shape* luax_newcylindershape(lua_State* L, int index) { } Shape* luax_newconvexshape(lua_State* L, int index) { + ConvexShape* parent = luax_totype(L, index, ConvexShape); + if (parent) return lovrConvexShapeClone(parent); + float* points; uint32_t count; bool shouldFree; @@ -80,6 +81,9 @@ Shape* luax_newconvexshape(lua_State* L, int index) { } Shape* luax_newmeshshape(lua_State* L, int index) { + MeshShape* parent = luax_totype(L, index, MeshShape); + if (parent) return lovrMeshShapeClone(parent); + float* vertices; uint32_t* indices; uint32_t vertexCount; @@ -149,83 +153,17 @@ 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); - 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); +static int l_lovrShapeDestroy(lua_State* L) { + Shape* shape = luax_checkshape(L, 1); + lovrShapeDestroyData(shape); + return 0; +} - CompoundShape* shape = lovrCompoundShapeCreate(shapes, positions, orientations, length, freeze); - lovrDeferPop(defer); - return shape; +static int l_lovrShapeIsDestroyed(lua_State* L) { + Shape* shape = luax_checkshape(L, 1); + bool destroyed = lovrShapeIsDestroyed(shape); + lua_pushboolean(L, destroyed); + return 1; } static int l_lovrShapeGetType(lua_State* L) { @@ -234,6 +172,13 @@ static int l_lovrShapeGetType(lua_State* L) { return 1; } +static int l_lovrShapeGetCollider(lua_State* L) { + Shape* shape = luax_checkshape(L, 1); + Collider* collider = lovrShapeGetCollider(shape); + luax_pushtype(L, Collider, collider); + return 1; +} + static int l_lovrShapeGetUserData(lua_State* L) { luax_checkshape(L, 1); luax_pushstash(L, "lovr.shape.userdata"); @@ -304,25 +249,81 @@ static int l_lovrShapeGetCenterOfMass(lua_State* L) { return 3; } +static int l_lovrShapeGetOffset(lua_State* L) { + Shape* shape = luax_checkshape(L, 1); + float position[3], orientation[4], angle, ax, ay, az; + lovrShapeGetOffset(shape, 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_lovrShapeSetOffset(lua_State* L) { + Shape* shape = luax_checkshape(L, 1); + float position[3], orientation[4]; + int index = 2; + index = luax_readvec3(L, index, position, NULL); + index = luax_readquat(L, index, orientation, NULL); + lovrShapeSetOffset(shape, position, orientation); + return 0; +} + +static int l_lovrShapeGetPosition(lua_State* L) { + Shape* shape = luax_checkshape(L, 1); + float position[3]; + lovrShapeGetPose(shape, position, NULL); + lua_pushnumber(L, position[0]); + lua_pushnumber(L, position[1]); + lua_pushnumber(L, position[2]); + return 3; +} + +static int l_lovrShapeGetOrientation(lua_State* L) { + Shape* shape = luax_checkshape(L, 1); + float orientation[4], angle, x, y, z; + lovrShapeGetPose(shape, NULL, 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_lovrShapeGetPose(lua_State* L) { + Shape* shape = luax_checkshape(L, 1); + float position[3], orientation[4], angle, ax, ay, az; + lovrShapeGetPose(shape, 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_lovrShapeGetAABB(lua_State* L) { Shape* shape = luax_checkshape(L, 1); - float position[3], orientation[4], aabb[6]; - if (lua_gettop(L) >= 2) { - int index = 2; - index = luax_readvec3(L, index, position, NULL); - index = luax_readquat(L, index, orientation, NULL); - lovrShapeGetAABB(shape, position, orientation, aabb); - } else { - lovrShapeGetAABB(shape, NULL, NULL, aabb); - } - for (int i = 0; i < 6; i++) { - lua_pushnumber(L, aabb[i]); - } + float aabb[6]; + lovrShapeGetAABB(shape, aabb); + for (int i = 0; i < 6; i++) lua_pushnumber(L, aabb[i]); return 6; } #define lovrShape \ + { "destroy", l_lovrShapeDestroy }, \ + { "isDestroyed", l_lovrShapeIsDestroyed }, \ { "getType", l_lovrShapeGetType }, \ + { "getCollider", l_lovrShapeGetCollider }, \ { "getUserData", l_lovrShapeGetUserData }, \ { "setUserData", l_lovrShapeSetUserData }, \ { "getVolume", l_lovrShapeGetVolume }, \ @@ -331,6 +332,11 @@ static int l_lovrShapeGetAABB(lua_State* L) { { "getMass", l_lovrShapeGetMass }, \ { "getInertia", l_lovrShapeGetInertia }, \ { "getCenterOfMass", l_lovrShapeGetCenterOfMass }, \ + { "getOffset", l_lovrShapeGetOffset }, \ + { "setOffset", l_lovrShapeSetOffset }, \ + { "getPosition", l_lovrShapeGetPosition }, \ + { "getOrientation", l_lovrShapeGetOrientation }, \ + { "getPose", l_lovrShapeGetPose }, \ { "getAABB", l_lovrShapeGetAABB } static int l_lovrBoxShapeGetDimensions(lua_State* L) { @@ -343,9 +349,18 @@ static int l_lovrBoxShapeGetDimensions(lua_State* L) { return 3; } +static int l_lovrBoxShapeSetDimensions(lua_State* L) { + BoxShape* box = luax_checktype(L, 1, BoxShape); + float dimensions[3]; + luax_readvec3(L, 2, dimensions, NULL); + lovrBoxShapeSetDimensions(box, dimensions); + return 0; +} + const luaL_Reg lovrBoxShape[] = { lovrShape, { "getDimensions", l_lovrBoxShapeGetDimensions }, + { "setDimensions", l_lovrBoxShapeSetDimensions }, { NULL, NULL } }; @@ -355,9 +370,17 @@ 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 } }; @@ -367,16 +390,32 @@ 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 } }; @@ -386,16 +425,32 @@ 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 } }; @@ -460,109 +515,3 @@ 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_lovrCompoundShapeAddChild(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); - lovrCompoundShapeAddChild(shape, child, position, orientation); - return 0; -} - -static int l_lovrCompoundShapeReplaceChild(lua_State* L) { - CompoundShape* shape = luax_checktype(L, 1, CompoundShape); - uint32_t index = luax_checku32(L, 2) - 1; - 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); - lovrCompoundShapeReplaceChild(shape, index, child, position, orientation); - return 0; -} - -static int l_lovrCompoundShapeRemoveChild(lua_State* L) { - CompoundShape* shape = luax_checktype(L, 1, CompoundShape); - uint32_t index = luax_checku32(L, 2) - 1; - lovrCompoundShapeRemoveChild(shape, index); - return 0; -} - -static int l_lovrCompoundShapeGetChild(lua_State* L) { - CompoundShape* shape = luax_checktype(L, 1, CompoundShape); - uint32_t index = luax_checku32(L, 2) - 1; - Shape* child = lovrCompoundShapeGetChild(shape, index); - luax_pushshape(L, child); - return 1; -} - -static int l_lovrCompoundShapeGetChildren(lua_State* L) { - CompoundShape* shape = luax_checktype(L, 1, CompoundShape); - int count = (int) lovrCompoundShapeGetChildCount(shape); - lua_createtable(L, count, 0); - for (int i = 0; i < count; i++) { - Shape* child = lovrCompoundShapeGetChild(shape, (uint32_t) i); - luax_pushshape(L, child); - lua_rawseti(L, -2, i + 1); - } - return 1; -} - -static int l_lovrCompoundShapeGetChildCount(lua_State* L) { - CompoundShape* shape = luax_checktype(L, 1, CompoundShape); - uint32_t count = lovrCompoundShapeGetChildCount(shape); - lua_pushinteger(L, count); - return 1; -} - -static int l_lovrCompoundShapeGetChildOffset(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; - lovrCompoundShapeGetChildOffset(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_lovrCompoundShapeSetChildOffset(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); - lovrCompoundShapeSetChildOffset(shape, index, position, orientation); - return 0; -} - -const luaL_Reg lovrCompoundShape[] = { - lovrShape, - { "isFrozen", l_lovrCompoundShapeIsFrozen }, - { "addChild", l_lovrCompoundShapeAddChild }, - { "replaceChild", l_lovrCompoundShapeReplaceChild }, - { "removeChild", l_lovrCompoundShapeRemoveChild }, - { "getChild", l_lovrCompoundShapeGetChild }, - { "getChildren", l_lovrCompoundShapeGetChildren }, - { "getChildCount", l_lovrCompoundShapeGetChildCount }, - { "getChildOffset", l_lovrCompoundShapeGetChildOffset }, - { "setChildOffset", l_lovrCompoundShapeSetChildOffset }, - { "__len", l_lovrCompoundShapeGetChildCount }, // :) - { NULL, NULL } -}; diff --git a/src/api/l_physics_world.c b/src/api/l_physics_world.c index ab2a5eaaa..b6398eaac 100644 --- a/src/api/l_physics_world.c +++ b/src/api/l_physics_world.c @@ -133,9 +133,8 @@ static void contactCallback(void* userdata, World* world, Collider* a, Collider* static int l_lovrWorldNewCollider(lua_State* L) { World* world = luax_checktype(L, 1, World); float position[3]; - int index = luax_readvec3(L, 2, position, NULL); - Shape* shape = luax_checkshape(L, index); - Collider* collider = lovrColliderCreate(world, position, shape); + luax_readvec3(L, 2, position, NULL); + Collider* collider = lovrColliderCreate(world, position, NULL); luax_pushtype(L, Collider, collider); lovrRelease(collider, lovrColliderDestroy); return 1; @@ -335,22 +334,21 @@ static int l_lovrWorldRaycast(lua_State* L) { static int l_lovrWorldShapecast(lua_State* L) { World* world = luax_checktype(L, 1, World); int index = 2; - float pose[7], scale, end[3]; + float pose[7], end[3]; Shape* shape = luax_checkshape(L, index++); index = luax_readvec3(L, index, pose, NULL); index = luax_readvec3(L, index, end, NULL); - scale = luax_optfloat(L, index++, 1.f); index = luax_readquat(L, index, pose + 3, NULL); uint32_t filter = luax_checktagmask(L, index++, world); if (lua_isnoneornil(L, index)) { CastResult hit; - if (lovrWorldShapecast(world, shape, pose, scale, end, filter, castClosestCallback, &hit)) { + if (lovrWorldShapecast(world, shape, pose, end, filter, castClosestCallback, &hit)) { return luax_pushcastresult(L, &hit); } } else { luaL_checktype(L, index, LUA_TFUNCTION); lua_settop(L, index); - lovrWorldShapecast(world, shape, pose, scale, end, filter, castCallback, L); + lovrWorldShapecast(world, shape, pose, end, filter, castCallback, L); } return 0; } @@ -358,31 +356,20 @@ static int l_lovrWorldShapecast(lua_State* L) { static int l_lovrWorldCollideShape(lua_State* L) { World* world = luax_checktype(L, 1, World); int index; - Shape* shape; - float pose[7], scale; - Collider* collider = luax_totype(L, 2, Collider); - if (collider) { - shape = lovrColliderGetShape(collider); - lovrColliderGetPosition(collider, pose); - lovrColliderGetOrientation(collider, pose + 3); - scale = 1.f; - index = 3; - } else { - shape = luax_checkshape(L, 2); - index = luax_readvec3(L, 3, pose, NULL); - scale = luax_optfloat(L, index++, 1.f); - index = luax_readquat(L, index, pose + 3, NULL); - } + float pose[7]; + Shape* shape = luax_checkshape(L, 2); + index = luax_readvec3(L, 3, pose, NULL); + index = luax_readquat(L, index, pose + 3, NULL); uint32_t filter = luax_checktagmask(L, index++, world); if (lua_isnoneornil(L, index)) { CollideResult hit; - if (lovrWorldCollideShape(world, shape, pose, scale, filter, collideFirstCallback, &hit)) { + if (lovrWorldCollideShape(world, shape, pose, filter, collideFirstCallback, &hit)) { return luax_pushcollideresult(L, &hit); } } else { luaL_checktype(L, index, LUA_TFUNCTION); lua_settop(L, index); - lovrWorldCollideShape(world, shape, pose, scale, filter, collideCallback, L); + lovrWorldCollideShape(world, shape, pose, filter, collideCallback, L); } return 0; } diff --git a/src/modules/physics/physics.h b/src/modules/physics/physics.h index 00a3c0778..86969e1d6 100644 --- a/src/modules/physics/physics.h +++ b/src/modules/physics/physics.h @@ -21,7 +21,6 @@ typedef Shape CylinderShape; typedef Shape ConvexShape; typedef Shape MeshShape; typedef Shape TerrainShape; -typedef Shape CompoundShape; typedef Joint WeldJoint; typedef Joint BallJoint; @@ -86,8 +85,8 @@ void lovrWorldGetGravity(World* world, float gravity[3]); void lovrWorldSetGravity(World* world, float gravity[3]); void lovrWorldUpdate(World* world, float dt); bool lovrWorldRaycast(World* world, float start[3], float end[3], uint32_t filter, CastCallback* callback, void* userdata); -bool lovrWorldShapecast(World* world, Shape* shape, float pose[7], float scale, float end[3], uint32_t filter, CastCallback* callback, void* userdata); -bool lovrWorldCollideShape(World* world, Shape* shape, float pose[7], float scale, uint32_t filter, CollideCallback* callback, void* userdata); +bool lovrWorldShapecast(World* world, Shape* shape, float pose[7], float end[3], uint32_t filter, CastCallback* callback, void* userdata); +bool lovrWorldCollideShape(World* world, Shape* shape, float pose[7], uint32_t filter, CollideCallback* callback, void* userdata); bool lovrWorldQueryBox(World* world, float position[3], float size[3], uint32_t filter, QueryCallback* callback, void* userdata); bool lovrWorldQuerySphere(World* world, float position[3], float radius, uint32_t filter, QueryCallback* callback, void* userdata); void lovrWorldDisableCollisionBetween(World* world, const char* tag1, const char* tag2); @@ -119,8 +118,9 @@ bool lovrColliderIsEnabled(Collider* collider); void lovrColliderSetEnabled(Collider* collider, bool enable); World* lovrColliderGetWorld(Collider* collider); Joint* lovrColliderGetJoints(Collider* collider, Joint* joint); -Shape* lovrColliderGetShape(Collider* collider); -void lovrColliderSetShape(Collider* collider, Shape* shape); +Shape* lovrColliderGetShapes(Collider* collider, Shape* shape); +void lovrColliderAddShape(Collider* collider, Shape* shape); +void lovrColliderRemoveShape(Collider* collider, Shape* shape); const char* lovrColliderGetTag(Collider* collider); void lovrColliderSetTag(Collider* collider, const char* tag); float lovrColliderGetFriction(Collider* collider); @@ -140,11 +140,13 @@ void lovrColliderSetSleepingAllowed(Collider* collider, bool allowed); bool lovrColliderIsAwake(Collider* collider); void lovrColliderSetAwake(Collider* collider, bool awake); float lovrColliderGetMass(Collider* collider); -void lovrColliderSetMass(Collider* collider, float* mass); +void lovrColliderSetMass(Collider* collider, float mass); void lovrColliderGetInertia(Collider* collider, float diagonal[3], float rotation[4]); void lovrColliderSetInertia(Collider* collider, float diagonal[3], float rotation[4]); void lovrColliderGetCenterOfMass(Collider* collider, float center[3]); void lovrColliderSetCenterOfMass(Collider* collider, float center[3]); +bool lovrColliderGetAutomaticMass(Collider* collider); +void lovrColliderSetAutomaticMass(Collider* collider, bool enable); void lovrColliderResetMassData(Collider* collider); void lovrColliderGetEnabledAxes(Collider* collider, bool translation[3], bool rotation[3]); void lovrColliderSetEnabledAxes(Collider* collider, bool translation[3], bool rotation[3]); @@ -205,54 +207,57 @@ typedef enum { SHAPE_CYLINDER, SHAPE_CONVEX, SHAPE_MESH, - SHAPE_TERRAIN, - SHAPE_COMPOUND + SHAPE_TERRAIN } ShapeType; void lovrShapeDestroy(void* ref); +void lovrShapeDestroyData(Shape* shape); +bool lovrShapeIsDestroyed(Shape* shape); ShapeType lovrShapeGetType(Shape* shape); +Collider* lovrShapeGetCollider(Shape* shape); float lovrShapeGetVolume(Shape* shape); float lovrShapeGetDensity(Shape* shape); void lovrShapeSetDensity(Shape* shape, float density); float lovrShapeGetMass(Shape* shape); void lovrShapeGetInertia(Shape* shape, float diagonal[3], float rotation[4]); void lovrShapeGetCenterOfMass(Shape* shape, float center[3]); -void lovrShapeGetAABB(Shape* shape, float position[3], float orientation[4], float aabb[6]); +void lovrShapeGetOffset(Shape* shape, float position[3], float orientation[4]); +void lovrShapeSetOffset(Shape* shape, float position[3], float orientation[4]); +void lovrShapeGetPose(Shape* shape, float position[3], float orientation[4]); +void lovrShapeGetAABB(Shape* shape, float aabb[6]); BoxShape* lovrBoxShapeCreate(float dimensions[3]); void lovrBoxShapeGetDimensions(BoxShape* shape, float dimensions[3]); +void lovrBoxShapeSetDimensions(BoxShape* shape, float dimensions[3]); SphereShape* lovrSphereShapeCreate(float radius); float lovrSphereShapeGetRadius(SphereShape* shape); +void lovrSphereShapeSetRadius(SphereShape* shape, float radius); CapsuleShape* lovrCapsuleShapeCreate(float radius, float length); float lovrCapsuleShapeGetRadius(CapsuleShape* shape); +void lovrCapsuleShapeSetRadius(CapsuleShape* shape, float radius); float lovrCapsuleShapeGetLength(CapsuleShape* shape); +void lovrCapsuleShapeSetLength(CapsuleShape* shape, float length); CylinderShape* lovrCylinderShapeCreate(float radius, float length); float lovrCylinderShapeGetRadius(CylinderShape* shape); +void lovrCylinderShapeSetRadius(CylinderShape* shape, float radius); float lovrCylinderShapeGetLength(CylinderShape* shape); +void lovrCylinderShapeSetLength(CylinderShape* shape, float length); ConvexShape* lovrConvexShapeCreate(float points[], uint32_t count); +ConvexShape* lovrConvexShapeClone(ConvexShape* parent); uint32_t lovrConvexShapeGetPointCount(ConvexShape* shape); void lovrConvexShapeGetPoint(ConvexShape* shape, uint32_t index, float point[3]); uint32_t lovrConvexShapeGetFaceCount(ConvexShape* shape); uint32_t lovrConvexShapeGetFace(ConvexShape* shape, uint32_t index, uint32_t* pointIndices, uint32_t capacity); MeshShape* lovrMeshShapeCreate(int vertexCount, float vertices[], int indexCount, uint32_t indices[]); +MeshShape* lovrMeshShapeClone(MeshShape* parent); TerrainShape* lovrTerrainShapeCreate(float* vertices, uint32_t n, float scaleXZ, float scaleY); -CompoundShape* lovrCompoundShapeCreate(Shape** shapes, float* positions, float* orientations, uint32_t count, bool freeze); -bool lovrCompoundShapeIsFrozen(CompoundShape* shape); -void lovrCompoundShapeAddChild(CompoundShape* shape, Shape* child, float position[3], float orientation[4]); -void lovrCompoundShapeReplaceChild(CompoundShape* shape, uint32_t index, Shape* child, float position[3], float orientation[4]); -void lovrCompoundShapeRemoveChild(CompoundShape* shape, uint32_t index); -Shape* lovrCompoundShapeGetChild(CompoundShape* shape, uint32_t index); -uint32_t lovrCompoundShapeGetChildCount(CompoundShape* shape); -void lovrCompoundShapeGetChildOffset(CompoundShape* shape, uint32_t index, float position[3], float orientation[4]); -void lovrCompoundShapeSetChildOffset(CompoundShape* shape, uint32_t index, float position[3], float orientation[4]); - // These tokens need to exist for Lua bindings #define lovrBoxShapeDestroy lovrShapeDestroy #define lovrSphereShapeDestroy lovrShapeDestroy @@ -261,7 +266,6 @@ void lovrCompoundShapeSetChildOffset(CompoundShape* shape, uint32_t index, float #define lovrConvexShapeDestroy lovrShapeDestroy #define lovrMeshShapeDestroy lovrShapeDestroy #define lovrTerrainShapeDestroy lovrShapeDestroy -#define lovrCompoundShapeDestroy lovrShapeDestroy // Joints diff --git a/src/modules/physics/physics_jolt.c b/src/modules/physics/physics_jolt.c index 2c3e6cd87..a6b3ee39e 100644 --- a/src/modules/physics/physics_jolt.c +++ b/src/modules/physics/physics_jolt.c @@ -47,9 +47,10 @@ struct Collider { Collider* prev; Collider* next; World* world; - Shape* shape; Joint* joints; - uint32_t tag; + Shape* shapes; + uint8_t tag; + bool automaticMass; uint32_t activeIndex; float lastPosition[4]; float lastOrientation[4]; @@ -59,6 +60,11 @@ struct Shape { uint32_t ref; ShapeType type; JPH_Shape* handle; + Collider* collider; + Shape* next; + uint32_t index; + float translation[3]; + float rotation[4]; }; typedef struct { @@ -80,6 +86,7 @@ static thread_local struct { static struct { bool initialized; + SphereShape* sphere; } state; #define vec3_toJolt(v) &(JPH_Vec3) { v[0], v[1], v[2] } @@ -87,23 +94,36 @@ static struct { #define quat_toJolt(q) &(JPH_Quat) { q[0], q[1], q[2], q[3] } #define quat_fromJolt(q, j) quat_set(q, (j)->x, (j)->y, (j)->z, (j)->w) -static uint32_t findTag(World* world, const char* name, size_t length) { +static uint8_t findTag(World* world, const char* name, size_t length) { uint32_t hash = (uint32_t) hash64(name, length); - for (uint32_t i = 0; i < world->tagCount; i++) { + for (uint8_t i = 0; i < world->tagCount; i++) { if (world->tagLookup[i] == hash) { return i; } } - return ~0u; + return 0xff; } static Shape* subshapeToShape(Collider* collider, JPH_SubShapeID id) { - if (collider->shape->type == SHAPE_COMPOUND) { + if (collider->shapes && collider->shapes->next) { + const JPH_Shape* shape = JPH_BodyInterface_GetShape(collider->world->bodies, collider->id); + + if (JPH_Shape_GetSubType(shape) == JPH_ShapeSubType_OffsetCenterOfMass) { + shape = (JPH_Shape*) JPH_DecoratedShape_GetInnerShape((JPH_DecoratedShape*) shape); + } + + if (JPH_Shape_GetSubType(shape) != JPH_ShapeSubType_MutableCompound) { + lovrUnreachable(); + } + JPH_SubShapeID remainder; - uint32_t index = JPH_CompoundShape_GetSubShapeIndexFromID((JPH_CompoundShape*) collider->shape->handle, id, &remainder); - return lovrCompoundShapeGetChild(collider->shape, index); + uint32_t index = JPH_CompoundShape_GetSubShapeIndexFromID((JPH_CompoundShape*) shape, id, &remainder); + + const JPH_Shape* child; + JPH_CompoundShape_GetSubShape((JPH_CompoundShape*) shape, index, &child, NULL, NULL, NULL); + return (Shape*) (uintptr_t) JPH_Shape_GetUserData(child); } else { - return collider->shape; + return collider->shapes; } } @@ -226,11 +246,13 @@ static void onContactRemoved(void* userdata, const JPH_SubShapeIDPair* pair) { bool lovrPhysicsInit(void) { if (state.initialized) return false; JPH_Init(32 * 1024 * 1024); + state.sphere = lovrSphereShapeCreate(.001f); return state.initialized = true; } void lovrPhysicsDestroy(void) { if (!state.initialized) return; + lovrRelease(state.sphere, lovrSphereShapeDestroy); JPH_Shutdown(); state.initialized = false; } @@ -359,8 +381,8 @@ uint32_t lovrWorldGetTagMask(World* world, const char* string, size_t length) { bool invert = *string == '~'; const char* space = memchr(string, ' ', length); size_t span = space ? space - string : length; - uint32_t tag = findTag(world, string + invert, span - invert); - lovrCheck(tag != ~0u, "Unknown tag in filter '%s'", string); + uint8_t tag = findTag(world, string + invert, span - invert); + lovrCheck(tag != 0xff, "Unknown tag in filter '%s'", string); if (invert) ignore |= (1 << tag); else accept |= (1 << tag); span += !!space; @@ -490,7 +512,7 @@ static float shapecastCallback(void* arg, JPH_ShapeCastResult* result) { return ctx->callback(ctx->userdata, &hit); } -bool lovrWorldShapecast(World* world, Shape* shape, float pose[7], float scale, float end[3], uint32_t filter, CastCallback callback, void* userdata) { +bool lovrWorldShapecast(World* world, Shape* shape, float pose[7], float end[3], uint32_t filter, CastCallback callback, void* userdata) { const JPH_NarrowPhaseQuery* query = JPH_PhysicsSystem_GetNarrowPhaseQueryNoLock(world->system); JPH_Vec3 centerOfMass; @@ -499,7 +521,6 @@ bool lovrWorldShapecast(World* world, Shape* shape, float pose[7], float scale, JPH_RMatrix4x4 transform; mat4_fromPose(&transform.m11, pose, pose + 3); mat4_translate(&transform.m11, centerOfMass.x, centerOfMass.y, centerOfMass.z); - mat4_scale(&transform.m11, scale, scale, scale); // TODO does this work, or should we use scale arg? float direction[3]; vec3_init(direction, end); @@ -538,7 +559,7 @@ static float collideCallback(void* arg, JPH_CollideShapeResult* result) { return ctx->callback(ctx->userdata, &hit); } -bool lovrWorldCollideShape(World* world, Shape* shape, float pose[7], float scale, uint32_t filter, CollideCallback* callback, void* userdata) { +bool lovrWorldCollideShape(World* world, Shape* shape, float pose[7], uint32_t filter, CollideCallback* callback, void* userdata) { const JPH_NarrowPhaseQuery* query = JPH_PhysicsSystem_GetNarrowPhaseQueryNoLock(world->system); JPH_Vec3 centerOfMass; @@ -548,7 +569,7 @@ bool lovrWorldCollideShape(World* world, Shape* shape, float pose[7], float scal mat4_fromPose(&transform.m11, pose, pose + 3); mat4_translate(&transform.m11, centerOfMass.x, centerOfMass.y, centerOfMass.z); - JPH_Vec3 scale3 = { scale, scale, scale }; + JPH_Vec3 scale = { 1.f, 1.f, 1.f }; JPH_RVec3 offset = { 0.f, 0.f, 0.f }; CollideContext context = { @@ -560,7 +581,7 @@ bool lovrWorldCollideShape(World* world, Shape* shape, float pose[7], float scal JPH_BroadPhaseLayerFilter* layerFilter = getBroadPhaseLayerFilter(world, filter); JPH_ObjectLayerFilter* tagFilter = getObjectLayerFilter(world, filter); - return JPH_NarrowPhaseQuery_CollideShape(query, shape->handle, &scale3, &transform, &offset, collideCallback, &context, layerFilter, tagFilter, NULL); + return JPH_NarrowPhaseQuery_CollideShape(query, shape->handle, &scale, &transform, &offset, collideCallback, &context, layerFilter, tagFilter, NULL); } typedef struct { @@ -614,27 +635,27 @@ bool lovrWorldQuerySphere(World* world, float position[3], float radius, uint32_ } void lovrWorldDisableCollisionBetween(World* world, const char* tag1, const char* tag2) { - uint32_t i = findTag(world, tag1, strlen(tag1)); - uint32_t j = findTag(world, tag2, strlen(tag2)); - lovrCheck(i != ~0u, "Unknown tag '%s'", tag1); - lovrCheck(j != ~0u, "Unknown tag '%s'", tag2); + uint8_t i = findTag(world, tag1, strlen(tag1)); + uint8_t j = findTag(world, tag2, strlen(tag2)); + lovrCheck(i != 0xff, "Unknown tag '%s'", tag1); + lovrCheck(j != 0xff, "Unknown tag '%s'", tag2); JPH_ObjectLayerPairFilterTable_DisableCollision(world->objectLayerPairFilter, i, j); } void lovrWorldEnableCollisionBetween(World* world, const char* tag1, const char* tag2) { - uint32_t i = findTag(world, tag1, strlen(tag1)); - uint32_t j = findTag(world, tag2, strlen(tag2)); - lovrCheck(i != ~0u, "Unknown tag '%s'", tag1); - lovrCheck(j != ~0u, "Unknown tag '%s'", tag2); + uint8_t i = findTag(world, tag1, strlen(tag1)); + uint8_t j = findTag(world, tag2, strlen(tag2)); + lovrCheck(i != 0xff, "Unknown tag '%s'", tag1); + lovrCheck(j != 0xff, "Unknown tag '%s'", tag2); JPH_ObjectLayerPairFilterTable_EnableCollision(world->objectLayerPairFilter, i, j); } bool lovrWorldIsCollisionEnabledBetween(World* world, const char* tag1, const char* tag2) { if (!tag1 || !tag2) return true; - uint32_t i = findTag(world, tag1, strlen(tag1)); - uint32_t j = findTag(world, tag2, strlen(tag2)); - lovrCheck(i != ~0u, "Unknown tag '%s'", tag1); - lovrCheck(j != ~0u, "Unknown tag '%s'", tag2); + uint8_t i = findTag(world, tag1, strlen(tag1)); + uint8_t j = findTag(world, tag2, strlen(tag2)); + lovrCheck(i != 0xff, "Unknown tag '%s'", tag1); + lovrCheck(j != 0xff, "Unknown tag '%s'", tag2); return JPH_ObjectLayerPairFilterTable_ShouldCollide(world->objectLayerPairFilter, i, j); } @@ -674,13 +695,9 @@ void lovrWorldSetAngularDamping(World* world, float damping, float threshold) { // Collider -static void changeCenterOfMass(Collider* collider, const JPH_Shape* oldShape, const JPH_Shape* newShape) { +static void adjustJoints(Collider* collider, JPH_Vec3* oldCenter, JPH_Vec3* newCenter) { if (collider->joints) { - JPH_Vec3 oldCenter; - JPH_Vec3 newCenter; - JPH_Shape_GetCenterOfMass(oldShape, &oldCenter); - JPH_Shape_GetCenterOfMass(newShape, &newCenter); - JPH_Vec3 delta = { newCenter.x - oldCenter.x, newCenter.y - oldCenter.y, newCenter.z - oldCenter.z }; + JPH_Vec3 delta = { newCenter->x - oldCenter->x, newCenter->y - oldCenter->y, newCenter->z - oldCenter->z }; for (Joint* joint = collider->joints; joint; joint = lovrJointGetNext(joint, collider)) { JPH_Constraint_NotifyShapeChanged(joint->constraint, collider->id, &delta); } @@ -695,14 +712,24 @@ Collider* lovrColliderCreate(World* world, float position[3], Shape* shape) { Collider* collider = lovrCalloc(sizeof(Collider)); collider->ref = 1; collider->world = world; - collider->shape = shape; - collider->tag = ~0u; + collider->tag = 0xff; + collider->automaticMass = true; + + if (shape) { + lovrCheck(!shape->collider, "Shape is already attached to a collider!"); + collider->shapes = shape; + shape->collider = collider; + shape->index = 0; + lovrRetain(shape); + } else { + shape = state.sphere; + } JPH_RVec3* p = vec3_toJolt(position); JPH_Quat q = { 0.f, 0.f, 0.f, 1.f }; - JPH_MotionType type = JPH_Shape_MustBeStatic(collider->shape->handle) ? JPH_MotionType_Static : JPH_MotionType_Dynamic; + JPH_MotionType type = JPH_Shape_MustBeStatic(shape->handle) ? JPH_MotionType_Static : JPH_MotionType_Dynamic; JPH_ObjectLayer objectLayer = world->tagCount; - JPH_BodyCreationSettings* settings = JPH_BodyCreationSettings_Create3(collider->shape->handle, p, &q, type, objectLayer); + JPH_BodyCreationSettings* settings = JPH_BodyCreationSettings_Create3(shape->handle, p, &q, type, objectLayer); collider->body = JPH_BodyInterface_CreateBody(world->bodies, settings); collider->id = JPH_Body_GetID(collider->body); JPH_BodyCreationSettings_Destroy(settings); @@ -726,7 +753,6 @@ Collider* lovrColliderCreate(World* world, float position[3], Shape* shape) { world->colliders = collider; - lovrRetain(collider->shape); lovrRetain(collider); return collider; } @@ -742,7 +768,7 @@ void lovrColliderDestroyData(Collider* collider) { return; } - lovrRelease(collider->shape, lovrShapeDestroy); + // Joints Joint* joint = collider->joints; @@ -752,6 +778,36 @@ void lovrColliderDestroyData(Collider* collider) { joint = next; } + // Shapes + + Shape* shape = collider->shapes; + + while (shape) { + Shape* next = shape->next; + shape->collider = NULL; + shape->next = NULL; + shape->index = ~0u; + lovrShapeDestroyData(shape); + lovrRelease(shape, lovrShapeDestroy); + shape = next; + } + + JPH_Shape* handle = (JPH_Shape*) JPH_BodyInterface_GetShape(collider->world->bodies, collider->id); + JPH_ShapeSubType type = JPH_Shape_GetSubType(handle); + + if (type == JPH_ShapeSubType_OffsetCenterOfMass) { + JPH_Shape* inner = (JPH_Shape*) JPH_DecoratedShape_GetInnerShape((JPH_DecoratedShape*) handle); + JPH_Shape_Destroy(handle); + handle = inner; + type = JPH_Shape_GetSubType(handle); + } + + if (type == JPH_ShapeSubType_MutableCompound) { + JPH_Shape_Destroy(handle); + } + + // Body + World* world = collider->world; JPH_BodyInterface_RemoveBody(world->bodies, collider->id); JPH_BodyInterface_DestroyBody(world->bodies, collider->id); @@ -761,8 +817,6 @@ void lovrColliderDestroyData(Collider* collider) { if (collider->prev) collider->prev->next = collider->next; if (world->colliders == collider) world->colliders = collider->next; collider->next = collider->prev = NULL; - - // If the Collider is destroyed, the world lets go of its reference to this Collider lovrRelease(collider, lovrColliderDestroy); } @@ -790,43 +844,279 @@ Joint* lovrColliderGetJoints(Collider* collider, Joint* joint) { return joint ? lovrJointGetNext(joint, collider) : collider->joints; } -Shape* lovrColliderGetShape(Collider* collider) { - return collider->shape; +Shape* lovrColliderGetShapes(Collider* collider, Shape* shape) { + return shape ? shape->next : collider->shapes; } -void lovrColliderSetShape(Collider* collider, Shape* shape) { - if (shape == collider->shape) { - return; +void lovrColliderAddShape(Collider* collider, Shape* shape) { + lovrCheck(!shape->collider, "Shape is already attached to a Collider"); + + // Set the Collider to static if the new shape requires it + if (JPH_Shape_MustBeStatic(shape->handle)) { + JPH_BodyInterface_SetMotionType(collider->world->bodies, collider->id, JPH_MotionType_Static, JPH_Activation_DontActivate); } - const JPH_Shape* oldShape = JPH_BodyInterface_GetShape(collider->world->bodies, collider->id); - changeCenterOfMass(collider, oldShape, shape->handle); + JPH_Shape* handle = (JPH_Shape*) JPH_BodyInterface_GetShape(collider->world->bodies, collider->id); + JPH_Shape* offsetCenterOfMass = JPH_Shape_GetSubType(handle) == JPH_ShapeSubType_OffsetCenterOfMass ? handle : NULL; + + JPH_Vec3 oldCenter; + JPH_Shape_GetCenterOfMass(handle, &oldCenter); + + if (offsetCenterOfMass) { + handle = (JPH_Shape*) JPH_DecoratedShape_GetInnerShape((JPH_DecoratedShape*) handle); + } + + bool alreadyCompound = JPH_Shape_GetSubType(handle) == JPH_ShapeSubType_MutableCompound; + + JPH_Vec3 position = { 0.f, 0.f, 0.f }; + JPH_Quat rotation = { 0.f, 0.f, 0.f, 1.f }; + + // Create or modify the MutableCompoundShape + if (alreadyCompound) { + JPH_MutableCompoundShape_AddShape((JPH_MutableCompoundShape*) handle, &position, &rotation, shape->handle, 0); + shape->index = JPH_CompoundShape_GetNumSubShapes((JPH_CompoundShape*) handle) - 1; + } else if (handle == state.sphere->handle) { + handle = shape->handle; + shape->index = 0; + } else { + JPH_MutableCompoundShapeSettings* settings = JPH_MutableCompoundShapeSettings_Create(); + JPH_CompoundShapeSettings_AddShape2((JPH_CompoundShapeSettings*) settings, &position, &rotation, handle, 0); + JPH_CompoundShapeSettings_AddShape2((JPH_CompoundShapeSettings*) settings, &position, &rotation, shape->handle, 0); + handle = (JPH_Shape*) JPH_MutableCompoundShape_Create(settings); + JPH_ShapeSettings_Destroy((JPH_ShapeSettings*) settings); + shape->index = 1; + } + + JPH_Vec3 newCenter; + JPH_Shape_GetCenterOfMass(handle, &newCenter); + + // Adjust mass + if (alreadyCompound) { + if (collider->automaticMass) { + if (offsetCenterOfMass) { + // Set the shape to the CompoundShape, replacing the OffsetCenterOfMassShape. This takes + // care of recomputing the mass, center, etc. + JPH_MutableCompoundShape_AdjustCenterOfMass((JPH_MutableCompoundShape*) handle); + JPH_BodyInterface_SetShape(collider->world->bodies, collider->id, handle, true, JPH_Activation_DontActivate); + adjustJoints(collider, &oldCenter, &newCenter); + JPH_Shape_Destroy(offsetCenterOfMass); + } else { + // If the shape is already the CompoundShape, use NotifyShapeChanged to update mass/center + JPH_MutableCompoundShape_AdjustCenterOfMass((JPH_MutableCompoundShape*) handle); + JPH_BodyInterface_NotifyShapeChanged(collider->world->bodies, collider->id, &oldCenter, true, JPH_Activation_DontActivate); + adjustJoints(collider, &oldCenter, &newCenter); + } + } else { + // Mark the shape as changed so the AABB updates, but don't change the mass/center. + JPH_BodyInterface_NotifyShapeChanged(collider->world->bodies, collider->id, &newCenter, false, JPH_Activation_DontActivate); + } + } else { + if (collider->automaticMass) { + // Replace the simple shape with the new compound shape, adjusting all the mass properties + JPH_BodyInterface_SetShape(collider->world->bodies, collider->id, handle, true, JPH_Activation_DontActivate); + if (offsetCenterOfMass) JPH_Shape_Destroy(offsetCenterOfMass); + adjustJoints(collider, &oldCenter, &newCenter); + } else { + // If automaticMass=false, use an OffsetCenterOfMassShape to keep the center of mass the same + JPH_Vec3 offset = { oldCenter.x - newCenter.x, oldCenter.y - newCenter.y, oldCenter.z - newCenter.z }; + JPH_Shape* wrapper = (JPH_Shape*) JPH_OffsetCenterOfMassShape_Create(&offset, handle); + JPH_BodyInterface_SetShape(collider->world->bodies, collider->id, wrapper, false, JPH_Activation_DontActivate); + if (offsetCenterOfMass) JPH_Shape_Destroy(offsetCenterOfMass); + } + } - lovrRelease(collider->shape, lovrShapeDestroy); - collider->shape = shape; + // Bookkeeping + shape->collider = collider; + shape->next = collider->shapes; + collider->shapes = shape; lovrRetain(shape); +} - bool isStatic = JPH_Shape_MustBeStatic(shape->handle); - bool updateMass = !isStatic; +void lovrColliderRemoveShape(Collider* collider, Shape* shape) { + lovrCheck(shape->collider == collider, "Shape is not attached to this Collider"); - if (isStatic) { - JPH_BodyInterface_SetMotionType(collider->world->bodies, collider->id, JPH_MotionType_Static, JPH_Activation_DontActivate); + JPH_Shape* handle = (JPH_Shape*) JPH_BodyInterface_GetShape(collider->world->bodies, collider->id); + JPH_Shape* offsetCenterOfMass = JPH_Shape_GetSubType(handle) == JPH_ShapeSubType_OffsetCenterOfMass ? handle : NULL; + + JPH_Vec3 oldCenter; + JPH_Shape_GetCenterOfMass(handle, &oldCenter); + + if (offsetCenterOfMass) { + handle = (JPH_Shape*) JPH_DecoratedShape_GetInnerShape((JPH_DecoratedShape*) handle); + } + + // Adjust shapes + if (JPH_Shape_GetSubType(handle) == JPH_ShapeSubType_MutableCompound) { + if (JPH_CompoundShape_GetNumSubShapes((JPH_CompoundShape*) handle) == 1) { + JPH_Shape_Destroy(handle); + handle = state.sphere->handle; + } else { + JPH_MutableCompoundShape_RemoveShape((JPH_MutableCompoundShape*) handle, shape->index); + } + } else { + handle = state.sphere->handle; + } + + JPH_Vec3 newCenter; + JPH_Shape_GetCenterOfMass(handle, &newCenter); + + // Adjust mass + if (handle == state.sphere->handle) { + if (collider->automaticMass) { + JPH_BodyInterface_SetShape(collider->world->bodies, collider->id, handle, true, JPH_Activation_DontActivate); + if (offsetCenterOfMass) JPH_Shape_Destroy(offsetCenterOfMass); + adjustJoints(collider, &oldCenter, &newCenter); + } else { + // Maintain the center of mass, no need to adjust joints since center isn't changing + JPH_Vec3 offset = { oldCenter.x - newCenter.x, oldCenter.y - newCenter.y, oldCenter.z - newCenter.z }; + JPH_Shape* wrapper = (JPH_Shape*) JPH_OffsetCenterOfMassShape_Create(&offset, handle); + JPH_BodyInterface_SetShape(collider->world->bodies, collider->id, wrapper, false, JPH_Activation_DontActivate); + if (offsetCenterOfMass) JPH_Shape_Destroy(offsetCenterOfMass); + } + } else { + if (collider->automaticMass) { + if (offsetCenterOfMass) { + // Replace the OffsetCenterOfMassShape with the CompoundShape + JPH_MutableCompoundShape_AdjustCenterOfMass((JPH_MutableCompoundShape*) handle); + JPH_BodyInterface_SetShape(collider->world->bodies, collider->id, handle, true, JPH_Activation_DontActivate); + adjustJoints(collider, &oldCenter, &newCenter); + JPH_Shape_Destroy(offsetCenterOfMass); + } else { + // Tell Jolt that the CompoundShape changed, recenter and recompute mass data + JPH_MutableCompoundShape_AdjustCenterOfMass((JPH_MutableCompoundShape*) handle); + JPH_BodyInterface_NotifyShapeChanged(collider->world->bodies, collider->id, &oldCenter, true, JPH_Activation_DontActivate); + adjustJoints(collider, &oldCenter, &newCenter); + } + } else { + // Mark shape as changed, don't update the mass/center, keep OffsetCenterOfMassShape, if any + JPH_BodyInterface_NotifyShapeChanged(collider->world->bodies, collider->id, &newCenter, false, JPH_Activation_DontActivate); + } + } + + // Remove from list, adjust shape indices + Shape** list = &collider->shapes; + while (*list) { + if (*list == shape) { + *list = shape->next; + continue; + } else if ((*list)->index > shape->index) { + (*list)->index--; + } + list = &(*list)->next; + } + + lovrRelease(shape, lovrShapeDestroy); + shape->collider = NULL; + shape->index = ~0u; + shape->next = NULL; +} + +// Assumes the shapes have the same center of mass (always true when modifying a simple shape) +static void lovrColliderReplaceShape(Collider* collider, uint32_t index, JPH_Shape* old, JPH_Shape* new) { + JPH_Shape* handle = (JPH_Shape*) JPH_BodyInterface_GetShape(collider->world->bodies, collider->id); + + if (handle == old) { + JPH_BodyInterface_SetShape(collider->world->bodies, collider->id, new, collider->automaticMass, JPH_Activation_DontActivate); + return; + } + + JPH_Vec3 oldCenter; + JPH_Shape_GetCenterOfMass(handle, &oldCenter); + + JPH_ShapeSubType type = JPH_Shape_GetSubType(handle); + + if (type == JPH_ShapeSubType_OffsetCenterOfMass) { + const JPH_Shape* inner = JPH_DecoratedShape_GetInnerShape((JPH_DecoratedShape*) handle); + + if (inner == old) { + JPH_Vec3 offset; + JPH_OffsetCenterOfMassShape_GetOffset((JPH_OffsetCenterOfMassShape*) handle, &offset); + JPH_Shape* wrapper = (JPH_Shape*) JPH_OffsetCenterOfMassShape_Create(&offset, new); + JPH_BodyInterface_SetShape(collider->world->bodies, collider->id, wrapper, collider->automaticMass, JPH_Activation_DontActivate); + JPH_Shape_Destroy(handle); + return; + } else { + handle = (JPH_Shape*) inner; + type = JPH_Shape_GetSubType(handle); + } } - JPH_BodyInterface_SetShape(collider->world->bodies, collider->id, shape->handle, updateMass, JPH_Activation_Activate); + lovrCheck(type == JPH_ShapeSubType_MutableCompound, "Unreachable"); + + JPH_Vec3 position = { 0.f, 0.f, 0.f }; + JPH_Quat orientation = { 0.f, 0.f, 0.f, 1.f }; + JPH_MutableCompoundShape_ModifyShape2((JPH_MutableCompoundShape*) handle, index, &position, &orientation, new); + JPH_BodyInterface_NotifyShapeChanged(collider->world->bodies, collider->id, &oldCenter, collider->automaticMass, JPH_Activation_DontActivate); +} + +static void lovrColliderMoveShape(Collider* collider, Shape* shape, float translation[3], float rotation[4]) { + JPH_Shape* handle = (JPH_Shape*) JPH_BodyInterface_GetShape(collider->world->bodies, collider->id); + JPH_Shape* offsetCenterOfMass = JPH_Shape_GetSubType(handle) == JPH_ShapeSubType_OffsetCenterOfMass ? handle : NULL; + + JPH_Vec3 oldCenter; + JPH_Shape_GetCenterOfMass(handle, &oldCenter); + + if (offsetCenterOfMass) { + handle = (JPH_Shape*) JPH_DecoratedShape_GetInnerShape((JPH_DecoratedShape*) handle); + } + + bool alreadyCompound = JPH_Shape_GetSubType(handle) == JPH_ShapeSubType_MutableCompound; + + // Wrap the shape in a compound shape if it isn't one already, otherwise just move the subshape + if (alreadyCompound) { + JPH_MutableCompoundShape_ModifyShape((JPH_MutableCompoundShape*) handle, shape->index, vec3_toJolt(translation), quat_toJolt(rotation)); + } else { + JPH_MutableCompoundShapeSettings* settings = JPH_MutableCompoundShapeSettings_Create(); + JPH_CompoundShapeSettings_AddShape2((JPH_CompoundShapeSettings*) settings, vec3_toJolt(translation), quat_toJolt(rotation), shape->handle, 0); + handle = (JPH_Shape*) JPH_MutableCompoundShape_Create(settings); + JPH_ShapeSettings_Destroy((JPH_ShapeSettings*) settings); + } + + JPH_Vec3 newCenter; + JPH_Shape_GetCenterOfMass(handle, &newCenter); + + if (alreadyCompound) { + if (collider->automaticMass) { + if (offsetCenterOfMass) { + JPH_MutableCompoundShape_AdjustCenterOfMass((JPH_MutableCompoundShape*) handle); + JPH_BodyInterface_SetShape(collider->world->bodies, collider->id, handle, true, JPH_Activation_DontActivate); + adjustJoints(collider, &oldCenter, &newCenter); + JPH_Shape_Destroy(offsetCenterOfMass); + } else { + JPH_MutableCompoundShape_AdjustCenterOfMass((JPH_MutableCompoundShape*) handle); + JPH_BodyInterface_NotifyShapeChanged(collider->world->bodies, collider->id, &oldCenter, true, JPH_Activation_DontActivate); + adjustJoints(collider, &oldCenter, &newCenter); + } + } else { + JPH_BodyInterface_NotifyShapeChanged(collider->world->bodies, collider->id, &newCenter, false, JPH_Activation_DontActivate); + } + } else { + if (collider->automaticMass) { + // Replace the simple shape with the new compound shape, adjusting all the mass properties + JPH_BodyInterface_SetShape(collider->world->bodies, collider->id, handle, true, JPH_Activation_DontActivate); + if (offsetCenterOfMass) JPH_Shape_Destroy(offsetCenterOfMass); + adjustJoints(collider, &oldCenter, &newCenter); + } else { + // If automaticMass=false, use an OffsetCenterOfMassShape to keep the center of mass the same + JPH_Vec3 offset = { oldCenter.x - newCenter.x, oldCenter.y - newCenter.y, oldCenter.z - newCenter.z }; + JPH_Shape* wrapper = (JPH_Shape*) JPH_OffsetCenterOfMassShape_Create(&offset, handle); + JPH_BodyInterface_SetShape(collider->world->bodies, collider->id, wrapper, false, JPH_Activation_DontActivate); + if (offsetCenterOfMass) JPH_Shape_Destroy(offsetCenterOfMass); + } + } } const char* lovrColliderGetTag(Collider* collider) { - return collider->tag == ~0u ? NULL : collider->world->tags[collider->tag]; + return collider->tag == 0xff ? NULL : collider->world->tags[collider->tag]; } void lovrColliderSetTag(Collider* collider, const char* tag) { - collider->tag = tag ? findTag(collider->world, tag, strlen(tag)) : ~0u; - lovrCheck(!tag || collider->tag != ~0u, "Unknown tag '%s'", tag); - JPH_ObjectLayer objectLayer = collider->tag == ~0u ? collider->world->tagCount : collider->tag; + collider->tag = tag ? findTag(collider->world, tag, strlen(tag)) : 0xff; + lovrCheck(!tag || collider->tag != 0xff, "Unknown tag '%s'", tag); + JPH_ObjectLayer objectLayer = collider->tag == 0xff ? collider->world->tagCount : collider->tag; JPH_BodyInterface_SetObjectLayer(collider->world->bodies, collider->id, objectLayer); - if (collider->tag != ~0u && collider->world->staticTagMask & (1 << collider->tag)) { + if (collider->tag != 0xff && collider->world->staticTagMask & (1 << collider->tag)) { JPH_BodyInterface_SetMotionType(collider->world->bodies, collider->id, JPH_MotionType_Static, JPH_Activation_DontActivate); } } @@ -852,8 +1142,8 @@ bool lovrColliderIsKinematic(Collider* collider) { } void lovrColliderSetKinematic(Collider* collider, bool kinematic) { - bool mustBeStatic = JPH_Shape_MustBeStatic(collider->shape->handle); - bool hasStaticTag = collider->tag != ~0u && (collider->world->staticTagMask & (1 << collider->tag)); + bool mustBeStatic = JPH_Shape_MustBeStatic(JPH_BodyInterface_GetShape(collider->world->bodies, collider->id)); + bool hasStaticTag = collider->tag != 0xff && (collider->world->staticTagMask & (1 << collider->tag)); if (!mustBeStatic && !hasStaticTag) { JPH_MotionType motionType = kinematic ? JPH_MotionType_Kinematic : JPH_MotionType_Dynamic; JPH_BodyInterface_SetMotionType(collider->world->bodies, collider->id, motionType, JPH_Activation_DontActivate); @@ -920,7 +1210,7 @@ float lovrColliderGetMass(Collider* collider) { return 1.f / JPH_MotionProperties_GetInverseMassUnchecked(motion); } -void lovrColliderSetMass(Collider* collider, float* mass) { +void lovrColliderSetMass(Collider* collider, float mass) { if (lovrColliderIsKinematic(collider)) { return; } @@ -932,12 +1222,8 @@ void lovrColliderSetMass(Collider* collider, float* mass) { return; } - if (mass) { - lovrCheck(*mass > 0.f, "Mass must be positive"); - JPH_MotionProperties_SetInverseMass(motion, 1.f / *mass); - } else { - JPH_MotionProperties_SetInverseMass(motion, 1.f / lovrShapeGetMass(collider->shape)); - } + lovrCheck(mass > 0.f, "Mass must be positive"); + JPH_MotionProperties_SetInverseMass(motion, 1.f / mass); } void lovrColliderGetInertia(Collider* collider, float diagonal[3], float rotation[4]) { @@ -977,17 +1263,8 @@ void lovrColliderSetInertia(Collider* collider, float diagonal[3], float rotatio return; } - if (diagonal) { - JPH_Vec3 idiagonal = { 1.f / diagonal[0], 1.f / diagonal[1], 1.f / diagonal[2] }; - JPH_MotionProperties_SetInverseInertia(motion, &idiagonal, quat_toJolt(rotation)); - } else { - JPH_MassProperties massProperties; - JPH_Shape_GetMassProperties(JPH_BodyInterface_GetShape(collider->world->bodies, collider->id), &massProperties); - float inverseMass = JPH_MotionProperties_GetInverseMassUnchecked(motion); - if (inverseMass > 0.f) JPH_MassProperties_ScaleToMass(&massProperties, 1.f / inverseMass); - JPH_AllowedDOFs dofs = JPH_MotionProperties_GetAllowedDOFs(motion); - JPH_MotionProperties_SetMassProperties(motion, dofs, &massProperties); - } + JPH_Vec3 idiagonal = { 1.f / diagonal[0], 1.f / diagonal[1], 1.f / diagonal[2] }; + JPH_MotionProperties_SetInverseInertia(motion, &idiagonal, quat_toJolt(rotation)); } void lovrColliderGetCenterOfMass(Collider* collider, float center[3]) { @@ -997,24 +1274,45 @@ void lovrColliderGetCenterOfMass(Collider* collider, float center[3]) { } void lovrColliderSetCenterOfMass(Collider* collider, float center[3]) { - JPH_Shape* oldShape = (JPH_Shape*) JPH_BodyInterface_GetShape(collider->world->bodies, collider->id); - JPH_Shape* newShape; + if (lovrColliderIsKinematic(collider)) { + return; + } - if (center) { - JPH_Vec3 base; - JPH_Shape_GetCenterOfMass(collider->shape->handle, &base); + const JPH_Shape* shape = JPH_BodyInterface_GetShape(collider->world->bodies, collider->id); - JPH_Vec3 offset = { center[0] - base.x, center[1] - base.y, center[2] - base.z }; - newShape = (JPH_Shape*) JPH_OffsetCenterOfMassShape_Create(&offset, collider->shape->handle); - } else { - newShape = collider->shape->handle; + JPH_Vec3 oldCenter; + JPH_Shape_GetCenterOfMass(shape, &oldCenter); + + if (JPH_Shape_GetSubType(shape) == JPH_ShapeSubType_OffsetCenterOfMass) { + const JPH_Shape* inner = JPH_DecoratedShape_GetInnerShape((JPH_DecoratedShape*) shape); + JPH_Shape_Destroy((JPH_Shape*) shape); + shape = inner; } - changeCenterOfMass(collider, oldShape, newShape); - JPH_BodyInterface_SetShape(collider->world->bodies, collider->id, newShape, false, JPH_Activation_DontActivate); + JPH_Vec3 base; + JPH_Shape_GetCenterOfMass(shape, &base); + JPH_Vec3 offset = { center[0] - base.x, center[1] - base.y, center[2] - base.z }; + JPH_Shape* outer = (JPH_Shape*) JPH_OffsetCenterOfMassShape_Create(&offset, (JPH_Shape*) shape); + JPH_BodyInterface_SetShape(collider->world->bodies, collider->id, outer, collider->automaticMass, JPH_Activation_DontActivate); + adjustJoints(collider, &oldCenter, vec3_toJolt(center)); +} + +bool lovrColliderGetAutomaticMass(Collider* collider) { + return collider->automaticMass; +} - if (JPH_Shape_GetSubType(oldShape) == JPH_ShapeSubType_OffsetCenterOfMass) { - JPH_Shape_Destroy(oldShape); +void lovrColliderSetAutomaticMass(Collider* collider, bool enable) { + if (collider->automaticMass != enable) { + collider->automaticMass = enable; + + JPH_Shape* shape = (JPH_Shape*) JPH_BodyInterface_GetShape(collider->world->bodies, collider->id); + + // While automatic mass is disabled, the compound shape's center of mass is not kept up-to-date + // when shapes are modified. So if automatic mass is ever re-enabled, we need to make sure to + // refresh the center of mass, so that future shape/mass changes will use the correct value. + if (JPH_Shape_GetSubType(shape) == JPH_ShapeSubType_MutableCompound) { + JPH_MutableCompoundShape_AdjustCenterOfMass((JPH_MutableCompoundShape*) shape); + } } } @@ -1026,17 +1324,23 @@ void lovrColliderResetMassData(Collider* collider) { JPH_Shape* shape = (JPH_Shape*) JPH_BodyInterface_GetShape(collider->world->bodies, collider->id); if (JPH_Shape_GetSubType(shape) == JPH_ShapeSubType_OffsetCenterOfMass) { - JPH_Shape_Destroy(shape); - changeCenterOfMass(collider, shape, collider->shape->handle); - JPH_BodyInterface_SetShape(collider->world->bodies, collider->id, collider->shape->handle, false, JPH_Activation_DontActivate); - } + JPH_Vec3 oldCenter; + JPH_Shape_GetCenterOfMass(shape, &oldCenter); - JPH_MassProperties mass; - JPH_Shape_GetMassProperties(collider->shape->handle, &mass); + const JPH_Shape* inner = JPH_DecoratedShape_GetInnerShape((JPH_DecoratedShape*) shape); + JPH_BodyInterface_SetShape(collider->world->bodies, collider->id, inner, true, JPH_Activation_DontActivate); + JPH_Shape_Destroy(shape); - JPH_MotionProperties* motion = JPH_Body_GetMotionProperties(collider->body); - JPH_AllowedDOFs dofs = JPH_MotionProperties_GetAllowedDOFs(motion); - JPH_MotionProperties_SetMassProperties(motion, dofs, &mass); + JPH_Vec3 newCenter; + JPH_Shape_GetCenterOfMass(inner, &newCenter); + adjustJoints(collider, &oldCenter, &newCenter); + } else{ + JPH_MassProperties mass; + JPH_Shape_GetMassProperties(shape, &mass); + JPH_MotionProperties* motion = JPH_Body_GetMotionProperties(collider->body); + JPH_AllowedDOFs dofs = JPH_MotionProperties_GetAllowedDOFs(motion); + JPH_MotionProperties_SetMassProperties(motion, dofs, &mass); + } } void lovrColliderGetEnabledAxes(Collider* collider, bool translation[3], bool rotation[3]) { @@ -1062,7 +1366,8 @@ void lovrColliderSetEnabledAxes(Collider* collider, bool translation[3], bool ro JPH_MotionProperties* motion = JPH_Body_GetMotionProperties(collider->body); JPH_MassProperties mass; - JPH_Shape_GetMassProperties(collider->shape->handle, &mass); + const JPH_Shape* shape = JPH_BodyInterface_GetShape(collider->world->bodies, collider->id); + JPH_Shape_GetMassProperties(shape, &mass); JPH_MotionProperties_SetMassProperties(motion, dofs, &mass); } @@ -1318,23 +1623,35 @@ void lovrContactDestroy(void* ref) { void lovrShapeDestroy(void* ref) { Shape* shape = ref; + lovrShapeDestroyData(shape); + lovrFree(shape); +} - if (shape->type == SHAPE_COMPOUND) { - uint32_t count = lovrCompoundShapeGetChildCount(shape); - for (uint32_t i = 0; i < count; i++) { - Shape* child = lovrCompoundShapeGetChild(shape, i); - lovrRelease(child, lovrShapeDestroy); - } +void lovrShapeDestroyData(Shape* shape) { + if (!shape->handle) { + return; + } + + if (shape->collider) { + lovrColliderRemoveShape(shape->collider, shape); } JPH_Shape_Destroy(shape->handle); - lovrFree(shape); + shape->handle = NULL; +} + +bool lovrShapeIsDestroyed(Shape* shape) { + return !shape->handle; } ShapeType lovrShapeGetType(Shape* shape) { return shape->type; } +Collider* lovrShapeGetCollider(Shape* shape) { + return shape->collider; +} + float lovrShapeGetVolume(Shape* shape) { if (shape->type == SHAPE_MESH || shape->type == SHAPE_TERRAIN) { return 0.f; @@ -1344,7 +1661,7 @@ float lovrShapeGetVolume(Shape* shape) { } float lovrShapeGetDensity(Shape* shape) { - if (shape->type == SHAPE_MESH || shape->type == SHAPE_TERRAIN || shape->type == SHAPE_COMPOUND) { + if (shape->type == SHAPE_MESH || shape->type == SHAPE_TERRAIN) { return 0.f; } else { return JPH_ConvexShape_GetDensity((JPH_ConvexShape*) shape->handle); @@ -1352,8 +1669,12 @@ float lovrShapeGetDensity(Shape* shape) { } void lovrShapeSetDensity(Shape* shape, float density) { - if (shape->type != SHAPE_MESH && shape->type != SHAPE_TERRAIN && shape->type != SHAPE_COMPOUND) { + if (shape->type != SHAPE_MESH && shape->type != SHAPE_TERRAIN) { JPH_ConvexShape_SetDensity((JPH_ConvexShape*) shape->handle, density); + + if (shape->collider && shape->collider->automaticMass) { + lovrColliderResetMassData(shape->collider); + } } } @@ -1390,15 +1711,49 @@ void lovrShapeGetCenterOfMass(Shape* shape, float center[3]) { vec3_fromJolt(center, ¢erOfMass); } -void lovrShapeGetAABB(Shape* shape, float position[3], float orientation[4], float aabb[6]) { - JPH_AABox box; - if (!position && !orientation) { - JPH_Shape_GetLocalBounds(shape->handle, &box); +void lovrShapeGetOffset(Shape* shape, float translation[3], float rotation[4]) { + vec3_init(translation, shape->translation); + quat_init(rotation, shape->rotation); +} + +void lovrShapeSetOffset(Shape* shape, float translation[3], float rotation[4]) { + vec3_init(shape->translation, translation); + quat_init(shape->rotation, rotation); + if (shape->collider) { + lovrColliderMoveShape(shape->collider, shape, translation, rotation); + } +} + +void lovrShapeGetPose(Shape* shape, float position[3], float orientation[4]) { + if (shape->collider) { + float colliderPosition[3], colliderOrientation[4]; + lovrColliderGetPosition(shape->collider, colliderPosition); + lovrColliderGetOrientation(shape->collider, colliderOrientation); + + if (position) { + vec3_init(position, shape->translation); + quat_rotate(colliderOrientation, position); + vec3_add(position, colliderPosition); + } + + if (orientation) quat_mul(orientation, colliderOrientation, shape->rotation); } else { + if (position) vec3_init(position, shape->translation); + if (orientation) quat_init(orientation, shape->rotation); + } +} + +void lovrShapeGetAABB(Shape* shape, float aabb[6]) { + JPH_AABox box; + if (shape->collider) { JPH_RMatrix4x4 transform; - JPH_Vec3 scale = { 1.f, 1.f, 1.f }; + float position[3], orientation[4], scale[3] = { 1.f, 1.f, 1.f }; + lovrColliderGetPosition(shape->collider, position); + lovrColliderGetOrientation(shape->collider, orientation); mat4_fromPose(&transform.m11, position, orientation); - JPH_Shape_GetWorldSpaceBounds(shape->handle, &transform, &scale, &box); + JPH_Shape_GetWorldSpaceBounds(shape->handle, &transform, vec3_toJolt(scale), &box); + } else { + JPH_Shape_GetLocalBounds(shape->handle, &box); } aabb[0] = box.min.x; aabb[1] = box.max.x; @@ -1408,13 +1763,22 @@ void lovrShapeGetAABB(Shape* shape, float position[3], float orientation[4], flo aabb[5] = box.max.z; } +static void lovrShapeReplace(Shape* shape, JPH_Shape* new) { + JPH_Shape* old = shape->handle; + if (shape->collider) lovrColliderReplaceShape(shape->collider, shape->index, old, new); + JPH_Shape_SetUserData(new, (uint64_t) (uintptr_t) shape); + JPH_Shape_Destroy(old); + shape->handle = new; +} + BoxShape* lovrBoxShapeCreate(float dimensions[3]) { BoxShape* shape = lovrCalloc(sizeof(BoxShape)); shape->ref = 1; shape->type = SHAPE_BOX; const JPH_Vec3 halfExtent = { dimensions[0] / 2.f, dimensions[1] / 2.f, dimensions[2] / 2.f }; - shape->handle = (JPH_Shape*) JPH_BoxShape_Create(&halfExtent, 0.f); + shape->handle = (JPH_Shape*) JPH_BoxShape_Create(&halfExtent, .05f); JPH_Shape_SetUserData(shape->handle, (uint64_t) (uintptr_t) shape); + quat_identity(shape->rotation); return shape; } @@ -1424,6 +1788,11 @@ void lovrBoxShapeGetDimensions(BoxShape* shape, float dimensions[3]) { vec3_set(dimensions, halfExtent.x * 2.f, halfExtent.y * 2.f, halfExtent.z * 2.f); } +void lovrBoxShapeSetDimensions(BoxShape* shape, float dimensions[3]) { + JPH_Vec3 halfExtent = { dimensions[0] / 2.f, dimensions[1] / 2.f, dimensions[2] / 2.f }; + lovrShapeReplace(shape, (JPH_Shape*) JPH_BoxShape_Create(&halfExtent, .05f)); +} + SphereShape* lovrSphereShapeCreate(float radius) { lovrCheck(radius > 0.f, "SphereShape radius must be positive"); SphereShape* shape = lovrCalloc(sizeof(SphereShape)); @@ -1431,6 +1800,7 @@ SphereShape* lovrSphereShapeCreate(float radius) { shape->type = SHAPE_SPHERE; shape->handle = (JPH_Shape*) JPH_SphereShape_Create(radius); JPH_Shape_SetUserData(shape->handle, (uint64_t) (uintptr_t) shape); + quat_identity(shape->rotation); return shape; } @@ -1438,6 +1808,10 @@ float lovrSphereShapeGetRadius(SphereShape* shape) { return JPH_SphereShape_GetRadius((JPH_SphereShape*) shape->handle); } +void lovrSphereShapeSetRadius(SphereShape* shape, float radius) { + lovrShapeReplace(shape, (JPH_Shape*) JPH_SphereShape_Create(radius)); +} + CapsuleShape* lovrCapsuleShapeCreate(float radius, float length) { lovrCheck(radius > 0.f && length > 0.f, "CapsuleShape dimensions must be positive"); CapsuleShape* shape = lovrCalloc(sizeof(CapsuleShape)); @@ -1445,6 +1819,7 @@ CapsuleShape* lovrCapsuleShapeCreate(float radius, float length) { shape->type = SHAPE_CAPSULE; shape->handle = (JPH_Shape*) JPH_CapsuleShape_Create(length / 2.f, radius); JPH_Shape_SetUserData(shape->handle, (uint64_t) (uintptr_t) shape); + quat_identity(shape->rotation); return shape; } @@ -1452,10 +1827,20 @@ float lovrCapsuleShapeGetRadius(CapsuleShape* shape) { return JPH_CapsuleShape_GetRadius((JPH_CapsuleShape*) shape->handle); } +void lovrCapsuleShapeSetRadius(CapsuleShape* shape, float radius) { + float length = lovrCapsuleShapeGetLength(shape); + lovrShapeReplace(shape, (JPH_Shape*) JPH_CapsuleShape_Create(length / 2.f, radius)); +} + float lovrCapsuleShapeGetLength(CapsuleShape* shape) { return 2.f * JPH_CapsuleShape_GetHalfHeightOfCylinder((JPH_CapsuleShape*) shape->handle); } +void lovrCapsuleShapeSetLength(CapsuleShape* shape, float length) { + float radius = lovrCapsuleShapeGetRadius(shape); + lovrShapeReplace(shape, (JPH_Shape*) JPH_CapsuleShape_Create(length / 2.f, radius)); +} + CylinderShape* lovrCylinderShapeCreate(float radius, float length) { lovrCheck(radius > 0.f && length > 0.f, "CylinderShape dimensions must be positive"); CylinderShape* shape = lovrCalloc(sizeof(CylinderShape)); @@ -1463,6 +1848,7 @@ CylinderShape* lovrCylinderShapeCreate(float radius, float length) { shape->type = SHAPE_CYLINDER; shape->handle = (JPH_Shape*) JPH_CylinderShape_Create(length / 2.f, radius); JPH_Shape_SetUserData(shape->handle, (uint64_t) (uintptr_t) shape); + quat_identity(shape->rotation); return shape; } @@ -1470,10 +1856,20 @@ float lovrCylinderShapeGetRadius(CylinderShape* shape) { return JPH_CylinderShape_GetRadius((JPH_CylinderShape*) shape->handle); } +void lovrCylinderShapeSetRadius(CylinderShape* shape, float radius) { + float length = lovrCylinderShapeGetLength(shape); + lovrShapeReplace(shape, (JPH_Shape*) JPH_CylinderShape_Create(length / 2.f, radius)); +} + float lovrCylinderShapeGetLength(CylinderShape* shape) { return JPH_CylinderShape_GetHalfHeight((JPH_CylinderShape*) shape->handle) * 2.f; } +void lovrCylinderShapeSetLength(CylinderShape* shape, float length) { + float radius = lovrCylinderShapeGetRadius(shape); + lovrShapeReplace(shape, (JPH_Shape*) JPH_CylinderShape_Create(length / 2.f, radius)); +} + ConvexShape* lovrConvexShapeCreate(float points[], uint32_t count) { ConvexShape* shape = lovrCalloc(sizeof(ConvexShape)); shape->ref = 1; @@ -1481,6 +1877,16 @@ ConvexShape* lovrConvexShapeCreate(float points[], uint32_t count) { JPH_ConvexHullShapeSettings* settings = JPH_ConvexHullShapeSettings_Create((const JPH_Vec3*) points, count, .05f); shape->handle = (JPH_Shape*) JPH_ConvexHullShapeSettings_CreateShape(settings); JPH_ShapeSettings_Destroy((JPH_ShapeSettings*) settings); + quat_identity(shape->rotation); + return shape; +} + +ConvexShape* lovrConvexShapeClone(ConvexShape* parent) { + ConvexShape* shape = lovrCalloc(sizeof(ConvexShape)); + shape->ref = 1; + shape->type = SHAPE_CONVEX; + shape->handle = parent->handle; + quat_identity(shape->rotation); return shape; } @@ -1508,6 +1914,7 @@ MeshShape* lovrMeshShapeCreate(int vertexCount, float vertices[], int indexCount MeshShape* shape = lovrCalloc(sizeof(MeshShape)); shape->ref = 1; shape->type = SHAPE_MESH; + quat_identity(shape->rotation); int triangleCount = indexCount / 3; JPH_IndexedTriangle* indexedTriangles = lovrMalloc(triangleCount * sizeof(JPH_IndexedTriangle)); @@ -1533,15 +1940,27 @@ MeshShape* lovrMeshShapeCreate(int vertexCount, float vertices[], int indexCount return shape; } +MeshShape* lovrMeshShapeClone(MeshShape* parent) { + MeshShape* shape = lovrCalloc(sizeof(MeshShape)); + shape->ref = 1; + shape->type = SHAPE_MESH; + shape->handle = parent->handle; + quat_identity(shape->rotation); + return shape; +} + TerrainShape* lovrTerrainShapeCreate(float* vertices, uint32_t n, float scaleXZ, float scaleY) { TerrainShape* shape = lovrCalloc(sizeof(TerrainShape)); shape->ref = 1; shape->type = SHAPE_TERRAIN; + quat_identity(shape->rotation); + const JPH_Vec3 offset = { .x = -.5f * scaleXZ, .y = 0.f, .z = -.5f * scaleXZ }; + const JPH_Vec3 scale = { .x = scaleXZ / (n - 1), .y = scaleY, @@ -1554,98 +1973,6 @@ TerrainShape* lovrTerrainShapeCreate(float* vertices, uint32_t n, float scaleXZ, return shape; } -CompoundShape* lovrCompoundShapeCreate(Shape** shapes, vec3 positions, quat orientations, uint32_t count, bool freeze) { - lovrCheck(!freeze || count >= 2, "A frozen CompoundShape must contain at least two shapes"); - - CompoundShape* shape = lovrCalloc(sizeof(CompoundShape)); - shape->ref = 1; - shape->type = SHAPE_COMPOUND; - - JPH_CompoundShapeSettings* settings = freeze ? - (JPH_CompoundShapeSettings*) JPH_StaticCompoundShapeSettings_Create() : - (JPH_CompoundShapeSettings*) JPH_MutableCompoundShapeSettings_Create(); - - for (uint32_t i = 0; i < count; i++) { - lovrCheck(shapes[i]->type != SHAPE_COMPOUND, "Currently, nesting compound shapes is not supported"); - JPH_Vec3 position = { positions[3 * i + 0], positions[3 * i + 1], positions[3 * i + 2] }; - JPH_Quat rotation = { orientations[4 * i + 0], orientations[4 * i + 1], orientations[4 * i + 2], orientations[4 * i + 3] }; - JPH_CompoundShapeSettings_AddShape2(settings, &position, &rotation, shapes[i]->handle, 0); - lovrRetain(shapes[i]); - } - - if (freeze) { - shape->handle = (JPH_Shape*) JPH_StaticCompoundShape_Create((JPH_StaticCompoundShapeSettings*) settings); - } else { - shape->handle = (JPH_Shape*) JPH_MutableCompoundShape_Create((JPH_MutableCompoundShapeSettings*) settings); - } - - JPH_ShapeSettings_Destroy((JPH_ShapeSettings*) settings); - return shape; -} - -bool lovrCompoundShapeIsFrozen(CompoundShape* shape) { - return JPH_Shape_GetSubType(shape->handle) == JPH_ShapeSubType_StaticCompound; -} - -void lovrCompoundShapeAddChild(CompoundShape* shape, Shape* child, float* position, float* orientation) { - lovrCheck(!lovrCompoundShapeIsFrozen(shape), "CompoundShape is frozen and can not be changed"); - lovrCheck(child->type != SHAPE_COMPOUND, "Currently, nesting compound shapes is not supported"); - JPH_Vec3 pos = { position[0], position[1], position[2] }; - JPH_Quat rot = { orientation[0], orientation[1], orientation[2], orientation[3] }; - JPH_MutableCompoundShape_AddShape((JPH_MutableCompoundShape*) shape->handle, &pos, &rot, child->handle, 0); - lovrRetain(child); -} - -void lovrCompoundShapeReplaceChild(CompoundShape* shape, uint32_t index, Shape* child, float* position, float* orientation) { - lovrCheck(!lovrCompoundShapeIsFrozen(shape), "CompoundShape is frozen and can not be changed"); - lovrCheck(child->type != SHAPE_COMPOUND, "Currently, nesting compound shapes is not supported"); - lovrCheck(index < lovrCompoundShapeGetChildCount(shape), "CompoundShape has no child at index %d", index + 1); - JPH_Vec3 pos = { position[0], position[1], position[2] }; - JPH_Quat rot = { orientation[0], orientation[1], orientation[2], orientation[3] }; - lovrRelease(lovrCompoundShapeGetChild(shape, index), lovrShapeDestroy); - JPH_MutableCompoundShape_ModifyShape2((JPH_MutableCompoundShape*) shape->handle, index, &pos, &rot, child->handle); - lovrRetain(child); -} - -void lovrCompoundShapeRemoveChild(CompoundShape* shape, uint32_t index) { - lovrCheck(!lovrCompoundShapeIsFrozen(shape), "CompoundShape is frozen and can not be changed"); - lovrCheck(index < lovrCompoundShapeGetChildCount(shape), "CompoundShape has no child at index %d", index + 1); - Shape* child = lovrCompoundShapeGetChild(shape, index); - JPH_MutableCompoundShape_RemoveShape((JPH_MutableCompoundShape*) shape->handle, index); - lovrRelease(child, lovrShapeDestroy); -} - -Shape* lovrCompoundShapeGetChild(CompoundShape* shape, uint32_t index) { - if (index < lovrCompoundShapeGetChildCount(shape)) { - const JPH_Shape* child; - JPH_CompoundShape_GetSubShape((JPH_CompoundShape*) shape->handle, index, &child, NULL, NULL, NULL); - return (Shape*) (uintptr_t) JPH_Shape_GetUserData(child); - } else { - return NULL; - } -} - -uint32_t lovrCompoundShapeGetChildCount(CompoundShape* shape) { - return JPH_CompoundShape_GetNumSubShapes((JPH_CompoundShape*) shape->handle); -} - -void lovrCompoundShapeGetChildOffset(CompoundShape* shape, uint32_t index, float position[3], float orientation[4]) { - lovrCheck(index < lovrCompoundShapeGetChildCount(shape), "CompoundShape has no child at index %d", index + 1); - const JPH_Shape* child; - JPH_Vec3 p; - JPH_Quat q; - uint32_t userData; - JPH_CompoundShape_GetSubShape((JPH_CompoundShape*) shape->handle, index, &child, &p, &q, &userData); - vec3_fromJolt(position, &p); - quat_fromJolt(orientation, &q); -} - -void lovrCompoundShapeSetChildOffset(CompoundShape* shape, uint32_t index, float position[3], float orientation[4]) { - lovrCheck(!lovrCompoundShapeIsFrozen(shape), "CompoundShape is frozen and can not be changed"); - lovrCheck(index < lovrCompoundShapeGetChildCount(shape), "CompoundShape has no child at index %d", index + 1); - JPH_MutableCompoundShape_ModifyShape((JPH_MutableCompoundShape*) shape->handle, index, vec3_toJolt(position), quat_toJolt(orientation)); -} - // Joints static void lovrJointGetAnchors(Joint* joint, float anchor1[3], float anchor2[3]) { diff --git a/src/modules/physics/physics_ode.c b/src/modules/physics/physics_ode.c index 05663156b..527013961 100644 --- a/src/modules/physics/physics_ode.c +++ b/src/modules/physics/physics_ode.c @@ -293,11 +293,11 @@ bool lovrWorldRaycast(World* world, float start[3], float end[3], uint32_t filte return false; } -bool lovrWorldShapecast(World* world, Shape* shape, float pose[7], float scale, float end[3], uint32_t filter, CastCallback* callback, void* userdata) { +bool lovrWorldShapecast(World* world, Shape* shape, float pose[7], float end[3], uint32_t filter, CastCallback* callback, void* userdata) { return false; } -bool lovrWorldCollideShape(World* world, Shape* shape, float pose[7], float scale, uint32_t filter, CollideCallback* callback, void* userdata) { +bool lovrWorldCollideShape(World* world, Shape* shape, float pose[7], uint32_t filter, CollideCallback* callback, void* userdata) { return false; } @@ -436,7 +436,7 @@ Collider* lovrColliderCreate(World* world, float position[3], Shape* shape) { dBodySetData(collider->body, collider); arr_init(&collider->joints); - lovrColliderSetShape(collider, shape); + lovrColliderAddShape(collider, shape); lovrColliderSetPosition(collider, position); // Adjust the world's collider list @@ -465,8 +465,6 @@ void lovrColliderDestroyData(Collider* collider) { return; } - lovrColliderSetShape(collider, NULL); - Joint** joints = collider->joints.data; size_t count = collider->joints.length; for (size_t i = 0; i < count; i++) { @@ -501,31 +499,12 @@ World* lovrColliderGetWorld(Collider* collider) { return collider->world; } -Shape* lovrColliderGetShape(Collider* collider) { - return collider->shape; +Shape* lovrColliderGetShapes(Collider* collider, Shape* shape) { + return NULL; } -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); - } - - 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); - } +void lovrColliderAddShape(Collider* collider, Shape* shape) { + // } Joint* lovrColliderGetJoints(Collider* collider, Joint* joint) { @@ -633,10 +612,10 @@ float lovrColliderGetMass(Collider* collider) { return m.mass; } -void lovrColliderSetMass(Collider* collider, float* mass) { +void lovrColliderSetMass(Collider* collider, float mass) { dMass m; dBodyGetMass(collider->body, &m); - dMassAdjust(&m, *mass); + dMassAdjust(&m, mass); dBodySetMass(collider->body, &m); } @@ -656,6 +635,14 @@ void lovrColliderSetCenterOfMass(Collider* collider, float center[3]) { // } +bool lovrColliderGetAutomaticMass(Collider* collider) { + return false; +} + +void lovrColliderSetAutomaticMass(Collider* collider, bool enable) { + // +} + void lovrColliderResetMassData(Collider* collider) { // } @@ -913,6 +900,14 @@ void lovrShapeDestroy(void* ref) { lovrFree(shape); } +void lovrShapeDestroyData(Shape* shape) { + // +} + +bool lovrShapeIsDestroyed(Shape* shape) { + return false; +} + ShapeType lovrShapeGetType(Shape* shape) { return shape->type; } @@ -949,7 +944,12 @@ void lovrShapeGetMassData(Shape* shape, float* mass, float inertia[9], float cen // } -void lovrShapeGetAABB(Shape* shape, float position[3], float orientation[4], float aabb[6]) { +void lovrShapeGetOffset(Shape* shape, float position[3], float orientation[4]) {} +void lovrShapeSetOffset(Shape* shape, float position[3], float orientation[4]) {} +void lovrShapeGetPosition(Shape* shape, float position[3]) {} +void lovrShapeGetOrientation(Shape* shape, float orientation[4]) {} + +void lovrShapeGetAABB(Shape* shape, float aabb[6]) { dGeomGetAABB(shape->id, aabb); } @@ -1035,6 +1035,10 @@ ConvexShape* lovrConvexShapeCreate(float positions[], uint32_t count) { lovrThrow("ODE does not support ConvexShape"); } +ConvexShape* lovrConvexShapeClone(ConvexShape* parent) { + return NULL; +} + uint32_t lovrConvexShapeGetPointCount(ConvexShape* convex) { return 0; } @@ -1065,6 +1069,10 @@ MeshShape* lovrMeshShapeCreate(int vertexCount, float* vertices, int indexCount, return mesh; } +MeshShape* lovrMeshShapeClone(MeshShape* parent) { + return NULL; +} + TerrainShape* lovrTerrainShapeCreate(float* vertices, uint32_t n, float scaleXZ, float scaleY) { const float thickness = 10.f; TerrainShape* terrain = lovrCalloc(sizeof(TerrainShape)); @@ -1077,42 +1085,6 @@ TerrainShape* lovrTerrainShapeCreate(float* vertices, uint32_t n, float scaleXZ, return terrain; } -CompoundShape* lovrCompoundShapeCreate(Shape** shapes, float* positions, float* orientations, uint32_t count, bool freeze) { - lovrThrow("ODE does not support CompoundShape"); -} - -bool lovrCompoundShapeIsFrozen(CompoundShape* shape) { - return false; -} - -void lovrCompoundShapeAddChild(CompoundShape* shape, Shape* child, float* position, float* orientation) { - // -} - -void lovrCompoundShapeReplaceChild(CompoundShape* shape, uint32_t index, Shape* child, float* position, float* orientation) { - // -} - -void lovrCompoundShapeRemoveChild(CompoundShape* shape, uint32_t index) { - // -} - -Shape* lovrCompoundShapeGetChild(CompoundShape* shape, uint32_t index) { - return NULL; -} - -uint32_t lovrCompoundShapeGetChildCount(CompoundShape* shape) { - return 0; -} - -void lovrCompoundShapeGetChildOffset(CompoundShape* shape, uint32_t index, float* position, float* orientation) { - // -} - -void lovrCompoundShapeSetChildOffset(CompoundShape* shape, uint32_t index, float* position, float* orientation) { - // -} - void lovrJointDestroy(void* ref) { Joint* joint = ref; lovrJointDestroyData(joint);