diff --git a/deps/ode b/deps/ode index b85a9518..dbc45754 160000 --- a/deps/ode +++ b/deps/ode @@ -1 +1 @@ -Subproject commit b85a951862d13d1f731daaf960249ebbbe12730f +Subproject commit dbc457549169d04fa6baece760d052133ac2e3ba diff --git a/src/api/api.h b/src/api/api.h index b2accf18..b01339ae 100644 --- a/src/api/api.h +++ b/src/api/api.h @@ -50,6 +50,7 @@ extern const luaL_Reg lovrSliderJoint[]; extern const luaL_Reg lovrSoundData[]; extern const luaL_Reg lovrSource[]; extern const luaL_Reg lovrSphereShape[]; +extern const luaL_Reg lovrMeshShape[]; extern const luaL_Reg lovrTexture[]; extern const luaL_Reg lovrTextureData[]; extern const luaL_Reg lovrThread[]; diff --git a/src/api/l_physics.c b/src/api/l_physics.c index aaea0e20..6adef466 100644 --- a/src/api/l_physics.c +++ b/src/api/l_physics.c @@ -7,6 +7,7 @@ StringEntry ShapeTypes[] = { [SHAPE_BOX] = ENTRY("box"), [SHAPE_CAPSULE] = ENTRY("capsule"), [SHAPE_CYLINDER] = ENTRY("cylinder"), + [SHAPE_MESH] = ENTRY("mesh"), { 0 } }; @@ -153,6 +154,7 @@ int luaopen_lovr_physics(lua_State* L) { luax_registertype(L, BoxShape); luax_registertype(L, CapsuleShape); luax_registertype(L, CylinderShape); + luax_registertype(L, MeshShape); if (lovrPhysicsInit()) { luax_atexit(L, lovrPhysicsDestroy); } diff --git a/src/api/l_physics_shapes.c b/src/api/l_physics_shapes.c index 3cae0ba6..79800eb2 100644 --- a/src/api/l_physics_shapes.c +++ b/src/api/l_physics_shapes.c @@ -7,6 +7,7 @@ void luax_pushshape(lua_State* L, Shape* shape) { case SHAPE_BOX: luax_pushtype(L, BoxShape, shape); break; case SHAPE_CAPSULE: luax_pushtype(L, CapsuleShape, shape); break; case SHAPE_CYLINDER: luax_pushtype(L, CylinderShape, shape); break; + case SHAPE_MESH: luax_pushtype(L, MeshShape, shape); break; default: lovrThrow("Unreachable"); } } @@ -19,7 +20,8 @@ Shape* luax_checkshape(lua_State* L, int index) { hash64("SphereShape", strlen("SphereShape")), hash64("BoxShape", strlen("BoxShape")), hash64("CapsuleShape", strlen("CapsuleShape")), - hash64("CylinderShape", strlen("CylinderShape")) + hash64("CylinderShape", strlen("CylinderShape")), + hash64("MeshShape", strlen("MeshShape")), }; for (size_t i = 0; i < sizeof(hashes) / sizeof(hashes[0]); i++) { @@ -298,3 +300,8 @@ const luaL_Reg lovrCylinderShape[] = { { "setLength", l_lovrCylinderShapeSetLength }, { NULL, NULL } }; + +const luaL_Reg lovrMeshShape[] = { + lovrShape, + { NULL, NULL } +}; diff --git a/src/api/l_physics_world.c b/src/api/l_physics_world.c index 1d2b5ffa..e6c73a8b 100644 --- a/src/api/l_physics_world.c +++ b/src/api/l_physics_world.c @@ -110,6 +110,44 @@ static int l_lovrWorldNewSphereCollider(lua_State* L) { return 1; } +static int l_lovrWorldNewMeshCollider(lua_State* L) { + World* world = luax_checktype(L, 1, World); + lovrAssert(lua_istable(L, 2), "Vertices must be a table"); + lovrAssert(lua_istable(L, 3), "Indices must be a table"); + int vertexCount = luax_len(L, 2); + int indexCount = luax_len(L, 3); + // TODO: this never gets deallocated + float * vertices = malloc(sizeof(float) * vertexCount * 3); + unsigned * indices = malloc(sizeof(unsigned) * indexCount); + + for (int i = 0; i < vertexCount; i++) { + lua_rawgeti(L, 2, i + 1); + lovrAssert(lua_istable(L, -1), "Each verticle must be a table of coordinates"); + lua_rawgeti(L, -1, 1); // x + vertices[i * 3 + 0] = luaL_optnumber(L, -1, 0.); + lua_pop(L, 1); + lua_rawgeti(L, -1, 2); // y + vertices[i * 3 + 1] = luaL_optnumber(L, -1, 0.); + lua_pop(L, 1); + lua_rawgeti(L, -1, 3); // z + vertices[i * 3 + 2] = luaL_optnumber(L, -1, 0.); + lua_pop(L, 2); + } + for (int i = 0; i < indexCount; i++) { + lua_rawgeti(L, 3, i + 1); + indices[i] = luaL_checkinteger(L, -1) - 1; + } + lua_pop(L, indexCount); + Collider* collider = lovrColliderCreate(world, 0,0,0); + MeshShape* shape = lovrMeshShapeCreate(vertexCount, vertices, indexCount, indices); + lovrColliderAddShape(collider, shape); + lovrColliderInitInertia(collider, shape); + luax_pushtype(L, Collider, collider); + lovrRelease(Collider, collider); + lovrRelease(Shape, shape); + return 1; +} + static int l_lovrWorldGetColliders(lua_State* L) { World* world = luax_checktype(L, 1, World); @@ -306,6 +344,7 @@ const luaL_Reg lovrWorld[] = { { "newCapsuleCollider", l_lovrWorldNewCapsuleCollider }, { "newCylinderCollider", l_lovrWorldNewCylinderCollider }, { "newSphereCollider", l_lovrWorldNewSphereCollider }, + { "newMeshCollider", l_lovrWorldNewMeshCollider }, { "getColliders", l_lovrWorldGetColliders }, { "destroy", l_lovrWorldDestroy }, { "update", l_lovrWorldUpdate }, diff --git a/src/modules/physics/physics.c b/src/modules/physics/physics.c index 47e81ed9..eba84934 100644 --- a/src/modules/physics/physics.c +++ b/src/modules/physics/physics.c @@ -687,6 +687,10 @@ void lovrShapeDestroy(void* ref) { void lovrShapeDestroyData(Shape* shape) { if (shape->id) { + if (shape->type == SHAPE_MESH) { + dTriMeshDataID dataID = dGeomTriMeshGetData(shape->id); + dGeomTriMeshDataDestroy(dataID); + } dGeomDestroy(shape->id); shape->id = NULL; } @@ -779,6 +783,13 @@ void lovrShapeGetMass(Shape* shape, float density, float* cx, float* cy, float* dMassSetCylinder(&m, density, 3, radius, length); break; } + + case SHAPE_MESH: { + dMassSetTrimesh(&m, density, shape->id); + dGeomSetPosition(shape->id, -m.c[0], -m.c[1], -m.c[2]); + dMassTranslate(&m, -m.c[0], -m.c[1], -m.c[2]); + break; + } } const dReal* position = dGeomGetOffsetPosition(shape->id); @@ -894,6 +905,17 @@ void lovrCylinderShapeSetLength(CylinderShape* cylinder, float length) { dGeomCylinderSetParams(cylinder->id, lovrCylinderShapeGetRadius(cylinder), length); } +MeshShape* lovrMeshShapeInit(MeshShape* mesh, int vertexCount, float vertices[], int indexCount, dTriIndex indices[]) { + dTriMeshDataID dataID = dGeomTriMeshDataCreate(); + dGeomTriMeshDataBuildSingle(dataID, vertices, 3 * sizeof(float), vertexCount, + indices, indexCount, 3 * sizeof(dTriIndex)); + dGeomTriMeshDataPreprocess2(dataID, (1U << dTRIDATAPREPROCESS_BUILD_FACE_ANGLES), NULL); + mesh->id = dCreateTriMesh(0, dataID, 0, 0, 0); + mesh->type = SHAPE_MESH; + dGeomSetData(mesh->id, mesh); + return mesh; +} + void lovrJointDestroy(void* ref) { Joint* joint = ref; lovrJointDestroyData(joint); diff --git a/src/modules/physics/physics.h b/src/modules/physics/physics.h index defe2acc..32f2c490 100644 --- a/src/modules/physics/physics.h +++ b/src/modules/physics/physics.h @@ -14,7 +14,8 @@ typedef enum { SHAPE_SPHERE, SHAPE_BOX, SHAPE_CAPSULE, - SHAPE_CYLINDER + SHAPE_CYLINDER, + SHAPE_MESH, } ShapeType; typedef enum { @@ -63,6 +64,7 @@ typedef Shape SphereShape; typedef Shape BoxShape; typedef Shape CapsuleShape; typedef Shape CylinderShape; +typedef Shape MeshShape; struct Joint { JointType type; @@ -212,6 +214,10 @@ void lovrCylinderShapeSetRadius(CylinderShape* cylinder, float radius); float lovrCylinderShapeGetLength(CylinderShape* cylinder); void lovrCylinderShapeSetLength(CylinderShape* cylinder, float length); +MeshShape* lovrMeshShapeInit(MeshShape* mesh, int vertexCount, float vertices[], int indexCount, dTriIndex indices[]); +#define lovrMeshShapeCreate(...) lovrMeshShapeInit(lovrAlloc(MeshShape), __VA_ARGS__) +#define lovrMeshShapeDestroy lovrShapeDestroy + void lovrJointDestroy(void* ref); void lovrJointDestroyData(Joint* joint); JointType lovrJointGetType(Joint* joint);