A 3d fps game made in OpenGL
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 
 
 
 
Symmetry/src/game/physics.c

242 lines
5.7 KiB

#include "physics.h"
#include "../common/log.h"
#include <ode/ode.h>
#include <assert.h>
static struct
{
dWorldID world;
dSpaceID space;
dJointGroupID contact_group;
double step_size;
RigidbodyColCB on_collision;
RigidbodyMoveCB on_move;
}
Physics;
static void physics_near_callback(void* data, dGeomID body1, dGeomID body2);
void physics_init(void)
{
if(dInitODE2(0) == 0)
{
log_error("physics:init", "Failed to initialize ode");
return;
}
dAllocateODEDataForThread(dAllocateMaskAll);
Physics.world = dWorldCreate();
if(!Physics.world)
{
log_error("physics:init", "Physics world created!");
}
else
{
log_message("Physics world created");
Physics.space = dHashSpaceCreate(0);
Physics.contact_group = dJointGroupCreate(0);
Physics.step_size = 0.016;
dWorldSetCFM(Physics.world,1e-5);
dWorldSetAutoDisableFlag(Physics.world, 1);
dWorldSetLinearDamping(Physics.world, 0.00001);
dWorldSetAngularDamping(Physics.world, 0.005);
dWorldSetMaxAngularSpeed(Physics.world, 200);
dWorldSetContactMaxCorrectingVel(Physics.world,0.1);
dWorldSetContactSurfaceLayer(Physics.world,0.001);
}
}
void physics_cleanup(void)
{
dJointGroupDestroy(Physics.contact_group);
dSpaceDestroy(Physics.space);
if(Physics.world)
{
dWorldDestroy(Physics.world);
}
dCleanupODEAllDataForThread();
dCloseODE();
}
void physics_step(float delta_time)
{
int steps = (int)ceilf(delta_time / Physics.step_size);
for(int i = 0; i < steps; i++)
{
dSpaceCollide(Physics.space, NULL, physics_near_callback);
dWorldQuickStep(Physics.world, Physics.step_size);
dJointGroupEmpty(Physics.contact_group);
}
}
void physics_gravity_set(float x, float y, float z)
{
dWorldSetGravity(Physics.world, x, y, z);
}
void physics_gravity_get(float * x, float * y, float * z)
{
assert(x && y && z);
dVector3 gravity;
dWorldGetGravity(Physics.world, gravity);
*x = gravity[0];
*y = gravity[1];
*z = gravity[2];
}
void physics_body_position_get(Rigidbody body, float * x, float * y, float * z)
{
assert(x && y && z);
const dReal* position = dBodyGetPosition(body);
*x = position[0];
*y = position[1];
*z = position[2];
}
void physics_body_position_set(Rigidbody body, float x, float y, float z)
{
dBodySetPosition(body, x, y, z);
}
void physics_body_rotation_get(Rigidbody body, float * x, float * y, float * z, float * w)
{
assert(x && y && z && w);
const dReal* rotation = dBodyGetQuaternion(body);
*x = rotation[1];
*y = rotation[2];
*z = rotation[3];
*w = rotation[0];
}
void physics_body_rotation_set(Rigidbody body, float x, float y, float z, float w)
{
dReal rotation[4] = { 0 };
rotation[1] = x;
rotation[2] = y;
rotation[3] = z;
rotation[0] = w;
dBodySetQuaternion(body, &rotation[0]);
}
void physics_near_callback(void* data, dGeomID o1, dGeomID o2)
{
assert(o1);
assert(o2);
//if(dGeomIsSpace(o1) || dGeomIsSpace(o2))
//{
// fprintf(stderr, "testing space %p %p\n", (void*)o1, (void*)o2);
// // colliding a space with something
// dSpaceCollide2(o1, o2, data, &physics_near_callback);
// // Note we do not want to test intersections within a space,
// // only between spaces.
// return;
//}
// fprintf(stderr,"testing geoms %p %p\n", o1, o2);
// exit without doing anything if the two bodies are connected by a joint
dBodyID b1 = dGeomGetBody(o1);
dBodyID b2 = dGeomGetBody(o2);
if (b1 && b2 && dAreConnectedExcluding(b1,b2,dJointTypeContact))
return;
if(o1 == o2)
log_message("same body!");
#define MAX_CONTACTS 8
dContact contact[MAX_CONTACTS];
for (int i = 0; i < MAX_CONTACTS; i++)
{
//contact[i].surface.mode = dContactBounce | dContactSoftCFM;
contact[i].surface.mode = dContactBounce | dContactSoftCFM;
contact[i].surface.mu = dInfinity;
contact[i].surface.mu2 = 0;
contact[i].surface.bounce = 0.1;
contact[i].surface.bounce_vel = 0.1;
contact[i].surface.soft_cfm = 0.01;
}
int n = dCollide(o1, o2, MAX_CONTACTS, &(contact[0].geom), sizeof(dContact));
if(n > 0)
{
Physics.on_collision(b1, b2);
for(int i = 0; i < n; i++)
{
//contact[i].surface.slip1 = 0.7;
//contact[i].surface.slip2 = 0.7;
//contact[i].surface.mode = dContactSoftERP | dContactSoftCFM | dContactApprox1 | dContactSlip1 | dContactSlip2;
//contact[i].surface.mu = 50.0; // was: dInfinity
//contact[i].surface.soft_erp = 0.96;
//contact[i].surface.soft_cfm = 0.04;
dJointID c = dJointCreateContact(Physics.world, Physics.contact_group, &contact[i]);
dJointAttach(c, b1, b2);
/*dGeomGetBody(contact[i].geom.g1),
dGeomGetBody(contact[i].geom.g2));*/
}
}
}
Rigidbody physics_plane_create(float a, float b, float c, float d)
{
dGeomID plane = dCreatePlane(Physics.space, a, b, c, d);
/*dBodyID body = dBodyCreate(Physics.world);
dGeomSetBody(plane, body);*/
return plane;
}
Rigidbody physics_box_create(float length, float width, float height)
{
dGeomID box = dCreateBox(Physics.space, length, height, width);
dBodyID body = dBodyCreate(Physics.world);
dGeomSetBody(box, body);
dBodySetAngularVel(body, 0, 0, 0);
dBodySetLinearVel(body, 0, 0, 0);
dBodySetTorque(body, 0, 0, 0);
dBodySetMovedCallback(body, Physics.on_move);
return body;
}
void physics_body_set_moved_callback(RigidbodyMoveCB callback)
{
Physics.on_move = callback;
}
void physics_body_set_collision_callback(RigidbodyColCB callback)
{
Physics.on_collision = callback;
}
float physics_body_mass_get(Rigidbody body)
{
return 0.0f;
}
void physics_body_mass_set(Rigidbody body, float mass)
{
/*dMass dmass;
dMassAdjust(&dmass, mass);
dBodySetMass(body, &dmass);*/
}
void physics_body_data_set(Rigidbody body, void * data)
{
dBodySetData(body, data);
}
void * physics_body_data_get(Rigidbody body)
{
return dBodyGetData(body);
}
void physics_body_kinematic_set(Rigidbody body)
{
dBodySetKinematic(body);
}