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 <dorileo@profusion.mobi>



SVN revision: 74501
This commit is contained in:
Leandro Dorileo 2012-07-27 14:49:53 +00:00 committed by Bruno Dilly
parent 6a2d290fce
commit 7b6a83144f
4 changed files with 161 additions and 0 deletions

View File

@ -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.

View File

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

View File

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

View File

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