Support for trimesh shape colliders

This commit is contained in:
Josip Miskovic 2020-09-13 12:34:36 +02:00
parent 61abb6f02b
commit 75591fde42
7 changed files with 80 additions and 3 deletions

2
deps/ode vendored

@ -1 +1 @@
Subproject commit b85a951862d13d1f731daaf960249ebbbe12730f
Subproject commit dbc457549169d04fa6baece760d052133ac2e3ba

View File

@ -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[];

View File

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

View File

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

View File

@ -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 },

View File

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

View File

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