Semantic tags;

This commit is contained in:
bjorn 2017-05-25 15:01:40 -07:00
parent 00142b7a74
commit 39400776dc
5 changed files with 173 additions and 5 deletions

View File

@ -33,7 +33,27 @@ int l_lovrPhysicsInit(lua_State* L) {
}
int l_lovrPhysicsNewWorld(lua_State* L) {
World* world = lovrWorldCreate();
float xg = luaL_optnumber(L, 1, 0.f);
float yg = luaL_optnumber(L, 2, -9.81);
float zg = luaL_optnumber(L, 3, 0.f);
int allowSleep = lua_gettop(L) < 4 || lua_toboolean(L, 4);
const char* tags[16];
int tagCount;
if (lua_type(L, 5) == LUA_TTABLE) {
tagCount = lua_objlen(L, 5);
for (int i = 0; i < tagCount; i++) {
lua_rawgeti(L, -1, i + 1);
if (lua_isstring(L, -1)) {
tags[i] = lua_tostring(L, -1);
} else {
return luaL_error(L, "World tags must be a table of strings");
}
lua_pop(L, 1);
}
} else {
tagCount = 0;
}
World* world = lovrWorldCreate(xg, yg, zg, allowSleep, tags, tagCount);
luax_pushtype(L, World, world);
return 1;
}

View File

