From 0547958961852fe51d5a1b3f77c6b97380cd87a2 Mon Sep 17 00:00:00 2001 From: Shariq Shah Date: Mon, 4 Dec 2017 20:01:18 +1100 Subject: [PATCH] Proper handling of rigidbody associated with an entity and notifying it of movement or collision --- README.md | 4 +- src/common/common.h | 6 +- src/game/main.c | 33 ++-- src/game/physics.c | 344 ++++++++++++++++++++------------------- src/game/physics.h | 6 +- src/libsymmetry/entity.c | 33 +++- src/libsymmetry/entity.h | 3 +- src/libsymmetry/game.c | 30 ++-- 8 files changed, 251 insertions(+), 208 deletions(-) diff --git a/README.md b/README.md index 78dbab6..5bbd54e 100644 --- a/README.md +++ b/README.md @@ -155,7 +155,7 @@ - ## TODO - - Proper physics time-step and speed + - Update physics if entity position/rotation/scale etc are changed - Fix lights type not being correctly saved/loaded from file - Physics Trimesh support - Debug physics mesh drawing @@ -356,3 +356,5 @@ * Implement necessary changes to run Soloud on linux * Moved third party libs/include directories into root/lib and root/include. Put common includes like header-only libs into root/include/common and others which require platform specific stuff into root/include/linux etc. * Got rid of pkg-confg and system-installed SDL2 dependancy on linux and instead put custom compiled SDL libs in libs folder similar to how we're handling it in windows + * Proper physics time-step and speed + * Proper handling of rigidbody associated with an entity and notifying it of movement or collision diff --git a/src/common/common.h b/src/common/common.h index 66af632..9a6e350 100644 --- a/src/common/common.h +++ b/src/common/common.h @@ -20,6 +20,7 @@ struct Sound_Source_Buffer; //Physics Decls typedef void* Rigidbody; typedef void (*RigidbodyMoveCB)(Rigidbody); +typedef void (*RigidbodyColCB)(Rigidbody, Rigidbody); // Function Pointer decls typedef void (*Keyboard_Event_Func) (int key, int scancode, int state, int repeat, int mod_ctrl, int mod_shift, int mod_alt); @@ -64,10 +65,13 @@ struct Physics_Api void (*body_rotation_get)(Rigidbody body, float* x, float* y, float* z, float* w); Rigidbody (*plane_create)(float a, float b, float c, float d); Rigidbody (*box_create)(float length, float width, float height); - void (*body_set_moved_callback)(Rigidbody body, RigidbodyMoveCB callback); + void (*body_set_moved_callback)(RigidbodyMoveCB callback); + void (*body_set_collision_callback)(RigidbodyColCB callback); void (*body_kinematic_set)(Rigidbody body); void (*body_mass_set)(Rigidbody body, float mass); float (*body_mass_get)(Rigidbody body); + void* (*body_data_get)(Rigidbody body); + void (*body_data_set)(Rigidbody body, void* data); }; struct Sound_Api diff --git a/src/game/main.c b/src/game/main.c index d069169..1f344f1 100644 --- a/src/game/main.c +++ b/src/game/main.c @@ -122,21 +122,24 @@ int main(int argc, char** args) }, .physics = { - .init = &physics_init, - .cleanup = &physics_cleanup, - .step = &physics_step, - .gravity_set = &physics_gravity_set, - .gravity_get = &physics_gravity_get, - .body_position_set = &physics_body_position_set, - .body_position_get = &physics_body_position_get, - .body_rotation_set = &physics_body_rotation_set, - .body_rotation_get = &physics_body_rotation_get, - .body_kinematic_set = &physics_body_kinematic_set, - .body_mass_set = &physics_body_mass_set, - .body_mass_get = &physics_body_mass_get, - .body_set_moved_callback = &physics_body_set_moved_callback, - .plane_create = &physics_plane_create, - .box_create = &physics_box_create + .init = &physics_init, + .cleanup = &physics_cleanup, + .step = &physics_step, + .gravity_set = &physics_gravity_set, + .gravity_get = &physics_gravity_get, + .body_position_set = &physics_body_position_set, + .body_position_get = &physics_body_position_get, + .body_rotation_set = &physics_body_rotation_set, + .body_rotation_get = &physics_body_rotation_get, + .body_kinematic_set = &physics_body_kinematic_set, + .body_mass_set = &physics_body_mass_set, + .body_mass_get = &physics_body_mass_get, + .body_data_set = &physics_body_data_set, + .body_data_get = &physics_body_data_get, + .body_set_moved_callback = &physics_body_set_moved_callback, + .body_set_collision_callback = &physics_body_set_collision_callback, + .plane_create = &physics_plane_create, + .box_create = &physics_box_create } }; diff --git a/src/game/physics.c b/src/game/physics.c index 2259d59..d46691e 100644 --- a/src/game/physics.c +++ b/src/game/physics.c @@ -1,134 +1,127 @@ -#include "physics.h" -#include "../common/log.h" - -#include -#include - -static struct -{ - dWorldID world; - dSpaceID space; - dJointGroupID contact_group; - double step_size; -} -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) -{ - //if(delta_time <= 0.f) delta_time = Physics.step_size; - //dSpaceCollide(Physics.space, NULL, physics_near_callback); - //dWorldQuickStep(Physics.world, delta_time); - ////dWorldStep(Physics.world, Physics.step_size); - //dJointGroupEmpty(Physics.contact_group); - - int steps = (int)ceilf(delta_time / Physics.step_size); - //log_message("Num steps : %d", steps); - for(int i = 0; i < steps; i++) - { - dSpaceCollide(Physics.space, NULL, physics_near_callback); - dWorldQuickStep(Physics.world, Physics.step_size); - //dWorldStep(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) -{ +#include "physics.h" +#include "../common/log.h" + +#include +#include + +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); @@ -171,7 +164,7 @@ void physics_near_callback(void* data, dGeomID o1, dGeomID o2) int n = dCollide(o1, o2, MAX_CONTACTS, &(contact[0].geom), sizeof(dContact)); if(n > 0) { - log_message("Collision!"); + Physics.on_collision(b1, b2); for(int i = 0; i < n; i++) { //contact[i].surface.slip1 = 0.7; @@ -186,47 +179,64 @@ void physics_near_callback(void* data, dGeomID o1, dGeomID o2) /*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); - return body; -} - -void physics_body_set_moved_callback(Rigidbody body, RigidbodyMoveCB callback) -{ - dBodySetMovedCallback(body, callback); + } +} + + +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; } -float physics_body_mass_get(Rigidbody body) +void physics_body_set_collision_callback(RigidbodyColCB callback) { - return 0.0f; + 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_mass_set(Rigidbody body, float mass) +void physics_body_data_set(Rigidbody body, void * data) { - /*dMass dmass; - dMassAdjust(&dmass, mass); - dBodySetMass(body, &dmass);*/ + dBodySetData(body, data); } -void physics_body_kinematic_set(Rigidbody body) +void * physics_body_data_get(Rigidbody body) { - dBodySetKinematic(body); -} \ No newline at end of file + return dBodyGetData(body); +} + +void physics_body_kinematic_set(Rigidbody body) +{ + dBodySetKinematic(body); +} diff --git a/src/game/physics.h b/src/game/physics.h index 0166298..8b0d0a4 100644 --- a/src/game/physics.h +++ b/src/game/physics.h @@ -18,11 +18,15 @@ void physics_body_rotation_set(Rigidbody body, float x, float y, float z, float Rigidbody physics_plane_create(float a, float b, float c, float d); Rigidbody physics_box_create(float length, float width, float height); -void physics_body_set_moved_callback(Rigidbody body, RigidbodyMoveCB callback); +void physics_body_set_moved_callback(RigidbodyMoveCB callback); +void physics_body_set_collision_callback(RigidbodyColCB callback); float physics_body_mass_get(Rigidbody body); void physics_body_mass_set(Rigidbody body, float mass); +void physics_body_data_set(Rigidbody body, void* data); +void* physics_body_data_get(Rigidbody body); + void physics_body_kinematic_set(Rigidbody body); #endif \ No newline at end of file diff --git a/src/libsymmetry/entity.c b/src/libsymmetry/entity.c index 4c37891..e09ead5 100644 --- a/src/libsymmetry/entity.c +++ b/src/libsymmetry/entity.c @@ -651,7 +651,36 @@ void entity_apply_sound_params(struct Entity* entity) } -void entity_on_rigidbody_move(Rigidbody body_A, Rigidbody body_B) +void entity_rigidbody_on_move(Rigidbody body) { - + int id = platform->physics.body_data_get(body); + struct Entity* entity = entity_get(id); + vec3 pos = {0}; + quat rot = {0}; + + platform->physics.body_position_get(body, &pos.x, &pos.y, &pos.z); + platform->physics.body_rotation_get(body, &rot.x, &rot.y, &rot.z, &rot.w); + + quat_assign(&entity->transform.rotation, &rot); + transform_set_position(entity, &pos); +} + +void entity_rigidbody_on_collision(Rigidbody body_A, Rigidbody body_B) +{ + struct Entity* ent_A = NULL; + struct Entity* ent_B = NULL; + + if(body_A) + { + int id_A = platform->physics.body_data_get(body_A); + ent_A = entity_get(id_A); + } + + if(body_B) + { + int id_B = platform->physics.body_data_get(body_B); + ent_B = entity_get(id_B); + } + + if(ent_A && ent_B) log_message("Entity %s collided with Entity %s", ent_A->name, ent_B->name); } diff --git a/src/libsymmetry/entity.h b/src/libsymmetry/entity.h index 76464fe..12932b2 100644 --- a/src/libsymmetry/entity.h +++ b/src/libsymmetry/entity.h @@ -141,6 +141,7 @@ bool entity_write(struct Entity* entity, struct Parser_Object* object) struct Entity* entity_read(struct Parser_Object* object); const char* entity_type_name_get(struct Entity* entity); void entity_apply_sound_params(struct Entity* entity); // Convenience function to sync the data set in entity's sound_source with the actual sound source's instance -void entity_on_rigidbody_move(Rigidbody body_A, Rigidbody body_B); +void entity_rigidbody_on_move(Rigidbody body); +void entity_rigidbody_on_collision(Rigidbody body_A, Rigidbody body_B); #endif diff --git a/src/libsymmetry/game.c b/src/libsymmetry/game.c index 7d1f66e..0455ad9 100644 --- a/src/libsymmetry/game.c +++ b/src/libsymmetry/game.c @@ -103,6 +103,8 @@ bool game_init(struct Window* window, struct Platform_Api* platform_api) entity_init(); platform->physics.init(); platform->physics.gravity_set(0.f, -9.8f, 0.f); + platform->physics.body_set_moved_callback(entity_rigidbody_on_move); + platform->physics.body_set_collision_callback(entity_rigidbody_on_collision); scene_init(); /* Debug scene setup */ @@ -254,12 +256,15 @@ void scene_setup(void) Rigidbody box = platform->physics.box_create(2.5, 2.5, 2.5); platform->physics.body_position_set(box, 0.f, 50.f, 0.f); platform->physics.body_mass_set(box, 10.f); - platform->physics.body_set_moved_callback(box, on_box_move); + platform->physics.body_data_set(box, (void*)suz_id); + + /*Rigidbody plane = platform->physics.plane_create(0, 1, 0, 0);*/ + Rigidbody ground_box = platform->physics.box_create(10, 10, 10); + platform->physics.body_position_set(ground_box, 0.f, 0.f, 0.f); + platform->physics.body_kinematic_set(ground_box); + struct Entity* ground = entity_find("Ground"); + platform->physics.body_data_set(ground_box, (void*)ground->id); - Rigidbody plane = platform->physics.plane_create(0, 1, 0, 0); - //Rigidbody ground_box = platform->physics.box_create(1000, 1, 1000); - /*platform->physics.body_position_set(ground_box, 0.f, 0.f, 0.f); - platform->physics.body_kinematic_set(ground_box);*/ } void debug(float dt) @@ -1706,19 +1711,4 @@ void game_cleanup(void) struct Game_State* game_state_get(void) { return game_state; -} - -void on_box_move(Rigidbody body) -{ - struct Entity* suz = entity_get(suz_id); - vec3 pos = {0}; - quat rot = {0}; - - platform->physics.body_position_get(body, &pos.x, &pos.y, &pos.z); - platform->physics.body_rotation_get(body, &rot.x, &rot.y, &rot.z, &rot.w); - - quat_assign(&suz->transform.rotation, &rot); - transform_set_position(suz, &pos); - - //log_message("Pos : %.3f, %.3f, %.3f", pos.x, pos.y, pos.z); } \ No newline at end of file