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 "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);
|
||||
|
|
|
@ -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));
|
||||
|
|
|
@ -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 }
|
||||
};
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
|
|
@ -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);
|
||||
|
|
Loading…
Reference in New Issue