lovr/src/modules/physics/physics.c

1164 lines
32 KiB
C
Raw Normal View History

2017-05-16 04:59:53 +00:00
#include "physics.h"
#include "core/ref.h"
#include "core/util.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;
arr_push(&world->overlaps, dGeomGetData(shapeA));
arr_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);
}
}
2019-09-07 22:07:07 +00:00
// XXX slow, but probably fine (tag names are not on any critical path), could switch to hashing if needed
static uint32_t findTag(World* world, const char* name) {
for (uint32_t i = 0; i < MAX_TAGS && world->tags[i]; i++) {
if (!strcmp(world->tags[i], name)) {
return i;
}
}
return NO_TAG;
}
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
2019-09-07 22:07:07 +00:00
World* lovrWorldInit(World* world, float xg, float yg, float zg, bool allowSleep, const char** tags, uint32_t 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);
arr_init(&world->overlaps);
2017-05-25 22:01:40 +00:00
lovrWorldSetGravity(world, xg, yg, zg);
lovrWorldSetSleepingAllowed(world, allowSleep);
2019-09-07 22:07:07 +00:00
for (uint32_t i = 0; i < tagCount; i++) {
size_t size = strlen(tags[i]) + 1;
world->tags[i] = malloc(size);
memcpy(world->tags[i], tags[i], size);
2017-05-25 22:01:40 +00:00
}
2019-09-07 22:07:07 +00:00
memset(world->masks, 0xff, sizeof(world->masks));
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);
arr_free(&world->overlaps);
2019-09-07 22:07:07 +00:00
for (uint32_t i = 0; i < MAX_TAGS && world->tags[i]; i++) {
free(world->tags[i]);
}
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) {
arr_clear(&world->overlaps);
2017-05-19 21:04:34 +00:00
dSpaceCollide(world->space, world, customNearCallback);
}
int lovrWorldGetNextOverlap(World* world, Shape** a, Shape** b) {
if (world->overlaps.length == 0) {
*a = *b = NULL;
return 0;
}
*a = arr_pop(&world->overlaps);
*b = arr_pop(&world->overlaps);
2017-05-19 21:04:34 +00:00
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;
2019-09-07 22:07:07 +00:00
uint32_t i = colliderA->tag;
uint32_t j = colliderB->tag;
2017-05-25 22:01:40 +00:00
2019-09-07 22:07:07 +00:00
if (i != NO_TAG && j != NO_TAG && !((world->masks[i] & (1 << j)) && (world->masks[j] & (1 << i)))) {
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.f) {
friction = sqrtf(colliderA->friction * colliderB->friction);
2017-05-25 00:39:12 +00:00
}
if (restitution < 0.f) {
2017-05-25 00:39:12 +00:00
restitution = MAX(colliderA->restitution, colliderB->restitution);
}
2017-05-25 22:01:40 +00:00
dContact contacts[MAX_CONTACTS];
2020-01-23 19:18:04 +00:00
for (int c = 0; c < MAX_CONTACTS; c++) {
contacts[c].surface.mode = 0;
contacts[c].surface.mu = friction;
contacts[c].surface.bounce = restitution;
contacts[c].surface.mu = dInfinity;
if (restitution > 0) {
2020-01-23 19:18:04 +00:00
contacts[c].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));
2019-10-10 22:36:28 +00:00
if (!a->sensor && !b->sensor) {
2020-01-23 19:18:04 +00:00
for (int c = 0; c < contactCount; c++) {
dJointID joint = dJointCreateContact(world->id, world->contactGroup, &contacts[c]);
2019-10-10 22:36:28 +00:00
dJointAttach(joint, colliderA->body, colliderB->body);
}
2017-05-19 21:04:34 +00:00
}
return contactCount;
}
2020-05-11 18:05:30 +00:00
Collider* lovrWorldGetFirstCollider(World* world) {
return world->head;
}
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);
}
Get/set World and Joint simulation parameters Tightness parameter is amount of force is exerted on collider to resolve collisions and enforce joint operation. Low values make joints loose, high values make it tight and can cause collider to overshot the joint target. With tightness set to 0 the joint loses its function. Going above 1 puts even more energy into joint oscillations. Tightness parameter is called ERP in ODE manual. The responseTime affects the time constant of physics simulation, both for collisions and for joint inertia. Low responseTime values make simulation tight and fast, higher values make it sluggish. For collisions it affects how fast penetration is resolved, with higher values resulting in spongy objects with more surface penetration and slower collision resolving. For joints the responseTime is similar to inertia, with higher responseTime values resulting in slow oscillations. The oscillation frequency is also affected by collider mass, so responseTime can be used to tweak the joint to get desired frequency with specific collider mass. Values higher than 1 are often desirable, especially for very light objects. Unlike tightness, responseTime is tweaked in orders of magnitude with useful values (depending on mass) being between 10^-8 and 10^8. Both parameters can be applied to World for simulation-wide usage, or specified per-joint in case of distance and ball joints. Other joints don't allow customizing these parameters, and will use World settings instead..
2020-05-29 14:38:32 +00:00
float lovrWorldGetResponseTime(World* world) {
return dWorldGetCFM(world->id);
}
void lovrWorldSetResponseTime(World* world, float responseTime) {
dWorldSetCFM(world->id, responseTime);
}
float lovrWorldGetTightness(World* world) {
return dWorldGetERP(world->id);
}
void lovrWorldSetTightness(World* world, float tightness) {
dWorldSetERP(world->id, tightness);
}
2017-05-20 04:09:33 +00:00
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 = sqrtf(dx * dx + dy * dy + dz * dz);
2017-05-25 00:40:02 +00:00
dGeomID ray = dCreateRay(world->space, length);
dGeomRaySet(ray, x1, y1, z1, dx, dy, dz);
dSpaceCollide2(ray, (dGeomID) world->space, &data, raycastCallback);
dGeomDestroy(ray);
}
2019-09-07 22:07:07 +00:00
const char* lovrWorldGetTagName(World* world, uint32_t tag) {
return (tag == NO_TAG) ? NULL : world->tags[tag];
2017-05-25 22:01:40 +00:00
}
int lovrWorldDisableCollisionBetween(World* world, const char* tag1, const char* tag2) {
2019-09-07 22:07:07 +00:00
uint32_t i = findTag(world, tag1);
uint32_t j = findTag(world, tag2);
if (i == NO_TAG || j == NO_TAG) {
2017-05-25 22:01:40 +00:00
return NO_TAG;
}
2019-09-07 22:07:07 +00:00
world->masks[i] &= ~(1 << j);
world->masks[j] &= ~(1 << i);
2017-05-25 22:01:40 +00:00
return 0;
}
int lovrWorldEnableCollisionBetween(World* world, const char* tag1, const char* tag2) {
2019-09-07 22:07:07 +00:00
uint32_t i = findTag(world, tag1);
uint32_t j = findTag(world, tag2);
if (i == NO_TAG || j == NO_TAG) {
2017-05-25 22:01:40 +00:00
return NO_TAG;
}
2019-09-07 22:07:07 +00:00
world->masks[i] |= (1 << j);
world->masks[j] |= (1 << i);
2017-05-25 22:01:40 +00:00
return 0;
}
int lovrWorldIsCollisionEnabledBetween(World* world, const char* tag1, const char* tag2) {
2019-09-07 22:07:07 +00:00
uint32_t i = findTag(world, tag1);
uint32_t j = findTag(world, tag2);
if (i == NO_TAG || j == NO_TAG) {
2017-05-25 22:01:40 +00:00
return NO_TAG;
}
2019-09-07 22:07:07 +00:00
return (world->masks[i] & (1 << j)) && (world->masks[j] & (1 << i));
2017-05-25 22:01:40 +00:00
}
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);
arr_init(&collider->shapes);
arr_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);
arr_free(&collider->shapes);
arr_free(&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
size_t count;
Shape** shapes = lovrColliderGetShapes(collider, &count);
for (size_t i = 0; i < count; i++) {
lovrColliderRemoveShape(collider, shapes[i]);
2018-08-22 16:29:34 +00:00
}
Joint** joints = lovrColliderGetJoints(collider, &count);
for (size_t i = 0; i < count; i++) {
lovrRelease(Joint, joints[i]);
2018-08-22 16:29:34 +00:00
}
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, collider);
2017-05-20 04:14:20 +00:00
}
2020-04-30 20:15:36 +00:00
void lovrColliderInitInertia(Collider* collider, Shape* shape) {
// compute inertia matrix for default density
const float density = 1.0f;
float cx, cy, cz, mass, inertia[6];
lovrShapeGetMass(shape, density, &cx, &cy, &cz, &mass, inertia);
lovrColliderSetMassData(collider, cx, cy, cz, mass, inertia);
}
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, shape);
2017-05-20 02:11:58 +00:00
}
}
Shape** lovrColliderGetShapes(Collider* collider, size_t* count) {
arr_clear(&collider->shapes);
for (dGeomID geom = dBodyGetFirstGeom(collider->body); geom; geom = dBodyGetNextGeom(geom)) {
Shape* shape = dGeomGetData(geom);
if (shape) {
arr_push(&collider->shapes, shape);
}
}
*count = collider->shapes.length;
return collider->shapes.data;
2017-05-20 04:51:16 +00:00
}
Joint** lovrColliderGetJoints(Collider* collider, size_t* count) {
arr_clear(&collider->joints);
int jointCount = dBodyGetNumJoints(collider->body);
for (int i = 0; i < jointCount; i++) {
Joint* joint = dJointGetData(dBodyGetJoint(collider->body, i));
if (joint) {
arr_push(&collider->joints, joint);
}
}
*count = collider->joints.length;
return collider->joints.data;
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);
}
2019-09-07 22:07:07 +00:00
bool lovrColliderSetTag(Collider* collider, const char* tag) {
if (!tag) {
2017-06-10 11:51:09 +00:00
collider->tag = NO_TAG;
2019-09-07 22:07:07 +00:00
return true;
2017-06-10 11:51:09 +00:00
}
2019-09-07 22:07:07 +00:00
collider->tag = findTag(collider->world, tag);
return collider->tag != NO_TAG;
2017-06-10 11:51:09 +00:00
}
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
}
void lovrColliderGetOrientation(Collider* collider, quat orientation) {
2017-05-20 02:11:58 +00:00
const dReal* q = dBodyGetQuaternion(collider->body);
quat_set(orientation, q[1], q[2], q[3], q[0]);
}
void lovrColliderSetOrientation(Collider* collider, quat orientation) {
float q[4] = { orientation[3], orientation[0], orientation[1], orientation[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) {
2020-09-13 10:34:36 +00:00
if (shape->type == SHAPE_MESH) {
dTriMeshDataID dataID = dGeomTriMeshGetData(shape->id);
dGeomTriMeshDataDestroy(dataID);
}
2017-05-20 04:24:23 +00:00
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
2019-10-10 22:36:28 +00:00
bool lovrShapeIsSensor(Shape* shape) {
return shape->sensor;
}
void lovrShapeSetSensor(Shape* shape, bool sensor) {
shape->sensor = sensor;
}
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, quat orientation) {
2017-05-17 05:11:53 +00:00
dReal q[4];
dGeomGetOffsetQuaternion(shape->id, q);
quat_set(orientation, q[1], q[2], q[3], q[0]);
}
void lovrShapeSetOrientation(Shape* shape, quat orientation) {
float q[4] = { orientation[3], orientation[0], orientation[1], orientation[2] };
2017-05-17 05:11:53 +00:00
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;
}
2020-09-13 10:34:36 +00:00
case SHAPE_MESH: {
dMassSetTrimesh(&m, density, shape->id);
dGeomSetPosition(shape->id, -m.c[0], -m.c[1], -m.c[2]);
dMassTranslate(&m, -m.c[0], -m.c[1], -m.c[2]);
break;
}
2017-05-17 00:25:08 +00:00
}
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);
}
2020-09-13 10:34:36 +00:00
MeshShape* lovrMeshShapeInit(MeshShape* mesh, int vertexCount, float vertices[], int indexCount, dTriIndex indices[]) {
dTriMeshDataID dataID = dGeomTriMeshDataCreate();
2020-11-21 21:37:47 +00:00
dGeomTriMeshDataBuildSingle(dataID, vertices, 3 * sizeof(float), vertexCount, indices, indexCount, 3 * sizeof(dTriIndex));
2020-09-13 10:34:36 +00:00
dGeomTriMeshDataPreprocess2(dataID, (1U << dTRIDATAPREPROCESS_BUILD_FACE_ANGLES), NULL);
mesh->id = dCreateTriMesh(0, dataID, 0, 0, 0);
mesh->type = SHAPE_MESH;
dGeomSetData(mesh->id, mesh);
return mesh;
}
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;
}
2019-11-12 00:27:30 +00:00
bool lovrJointIsEnabled(Joint* joint) {
return dJointIsEnabled(joint->id);
}
void lovrJointSetEnabled(Joint* joint, bool enable) {
if (enable) {
dJointEnable(joint->id);
} else {
dJointDisable(joint->id);
}
}
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
}
Get/set World and Joint simulation parameters Tightness parameter is amount of force is exerted on collider to resolve collisions and enforce joint operation. Low values make joints loose, high values make it tight and can cause collider to overshot the joint target. With tightness set to 0 the joint loses its function. Going above 1 puts even more energy into joint oscillations. Tightness parameter is called ERP in ODE manual. The responseTime affects the time constant of physics simulation, both for collisions and for joint inertia. Low responseTime values make simulation tight and fast, higher values make it sluggish. For collisions it affects how fast penetration is resolved, with higher values resulting in spongy objects with more surface penetration and slower collision resolving. For joints the responseTime is similar to inertia, with higher responseTime values resulting in slow oscillations. The oscillation frequency is also affected by collider mass, so responseTime can be used to tweak the joint to get desired frequency with specific collider mass. Values higher than 1 are often desirable, especially for very light objects. Unlike tightness, responseTime is tweaked in orders of magnitude with useful values (depending on mass) being between 10^-8 and 10^8. Both parameters can be applied to World for simulation-wide usage, or specified per-joint in case of distance and ball joints. Other joints don't allow customizing these parameters, and will use World settings instead..
2020-05-29 14:38:32 +00:00
float lovrBallJointGetResponseTime(Joint* joint) {
return dJointGetBallParam(joint->id, dParamCFM);
}
void lovrBallJointSetResponseTime(Joint* joint, float responseTime) {
dJointSetBallParam(joint->id, dParamCFM, responseTime);
}
float lovrBallJointGetTightness(Joint* joint) {
return dJointGetBallParam(joint->id, dParamERP);
}
void lovrBallJointSetTightness(Joint* joint, float tightness) {
dJointSetBallParam(joint->id, dParamERP, tightness);
}
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
Get/set World and Joint simulation parameters Tightness parameter is amount of force is exerted on collider to resolve collisions and enforce joint operation. Low values make joints loose, high values make it tight and can cause collider to overshot the joint target. With tightness set to 0 the joint loses its function. Going above 1 puts even more energy into joint oscillations. Tightness parameter is called ERP in ODE manual. The responseTime affects the time constant of physics simulation, both for collisions and for joint inertia. Low responseTime values make simulation tight and fast, higher values make it sluggish. For collisions it affects how fast penetration is resolved, with higher values resulting in spongy objects with more surface penetration and slower collision resolving. For joints the responseTime is similar to inertia, with higher responseTime values resulting in slow oscillations. The oscillation frequency is also affected by collider mass, so responseTime can be used to tweak the joint to get desired frequency with specific collider mass. Values higher than 1 are often desirable, especially for very light objects. Unlike tightness, responseTime is tweaked in orders of magnitude with useful values (depending on mass) being between 10^-8 and 10^8. Both parameters can be applied to World for simulation-wide usage, or specified per-joint in case of distance and ball joints. Other joints don't allow customizing these parameters, and will use World settings instead..
2020-05-29 14:38:32 +00:00
float lovrDistanceJointGetResponseTime(Joint* joint) {
return dJointGetDBallParam(joint->id, dParamCFM);
}
void lovrDistanceJointSetResponseTime(Joint* joint, float responseTime) {
dJointSetDBallParam(joint->id, dParamCFM, responseTime);
}
float lovrDistanceJointGetTightness(Joint* joint) {
return dJointGetDBallParam(joint->id, dParamERP);
}
void lovrDistanceJointSetTightness(Joint* joint, float tightness) {
dJointSetDBallParam(joint->id, dParamERP, tightness);
}
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
}