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);