From 8f40d980741c1f3d46ffb63e9048fe1c204ed403 Mon Sep 17 00:00:00 2001 From: bjorn Date: Thu, 4 Apr 2024 16:50:44 -0700 Subject: [PATCH] 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 fd5ae7a2..c40b8b9d 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 385acc76..8e1b9c75 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) {