World queries return collider/shapeindex instead of Shape;

This commit is contained in:
bjorn 2024-04-04 16:50:44 -07:00
parent e842c2b772
commit 8f40d98074
3 changed files with 69 additions and 63 deletions

View File

@ -27,17 +27,18 @@ static int nextOverlap(lua_State* L) {
}
}
static bool raycastCallback(Shape* shape, float x, float y, float z, float nx, float ny, float nz, void* userdata) {
static bool raycastCallback(Collider* collider, uint32_t shape, float position[3], float normal[3], void* userdata) {
lua_State* L = userdata;
lua_pushvalue(L, -1);
luax_pushshape(L, shape);
lua_pushnumber(L, x);
lua_pushnumber(L, y);
lua_pushnumber(L, z);
lua_pushnumber(L, nx);
lua_pushnumber(L, ny);
lua_pushnumber(L, nz);
lua_call(L, 7, 1);
luax_pushtype(L, Collider, collider);
lua_pushinteger(L, shape);
lua_pushnumber(L, position[0]);
lua_pushnumber(L, position[1]);
lua_pushnumber(L, position[2]);
lua_pushnumber(L, normal[0]);
lua_pushnumber(L, normal[1]);
lua_pushnumber(L, normal[2]);
lua_call(L, 8, 1);
bool shouldStop = lua_type(L, -1) == LUA_TBOOLEAN && !lua_toboolean(L, -1);
lua_pop(L, 1);
return shouldStop;
@ -45,53 +46,55 @@ static bool raycastCallback(Shape* shape, float x, float y, float z, float nx, f
typedef struct {
const char* tag;
Shape* shape;
Collider* collider;
uint32_t shape;
float distance;
float origin[3];
float position[3];
float normal[3];
} RaycastData;
static bool raycastAnyCallback(Shape* shape, float x, float y, float z, float nx, float ny, float nz, void* userdata) {
static bool raycastAnyCallback(Collider* collider, uint32_t shape, float position[3], float normal[3], void* userdata) {
RaycastData* data = userdata;
if (data->tag) {
const char* tag = 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;

View File

@ -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);

View File

@ -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) {