From ca3e40782ac0be7b11fff5079a11291456f3073b Mon Sep 17 00:00:00 2001 From: Bruno Dilly Date: Tue, 31 Jul 2012 19:55:52 +0000 Subject: [PATCH] EPhysics: allow user to configure simulation Required to fine tunning performance or avoid objects going throught others. SVN revision: 74659 --- .../ephysics/src/bin/test_collision_speed.c | 3 +- legacy/ephysics/src/lib/EPhysics.h | 80 +++++++++++++++++++ legacy/ephysics/src/lib/ephysics_world.cpp | 50 +++++++++++- 3 files changed, 130 insertions(+), 3 deletions(-) diff --git a/legacy/ephysics/src/bin/test_collision_speed.c b/legacy/ephysics/src/bin/test_collision_speed.c index 17a1fde135..5429ad7e1e 100644 --- a/legacy/ephysics/src/bin/test_collision_speed.c +++ b/legacy/ephysics/src/bin/test_collision_speed.c @@ -115,7 +115,7 @@ test_collision_speed(void *data __UNUSED__, Evas_Object *obj __UNUSED__, void *e speed_data->bt = bt; sp = elm_spinner_add(speed_data->base.win); - elm_spinner_min_max_set(sp, 0, 500); + elm_spinner_min_max_set(sp, 0, 300); elm_spinner_step_set(sp, 5); elm_spinner_value_set(sp, 100); elm_object_style_set(sp, "ephysics-test"); @@ -124,6 +124,7 @@ test_collision_speed(void *data __UNUSED__, Evas_Object *obj __UNUSED__, void *e world = ephysics_world_new(); ephysics_world_render_geometry_set(world, 50, 40, WIDTH - 100, FLOOR_Y - 40); + ephysics_world_simulation_set(world, 1/260.f, 5); speed_data->base.world = world; boundary = ephysics_body_bottom_boundary_add(world); diff --git a/legacy/ephysics/src/lib/EPhysics.h b/legacy/ephysics/src/lib/EPhysics.h index 8c42394fc4..f4c8227299 100644 --- a/legacy/ephysics/src/lib/EPhysics.h +++ b/legacy/ephysics/src/lib/EPhysics.h @@ -950,6 +950,86 @@ EAPI void ephysics_world_bodies_outside_left_autodel_set(EPhysics_World *world, */ EAPI Eina_Bool ephysics_world_bodies_outside_left_autodel_get(const EPhysics_World *world); +/** + * @brief + * Set world simulation's fixed time step and max number of sub steps + * configuration. + * + * It's important that time step is always less than + * @p max_sub_steps * @p fixed_time_step, otherwise you are losing time. + * Mathematically: + * + * time step < @p max_sub_steps * @p fixed_time_step; + * + * If you're a using a very large time step + * [say, five times the size of the fixed internal time step], + * then you must increase the number of max sub steps to compensate for this, + * otherwise your simulation is “losing” time. + * + * The time step may vary. Simulation ticks are called by an animator, + * so, by default, time step is @c 1/30 secs. If you're using elementary, + * default FPS configuration is 60 fps, i.e. time step is @c 1/60 secs. + * You can change that setting a + * different time with ecore_animator_frametime_set(). + * + * Also, keep in mind + * that if you're using CPU intense calculations maybe this framerate won't + * be achieved, so the time step will be bigger. You need to define + * what range of frames per secons you need to support and configure + * @p max_sub_steps and @p fixed_time_step according to this. + * + * By decreasing the size of @p fixed_time_step, you are increasing the + * “resolution” of the simulation. + * + * If you are finding that your objects are moving very fast and escaping + * from your walls instead of colliding with them, then one way to help fix + * this problem is by decreasing @p fixed_time_step. If you do this, + * then you will need to increase @p max_sub_steps to ensure the equation + * listed above is still satisfied. + * + * The issue with this is that each internal “tick” takes an amount of + * computation. More of them means your CPU will be spending more time on + * physics and therefore less time on other stuff. Say you want twice the + * resolution, you'll need twice the @p max_sub_steps, which could chew up + * twice as much CPU for the same amount of simulation time. + * + * When you pass @p max_sub_steps > 1, it will interpolate movement for you. + * This means that if your @p fixed_time_step is 3 units, and you pass + * a timeStep of 4, then it will do exactly one tick, and estimate the + * remaining movement by 1/3. This saves you having to do interpolation + * yourself, but keep in mind that maxSubSteps needs to be greater than 1. + * + * By default @p fixed_time_step is 1/60 seconds and @p max_sub_steps is 3. + * + * @param world The physics world. + * @param fixed_time_step size of the internal simulation step, in seconds. + * @param max_sub_steps maximum number of steps that simulation is allowed + * to take at each simulation tick. + * + * @note The unit used for time is seconds. + * + * @see ephysics_world_simulation_get(). + * + * @ingroup EPhysics_World + */ +EAPI void ephysics_world_simulation_set(EPhysics_World *world, double fixed_time_step, int max_sub_steps); + +/** + * @brief + * Get world simulation's fixed time step and max number of sub steps + * configuration. + * + * @param world The physics world. + * @param fixed_time_step size of the internal simulation step, in seconds. + * @param max_sub_steps maximum number of steps that simulation is allowed + * to take at each simulation tick. + * + * @see ephysics_world_simulation_set() for details. + * + * @ingroup EPhysics_World + */ +EAPI void ephysics_world_simulation_get(const EPhysics_World *world, double *fixed_time_step, int *max_sub_steps); + /** * @} */ diff --git a/legacy/ephysics/src/lib/ephysics_world.cpp b/legacy/ephysics/src/lib/ephysics_world.cpp index e21ebd76f9..af1a043550 100644 --- a/legacy/ephysics/src/lib/ephysics_world.cpp +++ b/legacy/ephysics/src/lib/ephysics_world.cpp @@ -31,8 +31,10 @@ struct _EPhysics_World { Evas_Coord x, y, w, h; Eina_Inlist *callbacks; Eina_List *bodies; + int max_sub_steps; double last_update; double rate; + double fixed_time_step; Eina_Bool running:1; Eina_Bool active:1; Eina_Bool outside_autodel:1; @@ -141,7 +143,8 @@ _simulate_worlds(void *data) world->last_update = time_now; gDeactivationTime = world->max_sleeping_time; - world->dynamics_world->stepSimulation(delta, 1, 1/40.f); + world->dynamics_world->stepSimulation(delta, world->max_sub_steps, + world->fixed_time_step); } return EINA_TRUE; @@ -342,6 +345,8 @@ ephysics_world_new(void) world->dynamics_world->getPairCache()->setOverlapFilterCallback(filter_cb); world->rate = 30; + world->max_sub_steps = 3; + world->fixed_time_step = 1/60.f; world->dynamics_world->setInternalTickCallback(_ephysics_world_tick_cb, (void *) world); @@ -927,7 +932,7 @@ ephysics_world_bodies_outside_right_autodel_get(const EPhysics_World *world) return world->outside_right; } -Eina_Bool +EAPI Eina_Bool ephysics_world_bodies_outside_autodel_get(const EPhysics_World *world) { if (!world) @@ -939,6 +944,47 @@ ephysics_world_bodies_outside_autodel_get(const EPhysics_World *world) return world->outside_autodel; } +EAPI void +ephysics_world_simulation_set(EPhysics_World *world, double fixed_time_step, int max_sub_steps) +{ + if (!world) + { + ERR("Can't set simulation, no world provided."); + return; + } + + if (max_sub_steps < 1) + { + ERR("At least one sub step for simulation is required."); + return; + } + + if (ecore_animator_frametime_get() >= max_sub_steps * fixed_time_step) + { + ERR("Assure frametime < max sub steps * fixed time step."); + return; + } + + world->max_sub_steps = max_sub_steps; + world->fixed_time_step = fixed_time_step; + + DBG("World %p simulation set to fixed time step: %lf, max substeps:%i.", + world, fixed_time_step, max_sub_steps); +} + +EAPI void +ephysics_world_simulation_get(const EPhysics_World *world, double *fixed_time_step, int *max_sub_steps) +{ + if (!world) + { + ERR("No world, can't get simulation configuration."); + return; + } + + if (fixed_time_step) *fixed_time_step = world->fixed_time_step; + if (max_sub_steps) *max_sub_steps = world->max_sub_steps; +} + #ifdef __cplusplus } #endif