diff --git a/src/api/l_physics_world.c b/src/api/l_physics_world.c index a97271d8..34a23d23 100644 --- a/src/api/l_physics_world.c +++ b/src/api/l_physics_world.c @@ -25,7 +25,7 @@ static int nextOverlap(lua_State* L) { } } -static void raycastCallback(Shape* shape, float x, float y, float z, float nx, float ny, float nz, void* userdata) { +static bool raycastCallback(Shape* shape, float x, float y, float z, float nx, float ny, float nz, void* userdata) { lua_State* L = userdata; lua_pushvalue(L, -1); luax_pushshape(L, shape); @@ -35,14 +35,20 @@ static void raycastCallback(Shape* shape, float x, float y, float z, float nx, f lua_pushnumber(L, nx); lua_pushnumber(L, ny); lua_pushnumber(L, nz); - lua_call(L, 7, 0); + lua_call(L, 7, 1); + bool should_stop = lua_type(L, -1) == LUA_TBOOLEAN && !lua_toboolean(L, -1); + lua_pop(L, 1); + return should_stop; } -static void queryCallback(Shape* shape, void* userdata) { +static bool queryCallback(Shape* shape, void* userdata) { lua_State* L = userdata; lua_pushvalue(L, -1); luax_pushshape(L, shape); - lua_call(L, 1, 0); + lua_call(L, 1, 1); + bool should_stop = lua_type(L, -1) == LUA_TBOOLEAN && !lua_toboolean(L, -1); + lua_pop(L, 1); + return should_stop; } static int l_lovrWorldNewCollider(lua_State* L) { diff --git a/src/modules/physics/physics.c b/src/modules/physics/physics.c index c4f695a6..20a563a3 100644 --- a/src/modules/physics/physics.c +++ b/src/modules/physics/physics.c @@ -60,9 +60,12 @@ static void customNearCallback(void* data, dGeomID shapeA, dGeomID shapeB) { typedef struct { RaycastCallback callback; void* userdata; + bool should_stop; } RaycastData; static void raycastCallback(void* data, dGeomID a, dGeomID b) { + if (((RaycastData*)data)->should_stop) return; + RaycastCallback callback = ((RaycastData*) data)->callback; void* userdata = ((RaycastData*) data)->userdata; Shape* shape = dGeomGetData(b); @@ -83,9 +86,11 @@ typedef struct { QueryCallback callback; void* userdata; bool called; + bool should_stop; } QueryData; static void queryCallback(void* d, dGeomID a, dGeomID b) { + if (((QueryData*)d)->should_stop) return; Shape* shape = dGeomGetData(b); if (!shape) { @@ -93,9 +98,12 @@ static void queryCallback(void* d, dGeomID a, dGeomID b) { } QueryData* data = d; + dContactGeom contact; if (dCollide(a, b, 1 | CONTACTS_UNIMPORTANT, &contact, sizeof(contact))) { - if (data->callback) data->callback(shape, data->userdata); + if (data->callback) { + data->should_stop = data->callback(shape, data->userdata); + } data->called = true; } } @@ -298,7 +306,7 @@ void lovrWorldGetContacts(World* world, Shape* a, Shape* b, Contact contacts[MAX } void lovrWorldRaycast(World* world, float x1, float y1, float z1, float x2, float y2, float z2, RaycastCallback callback, void* userdata) { - RaycastData data = { .callback = callback, .userdata = userdata }; + RaycastData data = { .callback = callback, .userdata = userdata, .should_stop = false }; float dx = x2 - x1; float dy = y2 - y1; float dz = z2 - z1; @@ -310,7 +318,7 @@ void lovrWorldRaycast(World* world, float x1, float y1, float z1, float x2, floa } bool lovrWorldQueryBox(World* world, float position[3], float size[3], QueryCallback callback, void* userdata) { - QueryData data = { .callback = callback, .userdata = userdata, .called = false }; + QueryData data = { .callback = callback, .userdata = userdata, .called = false, .should_stop = false }; dGeomID box = dCreateBox(world->space, fabsf(size[0]), fabsf(size[1]), fabsf(size[2])); dGeomSetPosition(box, position[0], position[1], position[2]); dSpaceCollide2(box, (dGeomID) world->space, &data, queryCallback); diff --git a/src/modules/physics/physics.h b/src/modules/physics/physics.h index 54a204ed..91954821 100644 --- a/src/modules/physics/physics.h +++ b/src/modules/physics/physics.h @@ -26,8 +26,8 @@ typedef Joint HingeJoint; typedef Joint SliderJoint; typedef void (*CollisionResolver)(World* world, void* userdata); -typedef void (*RaycastCallback)(Shape* shape, float x, float y, float z, float nx, float ny, float nz, void* userdata); -typedef void (*QueryCallback)(Shape* shape, 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); bool lovrPhysicsInit(void); void lovrPhysicsDestroy(void);