diff --git a/src/api/api.c b/src/api/api.c index 8c6f7ca3..05bc2260 100644 --- a/src/api/api.c +++ b/src/api/api.c @@ -515,18 +515,13 @@ void luax_optcolor(lua_State* L, int index, float color[4]) { int luax_readmesh(lua_State* L, int index, float** vertices, uint32_t* vertexCount, uint32_t** indices, uint32_t* indexCount, bool* shouldFree) { if (lua_istable(L, index)) { - luaL_checktype(L, index + 1, LUA_TTABLE); lua_rawgeti(L, index, 1); bool nested = lua_type(L, -1) == LUA_TTABLE; lua_pop(L, 1); *vertexCount = luax_len(L, index) / (nested ? 1 : 3); - *indexCount = luax_len(L, index + 1); lovrCheck(*vertexCount > 0, "Invalid mesh data: vertex count is zero"); - lovrCheck(*indexCount > 0, "Invalid mesh data: index count is zero"); - lovrCheck(*indexCount % 3 == 0, "Index count must be a multiple of 3"); *vertices = lovrMalloc(sizeof(float) * *vertexCount * 3); - *indices = lovrMalloc(sizeof(uint32_t) * *indexCount); *shouldFree = true; if (nested) { @@ -548,17 +543,33 @@ int luax_readmesh(lua_State* L, int index, float** vertices, uint32_t* vertexCou } } - for (uint32_t i = 0; i < *indexCount; i++) { - lua_rawgeti(L, index + 1, i + 1); - uint32_t index = luaL_checkinteger(L, -1) - 1; - lovrCheck(index < *vertexCount, "Invalid vertex index %d (expected [%d, %d])", index + 1, 1, *vertexCount); - (*indices)[i] = index; - lua_pop(L, 1); + if (indices) { + luaL_checktype(L, index + 1, LUA_TTABLE); + *indexCount = luax_len(L, index + 1); + lovrCheck(*indexCount > 0, "Invalid mesh data: index count is zero"); + lovrCheck(*indexCount % 3 == 0, "Index count must be a multiple of 3"); + *indices = lovrMalloc(sizeof(uint32_t) * *indexCount); + + for (uint32_t i = 0; i < *indexCount; i++) { + lua_rawgeti(L, index + 1, i + 1); + uint32_t index = luaL_checkinteger(L, -1) - 1; + lovrCheck(index < *vertexCount, "Invalid vertex index %d (expected [%d, %d])", index + 1, 1, *vertexCount); + (*indices)[i] = index; + lua_pop(L, 1); + } } return index + 2; } + ModelData* modelData = luax_totype(L, index, ModelData); + + if (modelData) { + lovrModelDataGetTriangles(modelData, vertices, indices, vertexCount, indexCount); + *shouldFree = false; + return index + 1; + } + #ifndef LOVR_DISABLE_GRAPHICS Model* model = luax_totype(L, index, Model); @@ -576,7 +587,9 @@ int luax_readmesh(lua_State* L, int index, float** vertices, uint32_t* vertexCou *shouldFree = true; return index + 1; } -#endif - return luaL_argerror(L, index, "table, Mesh, or Model"); + return luaL_argerror(L, index, "table, ModelData, Model, or Mesh expected"); +#else + return luaL_argerror(L, index, "table or ModelData expected"); +#endif } diff --git a/src/api/api.h b/src/api/api.h index 5593edf2..2c2937c1 100644 --- a/src/api/api.h +++ b/src/api/api.h @@ -201,6 +201,7 @@ struct Shape* luax_newsphereshape(lua_State* L, int index); struct Shape* luax_newboxshape(lua_State* L, int index); struct Shape* luax_newcapsuleshape(lua_State* L, int index); struct Shape* luax_newcylindershape(lua_State* L, int index); +struct Shape* luax_newconvexshape(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_newcompoundshape(lua_State* L, int index); diff --git a/src/api/l_physics.c b/src/api/l_physics.c index 12b0bf82..4c114e02 100644 --- a/src/api/l_physics.c +++ b/src/api/l_physics.c @@ -7,6 +7,7 @@ StringEntry lovrShapeType[] = { [SHAPE_BOX] = ENTRY("box"), [SHAPE_CAPSULE] = ENTRY("capsule"), [SHAPE_CYLINDER] = ENTRY("cylinder"), + [SHAPE_CONVEX] = ENTRY("convex"), [SHAPE_MESH] = ENTRY("mesh"), [SHAPE_TERRAIN] = ENTRY("terrain"), [SHAPE_COMPOUND] = ENTRY("compound"), @@ -121,6 +122,13 @@ static int l_lovrPhysicsNewCapsuleShape(lua_State* L) { return 1; } +static int l_lovrPhysicsNewConvexShape(lua_State* L) { + ConvexShape* convex = luax_newconvexshape(L, 1); + luax_pushtype(L, ConvexShape, convex); + lovrRelease(convex, lovrShapeDestroy); + return 1; +} + static int l_lovrPhysicsNewCylinderShape(lua_State* L) { CylinderShape* cylinder = luax_newcylindershape(L, 1); luax_pushtype(L, CylinderShape, cylinder); @@ -196,6 +204,7 @@ static const luaL_Reg lovrPhysics[] = { { "newBallJoint", l_lovrPhysicsNewBallJoint }, { "newBoxShape", l_lovrPhysicsNewBoxShape }, { "newCapsuleShape", l_lovrPhysicsNewCapsuleShape }, + { "newConvexShape", l_lovrPhysicsNewConvexShape }, { "newCylinderShape", l_lovrPhysicsNewCylinderShape }, { "newDistanceJoint", l_lovrPhysicsNewDistanceJoint }, { "newHingeJoint", l_lovrPhysicsNewHingeJoint }, @@ -217,6 +226,7 @@ extern const luaL_Reg lovrSphereShape[]; extern const luaL_Reg lovrBoxShape[]; extern const luaL_Reg lovrCapsuleShape[]; extern const luaL_Reg lovrCylinderShape[]; +extern const luaL_Reg lovrConvexShape[]; extern const luaL_Reg lovrMeshShape[]; extern const luaL_Reg lovrTerrainShape[]; extern const luaL_Reg lovrCompoundShape[]; @@ -234,6 +244,7 @@ int luaopen_lovr_physics(lua_State* L) { luax_registertype(L, BoxShape); luax_registertype(L, CapsuleShape); luax_registertype(L, CylinderShape); + luax_registertype(L, ConvexShape); luax_registertype(L, MeshShape); luax_registertype(L, TerrainShape); luax_registertype(L, CompoundShape); diff --git a/src/api/l_physics_shapes.c b/src/api/l_physics_shapes.c index f2638af1..d923d7fd 100644 --- a/src/api/l_physics_shapes.c +++ b/src/api/l_physics_shapes.c @@ -12,6 +12,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_CONVEX: luax_pushtype(L, ConvexShape, shape); break; case SHAPE_MESH: luax_pushtype(L, MeshShape, shape); break; case SHAPE_TERRAIN: luax_pushtype(L, TerrainShape, shape); break; case SHAPE_COMPOUND: luax_pushtype(L, CompoundShape, shape); break; @@ -28,6 +29,7 @@ Shape* luax_checkshape(lua_State* L, int index) { hash64("BoxShape", strlen("BoxShape")), hash64("CapsuleShape", strlen("CapsuleShape")), hash64("CylinderShape", strlen("CylinderShape")), + hash64("ConvexShape", strlen("ConvexShape")), hash64("MeshShape", strlen("MeshShape")), hash64("TerrainShape", strlen("TerrainShape")), hash64("CompoundShape", strlen("CompoundShape")) @@ -67,6 +69,16 @@ Shape* luax_newcylindershape(lua_State* L, int index) { return lovrCylinderShapeCreate(radius, length); } +Shape* luax_newconvexshape(lua_State* L, int index) { + float* points; + uint32_t count; + bool shouldFree; + luax_readmesh(L, index, &points, &count, NULL, NULL, &shouldFree); + ConvexShape* shape = lovrConvexShapeCreate(points, count); + if (shouldFree) lovrFree(points); + return shape; +} + Shape* luax_newmeshshape(lua_State* L, int index) { float* vertices; uint32_t* indices; @@ -371,6 +383,11 @@ const luaL_Reg lovrCylinderShape[] = { { NULL, NULL } }; +const luaL_Reg lovrConvexShape[] = { + lovrShape, + { 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 0a23fc12..6f7f057a 100644 --- a/src/api/l_physics_world.c +++ b/src/api/l_physics_world.c @@ -150,6 +150,19 @@ static int l_lovrWorldNewCylinderCollider(lua_State* L) { return 1; } +static int l_lovrWorldNewConvexCollider(lua_State* L) { + World* world = luax_checktype(L, 1, World); + float position[3]; + int index = luax_readvec3(L, 2, position, NULL); + ConvexShape* shape = luax_newconvexshape(L, index); + Collider* collider = lovrColliderCreate(world, shape, position); + lovrColliderInitInertia(collider, shape); + luax_pushtype(L, Collider, collider); + lovrRelease(collider, lovrColliderDestroy); + lovrRelease(shape, lovrShapeDestroy); + return 1; +} + static int l_lovrWorldNewSphereCollider(lua_State* L) { World* world = luax_checktype(L, 1, World); float position[3]; @@ -530,6 +543,7 @@ const luaL_Reg lovrWorld[] = { { "newBoxCollider", l_lovrWorldNewBoxCollider }, { "newCapsuleCollider", l_lovrWorldNewCapsuleCollider }, { "newCylinderCollider", l_lovrWorldNewCylinderCollider }, + { "newConvexCollider", l_lovrWorldNewConvexCollider }, { "newSphereCollider", l_lovrWorldNewSphereCollider }, { "newMeshCollider", l_lovrWorldNewMeshCollider }, { "newTerrainCollider", l_lovrWorldNewTerrainCollider }, diff --git a/src/modules/data/modelData.c b/src/modules/data/modelData.c index 729864d4..8b08d0a1 100644 --- a/src/modules/data/modelData.c +++ b/src/modules/data/modelData.c @@ -527,7 +527,7 @@ static void collectVertices(ModelData* model, uint32_t nodeIndex, float** vertic *baseIndex += positions->count; } - if (index) { + if (indices && index) { lovrAssert(index->type == U16 || index->type == U32, "Unreachable"); char* data = (char*) model->buffers[index->buffer].data + index->offset; @@ -558,19 +558,18 @@ void lovrModelDataGetTriangles(ModelData* model, float** vertices, uint32_t** in } if (vertices && !model->vertices) { + uint32_t* tempIndices; uint32_t baseIndex = 0; model->vertices = lovrMalloc(model->totalVertexCount * 3 * sizeof(float)); model->indices = lovrMalloc(model->totalIndexCount * sizeof(uint32_t)); *vertices = model->vertices; - *indices = model->indices; - collectVertices(model, model->rootNode, vertices, indices, &baseIndex, (float[16]) MAT4_IDENTITY); + tempIndices = model->indices; + collectVertices(model, model->rootNode, vertices, &tempIndices, &baseIndex, (float[16]) MAT4_IDENTITY); } - *vertexCount = model->totalVertexCount; - *indexCount = model->totalIndexCount; + if (vertexCount) *vertexCount = model->totalVertexCount; + if (indexCount) *indexCount = model->totalIndexCount; - if (vertices) { - *vertices = model->vertices; - *indices = model->indices; - } + if (vertices) *vertices = model->vertices; + if (indices) *indices = model->indices; } diff --git a/src/modules/physics/physics.h b/src/modules/physics/physics.h index a696c3fa..6cb5ea69 100644 --- a/src/modules/physics/physics.h +++ b/src/modules/physics/physics.h @@ -17,6 +17,7 @@ typedef Shape SphereShape; typedef Shape BoxShape; typedef Shape CapsuleShape; typedef Shape CylinderShape; +typedef Shape ConvexShape; typedef Shape MeshShape; typedef Shape TerrainShape; typedef Shape CompoundShape; @@ -157,6 +158,7 @@ typedef enum { SHAPE_BOX, SHAPE_CAPSULE, SHAPE_CYLINDER, + SHAPE_CONVEX, SHAPE_MESH, SHAPE_TERRAIN, SHAPE_COMPOUND @@ -182,6 +184,8 @@ CylinderShape* lovrCylinderShapeCreate(float radius, float length); float lovrCylinderShapeGetRadius(CylinderShape* cylinder); float lovrCylinderShapeGetLength(CylinderShape* cylinder); +ConvexShape* lovrConvexShapeCreate(float points[], uint32_t count); + MeshShape* lovrMeshShapeCreate(int vertexCount, float vertices[], int indexCount, uint32_t indices[]); TerrainShape* lovrTerrainShapeCreate(float* vertices, uint32_t n, float scaleXZ, float scaleY); @@ -201,6 +205,7 @@ void lovrCompoundShapeSetChildOffset(CompoundShape* shape, uint32_t index, float #define lovrBoxShapeDestroy lovrShapeDestroy #define lovrCapsuleShapeDestroy lovrShapeDestroy #define lovrCylinderShapeDestroy lovrShapeDestroy +#define lovrConvexShapeDestroy lovrShapeDestroy #define lovrMeshShapeDestroy lovrShapeDestroy #define lovrTerrainShapeDestroy lovrShapeDestroy #define lovrCompoundShapeDestroy lovrShapeDestroy diff --git a/src/modules/physics/physics_jolt.c b/src/modules/physics/physics_jolt.c index e8e8fb33..4b6bfdfd 100644 --- a/src/modules/physics/physics_jolt.c +++ b/src/modules/physics/physics_jolt.c @@ -915,6 +915,16 @@ float lovrCylinderShapeGetLength(CylinderShape* cylinder) { return JPH_CylinderShape_GetHalfHeight((JPH_CylinderShape*) cylinder->shape) * 2.f; } +ConvexShape* lovrConvexShapeCreate(float points[], uint32_t count) { + ConvexShape* convex = lovrCalloc(sizeof(ConvexShape)); + convex->ref = 1; + convex->type = SHAPE_CONVEX; + JPH_ConvexHullShapeSettings* settings = JPH_ConvexHullShapeSettings_Create((const JPH_Vec3*) points, count, .05f); + convex->shape = (JPH_Shape*) JPH_ConvexHullShapeSettings_CreateShape(settings); + JPH_ShapeSettings_Destroy((JPH_ShapeSettings*) settings); + return convex; +} + MeshShape* lovrMeshShapeCreate(int vertexCount, float vertices[], int indexCount, uint32_t indices[]) { MeshShape* mesh = lovrCalloc(sizeof(MeshShape)); mesh->ref = 1; diff --git a/src/modules/physics/physics_ode.c b/src/modules/physics/physics_ode.c index c44871d5..e7226af8 100644 --- a/src/modules/physics/physics_ode.c +++ b/src/modules/physics/physics_ode.c @@ -1048,6 +1048,10 @@ float lovrCylinderShapeGetLength(CylinderShape* cylinder) { return length; } +ConvexShape* lovrConvexShapeCreate(float positions[], uint32_t count) { + lovrThrow("ODE does not support ConvexShape"); +} + MeshShape* lovrMeshShapeCreate(int vertexCount, float* vertices, int indexCount, dTriIndex* indices) { MeshShape* mesh = lovrCalloc(sizeof(MeshShape)); mesh->ref = 1; @@ -1075,7 +1079,7 @@ TerrainShape* lovrTerrainShapeCreate(float* vertices, uint32_t n, float scaleXZ, } CompoundShape* lovrCompoundShapeCreate(Shape** shapes, float* positions, float* orientations, uint32_t count, bool freeze) { - lovrThrow("ODE does not support compound shape"); + lovrThrow("ODE does not support CompoundShape"); } bool lovrCompoundShapeIsFrozen(CompoundShape* shape) {