lovr/src/physics/physics.c

1073 lines
30 KiB
C
Raw Normal View History

2017-05-16 04:59:53 +00:00
#include "physics.h"
#include "lib/math.h"
2017-05-16 04:59:53 +00:00
#include <stdlib.h>
#include <stdbool.h>
2017-05-16 04:59:53 +00:00
2017-05-19 21:04:34 +00:00
static void defaultNearCallback(void* data, dGeomID a, dGeomID b) {
2017-05-25 00:39:12 +00:00
lovrWorldCollide((World*) data, dGeomGetData(a), dGeomGetData(b), -1, -1);
2017-05-19 21:04:34 +00:00
}
2017-05-17 05:12:10 +00:00
2017-05-19 21:04:34 +00:00
static void customNearCallback(void* data, dGeomID shapeA, dGeomID shapeB) {
World* world = data;
vec_push(&world->overlaps, dGeomGetData(shapeA));
vec_push(&world->overlaps, dGeomGetData(shapeB));
2017-05-17 05:12:10 +00:00
}
2017-05-25 00:40:02 +00:00
static void raycastCallback(void* data, dGeomID a, dGeomID b) {
RaycastCallback callback = ((RaycastData*) data)->callback;
void* userdata = ((RaycastData*) data)->userdata;
Shape* shape = dGeomGetData(b);
if (!shape) {
return;
}
dContact contact;
if (dCollide(a, b, MAX_CONTACTS, &contact.geom, sizeof(dContact))) {
dContactGeom g = contact.geom;
callback(shape, g.pos[0], g.pos[1], g.pos[2], g.normal[0], g.normal[1], g.normal[2], userdata);
}
}
static bool initialized = false;
bool lovrPhysicsInit() {
if (initialized) return false;
2017-05-16 04:59:53 +00:00
dInitODE();
return initialized = true;
2017-05-16 04:59:53 +00:00
}
void lovrPhysicsDestroy() {
if (!initialized) return;
2017-05-16 04:59:53 +00:00
dCloseODE();
initialized = false;
2017-05-16 04:59:53 +00:00
}
2017-05-16 05:02:08 +00:00
World* lovrWorldInit(World* world, float xg, float yg, float zg, bool allowSleep, const char** tags, int tagCount) {
2017-05-16 05:02:08 +00:00
world->id = dWorldCreate();
2017-05-17 05:12:10 +00:00
world->space = dHashSpaceCreate(0);
dHashSpaceSetLevels(world->space, -4, 8);
world->contactGroup = dJointGroupCreate(0);
2017-05-19 21:04:34 +00:00
vec_init(&world->overlaps);
2017-05-25 22:01:40 +00:00
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;
}
2017-05-16 05:02:08 +00:00
return world;
}
2018-02-26 08:59:03 +00:00
void lovrWorldDestroy(void* ref) {
World* world = ref;
2017-05-20 04:09:33 +00:00
lovrWorldDestroyData(world);
2017-05-19 21:04:34 +00:00
vec_deinit(&world->overlaps);
map_deinit(&world->tags);
2017-05-16 05:02:08 +00:00
}
2017-05-16 05:03:01 +00:00
2017-05-20 04:09:33 +00:00
void lovrWorldDestroyData(World* world) {
2018-08-22 16:29:34 +00:00
while (world->head) {
Collider* next = world->head->next;
lovrColliderDestroyData(world->head);
world->head = next;
}
2017-05-20 04:09:33 +00:00
if (world->contactGroup) {
2018-08-22 16:29:34 +00:00
dJointGroupDestroy(world->contactGroup);
2017-05-20 04:09:33 +00:00
world->contactGroup = NULL;
}
2017-05-20 04:09:33 +00:00
if (world->space) {
dSpaceDestroy(world->space);
world->space = NULL;
}
2017-05-20 04:09:33 +00:00
if (world->id) {
dWorldDestroy(world->id);
world->id = NULL;
}
}
2017-05-19 21:04:34 +00:00
void lovrWorldUpdate(World* world, float dt, CollisionResolver resolver, void* userdata) {
if (resolver) {
resolver(world, userdata);
} else {
dSpaceCollide(world->space, world, defaultNearCallback);
}
2017-08-27 20:23:40 +00:00
if (dt > 0) {
dWorldQuickStep(world->id, dt);
}
2017-05-17 05:12:10 +00:00
dJointGroupEmpty(world->contactGroup);
2017-05-16 05:04:05 +00:00
}
2017-05-16 05:09:32 +00:00
2017-05-19 21:04:34 +00:00
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;
}
2017-05-25 00:39:12 +00:00
int lovrWorldCollide(World* world, Shape* a, Shape* b, float friction, float restitution) {
2017-05-19 21:04:34 +00:00
if (!a || !b) {
2017-10-31 08:14:09 +00:00
return false;
2017-05-19 21:04:34 +00:00
}
2017-05-25 00:39:12 +00:00
Collider* colliderA = a->collider;
Collider* colliderB = b->collider;
2017-05-25 22:01:40 +00:00
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)))) {
2017-10-31 08:14:09 +00:00
return false;
2017-05-25 22:01:40 +00:00
}
2017-05-25 00:39:12 +00:00
if (friction < 0) {
friction = sqrt(colliderA->friction * colliderB->friction);
}
if (restitution < 0) {
restitution = MAX(colliderA->restitution, colliderB->restitution);
}
2017-05-25 22:01:40 +00:00
dContact contacts[MAX_CONTACTS];
2017-05-19 21:04:34 +00:00
for (int i = 0; i < MAX_CONTACTS; i++) {
contacts[i].surface.mode = 0;
2017-05-25 00:39:12 +00:00
contacts[i].surface.mu = friction;
contacts[i].surface.bounce = restitution;
2017-05-19 21:04:34 +00:00
contacts[i].surface.mu = dInfinity;
if (restitution > 0) {
contacts[i].surface.mode |= dContactBounce;
}
2017-05-19 21:04:34 +00:00
}
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]);
2017-05-25 00:39:12 +00:00
dJointAttach(joint, colliderA->body, colliderB->body);
2017-05-19 21:04:34 +00:00
}
return contactCount;
}
2017-05-20 04:09:33 +00:00
void lovrWorldGetGravity(World* world, float* x, float* y, float* z) {
dReal gravity[3];
dWorldGetGravity(world->id, gravity);
*x = gravity[0];
*y = gravity[1];
*z = gravity[2];
}
void lovrWorldSetGravity(World* world, float x, float y, float z) {
dWorldSetGravity(world->id, x, y, z);
}
void lovrWorldGetLinearDamping(World* world, float* damping, float* threshold) {
*damping = dWorldGetLinearDamping(world->id);
*threshold = dWorldGetLinearDampingThreshold(world->id);
}
void lovrWorldSetLinearDamping(World* world, float damping, float threshold) {
dWorldSetLinearDamping(world->id, damping);
dWorldSetLinearDampingThreshold(world->id, threshold);
}
void lovrWorldGetAngularDamping(World* world, float* damping, float* threshold) {
*damping = dWorldGetAngularDamping(world->id);
*threshold = dWorldGetAngularDampingThreshold(world->id);
}
void lovrWorldSetAngularDamping(World* world, float damping, float threshold) {
dWorldSetAngularDamping(world->id, damping);
dWorldSetAngularDampingThreshold(world->id, threshold);
}
2017-10-31 08:14:09 +00:00
bool lovrWorldIsSleepingAllowed(World* world) {
2017-05-20 04:09:33 +00:00
return dWorldGetAutoDisableFlag(world->id);
}
2017-10-31 08:14:09 +00:00
void lovrWorldSetSleepingAllowed(World* world, bool allowed) {
2017-05-20 04:09:33 +00:00
dWorldSetAutoDisableFlag(world->id, allowed);
}
2017-05-25 00:40:02 +00:00
void lovrWorldRaycast(World* world, float x1, float y1, float z1, float x2, float y2, float z2, RaycastCallback callback, void* userdata) {
RaycastData data = { .callback = callback, .userdata = userdata };
float dx = x2 - x1;
float dy = y2 - y1;
float dz = z2 - z1;
float length = sqrt(dx * dx + dy * dy + dz * dz);
dGeomID ray = dCreateRay(world->space, length);
dGeomRaySet(ray, x1, y1, z1, dx, dy, dz);
dSpaceCollide2(ray, (dGeomID) world->space, &data, raycastCallback);
dGeomDestroy(ray);
}
2017-05-25 22:01:40 +00:00
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* lovrColliderInit(Collider* collider, World* world, float x, float y, float z) {
2017-05-20 02:11:58 +00:00
collider->body = dBodyCreate(world->id);
collider->world = world;
collider->friction = 0;
collider->restitution = 0;
2017-05-25 22:01:40 +00:00
collider->tag = NO_TAG;
2017-05-20 02:11:58 +00:00
dBodySetData(collider->body, collider);
vec_init(&collider->shapes);
vec_init(&collider->joints);
2017-05-16 05:09:32 +00:00
2017-06-10 21:17:59 +00:00
lovrColliderSetPosition(collider, x, y, z);
2018-08-19 04:16:19 +00:00
// Adjust the world's collider list
if (!collider->world->head) {
collider->world->head = collider;
} else {
collider->next = collider->world->head;
collider->next->prev = collider;
collider->world->head = collider;
}
// The world owns a reference to the collider
lovrRetain(collider);
2017-05-20 02:11:58 +00:00
return collider;
2017-05-16 05:09:32 +00:00
}
2018-02-26 08:59:03 +00:00
void lovrColliderDestroy(void* ref) {
Collider* collider = ref;
2018-08-22 16:29:34 +00:00
lovrColliderDestroyData(collider);
vec_deinit(&collider->shapes);
vec_deinit(&collider->joints);
2017-05-16 05:09:32 +00:00
}
2017-05-16 05:10:17 +00:00
2017-05-20 04:14:20 +00:00
void lovrColliderDestroyData(Collider* collider) {
2018-08-19 04:16:19 +00:00
if (!collider->body) {
return;
2017-05-20 04:14:20 +00:00
}
2018-08-19 04:16:19 +00:00
2018-08-22 16:29:34 +00:00
vec_void_t* shapes = lovrColliderGetShapes(collider);
Shape* shape; int i;
vec_foreach(shapes, shape, i) {
lovrColliderRemoveShape(collider, shape);
}
vec_void_t* joints = lovrColliderGetJoints(collider);
Joint* joint; int j;
vec_foreach(joints, joint, j) {
lovrRelease(joint);
}
2018-08-19 04:16:19 +00:00
dBodyDestroy(collider->body);
collider->body = NULL;
if (collider->next) collider->next->prev = collider->prev;
if (collider->prev) collider->prev->next = collider->next;
if (collider->world->head == collider) collider->world->head = collider->next;
collider->next = collider->prev = NULL;
// If the Collider is destroyed, the world lets go of its reference to this Collider
lovrRelease(collider);
2017-05-20 04:14:20 +00:00
}
World* lovrColliderGetWorld(Collider* collider) {
return collider->world;
}
2017-05-20 02:11:58 +00:00
void lovrColliderAddShape(Collider* collider, Shape* shape) {
2018-08-22 16:29:34 +00:00
lovrRetain(shape);
2017-05-20 02:11:58 +00:00
2018-08-22 16:29:34 +00:00
if (shape->collider) {
lovrColliderRemoveShape(shape->collider, shape);
2017-05-20 02:11:58 +00:00
}
2018-08-22 16:29:34 +00:00
shape->collider = collider;
dGeomSetBody(shape->id, collider->body);
dSpaceID newSpace = collider->world->space;
2017-05-20 02:11:58 +00:00
dSpaceAdd(newSpace, shape->id);
}
void lovrColliderRemoveShape(Collider* collider, Shape* shape) {
if (shape->collider == collider) {
dSpaceRemove(collider->world->space, shape->id);
dGeomSetBody(shape->id, 0);
2018-08-22 16:29:34 +00:00
shape->collider = NULL;
lovrRelease(shape);
2017-05-20 02:11:58 +00:00
}
}
vec_void_t* lovrColliderGetShapes(Collider* collider) {
vec_clear(&collider->shapes);
for (dGeomID geom = dBodyGetFirstGeom(collider->body); geom; geom = dBodyGetNextGeom(geom)) {
Shape* shape = dGeomGetData(geom);
if (shape) {
vec_push(&collider->shapes, shape);
}
}
return &collider->shapes;
2017-05-20 04:51:16 +00:00
}
vec_void_t* lovrColliderGetJoints(Collider* collider) {
vec_clear(&collider->joints);
int jointCount = dBodyGetNumJoints(collider->body);
for (int i = 0; i < jointCount; i++) {
Joint* joint = dJointGetData(dBodyGetJoint(collider->body, i));
if (joint) {
vec_push(&collider->joints, joint);
}
}
return &collider->joints;
2017-05-20 04:51:16 +00:00
}
void* lovrColliderGetUserData(Collider* collider) {
return collider->userdata;
}
void lovrColliderSetUserData(Collider* collider, void* data) {
collider->userdata = data;
}
2017-06-10 11:51:09 +00:00
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;
}
float lovrColliderGetFriction(Collider* collider) {
return collider->friction;
}
void lovrColliderSetFriction(Collider* collider, float friction) {
collider->friction = friction;
}
float lovrColliderGetRestitution(Collider* collider) {
return collider->restitution;
}
void lovrColliderSetRestitution(Collider* collider, float restitution) {
collider->restitution = restitution;
}
2017-10-31 08:14:09 +00:00
bool lovrColliderIsKinematic(Collider* collider) {
return dBodyIsKinematic(collider->body);
}
2017-10-31 08:14:09 +00:00
void lovrColliderSetKinematic(Collider* collider, bool kinematic) {
if (kinematic) {
dBodySetKinematic(collider->body);
} else {
dBodySetDynamic(collider->body);
}
}
2017-10-31 08:14:09 +00:00
bool lovrColliderIsGravityIgnored(Collider* collider) {
return !dBodyGetGravityMode(collider->body);
}
2017-10-31 08:14:09 +00:00
void lovrColliderSetGravityIgnored(Collider* collider, bool ignored) {
dBodySetGravityMode(collider->body, !ignored);
}
2017-10-31 08:14:09 +00:00
bool lovrColliderIsSleepingAllowed(Collider* collider) {
return dBodyGetAutoDisableFlag(collider->body);
}
2017-10-31 08:14:09 +00:00
void lovrColliderSetSleepingAllowed(Collider* collider, bool allowed) {
dBodySetAutoDisableFlag(collider->body, allowed);
}
2017-10-31 08:14:09 +00:00
bool lovrColliderIsAwake(Collider* collider) {
return dBodyIsEnabled(collider->body);
}
2017-10-31 08:14:09 +00:00
void lovrColliderSetAwake(Collider* collider, bool awake) {
if (awake) {
dBodyEnable(collider->body);
} else {
dBodyDisable(collider->body);
}
}
float lovrColliderGetMass(Collider* collider) {
dMass m;
dBodyGetMass(collider->body, &m);
return m.mass;
}
void lovrColliderSetMass(Collider* collider, float mass) {
dMass m;
dBodyGetMass(collider->body, &m);
dMassAdjust(&m, mass);
dBodySetMass(collider->body, &m);
}
void lovrColliderGetMassData(Collider* collider, float* cx, float* cy, float* cz, float* mass, float inertia[6]) {
dMass m;
dBodyGetMass(collider->body, &m);
*cx = m.c[0];
*cy = m.c[1];
*cz = m.c[2];
*mass = m.mass;
// Diagonal
inertia[0] = m.I[0];
inertia[1] = m.I[5];
inertia[2] = m.I[10];
// Lower triangular
inertia[3] = m.I[4];
inertia[4] = m.I[8];
inertia[5] = m.I[9];
}
void lovrColliderSetMassData(Collider* collider, float cx, float cy, float cz, float mass, float inertia[]) {
dMass m;
dBodyGetMass(collider->body, &m);
dMassSetParameters(&m, mass, cx, cy, cz, inertia[0], inertia[1], inertia[2], inertia[3], inertia[4], inertia[5]);
dBodySetMass(collider->body, &m);
}
2017-05-20 02:11:58 +00:00
void lovrColliderGetPosition(Collider* collider, float* x, float* y, float* z) {
const dReal* position = dBodyGetPosition(collider->body);
2017-05-16 05:10:17 +00:00
*x = position[0];
*y = position[1];
*z = position[2];
}
2017-05-20 02:11:58 +00:00
void lovrColliderSetPosition(Collider* collider, float x, float y, float z) {
dBodySetPosition(collider->body, x, y, z);
2017-05-16 05:10:17 +00:00
}
2017-05-20 02:11:58 +00:00
void lovrColliderGetOrientation(Collider* collider, float* angle, float* x, float* y, float* z) {
const dReal* q = dBodyGetQuaternion(collider->body);
2017-05-17 05:11:53 +00:00
float quaternion[4] = { q[1], q[2], q[3], q[0] };
quat_getAngleAxis(quaternion, angle, x, y, z);
}
2017-05-20 02:11:58 +00:00
void lovrColliderSetOrientation(Collider* collider, float angle, float x, float y, float z) {
float quaternion[4];
2018-11-25 02:04:27 +00:00
quat_fromAngleAxis(quaternion, angle, x, y, z);
2017-05-17 05:11:53 +00:00
float q[4] = { quaternion[3], quaternion[0], quaternion[1], quaternion[2] };
2017-05-20 02:11:58 +00:00
dBodySetQuaternion(collider->body, q);
}
2017-05-20 02:11:58 +00:00
void lovrColliderGetLinearVelocity(Collider* collider, float* x, float* y, float* z) {
const dReal* velocity = dBodyGetLinearVel(collider->body);
*x = velocity[0];
*y = velocity[1];
*z = velocity[2];
}
2017-05-20 02:11:58 +00:00
void lovrColliderSetLinearVelocity(Collider* collider, float x, float y, float z) {
dBodySetLinearVel(collider->body, x, y, z);
}
2017-05-20 02:11:58 +00:00
void lovrColliderGetAngularVelocity(Collider* collider, float* x, float* y, float* z) {
const dReal* velocity = dBodyGetAngularVel(collider->body);
*x = velocity[0];
*y = velocity[1];
*z = velocity[2];
}
2017-05-20 02:11:58 +00:00
void lovrColliderSetAngularVelocity(Collider* collider, float x, float y, float z) {
dBodySetAngularVel(collider->body, x, y, z);
}
2017-05-20 02:11:58 +00:00
void lovrColliderGetLinearDamping(Collider* collider, float* damping, float* threshold) {
*damping = dBodyGetLinearDamping(collider->body);
*threshold = dBodyGetLinearDampingThreshold(collider->body);
}
2017-05-20 02:11:58 +00:00
void lovrColliderSetLinearDamping(Collider* collider, float damping, float threshold) {
dBodySetLinearDamping(collider->body, damping);
dBodySetLinearDampingThreshold(collider->body, threshold);
}
2017-05-20 02:11:58 +00:00
void lovrColliderGetAngularDamping(Collider* collider, float* damping, float* threshold) {
*damping = dBodyGetAngularDamping(collider->body);
*threshold = dBodyGetAngularDampingThreshold(collider->body);
}
2017-05-20 02:11:58 +00:00
void lovrColliderSetAngularDamping(Collider* collider, float damping, float threshold) {
dBodySetAngularDamping(collider->body, damping);
dBodySetAngularDampingThreshold(collider->body, threshold);
}
2017-05-16 05:15:22 +00:00
2017-05-20 02:11:58 +00:00
void lovrColliderApplyForce(Collider* collider, float x, float y, float z) {
dBodyAddForce(collider->body, x, y, z);
2017-05-16 05:15:22 +00:00
}
2017-05-20 02:11:58 +00:00
void lovrColliderApplyForceAtPosition(Collider* collider, float x, float y, float z, float cx, float cy, float cz) {
dBodyAddForceAtPos(collider->body, x, y, z, cx, cy, cz);
2017-05-16 05:15:22 +00:00
}
2017-05-20 02:11:58 +00:00
void lovrColliderApplyTorque(Collider* collider, float x, float y, float z) {
dBodyAddTorque(collider->body, x, y, z);
2017-05-16 05:15:22 +00:00
}
2017-05-16 05:15:50 +00:00
2017-05-20 03:51:43 +00:00
void lovrColliderGetLocalCenter(Collider* collider, float* x, float* y, float* z) {
dMass m;
dBodyGetMass(collider->body, &m);
*x = m.c[0];
*y = m.c[1];
*z = m.c[2];
}
2017-05-20 02:11:58 +00:00
void lovrColliderGetLocalPoint(Collider* collider, float wx, float wy, float wz, float* x, float* y, float* z) {
dReal local[3];
2017-05-20 02:11:58 +00:00
dBodyGetPosRelPoint(collider->body, wx, wy, wz, local);
*x = local[0];
*y = local[1];
*z = local[2];
}
2017-05-20 02:11:58 +00:00
void lovrColliderGetWorldPoint(Collider* collider, float x, float y, float z, float* wx, float* wy, float* wz) {
dReal world[3];
2017-05-20 02:11:58 +00:00
dBodyGetRelPointPos(collider->body, x, y, z, world);
*wx = world[0];
*wy = world[1];
*wz = world[2];
}
2017-05-20 02:11:58 +00:00
void lovrColliderGetLocalVector(Collider* collider, float wx, float wy, float wz, float* x, float* y, float* z) {
dReal local[3];
2017-05-20 02:11:58 +00:00
dBodyVectorFromWorld(collider->body, wx, wy, wz, local);
*x = local[0];
*y = local[1];
*z = local[2];
}
2017-05-20 02:11:58 +00:00
void lovrColliderGetWorldVector(Collider* collider, float x, float y, float z, float* wx, float* wy, float* wz) {
dReal world[3];
2017-05-20 02:11:58 +00:00
dBodyVectorToWorld(collider->body, x, y, z, world);
*wx = world[0];
*wy = world[1];
*wz = world[2];
}
2017-05-20 02:11:58 +00:00
void lovrColliderGetLinearVelocityFromLocalPoint(Collider* collider, float x, float y, float z, float* vx, float* vy, float* vz) {
dReal velocity[3];
2017-05-20 02:11:58 +00:00
dBodyGetRelPointVel(collider->body, x, y, z, velocity);
*vx = velocity[0];
*vy = velocity[1];
*vz = velocity[2];
}
2017-05-20 02:11:58 +00:00
void lovrColliderGetLinearVelocityFromWorldPoint(Collider* collider, float wx, float wy, float wz, float* vx, float* vy, float* vz) {
dReal velocity[3];
2017-05-20 02:11:58 +00:00
dBodyGetPointVel(collider->body, wx, wy, wz, velocity);
*vx = velocity[0];
*vy = velocity[1];
*vz = velocity[2];
}
2017-05-25 01:10:39 +00:00
void lovrColliderGetAABB(Collider* collider, float aabb[6]) {
dGeomID shape = dBodyGetFirstGeom(collider->body);
if (!shape) {
memset(aabb, 0, 6 * sizeof(float));
return;
}
dGeomGetAABB(shape, aabb);
float otherAABB[6];
while ((shape = dBodyGetNextGeom(shape)) != NULL) {
dGeomGetAABB(shape, otherAABB);
aabb[0] = MIN(aabb[0], otherAABB[0]);
2017-06-22 01:45:46 +00:00
aabb[1] = MAX(aabb[1], otherAABB[1]);
2017-05-25 01:10:39 +00:00
aabb[2] = MIN(aabb[2], otherAABB[2]);
aabb[3] = MAX(aabb[3], otherAABB[3]);
aabb[4] = MIN(aabb[4], otherAABB[4]);
aabb[5] = MAX(aabb[5], otherAABB[5]);
}
}
2018-02-26 08:59:03 +00:00
void lovrShapeDestroy(void* ref) {
Shape* shape = ref;
2017-05-20 04:24:23 +00:00
lovrShapeDestroyData(shape);
2017-05-16 18:24:49 +00:00
}
2017-05-20 04:24:23 +00:00
void lovrShapeDestroyData(Shape* shape) {
if (shape->id) {
dGeomDestroy(shape->id);
shape->id = NULL;
}
}
2017-05-16 18:17:01 +00:00
ShapeType lovrShapeGetType(Shape* shape) {
return shape->type;
}
2017-05-20 02:11:58 +00:00
Collider* lovrShapeGetCollider(Shape* shape) {
return shape->collider;
2017-05-16 18:23:13 +00:00
}
2017-10-31 08:14:09 +00:00
bool lovrShapeIsEnabled(Shape* shape) {
2017-05-16 18:29:18 +00:00
return dGeomIsEnabled(shape->id);
}
2017-10-31 08:14:09 +00:00
void lovrShapeSetEnabled(Shape* shape, bool enabled) {
2017-05-16 18:29:18 +00:00
if (enabled) {
dGeomEnable(shape->id);
} else {
dGeomDisable(shape->id);
}
2017-05-16 18:17:01 +00:00
}
2017-05-16 18:33:55 +00:00
void* lovrShapeGetUserData(Shape* shape) {
2017-05-19 21:04:34 +00:00
return shape->userdata;
2017-05-16 18:33:55 +00:00
}
void lovrShapeSetUserData(Shape* shape, void* data) {
2017-05-19 21:04:34 +00:00
shape->userdata = data;
2017-05-16 18:33:55 +00:00
}
2017-05-16 18:46:15 +00:00
void lovrShapeGetPosition(Shape* shape, float* x, float* y, float* z) {
const dReal* position = dGeomGetOffsetPosition(shape->id);
*x = position[0];
*y = position[1];
*z = position[2];
}
void lovrShapeSetPosition(Shape* shape, float x, float y, float z) {
dGeomSetOffsetPosition(shape->id, x, y, z);
}
void lovrShapeGetOrientation(Shape* shape, float* angle, float* x, float* y, float* z) {
2017-05-17 05:11:53 +00:00
dReal q[4];
dGeomGetOffsetQuaternion(shape->id, q);
float quaternion[4] = { q[1], q[2], q[3], q[0] };
quat_getAngleAxis(quaternion, angle, x, y, z);
}
void lovrShapeSetOrientation(Shape* shape, float angle, float x, float y, float z) {
float quaternion[4];
2018-11-25 02:04:27 +00:00
quat_fromAngleAxis(quaternion, angle, x, y, z);
2017-05-17 05:11:53 +00:00
float q[4] = { quaternion[3], quaternion[0], quaternion[1], quaternion[2] };
dGeomSetOffsetQuaternion(shape->id, q);
}
2017-05-16 20:26:09 +00:00
2017-05-25 00:47:59 +00:00
void lovrShapeGetMass(Shape* shape, float density, float* cx, float* cy, float* cz, float* mass, float inertia[6]) {
2017-05-17 00:25:08 +00:00
dMass m;
dMassSetZero(&m);
switch (shape->type) {
case SHAPE_SPHERE: {
dMassSetSphere(&m, density, dGeomSphereGetRadius(shape->id));
break;
}
case SHAPE_BOX: {
dReal lengths[3];
dGeomBoxGetLengths(shape->id, lengths);
dMassSetBox(&m, density, lengths[0], lengths[1], lengths[2]);
break;
}
case SHAPE_CAPSULE: {
dReal radius, length;
dGeomCapsuleGetParams(shape->id, &radius, &length);
dMassSetCapsule(&m, density, 3, radius, length);
break;
}
case SHAPE_CYLINDER: {
dReal radius, length;
dGeomCylinderGetParams(shape->id, &radius, &length);
dMassSetCylinder(&m, density, 3, radius, length);
break;
}
}
const dReal* position = dGeomGetOffsetPosition(shape->id);
dMassTranslate(&m, position[0], position[1], position[2]);
const dReal* rotation = dGeomGetOffsetRotation(shape->id);
dMassRotate(&m, rotation);
*cx = m.c[0];
*cy = m.c[1];
*cz = m.c[2];
*mass = m.mass;
2017-05-17 01:13:38 +00:00
// Diagonal
2017-05-17 00:25:08 +00:00
inertia[0] = m.I[0];
2017-05-17 01:13:38 +00:00
inertia[1] = m.I[5];
inertia[2] = m.I[10];
// Lower triangular
inertia[3] = m.I[4];
inertia[4] = m.I[8];
2017-05-17 00:25:08 +00:00
inertia[5] = m.I[9];
}
2017-05-25 00:47:59 +00:00
void lovrShapeGetAABB(Shape* shape, float aabb[6]) {
dGeomGetAABB(shape->id, aabb);
}
SphereShape* lovrSphereShapeInit(SphereShape* sphere, float radius) {
2017-05-16 21:21:10 +00:00
sphere->type = SHAPE_SPHERE;
sphere->id = dCreateSphere(0, radius);
2017-05-19 21:04:34 +00:00
dGeomSetData(sphere->id, sphere);
2017-05-16 21:21:10 +00:00
return sphere;
}
float lovrSphereShapeGetRadius(SphereShape* sphere) {
return dGeomSphereGetRadius(sphere->id);
}
void lovrSphereShapeSetRadius(SphereShape* sphere, float radius) {
dGeomSphereSetRadius(sphere->id, radius);
}
2017-05-16 21:37:05 +00:00
BoxShape* lovrBoxShapeInit(BoxShape* box, float x, float y, float z) {
2017-05-16 21:37:05 +00:00
box->type = SHAPE_BOX;
box->id = dCreateBox(0, x, y, z);
2017-05-19 21:04:34 +00:00
dGeomSetData(box->id, box);
2017-05-16 21:37:05 +00:00
return box;
}
void lovrBoxShapeGetDimensions(BoxShape* box, float* x, float* y, float* z) {
float dimensions[3];
dGeomBoxGetLengths(box->id, dimensions);
*x = dimensions[0];
*y = dimensions[1];
*z = dimensions[2];
}
void lovrBoxShapeSetDimensions(BoxShape* box, float x, float y, float z) {
dGeomBoxSetLengths(box->id, x, y, z);
}
2017-05-16 21:52:41 +00:00
CapsuleShape* lovrCapsuleShapeInit(CapsuleShape* capsule, float radius, float length) {
2017-05-16 21:52:41 +00:00
capsule->type = SHAPE_CAPSULE;
capsule->id = dCreateCapsule(0, radius, length);
2017-05-19 21:04:34 +00:00
dGeomSetData(capsule->id, capsule);
2017-05-16 21:52:41 +00:00
return capsule;
}
float lovrCapsuleShapeGetRadius(CapsuleShape* capsule) {
float radius, length;
dGeomCapsuleGetParams(capsule->id, &radius, &length);
return radius;
}
void lovrCapsuleShapeSetRadius(CapsuleShape* capsule, float radius) {
dGeomCapsuleSetParams(capsule->id, radius, lovrCapsuleShapeGetLength(capsule));
}
float lovrCapsuleShapeGetLength(CapsuleShape* capsule) {
float radius, length;
dGeomCapsuleGetParams(capsule->id, &radius, &length);
return length;
}
void lovrCapsuleShapeSetLength(CapsuleShape* capsule, float length) {
dGeomCapsuleSetParams(capsule->id, lovrCapsuleShapeGetRadius(capsule), length);
}
2017-05-16 21:56:20 +00:00
CylinderShape* lovrCylinderShapeInit(CylinderShape* cylinder, float radius, float length) {
2017-05-16 21:56:20 +00:00
cylinder->type = SHAPE_CYLINDER;
cylinder->id = dCreateCylinder(0, radius, length);
2017-05-19 21:04:34 +00:00
dGeomSetData(cylinder->id, cylinder);
2017-05-16 21:56:20 +00:00
return cylinder;
}
float lovrCylinderShapeGetRadius(CylinderShape* cylinder) {
float radius, length;
dGeomCylinderGetParams(cylinder->id, &radius, &length);
return radius;
}
void lovrCylinderShapeSetRadius(CylinderShape* cylinder, float radius) {
dGeomCylinderSetParams(cylinder->id, radius, lovrCylinderShapeGetLength(cylinder));
}
float lovrCylinderShapeGetLength(CylinderShape* cylinder) {
float radius, length;
dGeomCylinderGetParams(cylinder->id, &radius, &length);
return length;
}
void lovrCylinderShapeSetLength(CylinderShape* cylinder, float length) {
dGeomCylinderSetParams(cylinder->id, lovrCylinderShapeGetRadius(cylinder), length);
}
2018-02-26 08:59:03 +00:00
void lovrJointDestroy(void* ref) {
Joint* joint = ref;
lovrJointDestroyData(joint);
}
void lovrJointDestroyData(Joint* joint) {
if (joint->id) {
dJointDestroy(joint->id);
joint->id = NULL;
}
}
JointType lovrJointGetType(Joint* joint) {
return joint->type;
}
void lovrJointGetColliders(Joint* joint, Collider** a, Collider** b) {
dBodyID bodyA = dJointGetBody(joint->id, 0);
dBodyID bodyB = dJointGetBody(joint->id, 1);
if (bodyA) {
*a = dBodyGetData(bodyA);
}
if (bodyB) {
*b = dBodyGetData(bodyB);
}
}
void* lovrJointGetUserData(Joint* joint) {
return joint->userdata;
}
void lovrJointSetUserData(Joint* joint, void* data) {
joint->userdata = data;
}
BallJoint* lovrBallJointInit(BallJoint* joint, Collider* a, Collider* b, float x, float y, float z) {
lovrAssert(a->world == b->world, "Joint bodies must exist in same World");
joint->type = JOINT_BALL;
joint->id = dJointCreateBall(a->world->id, 0);
dJointSetData(joint->id, joint);
dJointAttach(joint->id, a->body, b->body);
2017-06-10 22:13:19 +00:00
lovrBallJointSetAnchor(joint, x, y, z);
2018-08-22 16:29:34 +00:00
lovrRetain(joint);
2017-06-10 22:13:19 +00:00
return joint;
}
void lovrBallJointGetAnchors(BallJoint* joint, float* x1, float* y1, float* z1, float* x2, float* y2, float* z2) {
float anchor[3];
dJointGetBallAnchor(joint->id, anchor);
*x1 = anchor[0];
*y1 = anchor[1];
*z1 = anchor[2];
dJointGetBallAnchor2(joint->id, anchor);
*x2 = anchor[0];
*y2 = anchor[1];
*z2 = anchor[2];
}
void lovrBallJointSetAnchor(BallJoint* joint, float x, float y, float z) {
dJointSetBallAnchor(joint->id, x, y, z);
2017-06-10 22:13:19 +00:00
}
DistanceJoint* lovrDistanceJointInit(DistanceJoint* joint, Collider* a, Collider* b, float x1, float y1, float z1, float x2, float y2, float z2) {
lovrAssert(a->world == b->world, "Joint bodies must exist in same World");
2017-06-10 22:13:19 +00:00
joint->type = JOINT_DISTANCE;
joint->id = dJointCreateDBall(a->world->id, 0);
dJointSetData(joint->id, joint);
dJointAttach(joint->id, a->body, b->body);
lovrDistanceJointSetAnchors(joint, x1, y1, z1, x2, y2, z2);
2018-08-22 16:29:34 +00:00
lovrRetain(joint);
return joint;
}
2017-06-10 22:13:19 +00:00
void lovrDistanceJointGetAnchors(DistanceJoint* joint, float* x1, float* y1, float* z1, float* x2, float* y2, float* z2) {
float anchor[3];
2017-06-10 22:13:19 +00:00
dJointGetDBallAnchor1(joint->id, anchor);
*x1 = anchor[0];
*y1 = anchor[1];
*z1 = anchor[2];
2017-06-10 22:13:19 +00:00
dJointGetDBallAnchor2(joint->id, anchor);
*x2 = anchor[0];
*y2 = anchor[1];
*z2 = anchor[2];
}
2017-06-10 22:13:19 +00:00
void lovrDistanceJointSetAnchors(DistanceJoint* joint, float x1, float y1, float z1, float x2, float y2, float z2) {
dJointSetDBallAnchor1(joint->id, x1, y1, z1);
dJointSetDBallAnchor2(joint->id, x2, y2, z2);
}
float lovrDistanceJointGetDistance(DistanceJoint* joint) {
return dJointGetDBallDistance(joint->id);
}
void lovrDistanceJointSetDistance(DistanceJoint* joint, float distance) {
dJointSetDBallDistance(joint->id, distance);
}
2017-05-25 06:51:27 +00:00
HingeJoint* lovrHingeJointInit(HingeJoint* joint, Collider* a, Collider* b, float x, float y, float z, float ax, float ay, float az) {
lovrAssert(a->world == b->world, "Joint bodies must exist in same World");
2017-05-25 06:51:27 +00:00
joint->type = JOINT_HINGE;
joint->id = dJointCreateHinge(a->world->id, 0);
dJointSetData(joint->id, joint);
dJointAttach(joint->id, a->body, b->body);
2017-06-10 22:13:19 +00:00
lovrHingeJointSetAnchor(joint, x, y, z);
lovrHingeJointSetAxis(joint, ax, ay, az);
2018-08-22 16:29:34 +00:00
lovrRetain(joint);
2017-05-25 06:51:27 +00:00
return joint;
}
2017-06-10 22:13:19 +00:00
void lovrHingeJointGetAnchors(HingeJoint* joint, float* x1, float* y1, float* z1, float* x2, float* y2, float* z2) {
2017-05-25 06:51:27 +00:00
float anchor[3];
2017-06-10 22:13:19 +00:00
dJointGetHingeAnchor(joint->id, anchor);
2017-05-25 06:51:27 +00:00
*x1 = anchor[0];
*y1 = anchor[1];
*z1 = anchor[2];
2017-06-10 22:13:19 +00:00
dJointGetHingeAnchor2(joint->id, anchor);
2017-05-25 06:51:27 +00:00
*x2 = anchor[0];
*y2 = anchor[1];
*z2 = anchor[2];
}
2017-06-10 22:13:19 +00:00
void lovrHingeJointSetAnchor(HingeJoint* joint, float x, float y, float z) {
dJointSetHingeAnchor(joint->id, x, y, z);
2017-05-25 06:51:27 +00:00
}
2017-06-10 22:13:19 +00:00
void lovrHingeJointGetAxis(HingeJoint* joint, float* x, float* y, float* z) {
2017-05-25 07:48:02 +00:00
float axis[3];
2017-06-10 22:13:19 +00:00
dJointGetHingeAxis(joint->id, axis);
2017-05-25 07:48:02 +00:00
*x = axis[0];
*y = axis[1];
*z = axis[2];
2017-05-25 06:51:27 +00:00
}
2017-06-10 22:13:19 +00:00
void lovrHingeJointSetAxis(HingeJoint* joint, float x, float y, float z) {
dJointSetHingeAxis(joint->id, x, y, z);
2017-05-25 06:51:27 +00:00
}
2017-06-10 22:13:19 +00:00
float lovrHingeJointGetAngle(HingeJoint* joint) {
return dJointGetHingeAngle(joint->id);
2017-05-25 06:51:27 +00:00
}
2017-05-25 07:48:02 +00:00
2017-06-10 22:13:19 +00:00
float lovrHingeJointGetLowerLimit(HingeJoint* joint) {
return dJointGetHingeParam(joint->id, dParamLoStop);
2017-05-25 22:20:55 +00:00
}
2017-06-10 22:13:19 +00:00
void lovrHingeJointSetLowerLimit(HingeJoint* joint, float limit) {
dJointSetHingeParam(joint->id, dParamLoStop, limit);
2017-05-25 22:20:55 +00:00
}
2017-06-10 22:13:19 +00:00
float lovrHingeJointGetUpperLimit(HingeJoint* joint) {
return dJointGetHingeParam(joint->id, dParamHiStop);
2017-05-25 22:20:55 +00:00
}
2017-06-10 22:13:19 +00:00
void lovrHingeJointSetUpperLimit(HingeJoint* joint, float limit) {
dJointSetHingeParam(joint->id, dParamHiStop, limit);
2017-05-25 22:20:55 +00:00
}
SliderJoint* lovrSliderJointInit(SliderJoint* joint, Collider* a, Collider* b, float ax, float ay, float az) {
lovrAssert(a->world == b->world, "Joint bodies must exist in the same world");
2017-05-25 07:48:02 +00:00
joint->type = JOINT_SLIDER;
joint->id = dJointCreateSlider(a->world->id, 0);
dJointSetData(joint->id, joint);
dJointAttach(joint->id, a->body, b->body);
2017-06-10 22:13:19 +00:00
lovrSliderJointSetAxis(joint, ax, ay, az);
2018-08-22 16:29:34 +00:00
lovrRetain(joint);
2017-05-25 07:48:02 +00:00
return joint;
}
2017-06-10 22:13:19 +00:00
void lovrSliderJointGetAxis(SliderJoint* joint, float* x, float* y, float* z) {
2017-05-25 07:48:02 +00:00
float axis[3];
2017-06-10 22:13:19 +00:00
dJointGetSliderAxis(joint->id, axis);
2017-05-25 07:48:02 +00:00
*x = axis[0];
*y = axis[1];
*z = axis[2];
}
2017-06-10 22:13:19 +00:00
void lovrSliderJointSetAxis(SliderJoint* joint, float x, float y, float z) {
dJointSetSliderAxis(joint->id, x, y, z);
2017-05-25 07:48:02 +00:00
}
2017-06-10 22:13:19 +00:00
float lovrSliderJointGetPosition(SliderJoint* joint) {
return dJointGetSliderPosition(joint->id);
2017-05-25 07:48:02 +00:00
}
2017-05-25 22:20:55 +00:00
2017-06-10 22:13:19 +00:00
float lovrSliderJointGetLowerLimit(SliderJoint* joint) {
return dJointGetSliderParam(joint->id, dParamLoStop);
2017-05-25 22:20:55 +00:00
}
2017-06-10 22:13:19 +00:00
void lovrSliderJointSetLowerLimit(SliderJoint* joint, float limit) {
dJointSetSliderParam(joint->id, dParamLoStop, limit);
2017-05-25 22:20:55 +00:00
}
2017-06-10 22:13:19 +00:00
float lovrSliderJointGetUpperLimit(SliderJoint* joint) {
return dJointGetSliderParam(joint->id, dParamHiStop);
2017-05-25 22:20:55 +00:00
}
2017-06-10 22:13:19 +00:00
void lovrSliderJointSetUpperLimit(SliderJoint* joint, float limit) {
dJointSetSliderParam(joint->id, dParamHiStop, limit);
2017-05-25 22:20:55 +00:00
}