From 9e12c89b207486a9a2c7f96252aaa80666790efd Mon Sep 17 00:00:00 2001 From: bjorn Date: Fri, 5 Apr 2024 11:29:16 -0700 Subject: [PATCH 01/17] Update Jolt; --- deps/jolt-physics-sharp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/deps/jolt-physics-sharp b/deps/jolt-physics-sharp index 29fe07e8..22a062b3 160000 --- a/deps/jolt-physics-sharp +++ b/deps/jolt-physics-sharp @@ -1 +1 @@ -Subproject commit 29fe07e8088279c47d7108107856ec3c826d1817 +Subproject commit 22a062b3729f72eaaa24148195368e8b564ecfd1 From 9389ac0b97dc6f4053bde560e217e09e1d4f36f6 Mon Sep 17 00:00:00 2001 From: bjorn Date: Wed, 3 Apr 2024 14:18:28 -0700 Subject: [PATCH 02/17] Colliders can only have 1 shape; rm shape pose; --- src/api/l_physics_collider.c | 43 ++++++------ src/api/l_physics_shapes.c | 81 ---------------------- src/api/l_physics_world.c | 16 ++--- src/modules/physics/physics.h | 6 +- src/modules/physics/physics_jolt.c | 106 +++++++++-------------------- 5 files changed, 61 insertions(+), 191 deletions(-) diff --git a/src/api/l_physics_collider.c b/src/api/l_physics_collider.c index 5a13bbdb..d60d31df 100644 --- a/src/api/l_physics_collider.c +++ b/src/api/l_physics_collider.c @@ -24,32 +24,28 @@ 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); + if (shape) { + luax_pushshape(L, shape); + } else { + lua_pushnil(L); } return 1; } +static int l_lovrColliderSetShape(lua_State* L) { + Collider* collider = luax_checktype(L, 1, Collider); + if (lua_isnoneornil(L, 2)) { + lovrColliderSetShape(collider, NULL); + } else { + Shape* shape = luax_checkshape(L, 2); + lovrColliderSetShape(collider, shape); + } + return 0; +} + static int l_lovrColliderGetJoints(lua_State* L) { Collider* collider = luax_checktype(L, 1, Collider); size_t count; @@ -527,9 +523,8 @@ 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 }, { "getJoints", l_lovrColliderGetJoints }, { "getUserData", l_lovrColliderGetUserData }, { "setUserData", l_lovrColliderSetUserData }, diff --git a/src/api/l_physics_shapes.c b/src/api/l_physics_shapes.c index 015d221b..586765b6 100644 --- a/src/api/l_physics_shapes.c +++ b/src/api/l_physics_shapes.c @@ -147,12 +147,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 +208,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 +239,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 } diff --git a/src/api/l_physics_world.c b/src/api/l_physics_world.c index bf1a708b..e530e668 100644 --- a/src/api/l_physics_world.c +++ b/src/api/l_physics_world.c @@ -55,7 +55,7 @@ typedef struct { static bool raycastAnyCallback(Shape* shape, float x, float y, float z, float nx, float ny, float nz, void* userdata) { RaycastData* data = userdata; if (data->tag) { - const char* tag = lovrColliderGetTag(lovrShapeGetCollider(shape)); + const char* tag = NULL; // TODO if (!tag || strcmp(tag, data->tag)) { return false; } @@ -70,7 +70,7 @@ static bool raycastAnyCallback(Shape* shape, float x, float y, float z, float nx static bool raycastClosestCallback(Shape* shape, float x, float y, float z, float nx, float ny, float nz, void* userdata) { RaycastData* data = userdata; if (data->tag) { - const char* tag = lovrColliderGetTag(lovrShapeGetCollider(shape)); + const char* tag = NULL; // TODO if (!tag || strcmp(tag, data->tag)) { return false; } @@ -113,7 +113,7 @@ static int l_lovrWorldNewBoxCollider(lua_State* L) { 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); + lovrColliderSetShape(collider, shape); lovrColliderInitInertia(collider, shape); luax_pushtype(L, Collider, collider); lovrRelease(collider, lovrColliderDestroy); @@ -127,7 +127,7 @@ static int l_lovrWorldNewCapsuleCollider(lua_State* L) { 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); + lovrColliderSetShape(collider, shape); lovrColliderInitInertia(collider, shape); luax_pushtype(L, Collider, collider); lovrRelease(collider, lovrColliderDestroy); @@ -141,7 +141,7 @@ static int l_lovrWorldNewCylinderCollider(lua_State* L) { 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); + lovrColliderSetShape(collider, shape); lovrColliderInitInertia(collider, shape); luax_pushtype(L, Collider, collider); lovrRelease(collider, lovrColliderDestroy); @@ -155,7 +155,7 @@ static int l_lovrWorldNewSphereCollider(lua_State* L) { 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); + lovrColliderSetShape(collider, shape); lovrColliderInitInertia(collider, shape); luax_pushtype(L, Collider, collider); lovrRelease(collider, lovrColliderDestroy); @@ -167,7 +167,7 @@ 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); + lovrColliderSetShape(collider, shape); lovrColliderInitInertia(collider, shape); luax_pushtype(L, Collider, collider); lovrRelease(collider, lovrColliderDestroy); @@ -179,7 +179,7 @@ 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); + lovrColliderSetShape(collider, shape); lovrColliderSetKinematic(collider, true); luax_pushtype(L, Collider, collider); lovrRelease(collider, lovrColliderDestroy); diff --git a/src/modules/physics/physics.h b/src/modules/physics/physics.h index d3874d9d..fe636902 100644 --- a/src/modules/physics/physics.h +++ b/src/modules/physics/physics.h @@ -92,9 +92,8 @@ 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); Joint** lovrColliderGetJoints(Collider* collider, size_t* count); const char* lovrColliderGetTag(Collider* collider); bool lovrColliderSetTag(Collider* collider, const char* tag); @@ -152,7 +151,6 @@ typedef enum { 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); diff --git a/src/modules/physics/physics_jolt.c b/src/modules/physics/physics_jolt.c index ad6991fb..38eba7c6 100644 --- a/src/modules/physics/physics_jolt.c +++ b/src/modules/physics/physics_jolt.c @@ -22,9 +22,9 @@ struct Collider { JPH_BodyID id; JPH_Body* body; World* world; + Shape* shape; Collider* prev; Collider* next; - arr_t(Shape*) shapes; arr_t(Joint*) joints; uint32_t tag; }; @@ -32,7 +32,6 @@ struct Collider { struct Shape { uint32_t ref; ShapeType type; - Collider* collider; JPH_Shape* shape; }; @@ -184,13 +183,13 @@ void lovrWorldRaycast(World* world, float x1, float y1, float z1, float x2, floa world->bodies, hit_array[i].bodyID); size_t count; - Shape** shape = lovrColliderGetShapes(collider, &count); + Shape* shape = lovrColliderGetShape(collider); const JPH_RVec3 position = { x, y, z }; JPH_Vec3 normal; JPH_Body_GetWorldSpaceSurfaceNormal(collider->body, hit_array[i].subShapeID2, &position, &normal); bool shouldStop = callback( - shape[0], // assumes one shape per collider; todo: compound shapes + shape, // assumes one shape per collider; todo: compound shapes x, y, z, normal.x, normal.y, normal.z, userdata); @@ -222,8 +221,8 @@ static bool lovrWorldQueryShape(World* world, JPH_Shape* shape, float position[3 world->bodies, id); size_t count; - Shape** shape = lovrColliderGetShapes(collider, &count); - bool shouldStop = callback(shape[0], userdata); + Shape* shape = lovrColliderGetShape(collider); + bool shouldStop = callback(shape, userdata); if (shouldStop) { break; } @@ -338,7 +337,6 @@ Collider* lovrColliderCreate(World* world, float x, float y, float z) { lovrColliderSetAngularDamping(collider, world->defaultAngularDamping, 0.f); lovrColliderSetSleepingAllowed(collider, world->defaultIsSleepingAllowed); - arr_init(&collider->shapes); arr_init(&collider->joints); // Adjust the world's collider list @@ -358,7 +356,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); } @@ -368,13 +365,9 @@ void lovrColliderDestroyData(Collider* collider) { return; } + lovrRelease(collider->shape, lovrShapeDestroy); + 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); @@ -408,29 +401,24 @@ Collider* lovrColliderGetNext(Collider* collider) { return collider->next; } -void lovrColliderAddShape(Collider* collider, Shape* shape) { - lovrRetain(shape); - shape->collider = collider; - arr_push(&collider->shapes, shape); - bool isMeshOrTerrain = (shape->type == SHAPE_TERRAIN) || (shape->type == SHAPE_MESH); - bool shouldUpdateMass = !isMeshOrTerrain; - if (isMeshOrTerrain) { - lovrColliderSetKinematic(shape->collider, true); - } - JPH_BodyInterface_SetShape(collider->world->bodies, collider->id, shape->shape, shouldUpdateMass, JPH_Activation_Activate); +Shape* lovrColliderGetShape(Collider* collider) { + return collider->shape; } -void lovrColliderRemoveShape(Collider* collider, Shape* shape) { - if (shape->collider == collider) { - // todo: actions necessary for compound shapes - shape->collider = NULL; - lovrRelease(shape, lovrShapeDestroy); - } -} +void lovrColliderSetShape(Collider* collider, Shape* shape) { + if (shape != collider->shape) { + lovrRelease(collider->shape, lovrShapeDestroy); + collider->shape = shape; + lovrRetain(shape); -Shape** lovrColliderGetShapes(Collider* collider, size_t* count) { - *count = collider->shapes.length; - return collider->shapes.data; + bool updateMass = true; + if (shape->type == SHAPE_MESH || shape->type == SHAPE_TERRAIN) { + lovrColliderSetKinematic(collider, true); + updateMass = false; + } + + JPH_BodyInterface_SetShape(collider->world->bodies, collider->id, shape->shape, updateMass, JPH_Activation_Activate); + } } Joint** lovrColliderGetJoints(Collider* collider, size_t* count) { @@ -526,17 +514,15 @@ void lovrColliderSetAwake(Collider* collider, bool awake) { } float lovrColliderGetMass(Collider* collider) { - if (collider->shapes.length > 0) { - JPH_MotionProperties* motionProperties = JPH_Body_GetMotionProperties(collider->body); - return 1.f / JPH_MotionProperties_GetInverseMassUnchecked(motionProperties); - } - return 0.f; + if (!collider->shape) return 0.f; + JPH_MotionProperties* motionProperties = JPH_Body_GetMotionProperties(collider->body); + return 1.f / JPH_MotionProperties_GetInverseMassUnchecked(motionProperties); } void lovrColliderSetMass(Collider* collider, float mass) { - if (collider->shapes.length > 0) { + if (collider->shape) { JPH_MotionProperties* motionProperties = JPH_Body_GetMotionProperties(collider->body); - Shape* shape = collider->shapes.data[0]; + Shape* shape = collider->shape; JPH_MassProperties* massProperties; JPH_Shape_GetMassProperties(shape->shape, massProperties); JPH_MassProperties_ScaleToMass(massProperties, mass); @@ -754,10 +740,6 @@ ShapeType lovrShapeGetType(Shape* shape) { return shape->type; } -Collider* lovrShapeGetCollider(Shape* shape) { - return shape->collider; -} - bool lovrShapeIsEnabled(Shape* shape) { return true; } @@ -769,43 +751,19 @@ void lovrShapeSetEnabled(Shape* shape, bool enabled) { } bool lovrShapeIsSensor(Shape* shape) { - lovrLog(LOG_WARN, "PHY", "Jolt sensor property fetched from collider, not shape"); - return JPH_Body_IsSensor(shape->collider->body); + lovrThrow("NYI"); } void lovrShapeSetSensor(Shape* shape, bool sensor) { - lovrLog(LOG_WARN, "PHY", "Jolt sensor property is applied to collider, not shape"); - JPH_Body_SetIsSensor(shape->collider->body, sensor); + lovrThrow("NYI"); } -void lovrShapeGetPosition(Shape* shape, float* x, float* y, float* z) { - // todo: compound shapes - *x = 0.f; - *y = 0.f; - *z = 0.f; +void lovrShapeGetMass(Shape* shape, float density, float* cx, float* cy, float* cz, float* mass, float inertia[6]) { + // } -void lovrShapeSetPosition(Shape* shape, float x, float y, float z) { - // todo: compound shapes -} - -void lovrShapeGetOrientation(Shape* shape, float* orientation) { - // todo: compound shapes - orientation[0] = 0.f; - orientation[1] = 0.f; - orientation[2] = 0.f; - orientation[3] = 1.f; -} - -void lovrShapeSetOrientation(Shape* shape, float* orientation) { - // todo: compound shapes -} - -void lovrShapeGetMass(Shape* shape, float density, float* cx, float* cy, float* cz, float* mass, float inertia[6]) {} - void lovrShapeGetAABB(Shape* shape, float aabb[6]) { - // todo: with compound shapes this is no longer correct - lovrColliderGetAABB(shape->collider, aabb); + // TODO } SphereShape* lovrSphereShapeCreate(float radius) { From 5312acaaf9f591c64b3e67aebdb4da446e0f429f Mon Sep 17 00:00:00 2001 From: bjorn Date: Wed, 3 Apr 2024 15:03:46 -0700 Subject: [PATCH 03/17] Start CompoundShape; --- src/api/api.h | 1 + src/api/l_physics.c | 11 +++++++++++ src/api/l_physics_shapes.c | 21 ++++++++++++++++++++- src/modules/physics/physics.h | 8 +++++++- src/modules/physics/physics_jolt.c | 30 ++++++++++++++++++++++++++++++ 5 files changed, 69 insertions(+), 2 deletions(-) diff --git a/src/api/api.h b/src/api/api.h index 527f4a6d..5593edf2 100644 --- a/src/api/api.h +++ b/src/api/api.h @@ -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 diff --git a/src/api/l_physics.c b/src/api/l_physics.c index 4f484984..206bcf90 100644 --- a/src/api/l_physics.c +++ b/src/api/l_physics.c @@ -9,6 +9,7 @@ StringEntry lovrShapeType[] = { [SHAPE_CYLINDER] = ENTRY("cylinder"), [SHAPE_MESH] = ENTRY("mesh"), [SHAPE_TERRAIN] = ENTRY("terrain"), + [SHAPE_COMPOUND] = ENTRY("compound"), { 0 } }; @@ -178,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 }, @@ -190,6 +198,7 @@ static const luaL_Reg lovrPhysics[] = { { "newSliderJoint", l_lovrPhysicsNewSliderJoint }, { "newSphereShape", l_lovrPhysicsNewSphereShape }, { "newTerrainShape", l_lovrPhysicsNewTerrainShape }, + { "newCompoundShape", l_lovrPhysicsNewCompoundShape }, { NULL, NULL } }; @@ -205,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); @@ -221,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; diff --git a/src/api/l_physics_shapes.c b/src/api/l_physics_shapes.c index 586765b6..46eb5fa7 100644 --- a/src/api/l_physics_shapes.c +++ b/src/api/l_physics_shapes.c @@ -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,10 @@ Shape* luax_newterrainshape(lua_State* L, int index) { } } +Shape* luax_newcompoundshape(lua_State* L, int index) { + return NULL; // TODO +} + static int l_lovrShapeDestroy(lua_State* L) { Shape* shape = luax_checkshape(L, 1); lovrShapeDestroyData(shape); @@ -372,3 +378,16 @@ const luaL_Reg lovrTerrainShape[] = { lovrShape, { NULL, NULL } }; + +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; +} + +const luaL_Reg lovrCompoundShape[] = { + lovrShape, + { "getShapeCount", l_lovrCompoundShapeGetShapeCount }, + { NULL, NULL } +}; diff --git a/src/modules/physics/physics.h b/src/modules/physics/physics.h index fe636902..b1e0c91f 100644 --- a/src/modules/physics/physics.h +++ b/src/modules/physics/physics.h @@ -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; @@ -145,7 +146,8 @@ typedef enum { SHAPE_CAPSULE, SHAPE_CYLINDER, SHAPE_MESH, - SHAPE_TERRAIN + SHAPE_TERRAIN, + SHAPE_COMPOUND } ShapeType; void lovrShapeDestroy(void* ref); @@ -186,6 +188,9 @@ MeshShape* lovrMeshShapeCreate(int vertexCount, float vertices[], int indexCount 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); +uint32_t lovrCompoundShapeGetShapeCount(CompoundShape* shape); + // These tokens need to exist for Lua bindings #define lovrSphereShapeDestroy lovrShapeDestroy #define lovrBoxShapeDestroy lovrShapeDestroy @@ -193,6 +198,7 @@ TerrainShape* lovrTerrainShapeCreate(float* vertices, uint32_t widthSamples, uin #define lovrCylinderShapeDestroy 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 38eba7c6..af054202 100644 --- a/src/modules/physics/physics_jolt.c +++ b/src/modules/physics/physics_jolt.c @@ -723,6 +723,8 @@ void lovrColliderGetAABB(Collider* collider, float aabb[6]) { aabb[5] = box.max.z; } +// Shapes + void lovrShapeDestroy(void* ref) { Shape* shape = ref; lovrShapeDestroyData(shape); @@ -912,6 +914,34 @@ TerrainShape* lovrTerrainShapeCreate(float* vertices, uint32_t widthSamples, uin return terrain; } +CompoundShape* lovrCompoundShapeCreate(Shape** shapes, vec3 positions, quat orientations, uint32_t count) { + CompoundShape* parent = lovrCalloc(sizeof(CompoundShape)); + parent->ref = 1; + parent->type = SHAPE_COMPOUND; + + JPH_MutableCompoundShapeSettings* settings = JPH_MutableCompoundShapeSettings_Create(); + JPH_CompoundShapeSettings* settingsSuper = (JPH_CompoundShapeSettings*) settings; + + for (uint32_t i = 0; i < count; i++) { + JPH_Vec3 position; + JPH_Quat rotation; + vec3_init(&position.x, positions + 3 * i); + quat_init(&rotation.x, orientations + 3 * i); + JPH_CompoundShapeSettings_AddShape2(settingsSuper, &position, &rotation, shapes[i]->shape, 0); + lovrRetain(shapes[i]); + } + + parent->shape = (JPH_Shape*) JPH_MutableCompoundShape_Create(settings); + JPH_ShapeSettings_Destroy((JPH_ShapeSettings*) settings); + return parent; +} + +uint32_t lovrCompoundShapeGetShapeCount(CompoundShape* shape) { + return JPH_CompoundShape_GetNumSubShapes((JPH_CompoundShape*) shape->shape); +} + +// Joints + void lovrJointGetAnchors(Joint* joint, float anchor1[3], float anchor2[3]) { JPH_Body* body1 = JPH_TwoBodyConstraint_GetBody1((JPH_TwoBodyConstraint*) joint->constraint); JPH_Body* body2 = JPH_TwoBodyConstraint_GetBody2((JPH_TwoBodyConstraint*) joint->constraint); From 98a75410a301481eb3b23edfb2ee2de332dd2e6e Mon Sep 17 00:00:00 2001 From: bjorn Date: Thu, 4 Apr 2024 12:34:49 -0700 Subject: [PATCH 04/17] CompoundShape API; --- src/api/l_physics_shapes.c | 172 ++++++++++++++++++++++++++++- src/modules/physics/physics.h | 9 +- src/modules/physics/physics_jolt.c | 66 ++++++++++- 3 files changed, 241 insertions(+), 6 deletions(-) diff --git a/src/api/l_physics_shapes.c b/src/api/l_physics_shapes.c index 46eb5fa7..91f4a915 100644 --- a/src/api/l_physics_shapes.c +++ b/src/api/l_physics_shapes.c @@ -138,7 +138,82 @@ Shape* luax_newterrainshape(lua_State* L, int index) { } Shape* luax_newcompoundshape(lua_State* L, int index) { - return NULL; // TODO + 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_totype(L, -1, Shape); + 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++); + lua_rawgeti(L, -3, index++); + vec3_set(&positions[3 * i], luax_tofloat(L, -3), luax_tofloat(L, -2), luax_tofloat(L, -1)); + lua_pop(L, 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) { @@ -379,6 +454,63 @@ const luaL_Reg lovrTerrainShape[] = { { 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); + 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); + 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* shape = lovrCompoundShapeGetShape(shape, (uint32_t) i); + luax_pushshape(L, shape); + 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); @@ -386,8 +518,44 @@ static int l_lovrCompoundShapeGetShapeCount(lua_State* L) { return 1; } +static int l_lovrCompoundShapeGetShapeOffset(lua_State* L) { + CompoundShape* shape = luax_checktype(L, 1, CompoundShape); + uint32_t index = luax_checku32(L, 2); + 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); + 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, - { "getShapeCount", l_lovrCompoundShapeGetShapeCount }, + { "isFrozen", l_lovrCompoundShapeIsFrozen }, + { "addShape", l_lovrCompoundShapeAddShape }, + { "replaceShape", l_lovrCompoundShapeReplaceShape }, + { "removeShape", l_lovrCompoundShapeRemoveShape }, + { "getShape", l_lovrCompoundShapeGetShape }, + { "getShapes", l_lovrCompoundShapeGetShapes }, + { "getShapeCount", l_lovrCompoundShapeGetShapes }, + { "getShapeOffset", l_lovrCompoundShapeGetShapeOffset }, + { "setShapeOffset", l_lovrCompoundShapeSetShapeOffset }, + { "__len", l_lovrCompoundShapeGetShapeCount }, // :) { NULL, NULL } }; diff --git a/src/modules/physics/physics.h b/src/modules/physics/physics.h index b1e0c91f..8a3bbfdc 100644 --- a/src/modules/physics/physics.h +++ b/src/modules/physics/physics.h @@ -188,8 +188,15 @@ MeshShape* lovrMeshShapeCreate(int vertexCount, float vertices[], int indexCount 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); +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 diff --git a/src/modules/physics/physics_jolt.c b/src/modules/physics/physics_jolt.c index af054202..785ec9ac 100644 --- a/src/modules/physics/physics_jolt.c +++ b/src/modules/physics/physics_jolt.c @@ -733,6 +733,14 @@ void lovrShapeDestroy(void* ref) { void lovrShapeDestroyData(Shape* shape) { if (shape->shape) { + if (shape->type == SHAPE_COMPOUND) { + uint32_t count = lovrCompoundShapeGetShapeCount(shape); + for (uint32_t i = 0; i < count; i++) { + Shape* child = lovrCompoundShapeGetShape(shape, i); + lovrRelease(child, lovrShapeDestroy); + } + } + JPH_Shape_Destroy(shape->shape); shape->shape = NULL; } @@ -914,20 +922,20 @@ TerrainShape* lovrTerrainShapeCreate(float* vertices, uint32_t widthSamples, uin return terrain; } -CompoundShape* lovrCompoundShapeCreate(Shape** shapes, vec3 positions, quat orientations, uint32_t count) { +CompoundShape* lovrCompoundShapeCreate(Shape** shapes, vec3 positions, quat orientations, uint32_t count, bool freeze) { CompoundShape* parent = lovrCalloc(sizeof(CompoundShape)); parent->ref = 1; parent->type = SHAPE_COMPOUND; JPH_MutableCompoundShapeSettings* settings = JPH_MutableCompoundShapeSettings_Create(); - JPH_CompoundShapeSettings* settingsSuper = (JPH_CompoundShapeSettings*) settings; + JPH_CompoundShapeSettings* superSettings = (JPH_CompoundShapeSettings*) settings; for (uint32_t i = 0; i < count; i++) { JPH_Vec3 position; JPH_Quat rotation; vec3_init(&position.x, positions + 3 * i); quat_init(&rotation.x, orientations + 3 * i); - JPH_CompoundShapeSettings_AddShape2(settingsSuper, &position, &rotation, shapes[i]->shape, 0); + JPH_CompoundShapeSettings_AddShape2(superSettings, &position, &rotation, shapes[i]->shape, 0); lovrRetain(shapes[i]); } @@ -936,10 +944,62 @@ CompoundShape* lovrCompoundShapeCreate(Shape** shapes, vec3 positions, quat orie return parent; } +bool lovrCompoundShapeIsFrozen(CompoundShape* shape) { + return JPH_Shape_GetSubType(shape->shape) == JPH_ShapeSubType_StaticCompound; +} + +void lovrCompoundShapeAddShape(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->shape, &pos, &rot, child->shape, 0); + lovrRetain(child); +} + +void lovrCompoundShapeReplaceShape(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"); + JPH_Vec3 pos = { position[0], position[1], position[2] }; + JPH_Quat rot = { orientation[0], orientation[1], orientation[2], orientation[3] }; + JPH_MutableCompoundShape_ModifyShape2((JPH_MutableCompoundShape*) shape->shape, index, &pos, &rot, child->shape); + lovrRetain(child); +} + +void lovrCompoundShapeRemoveShape(CompoundShape* shape, uint32_t index) { + lovrCheck(!lovrCompoundShapeIsFrozen(shape), "CompoundShape is frozen and can not be changed"); + Shape* child = lovrCompoundShapeGetShape(shape, index); + JPH_MutableCompoundShape_RemoveShape((JPH_MutableCompoundShape*) shape->shape, index); + lovrRelease(child, lovrShapeDestroy); +} + +Shape* lovrCompoundShapeGetShape(CompoundShape* shape, uint32_t index) { + const JPH_Shape* child; + JPH_CompoundShape_GetSubShape((JPH_CompoundShape*) shape->shape, index, &child, NULL, NULL, NULL); + return (Shape*) (uintptr_t) JPH_Shape_GetUserData(child); +} + uint32_t lovrCompoundShapeGetShapeCount(CompoundShape* shape) { return JPH_CompoundShape_GetNumSubShapes((JPH_CompoundShape*) shape->shape); } +void lovrCompoundShapeGetShapeOffset(CompoundShape* shape, uint32_t index, float* position, float* orientation) { + const JPH_Shape* child; + JPH_Vec3 pos; + JPH_Quat rot; + uint32_t userData; + JPH_CompoundShape_GetSubShape((JPH_CompoundShape*) shape->shape, index, &child, &pos, &rot, &userData); + vec3_init(position, &pos.x); + quat_init(orientation, &rot.x); +} + +void lovrCompoundShapeSetShapeOffset(CompoundShape* shape, uint32_t index, float* position, float* orientation) { + lovrCheck(!lovrCompoundShapeIsFrozen(shape), "CompoundShape is frozen and can not be changed"); + JPH_Vec3 pos = { position[0], position[1], position[2] }; + JPH_Quat rot = { orientation[0], orientation[1], orientation[2], orientation[3] }; + JPH_MutableCompoundShape_ModifyShape((JPH_MutableCompoundShape*) shape->shape, index, &pos, &rot); +} + // Joints void lovrJointGetAnchors(Joint* joint, float anchor1[3], float anchor2[3]) { From a7c5151200c72a8a3d34a00241b04f34b2413c17 Mon Sep 17 00:00:00 2001 From: bjorn Date: Thu, 4 Apr 2024 13:18:15 -0700 Subject: [PATCH 05/17] Shapes set their userdata; --- src/modules/physics/physics_jolt.c | 24 ++++++++++++++---------- 1 file changed, 14 insertions(+), 10 deletions(-) diff --git a/src/modules/physics/physics_jolt.c b/src/modules/physics/physics_jolt.c index 785ec9ac..8a03b236 100644 --- a/src/modules/physics/physics_jolt.c +++ b/src/modules/physics/physics_jolt.c @@ -782,6 +782,7 @@ SphereShape* lovrSphereShapeCreate(float radius) { sphere->ref = 1; sphere->type = SHAPE_SPHERE; sphere->shape = (JPH_Shape*) JPH_SphereShape_Create(radius); + JPH_Shape_SetUserData(sphere->shape, (uint64_t) (uintptr_t) sphere); return sphere; } @@ -800,6 +801,7 @@ BoxShape* lovrBoxShapeCreate(float w, float h, float d) { box->type = SHAPE_BOX; const JPH_Vec3 halfExtent = { w / 2.f, h / 2.f, d / 2.f }; box->shape = (JPH_Shape*) JPH_BoxShape_Create(&halfExtent, 0.f); + JPH_Shape_SetUserData(box->shape, (uint64_t) (uintptr_t) box); return box; } @@ -822,6 +824,7 @@ CapsuleShape* lovrCapsuleShapeCreate(float radius, float length) { capsule->ref = 1; capsule->type = SHAPE_CAPSULE; capsule->shape = (JPH_Shape*) JPH_CapsuleShape_Create(length / 2, radius); + JPH_Shape_SetUserData(capsule->shape, (uint64_t) (uintptr_t) capsule); return capsule; } @@ -845,24 +848,25 @@ void lovrCapsuleShapeSetLength(CapsuleShape* capsule, float length) { CylinderShape* lovrCylinderShapeCreate(float radius, float length) { lovrCheck(radius > 0.f && length > 0.f, "CylinderShape dimensions must be positive"); - CylinderShape* Cylinder = lovrCalloc(sizeof(CylinderShape)); - Cylinder->ref = 1; - Cylinder->type = SHAPE_CYLINDER; - Cylinder->shape = (JPH_Shape*) JPH_CylinderShape_Create(length / 2.f, radius); - return Cylinder; + CylinderShape* cylinder = lovrCalloc(sizeof(CylinderShape)); + cylinder->ref = 1; + cylinder->type = SHAPE_CYLINDER; + cylinder->shape = (JPH_Shape*) JPH_CylinderShape_Create(length / 2.f, radius); + JPH_Shape_SetUserData(cylinder->shape, (uint64_t) (uintptr_t) cylinder); + return cylinder; } -float lovrCylinderShapeGetRadius(CylinderShape* Cylinder) { - return JPH_CylinderShape_GetRadius((JPH_CylinderShape*) Cylinder->shape); +float lovrCylinderShapeGetRadius(CylinderShape* cylinder) { + return JPH_CylinderShape_GetRadius((JPH_CylinderShape*) cylinder->shape); } -void lovrCylinderShapeSetRadius(CylinderShape* Cylinder, float radius) { +void lovrCylinderShapeSetRadius(CylinderShape* cylinder, float radius) { lovrLog(LOG_WARN, "PHY", "Jolt CylinderShape radius is read-only"); // todo: no setter available, but the shape could be removed and re-added } -float lovrCylinderShapeGetLength(CylinderShape* Cylinder) { - return JPH_CylinderShape_GetHalfHeight((JPH_CylinderShape*) Cylinder->shape) * 2.f; +float lovrCylinderShapeGetLength(CylinderShape* cylinder) { + return JPH_CylinderShape_GetHalfHeight((JPH_CylinderShape*) cylinder->shape) * 2.f; } void lovrCylinderShapeSetLength(CylinderShape* cylinder, float length) { From 0061bdb98d47cbd3e160068d2ccdaabbee36b4b8 Mon Sep 17 00:00:00 2001 From: bjorn Date: Thu, 4 Apr 2024 13:38:41 -0700 Subject: [PATCH 06/17] CompoundShape fixes; --- src/api/l_physics_shapes.c | 27 +++++++++++---------- src/modules/physics/physics_jolt.c | 39 +++++++++++++++++++++--------- 2 files changed, 42 insertions(+), 24 deletions(-) diff --git a/src/api/l_physics_shapes.c b/src/api/l_physics_shapes.c index 91f4a915..d8fa0140 100644 --- a/src/api/l_physics_shapes.c +++ b/src/api/l_physics_shapes.c @@ -158,7 +158,7 @@ Shape* luax_newcompoundshape(lua_State* L, int index) { lovrCheck(lua_istable(L, -1), "Expected table of tables for compound shape"); lua_rawgeti(L, -1, 1); - shapes[i] = luax_totype(L, -1, Shape); + shapes[i] = luax_checkshape(L, -1); lovrCheck(shapes[i], "Expected a Shape for CompoundShape entry #%d", i + 1); lua_pop(L, 1); @@ -170,10 +170,11 @@ Shape* luax_newcompoundshape(lua_State* L, int index) { lua_pop(L, 1); break; case LUA_TNUMBER: - lua_rawgeti(L, -2, index++); - lua_rawgeti(L, -3, index++); + 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"); @@ -190,9 +191,9 @@ Shape* luax_newcompoundshape(lua_State* L, int index) { lua_pop(L, 1); break; case LUA_TNUMBER: - lua_rawgeti(L, -2, index++); - lua_rawgeti(L, -3, index++); - lua_rawgeti(L, -4, index++); + 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; @@ -486,14 +487,14 @@ static int l_lovrCompoundShapeReplaceShape(lua_State* L) { static int l_lovrCompoundShapeRemoveShape(lua_State* L) { CompoundShape* shape = luax_checktype(L, 1, CompoundShape); - uint32_t index = luax_checku32(L, 2); + 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); + uint32_t index = luax_checku32(L, 2) - 1; Shape* child = lovrCompoundShapeGetShape(shape, index); luax_pushshape(L, child); return 1; @@ -504,8 +505,8 @@ static int l_lovrCompoundShapeGetShapes(lua_State* L) { int count = (int) lovrCompoundShapeGetShapeCount(shape); lua_createtable(L, count, 0); for (int i = 0; i < count; i++) { - Shape* shape = lovrCompoundShapeGetShape(shape, (uint32_t) i); - luax_pushshape(L, shape); + Shape* child = lovrCompoundShapeGetShape(shape, (uint32_t) i); + luax_pushshape(L, child); lua_rawseti(L, -2, i + 1); } return 1; @@ -520,7 +521,7 @@ static int l_lovrCompoundShapeGetShapeCount(lua_State* L) { static int l_lovrCompoundShapeGetShapeOffset(lua_State* L) { CompoundShape* shape = luax_checktype(L, 1, CompoundShape); - uint32_t index = luax_checku32(L, 2); + 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); @@ -536,7 +537,7 @@ static int l_lovrCompoundShapeGetShapeOffset(lua_State* L) { static int l_lovrCompoundShapeSetShapeOffset(lua_State* L) { CompoundShape* shape = luax_checktype(L, 1, CompoundShape); - uint32_t index = luax_checku32(L, 2); + uint32_t index = luax_checku32(L, 2) - 1; float position[3], orientation[4]; int i = 3; i = luax_readvec3(L, i, position, NULL); @@ -553,7 +554,7 @@ const luaL_Reg lovrCompoundShape[] = { { "removeShape", l_lovrCompoundShapeRemoveShape }, { "getShape", l_lovrCompoundShapeGetShape }, { "getShapes", l_lovrCompoundShapeGetShapes }, - { "getShapeCount", l_lovrCompoundShapeGetShapes }, + { "getShapeCount", l_lovrCompoundShapeGetShapeCount }, { "getShapeOffset", l_lovrCompoundShapeGetShapeOffset }, { "setShapeOffset", l_lovrCompoundShapeSetShapeOffset }, { "__len", l_lovrCompoundShapeGetShapeCount }, // :) diff --git a/src/modules/physics/physics_jolt.c b/src/modules/physics/physics_jolt.c index 8a03b236..eeeef0ea 100644 --- a/src/modules/physics/physics_jolt.c +++ b/src/modules/physics/physics_jolt.c @@ -927,23 +927,30 @@ TerrainShape* lovrTerrainShapeCreate(float* vertices, uint32_t widthSamples, uin } CompoundShape* lovrCompoundShapeCreate(Shape** shapes, vec3 positions, quat orientations, uint32_t count, bool freeze) { + lovrCheck(!freeze || count > 0, "A frozen CompoundShape must contain at least one shape"); + CompoundShape* parent = lovrCalloc(sizeof(CompoundShape)); parent->ref = 1; parent->type = SHAPE_COMPOUND; - JPH_MutableCompoundShapeSettings* settings = JPH_MutableCompoundShapeSettings_Create(); - JPH_CompoundShapeSettings* superSettings = (JPH_CompoundShapeSettings*) settings; + JPH_CompoundShapeSettings* settings = freeze ? + (JPH_CompoundShapeSettings*) JPH_StaticCompoundShapeSettings_Create() : + (JPH_CompoundShapeSettings*) JPH_MutableCompoundShapeSettings_Create(); for (uint32_t i = 0; i < count; i++) { - JPH_Vec3 position; - JPH_Quat rotation; - vec3_init(&position.x, positions + 3 * i); - quat_init(&rotation.x, orientations + 3 * i); - JPH_CompoundShapeSettings_AddShape2(superSettings, &position, &rotation, shapes[i]->shape, 0); + 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]->shape, 0); lovrRetain(shapes[i]); } - parent->shape = (JPH_Shape*) JPH_MutableCompoundShape_Create(settings); + if (freeze) { + parent->shape = (JPH_Shape*) JPH_StaticCompoundShape_Create((JPH_StaticCompoundShapeSettings*) settings); + } else { + parent->shape = (JPH_Shape*) JPH_MutableCompoundShape_Create((JPH_MutableCompoundShapeSettings*) settings); + } + JPH_ShapeSettings_Destroy((JPH_ShapeSettings*) settings); return parent; } @@ -955,6 +962,7 @@ bool lovrCompoundShapeIsFrozen(CompoundShape* shape) { void lovrCompoundShapeAddShape(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"); + lovrCheck(child != shape, "Don't put a CompoundShape inside itself! lol"); 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->shape, &pos, &rot, child->shape, 0); @@ -964,6 +972,8 @@ void lovrCompoundShapeAddShape(CompoundShape* shape, Shape* child, float* positi void lovrCompoundShapeReplaceShape(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 < lovrCompoundShapeGetShapeCount(shape), "CompoundShape has no shape at index %d", index + 1); + lovrCheck(child != shape, "Don't put a CompoundShape inside itself! lol"); JPH_Vec3 pos = { position[0], position[1], position[2] }; JPH_Quat rot = { orientation[0], orientation[1], orientation[2], orientation[3] }; JPH_MutableCompoundShape_ModifyShape2((JPH_MutableCompoundShape*) shape->shape, index, &pos, &rot, child->shape); @@ -972,15 +982,20 @@ void lovrCompoundShapeReplaceShape(CompoundShape* shape, uint32_t index, Shape* void lovrCompoundShapeRemoveShape(CompoundShape* shape, uint32_t index) { lovrCheck(!lovrCompoundShapeIsFrozen(shape), "CompoundShape is frozen and can not be changed"); + lovrCheck(index < lovrCompoundShapeGetShapeCount(shape), "CompoundShape has no shape at index %d", index + 1); Shape* child = lovrCompoundShapeGetShape(shape, index); JPH_MutableCompoundShape_RemoveShape((JPH_MutableCompoundShape*) shape->shape, index); lovrRelease(child, lovrShapeDestroy); } Shape* lovrCompoundShapeGetShape(CompoundShape* shape, uint32_t index) { - const JPH_Shape* child; - JPH_CompoundShape_GetSubShape((JPH_CompoundShape*) shape->shape, index, &child, NULL, NULL, NULL); - return (Shape*) (uintptr_t) JPH_Shape_GetUserData(child); + if (index < lovrCompoundShapeGetShapeCount(shape)) { + const JPH_Shape* child; + JPH_CompoundShape_GetSubShape((JPH_CompoundShape*) shape->shape, index, &child, NULL, NULL, NULL); + return (Shape*) (uintptr_t) JPH_Shape_GetUserData(child); + } else { + return NULL; + } } uint32_t lovrCompoundShapeGetShapeCount(CompoundShape* shape) { @@ -988,6 +1003,7 @@ uint32_t lovrCompoundShapeGetShapeCount(CompoundShape* shape) { } void lovrCompoundShapeGetShapeOffset(CompoundShape* shape, uint32_t index, float* position, float* orientation) { + lovrCheck(index < lovrCompoundShapeGetShapeCount(shape), "CompoundShape has no shape at index %d", index + 1); const JPH_Shape* child; JPH_Vec3 pos; JPH_Quat rot; @@ -999,6 +1015,7 @@ void lovrCompoundShapeGetShapeOffset(CompoundShape* shape, uint32_t index, float void lovrCompoundShapeSetShapeOffset(CompoundShape* shape, uint32_t index, float* position, float* orientation) { lovrCheck(!lovrCompoundShapeIsFrozen(shape), "CompoundShape is frozen and can not be changed"); + lovrCheck(index < lovrCompoundShapeGetShapeCount(shape), "CompoundShape has no shape 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] }; JPH_MutableCompoundShape_ModifyShape((JPH_MutableCompoundShape*) shape->shape, index, &pos, &rot); From 2880f1f6bf9d4961613c31e330dc0e059dcb7691 Mon Sep 17 00:00:00 2001 From: bjorn Date: Thu, 4 Apr 2024 14:37:48 -0700 Subject: [PATCH 07/17] 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. --- src/api/l_physics_shapes.c | 49 ------------------------------ src/modules/physics/physics.h | 6 ---- src/modules/physics/physics_jolt.c | 30 ------------------ 3 files changed, 85 deletions(-) diff --git a/src/api/l_physics_shapes.c b/src/api/l_physics_shapes.c index d8fa0140..2a28eb86 100644 --- a/src/api/l_physics_shapes.c +++ b/src/api/l_physics_shapes.c @@ -336,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 } }; @@ -360,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 } }; @@ -381,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 } }; @@ -416,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 } }; diff --git a/src/modules/physics/physics.h b/src/modules/physics/physics.h index 8a3bbfdc..81bdf5a0 100644 --- a/src/modules/physics/physics.h +++ b/src/modules/physics/physics.h @@ -166,23 +166,17 @@ 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[]); diff --git a/src/modules/physics/physics_jolt.c b/src/modules/physics/physics_jolt.c index eeeef0ea..b57e22f5 100644 --- a/src/modules/physics/physics_jolt.c +++ b/src/modules/physics/physics_jolt.c @@ -790,11 +790,6 @@ float lovrSphereShapeGetRadius(SphereShape* sphere) { return JPH_SphereShape_GetRadius((JPH_SphereShape*) sphere->shape); } -void lovrSphereShapeSetRadius(SphereShape* sphere, float radius) { - lovrLog(LOG_WARN, "PHY", "Jolt SphereShape radius is read-only"); - // todo: no setter available, but the shape could be removed and re-added -} - BoxShape* lovrBoxShapeCreate(float w, float h, float d) { BoxShape* box = lovrCalloc(sizeof(BoxShape)); box->ref = 1; @@ -813,11 +808,6 @@ void lovrBoxShapeGetDimensions(BoxShape* box, float* w, float* h, float* d) { *d = halfExtent.z * 2.f; } -void lovrBoxShapeSetDimensions(BoxShape* box, float w, float h, float d) { - lovrLog(LOG_WARN, "PHY", "Jolt BoxShape dimensions are read-only"); - // todo: no setter available, but the shape could be removed and re-added -} - CapsuleShape* lovrCapsuleShapeCreate(float radius, float length) { lovrCheck(radius > 0.f && length > 0.f, "CapsuleShape dimensions must be positive"); CapsuleShape* capsule = lovrCalloc(sizeof(CapsuleShape)); @@ -832,20 +822,10 @@ float lovrCapsuleShapeGetRadius(CapsuleShape* capsule) { return JPH_CapsuleShape_GetRadius((JPH_CapsuleShape*) capsule->shape); } -void lovrCapsuleShapeSetRadius(CapsuleShape* capsule, float radius) { - lovrLog(LOG_WARN, "PHY", "Jolt CapsuleShape radius is read-only"); - // todo: no setter available, but the shape could be removed and re-added -} - float lovrCapsuleShapeGetLength(CapsuleShape* capsule) { return 2.f * JPH_CapsuleShape_GetHalfHeightOfCylinder((JPH_CapsuleShape*) capsule->shape); } -void lovrCapsuleShapeSetLength(CapsuleShape* capsule, float length) { - lovrLog(LOG_WARN, "PHY", "Jolt CapsuleShape length is read-only"); - // todo: no setter available, but the shape could be removed and re-added -} - CylinderShape* lovrCylinderShapeCreate(float radius, float length) { lovrCheck(radius > 0.f && length > 0.f, "CylinderShape dimensions must be positive"); CylinderShape* cylinder = lovrCalloc(sizeof(CylinderShape)); @@ -860,20 +840,10 @@ float lovrCylinderShapeGetRadius(CylinderShape* cylinder) { return JPH_CylinderShape_GetRadius((JPH_CylinderShape*) cylinder->shape); } -void lovrCylinderShapeSetRadius(CylinderShape* cylinder, float radius) { - lovrLog(LOG_WARN, "PHY", "Jolt CylinderShape radius is read-only"); - // todo: no setter available, but the shape could be removed and re-added -} - float lovrCylinderShapeGetLength(CylinderShape* cylinder) { return JPH_CylinderShape_GetHalfHeight((JPH_CylinderShape*) cylinder->shape) * 2.f; } -void lovrCylinderShapeSetLength(CylinderShape* cylinder, float length) { - lovrLog(LOG_WARN, "PHY", "Jolt CylinderShape length is read-only"); - // todo: no setter available, but the shape could be removed and re-added -} - MeshShape* lovrMeshShapeCreate(int vertexCount, float vertices[], int indexCount, uint32_t indices[]) { MeshShape* mesh = lovrCalloc(sizeof(MeshShape)); mesh->ref = 1; From fd4207a40f1a781e138927914ab8a24f46d58b2c Mon Sep 17 00:00:00 2001 From: bjorn Date: Thu, 4 Apr 2024 16:23:20 -0700 Subject: [PATCH 08/17] 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. --- src/modules/physics/physics_jolt.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/modules/physics/physics_jolt.c b/src/modules/physics/physics_jolt.c index b57e22f5..02335a22 100644 --- a/src/modules/physics/physics_jolt.c +++ b/src/modules/physics/physics_jolt.c @@ -897,7 +897,7 @@ TerrainShape* lovrTerrainShapeCreate(float* vertices, uint32_t widthSamples, uin } CompoundShape* lovrCompoundShapeCreate(Shape** shapes, vec3 positions, quat orientations, uint32_t count, bool freeze) { - lovrCheck(!freeze || count > 0, "A frozen CompoundShape must contain at least one shape"); + lovrCheck(!freeze || count >= 2, "A frozen CompoundShape must contain at least two shapes"); CompoundShape* parent = lovrCalloc(sizeof(CompoundShape)); parent->ref = 1; From df43f4b4b4c3452e943627ea2150045b19a558ae Mon Sep 17 00:00:00 2001 From: bjorn Date: Thu, 4 Apr 2024 16:50:44 -0700 Subject: [PATCH 09/17] World queries return collider/shapeindex instead of Shape; --- src/api/l_physics_world.c | 59 +++++++++++++------------ src/modules/physics/physics.h | 4 +- src/modules/physics/physics_jolt.c | 69 +++++++++++++++--------------- 3 files changed, 69 insertions(+), 63 deletions(-) diff --git a/src/api/l_physics_world.c b/src/api/l_physics_world.c index e530e668..a2d47b94 100644 --- a/src/api/l_physics_world.c +++ b/src/api/l_physics_world.c @@ -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 = NULL; // TODO + 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 = NULL; // TODO + 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; @@ -309,15 +312,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 +338,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; diff --git a/src/modules/physics/physics.h b/src/modules/physics/physics.h index 81bdf5a0..09ea783c 100644 --- a/src/modules/physics/physics.h +++ b/src/modules/physics/physics.h @@ -27,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); diff --git a/src/modules/physics/physics_jolt.c b/src/modules/physics/physics_jolt.c index 02335a22..7c014c67 100644 --- a/src/modules/physics/physics_jolt.c +++ b/src/modules/physics/physics_jolt.c @@ -172,32 +172,34 @@ void lovrWorldRaycast(World* world, float x1, float y1, float z1, float x2, floa const JPH_Vec3 direction = { x2 - x1, y2 - y1, z2 - z1 }; JPH_AllHit_CastRayCollector* collector = JPH_AllHit_CastRayCollector_Create(); JPH_NarrowPhaseQuery_CastRayAll(query, &origin, &direction, collector, NULL, NULL, NULL); - size_t hit_count; - JPH_RayCastResult* hit_array = JPH_AllHit_CastRayCollector_GetHits(collector, &hit_count); - for (int i = 0; i < hit_count; i++) { - float x = x1 + hit_array[i].fraction * (x2 - x1); - float y = y1 + hit_array[i].fraction * (y2 - y1); - float z = z1 + hit_array[i].fraction * (z2 - z1); - // todo: assuming one shape per collider; doesn't support compound shape - Collider* collider = (Collider*) JPH_BodyInterface_GetUserData( - world->bodies, - hit_array[i].bodyID); - size_t count; - Shape* shape = lovrColliderGetShape(collider); - const JPH_RVec3 position = { x, y, z }; + + size_t count; + JPH_RayCastResult* hits = JPH_AllHit_CastRayCollector_GetHits(collector, &count); + + for (size_t i = 0; i < count; i++) { + Collider* collider = (Collider*) (uintptr_t) JPH_BodyInterface_GetUserData(world->bodies, hits[i].bodyID); + + uint32_t shape = 0; + if (collider->shape->type == SHAPE_COMPOUND) { + JPH_SubShapeID id = hits[i].subShapeID2; + JPH_SubShapeID remainder; + shape = JPH_CompoundShape_GetSubShapeIndexFromID((JPH_CompoundShape*) collider->shape, id, &remainder); + } + + JPH_RVec3 position = { + x1 + hits[i].fraction * (x2 - x1), + y1 + hits[i].fraction * (y2 - y1), + z1 + hits[i].fraction * (z2 - z1) + }; + JPH_Vec3 normal; - JPH_Body_GetWorldSpaceSurfaceNormal(collider->body, hit_array[i].subShapeID2, &position, &normal); + JPH_Body_GetWorldSpaceSurfaceNormal(collider->body, hits[i].subShapeID2, &position, &normal); - bool shouldStop = callback( - shape, // assumes one shape per collider; todo: compound shapes - x, y, z, - normal.x, normal.y, normal.z, - userdata); - - if (shouldStop) { + if (callback(collider, shape, &position.x, &normal.x, userdata)) { break; } } + JPH_AllHit_CastRayCollector_Destroy(collector); } @@ -208,26 +210,25 @@ static bool lovrWorldQueryShape(World* world, JPH_Shape* shape, float position[3 mat4_translate(m, position[0], position[1], position[2]); mat4_scale(m, scale[0], scale[1], scale[2]); - JPH_Vec3 direction = { 0.f }; - JPH_RVec3 base_offset = { 0.f }; + JPH_Vec3 direction = { 0.f, 0.f, 0.f }; + JPH_RVec3 base_offset = { 0.f, 0.f, 0.f }; const JPH_NarrowPhaseQuery* query = JPC_PhysicsSystem_GetNarrowPhaseQueryNoLock(world->system); JPH_AllHit_CastShapeCollector_Reset(state.castShapeCollector); JPH_NarrowPhaseQuery_CastShape(query, shape, &transform, &direction, &base_offset, state.castShapeCollector); - size_t hit_count; - JPH_ShapeCastResult* hit_array = JPH_AllHit_CastShapeCollector_GetHits(state.castShapeCollector, &hit_count); - for (int i = 0; i < hit_count; i++) { + + size_t count; + JPH_AllHit_CastShapeCollector_GetHits(state.castShapeCollector, &count); + + for (size_t i = 0; i < count; i++) { JPH_BodyID id = JPH_AllHit_CastShapeCollector_GetBodyID2(state.castShapeCollector, i); - Collider* collider = (Collider*) JPH_BodyInterface_GetUserData( - world->bodies, - id); - size_t count; - Shape* shape = lovrColliderGetShape(collider); - bool shouldStop = callback(shape, userdata); - if (shouldStop) { + Collider* collider = (Collider*) (uintptr_t) JPH_BodyInterface_GetUserData(world->bodies, id); + + if (callback(collider, 0, userdata)) { break; } } - return hit_count > 0; + + return count > 0; } bool lovrWorldQueryBox(World* world, float position[3], float size[3], QueryCallback callback, void* userdata) { From d5b69ed135beffab9c60f1baa2322ca6cfc05611 Mon Sep 17 00:00:00 2001 From: bjorn Date: Thu, 4 Apr 2024 21:41:12 -0700 Subject: [PATCH 10/17] Add Collider:get/setShapeOffset; --- src/api/l_physics_collider.c | 27 ++++++++++++++++++++ src/modules/physics/physics.h | 2 ++ src/modules/physics/physics_jolt.c | 40 ++++++++++++++++++++++++++++++ 3 files changed, 69 insertions(+) diff --git a/src/api/l_physics_collider.c b/src/api/l_physics_collider.c index d60d31df..aaa8b433 100644 --- a/src/api/l_physics_collider.c +++ b/src/api/l_physics_collider.c @@ -46,6 +46,31 @@ static int l_lovrColliderSetShape(lua_State* L) { 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; @@ -525,6 +550,8 @@ const luaL_Reg lovrCollider[] = { { "getWorld", l_lovrColliderGetWorld }, { "getShape", l_lovrColliderGetShape }, { "setShape", l_lovrColliderSetShape }, + { "getShapeOffset", l_lovrColliderGetShapeOffset }, + { "setShapeOffset", l_lovrColliderSetShapeOffset }, { "getJoints", l_lovrColliderGetJoints }, { "getUserData", l_lovrColliderGetUserData }, { "setUserData", l_lovrColliderSetUserData }, diff --git a/src/modules/physics/physics.h b/src/modules/physics/physics.h index 09ea783c..b3937d94 100644 --- a/src/modules/physics/physics.h +++ b/src/modules/physics/physics.h @@ -95,6 +95,8 @@ World* lovrColliderGetWorld(Collider* collider); Collider* lovrColliderGetNext(Collider* collider); 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); diff --git a/src/modules/physics/physics_jolt.c b/src/modules/physics/physics_jolt.c index 7c014c67..a8507a13 100644 --- a/src/modules/physics/physics_jolt.c +++ b/src/modules/physics/physics_jolt.c @@ -422,6 +422,46 @@ void lovrColliderSetShape(Collider* collider, Shape* shape) { } } +void lovrColliderGetShapeOffset(Collider* collider, float* position, float* orientation) { + if (!collider->shape) { + vec3_set(position, 0.f, 0.f, 0.f); + quat_identity(orientation); + return; + } + + const JPH_Shape* shape = JPH_BodyInterface_GetShape(collider->world->body_interface, collider->id); + + if (JPH_Shape_GetSubType(shape) == JPH_ShapeSubType_RotatedTranslated) { + JPH_Vec3 jposition; + JPH_Quat jrotation; + JPH_RotatedTranslatedShape_GetPosition((JPH_RotatedTranslatedShape*) shape, &jposition); + JPH_RotatedTranslatedShape_GetRotation((JPH_RotatedTranslatedShape*) shape, &jrotation); + vec3_init(position, &jposition.x); + quat_init(orientation, &jrotation.x); + } else { + vec3_set(position, 0.f, 0.f, 0.f); + quat_identity(orientation); + } +} + +void lovrColliderSetShapeOffset(Collider* collider, float* position, float* orientation) { + if (!collider->shape) { + return; + } + + const JPH_Shape* shape = JPH_BodyInterface_GetShape(collider->world->body_interface, collider->id); + + if (JPH_Shape_GetSubType(shape) == JPH_ShapeSubType_RotatedTranslated) { + JPH_Shape_Destroy((JPH_Shape*) shape); + } + + JPH_Vec3 jposition = { position[0], position[1], position[2] }; + JPH_Quat jrotation = { orientation[0], orientation[1], orientation[2], orientation[3] }; + shape = (JPH_Shape*) JPH_RotatedTranslatedShape_Create(&jposition, &jrotation, collider->shape->shape); + bool updateMass = collider->shape->type == SHAPE_MESH || collider->shape->type == SHAPE_TERRAIN; + JPH_BodyInterface_SetShape(collider->world->body_interface, collider->id, shape, updateMass, JPH_Activation_Activate); +} + Joint** lovrColliderGetJoints(Collider* collider, size_t* count) { *count = collider->joints.length; return collider->joints.data; From f30f3c7944e903d3c307862e65d2cf7795488f49 Mon Sep 17 00:00:00 2001 From: bjorn Date: Thu, 4 Apr 2024 21:52:51 -0700 Subject: [PATCH 11/17] Collider shape is required I think; Jolt doesn't really support bodies without shapes. --- src/api/l_physics_collider.c | 14 +++----------- src/modules/physics/physics_jolt.c | 10 ---------- 2 files changed, 3 insertions(+), 21 deletions(-) diff --git a/src/api/l_physics_collider.c b/src/api/l_physics_collider.c index aaa8b433..37af9ef8 100644 --- a/src/api/l_physics_collider.c +++ b/src/api/l_physics_collider.c @@ -27,22 +27,14 @@ static int l_lovrColliderGetWorld(lua_State* L) { static int l_lovrColliderGetShape(lua_State* L) { Collider* collider = luax_checktype(L, 1, Collider); Shape* shape = lovrColliderGetShape(collider); - if (shape) { - luax_pushshape(L, shape); - } else { - lua_pushnil(L); - } + luax_pushshape(L, shape); return 1; } static int l_lovrColliderSetShape(lua_State* L) { Collider* collider = luax_checktype(L, 1, Collider); - if (lua_isnoneornil(L, 2)) { - lovrColliderSetShape(collider, NULL); - } else { - Shape* shape = luax_checkshape(L, 2); - lovrColliderSetShape(collider, shape); - } + Shape* shape = luax_checkshape(L, 2); + lovrColliderSetShape(collider, shape); return 0; } diff --git a/src/modules/physics/physics_jolt.c b/src/modules/physics/physics_jolt.c index a8507a13..facf904a 100644 --- a/src/modules/physics/physics_jolt.c +++ b/src/modules/physics/physics_jolt.c @@ -423,12 +423,6 @@ void lovrColliderSetShape(Collider* collider, Shape* shape) { } void lovrColliderGetShapeOffset(Collider* collider, float* position, float* orientation) { - if (!collider->shape) { - vec3_set(position, 0.f, 0.f, 0.f); - quat_identity(orientation); - return; - } - const JPH_Shape* shape = JPH_BodyInterface_GetShape(collider->world->body_interface, collider->id); if (JPH_Shape_GetSubType(shape) == JPH_ShapeSubType_RotatedTranslated) { @@ -445,10 +439,6 @@ void lovrColliderGetShapeOffset(Collider* collider, float* position, float* orie } void lovrColliderSetShapeOffset(Collider* collider, float* position, float* orientation) { - if (!collider->shape) { - return; - } - const JPH_Shape* shape = JPH_BodyInterface_GetShape(collider->world->body_interface, collider->id); if (JPH_Shape_GetSubType(shape) == JPH_ShapeSubType_RotatedTranslated) { From d2002711f075e9c3b629574ae51a491c63a44664 Mon Sep 17 00:00:00 2001 From: bjorn Date: Fri, 5 Apr 2024 00:35:03 -0700 Subject: [PATCH 12/17] ODE compatibility; --- src/modules/physics/physics_ode.c | 151 +++++++++++++++++------------- 1 file changed, 85 insertions(+), 66 deletions(-) diff --git a/src/modules/physics/physics_ode.c b/src/modules/physics/physics_ode.c index 55b5da92..f8e013b5 100644 --- a/src/modules/physics/physics_ode.c +++ b/src/modules/physics/physics_ode.c @@ -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; } @@ -445,7 +445,6 @@ 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); lovrColliderSetPosition(collider, x, y, z); @@ -467,7 +466,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 +475,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 +515,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) { @@ -888,31 +894,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 +934,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 +1095,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); From dba9c28cdec26c0b9bac83c2d14debf7662f2111 Mon Sep 17 00:00:00 2001 From: bjorn Date: Fri, 5 Apr 2024 00:38:34 -0700 Subject: [PATCH 13/17] rm unused shape prototypes; --- src/modules/physics/physics.h | 4 ---- 1 file changed, 4 deletions(-) diff --git a/src/modules/physics/physics.h b/src/modules/physics/physics.h index b3937d94..565eb1c0 100644 --- a/src/modules/physics/physics.h +++ b/src/modules/physics/physics.h @@ -159,10 +159,6 @@ 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]); From 726e00cf602f09b159934394fd03943f8f5d20f2 Mon Sep 17 00:00:00 2001 From: bjorn Date: Fri, 5 Apr 2024 11:55:12 -0700 Subject: [PATCH 14/17] Add Collider:getShapes for backcompat; --- src/api/l_physics_collider.c | 11 +++++++++++ 1 file changed, 11 insertions(+) diff --git a/src/api/l_physics_collider.c b/src/api/l_physics_collider.c index 37af9ef8..250beb93 100644 --- a/src/api/l_physics_collider.c +++ b/src/api/l_physics_collider.c @@ -521,6 +521,16 @@ 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); @@ -591,6 +601,7 @@ const luaL_Reg lovrCollider[] = { { "setTag", l_lovrColliderSetTag }, // Deprecated + { "getShapes", l_lovrColliderGetShapes }, { "isGravityIgnored", l_lovrColliderIsGravityIgnored }, { "setGravityIgnored", l_lovrColliderSetGravityIgnored }, From 23895ba8a02066b322825e9bc26a72ed9ad18a22 Mon Sep 17 00:00:00 2001 From: bjorn Date: Fri, 5 Apr 2024 18:04:07 -0700 Subject: [PATCH 15/17] lovrColliderCreate takes shape; Jolt requires a shape, also it saves a bit of work. --- src/api/l_physics_world.c | 20 +++++++------------- src/modules/physics/physics.h | 2 +- src/modules/physics/physics_jolt.c | 10 +++++----- src/modules/physics/physics_ode.c | 3 ++- 4 files changed, 15 insertions(+), 20 deletions(-) diff --git a/src/api/l_physics_world.c b/src/api/l_physics_world.c index a2d47b94..99c16067 100644 --- a/src/api/l_physics_world.c +++ b/src/api/l_physics_world.c @@ -104,7 +104,7 @@ static int l_lovrWorldNewCollider(lua_State* L) { World* world = luax_checktype(L, 1, World); float position[3]; luax_readvec3(L, 2, position, NULL); - Collider* collider = lovrColliderCreate(world, position[0], position[1], position[2]); + Collider* collider = lovrColliderCreate(world, NULL, position[0], position[1], position[2]); luax_pushtype(L, Collider, collider); lovrRelease(collider, lovrColliderDestroy); return 1; @@ -114,9 +114,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); - lovrColliderSetShape(collider, shape); + Collider* collider = lovrColliderCreate(world, shape, position[0], position[1], position[2]); lovrColliderInitInertia(collider, shape); luax_pushtype(L, Collider, collider); lovrRelease(collider, lovrColliderDestroy); @@ -128,9 +127,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); - lovrColliderSetShape(collider, shape); + Collider* collider = lovrColliderCreate(world, shape, position[0], position[1], position[2]); lovrColliderInitInertia(collider, shape); luax_pushtype(L, Collider, collider); lovrRelease(collider, lovrColliderDestroy); @@ -142,9 +140,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); - lovrColliderSetShape(collider, shape); + Collider* collider = lovrColliderCreate(world, shape, position[0], position[1], position[2]); lovrColliderInitInertia(collider, shape); luax_pushtype(L, Collider, collider); lovrRelease(collider, lovrColliderDestroy); @@ -156,9 +153,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); - lovrColliderSetShape(collider, shape); + Collider* collider = lovrColliderCreate(world, shape, position[0], position[1], position[2]); lovrColliderInitInertia(collider, shape); luax_pushtype(L, Collider, collider); lovrRelease(collider, lovrColliderDestroy); @@ -168,9 +164,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); - lovrColliderSetShape(collider, shape); + Collider* collider = lovrColliderCreate(world, shape, 0.f, 0.f, 0.f); lovrColliderInitInertia(collider, shape); luax_pushtype(L, Collider, collider); lovrRelease(collider, lovrColliderDestroy); @@ -180,9 +175,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); - lovrColliderSetShape(collider, shape); + Collider* collider = lovrColliderCreate(world, shape, 0.f, 0.f, 0.f); lovrColliderSetKinematic(collider, true); luax_pushtype(L, Collider, collider); lovrRelease(collider, lovrColliderDestroy); diff --git a/src/modules/physics/physics.h b/src/modules/physics/physics.h index 565eb1c0..6ecdb669 100644 --- a/src/modules/physics/physics.h +++ b/src/modules/physics/physics.h @@ -86,7 +86,7 @@ void lovrWorldSetSleepingAllowed(World* world, bool allowed); // 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); diff --git a/src/modules/physics/physics_jolt.c b/src/modules/physics/physics_jolt.c index facf904a..9dc83c81 100644 --- a/src/modules/physics/physics_jolt.c +++ b/src/modules/physics/physics_jolt.c @@ -315,7 +315,7 @@ void lovrWorldSetAngularDamping(World* world, float damping, float threshold) { // Collider -Collider* lovrColliderCreate(World* world, float x, float y, float z) { +Collider* lovrColliderCreate(World* world, Shape* shape, float x, float y, float z) { // todo: crashes when too many are added Collider* collider = lovrCalloc(sizeof(Collider)); collider->ref = 1; @@ -328,7 +328,7 @@ Collider* lovrColliderCreate(World* world, float x, float y, float z) { const JPH_Quat rotation = { 0.f, 0.f, 0.f, 1.f }; // todo: a placeholder querySphere shape is used in collider, then replaced in lovrColliderAddShape JPH_BodyCreationSettings* settings = JPH_BodyCreationSettings_Create3( - state.querySphere, &position, &rotation, motionType, objectLayer); + shape ? shape->shape : state.querySphere, &position, &rotation, motionType, objectLayer); collider->body = JPH_BodyInterface_CreateBody(world->bodies, settings); JPH_BodyCreationSettings_Destroy(settings); collider->id = JPH_Body_GetID(collider->body); @@ -423,7 +423,7 @@ void lovrColliderSetShape(Collider* collider, Shape* shape) { } void lovrColliderGetShapeOffset(Collider* collider, float* position, float* orientation) { - const JPH_Shape* shape = JPH_BodyInterface_GetShape(collider->world->body_interface, collider->id); + const JPH_Shape* shape = JPH_BodyInterface_GetShape(collider->world->bodies, collider->id); if (JPH_Shape_GetSubType(shape) == JPH_ShapeSubType_RotatedTranslated) { JPH_Vec3 jposition; @@ -439,7 +439,7 @@ void lovrColliderGetShapeOffset(Collider* collider, float* position, float* orie } void lovrColliderSetShapeOffset(Collider* collider, float* position, float* orientation) { - const JPH_Shape* shape = JPH_BodyInterface_GetShape(collider->world->body_interface, collider->id); + const JPH_Shape* shape = JPH_BodyInterface_GetShape(collider->world->bodies, collider->id); if (JPH_Shape_GetSubType(shape) == JPH_ShapeSubType_RotatedTranslated) { JPH_Shape_Destroy((JPH_Shape*) shape); @@ -449,7 +449,7 @@ void lovrColliderSetShapeOffset(Collider* collider, float* position, float* orie JPH_Quat jrotation = { orientation[0], orientation[1], orientation[2], orientation[3] }; shape = (JPH_Shape*) JPH_RotatedTranslatedShape_Create(&jposition, &jrotation, collider->shape->shape); bool updateMass = collider->shape->type == SHAPE_MESH || collider->shape->type == SHAPE_TERRAIN; - JPH_BodyInterface_SetShape(collider->world->body_interface, collider->id, shape, updateMass, JPH_Activation_Activate); + JPH_BodyInterface_SetShape(collider->world->bodies, collider->id, shape, updateMass, JPH_Activation_Activate); } Joint** lovrColliderGetJoints(Collider* collider, size_t* count) { diff --git a/src/modules/physics/physics_ode.c b/src/modules/physics/physics_ode.c index f8e013b5..259521b6 100644 --- a/src/modules/physics/physics_ode.c +++ b/src/modules/physics/physics_ode.c @@ -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); @@ -447,6 +447,7 @@ Collider* lovrColliderCreate(World* world, float x, float y, float z) { dBodySetData(collider->body, collider); arr_init(&collider->joints); + lovrColliderSetShape(collider, shape); lovrColliderSetPosition(collider, x, y, z); // Adjust the world's collider list From e24ba87bb4ce914c0caa9b4528ec85aa499c2b43 Mon Sep 17 00:00:00 2001 From: bjorn Date: Fri, 5 Apr 2024 18:40:23 -0700 Subject: [PATCH 16/17] 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. --- src/modules/physics/physics_jolt.c | 76 ++++++++++++++++++------------ 1 file changed, 46 insertions(+), 30 deletions(-) diff --git a/src/modules/physics/physics_jolt.c b/src/modules/physics/physics_jolt.c index 9dc83c81..4f62d319 100644 --- a/src/modules/physics/physics_jolt.c +++ b/src/modules/physics/physics_jolt.c @@ -43,6 +43,7 @@ struct Joint { static struct { bool initialized; + Shape* pointShape; JPH_Shape* queryBox; JPH_Shape* querySphere; JPH_AllHit_CastShapeCollector* castShapeCollector; @@ -69,14 +70,16 @@ static uint32_t findTag(World* world, const char* name) { bool lovrPhysicsInit(void) { if (state.initialized) return false; JPH_Init(32 * 1024 * 1024); - state.castShapeCollector = JPH_AllHit_CastShapeCollector_Create(); + state.pointShape = lovrSphereShapeCreate(FLT_EPSILON); state.querySphere = (JPH_Shape*) JPH_SphereShape_Create(1.f); state.queryBox = (JPH_Shape*) JPH_BoxShape_Create(&(const JPH_Vec3) { .5, .5f, .5f }, 0.f); + state.castShapeCollector = JPH_AllHit_CastShapeCollector_Create(); return state.initialized = true; } void lovrPhysicsDestroy(void) { if (!state.initialized) return; + lovrRelease(state.pointShape, lovrShapeDestroy); JPH_Shutdown(); state.initialized = false; } @@ -316,24 +319,27 @@ void lovrWorldSetAngularDamping(World* world, float damping, float threshold) { // Collider Collider* lovrColliderCreate(World* world, Shape* shape, float x, float y, float z) { + if (!shape) shape = state.pointShape; + // todo: crashes when too many are added Collider* collider = lovrCalloc(sizeof(Collider)); collider->ref = 1; collider->world = world; + collider->shape = shape; collider->tag = UNTAGGED; - JPH_MotionType motionType = JPH_MotionType_Dynamic; - JPH_ObjectLayer objectLayer = UNTAGGED * 2 + 1; const JPH_RVec3 position = { x, y, z }; const JPH_Quat rotation = { 0.f, 0.f, 0.f, 1.f }; - // todo: a placeholder querySphere shape is used in collider, then replaced in lovrColliderAddShape - JPH_BodyCreationSettings* settings = JPH_BodyCreationSettings_Create3( - shape ? shape->shape : state.querySphere, &position, &rotation, motionType, objectLayer); + JPH_MotionType type = JPH_MotionType_Dynamic; + JPH_ObjectLayer objectLayer = UNTAGGED * 2 + 1; + JPH_BodyCreationSettings* settings = JPH_BodyCreationSettings_Create3(shape->shape, &position, &rotation, type, objectLayer); collider->body = JPH_BodyInterface_CreateBody(world->bodies, settings); - JPH_BodyCreationSettings_Destroy(settings); collider->id = JPH_Body_GetID(collider->body); + JPH_BodyCreationSettings_Destroy(settings); + JPH_BodyInterface_AddBody(world->bodies, collider->id, JPH_Activation_Activate); JPH_BodyInterface_SetUserData(world->bodies, collider->id, (uint64_t) collider); + lovrColliderSetLinearDamping(collider, world->defaultLinearDamping, 0.f); lovrColliderSetAngularDamping(collider, world->defaultAngularDamping, 0.f); lovrColliderSetSleepingAllowed(collider, world->defaultIsSleepingAllowed); @@ -349,8 +355,8 @@ Collider* lovrColliderCreate(World* world, Shape* shape, float x, float y, float world->head = collider; } - // The world owns a reference to the collider - lovrRetain(collider); + lovrRetain(collider->shape); + lovrRetain(collider); // The world owns a reference to the collider return collider; } @@ -403,22 +409,35 @@ Collider* lovrColliderGetNext(Collider* collider) { } Shape* lovrColliderGetShape(Collider* collider) { - return collider->shape; + return collider->shape == state.pointShape ? NULL : collider->shape; } void lovrColliderSetShape(Collider* collider, Shape* shape) { - if (shape != collider->shape) { - lovrRelease(collider->shape, lovrShapeDestroy); - collider->shape = shape; - lovrRetain(shape); + shape = shape ? shape : state.pointShape; - bool updateMass = true; - if (shape->type == SHAPE_MESH || shape->type == SHAPE_TERRAIN) { - lovrColliderSetKinematic(collider, true); - updateMass = false; - } + if (shape == collider->shape) { + return; + } - JPH_BodyInterface_SetShape(collider->world->bodies, collider->id, shape->shape, updateMass, JPH_Activation_Activate); + float position[3], orientation[4]; + const JPH_Shape* parent = JPH_BodyInterface_GetShape(collider->world->bodies, collider->id); + bool hasOffset = JPH_Shape_GetSubType(parent) == JPH_ShapeSubType_RotatedTranslated; + if (hasOffset) lovrColliderGetShapeOffset(collider, position, orientation); + + lovrRelease(collider->shape, lovrShapeDestroy); + collider->shape = shape; + lovrRetain(shape); + + bool updateMass = true; + if (shape->type == SHAPE_MESH || shape->type == SHAPE_TERRAIN) { + lovrColliderSetKinematic(collider, true); + updateMass = false; + } + + JPH_BodyInterface_SetShape(collider->world->bodies, collider->id, shape->shape, updateMass, JPH_Activation_Activate); + + if (hasOffset) { + lovrColliderSetShapeOffset(collider, position, orientation); } } @@ -448,7 +467,7 @@ void lovrColliderSetShapeOffset(Collider* collider, float* position, float* orie JPH_Vec3 jposition = { position[0], position[1], position[2] }; JPH_Quat jrotation = { orientation[0], orientation[1], orientation[2], orientation[3] }; shape = (JPH_Shape*) JPH_RotatedTranslatedShape_Create(&jposition, &jrotation, collider->shape->shape); - bool updateMass = collider->shape->type == SHAPE_MESH || collider->shape->type == SHAPE_TERRAIN; + bool updateMass = collider->shape && (collider->shape->type == SHAPE_MESH || collider->shape->type == SHAPE_TERRAIN); JPH_BodyInterface_SetShape(collider->world->bodies, collider->id, shape, updateMass, JPH_Activation_Activate); } @@ -545,20 +564,17 @@ void lovrColliderSetAwake(Collider* collider, bool awake) { } float lovrColliderGetMass(Collider* collider) { - if (!collider->shape) return 0.f; JPH_MotionProperties* motionProperties = JPH_Body_GetMotionProperties(collider->body); return 1.f / JPH_MotionProperties_GetInverseMassUnchecked(motionProperties); } void lovrColliderSetMass(Collider* collider, float mass) { - if (collider->shape) { - JPH_MotionProperties* motionProperties = JPH_Body_GetMotionProperties(collider->body); - Shape* shape = collider->shape; - JPH_MassProperties* massProperties; - JPH_Shape_GetMassProperties(shape->shape, massProperties); - JPH_MassProperties_ScaleToMass(massProperties, mass); - JPH_MotionProperties_SetMassProperties(motionProperties, JPH_AllowedDOFs_All, massProperties); - } + JPH_MotionProperties* motionProperties = JPH_Body_GetMotionProperties(collider->body); + Shape* shape = collider->shape; + JPH_MassProperties* massProperties; + JPH_Shape_GetMassProperties(shape->shape, massProperties); + JPH_MassProperties_ScaleToMass(massProperties, mass); + JPH_MotionProperties_SetMassProperties(motionProperties, JPH_AllowedDOFs_All, massProperties); } void lovrColliderGetMassData(Collider* collider, float* cx, float* cy, float* cz, float* mass, float inertia[6]) { From 5b4ee301870c1a5cf97face126e258c9510ce17a Mon Sep 17 00:00:00 2001 From: bjorn Date: Fri, 5 Apr 2024 18:44:04 -0700 Subject: [PATCH 17/17] newCollider takes optional Shape as first arg; --- src/api/l_physics_world.c | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/src/api/l_physics_world.c b/src/api/l_physics_world.c index 99c16067..dc551ecf 100644 --- a/src/api/l_physics_world.c +++ b/src/api/l_physics_world.c @@ -102,9 +102,10 @@ static bool queryCallback(Collider* collider, uint32_t 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, NULL, 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;