mirror of https://github.com/bjornbytes/lovr.git
Custom collision handling;
This commit is contained in:
parent
e6b8d0adea
commit
661e9188c7
|
@ -2,6 +2,7 @@
|
||||||
#include "filesystem/blob.h"
|
#include "filesystem/blob.h"
|
||||||
#include "graphics/mesh.h"
|
#include "graphics/mesh.h"
|
||||||
#include "math/math.h"
|
#include "math/math.h"
|
||||||
|
#include "physics/physics.h"
|
||||||
#include "lib/map/map.h"
|
#include "lib/map/map.h"
|
||||||
|
|
||||||
int l_lovrAudioInit(lua_State* L);
|
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);
|
void luax_checkmeshformat(lua_State* L, int index, MeshFormat* format);
|
||||||
int luax_readtransform(lua_State* L, int index, mat4 transform);
|
int luax_readtransform(lua_State* L, int index, mat4 transform);
|
||||||
Blob* luax_readblob(lua_State* L, int index, const char* debug);
|
Blob* luax_readblob(lua_State* L, int index, const char* debug);
|
||||||
|
int luax_pushshape(lua_State* L, Shape* shape);
|
||||||
|
|
|
@ -1,6 +1,15 @@
|
||||||
#include "api/lovr.h"
|
#include "api/lovr.h"
|
||||||
#include "physics/physics.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) {
|
int l_lovrShapeGetType(lua_State* L) {
|
||||||
Shape* shape = luax_checktypeof(L, 1, Shape);
|
Shape* shape = luax_checktypeof(L, 1, Shape);
|
||||||
luax_pushenum(L, &ShapeTypes, lovrShapeGetType(shape));
|
luax_pushenum(L, &ShapeTypes, lovrShapeGetType(shape));
|
||||||
|
|
|
@ -1,6 +1,27 @@
|
||||||
#include "api/lovr.h"
|
#include "api/lovr.h"
|
||||||
#include "physics/physics.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) {
|
int l_lovrWorldGetGravity(lua_State* L) {
|
||||||
World* world = luax_checktype(L, 1, World);
|
World* world = luax_checktype(L, 1, World);
|
||||||
float x, y, z;
|
float x, y, z;
|
||||||
|
@ -68,12 +89,35 @@ int l_lovrWorldSetSleepingAllowed(lua_State* L) {
|
||||||
}
|
}
|
||||||
|
|
||||||
int l_lovrWorldUpdate(lua_State* L) {
|
int l_lovrWorldUpdate(lua_State* L) {
|
||||||
|
lua_settop(L, 3);
|
||||||
World* world = luax_checktype(L, 1, World);
|
World* world = luax_checktype(L, 1, World);
|
||||||
float dt = luaL_checknumber(L, 2);
|
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;
|
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[] = {
|
const luaL_Reg lovrWorld[] = {
|
||||||
{ "getGravity", l_lovrWorldGetGravity },
|
{ "getGravity", l_lovrWorldGetGravity },
|
||||||
{ "setGravity", l_lovrWorldSetGravity },
|
{ "setGravity", l_lovrWorldSetGravity },
|
||||||
|
@ -84,5 +128,8 @@ const luaL_Reg lovrWorld[] = {
|
||||||
{ "isSleepingAllowed", l_lovrWorldIsSleepingAllowed },
|
{ "isSleepingAllowed", l_lovrWorldIsSleepingAllowed },
|
||||||
{ "setSleepingAllowed", l_lovrWorldSetSleepingAllowed },
|
{ "setSleepingAllowed", l_lovrWorldSetSleepingAllowed },
|
||||||
{ "update", l_lovrWorldUpdate },
|
{ "update", l_lovrWorldUpdate },
|
||||||
|
{ "computeOverlaps", l_lovrWorldComputeOverlaps },
|
||||||
|
{ "overlaps", l_lovrWorldOverlaps },
|
||||||
|
{ "collide", l_lovrWorldCollide },
|
||||||
{ NULL, NULL }
|
{ NULL, NULL }
|
||||||
};
|
};
|
||||||
|
|
|
@ -2,31 +2,14 @@
|
||||||
#include "math/quat.h"
|
#include "math/quat.h"
|
||||||
#include <stdlib.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;
|
World* world = data;
|
||||||
|
vec_push(&world->overlaps, dGeomGetData(shapeA));
|
||||||
dBodyID bodyA = dGeomGetBody(shapeA);
|
vec_push(&world->overlaps, dGeomGetData(shapeB));
|
||||||
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);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void lovrPhysicsInit() {
|
void lovrPhysicsInit() {
|
||||||
|
@ -51,6 +34,7 @@ World* lovrWorldCreate() {
|
||||||
world->space = dHashSpaceCreate(0);
|
world->space = dHashSpaceCreate(0);
|
||||||
dHashSpaceSetLevels(world->space, -4, 8);
|
dHashSpaceSetLevels(world->space, -4, 8);
|
||||||
world->contactGroup = dJointGroupCreate(0);
|
world->contactGroup = dJointGroupCreate(0);
|
||||||
|
vec_init(&world->overlaps);
|
||||||
|
|
||||||
return world;
|
return world;
|
||||||
}
|
}
|
||||||
|
@ -58,6 +42,7 @@ World* lovrWorldCreate() {
|
||||||
void lovrWorldDestroy(const Ref* ref) {
|
void lovrWorldDestroy(const Ref* ref) {
|
||||||
World* world = containerof(ref, World);
|
World* world = containerof(ref, World);
|
||||||
dWorldDestroy(world->id);
|
dWorldDestroy(world->id);
|
||||||
|
vec_deinit(&world->overlaps);
|
||||||
free(world);
|
free(world);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -101,12 +86,55 @@ void lovrWorldSetSleepingAllowed(World* world, int allowed) {
|
||||||
dWorldSetAutoDisableFlag(world->id, allowed);
|
dWorldSetAutoDisableFlag(world->id, allowed);
|
||||||
}
|
}
|
||||||
|
|
||||||
void lovrWorldUpdate(World* world, float dt) {
|
void lovrWorldUpdate(World* world, float dt, CollisionResolver resolver, void* userdata) {
|
||||||
dSpaceCollide(world->space, world, nearCallback);
|
if (resolver) {
|
||||||
|
resolver(world, userdata);
|
||||||
|
} else {
|
||||||
|
dSpaceCollide(world->space, world, defaultNearCallback);
|
||||||
|
}
|
||||||
|
|
||||||
dWorldQuickStep(world->id, dt);
|
dWorldQuickStep(world->id, dt);
|
||||||
dJointGroupEmpty(world->contactGroup);
|
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) {
|
Body* lovrBodyCreate(World* world) {
|
||||||
if (!world) {
|
if (!world) {
|
||||||
error("No world specified");
|
error("No world specified");
|
||||||
|
@ -117,6 +145,7 @@ Body* lovrBodyCreate(World* world) {
|
||||||
|
|
||||||
body->id = dBodyCreate(world->id);
|
body->id = dBodyCreate(world->id);
|
||||||
body->world = world;
|
body->world = world;
|
||||||
|
dBodySetData(body->id, body);
|
||||||
|
|
||||||
return body;
|
return body;
|
||||||
}
|
}
|
||||||
|
@ -287,11 +316,11 @@ void lovrBodySetAwake(Body* body, int awake) {
|
||||||
}
|
}
|
||||||
|
|
||||||
void* lovrBodyGetUserData(Body* body) {
|
void* lovrBodyGetUserData(Body* body) {
|
||||||
return dBodyGetData(body->id);
|
return body->userdata;
|
||||||
}
|
}
|
||||||
|
|
||||||
void lovrBodySetUserData(Body* body, void* data) {
|
void lovrBodySetUserData(Body* body, void* data) {
|
||||||
dBodySetData(body->id, data);
|
body->userdata = data;
|
||||||
}
|
}
|
||||||
|
|
||||||
World* lovrBodyGetWorld(Body* body) {
|
World* lovrBodyGetWorld(Body* body) {
|
||||||
|
@ -380,11 +409,11 @@ void lovrShapeSetEnabled(Shape* shape, int enabled) {
|
||||||
}
|
}
|
||||||
|
|
||||||
void* lovrShapeGetUserData(Shape* shape) {
|
void* lovrShapeGetUserData(Shape* shape) {
|
||||||
return dGeomGetData(shape->id);
|
return shape->userdata;
|
||||||
}
|
}
|
||||||
|
|
||||||
void lovrShapeSetUserData(Shape* shape, void* data) {
|
void lovrShapeSetUserData(Shape* shape, void* data) {
|
||||||
dGeomSetData(shape->id, data);
|
shape->userdata = data;
|
||||||
}
|
}
|
||||||
|
|
||||||
void lovrShapeGetPosition(Shape* shape, float* x, float* y, float* z) {
|
void lovrShapeGetPosition(Shape* shape, float* x, float* y, float* z) {
|
||||||
|
@ -487,6 +516,7 @@ SphereShape* lovrSphereShapeCreate(float radius) {
|
||||||
|
|
||||||
sphere->type = SHAPE_SPHERE;
|
sphere->type = SHAPE_SPHERE;
|
||||||
sphere->id = dCreateSphere(0, radius);
|
sphere->id = dCreateSphere(0, radius);
|
||||||
|
dGeomSetData(sphere->id, sphere);
|
||||||
|
|
||||||
return sphere;
|
return sphere;
|
||||||
}
|
}
|
||||||
|
@ -505,6 +535,7 @@ BoxShape* lovrBoxShapeCreate(float x, float y, float z) {
|
||||||
|
|
||||||
box->type = SHAPE_BOX;
|
box->type = SHAPE_BOX;
|
||||||
box->id = dCreateBox(0, x, y, z);
|
box->id = dCreateBox(0, x, y, z);
|
||||||
|
dGeomSetData(box->id, box);
|
||||||
|
|
||||||
return box;
|
return box;
|
||||||
}
|
}
|
||||||
|
@ -527,6 +558,7 @@ CapsuleShape* lovrCapsuleShapeCreate(float radius, float length) {
|
||||||
|
|
||||||
capsule->type = SHAPE_CAPSULE;
|
capsule->type = SHAPE_CAPSULE;
|
||||||
capsule->id = dCreateCapsule(0, radius, length);
|
capsule->id = dCreateCapsule(0, radius, length);
|
||||||
|
dGeomSetData(capsule->id, capsule);
|
||||||
|
|
||||||
return capsule;
|
return capsule;
|
||||||
}
|
}
|
||||||
|
@ -557,6 +589,7 @@ CylinderShape* lovrCylinderShapeCreate(float radius, float length) {
|
||||||
|
|
||||||
cylinder->type = SHAPE_CYLINDER;
|
cylinder->type = SHAPE_CYLINDER;
|
||||||
cylinder->id = dCreateCylinder(0, radius, length);
|
cylinder->id = dCreateCylinder(0, radius, length);
|
||||||
|
dGeomSetData(cylinder->id, cylinder);
|
||||||
|
|
||||||
return cylinder;
|
return cylinder;
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,7 +1,12 @@
|
||||||
#include "util.h"
|
#include "util.h"
|
||||||
|
#include "lib/vec/vec.h"
|
||||||
#include <stdint.h>
|
#include <stdint.h>
|
||||||
#include <ode/ode.h>
|
#include <ode/ode.h>
|
||||||
|
|
||||||
|
#pragma once
|
||||||
|
|
||||||
|
#define MAX_CONTACTS 4
|
||||||
|
|
||||||
typedef enum {
|
typedef enum {
|
||||||
SHAPE_SPHERE,
|
SHAPE_SPHERE,
|
||||||
SHAPE_BOX,
|
SHAPE_BOX,
|
||||||
|
@ -14,12 +19,14 @@ typedef struct {
|
||||||
dWorldID id;
|
dWorldID id;
|
||||||
dSpaceID space;
|
dSpaceID space;
|
||||||
dJointGroupID contactGroup;
|
dJointGroupID contactGroup;
|
||||||
|
vec_void_t overlaps;
|
||||||
} World;
|
} World;
|
||||||
|
|
||||||
typedef struct {
|
typedef struct {
|
||||||
Ref ref;
|
Ref ref;
|
||||||
dBodyID id;
|
dBodyID id;
|
||||||
World* world;
|
World* world;
|
||||||
|
void* userdata;
|
||||||
} Body;
|
} Body;
|
||||||
|
|
||||||
typedef struct {
|
typedef struct {
|
||||||
|
@ -27,6 +34,7 @@ typedef struct {
|
||||||
ShapeType type;
|
ShapeType type;
|
||||||
dGeomID id;
|
dGeomID id;
|
||||||
Body* body;
|
Body* body;
|
||||||
|
void* userdata;
|
||||||
} Shape;
|
} Shape;
|
||||||
|
|
||||||
typedef Shape SphereShape;
|
typedef Shape SphereShape;
|
||||||
|
@ -34,6 +42,8 @@ typedef Shape BoxShape;
|
||||||
typedef Shape CapsuleShape;
|
typedef Shape CapsuleShape;
|
||||||
typedef Shape CylinderShape;
|
typedef Shape CylinderShape;
|
||||||
|
|
||||||
|
typedef void (*CollisionResolver)(World* world, void* userdata);
|
||||||
|
|
||||||
void lovrPhysicsInit();
|
void lovrPhysicsInit();
|
||||||
void lovrPhysicsDestroy();
|
void lovrPhysicsDestroy();
|
||||||
|
|
||||||
|
@ -47,7 +57,10 @@ void lovrWorldGetAngularDamping(World* world, float* damping, float* threshold);
|
||||||
void lovrWorldSetAngularDamping(World* world, float damping, float threshold);
|
void lovrWorldSetAngularDamping(World* world, float damping, float threshold);
|
||||||
int lovrWorldIsSleepingAllowed(World* world);
|
int lovrWorldIsSleepingAllowed(World* world);
|
||||||
void lovrWorldSetSleepingAllowed(World* world, int allowed);
|
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();
|
Body* lovrBodyCreate();
|
||||||
void lovrBodyDestroy(const Ref* ref);
|
void lovrBodyDestroy(const Ref* ref);
|
||||||
|
|
Loading…
Reference in New Issue