From 9d0b63143bb74cac808f7db842ba39a215e45112 Mon Sep 17 00:00:00 2001 From: Bruno Dilly Date: Tue, 3 Jul 2012 23:20:49 +0000 Subject: [PATCH] EPhysics: support autodel of bodies outside render area Now it's possible to request a world to delete bodies outside render area, so we can save some resources and avoid issues with world stopped event. SVN revision: 73245 --- legacy/ephysics/src/lib/EPhysics.h | 144 +++++++++++++++++++++ legacy/ephysics/src/lib/ephysics_body.cpp | 27 ++++ legacy/ephysics/src/lib/ephysics_private.h | 1 + legacy/ephysics/src/lib/ephysics_world.cpp | 121 +++++++++++++++++ 4 files changed, 293 insertions(+) diff --git a/legacy/ephysics/src/lib/EPhysics.h b/legacy/ephysics/src/lib/EPhysics.h index 994d9891d4..5b48fffdef 100644 --- a/legacy/ephysics/src/lib/EPhysics.h +++ b/legacy/ephysics/src/lib/EPhysics.h @@ -621,6 +621,150 @@ EAPI void ephysics_world_linear_slop_set(EPhysics_World *world, double linear_sl */ EAPI double ephysics_world_linear_slop_get(EPhysics_World *world); +/** + * @brief + * Set world autodeleting bodies mode when they're outside of render area + * by the top. + * + * It's useful when you don't care about bodies leaving the render + * area set with @ref ephysics_world_render_area_set(), and don't think + * they could / should return. So you can safely delete them and save resources. + * + * Also, it's useful if you have only a bottom border set with + * @ref ephysics_body_top_boundary_add() and gravity set, + * and want to listen for @ref EPHYSICS_CALLBACK_WORLD_STOPPED event. + * If a body goes out of the render area, they will be acting by gravity + * and won't collide to anything, so they could be moving forever and + * world would never stop. For this case, enabling autodel for left and right + * borders seems to be a good idea. + * + * @param world The physics world. + * @param autodel If @c EINA_TRUE delete bodies when they are outside render + * area, otherwise, don't delete. + * + * @see ephysics_world_bodies_outside_top_autodel_get(). + * @see ephysics_world_bodies_outside_bottom_autodel_set(). + * @see ephysics_world_bodies_outside_left_autodel_set(). + * @see ephysics_world_bodies_outside_right_autodel_set(). + * + * @ingroup EPhysics_World + */ +EAPI void ephysics_world_bodies_outside_top_autodel_set(EPhysics_World *world, Eina_Bool autodel); + +/** + * @brief + * Get world autodeleting bodies mode when they're outside of render area by + * the top. + * + * @param world The physics world. + * @return @c EINA_TRUE if bodies will be deleted or @c EINA_FALSE if they + * won't, or on error. + * + * @see ephysics_world_bodies_outside_top_autodel_set() for details. + * + * @ingroup EPhysics_World + */ +EAPI Eina_Bool ephysics_world_bodies_outside_top_autodel_get(EPhysics_World *world); + +/** + * @brief + * Set world autodeleting bodies mode when they're outside of render area + * by the bottom. + * + * @param world The physics world. + * @param autodel If @c EINA_TRUE delete bodies when they are outside render + * area, otherwise, don't delete. + * + * @see ephysics_world_bodies_outside_top_autodel_set() for more details. + * @see ephysics_world_bodies_outside_bottom_autodel_get(). + * @see ephysics_world_bodies_outside_left_autodel_set(). + * @see ephysics_world_bodies_outside_right_autodel_set(). + * + * @ingroup EPhysics_World + */ +EAPI void ephysics_world_bodies_outside_bottom_autodel_set(EPhysics_World *world, Eina_Bool autodel); + +/** + * @brief + * Get world autodeleting bodies mode when they're outside of render area by + * the bottom. + * + * @param world The physics world. + * @return @c EINA_TRUE if bodies will be deleted or @c EINA_FALSE if they + * won't, or on error. + * + * @see ephysics_world_bodies_outside_bottom_autodel_set() for details. + * + * @ingroup EPhysics_World + */ +EAPI Eina_Bool ephysics_world_bodies_outside_bottom_autodel_get(EPhysics_World *world); + +/** + * @brief + * Set world autodeleting bodies mode when they're outside of render area + * by the right. + * + * @param world The physics world. + * @param autodel If @c EINA_TRUE delete bodies when they are outside render + * area, otherwise, don't delete. + * + * @see ephysics_world_bodies_outside_top_autodel_set() for more details. + * @see ephysics_world_bodies_outside_right_autodel_get(). + * @see ephysics_world_bodies_outside_bottom_autodel_set(). + * @see ephysics_world_bodies_outside_left_autodel_set(). + * + * @ingroup EPhysics_World + */ +EAPI void ephysics_world_bodies_outside_right_autodel_set(EPhysics_World *world, Eina_Bool autodel); + +/** + * @brief + * Get world autodeleting bodies mode when they're outside of render area by + * the right. + * + * @param world The physics world. + * @return @c EINA_TRUE if bodies will be deleted or @c EINA_FALSE if they + * won't, or on error. + * + * @see ephysics_world_bodies_outside_right_autodel_set() for details. + * + * @ingroup EPhysics_World + */ +EAPI Eina_Bool ephysics_world_bodies_outside_right_autodel_get(EPhysics_World *world); + +/** + * @brief + * Set world autodeleting bodies mode when they're outside of render area + * by the left. + * + * @param world The physics world. + * @param autodel If @c EINA_TRUE delete bodies when they are outside render + * area, otherwise, don't delete. + * + * @see ephysics_world_bodies_outside_top_autodel_set() for more details. + * @see ephysics_world_bodies_outside_left_autodel_get(). + * @see ephysics_world_bodies_outside_bottom_autodel_set(). + * @see ephysics_world_bodies_outside_right_autodel_set(). + * + * @ingroup EPhysics_World + */ +EAPI void ephysics_world_bodies_outside_left_autodel_set(EPhysics_World *world, Eina_Bool autodel); + +/** + * @brief + * Get world autodeleting bodies mode when they're outside of render area by + * the left. + * + * @param world The physics world. + * @return @c EINA_TRUE if bodies will be deleted or @c EINA_FALSE if they + * won't, or on error. + * + * @see ephysics_world_bodies_outside_left_autodel_set() for details. + * + * @ingroup EPhysics_World + */ +EAPI Eina_Bool ephysics_world_bodies_outside_left_autodel_get(EPhysics_World *world); + /** * @} */ diff --git a/legacy/ephysics/src/lib/ephysics_body.cpp b/legacy/ephysics/src/lib/ephysics_body.cpp index 813f00684b..75c356e754 100644 --- a/legacy/ephysics/src/lib/ephysics_body.cpp +++ b/legacy/ephysics/src/lib/ephysics_body.cpp @@ -186,6 +186,30 @@ _ephysics_body_evas_object_default_update(EPhysics_Body *body) evas_map_free(map); } +static void +_ephysics_body_outside_render_area_check(EPhysics_Body *body) +{ + int wx, wy, ww, wh, bx, by, bw, bh; + + ephysics_world_render_geometry_get(body->world, &wx, &wy, &ww, &wh); + ephysics_body_geometry_get(body, &bx, &by, &bw, &bh); + + // FIXME: check what should be done regarding rotated bodies + if (((ephysics_world_bodies_outside_top_autodel_get(body->world)) && + (by + bh < wy)) || + ((ephysics_world_bodies_outside_bottom_autodel_get(body->world)) && + (by > wy + wh)) || + ((ephysics_world_bodies_outside_left_autodel_get(body->world)) && + (bx + bh < wx)) || + ((ephysics_world_bodies_outside_right_autodel_get(body->world)) && + (bx > wx + ww))) + { + ephysics_world_body_del(body->world, body, body->rigid_body); + ephysics_orphan_body_del(body); + DBG("Body %p deleted. Out of render area", body); + } +} + void ephysics_body_evas_object_update_select(EPhysics_Body *body) { @@ -205,6 +229,9 @@ ephysics_body_evas_object_update_select(EPhysics_Body *body) if (!callback_called) _ephysics_body_evas_object_default_update(body); + + if (ephysics_world_bodies_outside_autodel_get(body->world)) + _ephysics_body_outside_render_area_check(body); } void diff --git a/legacy/ephysics/src/lib/ephysics_private.h b/legacy/ephysics/src/lib/ephysics_private.h index 6eba410ad0..363656bb7b 100644 --- a/legacy/ephysics/src/lib/ephysics_private.h +++ b/legacy/ephysics/src/lib/ephysics_private.h @@ -62,6 +62,7 @@ void ephysics_world_constraint_del(EPhysics_World *world, btTypedConstraint *bt_ void ephysics_body_world_boundaries_resize(EPhysics_World *world); void ephysics_world_boundary_set(EPhysics_World *world, EPhysics_World_Boundary boundary, EPhysics_Body *body); EPhysics_Body *ephysics_world_boundary_get(const EPhysics_World *world, EPhysics_World_Boundary boundary); +Eina_Bool ephysics_world_bodies_outside_autodel_get(EPhysics_World *world); void ephysics_body_evas_object_update_select(EPhysics_Body *body); void ephysics_orphan_body_del(EPhysics_Body *body); diff --git a/legacy/ephysics/src/lib/ephysics_world.cpp b/legacy/ephysics/src/lib/ephysics_world.cpp index 31aeb46058..403487d856 100644 --- a/legacy/ephysics/src/lib/ephysics_world.cpp +++ b/legacy/ephysics/src/lib/ephysics_world.cpp @@ -35,6 +35,11 @@ struct _EPhysics_World { double rate; Eina_Bool running:1; Eina_Bool active:1; + Eina_Bool outside_autodel:1; + Eina_Bool outside_top:1; + Eina_Bool outside_bottom:1; + Eina_Bool outside_left:1; + Eina_Bool outside_right:1; }; static int _ephysics_world_init_count = 0; @@ -692,6 +697,122 @@ ephysics_world_linear_slop_get(EPhysics_World *world) return world->dynamics_world->getSolverInfo().m_linearSlop; } +EAPI void +ephysics_world_bodies_outside_top_autodel_set(EPhysics_World *world, Eina_Bool autodel) +{ + if (!world) + { + ERR("Can't set autodelete mode, world is null."); + return; + } + + world->outside_top = !!autodel; + world->outside_autodel = world->outside_top || world->outside_bottom || + world->outside_left || world->outside_right; +} + +EAPI Eina_Bool +ephysics_world_bodies_outside_top_autodel_get(EPhysics_World *world) +{ + if (!world) + { + ERR("Can't get autodelete mode, world is null."); + return EINA_FALSE; + } + + return world->outside_top; +} + +EAPI void +ephysics_world_bodies_outside_bottom_autodel_set(EPhysics_World *world, Eina_Bool autodel) +{ + if (!world) + { + ERR("Can't set autodelete mode, world is null."); + return; + } + + world->outside_bottom = !!autodel; + world->outside_autodel = world->outside_top || world->outside_bottom || + world->outside_left || world->outside_right; +} + +EAPI Eina_Bool +ephysics_world_bodies_outside_bottom_autodel_get(EPhysics_World *world) +{ + if (!world) + { + ERR("Can't get autodelete mode, world is null."); + return EINA_FALSE; + } + + return world->outside_bottom; +} + +EAPI void +ephysics_world_bodies_outside_left_autodel_set(EPhysics_World *world, Eina_Bool autodel) +{ + if (!world) + { + ERR("Can't set autodelete mode, world is null."); + return; + } + + world->outside_left = !!autodel; + world->outside_autodel = world->outside_top || world->outside_bottom || + world->outside_left || world->outside_right; +} + +EAPI Eina_Bool +ephysics_world_bodies_outside_left_autodel_get(EPhysics_World *world) +{ + if (!world) + { + ERR("Can't get autodelete mode, world is null."); + return EINA_FALSE; + } + + return world->outside_left; +} + +EAPI void +ephysics_world_bodies_outside_right_autodel_set(EPhysics_World *world, Eina_Bool autodel) +{ + if (!world) + { + ERR("Can't set autodelete mode, world is null."); + return; + } + + world->outside_right = !!autodel; + world->outside_autodel = world->outside_top || world->outside_bottom || + world->outside_left || world->outside_right; +} + +EAPI Eina_Bool +ephysics_world_bodies_outside_right_autodel_get(EPhysics_World *world) +{ + if (!world) + { + ERR("Can't get autodelete mode, world is null."); + return EINA_FALSE; + } + + return world->outside_right; +} + +Eina_Bool +ephysics_world_bodies_outside_autodel_get(EPhysics_World *world) +{ + if (!world) + { + ERR("Can't get autodelete mode, world is null."); + return EINA_FALSE; + } + + return world->outside_autodel; +} + #ifdef __cplusplus } #endif