diff --git a/README.md b/README.md index 5bbd54e..4615273 100644 --- a/README.md +++ b/README.md @@ -156,6 +156,8 @@ - ## TODO - Update physics if entity position/rotation/scale etc are changed + - Physics raycasting + - Physics forces/torque etc - Fix lights type not being correctly saved/loaded from file - Physics Trimesh support - Debug physics mesh drawing @@ -358,3 +360,6 @@ * 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 + * Added physics spheres and other primitive shapes + * Separated collision shape and rigidbody + * Implemented Getting/Modifying primitive physics shapes' values like length, radius etc diff --git a/src/common/common.h b/src/common/common.h index 9a6e350..fb3d971 100644 --- a/src/common/common.h +++ b/src/common/common.h @@ -1,186 +1,211 @@ -#ifndef COMMON_H -#define COMMON_H - -#include - -#include "num_types.h" - -#ifdef GAME_LIB -extern struct Platform_Api* platform; -#endif - -#ifdef GAME -extern struct Game_Api game; -#endif - -struct Window; -struct Hashmap; -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); -typedef void (*Mousebutton_Event_Func) (int button, int state, int x, int y, int8 num_clicks); -typedef void (*Mousemotion_Event_Func) (int x, int y, int xrel, int yrel); -typedef void (*Mousewheel_Event_Func) (int x, int y); -typedef void (*Windowresize_Event_Func) (int x, int y); -typedef void (*Textinput_Event_Func) (const char* text); - -enum Directory_Type -{ - DIRT_USER, /* User directory or preferences directory */ - DIRT_INSTALL, /* Directory where the game's assets are, usually alongside the game's executable where the game is installed */ - DIRT_EXECUTABLE, /* Directory where the game's executable is located */ - DIRT_COUNT -}; - -enum Sound_Source_Type -{ - ST_WAV = 0, - ST_WAV_STREAM -}; - -enum Sound_Attenuation_Type -{ +#ifndef COMMON_H +#define COMMON_H + +#include + +#include "num_types.h" + +#ifdef GAME_LIB +extern struct Platform_Api* platform; +#endif + +#ifdef GAME +extern struct Game_Api game; +#endif + +struct Window; +struct Hashmap; +struct Sound_Source_Buffer; + +//Physics Decls +typedef void* Rigidbody; +typedef void* Collision_Shape; +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); +typedef void (*Mousebutton_Event_Func) (int button, int state, int x, int y, int8 num_clicks); +typedef void (*Mousemotion_Event_Func) (int x, int y, int xrel, int yrel); +typedef void (*Mousewheel_Event_Func) (int x, int y); +typedef void (*Windowresize_Event_Func) (int x, int y); +typedef void (*Textinput_Event_Func) (const char* text); + +enum Directory_Type +{ + DIRT_USER, /* User directory or preferences directory */ + DIRT_INSTALL, /* Directory where the game's assets are, usually alongside the game's executable where the game is installed */ + DIRT_EXECUTABLE, /* Directory where the game's executable is located */ + DIRT_COUNT +}; + +enum Sound_Source_Type +{ + ST_WAV = 0, + ST_WAV_STREAM +}; + +enum Sound_Attenuation_Type +{ SA_NONE = 0, // No attenuation SA_INVERSE, // Inverse distance attenuation model SA_LINEAR, // Linear distance attenuation model - SA_EXPONENTIAL // Exponential distance attenuation model -}; - -struct Physics_Api -{ - void (*init)(void); - void (*cleanup)(void); - void (*step)(float); - void (*gravity_set)(float x, float y, float z); - void (*gravity_get)(float* x, float* y, float* z); - void (*body_position_set)(Rigidbody body, float x, float y, float z); - void (*body_position_get)(Rigidbody body, float* x, float* y, float* z); - void (*body_rotation_set)(Rigidbody body, float x, float y, float z, float w); - 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)(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 -{ - void (*update_3d)(void); - void (*volume_set)(float volume); - void (*listener_update)(float apos_x, float apos_y, float apos_z, - float afwd_x, float afwd_y, float afwd_z, - float aup_x, float aup_y, float aup_z); - - void (*source_instance_update_position)(uint source_instance, float apos_x, float apos_y, float apos_z); - uint (*source_instance_create)(struct Sound_Source_Buffer* source, bool is3d); - void (*source_instance_destroy)(uint source_instance); - void (*source_instance_volume_set)(uint source_instance, float volume); - void (*source_instance_loop_set)(uint source_instance, bool loop); - void (*source_instance_play)(uint source_instance); - void (*source_instance_pause)(uint source_instance); - void (*source_instance_rewind)(uint source_instance); - void (*source_instance_stop)(uint source_instance); - void (*source_instance_min_max_distance_set)(uint source_instance, float min_distance, float max_distance); - void (*source_instance_attenuation_set)(uint source_instance, int attenuation_type, float rolloff_factor); - float (*source_instance_volume_get)(uint source_instance); - bool (*source_instance_loop_get)(uint source_instance); - bool (*source_instance_is_paused)(uint source_instance); - - struct Sound_Source_Buffer* (*source_create)(const char* filename, int type); - struct Sound_Source_Buffer* (*source_get)(const char* name); - void (*source_destroy)(const char* buffer_name); - void (*source_volume_set)(struct Sound_Source_Buffer* source, float volume); - void (*source_loop_set)(struct Sound_Source_Buffer* source, bool loop); - void (*source_stop_all)(struct Sound_Source_Buffer* source); - void (*source_min_max_distance_set)(struct Sound_Source_Buffer* source, float min_distance, float max_distance); -}; - -struct Window_Api -{ - struct Window* (*create)(const char* title, int width, int height, int msaa, int msaa_levels); - void (*destroy)(struct Window* window); - void (*show)(struct Window* window); - void (*hide)(struct Window* window); - void (*raise)(struct Window* window); - void (*make_context_current)(struct Window* window); - void (*set_size)(struct Window* window, int width, int height); - void (*get_size)(struct Window* window, int* out_width, int* out_height); - void (*get_drawable_size)(struct Window* window, int* out_width, int* out_height); - void (*swap_buffers)(struct Window* window); - int (*fullscreen_set)(struct Window* window, int fullscreen); -}; - -struct File_Api -{ - char* (*read)(const int directory_type, const char* path, const char* mode, long* file_size); - FILE* (*open)(const int directory_type, const char* path, const char* mode); - bool (*copy)(const int directory_type, const char* source, const char* destination); - bool (*delete)(const int directory_type, const char* filename); -}; - -struct Config_Api -{ - bool (*load)(const char* filename, int directory_type); - bool (*save)(const char* filename, int directory_types); - struct Hashmap* (*get)(void); -}; - -struct Log_Api -{ - FILE* (*file_handle_get)(void); -}; - -struct Platform_Api -{ - // General platform api - void (*poll_events)(bool* out_quit); - void (*keyboard_callback_set)(Keyboard_Event_Func func); - void (*mousebutton_callback_set)(Mousebutton_Event_Func func); - void (*mousemotion_callback_set)(Mousemotion_Event_Func func); - void (*mousewheel_callback_set)(Mousewheel_Event_Func func); - void (*windowresize_callback_set)(Windowresize_Event_Func func); - void (*textinput_callback_set)(Textinput_Event_Func func); - int (*is_key_pressed)(int key); - int (*mousebutton_state_get)(uint button); - void (*mouse_position_get)(int* x, int* y); - void (*mouse_delta_get)(int* x, int* y); - void (*mouse_position_set)(struct Window* window, int x, int y); - void (*mouse_global_position_set)(int x, int y); - void (*mouse_relative_mode_set)(int relative_mode); - int (*mouse_relative_mode_get)(void); - uint32 (*ticks_get)(void); - char* (*install_directory_get)(void); - char* (*user_directory_get)(const char* organization, const char* application); - void (*clipboard_text_set)(const char* text); - char* (*clipboard_text_get)(void); - int (*key_from_name)(const char* key_name); - const char* (*key_name_get)(int key); - void* (*load_function_gl)(const char* name); - void (*reload_game_lib)(void); - - struct Window_Api window; - struct Sound_Api sound; - struct File_Api file; - struct Config_Api config; - struct Log_Api log; - struct Physics_Api physics; -}; - -struct Game_Api -{ - bool (*init)(struct Window*, struct Platform_Api* platform_api); - void (*cleanup)(void); -}; - -#endif + SA_EXPONENTIAL // Exponential distance attenuation model +}; + +struct Physics_Api +{ + void (*init)(void); + void (*cleanup)(void); + void (*step)(float); + void (*gravity_set)(float x, float y, float z); + void (*gravity_get)(float* x, float* y, float* z); + + void (*cs_remove)(Collision_Shape shape); + + Collision_Shape (*cs_plane_create)(float a, float b, float c, float d); + void (*cs_plane_params_set)(Collision_Shape shape, float a, float b, float c, float d); + void (*cs_plane_params_get)(Collision_Shape shape, float* a, float* b, float* c, float* d); + + Collision_Shape (*cs_box_create)(float x, float y, float z); + void (*cs_box_params_set)(Collision_Shape shape, float x, float y, float z); + void (*cs_box_params_get)(Collision_Shape shape, float* x, float* y, float* z); + + Collision_Shape (*cs_sphere_create)(float radius); + void (*cs_shpere_radius_set)(Collision_Shape shape, float radius); + float (*cs_sphere_radius_get)(Collision_Shape shape); + + Collision_Shape (*cs_capsule_create)(float radius, float length); + void (*cs_capsule_params_set)(Collision_Shape shape, float radius, float length); + void (*cs_capsule_params_get)(Collision_Shape shape, float* radius, float* length); + + void (*body_remove)(Rigidbody body); + Rigidbody (*body_box_create)(float length, float width, float height); + Rigidbody (*body_sphere_create)(float radius); + Rigidbody (*body_capsule_create)(float radius, float height); + Collision_Shape (*body_cs_get)(Rigidbody body); + void (*body_cs_set)(Rigidbody body, Collision_Shape shape); + void (*body_position_set)(Rigidbody body, float x, float y, float z); + void (*body_position_get)(Rigidbody body, float* x, float* y, float* z); + void (*body_rotation_set)(Rigidbody body, float x, float y, float z, float w); + void (*body_rotation_get)(Rigidbody body, float* x, float* y, float* z, float* w); + 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); + void (*body_force_add)(Rigidbody body, float fx, float fy, float fz); +}; + +struct Sound_Api +{ + void (*update_3d)(void); + void (*volume_set)(float volume); + void (*listener_update)(float apos_x, float apos_y, float apos_z, + float afwd_x, float afwd_y, float afwd_z, + float aup_x, float aup_y, float aup_z); + + void (*source_instance_update_position)(uint source_instance, float apos_x, float apos_y, float apos_z); + uint (*source_instance_create)(struct Sound_Source_Buffer* source, bool is3d); + void (*source_instance_destroy)(uint source_instance); + void (*source_instance_volume_set)(uint source_instance, float volume); + void (*source_instance_loop_set)(uint source_instance, bool loop); + void (*source_instance_play)(uint source_instance); + void (*source_instance_pause)(uint source_instance); + void (*source_instance_rewind)(uint source_instance); + void (*source_instance_stop)(uint source_instance); + void (*source_instance_min_max_distance_set)(uint source_instance, float min_distance, float max_distance); + void (*source_instance_attenuation_set)(uint source_instance, int attenuation_type, float rolloff_factor); + float (*source_instance_volume_get)(uint source_instance); + bool (*source_instance_loop_get)(uint source_instance); + bool (*source_instance_is_paused)(uint source_instance); + + struct Sound_Source_Buffer* (*source_create)(const char* filename, int type); + struct Sound_Source_Buffer* (*source_get)(const char* name); + void (*source_destroy)(const char* buffer_name); + void (*source_volume_set)(struct Sound_Source_Buffer* source, float volume); + void (*source_loop_set)(struct Sound_Source_Buffer* source, bool loop); + void (*source_stop_all)(struct Sound_Source_Buffer* source); + void (*source_min_max_distance_set)(struct Sound_Source_Buffer* source, float min_distance, float max_distance); +}; + +struct Window_Api +{ + struct Window* (*create)(const char* title, int width, int height, int msaa, int msaa_levels); + void (*destroy)(struct Window* window); + void (*show)(struct Window* window); + void (*hide)(struct Window* window); + void (*raise)(struct Window* window); + void (*make_context_current)(struct Window* window); + void (*set_size)(struct Window* window, int width, int height); + void (*get_size)(struct Window* window, int* out_width, int* out_height); + void (*get_drawable_size)(struct Window* window, int* out_width, int* out_height); + void (*swap_buffers)(struct Window* window); + int (*fullscreen_set)(struct Window* window, int fullscreen); +}; + +struct File_Api +{ + char* (*read)(const int directory_type, const char* path, const char* mode, long* file_size); + FILE* (*open)(const int directory_type, const char* path, const char* mode); + bool (*copy)(const int directory_type, const char* source, const char* destination); + bool (*delete)(const int directory_type, const char* filename); +}; + +struct Config_Api +{ + bool (*load)(const char* filename, int directory_type); + bool (*save)(const char* filename, int directory_types); + struct Hashmap* (*get)(void); +}; + +struct Log_Api +{ + FILE* (*file_handle_get)(void); +}; + +struct Platform_Api +{ + // General platform api + void (*poll_events)(bool* out_quit); + void (*keyboard_callback_set)(Keyboard_Event_Func func); + void (*mousebutton_callback_set)(Mousebutton_Event_Func func); + void (*mousemotion_callback_set)(Mousemotion_Event_Func func); + void (*mousewheel_callback_set)(Mousewheel_Event_Func func); + void (*windowresize_callback_set)(Windowresize_Event_Func func); + void (*textinput_callback_set)(Textinput_Event_Func func); + int (*is_key_pressed)(int key); + int (*mousebutton_state_get)(uint button); + void (*mouse_position_get)(int* x, int* y); + void (*mouse_delta_get)(int* x, int* y); + void (*mouse_position_set)(struct Window* window, int x, int y); + void (*mouse_global_position_set)(int x, int y); + void (*mouse_relative_mode_set)(int relative_mode); + int (*mouse_relative_mode_get)(void); + uint32 (*ticks_get)(void); + char* (*install_directory_get)(void); + char* (*user_directory_get)(const char* organization, const char* application); + void (*clipboard_text_set)(const char* text); + char* (*clipboard_text_get)(void); + int (*key_from_name)(const char* key_name); + const char* (*key_name_get)(int key); + void* (*load_function_gl)(const char* name); + void (*reload_game_lib)(void); + + struct Window_Api window; + struct Sound_Api sound; + struct File_Api file; + struct Config_Api config; + struct Log_Api log; + struct Physics_Api physics; +}; + +struct Game_Api +{ + bool (*init)(struct Window*, struct Platform_Api* platform_api); + void (*cleanup)(void); +}; + +#endif diff --git a/src/game/main.c b/src/game/main.c index 1f344f1..7ae3cd8 100644 --- a/src/game/main.c +++ b/src/game/main.c @@ -79,15 +79,15 @@ int main(int argc, char** args) .source_instance_stop = &sound_source_instance_stop, .source_instance_min_max_distance_set = &sound_source_instance_min_max_distance_set, .source_instance_attenuation_set = &sound_source_instance_attenuation_set, - .source_instance_volume_get = &sound_source_instance_volume_get, - .source_instance_loop_get = &sound_source_instance_loop_get, + .source_instance_volume_get = &sound_source_instance_volume_get, + .source_instance_loop_get = &sound_source_instance_loop_get, .source_instance_is_paused = &sound_source_instance_is_paused, - .source_create = &sound_source_create, - .source_get = &sound_source_get, - .source_destroy = &sound_source_destroy, - .source_volume_set = &sound_source_volume_set, - .source_loop_set = &sound_source_loop_set, - .source_stop_all = &sound_source_stop_all, + .source_create = &sound_source_create, + .source_get = &sound_source_get, + .source_destroy = &sound_source_destroy, + .source_volume_set = &sound_source_volume_set, + .source_loop_set = &sound_source_loop_set, + .source_stop_all = &sound_source_stop_all, .source_min_max_distance_set = &sound_source_min_max_distance_set }, .window = @@ -127,6 +127,7 @@ int main(int argc, char** args) .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, @@ -138,8 +139,27 @@ int main(int argc, char** args) .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 + .body_force_add = &physics_body_force_add, + .body_box_create = &physics_body_box_create, + .body_sphere_create = &physics_body_sphere_create, + .body_capsule_create = &physics_body_capsule_create, + .body_remove = &physics_body_remove, + .body_cs_set = &physics_body_cs_set, + .body_cs_get = &physics_body_cs_get, + + .cs_box_create = &physics_cs_box_create, + .cs_plane_create = &physics_cs_plane_create, + .cs_sphere_create = &physics_cs_sphere_create, + .cs_capsule_create = &physics_cs_capsule_create, + .cs_remove = &physics_cs_remove, + .cs_plane_params_get = &physics_cs_plane_params_get, + .cs_capsule_params_get = &physics_cs_capsule_params_get, + .cs_box_params_get = &physics_cs_box_params_get, + .cs_sphere_radius_get = &physics_cs_sphere_radius_get, + .cs_plane_params_set = &physics_cs_plane_params_set, + .cs_capsule_params_set = &physics_cs_capsule_params_set, + .cs_box_params_set = &physics_cs_box_params_set, + .cs_shpere_radius_set = &physics_cs_sphere_radius_set } }; diff --git a/src/game/physics.c b/src/game/physics.c index d46691e..a41236f 100644 --- a/src/game/physics.c +++ b/src/game/physics.c @@ -1,229 +1,385 @@ -#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); - - //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; +#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); + + //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));*/ + } + } +} + +Collision_Shape physics_body_cs_get(Rigidbody body) +{ + return dBodyGetFirstGeom(body); +} + +void physics_body_cs_set(Rigidbody body, Collision_Shape shape) +{ + dGeomSetBody(shape, body); +} + +Collision_Shape physics_cs_plane_create(float a, float b, float c, float d) +{ + dGeomID plane = dCreatePlane(Physics.space, a, b, c, d); + return plane; +} + +void physics_cs_plane_params_set(Collision_Shape shape, float a, float b, float c, float d) +{ + dGeomPlaneSetParams(shape, a, b, c, d); +} + +void physics_cs_plane_params_get(Collision_Shape shape, float* a, float* b, float* c, float* d) +{ + assert(a && b && c && d); + *a = *b = *c = *d = 0.f; + float result[4] = { 0.f }; + dGeomPlaneGetParams(shape, result); + *a = result[0]; + *b = result[1]; + *c = result[2]; + *d = result[3]; +} + +Collision_Shape physics_cs_box_create(float x, float y, float z) +{ + dGeomID box = dCreateBox(Physics.space, x, y, z); + if(!box) + { + log_error("physics:cs_box_create", "Failed to create box collision shape"); + } + return box; + +} + +void physics_cs_box_params_get(Collision_Shape shape, float* x, float* y, float* z) +{ + assert(x && y && z); + *x = *y = *z = 0.f; + float lengths[3] = { 0.f }; + dGeomBoxGetLengths(shape, lengths); + *x = lengths[0]; + *y = lengths[1]; + *z = lengths[2]; +} + +void physics_cs_box_params_set(Collision_Shape shape, float x, float y, float z) +{ + dGeomBoxSetLengths(shape, x, y, z); +} + +Collision_Shape physics_cs_sphere_create(float radius) +{ + dGeomID sphere = dCreateSphere(Physics.space, radius); + if(!sphere) + { + log_error("physics:cs_sphere_create", "Failed to create sphere collision shape"); + } + return sphere; +} + +float physics_cs_sphere_radius_get(Collision_Shape shape) +{ + return dGeomSphereGetRadius(shape); +} + +void physics_cs_sphere_radius_set(Collision_Shape shape, float radius) +{ + dGeomSphereSetRadius(shape, radius); +} + +Collision_Shape physics_cs_capsule_create(float radius, float length) +{ + dGeomID capsule = dCreateCapsule(Physics.space, radius, length); + if(!capsule) + { + log_error("physics:cs_capsule_create", "Failed to create capsule collision shape"); + } + return capsule; +} + +void physics_cs_capsule_params_get(Collision_Shape shape, float* radius, float* length) +{ + assert(radius && length); + *radius = *length = 0.f; + dGeomCapsuleGetParams(shape, radius, length); +} + +void physics_cs_capsule_params_set(Collision_Shape shape, float radius, float length) +{ + dGeomCapsuleSetParams(shape, radius, length); +} + +void physics_box_params_get(Rigidbody body, float* x, float* y, float* z) +{ + assert(x && y && z); + *x = *y = *z = 0.f; + dGeomID box = dBodyGetFirstGeom(body); + if(box == 0) + { + log_error("physics:box_get_params", "Body has invalid geometry"); + return; + } + float lengths[3] = { 0.f }; + dGeomBoxGetLengths(box, lengths); + *x = lengths[0]; + *y = lengths[1]; + *z = lengths[2]; +} + +void physics_box_params_set(Rigidbody body, float x, float y, float z) +{ + assert(x && y && z); + dGeomID box = dBodyGetFirstGeom(body); + if(box == 0) + { + log_error("physics:box_get_params", "Body has invalid geometry"); + return; + } + dGeomBoxSetLengths(box, x, y, z); +} + +Rigidbody physics_body_box_create(float x, float y, float z) +{ + Rigidbody body = NULL; + Collision_Shape box = physics_cs_box_create(x, y, z); + if(box) + { + body = dBodyCreate(Physics.world); + physics_body_cs_set(body, box); + dBodySetMovedCallback(body, Physics.on_move); + } + + return body; +} + +Rigidbody physics_body_sphere_create(float radius) +{ + Rigidbody body = NULL; + Collision_Shape sphere = physics_cs_sphere_create(radius); + if(sphere) + { + body = dBodyCreate(Physics.world); + physics_body_cs_set(body, sphere); + dBodySetMovedCallback(body, Physics.on_move); + } + + return body; +} + +Rigidbody physics_body_capsule_create(float radius, float length) +{ + Rigidbody body = NULL; + Collision_Shape capsule = physics_cs_capsule_create(radius, length); + if(capsule) + { + body = dBodyCreate(Physics.world); + physics_body_cs_set(body, capsule); + dBodySetMovedCallback(body, Physics.on_move); + } + + return body; +} + +void physics_body_force_add(Rigidbody body, float fx, float fy, float fz) +{ + dBodyAddForce(body, fx, fy, fz); +} + +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);*/ +} + +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) @@ -234,9 +390,22 @@ void physics_body_data_set(Rigidbody body, void * data) void * physics_body_data_get(Rigidbody body) { return dBodyGetData(body); -} - -void physics_body_kinematic_set(Rigidbody body) -{ - dBodySetKinematic(body); -} +} + +void physics_body_kinematic_set(Rigidbody body) +{ + dBodySetKinematic(body); +} + +void physics_body_remove(Rigidbody body) +{ + dGeomID shape = dBodyGetFirstGeom(body); + if(shape) + physics_cs_remove(shape); + dBodyDestroy(body); +} + +void physics_cs_remove(Collision_Shape shape) +{ + dGeomDestroy(shape); +} diff --git a/src/game/physics.h b/src/game/physics.h index 8b0d0a4..c2993fa 100644 --- a/src/game/physics.h +++ b/src/game/physics.h @@ -15,8 +15,32 @@ void physics_body_position_set(Rigidbody body, float x, float y, float z); void physics_body_rotation_get(Rigidbody body, float* x, float* y, float* z, float* w); void physics_body_rotation_set(Rigidbody body, float x, float y, float z, float w); -Rigidbody physics_plane_create(float a, float b, float c, float d); -Rigidbody physics_box_create(float length, float width, float height); +Collision_Shape physics_body_cs_get(Rigidbody body); +void physics_body_cs_set(Rigidbody body, Collision_Shape shape); + +void physics_cs_remove(Collision_Shape shape); + +Collision_Shape physics_cs_plane_create(float a, float b, float c, float d); +void physics_cs_plane_params_set(Collision_Shape shape, float a, float b, float c, float d); +void physics_cs_plane_params_get(Collision_Shape shape, float* a, float* b, float* c, float* d); + +Collision_Shape physics_cs_box_create(float x, float y, float z); +void physics_cs_box_params_get(Collision_Shape shape, float* x, float* y, float* z); +void physics_cs_box_params_set(Collision_Shape shape, float x, float y, float z); + +Collision_Shape physics_cs_sphere_create(float radius); +float physics_cs_sphere_radius_get(Collision_Shape shape); +void physics_cs_sphere_radius_set(Collision_Shape shape, float radius); + +Collision_Shape physics_cs_capsule_create(float radius, float height); +void physics_cs_capsule_params_get(Collision_Shape shape, float* radius, float* height); +void physics_cs_capsule_params_set(Collision_Shape shape, float radius, float height); + +Rigidbody physics_body_box_create(float x, float y, float z); +Rigidbody physics_body_sphere_create(float radius); +Rigidbody physics_body_capsule_create(float radius, float height); + +void physics_body_remove(Rigidbody body); void physics_body_set_moved_callback(RigidbodyMoveCB callback); void physics_body_set_collision_callback(RigidbodyColCB callback); @@ -27,6 +51,8 @@ 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_force_add(Rigidbody body, float fx, float fy, float fz); + void physics_body_kinematic_set(Rigidbody body); #endif \ No newline at end of file diff --git a/src/libsymmetry/game.c b/src/libsymmetry/game.c index 0455ad9..bcf7efe 100644 --- a/src/libsymmetry/game.c +++ b/src/libsymmetry/game.c @@ -252,14 +252,15 @@ void scene_setup(void) camera_update_proj(player);*/ } - platform->physics.plane_create(0, 1, 0, 0); - Rigidbody box = platform->physics.box_create(2.5, 2.5, 2.5); + platform->physics.cs_plane_create(0, 1, 0, 0); + Rigidbody box = platform->physics.body_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_data_set(box, (void*)suz_id); + platform->physics.body_force_add(box, -100.f, 0.f, 0.f); /*Rigidbody plane = platform->physics.plane_create(0, 1, 0, 0);*/ - Rigidbody ground_box = platform->physics.box_create(10, 10, 10); + Rigidbody ground_box = platform->physics.body_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");