Compare commits

...

28 Commits

Author SHA1 Message Date
Bjorn 9b57b3de70
Merge 060e72c525 into f4d1161a3d 2024-04-07 20:48:14 +00:00
bjorn 060e72c525 Rename CompoundShape 'shape' to 'child';
Maybe slightly less ambiguous/confusing?
2024-04-07 13:47:52 -07:00
bjorn 47dec01772 rm more useless checks; 2024-04-07 13:47:52 -07:00
bjorn 582ee1625f CompoundShape:replaceShape fixes; 2024-04-07 13:47:52 -07:00
bjorn e36374c4cf rm useless check; 2024-04-07 13:47:52 -07:00
bjorn 98601b3425 Collider:setShape accepts nil;
Internally it still uses a teeny tiny sphere (it's kinda like the
collider's shape is a "point").
2024-04-07 13:47:52 -07:00
bjorn 2ac0d6946e Move shape arg to last argument of query callbacks;
Also fix an off-by-one error.
2024-04-07 13:47:52 -07:00
bjorn b589cec975 Collider:getShape takes optional child index;
For convenience when you're trying to dig a leaf shape out of a CompoundShape.

It's ignored if the collider's shape is not a CompoundShape.
2024-04-07 13:47:52 -07:00
bjorn 8bdab9f2d4 Shape:getAABB; 2024-04-07 13:47:52 -07:00
bjorn 5751068728 Move Shape:is/setSensor and Shape:is/setEnabled to Collider; 2024-04-07 13:47:52 -07:00
bjorn 481a9dafa2 newCollider takes optional Shape as first arg; 2024-04-07 13:47:52 -07:00
bjorn 95cc6c2753 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.
2024-04-07 13:47:52 -07:00
bjorn f35cda7db8 lovrColliderCreate takes shape;
Jolt requires a shape, also it saves a bit of work.
2024-04-07 13:47:52 -07:00
bjorn 907d89c913 Add Collider:getShapes for backcompat; 2024-04-07 13:47:52 -07:00
bjorn ff0f39fc7b rm unused shape prototypes; 2024-04-07 13:47:52 -07:00
bjorn b809db1d83 ODE compatibility; 2024-04-07 13:47:52 -07:00
bjorn 051266f8ea Collider shape is required I think;
Jolt doesn't really support bodies without shapes.
2024-04-07 13:47:52 -07:00
bjorn 930e713079 Add Collider:get/setShapeOffset; 2024-04-07 13:47:52 -07:00
bjorn 4f26182595 World queries return collider/shapeindex instead of Shape; 2024-04-07 13:47:52 -07:00
bjorn 8cbdda00f3 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.
2024-04-07 13:47:52 -07:00
bjorn 10f965d69e 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.
2024-04-07 13:47:52 -07:00
bjorn a7bf4ca2a4 CompoundShape fixes; 2024-04-07 13:47:52 -07:00
bjorn c27694fd8e Shapes set their userdata; 2024-04-07 13:47:52 -07:00
bjorn b3e9e55b8a CompoundShape API; 2024-04-07 13:47:52 -07:00
bjorn 6f0b6391df Start CompoundShape; 2024-04-07 13:47:52 -07:00
bjorn ce58619094 Colliders can only have 1 shape; rm shape pose; 2024-04-07 13:47:52 -07:00
bjorn 9b6f58ac1e Update Jolt; 2024-04-07 13:47:52 -07:00
bjorn f4d1161a3d Disable Jolt profiler and debug renderer; 2024-04-07 13:46:57 -07:00
10 changed files with 750 additions and 515 deletions

View File

@ -185,6 +185,8 @@ if(LOVR_ENABLE_PHYSICS)
set(LOVR_PHYSICS_LIB ode) set(LOVR_PHYSICS_LIB ode)
endif() endif()
elseif(LOVR_PHYSICS_LIBRARY STREQUAL "JOLT") elseif(LOVR_PHYSICS_LIBRARY STREQUAL "JOLT")
set(DEBUG_RENDERER_IN_DEBUG_AND_RELEASE OFF CACHE BOOL "")
set(PROFILER_IN_DEBUG_AND_RELEASE OFF CACHE BOOL "")
add_subdirectory(deps/jolt-physics-sharp jolt) add_subdirectory(deps/jolt-physics-sharp jolt)
set(LOVR_PHYSICS_LIB joltc) set(LOVR_PHYSICS_LIB joltc)
endif() endif()

@ -1 +1 @@
Subproject commit 29fe07e8088279c47d7108107856ec3c826d1817 Subproject commit 2cda386d71174bec355888539679f7a4f7be1c2a

View File

@ -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_newcylindershape(lua_State* L, int index);
struct Shape* luax_newmeshshape(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_newterrainshape(lua_State* L, int index);
struct Shape* luax_newcompoundshape(lua_State* L, int index);
#endif #endif

View File

@ -9,6 +9,7 @@ StringEntry lovrShapeType[] = {
[SHAPE_CYLINDER] = ENTRY("cylinder"), [SHAPE_CYLINDER] = ENTRY("cylinder"),
[SHAPE_MESH] = ENTRY("mesh"), [SHAPE_MESH] = ENTRY("mesh"),
[SHAPE_TERRAIN] = ENTRY("terrain"), [SHAPE_TERRAIN] = ENTRY("terrain"),
[SHAPE_COMPOUND] = ENTRY("compound"),
{ 0 } { 0 }
}; };
@ -178,6 +179,13 @@ static int l_lovrPhysicsNewTerrainShape(lua_State* L) {
return 1; 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[] = { static const luaL_Reg lovrPhysics[] = {
{ "newWorld", l_lovrPhysicsNewWorld }, { "newWorld", l_lovrPhysicsNewWorld },
{ "newBallJoint", l_lovrPhysicsNewBallJoint }, { "newBallJoint", l_lovrPhysicsNewBallJoint },
@ -190,6 +198,7 @@ static const luaL_Reg lovrPhysics[] = {
{ "newSliderJoint", l_lovrPhysicsNewSliderJoint }, { "newSliderJoint", l_lovrPhysicsNewSliderJoint },
{ "newSphereShape", l_lovrPhysicsNewSphereShape }, { "newSphereShape", l_lovrPhysicsNewSphereShape },
{ "newTerrainShape", l_lovrPhysicsNewTerrainShape }, { "newTerrainShape", l_lovrPhysicsNewTerrainShape },
{ "newCompoundShape", l_lovrPhysicsNewCompoundShape },
{ NULL, NULL } { NULL, NULL }
}; };
@ -205,6 +214,7 @@ extern const luaL_Reg lovrCapsuleShape[];
extern const luaL_Reg lovrCylinderShape[]; extern const luaL_Reg lovrCylinderShape[];
extern const luaL_Reg lovrMeshShape[]; extern const luaL_Reg lovrMeshShape[];
extern const luaL_Reg lovrTerrainShape[]; extern const luaL_Reg lovrTerrainShape[];
extern const luaL_Reg lovrCompoundShape[];
int luaopen_lovr_physics(lua_State* L) { int luaopen_lovr_physics(lua_State* L) {
lua_newtable(L); lua_newtable(L);
@ -221,6 +231,7 @@ int luaopen_lovr_physics(lua_State* L) {
luax_registertype(L, CylinderShape); luax_registertype(L, CylinderShape);
luax_registertype(L, MeshShape); luax_registertype(L, MeshShape);
luax_registertype(L, TerrainShape); luax_registertype(L, TerrainShape);
luax_registertype(L, CompoundShape);
lovrPhysicsInit(); lovrPhysicsInit();
luax_atexit(L, lovrPhysicsDestroy); luax_atexit(L, lovrPhysicsDestroy);
return 1; return 1;

View File

@ -17,6 +17,20 @@ static int l_lovrColliderIsDestroyed(lua_State* L) {
return 1; return 1;
} }
static int l_lovrColliderIsEnabled(lua_State* L) {
Collider* collider = luax_checktype(L, 1, Collider);
bool enabled = lovrColliderIsEnabled(collider);
lua_pushboolean(L, enabled);
return 1;
}
static int l_lovrColliderSetEnabled(lua_State* L) {
Collider* collider = luax_checktype(L, 1, Collider);
bool enable = lua_toboolean(L, 2);
lovrColliderSetEnabled(collider, enable);
return 1;
}
static int l_lovrColliderGetWorld(lua_State* L) { static int l_lovrColliderGetWorld(lua_State* L) {
Collider* collider = luax_checktype(L, 1, Collider); Collider* collider = luax_checktype(L, 1, Collider);
World* world = lovrColliderGetWorld(collider); World* world = lovrColliderGetWorld(collider);
@ -24,32 +38,50 @@ static int l_lovrColliderGetWorld(lua_State* L) {
return 1; return 1;
} }
static int l_lovrColliderAddShape(lua_State* L) { static int l_lovrColliderGetShape(lua_State* L) {
Collider* collider = luax_checktype(L, 1, Collider); Collider* collider = luax_checktype(L, 1, Collider);
Shape* shape = luax_checkshape(L, 2); uint32_t child = lua_gettop(L) == 1 ? ~0u : luax_checku32(L, 2) - 1;
lovrColliderAddShape(collider, shape); Shape* shape = lovrColliderGetShape(collider, child);
return 0; if (shape) {
} luax_pushshape(L, shape);
} else {
static int l_lovrColliderRemoveShape(lua_State* L) { lua_pushnil(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);
} }
return 1; return 1;
} }
static int l_lovrColliderSetShape(lua_State* L) {
Collider* collider = luax_checktype(L, 1, Collider);
Shape* shape = lua_isnoneornil(L, 2) ? NULL : luax_checkshape(L, 2);
lovrColliderSetShape(collider, shape);
return 0;
}
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) { static int l_lovrColliderGetJoints(lua_State* L) {
Collider* collider = luax_checktype(L, 1, Collider); Collider* collider = luax_checktype(L, 1, Collider);
size_t count; size_t count;
@ -110,6 +142,19 @@ static int l_lovrColliderSetKinematic(lua_State* L) {
return 0; return 0;
} }
static int l_lovrColliderIsSensor(lua_State* L) {
Collider* collider = luax_checktype(L, 1, Collider);
lua_pushboolean(L, lovrColliderIsSensor(collider));
return 1;
}
static int l_lovrColliderSetSensor(lua_State* L) {
Collider* collider = luax_checktype(L, 1, Collider);
bool sensor = lua_toboolean(L, 2);
lovrColliderSetSensor(collider, sensor);
return 0;
}
static int l_lovrColliderIsContinuous(lua_State* L) { static int l_lovrColliderIsContinuous(lua_State* L) {
Collider* collider = luax_checktype(L, 1, Collider); Collider* collider = luax_checktype(L, 1, Collider);
bool continuous = lovrColliderIsContinuous(collider); bool continuous = lovrColliderIsContinuous(collider);
@ -544,6 +589,16 @@ static int l_lovrColliderSetTag(lua_State* L) {
return 0; return 0;
} }
// Deprecated
static int l_lovrColliderGetShapes(lua_State* L) {
Collider* collider = luax_checktype(L, 1, Collider);
Shape* shape = lovrColliderGetShape(collider, ~0u);
lua_createtable(L, 1, 0);
luax_pushshape(L, shape);
lua_rawseti(L, -2, 1);
return 1;
}
// Deprecated // Deprecated
static int l_lovrColliderIsGravityIgnored(lua_State* L) { static int l_lovrColliderIsGravityIgnored(lua_State* L) {
Collider* collider = luax_checktype(L, 1, Collider); Collider* collider = luax_checktype(L, 1, Collider);
@ -562,15 +617,20 @@ static int l_lovrColliderSetGravityIgnored(lua_State* L) {
const luaL_Reg lovrCollider[] = { const luaL_Reg lovrCollider[] = {
{ "destroy", l_lovrColliderDestroy }, { "destroy", l_lovrColliderDestroy },
{ "isDestroyed", l_lovrColliderIsDestroyed }, { "isDestroyed", l_lovrColliderIsDestroyed },
{ "isEnabled", l_lovrColliderIsEnabled },
{ "setEnabled", l_lovrColliderSetEnabled },
{ "getWorld", l_lovrColliderGetWorld }, { "getWorld", l_lovrColliderGetWorld },
{ "addShape", l_lovrColliderAddShape }, { "getShape", l_lovrColliderGetShape },
{ "removeShape", l_lovrColliderRemoveShape }, { "setShape", l_lovrColliderSetShape },
{ "getShapes", l_lovrColliderGetShapes }, { "getShapeOffset", l_lovrColliderGetShapeOffset },
{ "setShapeOffset", l_lovrColliderSetShapeOffset },
{ "getJoints", l_lovrColliderGetJoints }, { "getJoints", l_lovrColliderGetJoints },
{ "getUserData", l_lovrColliderGetUserData }, { "getUserData", l_lovrColliderGetUserData },
{ "setUserData", l_lovrColliderSetUserData }, { "setUserData", l_lovrColliderSetUserData },
{ "isKinematic", l_lovrColliderIsKinematic }, { "isKinematic", l_lovrColliderIsKinematic },
{ "setKinematic", l_lovrColliderSetKinematic }, { "setKinematic", l_lovrColliderSetKinematic },
{ "isSensor", l_lovrColliderIsSensor },
{ "setSensor", l_lovrColliderSetSensor },
{ "isContinuous", l_lovrColliderIsContinuous }, { "isContinuous", l_lovrColliderIsContinuous },
{ "setContinuous", l_lovrColliderSetContinuous }, { "setContinuous", l_lovrColliderSetContinuous },
{ "getGravityScale", l_lovrColliderGetGravityScale }, { "getGravityScale", l_lovrColliderGetGravityScale },
@ -617,6 +677,7 @@ const luaL_Reg lovrCollider[] = {
{ "setTag", l_lovrColliderSetTag }, { "setTag", l_lovrColliderSetTag },
// Deprecated // Deprecated
{ "getShapes", l_lovrColliderGetShapes },
{ "isGravityIgnored", l_lovrColliderIsGravityIgnored }, { "isGravityIgnored", l_lovrColliderIsGravityIgnored },
{ "setGravityIgnored", l_lovrColliderSetGravityIgnored }, { "setGravityIgnored", l_lovrColliderSetGravityIgnored },

View File

@ -14,6 +14,7 @@ void luax_pushshape(lua_State* L, Shape* shape) {
case SHAPE_CYLINDER: luax_pushtype(L, CylinderShape, shape); break; case SHAPE_CYLINDER: luax_pushtype(L, CylinderShape, shape); break;
case SHAPE_MESH: luax_pushtype(L, MeshShape, shape); break; case SHAPE_MESH: luax_pushtype(L, MeshShape, shape); break;
case SHAPE_TERRAIN: luax_pushtype(L, TerrainShape, shape); break; case SHAPE_TERRAIN: luax_pushtype(L, TerrainShape, shape); break;
case SHAPE_COMPOUND: luax_pushtype(L, CompoundShape, shape); break;
default: lovrUnreachable(); default: lovrUnreachable();
} }
} }
@ -28,7 +29,8 @@ Shape* luax_checkshape(lua_State* L, int index) {
hash64("CapsuleShape", strlen("CapsuleShape")), hash64("CapsuleShape", strlen("CapsuleShape")),
hash64("CylinderShape", strlen("CylinderShape")), hash64("CylinderShape", strlen("CylinderShape")),
hash64("MeshShape", strlen("MeshShape")), 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++) { for (size_t i = 0; i < COUNTOF(hashes); i++) {
@ -135,6 +137,85 @@ Shape* luax_newterrainshape(lua_State* L, int index) {
} }
} }
Shape* luax_newcompoundshape(lua_State* L, int index) {
if (lua_isnoneornil(L, index)) {
return lovrCompoundShapeCreate(NULL, NULL, NULL, 0, false);
}
luaL_checktype(L, index, LUA_TTABLE);
int length = luax_len(L, index);
uint32_t defer = lovrDeferPush();
Shape** shapes = lovrMalloc(length * sizeof(Shape*));
float* positions = lovrMalloc(length * 3 * sizeof(float));
float* orientations = lovrMalloc(length * 4 * sizeof(float));
lovrDefer(lovrFree, shapes);
lovrDefer(lovrFree, positions);
lovrDefer(lovrFree, orientations);
for (int i = 0; i < length; i++) {
lua_rawgeti(L, index, i + 1);
lovrCheck(lua_istable(L, -1), "Expected table of tables for compound shape");
lua_rawgeti(L, -1, 1);
shapes[i] = luax_checkshape(L, -1);
lua_pop(L, 1);
int index = 2;
lua_rawgeti(L, -1, index);
switch (lua_type(L, -1)) {
case LUA_TNIL:
vec3_set(&positions[3 * i], 0.f, 0.f, 0.f);
lua_pop(L, 1);
break;
case LUA_TNUMBER:
lua_rawgeti(L, -2, index + 1);
lua_rawgeti(L, -3, index + 2);
vec3_set(&positions[3 * i], luax_tofloat(L, -3), luax_tofloat(L, -2), luax_tofloat(L, -1));
lua_pop(L, 3);
index += 3;
break;
default: {
float* v = luax_checkvector(L, -1, V_VEC3, "nil, number, or vec3");
vec3_init(&positions[3 * i], v);
lua_pop(L, 1);
break;
}
}
lua_rawgeti(L, -1, index);
switch (lua_type(L, -1)) {
case LUA_TNIL:
quat_identity(&orientations[4 * i]);
lua_pop(L, 1);
break;
case LUA_TNUMBER:
lua_rawgeti(L, -2, index);
lua_rawgeti(L, -3, index);
lua_rawgeti(L, -4, index);
quat_set(&orientations[4 * i], luax_tofloat(L, -4), luax_tofloat(L, -3), luax_tofloat(L, -2), luax_tofloat(L, -1));
lua_pop(L, 4);
break;
default: {
float* q = luax_checkvector(L, -1, V_QUAT, "nil, number, or quat");
quat_init(&positions[4 * i], q);
lua_pop(L, 1);
break;
}
}
lua_pop(L, 1);
}
lua_getfield(L, index, "freeze");
bool freeze = lua_toboolean(L, -1);
lua_pop(L, 1);
CompoundShape* shape = lovrCompoundShapeCreate(shapes, positions, orientations, length, freeze);
lovrDeferPop(defer);
return shape;
}
static int l_lovrShapeDestroy(lua_State* L) { static int l_lovrShapeDestroy(lua_State* L) {
Shape* shape = luax_checkshape(L, 1); Shape* shape = luax_checkshape(L, 1);
lovrShapeDestroyData(shape); lovrShapeDestroyData(shape);
@ -147,38 +228,6 @@ static int l_lovrShapeGetType(lua_State* L) {
return 1; 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));
return 1;
}
static int l_lovrShapeSetEnabled(lua_State* L) {
Shape* shape = luax_checkshape(L, 1);
bool enabled = lua_toboolean(L, 2);
lovrShapeSetEnabled(shape, enabled);
return 0;
}
static int l_lovrShapeIsSensor(lua_State* L) {
Shape* shape = luax_checkshape(L, 1);
lua_pushboolean(L, lovrShapeIsSensor(shape));
return 1;
}
static int l_lovrShapeSetSensor(lua_State* L) {
Shape* shape = luax_checkshape(L, 1);
bool sensor = lua_toboolean(L, 2);
lovrShapeSetSensor(shape, sensor);
return 0;
}
static void luax_pushshapestash(lua_State* L) { static void luax_pushshapestash(lua_State* L) {
lua_getfield(L, LUA_REGISTRYINDEX, "_lovrshapestash"); lua_getfield(L, LUA_REGISTRYINDEX, "_lovrshapestash");
@ -214,74 +263,6 @@ static int l_lovrShapeSetUserData(lua_State* L) {
return 0; 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) { static int l_lovrShapeGetMass(lua_State* L) {
Shape* shape = luax_checkshape(L, 1); Shape* shape = luax_checkshape(L, 1);
float density = luax_checkfloat(L, 2); float density = luax_checkfloat(L, 2);
@ -302,8 +283,15 @@ static int l_lovrShapeGetMass(lua_State* L) {
static int l_lovrShapeGetAABB(lua_State* L) { static int l_lovrShapeGetAABB(lua_State* L) {
Shape* shape = luax_checkshape(L, 1); Shape* shape = luax_checkshape(L, 1);
float aabb[6]; float position[3], orientation[4], aabb[6];
lovrShapeGetAABB(shape, aabb); if (lua_gettop(L) >= 2) {
int index = 2;
index = luax_readvec3(L, index, position, NULL);
index = luax_readquat(L, index, orientation, NULL);
lovrShapeGetAABB(shape, position, orientation, aabb);
} else {
lovrShapeGetAABB(shape, NULL, NULL, aabb);
}
for (int i = 0; i < 6; i++) { for (int i = 0; i < 6; i++) {
lua_pushnumber(L, aabb[i]); lua_pushnumber(L, aabb[i]);
} }
@ -313,19 +301,8 @@ static int l_lovrShapeGetAABB(lua_State* L) {
#define lovrShape \ #define lovrShape \
{ "destroy", l_lovrShapeDestroy }, \ { "destroy", l_lovrShapeDestroy }, \
{ "getType", l_lovrShapeGetType }, \ { "getType", l_lovrShapeGetType }, \
{ "getCollider", l_lovrShapeGetCollider }, \
{ "isEnabled", l_lovrShapeIsEnabled }, \
{ "setEnabled", l_lovrShapeSetEnabled }, \
{ "isSensor", l_lovrShapeIsSensor }, \
{ "setSensor", l_lovrShapeSetSensor }, \
{ "getUserData", l_lovrShapeGetUserData }, \ { "getUserData", l_lovrShapeGetUserData }, \
{ "setUserData", l_lovrShapeSetUserData }, \ { "setUserData", l_lovrShapeSetUserData }, \
{ "getPosition", l_lovrShapeGetPosition }, \
{ "setPosition", l_lovrShapeSetPosition }, \
{ "getOrientation", l_lovrShapeGetOrientation }, \
{ "setOrientation", l_lovrShapeSetOrientation }, \
{ "getPose", l_lovrShapeGetPose }, \
{ "setPose", l_lovrShapeSetPose }, \
{ "getMass", l_lovrShapeGetMass }, \ { "getMass", l_lovrShapeGetMass }, \
{ "getAABB", l_lovrShapeGetAABB } { "getAABB", l_lovrShapeGetAABB }
@ -335,17 +312,9 @@ static int l_lovrSphereShapeGetRadius(lua_State* L) {
return 1; 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[] = { const luaL_Reg lovrSphereShape[] = {
lovrShape, lovrShape,
{ "getRadius", l_lovrSphereShapeGetRadius }, { "getRadius", l_lovrSphereShapeGetRadius },
{ "setRadius", l_lovrSphereShapeSetRadius },
{ NULL, NULL } { NULL, NULL }
}; };
@ -359,18 +328,9 @@ static int l_lovrBoxShapeGetDimensions(lua_State* L) {
return 3; 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[] = { const luaL_Reg lovrBoxShape[] = {
lovrShape, lovrShape,
{ "getDimensions", l_lovrBoxShapeGetDimensions }, { "getDimensions", l_lovrBoxShapeGetDimensions },
{ "setDimensions", l_lovrBoxShapeSetDimensions },
{ NULL, NULL } { NULL, NULL }
}; };
@ -380,32 +340,16 @@ static int l_lovrCapsuleShapeGetRadius(lua_State* L) {
return 1; 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) { static int l_lovrCapsuleShapeGetLength(lua_State* L) {
CapsuleShape* capsule = luax_checktype(L, 1, CapsuleShape); CapsuleShape* capsule = luax_checktype(L, 1, CapsuleShape);
lua_pushnumber(L, lovrCapsuleShapeGetLength(capsule)); lua_pushnumber(L, lovrCapsuleShapeGetLength(capsule));
return 1; 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[] = { const luaL_Reg lovrCapsuleShape[] = {
lovrShape, lovrShape,
{ "getRadius", l_lovrCapsuleShapeGetRadius }, { "getRadius", l_lovrCapsuleShapeGetRadius },
{ "setRadius", l_lovrCapsuleShapeSetRadius },
{ "getLength", l_lovrCapsuleShapeGetLength }, { "getLength", l_lovrCapsuleShapeGetLength },
{ "setLength", l_lovrCapsuleShapeSetLength },
{ NULL, NULL } { NULL, NULL }
}; };
@ -415,32 +359,16 @@ static int l_lovrCylinderShapeGetRadius(lua_State* L) {
return 1; 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) { static int l_lovrCylinderShapeGetLength(lua_State* L) {
CylinderShape* cylinder = luax_checktype(L, 1, CylinderShape); CylinderShape* cylinder = luax_checktype(L, 1, CylinderShape);
lua_pushnumber(L, lovrCylinderShapeGetLength(cylinder)); lua_pushnumber(L, lovrCylinderShapeGetLength(cylinder));
return 1; 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[] = { const luaL_Reg lovrCylinderShape[] = {
lovrShape, lovrShape,
{ "getRadius", l_lovrCylinderShapeGetRadius }, { "getRadius", l_lovrCylinderShapeGetRadius },
{ "setRadius", l_lovrCylinderShapeSetRadius },
{ "getLength", l_lovrCylinderShapeGetLength }, { "getLength", l_lovrCylinderShapeGetLength },
{ "setLength", l_lovrCylinderShapeSetLength },
{ NULL, NULL } { NULL, NULL }
}; };
@ -453,3 +381,109 @@ const luaL_Reg lovrTerrainShape[] = {
lovrShape, lovrShape,
{ NULL, NULL } { NULL, NULL }
}; };
static int l_lovrCompoundShapeIsFrozen(lua_State* L) {
CompoundShape* shape = luax_checktype(L, 1, CompoundShape);
bool frozen = lovrCompoundShapeIsFrozen(shape);
lua_pushboolean(L, frozen);
return 1;
}
static int l_lovrCompoundShapeAddChild(lua_State* L) {
CompoundShape* shape = luax_checktype(L, 1, CompoundShape);
Shape* child = luax_checkshape(L, 2);
float position[3], orientation[4];
int index = 3;
index = luax_readvec3(L, index, position, NULL);
index = luax_readquat(L, index, orientation, NULL);
lovrCompoundShapeAddChild(shape, child, position, orientation);
return 0;
}
static int l_lovrCompoundShapeReplaceChild(lua_State* L) {
CompoundShape* shape = luax_checktype(L, 1, CompoundShape);
uint32_t index = luax_checku32(L, 2) - 1;
Shape* child = luax_checkshape(L, 3);
float position[3], orientation[4];
int i = 4;
i = luax_readvec3(L, i, position, NULL);
i = luax_readquat(L, i, orientation, NULL);
lovrCompoundShapeReplaceChild(shape, index, child, position, orientation);
return 0;
}
static int l_lovrCompoundShapeRemoveChild(lua_State* L) {
CompoundShape* shape = luax_checktype(L, 1, CompoundShape);
uint32_t index = luax_checku32(L, 2) - 1;
lovrCompoundShapeRemoveChild(shape, index);
return 0;
}
static int l_lovrCompoundShapeGetChild(lua_State* L) {
CompoundShape* shape = luax_checktype(L, 1, CompoundShape);
uint32_t index = luax_checku32(L, 2) - 1;
Shape* child = lovrCompoundShapeGetChild(shape, index);
luax_pushshape(L, child);
return 1;
}
static int l_lovrCompoundShapeGetChildren(lua_State* L) {
CompoundShape* shape = luax_checktype(L, 1, CompoundShape);
int count = (int) lovrCompoundShapeGetChildCount(shape);
lua_createtable(L, count, 0);
for (int i = 0; i < count; i++) {
Shape* child = lovrCompoundShapeGetChild(shape, (uint32_t) i);
luax_pushshape(L, child);
lua_rawseti(L, -2, i + 1);
}
return 1;
}
static int l_lovrCompoundShapeGetChildCount(lua_State* L) {
CompoundShape* shape = luax_checktype(L, 1, CompoundShape);
uint32_t count = lovrCompoundShapeGetChildCount(shape);
lua_pushinteger(L, count);
return 1;
}
static int l_lovrCompoundShapeGetChildOffset(lua_State* L) {
CompoundShape* shape = luax_checktype(L, 1, CompoundShape);
uint32_t index = luax_checku32(L, 2) - 1;
float position[3], orientation[4], angle, ax, ay, az;
lovrCompoundShapeGetChildOffset(shape, index, position, orientation);
quat_getAngleAxis(orientation, &angle, &ax, &ay, &az);
lua_pushnumber(L, position[0]);
lua_pushnumber(L, position[1]);
lua_pushnumber(L, position[2]);
lua_pushnumber(L, angle);
lua_pushnumber(L, ax);
lua_pushnumber(L, ay);
lua_pushnumber(L, az);
return 7;
}
static int l_lovrCompoundShapeSetChildOffset(lua_State* L) {
CompoundShape* shape = luax_checktype(L, 1, CompoundShape);
uint32_t index = luax_checku32(L, 2) - 1;
float position[3], orientation[4];
int i = 3;
i = luax_readvec3(L, i, position, NULL);
i = luax_readquat(L, i, orientation, NULL);
lovrCompoundShapeSetChildOffset(shape, index, position, orientation);
return 0;
}
const luaL_Reg lovrCompoundShape[] = {
lovrShape,
{ "isFrozen", l_lovrCompoundShapeIsFrozen },
{ "addChild", l_lovrCompoundShapeAddChild },
{ "replaceChild", l_lovrCompoundShapeReplaceChild },
{ "removeChild", l_lovrCompoundShapeRemoveChild },
{ "getChild", l_lovrCompoundShapeGetChild },
{ "getChildren", l_lovrCompoundShapeGetChildren },
{ "getChildCount", l_lovrCompoundShapeGetChildCount },
{ "getChildOffset", l_lovrCompoundShapeGetChildOffset },
{ "setChildOffset", l_lovrCompoundShapeSetChildOffset },
{ "__len", l_lovrCompoundShapeGetChildCount }, // :)
{ NULL, NULL }
};

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, float position[3], float normal[3], uint32_t shape, void* userdata) {
lua_State* L = userdata; lua_State* L = userdata;
lua_pushvalue(L, -1); lua_pushvalue(L, -1);
luax_pushshape(L, shape); luax_pushtype(L, Collider, collider);
lua_pushnumber(L, x); lua_pushnumber(L, position[0]);
lua_pushnumber(L, y); lua_pushnumber(L, position[1]);
lua_pushnumber(L, z); lua_pushnumber(L, position[2]);
lua_pushnumber(L, nx); lua_pushnumber(L, normal[0]);
lua_pushnumber(L, ny); lua_pushnumber(L, normal[1]);
lua_pushnumber(L, nz); lua_pushnumber(L, normal[2]);
lua_call(L, 7, 1); lua_pushinteger(L, shape + 1);
lua_call(L, 8, 1);
bool shouldStop = lua_type(L, -1) == LUA_TBOOLEAN && !lua_toboolean(L, -1); bool shouldStop = lua_type(L, -1) == LUA_TBOOLEAN && !lua_toboolean(L, -1);
lua_pop(L, 1); lua_pop(L, 1);
return shouldStop; return shouldStop;
@ -45,53 +46,55 @@ static bool raycastCallback(Shape* shape, float x, float y, float z, float nx, f
typedef struct { typedef struct {
const char* tag; const char* tag;
Shape* shape; Collider* collider;
uint32_t shape;
float distance; float distance;
float origin[3]; float origin[3];
float position[3]; float position[3];
float normal[3]; float normal[3];
} RaycastData; } 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, float position[3], float normal[3], uint32_t shape, void* userdata) {
RaycastData* data = userdata; RaycastData* data = userdata;
if (data->tag) { if (data->tag) {
const char* tag = lovrColliderGetTag(lovrShapeGetCollider(shape)); const char* tag = lovrColliderGetTag(collider);
if (!tag || strcmp(tag, data->tag)) { if (!tag || strcmp(tag, data->tag)) {
return false; return false;
} }
} }
data->collider = collider;
data->shape = shape; data->shape = shape;
vec3_set(data->position, x, y, z); vec3_init(data->position, position);
vec3_set(data->normal, nx, ny, nz); vec3_init(data->normal, normal);
data->distance = vec3_distance(data->origin, data->position); data->distance = vec3_distance(data->origin, data->position);
return true; 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, float position[3], float normal[3], uint32_t shape, void* userdata) {
RaycastData* data = userdata; RaycastData* data = userdata;
if (data->tag) { if (data->tag) {
const char* tag = lovrColliderGetTag(lovrShapeGetCollider(shape)); const char* tag = lovrColliderGetTag(collider);
if (!tag || strcmp(tag, data->tag)) { if (!tag || strcmp(tag, data->tag)) {
return false; return false;
} }
} }
float position[3];
vec3_set(position, x, y, z);
float distance = vec3_distance(data->origin, position); float distance = vec3_distance(data->origin, position);
if (distance < data->distance) { if (distance < data->distance) {
vec3_init(data->position, position); vec3_init(data->position, position);
vec3_set(data->normal, nx, ny, nz); vec3_init(data->normal, normal);
data->distance = distance; data->distance = distance;
data->collider = collider;
data->shape = shape; data->shape = shape;
} }
return false; return false;
} }
static bool queryCallback(Shape* shape, void* userdata) { static bool queryCallback(Collider* collider, uint32_t shape, void* userdata) {
lua_State* L = userdata; lua_State* L = userdata;
lua_pushvalue(L, -1); lua_pushvalue(L, -1);
luax_pushshape(L, shape); luax_pushtype(L, Collider, collider);
lua_call(L, 1, 1); lua_pushinteger(L, shape + 1);
lua_call(L, 2, 1);
bool shouldStop = lua_type(L, -1) == LUA_TBOOLEAN && !lua_toboolean(L, -1); bool shouldStop = lua_type(L, -1) == LUA_TBOOLEAN && !lua_toboolean(L, -1);
lua_pop(L, 1); lua_pop(L, 1);
return shouldStop; return shouldStop;
@ -99,9 +102,10 @@ static bool queryCallback(Shape* shape, void* userdata) {
static int l_lovrWorldNewCollider(lua_State* L) { static int l_lovrWorldNewCollider(lua_State* L) {
World* world = luax_checktype(L, 1, World); World* world = luax_checktype(L, 1, World);
Shape* shape = luax_totype(L, 2, Shape);
float position[3]; float position[3];
luax_readvec3(L, 2, position, NULL); luax_readvec3(L, 2 + !!shape, position, NULL);
Collider* collider = lovrColliderCreate(world, position[0], position[1], position[2]); Collider* collider = lovrColliderCreate(world, shape, position[0], position[1], position[2]);
luax_pushtype(L, Collider, collider); luax_pushtype(L, Collider, collider);
lovrRelease(collider, lovrColliderDestroy); lovrRelease(collider, lovrColliderDestroy);
return 1; return 1;
@ -111,9 +115,8 @@ static int l_lovrWorldNewBoxCollider(lua_State* L) {
World* world = luax_checktype(L, 1, World); World* world = luax_checktype(L, 1, World);
float position[3]; float position[3];
int index = luax_readvec3(L, 2, position, NULL); int index = luax_readvec3(L, 2, position, NULL);
Collider* collider = lovrColliderCreate(world, position[0], position[1], position[2]);
BoxShape* shape = luax_newboxshape(L, index); BoxShape* shape = luax_newboxshape(L, index);
lovrColliderAddShape(collider, shape); Collider* collider = lovrColliderCreate(world, shape, position[0], position[1], position[2]);
lovrColliderInitInertia(collider, shape); lovrColliderInitInertia(collider, shape);
luax_pushtype(L, Collider, collider); luax_pushtype(L, Collider, collider);
lovrRelease(collider, lovrColliderDestroy); lovrRelease(collider, lovrColliderDestroy);
@ -125,9 +128,8 @@ static int l_lovrWorldNewCapsuleCollider(lua_State* L) {
World* world = luax_checktype(L, 1, World); World* world = luax_checktype(L, 1, World);
float position[3]; float position[3];
int index = luax_readvec3(L, 2, position, NULL); int index = luax_readvec3(L, 2, position, NULL);
Collider* collider = lovrColliderCreate(world, position[0], position[1], position[2]);
CapsuleShape* shape = luax_newcapsuleshape(L, index); CapsuleShape* shape = luax_newcapsuleshape(L, index);
lovrColliderAddShape(collider, shape); Collider* collider = lovrColliderCreate(world, shape, position[0], position[1], position[2]);
lovrColliderInitInertia(collider, shape); lovrColliderInitInertia(collider, shape);
luax_pushtype(L, Collider, collider); luax_pushtype(L, Collider, collider);
lovrRelease(collider, lovrColliderDestroy); lovrRelease(collider, lovrColliderDestroy);
@ -139,9 +141,8 @@ static int l_lovrWorldNewCylinderCollider(lua_State* L) {
World* world = luax_checktype(L, 1, World); World* world = luax_checktype(L, 1, World);
float position[3]; float position[3];
int index = luax_readvec3(L, 2, position, NULL); int index = luax_readvec3(L, 2, position, NULL);
Collider* collider = lovrColliderCreate(world, position[0], position[1], position[2]);
CylinderShape* shape = luax_newcylindershape(L, index); CylinderShape* shape = luax_newcylindershape(L, index);
lovrColliderAddShape(collider, shape); Collider* collider = lovrColliderCreate(world, shape, position[0], position[1], position[2]);
lovrColliderInitInertia(collider, shape); lovrColliderInitInertia(collider, shape);
luax_pushtype(L, Collider, collider); luax_pushtype(L, Collider, collider);
lovrRelease(collider, lovrColliderDestroy); lovrRelease(collider, lovrColliderDestroy);
@ -153,9 +154,8 @@ static int l_lovrWorldNewSphereCollider(lua_State* L) {
World* world = luax_checktype(L, 1, World); World* world = luax_checktype(L, 1, World);
float position[3]; float position[3];
int index = luax_readvec3(L, 2, position, NULL); int index = luax_readvec3(L, 2, position, NULL);
Collider* collider = lovrColliderCreate(world, position[0], position[1], position[2]);
SphereShape* shape = luax_newsphereshape(L, index); SphereShape* shape = luax_newsphereshape(L, index);
lovrColliderAddShape(collider, shape); Collider* collider = lovrColliderCreate(world, shape, position[0], position[1], position[2]);
lovrColliderInitInertia(collider, shape); lovrColliderInitInertia(collider, shape);
luax_pushtype(L, Collider, collider); luax_pushtype(L, Collider, collider);
lovrRelease(collider, lovrColliderDestroy); lovrRelease(collider, lovrColliderDestroy);
@ -165,9 +165,8 @@ static int l_lovrWorldNewSphereCollider(lua_State* L) {
static int l_lovrWorldNewMeshCollider(lua_State* L) { static int l_lovrWorldNewMeshCollider(lua_State* L) {
World* world = luax_checktype(L, 1, World); World* world = luax_checktype(L, 1, World);
Collider* collider = lovrColliderCreate(world, 0.f, 0.f, 0.f);
MeshShape* shape = luax_newmeshshape(L, 2); MeshShape* shape = luax_newmeshshape(L, 2);
lovrColliderAddShape(collider, shape); Collider* collider = lovrColliderCreate(world, shape, 0.f, 0.f, 0.f);
lovrColliderInitInertia(collider, shape); lovrColliderInitInertia(collider, shape);
luax_pushtype(L, Collider, collider); luax_pushtype(L, Collider, collider);
lovrRelease(collider, lovrColliderDestroy); lovrRelease(collider, lovrColliderDestroy);
@ -177,9 +176,8 @@ static int l_lovrWorldNewMeshCollider(lua_State* L) {
static int l_lovrWorldNewTerrainCollider(lua_State* L) { static int l_lovrWorldNewTerrainCollider(lua_State* L) {
World* world = luax_checktype(L, 1, World); World* world = luax_checktype(L, 1, World);
Collider* collider = lovrColliderCreate(world, 0.f, 0.f, 0.f);
TerrainShape* shape = luax_newterrainshape(L, 2); TerrainShape* shape = luax_newterrainshape(L, 2);
lovrColliderAddShape(collider, shape); Collider* collider = lovrColliderCreate(world, shape, 0.f, 0.f, 0.f);
lovrColliderSetKinematic(collider, true); lovrColliderSetKinematic(collider, true);
luax_pushtype(L, Collider, collider); luax_pushtype(L, Collider, collider);
lovrRelease(collider, lovrColliderDestroy); lovrRelease(collider, lovrColliderDestroy);
@ -309,15 +307,16 @@ static int l_lovrWorldRaycastAny(lua_State* L) {
RaycastData data = { 0 }; RaycastData data = { 0 };
data.tag = lua_tostring(L, index); data.tag = lua_tostring(L, index);
lovrWorldRaycast(world, start[0], start[1], start[2], end[0], end[1], end[2], raycastAnyCallback, &data); lovrWorldRaycast(world, start[0], start[1], start[2], end[0], end[1], end[2], raycastAnyCallback, &data);
if (data.shape) { if (data.collider) {
luax_pushshape(L, data.shape); luax_pushtype(L, Collider, data.collider);
lua_pushnumber(L, data.position[0]); lua_pushnumber(L, data.position[0]);
lua_pushnumber(L, data.position[1]); lua_pushnumber(L, data.position[1]);
lua_pushnumber(L, data.position[2]); lua_pushnumber(L, data.position[2]);
lua_pushnumber(L, data.normal[0]); lua_pushnumber(L, data.normal[0]);
lua_pushnumber(L, data.normal[1]); lua_pushnumber(L, data.normal[1]);
lua_pushnumber(L, data.normal[2]); lua_pushnumber(L, data.normal[2]);
return 7; lua_pushinteger(L, data.shape + 1);
return 8;
} else { } else {
lua_pushnil(L); lua_pushnil(L);
return 1; return 1;
@ -334,14 +333,15 @@ static int l_lovrWorldRaycastClosest(lua_State* L) {
data.tag = lua_tostring(L, index); data.tag = lua_tostring(L, index);
lovrWorldRaycast(world, start[0], start[1], start[2], end[0], end[1], end[2], raycastClosestCallback, &data); lovrWorldRaycast(world, start[0], start[1], start[2], end[0], end[1], end[2], raycastClosestCallback, &data);
if (data.shape) { if (data.shape) {
luax_pushshape(L, data.shape); luax_pushtype(L, Collider, data.collider);
lua_pushnumber(L, data.position[0]); lua_pushnumber(L, data.position[0]);
lua_pushnumber(L, data.position[1]); lua_pushnumber(L, data.position[1]);
lua_pushnumber(L, data.position[2]); lua_pushnumber(L, data.position[2]);
lua_pushnumber(L, data.normal[0]); lua_pushnumber(L, data.normal[0]);
lua_pushnumber(L, data.normal[1]); lua_pushnumber(L, data.normal[1]);
lua_pushnumber(L, data.normal[2]); lua_pushnumber(L, data.normal[2]);
return 7; lua_pushinteger(L, data.shape + 1);
return 8;
} else { } else {
lua_pushnil(L); lua_pushnil(L);
return 1; return 1;

View File

@ -19,6 +19,7 @@ typedef Shape CapsuleShape;
typedef Shape CylinderShape; typedef Shape CylinderShape;
typedef Shape MeshShape; typedef Shape MeshShape;
typedef Shape TerrainShape; typedef Shape TerrainShape;
typedef Shape CompoundShape;
typedef Joint BallJoint; typedef Joint BallJoint;
typedef Joint DistanceJoint; typedef Joint DistanceJoint;
@ -26,8 +27,8 @@ typedef Joint HingeJoint;
typedef Joint SliderJoint; typedef Joint SliderJoint;
typedef void (*CollisionResolver)(World* world, void* userdata); 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 (*RaycastCallback)(Collider* collider, float position[3], float normal[3], uint32_t child, void* userdata);
typedef bool (*QueryCallback)(Shape* shape, void* userdata); typedef bool (*QueryCallback)(Collider* collider, uint32_t child, void* userdata);
bool lovrPhysicsInit(void); bool lovrPhysicsInit(void);
void lovrPhysicsDestroy(void); void lovrPhysicsDestroy(void);
@ -85,16 +86,19 @@ void lovrWorldSetSleepingAllowed(World* world, bool allowed);
// Collider // 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 lovrColliderDestroy(void* ref);
void lovrColliderDestroyData(Collider* collider); void lovrColliderDestroyData(Collider* collider);
bool lovrColliderIsDestroyed(Collider* collider); bool lovrColliderIsDestroyed(Collider* collider);
bool lovrColliderIsEnabled(Collider* collider);
void lovrColliderSetEnabled(Collider* collider, bool enable);
void lovrColliderInitInertia(Collider* collider, Shape* shape); void lovrColliderInitInertia(Collider* collider, Shape* shape);
World* lovrColliderGetWorld(Collider* collider); World* lovrColliderGetWorld(Collider* collider);
Collider* lovrColliderGetNext(Collider* collider); Collider* lovrColliderGetNext(Collider* collider);
void lovrColliderAddShape(Collider* collider, Shape* shape); Shape* lovrColliderGetShape(Collider* collider, uint32_t child);
void lovrColliderRemoveShape(Collider* collider, Shape* shape); void lovrColliderSetShape(Collider* collider, Shape* shape);
Shape** lovrColliderGetShapes(Collider* collider, size_t* count); void lovrColliderGetShapeOffset(Collider* collider, float* position, float* orientation);
void lovrColliderSetShapeOffset(Collider* collider, float* position, float* orientation);
Joint** lovrColliderGetJoints(Collider* collider, size_t* count); Joint** lovrColliderGetJoints(Collider* collider, size_t* count);
const char* lovrColliderGetTag(Collider* collider); const char* lovrColliderGetTag(Collider* collider);
bool lovrColliderSetTag(Collider* collider, const char* tag); bool lovrColliderSetTag(Collider* collider, const char* tag);
@ -104,6 +108,8 @@ float lovrColliderGetRestitution(Collider* collider);
void lovrColliderSetRestitution(Collider* collider, float restitution); void lovrColliderSetRestitution(Collider* collider, float restitution);
bool lovrColliderIsKinematic(Collider* collider); bool lovrColliderIsKinematic(Collider* collider);
void lovrColliderSetKinematic(Collider* collider, bool kinematic); void lovrColliderSetKinematic(Collider* collider, bool kinematic);
bool lovrColliderIsSensor(Collider* collider);
void lovrColliderSetSensor(Collider* collider, bool sensor);
bool lovrColliderIsContinuous(Collider* collider); bool lovrColliderIsContinuous(Collider* collider);
void lovrColliderSetContinuous(Collider* collider, bool continuous); void lovrColliderSetContinuous(Collider* collider, bool continuous);
float lovrColliderGetGravityScale(Collider* collider); float lovrColliderGetGravityScale(Collider* collider);
@ -151,48 +157,44 @@ typedef enum {
SHAPE_CAPSULE, SHAPE_CAPSULE,
SHAPE_CYLINDER, SHAPE_CYLINDER,
SHAPE_MESH, SHAPE_MESH,
SHAPE_TERRAIN SHAPE_TERRAIN,
SHAPE_COMPOUND
} ShapeType; } ShapeType;
void lovrShapeDestroy(void* ref); void lovrShapeDestroy(void* ref);
void lovrShapeDestroyData(Shape* shape); void lovrShapeDestroyData(Shape* shape);
ShapeType lovrShapeGetType(Shape* shape); ShapeType lovrShapeGetType(Shape* shape);
Collider* lovrShapeGetCollider(Shape* shape);
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 lovrShapeGetMass(Shape* shape, float density, float* cx, float* cy, float* cz, float* mass, float inertia[6]);
void lovrShapeGetAABB(Shape* shape, float aabb[6]); void lovrShapeGetAABB(Shape* shape, float position[3], float orientation[4], float aabb[6]);
SphereShape* lovrSphereShapeCreate(float radius); SphereShape* lovrSphereShapeCreate(float radius);
float lovrSphereShapeGetRadius(SphereShape* sphere); float lovrSphereShapeGetRadius(SphereShape* sphere);
void lovrSphereShapeSetRadius(SphereShape* sphere, float radius);
BoxShape* lovrBoxShapeCreate(float w, float h, float d); BoxShape* lovrBoxShapeCreate(float w, float h, float d);
void lovrBoxShapeGetDimensions(BoxShape* box, 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); CapsuleShape* lovrCapsuleShapeCreate(float radius, float length);
float lovrCapsuleShapeGetRadius(CapsuleShape* capsule); float lovrCapsuleShapeGetRadius(CapsuleShape* capsule);
void lovrCapsuleShapeSetRadius(CapsuleShape* capsule, float radius);
float lovrCapsuleShapeGetLength(CapsuleShape* capsule); float lovrCapsuleShapeGetLength(CapsuleShape* capsule);
void lovrCapsuleShapeSetLength(CapsuleShape* capsule, float length);
CylinderShape* lovrCylinderShapeCreate(float radius, float length); CylinderShape* lovrCylinderShapeCreate(float radius, float length);
float lovrCylinderShapeGetRadius(CylinderShape* cylinder); float lovrCylinderShapeGetRadius(CylinderShape* cylinder);
void lovrCylinderShapeSetRadius(CylinderShape* cylinder, float radius);
float lovrCylinderShapeGetLength(CylinderShape* cylinder); float lovrCylinderShapeGetLength(CylinderShape* cylinder);
void lovrCylinderShapeSetLength(CylinderShape* cylinder, float length);
MeshShape* lovrMeshShapeCreate(int vertexCount, float vertices[], int indexCount, uint32_t indices[]); MeshShape* lovrMeshShapeCreate(int vertexCount, float vertices[], int indexCount, uint32_t indices[]);
TerrainShape* lovrTerrainShapeCreate(float* vertices, uint32_t n, float scaleXZ, float scaleY); TerrainShape* lovrTerrainShapeCreate(float* vertices, uint32_t n, float scaleXZ, float scaleY);
CompoundShape* lovrCompoundShapeCreate(Shape** shapes, float* positions, float* orientations, uint32_t count, bool freeze);
bool lovrCompoundShapeIsFrozen(CompoundShape* shape);
void lovrCompoundShapeAddChild(CompoundShape* shape, Shape* child, float* position, float* orientation);
void lovrCompoundShapeReplaceChild(CompoundShape* shape, uint32_t index, Shape* child, float* position, float* orientation);
void lovrCompoundShapeRemoveChild(CompoundShape* shape, uint32_t index);
Shape* lovrCompoundShapeGetChild(CompoundShape* shape, uint32_t index);
uint32_t lovrCompoundShapeGetChildCount(CompoundShape* shape);
void lovrCompoundShapeGetChildOffset(CompoundShape* shape, uint32_t index, float* position, float* orientation);
void lovrCompoundShapeSetChildOffset(CompoundShape* shape, uint32_t index, float* position, float* orientation);
// These tokens need to exist for Lua bindings // These tokens need to exist for Lua bindings
#define lovrSphereShapeDestroy lovrShapeDestroy #define lovrSphereShapeDestroy lovrShapeDestroy
#define lovrBoxShapeDestroy lovrShapeDestroy #define lovrBoxShapeDestroy lovrShapeDestroy
@ -200,6 +202,7 @@ TerrainShape* lovrTerrainShapeCreate(float* vertices, uint32_t n, float scaleXZ,
#define lovrCylinderShapeDestroy lovrShapeDestroy #define lovrCylinderShapeDestroy lovrShapeDestroy
#define lovrMeshShapeDestroy lovrShapeDestroy #define lovrMeshShapeDestroy lovrShapeDestroy
#define lovrTerrainShapeDestroy lovrShapeDestroy #define lovrTerrainShapeDestroy lovrShapeDestroy
#define lovrCompoundShapeDestroy lovrShapeDestroy
// Joints // Joints

View File

@ -22,9 +22,9 @@ struct Collider {
JPH_BodyID id; JPH_BodyID id;
JPH_Body* body; JPH_Body* body;
World* world; World* world;
Shape* shape;
Collider* prev; Collider* prev;
Collider* next; Collider* next;
arr_t(Shape*) shapes;
arr_t(Joint*) joints; arr_t(Joint*) joints;
uint32_t tag; uint32_t tag;
}; };
@ -32,7 +32,6 @@ struct Collider {
struct Shape { struct Shape {
uint32_t ref; uint32_t ref;
ShapeType type; ShapeType type;
Collider* collider;
JPH_Shape* shape; JPH_Shape* shape;
}; };
@ -44,6 +43,7 @@ struct Joint {
static struct { static struct {
bool initialized; bool initialized;
Shape* pointShape;
JPH_Shape* queryBox; JPH_Shape* queryBox;
JPH_Shape* querySphere; JPH_Shape* querySphere;
JPH_AllHit_CastShapeCollector* castShapeCollector; JPH_AllHit_CastShapeCollector* castShapeCollector;
@ -70,14 +70,16 @@ static uint32_t findTag(World* world, const char* name) {
bool lovrPhysicsInit(void) { bool lovrPhysicsInit(void) {
if (state.initialized) return false; if (state.initialized) return false;
JPH_Init(32 * 1024 * 1024); 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.querySphere = (JPH_Shape*) JPH_SphereShape_Create(1.f);
state.queryBox = (JPH_Shape*) JPH_BoxShape_Create(&(const JPH_Vec3) { .5, .5f, .5f }, 0.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; return state.initialized = true;
} }
void lovrPhysicsDestroy(void) { void lovrPhysicsDestroy(void) {
if (!state.initialized) return; if (!state.initialized) return;
lovrRelease(state.pointShape, lovrShapeDestroy);
JPH_Shutdown(); JPH_Shutdown();
state.initialized = false; state.initialized = false;
} }
@ -173,32 +175,34 @@ void lovrWorldRaycast(World* world, float x1, float y1, float z1, float x2, floa
const JPH_Vec3 direction = { x2 - x1, y2 - y1, z2 - z1 }; const JPH_Vec3 direction = { x2 - x1, y2 - y1, z2 - z1 };
JPH_AllHit_CastRayCollector* collector = JPH_AllHit_CastRayCollector_Create(); JPH_AllHit_CastRayCollector* collector = JPH_AllHit_CastRayCollector_Create();
JPH_NarrowPhaseQuery_CastRayAll(query, &origin, &direction, collector, NULL, NULL, NULL); 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); size_t count;
for (int i = 0; i < hit_count; i++) { JPH_RayCastResult* hits = JPH_AllHit_CastRayCollector_GetHits(collector, &count);
float x = x1 + hit_array[i].fraction * (x2 - x1);
float y = y1 + hit_array[i].fraction * (y2 - y1); for (size_t i = 0; i < count; i++) {
float z = z1 + hit_array[i].fraction * (z2 - z1); Collider* collider = (Collider*) (uintptr_t) JPH_BodyInterface_GetUserData(world->bodies, hits[i].bodyID);
// todo: assuming one shape per collider; doesn't support compound shape uint32_t child = 0;
Collider* collider = (Collider*) JPH_BodyInterface_GetUserData(
world->bodies, if (collider->shape->type == SHAPE_COMPOUND) {
hit_array[i].bodyID); JPH_SubShapeID id = hits[i].subShapeID2;
size_t count; JPH_SubShapeID remainder;
Shape** shape = lovrColliderGetShapes(collider, &count); child = JPH_CompoundShape_GetSubShapeIndexFromID((JPH_CompoundShape*) collider->shape, id, &remainder);
const JPH_RVec3 position = { x, y, z }; }
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_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( if (callback(collider, &position.x, &normal.x, child, userdata)) {
shape[0], // assumes one shape per collider; todo: compound shapes
x, y, z,
normal.x, normal.y, normal.z,
userdata);
if (shouldStop) {
break; break;
} }
} }
JPH_AllHit_CastRayCollector_Destroy(collector); JPH_AllHit_CastRayCollector_Destroy(collector);
} }
@ -209,26 +213,25 @@ static bool lovrWorldQueryShape(World* world, JPH_Shape* shape, float position[3
mat4_translate(m, position[0], position[1], position[2]); mat4_translate(m, position[0], position[1], position[2]);
mat4_scale(m, scale[0], scale[1], scale[2]); mat4_scale(m, scale[0], scale[1], scale[2]);
JPH_Vec3 direction = { 0.f }; JPH_Vec3 direction = { 0.f, 0.f, 0.f };
JPH_RVec3 base_offset = { 0.f }; JPH_RVec3 base_offset = { 0.f, 0.f, 0.f };
const JPH_NarrowPhaseQuery* query = JPC_PhysicsSystem_GetNarrowPhaseQueryNoLock(world->system); const JPH_NarrowPhaseQuery* query = JPC_PhysicsSystem_GetNarrowPhaseQueryNoLock(world->system);
JPH_AllHit_CastShapeCollector_Reset(state.castShapeCollector); JPH_AllHit_CastShapeCollector_Reset(state.castShapeCollector);
JPH_NarrowPhaseQuery_CastShape(query, shape, &transform, &direction, &base_offset, 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); size_t count;
for (int i = 0; i < hit_count; i++) { 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); JPH_BodyID id = JPH_AllHit_CastShapeCollector_GetBodyID2(state.castShapeCollector, i);
Collider* collider = (Collider*) JPH_BodyInterface_GetUserData( Collider* collider = (Collider*) (uintptr_t) JPH_BodyInterface_GetUserData(world->bodies, id);
world->bodies,
id); if (callback(collider, 0, userdata)) {
size_t count;
Shape** shape = lovrColliderGetShapes(collider, &count);
bool shouldStop = callback(shape[0], userdata);
if (shouldStop) {
break; break;
} }
} }
return hit_count > 0;
return count > 0;
} }
bool lovrWorldQueryBox(World* world, float position[3], float size[3], QueryCallback callback, void* userdata) { bool lovrWorldQueryBox(World* world, float position[3], float size[3], QueryCallback callback, void* userdata) {
@ -315,7 +318,7 @@ void lovrWorldSetAngularDamping(World* world, float damping, float threshold) {
// Collider // Collider
Collider* lovrColliderCreate(World* world, float x, float y, float z) { Collider* lovrColliderCreate(World* world, Shape* shape, float x, float y, float z) {
uint32_t count = JPH_PhysicsSystem_GetNumBodies(world->system); uint32_t count = JPH_PhysicsSystem_GetNumBodies(world->system);
uint32_t limit = JPH_PhysicsSystem_GetMaxBodies(world->system); uint32_t limit = JPH_PhysicsSystem_GetMaxBodies(world->system);
lovrCheck(count < limit, "Too many colliders!"); lovrCheck(count < limit, "Too many colliders!");
@ -323,25 +326,25 @@ Collider* lovrColliderCreate(World* world, float x, float y, float z) {
Collider* collider = lovrCalloc(sizeof(Collider)); Collider* collider = lovrCalloc(sizeof(Collider));
collider->ref = 1; collider->ref = 1;
collider->world = world; collider->world = world;
collider->shape = shape ? shape : state.pointShape;
collider->tag = UNTAGGED; collider->tag = UNTAGGED;
JPH_MotionType motionType = JPH_MotionType_Dynamic;
JPH_ObjectLayer objectLayer = UNTAGGED * 2 + 1;
const JPH_RVec3 position = { x, y, z }; const JPH_RVec3 position = { x, y, z };
const JPH_Quat rotation = { 0.f, 0.f, 0.f, 1.f }; 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_MotionType type = JPH_MotionType_Dynamic;
JPH_BodyCreationSettings* settings = JPH_BodyCreationSettings_Create3( JPH_ObjectLayer objectLayer = UNTAGGED * 2 + 1;
state.querySphere, &position, &rotation, motionType, objectLayer); JPH_BodyCreationSettings* settings = JPH_BodyCreationSettings_Create3(collider->shape->shape, &position, &rotation, type, objectLayer);
collider->body = JPH_BodyInterface_CreateBody(world->bodies, settings); collider->body = JPH_BodyInterface_CreateBody(world->bodies, settings);
JPH_BodyCreationSettings_Destroy(settings);
collider->id = JPH_Body_GetID(collider->body); collider->id = JPH_Body_GetID(collider->body);
JPH_BodyCreationSettings_Destroy(settings);
JPH_BodyInterface_AddBody(world->bodies, collider->id, JPH_Activation_Activate); JPH_BodyInterface_AddBody(world->bodies, collider->id, JPH_Activation_Activate);
JPH_BodyInterface_SetUserData(world->bodies, collider->id, (uint64_t) collider); JPH_BodyInterface_SetUserData(world->bodies, collider->id, (uint64_t) collider);
lovrColliderSetLinearDamping(collider, world->defaultLinearDamping, 0.f); lovrColliderSetLinearDamping(collider, world->defaultLinearDamping, 0.f);
lovrColliderSetAngularDamping(collider, world->defaultAngularDamping, 0.f); lovrColliderSetAngularDamping(collider, world->defaultAngularDamping, 0.f);
lovrColliderSetSleepingAllowed(collider, world->defaultIsSleepingAllowed); lovrColliderSetSleepingAllowed(collider, world->defaultIsSleepingAllowed);
arr_init(&collider->shapes);
arr_init(&collider->joints); arr_init(&collider->joints);
// Adjust the world's collider list // Adjust the world's collider list
@ -353,15 +356,14 @@ Collider* lovrColliderCreate(World* world, float x, float y, float z) {
world->head = collider; world->head = collider;
} }
// The world owns a reference to the collider lovrRetain(collider->shape);
lovrRetain(collider); lovrRetain(collider); // The world owns a reference to the collider
return collider; return collider;
} }
void lovrColliderDestroy(void* ref) { void lovrColliderDestroy(void* ref) {
Collider* collider = ref; Collider* collider = ref;
lovrColliderDestroyData(collider); lovrColliderDestroyData(collider);
arr_free(&collider->shapes);
arr_free(&collider->joints); arr_free(&collider->joints);
lovrFree(collider); lovrFree(collider);
} }
@ -371,13 +373,9 @@ void lovrColliderDestroyData(Collider* collider) {
return; return;
} }
lovrRelease(collider->shape, lovrShapeDestroy);
size_t count; 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); Joint** joints = lovrColliderGetJoints(collider, &count);
for (size_t i = 0; i < count; i++) { for (size_t i = 0; i < count; i++) {
lovrRelease(joints[i], lovrJointDestroy); lovrRelease(joints[i], lovrJointDestroy);
@ -399,6 +397,18 @@ bool lovrColliderIsDestroyed(Collider* collider) {
return !collider->body; return !collider->body;
} }
bool lovrColliderIsEnabled(Collider* collider) {
return JPH_BodyInterface_IsAdded(collider->world->bodies, collider->id);
}
void lovrColliderSetEnabled(Collider* collider, bool enable) {
if (enable && !lovrColliderIsEnabled(collider)) {
JPH_BodyInterface_AddBody(collider->world->bodies, collider->id, JPH_Activation_DontActivate);
} else if (!enable && lovrColliderIsEnabled(collider)) {
JPH_BodyInterface_RemoveBody(collider->world->bodies, collider->id);
}
}
void lovrColliderInitInertia(Collider* collider, Shape* shape) { void lovrColliderInitInertia(Collider* collider, Shape* shape) {
// //
} }
@ -411,29 +421,75 @@ Collider* lovrColliderGetNext(Collider* collider) {
return collider->next; return collider->next;
} }
void lovrColliderAddShape(Collider* collider, Shape* shape) { Shape* lovrColliderGetShape(Collider* collider, uint32_t child) {
if (collider->shape == state.pointShape) {
return NULL;
}
if (child == ~0u || collider->shape->type != SHAPE_COMPOUND) {
return collider->shape;
}
return lovrCompoundShapeGetChild(collider->shape, child);
}
void lovrColliderSetShape(Collider* collider, Shape* shape) {
shape = shape ? shape : state.pointShape;
if (shape == collider->shape) {
return;
}
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); 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);
}
void lovrColliderRemoveShape(Collider* collider, Shape* shape) { bool updateMass = true;
if (shape->collider == collider) { if (shape->type == SHAPE_MESH || shape->type == SHAPE_TERRAIN) {
// todo: actions necessary for compound shapes lovrColliderSetKinematic(collider, true);
shape->collider = NULL; updateMass = false;
lovrRelease(shape, lovrShapeDestroy); }
JPH_BodyInterface_SetShape(collider->world->bodies, collider->id, shape->shape, updateMass, JPH_Activation_Activate);
if (hasOffset) {
lovrColliderSetShapeOffset(collider, position, orientation);
} }
} }
Shape** lovrColliderGetShapes(Collider* collider, size_t* count) { void lovrColliderGetShapeOffset(Collider* collider, float* position, float* orientation) {
*count = collider->shapes.length; const JPH_Shape* shape = JPH_BodyInterface_GetShape(collider->world->bodies, collider->id);
return collider->shapes.data;
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) {
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);
}
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 && (collider->shape->type == SHAPE_MESH || collider->shape->type == SHAPE_TERRAIN);
JPH_BodyInterface_SetShape(collider->world->bodies, collider->id, shape, updateMass, JPH_Activation_Activate);
} }
Joint** lovrColliderGetJoints(Collider* collider, size_t* count) { Joint** lovrColliderGetJoints(Collider* collider, size_t* count) {
@ -500,6 +556,14 @@ void lovrColliderSetKinematic(Collider* collider, bool kinematic) {
} }
} }
bool lovrColliderIsSensor(Collider* collider) {
return JPH_Body_IsSensor(collider->body);
}
void lovrColliderSetSensor(Collider* collider, bool sensor) {
JPH_Body_SetIsSensor(collider->body, sensor);
}
bool lovrColliderIsContinuous(Collider* collider) { bool lovrColliderIsContinuous(Collider* collider) {
return JPH_BodyInterface_GetMotionQuality(collider->world->bodies, collider->id) == JPH_MotionQuality_LinearCast; return JPH_BodyInterface_GetMotionQuality(collider->world->bodies, collider->id) == JPH_MotionQuality_LinearCast;
} }
@ -538,22 +602,17 @@ void lovrColliderSetAwake(Collider* collider, bool awake) {
} }
float lovrColliderGetMass(Collider* collider) { float lovrColliderGetMass(Collider* collider) {
if (collider->shapes.length > 0) { JPH_MotionProperties* motionProperties = JPH_Body_GetMotionProperties(collider->body);
JPH_MotionProperties* motionProperties = JPH_Body_GetMotionProperties(collider->body); return 1.f / JPH_MotionProperties_GetInverseMassUnchecked(motionProperties);
return 1.f / JPH_MotionProperties_GetInverseMassUnchecked(motionProperties);
}
return 0.f;
} }
void lovrColliderSetMass(Collider* collider, float mass) { void lovrColliderSetMass(Collider* collider, float mass) {
if (collider->shapes.length > 0) { JPH_MotionProperties* motionProperties = JPH_Body_GetMotionProperties(collider->body);
JPH_MotionProperties* motionProperties = JPH_Body_GetMotionProperties(collider->body); Shape* shape = collider->shape;
Shape* shape = collider->shapes.data[0]; JPH_MassProperties* massProperties;
JPH_MassProperties* massProperties; JPH_Shape_GetMassProperties(shape->shape, massProperties);
JPH_Shape_GetMassProperties(shape->shape, massProperties); JPH_MassProperties_ScaleToMass(massProperties, mass);
JPH_MassProperties_ScaleToMass(massProperties, mass); JPH_MotionProperties_SetMassProperties(motionProperties, JPH_AllowedDOFs_All, massProperties);
JPH_MotionProperties_SetMassProperties(motionProperties, JPH_AllowedDOFs_All, massProperties);
}
} }
void lovrColliderGetMassData(Collider* collider, float* cx, float* cy, float* cz, float* mass, float inertia[6]) { void lovrColliderGetMassData(Collider* collider, float* cx, float* cy, float* cz, float* mass, float inertia[6]) {
@ -765,6 +824,8 @@ void lovrColliderGetAABB(Collider* collider, float aabb[6]) {
aabb[5] = box.max.z; aabb[5] = box.max.z;
} }
// Shapes
void lovrShapeDestroy(void* ref) { void lovrShapeDestroy(void* ref) {
Shape* shape = ref; Shape* shape = ref;
lovrShapeDestroyData(shape); lovrShapeDestroyData(shape);
@ -773,6 +834,14 @@ void lovrShapeDestroy(void* ref) {
void lovrShapeDestroyData(Shape* shape) { void lovrShapeDestroyData(Shape* shape) {
if (shape->shape) { if (shape->shape) {
if (shape->type == SHAPE_COMPOUND) {
uint32_t count = lovrCompoundShapeGetChildCount(shape);
for (uint32_t i = 0; i < count; i++) {
Shape* child = lovrCompoundShapeGetChild(shape, i);
lovrRelease(child, lovrShapeDestroy);
}
}
JPH_Shape_Destroy(shape->shape); JPH_Shape_Destroy(shape->shape);
shape->shape = NULL; shape->shape = NULL;
} }
@ -782,58 +851,26 @@ ShapeType lovrShapeGetType(Shape* shape) {
return shape->type; return shape->type;
} }
Collider* lovrShapeGetCollider(Shape* shape) { void lovrShapeGetMass(Shape* shape, float density, float* cx, float* cy, float* cz, float* mass, float inertia[6]) {
return shape->collider; //
} }
bool lovrShapeIsEnabled(Shape* shape) { void lovrShapeGetAABB(Shape* shape, float position[3], float orientation[4], float aabb[6]) {
return true; JPH_AABox box;
} if (!position && !orientation) {
JPH_Shape_GetLocalBounds(shape->shape, &box);
void lovrShapeSetEnabled(Shape* shape, bool enabled) { } else {
if (!enabled) { JPH_RMatrix4x4 transform;
lovrLog(LOG_WARN, "PHY", "Jolt doesn't support disabling shapes"); JPH_Vec3 scale = { 1.f, 1.f, 1.f };
mat4_fromPose(&transform.m11, position, orientation);
JPH_Shape_GetWorldSpaceBounds(shape->shape, &transform, &scale, &box);
} }
} aabb[0] = box.min.x;
aabb[1] = box.max.x;
bool lovrShapeIsSensor(Shape* shape) { aabb[2] = box.min.y;
lovrLog(LOG_WARN, "PHY", "Jolt sensor property fetched from collider, not shape"); aabb[3] = box.max.y;
return JPH_Body_IsSensor(shape->collider->body); aabb[4] = box.min.z;
} aabb[5] = box.max.z;
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);
}
void lovrShapeGetPosition(Shape* shape, float* x, float* y, float* z) {
// todo: compound shapes
*x = 0.f;
*y = 0.f;
*z = 0.f;
}
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);
} }
SphereShape* lovrSphereShapeCreate(float radius) { SphereShape* lovrSphereShapeCreate(float radius) {
@ -842,6 +879,7 @@ SphereShape* lovrSphereShapeCreate(float radius) {
sphere->ref = 1; sphere->ref = 1;
sphere->type = SHAPE_SPHERE; sphere->type = SHAPE_SPHERE;
sphere->shape = (JPH_Shape*) JPH_SphereShape_Create(radius); sphere->shape = (JPH_Shape*) JPH_SphereShape_Create(radius);
JPH_Shape_SetUserData(sphere->shape, (uint64_t) (uintptr_t) sphere);
return sphere; return sphere;
} }
@ -849,17 +887,13 @@ float lovrSphereShapeGetRadius(SphereShape* sphere) {
return JPH_SphereShape_GetRadius((JPH_SphereShape*) sphere->shape); 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* lovrBoxShapeCreate(float w, float h, float d) {
BoxShape* box = lovrCalloc(sizeof(BoxShape)); BoxShape* box = lovrCalloc(sizeof(BoxShape));
box->ref = 1; box->ref = 1;
box->type = SHAPE_BOX; box->type = SHAPE_BOX;
const JPH_Vec3 halfExtent = { w / 2.f, h / 2.f, d / 2.f }; const JPH_Vec3 halfExtent = { w / 2.f, h / 2.f, d / 2.f };
box->shape = (JPH_Shape*) JPH_BoxShape_Create(&halfExtent, 0.f); box->shape = (JPH_Shape*) JPH_BoxShape_Create(&halfExtent, 0.f);
JPH_Shape_SetUserData(box->shape, (uint64_t) (uintptr_t) box);
return box; return box;
} }
@ -871,17 +905,13 @@ void lovrBoxShapeGetDimensions(BoxShape* box, float* w, float* h, float* d) {
*d = halfExtent.z * 2.f; *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) { CapsuleShape* lovrCapsuleShapeCreate(float radius, float length) {
lovrCheck(radius > 0.f && length > 0.f, "CapsuleShape dimensions must be positive"); lovrCheck(radius > 0.f && length > 0.f, "CapsuleShape dimensions must be positive");
CapsuleShape* capsule = lovrCalloc(sizeof(CapsuleShape)); CapsuleShape* capsule = lovrCalloc(sizeof(CapsuleShape));
capsule->ref = 1; capsule->ref = 1;
capsule->type = SHAPE_CAPSULE; capsule->type = SHAPE_CAPSULE;
capsule->shape = (JPH_Shape*) JPH_CapsuleShape_Create(length / 2, radius); capsule->shape = (JPH_Shape*) JPH_CapsuleShape_Create(length / 2, radius);
JPH_Shape_SetUserData(capsule->shape, (uint64_t) (uintptr_t) capsule);
return capsule; return capsule;
} }
@ -889,45 +919,26 @@ float lovrCapsuleShapeGetRadius(CapsuleShape* capsule) {
return JPH_CapsuleShape_GetRadius((JPH_CapsuleShape*) capsule->shape); 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) { float lovrCapsuleShapeGetLength(CapsuleShape* capsule) {
return 2.f * JPH_CapsuleShape_GetHalfHeightOfCylinder((JPH_CapsuleShape*) capsule->shape); 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) { CylinderShape* lovrCylinderShapeCreate(float radius, float length) {
lovrCheck(radius > 0.f && length > 0.f, "CylinderShape dimensions must be positive"); lovrCheck(radius > 0.f && length > 0.f, "CylinderShape dimensions must be positive");
CylinderShape* Cylinder = lovrCalloc(sizeof(CylinderShape)); CylinderShape* cylinder = lovrCalloc(sizeof(CylinderShape));
Cylinder->ref = 1; cylinder->ref = 1;
Cylinder->type = SHAPE_CYLINDER; cylinder->type = SHAPE_CYLINDER;
Cylinder->shape = (JPH_Shape*) JPH_CylinderShape_Create(length / 2.f, radius); cylinder->shape = (JPH_Shape*) JPH_CylinderShape_Create(length / 2.f, radius);
return Cylinder; JPH_Shape_SetUserData(cylinder->shape, (uint64_t) (uintptr_t) cylinder);
return cylinder;
} }
float lovrCylinderShapeGetRadius(CylinderShape* Cylinder) { float lovrCylinderShapeGetRadius(CylinderShape* cylinder) {
return JPH_CylinderShape_GetRadius((JPH_CylinderShape*) Cylinder->shape); return JPH_CylinderShape_GetRadius((JPH_CylinderShape*) cylinder->shape);
} }
void lovrCylinderShapeSetRadius(CylinderShape* Cylinder, float radius) { float lovrCylinderShapeGetLength(CylinderShape* cylinder) {
lovrLog(LOG_WARN, "PHY", "Jolt CylinderShape radius is read-only"); return JPH_CylinderShape_GetHalfHeight((JPH_CylinderShape*) cylinder->shape) * 2.f;
// 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* lovrMeshShapeCreate(int vertexCount, float vertices[], int indexCount, uint32_t indices[]) {
@ -980,6 +991,102 @@ TerrainShape* lovrTerrainShapeCreate(float* vertices, uint32_t n, float scaleXZ,
return terrain; return terrain;
} }
CompoundShape* lovrCompoundShapeCreate(Shape** shapes, vec3 positions, quat orientations, uint32_t count, bool freeze) {
lovrCheck(!freeze || count >= 2, "A frozen CompoundShape must contain at least two shapes");
CompoundShape* shape = lovrCalloc(sizeof(CompoundShape));
shape->ref = 1;
shape->type = SHAPE_COMPOUND;
JPH_CompoundShapeSettings* settings = freeze ?
(JPH_CompoundShapeSettings*) JPH_StaticCompoundShapeSettings_Create() :
(JPH_CompoundShapeSettings*) JPH_MutableCompoundShapeSettings_Create();
for (uint32_t i = 0; i < count; i++) {
lovrCheck(shapes[i]->type != SHAPE_COMPOUND, "Currently, nesting compound shapes is not supported");
JPH_Vec3 position = { positions[3 * i + 0], positions[3 * i + 1], positions[3 * i + 2] };
JPH_Quat rotation = { orientations[4 * i + 0], orientations[4 * i + 1], orientations[4 * i + 2], orientations[4 * i + 3] };
JPH_CompoundShapeSettings_AddShape2(settings, &position, &rotation, shapes[i]->shape, 0);
lovrRetain(shapes[i]);
}
if (freeze) {
shape->shape = (JPH_Shape*) JPH_StaticCompoundShape_Create((JPH_StaticCompoundShapeSettings*) settings);
} else {
shape->shape = (JPH_Shape*) JPH_MutableCompoundShape_Create((JPH_MutableCompoundShapeSettings*) settings);
}
JPH_ShapeSettings_Destroy((JPH_ShapeSettings*) settings);
return shape;
}
bool lovrCompoundShapeIsFrozen(CompoundShape* shape) {
return JPH_Shape_GetSubType(shape->shape) == JPH_ShapeSubType_StaticCompound;
}
void lovrCompoundShapeAddChild(CompoundShape* shape, Shape* child, float* position, float* orientation) {
lovrCheck(!lovrCompoundShapeIsFrozen(shape), "CompoundShape is frozen and can not be changed");
lovrCheck(child->type != SHAPE_COMPOUND, "Currently, nesting compound shapes is not supported");
JPH_Vec3 pos = { position[0], position[1], position[2] };
JPH_Quat rot = { orientation[0], orientation[1], orientation[2], orientation[3] };
JPH_MutableCompoundShape_AddShape((JPH_MutableCompoundShape*) shape->shape, &pos, &rot, child->shape, 0);
lovrRetain(child);
}
void lovrCompoundShapeReplaceChild(CompoundShape* shape, uint32_t index, Shape* child, float* position, float* orientation) {
lovrCheck(!lovrCompoundShapeIsFrozen(shape), "CompoundShape is frozen and can not be changed");
lovrCheck(child->type != SHAPE_COMPOUND, "Currently, nesting compound shapes is not supported");
lovrCheck(index < lovrCompoundShapeGetChildCount(shape), "CompoundShape has no child at index %d", index + 1);
JPH_Vec3 pos = { position[0], position[1], position[2] };
JPH_Quat rot = { orientation[0], orientation[1], orientation[2], orientation[3] };
lovrRelease(lovrCompoundShapeGetChild(shape, index), lovrShapeDestroy);
JPH_MutableCompoundShape_ModifyShape2((JPH_MutableCompoundShape*) shape->shape, index, &pos, &rot, child->shape);
lovrRetain(child);
}
void lovrCompoundShapeRemoveChild(CompoundShape* shape, uint32_t index) {
lovrCheck(!lovrCompoundShapeIsFrozen(shape), "CompoundShape is frozen and can not be changed");
lovrCheck(index < lovrCompoundShapeGetChildCount(shape), "CompoundShape has no child at index %d", index + 1);
Shape* child = lovrCompoundShapeGetChild(shape, index);
JPH_MutableCompoundShape_RemoveShape((JPH_MutableCompoundShape*) shape->shape, index);
lovrRelease(child, lovrShapeDestroy);
}
Shape* lovrCompoundShapeGetChild(CompoundShape* shape, uint32_t index) {
if (index < lovrCompoundShapeGetChildCount(shape)) {
const JPH_Shape* child;
JPH_CompoundShape_GetSubShape((JPH_CompoundShape*) shape->shape, index, &child, NULL, NULL, NULL);
return (Shape*) (uintptr_t) JPH_Shape_GetUserData(child);
} else {
return NULL;
}
}
uint32_t lovrCompoundShapeGetChildCount(CompoundShape* shape) {
return JPH_CompoundShape_GetNumSubShapes((JPH_CompoundShape*) shape->shape);
}
void lovrCompoundShapeGetChildOffset(CompoundShape* shape, uint32_t index, float* position, float* orientation) {
lovrCheck(index < lovrCompoundShapeGetChildCount(shape), "CompoundShape has no child at index %d", index + 1);
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 lovrCompoundShapeSetChildOffset(CompoundShape* shape, uint32_t index, float* position, float* orientation) {
lovrCheck(!lovrCompoundShapeIsFrozen(shape), "CompoundShape is frozen and can not be changed");
lovrCheck(index < lovrCompoundShapeGetChildCount(shape), "CompoundShape has no child at index %d", index + 1);
JPH_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]) { void lovrJointGetAnchors(Joint* joint, float anchor1[3], float anchor2[3]) {
JPH_Body* body1 = JPH_TwoBodyConstraint_GetBody1((JPH_TwoBodyConstraint*) joint->constraint); JPH_Body* body1 = JPH_TwoBodyConstraint_GetBody1((JPH_TwoBodyConstraint*) joint->constraint);
JPH_Body* body2 = JPH_TwoBodyConstraint_GetBody2((JPH_TwoBodyConstraint*) joint->constraint); JPH_Body* body2 = JPH_TwoBodyConstraint_GetBody2((JPH_TwoBodyConstraint*) joint->constraint);

View File

@ -22,10 +22,11 @@ struct Collider {
Collider* prev; Collider* prev;
Collider* next; Collider* next;
uint32_t tag; uint32_t tag;
arr_t(Shape*) shapes; Shape* shape;
arr_t(Joint*) joints; arr_t(Joint*) joints;
float friction; float friction;
float restitution; float restitution;
bool sensor;
}; };
struct Shape { struct Shape {
@ -35,7 +36,6 @@ struct Shape {
Collider* collider; Collider* collider;
void* vertices; void* vertices;
void* indices; void* indices;
bool sensor;
}; };
struct Joint { struct Joint {
@ -66,8 +66,9 @@ static void raycastCallback(void* d, dGeomID a, dGeomID b) {
RaycastCallback callback = data->callback; RaycastCallback callback = data->callback;
void* userdata = data->userdata; void* userdata = data->userdata;
Shape* shape = dGeomGetData(b); Shape* shape = dGeomGetData(b);
Collider* collider = dBodyGetData(dGeomGetBody(b));
if (!shape) { if (!shape || !collider) {
return; 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)); int count = dCollide(a, b, MAX_CONTACTS, &contact->geom, sizeof(dContact));
for (int i = 0; i < count; i++) { for (int i = 0; i < count; i++) {
dContactGeom g = contact[i].geom; dContactGeom g = contact[i].geom;
data->shouldStop = callback( data->shouldStop = callback(collider, g.pos, g.normal, 0, userdata);
shape, g.pos[0], g.pos[1], g.pos[2], g.normal[0], g.normal[1], g.normal[2], userdata
);
} }
} }
@ -93,14 +92,15 @@ static void queryCallback(void* d, dGeomID a, dGeomID b) {
if (data->shouldStop) return; if (data->shouldStop) return;
Shape* shape = dGeomGetData(b); Shape* shape = dGeomGetData(b);
if (!shape) { Collider* collider = dBodyGetData(dGeomGetBody(b));
if (!shape || !collider) {
return; return;
} }
dContactGeom contact; dContactGeom contact;
if (dCollide(a, b, 1 | CONTACTS_UNIMPORTANT, &contact, sizeof(contact))) { if (dCollide(a, b, 1 | CONTACTS_UNIMPORTANT, &contact, sizeof(contact))) {
if (data->callback) { if (data->callback) {
data->shouldStop = data->callback(shape, data->userdata); data->shouldStop = data->callback(collider, 0, data->userdata);
} else { } else {
data->shouldStop = true; data->shouldStop = true;
} }
@ -279,7 +279,7 @@ int lovrWorldCollide(World* world, Shape* a, Shape* b, float friction, float res
int contactCount = dCollide(a->id, b->id, MAX_CONTACTS, &contacts[0].geom, sizeof(dContact)); int contactCount = dCollide(a->id, b->id, MAX_CONTACTS, &contacts[0].geom, sizeof(dContact));
if (!a->sensor && !b->sensor) { if (!colliderA->sensor && !colliderB->sensor) {
for (int c = 0; c < contactCount; c++) { for (int c = 0; c < contactCount; c++) {
dJointID joint = dJointCreateContact(world->id, world->contactGroup, &contacts[c]); dJointID joint = dJointCreateContact(world->id, world->contactGroup, &contacts[c]);
dJointAttach(joint, colliderA->body, colliderB->body); dJointAttach(joint, colliderA->body, colliderB->body);
@ -436,7 +436,7 @@ bool lovrWorldIsCollisionEnabledBetween(World* world, const char* tag1, const ch
return (world->masks[i] & (1 << j)) && (world->masks[j] & (1 << i)); 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* collider = lovrCalloc(sizeof(Collider));
collider->ref = 1; collider->ref = 1;
collider->body = dBodyCreate(world->id); collider->body = dBodyCreate(world->id);
@ -445,9 +445,9 @@ Collider* lovrColliderCreate(World* world, float x, float y, float z) {
collider->restitution = 0; collider->restitution = 0;
collider->tag = NO_TAG; collider->tag = NO_TAG;
dBodySetData(collider->body, collider); dBodySetData(collider->body, collider);
arr_init(&collider->shapes);
arr_init(&collider->joints); arr_init(&collider->joints);
lovrColliderSetShape(collider, shape);
lovrColliderSetPosition(collider, x, y, z); lovrColliderSetPosition(collider, x, y, z);
// Adjust the world's collider list // Adjust the world's collider list
@ -467,7 +467,6 @@ Collider* lovrColliderCreate(World* world, float x, float y, float z) {
void lovrColliderDestroy(void* ref) { void lovrColliderDestroy(void* ref) {
Collider* collider = ref; Collider* collider = ref;
lovrColliderDestroyData(collider); lovrColliderDestroyData(collider);
arr_free(&collider->shapes);
arr_free(&collider->joints); arr_free(&collider->joints);
lovrFree(collider); lovrFree(collider);
} }
@ -477,13 +476,9 @@ void lovrColliderDestroyData(Collider* collider) {
return; return;
} }
lovrColliderSetShape(collider, NULL);
size_t count; 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); Joint** joints = lovrColliderGetJoints(collider, &count);
for (size_t i = 0; i < count; i++) { for (size_t i = 0; i < count; i++) {
lovrRelease(joints[i], lovrJointDestroy); lovrRelease(joints[i], lovrJointDestroy);
@ -505,6 +500,14 @@ bool lovrColliderIsDestroyed(Collider* collider) {
return !collider->body; return !collider->body;
} }
bool lovrColliderIsEnabled(Collider* collider) {
return true;
}
void lovrColliderSetEnabled(Collider* collider, bool enable) {
//
}
void lovrColliderInitInertia(Collider* collider, Shape* shape) { void lovrColliderInitInertia(Collider* collider, Shape* shape) {
// compute inertia matrix for default density // compute inertia matrix for default density
const float density = 1.0f; const float density = 1.0f;
@ -521,38 +524,50 @@ Collider* lovrColliderGetNext(Collider* collider) {
return collider->next; return collider->next;
} }
void lovrColliderAddShape(Collider* collider, Shape* shape) { Shape* lovrColliderGetShape(Collider* collider, uint32_t child) {
lovrRetain(shape); return collider->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);
} }
void lovrColliderRemoveShape(Collider* collider, Shape* shape) { void lovrColliderSetShape(Collider* collider, Shape* shape) {
if (shape->collider == collider) { if (collider->shape) {
dSpaceRemove(collider->world->space, shape->id); dSpaceRemove(collider->world->space, collider->shape->id);
dGeomSetBody(shape->id, 0); dGeomSetBody(collider->shape->id, 0);
shape->collider = NULL; collider->shape->collider = NULL;
lovrRelease(shape, lovrShapeDestroy); lovrRelease(collider->shape, lovrShapeDestroy);
} }
}
Shape** lovrColliderGetShapes(Collider* collider, size_t* count) { collider->shape = shape;
arr_clear(&collider->shapes);
for (dGeomID geom = dBodyGetFirstGeom(collider->body); geom; geom = dBodyGetNextGeom(geom)) { if (shape) {
Shape* shape = dGeomGetData(geom); if (shape->collider) {
if (shape) { lovrColliderSetShape(shape->collider, NULL);
arr_push(&collider->shapes, shape);
} }
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) { Joint** lovrColliderGetJoints(Collider* collider, size_t* count) {
@ -610,6 +625,14 @@ void lovrColliderSetKinematic(Collider* collider, bool kinematic) {
} }
} }
bool lovrColliderIsSensor(Collider* collider) {
return collider->sensor;
}
void lovrColliderSetSensor(Collider* collider, bool sensor) {
collider->sensor = sensor;
}
bool lovrColliderIsContinuous(Collider* collider) { bool lovrColliderIsContinuous(Collider* collider) {
return false; return false;
} }
@ -888,51 +911,6 @@ Collider* lovrShapeGetCollider(Shape* shape) {
return shape->collider; return shape->collider;
} }
bool lovrShapeIsEnabled(Shape* shape) {
return dGeomIsEnabled(shape->id);
}
void lovrShapeSetEnabled(Shape* shape, bool enabled) {
if (enabled) {
dGeomEnable(shape->id);
} else {
dGeomDisable(shape->id);
}
}
bool lovrShapeIsSensor(Shape* shape) {
return shape->sensor;
}
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]) { void lovrShapeGetMass(Shape* shape, float density, float* cx, float* cy, float* cz, float* mass, float inertia[6]) {
dMass m; dMass m;
dMassSetZero(&m); dMassSetZero(&m);
@ -973,6 +951,8 @@ void lovrShapeGetMass(Shape* shape, float density, float* cx, float* cy, float*
case SHAPE_TERRAIN: { case SHAPE_TERRAIN: {
break; break;
} }
default: break;
} }
const dReal* position = dGeomGetOffsetPosition(shape->id); const dReal* position = dGeomGetOffsetPosition(shape->id);
@ -996,7 +976,7 @@ void lovrShapeGetMass(Shape* shape, float density, float* cx, float* cy, float*
inertia[5] = m.I[9]; inertia[5] = m.I[9];
} }
void lovrShapeGetAABB(Shape* shape, float aabb[6]) { void lovrShapeGetAABB(Shape* shape, float position[3], float orientation[4], float aabb[6]) {
dGeomGetAABB(shape->id, aabb); dGeomGetAABB(shape->id, aabb);
} }
@ -1131,6 +1111,42 @@ TerrainShape* lovrTerrainShapeCreate(float* vertices, uint32_t n, float scaleXZ,
return terrain; 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 lovrCompoundShapeAddChild(CompoundShape* shape, Shape* child, float* position, float* orientation) {
//
}
void lovrCompoundShapeReplaceChild(CompoundShape* shape, uint32_t index, Shape* child, float* position, float* orientation) {
//
}
void lovrCompoundShapeRemoveChild(CompoundShape* shape, uint32_t index) {
//
}
Shape* lovrCompoundShapeGetChild(CompoundShape* shape, uint32_t index) {
return NULL;
}
uint32_t lovrCompoundShapeGetChildCount(CompoundShape* shape) {
return 0;
}
void lovrCompoundShapeGetChildOffset(CompoundShape* shape, uint32_t index, float* position, float* orientation) {
//
}
void lovrCompoundShapeSetChildOffset(CompoundShape* shape, uint32_t index, float* position, float* orientation) {
//
}
void lovrJointDestroy(void* ref) { void lovrJointDestroy(void* ref) {
Joint* joint = ref; Joint* joint = ref;
lovrJointDestroyData(joint); lovrJointDestroyData(joint);