Custom collision handling;

This commit is contained in:
bjorn 2017-05-19 15:04:34 -06:00
parent e6b8d0adea
commit 661e9188c7
5 changed files with 136 additions and 32 deletions

View File

@ -2,6 +2,7 @@
#include "filesystem/blob.h"
#include "graphics/mesh.h"
#include "math/math.h"
#include "physics/physics.h"
#include "lib/map/map.h"
int l_lovrAudioInit(lua_State* L);
@ -62,3 +63,4 @@ extern map_int_t WrapModes;
void luax_checkmeshformat(lua_State* L, int index, MeshFormat* format);
int luax_readtransform(lua_State* L, int index, mat4 transform);
Blob* luax_readblob(lua_State* L, int index, const char* debug);
int luax_pushshape(lua_State* L, Shape* shape);

View File

@ -1,6 +1,15 @@
#include "api/lovr.h"
#include "physics/physics.h"
int luax_pushshape(lua_State* L, Shape* shape) {
switch (lovrShapeGetType(shape)) {
case SHAPE_SPHERE: luax_pushtype(L, SphereShape, shape); return 1;
case SHAPE_BOX: luax_pushtype(L, BoxShape, shape); return 1;
case SHAPE_CAPSULE: luax_pushtype(L, CapsuleShape, shape); return 1;
case SHAPE_CYLINDER: luax_pushtype(L, CylinderShape, shape); return 1;
}
}
int l_lovrShapeGetType(lua_State* L) {
Shape* shape = luax_checktypeof(L, 1, Shape);
luax_pushenum(L, &ShapeTypes, lovrShapeGetType(shape));

View File

@ -1,6 +1,27 @@
#include "api/lovr.h"
#include "physics/physics.h"
static void collisionResolver(World* world, void* userdata) {
lua_State* L = userdata;
luaL_checktype(L, -1, LUA_TFUNCTION);
luax_pushtype(L, World, world);
lua_call(L, 1, 0);
}
static int nextOverlap(lua_State* L) {
World* world = luax_checktype(L, lua_upvalueindex(1), World);
Shape* a;
Shape* b;
if (lovrWorldGetNextOverlap(world, &a, &b)) {
luax_pushshape(L, a);
luax_pushshape(L, b);
return 2;
} else {
lua_pushnil(L);
return 1;
}
}
int l_lovrWorldGetGravity(lua_State* L) {
World* world = luax_checktype(L, 1, World);
float x, y, z;
@ -68,12 +89,35 @@ int l_lovrWorldSetSleepingAllowed(lua_State* L) {
}
int l_lovrWorldUpdate(lua_State* L) {
lua_settop(L, 3);
World* world = luax_checktype(L, 1, World);
float dt = luaL_checknumber(L, 2);
lovrWorldUpdate(world, dt);
CollisionResolver resolver = lua_type(L, 3) == LUA_TFUNCTION ? collisionResolver : NULL;
lovrWorldUpdate(world, dt, resolver, L);
return 0;
}
int l_lovrWorldComputeOverlaps(lua_State* L) {
World* world = luax_checktype(L, 1, World);
lovrWorldComputeOverlaps(world);
return 0;
}
int l_lovrWorldOverlaps(lua_State* L) {
luax_checktype(L, 1, World);
lua_settop(L, 1);
lua_pushcclosure(L, nextOverlap, 1);
return 1;
}
int l_lovrWorldCollide(lua_State* L) {
World* world = luax_checktype(L, 1, World);
Shape* a = luax_checktypeof(L, 2, Shape);
Shape* b = luax_checktypeof(L, 3, Shape);
lua_pushboolean(L, lovrWorldCollide(world, a, b));
return 1;
}
const luaL_Reg lovrWorld[] = {
{ "getGravity", l_lovrWorldGetGravity },
{ "setGravity", l_lovrWorldSetGravity },
@ -84,5 +128,8 @@ const luaL_Reg lovrWorld[] = {
{ "isSleepingAllowed", l_lovrWorldIsSleepingAllowed },
{ "setSleepingAllowed", l_lovrWorldSetSleepingAllowed },
{ "update", l_lovrWorldUpdate },
{ "computeOverlaps", l_lovrWorldComputeOverlaps },
{ "overlaps", l_lovrWorldOverlaps },
{ "collide", l_lovrWorldCollide },
{ NULL, NULL }
};

View File

@ -2,31 +2,14 @@
#include "math/quat.h"
#include <stdlib.h>
static void nearCallback(void* data, dGeomID shapeA, dGeomID shapeB) {
static void defaultNearCallback(void* data, dGeomID a, dGeomID b) {
lovrWorldCollide((World*) data, dGeomGetData(a), dGeomGetData(b));
}
static void customNearCallback(void* data, dGeomID shapeA, dGeomID shapeB) {
World* world = data;
dBodyID bodyA = dGeomGetBody(shapeA);
dBodyID bodyB = dGeomGetBody(shapeB);
if (bodyA && bodyB && dAreConnectedExcluding(bodyA, bodyB, dJointTypeContact)) {
return;
}
dContact contacts[8];
for (int i = 0; i < 8; i++) {
contacts[i].surface.mode = 0;
contacts[i].surface.mu = dInfinity;
contacts[i].surface.mu2 = 0;
}
int contactCount;
contactCount = dCollide(shapeA, shapeB, 8, &contacts[0].geom, sizeof(dContact));
for (int i = 0; i < contactCount; i++) {
dJointID joint = dJointCreateContact(world->id, world->contactGroup, &contacts[i]);
dJointAttach(joint, bodyA, bodyB);
}
vec_push(&world->overlaps, dGeomGetData(shapeA));
vec_push(&world->overlaps, dGeomGetData(shapeB));
}
void lovrPhysicsInit() {
@ -51,6 +34,7 @@ World* lovrWorldCreate() {
world->space = dHashSpaceCreate(0);
dHashSpaceSetLevels(world->space, -4, 8);
world->contactGroup = dJointGroupCreate(0);
vec_init(&world->overlaps);
return world;
}
@ -58,6 +42,7 @@ World* lovrWorldCreate() {
void lovrWorldDestroy(const Ref* ref) {
World* world = containerof(ref, World);
dWorldDestroy(world->id);
vec_deinit(&world->overlaps);
free(world);
}
@ -101,12 +86,55 @@ void lovrWorldSetSleepingAllowed(World* world, int allowed) {
dWorldSetAutoDisableFlag(world->id, allowed);
}
void lovrWorldUpdate(World* world, float dt) {
dSpaceCollide(world->space, world, nearCallback);
void lovrWorldUpdate(World* world, float dt, CollisionResolver resolver, void* userdata) {
if (resolver) {
resolver(world, userdata);
} else {
dSpaceCollide(world->space, world, defaultNearCallback);
}
dWorldQuickStep(world->id, dt);
dJointGroupEmpty(world->contactGroup);
}
void lovrWorldComputeOverlaps(World* world) {
vec_clear(&world->overlaps);
dSpaceCollide(world->space, world, customNearCallback);
}
int lovrWorldGetNextOverlap(World* world, Shape** a, Shape** b) {
if (world->overlaps.length == 0) {
*a = *b = NULL;
return 0;
}
*a = vec_pop(&world->overlaps);
*b = vec_pop(&world->overlaps);
return 1;
}
int lovrWorldCollide(World* world, Shape* a, Shape* b) {
if (!a || !b) {
return 0;
}
dContact contacts[MAX_CONTACTS];
for (int i = 0; i < MAX_CONTACTS; i++) {
contacts[i].surface.mode = 0;
contacts[i].surface.mu = dInfinity;
}
int contactCount = dCollide(a->id, b->id, MAX_CONTACTS, &contacts[0].geom, sizeof(dContact));
for (int i = 0; i < contactCount; i++) {
dJointID joint = dJointCreateContact(world->id, world->contactGroup, &contacts[i]);
dJointAttach(joint, a->body->id, b->body->id);
}
return contactCount;
}
Body* lovrBodyCreate(World* world) {
if (!world) {
error("No world specified");
@ -117,6 +145,7 @@ Body* lovrBodyCreate(World* world) {
body->id = dBodyCreate(world->id);
body->world = world;
dBodySetData(body->id, body);
return body;
}
@ -287,11 +316,11 @@ void lovrBodySetAwake(Body* body, int awake) {
}
void* lovrBodyGetUserData(Body* body) {
return dBodyGetData(body->id);
return body->userdata;
}
void lovrBodySetUserData(Body* body, void* data) {
dBodySetData(body->id, data);
body->userdata = data;
}
World* lovrBodyGetWorld(Body* body) {
@ -380,11 +409,11 @@ void lovrShapeSetEnabled(Shape* shape, int enabled) {
}
void* lovrShapeGetUserData(Shape* shape) {
return dGeomGetData(shape->id);
return shape->userdata;
}
void lovrShapeSetUserData(Shape* shape, void* data) {
dGeomSetData(shape->id, data);
shape->userdata = data;
}
void lovrShapeGetPosition(Shape* shape, float* x, float* y, float* z) {
@ -487,6 +516,7 @@ SphereShape* lovrSphereShapeCreate(float radius) {
sphere->type = SHAPE_SPHERE;
sphere->id = dCreateSphere(0, radius);
dGeomSetData(sphere->id, sphere);
return sphere;
}
@ -505,6 +535,7 @@ BoxShape* lovrBoxShapeCreate(float x, float y, float z) {
box->type = SHAPE_BOX;
box->id = dCreateBox(0, x, y, z);
dGeomSetData(box->id, box);
return box;
}
@ -527,6 +558,7 @@ CapsuleShape* lovrCapsuleShapeCreate(float radius, float length) {
capsule->type = SHAPE_CAPSULE;
capsule->id = dCreateCapsule(0, radius, length);
dGeomSetData(capsule->id, capsule);
return capsule;
}
@ -557,6 +589,7 @@ CylinderShape* lovrCylinderShapeCreate(float radius, float length) {
cylinder->type = SHAPE_CYLINDER;
cylinder->id = dCreateCylinder(0, radius, length);
dGeomSetData(cylinder->id, cylinder);
return cylinder;
}

View File

@ -1,7 +1,12 @@
#include "util.h"
#include "lib/vec/vec.h"
#include <stdint.h>
#include <ode/ode.h>
#pragma once
#define MAX_CONTACTS 4
typedef enum {
SHAPE_SPHERE,
SHAPE_BOX,
@ -14,12 +19,14 @@ typedef struct {
dWorldID id;
dSpaceID space;
dJointGroupID contactGroup;
vec_void_t overlaps;
} World;
typedef struct {
Ref ref;
dBodyID id;
World* world;
void* userdata;
} Body;
typedef struct {
@ -27,6 +34,7 @@ typedef struct {
ShapeType type;
dGeomID id;
Body* body;
void* userdata;
} Shape;
typedef Shape SphereShape;
@ -34,6 +42,8 @@ typedef Shape BoxShape;
typedef Shape CapsuleShape;
typedef Shape CylinderShape;
typedef void (*CollisionResolver)(World* world, void* userdata);
void lovrPhysicsInit();
void lovrPhysicsDestroy();
@ -47,7 +57,10 @@ void lovrWorldGetAngularDamping(World* world, float* damping, float* threshold);
void lovrWorldSetAngularDamping(World* world, float damping, float threshold);
int lovrWorldIsSleepingAllowed(World* world);
void lovrWorldSetSleepingAllowed(World* world, int allowed);
void lovrWorldUpdate(World* world, float dt);
void lovrWorldUpdate(World* world, float dt, CollisionResolver resolver, void* userdata);
void lovrWorldComputeOverlaps(World* world);
int lovrWorldGetNextOverlap(World* world, Shape** a, Shape** b);
int lovrWorldCollide(World* world, Shape* a, Shape* b);
Body* lovrBodyCreate();
void lovrBodyDestroy(const Ref* ref);