From 7b6a83144f75bedc1cd1c7fae3d31fb889ff17fd Mon Sep 17 00:00:00 2001 From: Leandro Dorileo Date: Fri, 27 Jul 2012 14:49:53 +0000 Subject: [PATCH] EPhysics: collision filter This patch introduces a collision filter API. Once a rigid body has been added to some group it must just collide against rigid bodies in the same group, if no group has been attribute it's going to collide against any other body. Patch by: Leandro Dorileo SVN revision: 74501 --- legacy/ephysics/src/lib/EPhysics.h | 52 ++++++++++++++ legacy/ephysics/src/lib/ephysics_body.cpp | 82 ++++++++++++++++++++++ legacy/ephysics/src/lib/ephysics_private.h | 2 + legacy/ephysics/src/lib/ephysics_world.cpp | 25 +++++++ 4 files changed, 161 insertions(+) diff --git a/legacy/ephysics/src/lib/EPhysics.h b/legacy/ephysics/src/lib/EPhysics.h index 0be3ec4dec..8448c882d9 100644 --- a/legacy/ephysics/src/lib/EPhysics.h +++ b/legacy/ephysics/src/lib/EPhysics.h @@ -1451,6 +1451,58 @@ EAPI void ephysics_body_damping_set(EPhysics_Body *body, double linear_damping, */ EAPI void ephysics_body_damping_get(const EPhysics_Body *body, double *linear_damping, double *angular_damping); +/** + * @brief + * Add a @p body to a given collision group. + * + * After calling this function the body is said to be added to collision @p + * group. + * + * If not added to any group the body will collide against any other body. + * Otherwise this body will collide only against those in the same groups. + * + * @param body The body to be added to @p group. + * @param group The group the @p body will belong to. + * @return EINA_TRUE on success, EINA_FALSE otherwise. + * + * @see ephysics_body_collision_group_del() + * @see ephysics_body_collision_group_list_get() + * @ingroup EPhysics_Body + */ +EAPI Eina_Bool ephysics_body_collision_group_add(EPhysics_Body *body, const char *group); + +/** + * @brief + * Removes @p body from collision @p group. + * + * This @p body will not belong to @p group any more and the collisions filter + * must take that on account. + * + * @param body The body to be removed from @p group. + * @param group The group @p body must be removed from. + * @return EINA_TRUE on success, EINA_FALSE otherwise. + * + * @see ephysics_body_collision_group_add() + * @ingroup EPhysics_Body + */ +EAPI Eina_Bool ephysics_body_collision_group_del(EPhysics_Body *body, const char *group); + +/** + * @brief + * Get the collision group list of @p body. + * + * @param body The body of interest. + * @return The collision group list of @p body, NULL on failure or case no + * group has been added to @p body. + * + * @warning The collision group list is an EPhysics internal data structure and + * should @b never be modified by its callers. + * + * @see ephysics_body_collision_group_add() + * @ingroup EPhysics_Body + */ +EAPI const Eina_List *ephysics_body_collision_group_list_get(const EPhysics_Body *body); + /** * @brief * Update the evas object associated to the body. diff --git a/legacy/ephysics/src/lib/ephysics_body.cpp b/legacy/ephysics/src/lib/ephysics_body.cpp index f7be1878b8..133c36aac1 100644 --- a/legacy/ephysics/src/lib/ephysics_body.cpp +++ b/legacy/ephysics/src/lib/ephysics_body.cpp @@ -30,6 +30,7 @@ struct _EPhysics_Body { Eina_Inlist *callbacks; double mass; Eina_Bool active:1; + Eina_List *collision_groups; }; struct _EPhysics_Body_Collision { @@ -50,6 +51,82 @@ ephysics_body_active_set(EPhysics_Body *body, Eina_Bool active) EINA_INLIST_FOREACH(body->callbacks, cb) if (cb->type == EPHYSICS_CALLBACK_BODY_STOPPED) cb->func(cb->data, body, (void *) body->evas_obj); +}; + +Eina_Bool +ephysics_body_filter_collision(EPhysics_Body *body0, EPhysics_Body *body1) +{ + void *grp; + Eina_Iterator *it; + Eina_List *l; + + if ((!body0->collision_groups) || (!body1->collision_groups)) + return EINA_TRUE; + + EINA_LIST_FOREACH(body0->collision_groups, l, grp) + { + if (eina_list_data_find(body1->collision_groups, grp)) + return EINA_TRUE; + } + + return EINA_FALSE; +} + +EAPI Eina_Bool +ephysics_body_collision_group_add(EPhysics_Body *body, const char *group) +{ + Eina_List *l; + void *grp; + Eina_Stringshare *group_str; + + if (!body) + { + ERR("Can't add body collision group, body is null."); + return EINA_FALSE; + } + + group_str = eina_stringshare_add(group); + EINA_LIST_FOREACH(body->collision_groups, l, grp) + { + if (grp == group_str) + { + eina_stringshare_del(group_str); + return EINA_TRUE; + } + } + + body->collision_groups = eina_list_append(body->collision_groups, group_str); + return EINA_TRUE; +} + +EAPI Eina_Bool +ephysics_body_collision_group_del(EPhysics_Body *body, const char *group) +{ + Eina_Stringshare *group_str; + + if (!body) + { + ERR("Can't remove body collision group, body is null."); + return EINA_FALSE; + } + + group_str = eina_stringshare_add(group); + body->collision_groups = eina_list_remove(body->collision_groups, group_str); + eina_stringshare_del(group_str); + eina_stringshare_del(group_str); + return EINA_TRUE; +} + +EAPI const Eina_List * +ephysics_body_collision_group_list_get(const EPhysics_Body *body) +{ + if (!body) + { + ERR("Can't get the body's collision group, body is null."); + return NULL; + } + + return body->collision_groups; } static EPhysics_Body * @@ -88,6 +165,7 @@ _ephysics_body_add(EPhysics_World *world, btCollisionShape *collision_shape) return NULL; } + body->collision_groups = NULL; body->collision_shape = collision_shape; body->rigid_body = rigid_body; body->mass = mass; @@ -111,6 +189,7 @@ static void _ephysics_body_del(EPhysics_Body *body) { EPhysics_Body_Callback *cb; + void *group; if (body->evas_obj) evas_object_event_callback_del(body->evas_obj, EVAS_CALLBACK_DEL, @@ -124,6 +203,9 @@ _ephysics_body_del(EPhysics_Body *body) free(cb); } + EINA_LIST_FREE(body->collision_groups, group) + eina_stringshare_del((Eina_Stringshare *)group); + delete body->rigid_body->getMotionState(); delete body->collision_shape; delete body->rigid_body; diff --git a/legacy/ephysics/src/lib/ephysics_private.h b/legacy/ephysics/src/lib/ephysics_private.h index 8ef80422ed..37c89cb15a 100644 --- a/legacy/ephysics/src/lib/ephysics_private.h +++ b/legacy/ephysics/src/lib/ephysics_private.h @@ -64,6 +64,8 @@ void ephysics_world_boundary_set(EPhysics_World *world, EPhysics_World_Boundary EPhysics_Body *ephysics_world_boundary_get(const EPhysics_World *world, EPhysics_World_Boundary boundary); Eina_Bool ephysics_world_bodies_outside_autodel_get(const EPhysics_World *world); +Eina_Bool ephysics_body_filter_collision(EPhysics_Body *body0, EPhysics_Body *body1); + void ephysics_body_evas_object_update_select(EPhysics_Body *body); void ephysics_orphan_body_del(EPhysics_Body *body); void ephysics_body_contact_processed(EPhysics_Body *body, EPhysics_Body *contact_body, btVector3 position); diff --git a/legacy/ephysics/src/lib/ephysics_world.cpp b/legacy/ephysics/src/lib/ephysics_world.cpp index d2c20a4b06..2b1e04a3b6 100644 --- a/legacy/ephysics/src/lib/ephysics_world.cpp +++ b/legacy/ephysics/src/lib/ephysics_world.cpp @@ -48,6 +48,23 @@ static int _worlds_running = 0; static Eina_List *_worlds = NULL; static Ecore_Animator *_anim_simulate = NULL; +struct _ephysics_world_ovelap_filter_cb : public btOverlapFilterCallback +{ + virtual bool needBroadphaseCollision(btBroadphaseProxy* proxy0,btBroadphaseProxy* proxy1) const + { + btCollisionObject *coll0 = (btCollisionObject *)proxy0->m_clientObject; + btCollisionObject *coll1 = (btCollisionObject *)proxy1->m_clientObject; + + EPhysics_Body *body0 = (EPhysics_Body *)coll0->getUserPointer(); + EPhysics_Body *body1 = (EPhysics_Body *)coll1->getUserPointer(); + + if ((!body0 || !body1) || (ephysics_body_filter_collision(body0, body1))) + return EINA_TRUE; + + return EINA_FALSE; + } +}; + static void _ephysics_world_tick_cb(btDynamicsWorld *dynamics_world, btScalar timeStep) { @@ -235,6 +252,7 @@ EAPI EPhysics_World * ephysics_world_new(void) { EPhysics_World *world; + btOverlapFilterCallback *filter_cb; world = (EPhysics_World *) calloc(1, sizeof(EPhysics_World)); if (!world) @@ -297,6 +315,13 @@ ephysics_world_new(void) world->dynamics_world->getSolverInfo().m_solverMode ^= EPHYSICS_WORLD_SOLVER_SIMD; world->dynamics_world->setGravity(btVector3(0, -9.8, 0)); + + filter_cb = new _ephysics_world_ovelap_filter_cb(); + if (!filter_cb) + INF("Couldn't initialize the collision filter."); + else + world->dynamics_world->getPairCache()->setOverlapFilterCallback(filter_cb); + world->rate = 30; world->dynamics_world->setInternalTickCallback(_ephysics_world_tick_cb, (void *) world);