@ -449,6 +449,27 @@ int l_lovrColliderSetRestitution(lua_State* L) {
return 0;
}
int l_lovrColliderGetTag(lua_State* L) {
Collider* collider = luax_checktype(L, 1, Collider);
lua_pushstring(L, lovrColliderGetTag(collider));
return 1;
}
int l_lovrColliderSetTag(lua_State* L) {
Collider* collider = luax_checktype(L, 1, Collider);
if (lua_isnoneornil(L, 2)) {
lovrColliderSetTag(collider, NULL);
return 0;
}
const char* tag = luaL_checkstring(L, 2);
if (lovrColliderSetTag(collider, tag)) {
return luaL_error(L, "Invalid tag %s", tag);
}
return 0;
}
const luaL_Reg lovrCollider[] = {
{ "destroy", l_lovrColliderDestroy },
{ "getWorld", l_lovrColliderGetWorld },
@ -495,5 +516,7 @@ const luaL_Reg lovrCollider[] = {
{ "setFriction", l_lovrColliderSetFriction },
{ "getRestitution", l_lovrColliderGetRestitution },
{ "setRestitution", l_lovrColliderSetRestitution },
{ "getTag", l_lovrColliderGetTag },
{ "setTag", l_lovrColliderSetTag },
{ NULL, NULL }
};

View File

@ -200,6 +200,30 @@ int l_lovrWorldRaycast(lua_State* L) {
return 0;
}
int l_lovrWorldDisableCollisionBetween(lua_State* L) {
World* world = luax_checktype(L, 1, World);
const char* tag1 = luaL_checkstring(L, 2);
const char* tag2 = luaL_checkstring(L, 3);
lovrWorldDisableCollisionBetween(world, tag1, tag2);
return 0;
}
int l_lovrWorldEnableCollisionBetween(lua_State* L) {
World* world = luax_checktype(L, 1, World);
const char* tag1 = luaL_checkstring(L, 2);
const char* tag2 = luaL_checkstring(L, 3);
lovrWorldEnableCollisionBetween(world, tag1, tag2);
return 0;
}
int l_lovrWorldIsCollisionEnabledBetween(lua_State* L) {
World* world = luax_checktype(L, 1, World);
const char* tag1 = luaL_checkstring(L, 2);
const char* tag2 = luaL_checkstring(L, 3);
lua_pushboolean(L, lovrWorldIsCollisionEnabledBetween(world, tag1, tag2));
return 1;
}
const luaL_Reg lovrWorld[] = {
{ "newCollider", l_lovrWorldNewCollider },
{ "newBoxCollider", l_lovrWorldNewBoxCollider },
@ -220,5 +244,8 @@ const luaL_Reg lovrWorld[] = {
{ "isSleepingAllowed", l_lovrWorldIsSleepingAllowed },
{ "setSleepingAllowed", l_lovrWorldSetSleepingAllowed },
{ "raycast", l_lovrWorldRaycast },
{ "disableCollisionBetween", l_lovrWorldDisableCollisionBetween },
{ "enableCollisionBetween", l_lovrWorldEnableCollisionBetween },
{ "isCollisionEnabledBetween", l_lovrWorldIsCollisionEnabledBetween },
{ NULL, NULL }
};

View File

@ -42,7 +42,7 @@ void lovrPhysicsDestroy() {
dCloseODE();
}
World* lovrWorldCreate() {
World* lovrWorldCreate(float xg, float yg, float zg, int allowSleep, const char** tags, int tagCount) {
World* world = lovrAlloc(sizeof(World), lovrWorldDestroy);
if (!world) return NULL;
@ -51,6 +51,16 @@ World* lovrWorldCreate() {
dHashSpaceSetLevels(world->space, -4, 8);
world->contactGroup = dJointGroupCreate(0);
vec_init(&world->overlaps);
lovrWorldSetGravity(world, xg, yg, zg);
lovrWorldSetSleepingAllowed(world, allowSleep);
map_init(&world->tags);
for (int i = 0; i < tagCount; i++) {
map_set(&world->tags, tags[i], i);
}
for (int i = 0; i < MAX_TAGS; i++) {
world->masks[i] = ~0;
}
return world;
}
@ -111,10 +121,14 @@ int lovrWorldCollide(World* world, Shape* a, Shape* b, float friction, float res
return 0;
}
dContact contacts[MAX_CONTACTS];
Collider* colliderA = a->collider;
Collider* colliderB = b->collider;
int tag1 = colliderA->tag;
int tag2 = colliderB->tag;
if (tag1 != NO_TAG && tag2 != NO_TAG && !((world->masks[tag1] & (1 << tag2)) && (world->masks[tag2] & (1 << tag1)))) {
return 0;
}
if (friction < 0) {
friction = sqrt(colliderA->friction * colliderB->friction);
@ -124,6 +138,7 @@ int lovrWorldCollide(World* world, Shape* a, Shape* b, float friction, float res
restitution = MAX(colliderA->restitution, colliderB->restitution);
}
dContact contacts[MAX_CONTACTS];
for (int i = 0; i < MAX_CONTACTS; i++) {
contacts[i].surface.mode = 0;
contacts[i].surface.mu = friction;
@ -197,6 +212,56 @@ void lovrWorldRaycast(World* world, float x1, float y1, float z1, float x2, floa
dGeomDestroy(ray);
}
const char* lovrWorldGetTagName(World* world, int tag) {
if (tag == NO_TAG) {
return NULL;
}
const char* key;
map_iter_t iter = map_iter(&world->tags);
while ((key = map_next(&world->tags, &iter))) {
if (*map_get(&world->tags, key) == tag) {
return key;
}
}
return NULL;
}
int lovrWorldDisableCollisionBetween(World* world, const char* tag1, const char* tag2) {
int* index1 = map_get(&world->tags, tag1);
int* index2 = map_get(&world->tags, tag2);
if (!index1 || !index2) {
return NO_TAG;
}
world->masks[*index1] &= ~(1 << *index2);
world->masks[*index2] &= ~(1 << *index1);
return 0;
}
int lovrWorldEnableCollisionBetween(World* world, const char* tag1, const char* tag2) {
int* index1 = map_get(&world->tags, tag1);
int* index2 = map_get(&world->tags, tag2);
if (!index1 || !index2) {
return NO_TAG;
}
world->masks[*index1] |= (1 << *index2);
world->masks[*index2] |= (1 << *index1);
return 0;
}
int lovrWorldIsCollisionEnabledBetween(World* world, const char* tag1, const char* tag2) {
int* index1 = map_get(&world->tags, tag1);
int* index2 = map_get(&world->tags, tag2);
if (!index1 || !index2) {
return NO_TAG;
}
return (world->masks[*index1] & (1 << *index2)) && (world->masks[*index2] & (1 << *index1));
}
Collider* lovrColliderCreate(World* world) {
if (!world) {
error("No world specified");
@ -209,6 +274,7 @@ Collider* lovrColliderCreate(World* world) {
collider->world = world;
collider->friction = 0;
collider->restitution = 0;
collider->tag = NO_TAG;
dBodySetData(collider->body, collider);
vec_init(&collider->shapes);
vec_init(&collider->joints);
@ -539,6 +605,26 @@ void lovrColliderGetAABB(Collider* collider, float aabb[6]) {
}
}
const char* lovrColliderGetTag(Collider* collider) {
return lovrWorldGetTagName(collider->world, collider->tag);
}
int lovrColliderSetTag(Collider* collider, const char* tag) {
if (tag == NULL) {
collider->tag = NO_TAG;
return 0;
}
int* index = map_get(&collider->world->tags, tag);
if (!index) {
return NO_TAG;
}
collider->tag = *index;
return 0;
}
void lovrShapeDestroy(const Ref* ref) {
Shape* shape = containerof(ref, Shape);
lovrShapeDestroyData(shape);

View File

@ -1,11 +1,14 @@
#include "util.h"
#include "lib/vec/vec.h"
#include "lib/map/map.h"
#include <stdint.h>
#include <ode/ode.h>
#pragma once
#define MAX_CONTACTS 4
#define MAX_TAGS 16
#define NO_TAG ~0
typedef enum {
SHAPE_SPHERE,
@ -26,6 +29,8 @@ typedef struct {
dSpaceID space;
dJointGroupID contactGroup;
vec_void_t overlaps;
map_int_t tags;
uint16_t masks[MAX_TAGS];
} World;
typedef struct {
@ -33,6 +38,7 @@ typedef struct {
dBodyID body;
World* world;
void* userdata;
int tag;
vec_void_t shapes;
vec_void_t joints;
float friction;
@ -74,7 +80,7 @@ typedef struct {
void lovrPhysicsInit();
void lovrPhysicsDestroy();
World* lovrWorldCreate();
World* lovrWorldCreate(float xg, float yg, float zg, int allowSleep, const char** tags, int tagCount);
void lovrWorldDestroy(const Ref* ref);
void lovrWorldDestroyData(World* world);
void lovrWorldUpdate(World* world, float dt, CollisionResolver resolver, void* userdata);
@ -90,6 +96,10 @@ void lovrWorldSetAngularDamping(World* world, float damping, float threshold);
int lovrWorldIsSleepingAllowed(World* world);
void lovrWorldSetSleepingAllowed(World* world, int allowed);
void lovrWorldRaycast(World* world, float x1, float y1, float z1, float x2, float y2, float z2, RaycastCallback callback, void* userdata);
const char* lovrWorldGetTagName(World* world, int tag);
int lovrWorldDisableCollisionBetween(World* world, const char* tag1, const char* tag2);
int lovrWorldEnableCollisionBetween(World* world, const char* tag1, const char* tag2);
int lovrWorldIsCollisionEnabledBetween(World* world, const char* tag1, const char* tag);
Collider* lovrColliderCreate();
void lovrColliderDestroy(const Ref* ref);
@ -140,6 +150,8 @@ float lovrColliderGetFriction(Collider* collider);
void lovrColliderSetFriction(Collider* collider, float friction);
float lovrColliderGetRestitution(Collider* collider);
void lovrColliderSetRestitution(Collider* collider, float restitution);
const char* lovrColliderGetTag(Collider* collider);
int lovrColliderSetTag(Collider* collider, const char* tag);
void lovrShapeDestroy(const Ref* ref);
void lovrShapeDestroyData(Shape* shape);