ephysics: use multiple threads

Use a mainloop thread and one thread per world dedicated to simulation.

It's using ecore threads, out of the pool.

For now there are still some locks when trying to change physics
elements properties while a simulation is going on, but soon it will
have a queue of properties to be applied after a simulation step, so
it won't lock.



SVN revision: 77455
This commit is contained in:
Bruno Dilly 2012-10-04 22:38:06 +00:00
parent cfdd39c2d7
commit 9668304291
5 changed files with 392 additions and 110 deletions

View File

@ -602,7 +602,7 @@ EAPI void ephysics_world_render_geometry_get(const EPhysics_World *world, Evas_C
*
* @ingroup EPhysics_World
*/
EAPI Eina_Bool ephysics_world_serialize(const EPhysics_World *world, const char *path);
EAPI Eina_Bool ephysics_world_serialize(EPhysics_World *world, const char *path);
/**
* @brief

View File

@ -141,15 +141,18 @@ ephysics_body_collision_group_add(EPhysics_Body *body, const char *group)
return EINA_FALSE;
}
ephysics_world_lock_take(body->world);
group_str = eina_stringshare_add(group);
if (eina_list_data_find(body->collision_groups, group_str))
{
INF("Body already added to group: %s", group);
eina_stringshare_del(group_str);
ephysics_world_lock_release(body->world);
return EINA_TRUE;
}
body->collision_groups = eina_list_append(body->collision_groups, group_str);
ephysics_world_lock_release(body->world);
return EINA_TRUE;
}
@ -164,17 +167,20 @@ ephysics_body_collision_group_del(EPhysics_Body *body, const char *group)
return EINA_FALSE;
}
ephysics_world_lock_take(body->world);
group_str = eina_stringshare_add(group);
if (!eina_list_data_find(body->collision_groups, group_str))
{
INF("Body isn't part of group: %s", group);
eina_stringshare_del(group_str);
ephysics_world_lock_release(body->world);
return EINA_TRUE;
}
body->collision_groups = eina_list_remove(body->collision_groups, group_str);
eina_stringshare_del(group_str);
eina_stringshare_del(group_str);
ephysics_world_lock_release(body->world);
return EINA_TRUE;
}
@ -341,6 +347,24 @@ _ephysics_body_soft_body_constraints_rebuild(EPhysics_Body *body)
_ephysics_body_soft_body_points_distance_get(body, body->distances);
}
static void
_ephysics_body_mass_set(EPhysics_Body *body, double mass)
{
btVector3 inertia(0, 0, 0);
if (body->soft_body)
body->soft_body->setTotalMass(mass);
else
{
body->collision_shape->calculateLocalInertia(mass, inertia);
body->rigid_body->setMassProps(mass, inertia);
body->rigid_body->updateInertiaTensor();
}
body->mass = mass;
DBG("Body %p mass changed to %lf.", body, mass);
}
static void
_ephysics_body_resize(EPhysics_Body *body, Evas_Coord w, Evas_Coord h)
{
@ -360,7 +384,7 @@ _ephysics_body_resize(EPhysics_Body *body, Evas_Coord w, Evas_Coord h)
body->collision_shape->setLocalScaling(btVector3(sx, sy, 1));
if(!body->rigid_body->isStaticObject())
ephysics_body_mass_set(body, ephysics_body_mass_get(body));
_ephysics_body_mass_set(body, ephysics_body_mass_get(body));
}
body->w = w;
@ -429,7 +453,7 @@ _ephysics_body_geometry_set(EPhysics_Body *body, Evas_Coord x, Evas_Coord y, Eva
body->rigid_body->proceedToTransform(trans);
if (!body->rigid_body->isStaticObject())
ephysics_body_mass_set(body, ephysics_body_mass_get(body));
_ephysics_body_mass_set(body, ephysics_body_mass_get(body));
}
body->rigid_body->getMotionState()->setWorldTransform(trans);
@ -480,7 +504,9 @@ _ephysics_body_evas_obj_resize_cb(void *data, Evas *e __UNUSED__, Evas_Object *o
return;
DBG("Resizing body %p to w=%i, h=%i", body, w, h);
ephysics_world_lock_take(body->world);
_ephysics_body_resize(body, w, h);
ephysics_world_lock_release(body->world);
}
static void
@ -708,11 +734,20 @@ ephysics_body_soft_body_get(const EPhysics_Body *body)
return body->soft_body;
}
static void
_ephysics_body_soft_body_hardness_set(EPhysics_Body *body, double hardness)
{
btSoftBody *soft_body = body->soft_body;
soft_body->m_cfg.kAHR = (hardness / 100) * 0.6;
soft_body->m_materials[0]->m_kVST = (hardness / 100);
soft_body->m_materials[0]->m_kLST = (hardness / 100);
soft_body->m_materials[0]->m_kAST = (hardness / 100);
DBG("Soft body %p hardness set to %lf.", body, hardness);
}
EAPI void
ephysics_body_soft_body_hardness_set(EPhysics_Body *body, double hardness)
{
btSoftBody *soft_body;
if (!body)
{
ERR("Can't set soft body's hardness, body is null.");
@ -731,12 +766,9 @@ ephysics_body_soft_body_hardness_set(EPhysics_Body *body, double hardness)
return;
}
soft_body = body->soft_body;
soft_body->m_cfg.kAHR = (hardness / 100) * 0.6;
soft_body->m_materials[0]->m_kVST = (hardness / 100);
soft_body->m_materials[0]->m_kLST = (hardness / 100);
soft_body->m_materials[0]->m_kAST = (hardness / 100);
DBG("Soft body hardness set.");
ephysics_world_lock_take(body->world);
_ephysics_body_soft_body_hardness_set(body, hardness);
ephysics_world_lock_release(body->world);
}
EAPI double
@ -775,7 +807,7 @@ _ephysics_body_soft_add(EPhysics_World *world, btCollisionShape *collision_shape
body->soft_body->m_cfg.collisions += btSoftBody::fCollision::SDF_RS;
body->soft_body->m_cfg.collisions += btSoftBody::fCollision::VF_SS;
ephysics_body_soft_body_hardness_set(body, 100);
_ephysics_body_soft_body_hardness_set(body, 100);
body->rigid_body->setCollisionFlags(
btCollisionObject::CF_NO_CONTACT_RESPONSE);
@ -799,6 +831,7 @@ ephysics_body_soft_circle_add(EPhysics_World *world)
return NULL;
}
ephysics_world_lock_take(world);
shape = new btCylinderShapeZ(btVector3(0.25, 0.25, 0.25));
if (!shape)
{
@ -836,6 +869,7 @@ ephysics_body_soft_circle_add(EPhysics_World *world)
body->points_deform[3][1] = 3;
body->points_deform[3][2] = 76;
ephysics_world_lock_release(world);
return body;
no_body:
@ -843,6 +877,7 @@ no_body:
no_soft_body:
delete shape;
no_collision_shape:
ephysics_world_lock_release(world);
return NULL;
}
@ -850,6 +885,7 @@ EAPI EPhysics_Body *
ephysics_body_circle_add(EPhysics_World *world)
{
btCollisionShape *collision_shape;
EPhysics_Body *body;
if (!world)
{
@ -864,7 +900,10 @@ ephysics_body_circle_add(EPhysics_World *world)
return NULL;
}
return _ephysics_body_add(world, collision_shape, "circle", 0.5, 0.5);
ephysics_world_lock_take(world);
body = _ephysics_body_add(world, collision_shape, "circle", 0.5, 0.5);
ephysics_world_lock_release(world);
return body;
}
EAPI EPhysics_Body *
@ -881,6 +920,7 @@ ephysics_body_soft_box_add(EPhysics_World *world)
return NULL;
}
ephysics_world_lock_take(world);
shape = new btBoxShape(btVector3(0.25, 0.25, 0.25));
if (!shape)
{
@ -918,6 +958,7 @@ ephysics_body_soft_box_add(EPhysics_World *world)
body->points_deform[3][1] = 62;
body->points_deform[3][2] = 8;
ephysics_world_lock_release(world);
return body;
no_body:
@ -925,6 +966,7 @@ no_body:
no_soft_body:
delete shape;
no_collision_shape:
ephysics_world_lock_release(world);
return NULL;
}
@ -932,6 +974,7 @@ EAPI EPhysics_Body *
ephysics_body_box_add(EPhysics_World *world)
{
btCollisionShape *collision_shape;
EPhysics_Body *body;
if (!world)
{
@ -941,7 +984,10 @@ ephysics_body_box_add(EPhysics_World *world)
collision_shape = new btBoxShape(btVector3(0.5, 0.5, 0.5));
return _ephysics_body_add(world, collision_shape, "box", 0.5, 0.5);
ephysics_world_lock_take(world);
body = _ephysics_body_add(world, collision_shape, "box", 0.5, 0.5);
ephysics_world_lock_release(world);
return body;
}
EAPI EPhysics_Body *
@ -952,6 +998,7 @@ ephysics_body_shape_add(EPhysics_World *world, EPhysics_Shape *shape)
btAlignedObjectArray<btVector3> vertexes, planes;
const Eina_Inlist *points;
EPhysics_Point *point;
EPhysics_Body *body;
int array_size, i;
btShapeHull *hull;
btVector3 point3d;
@ -1052,9 +1099,12 @@ ephysics_body_shape_add(EPhysics_World *world, EPhysics_Shape *shape)
return NULL;
}
return _ephysics_body_add(world, (btCollisionShape *)simplified_shape,
ephysics_world_lock_take(world);
body = _ephysics_body_add(world, (btCollisionShape *)simplified_shape,
"generic", (cm_x - min_x) / range_x,
1 - (cm_y - min_y) / range_y);
ephysics_world_lock_release(world);
return body;
}
void
@ -1111,37 +1161,49 @@ _ephysics_body_boundary_add(EPhysics_World *world, EPhysics_World_Boundary bound
EAPI EPhysics_Body *
ephysics_body_top_boundary_add(EPhysics_World *world)
{
EPhysics_Body *body;
Evas_Coord x, y, w;
ephysics_world_render_geometry_get(world, &x, &y, &w, NULL);
return _ephysics_body_boundary_add(world, EPHYSICS_WORLD_BOUNDARY_TOP,
0, y - 10, x + w, 10);
body = _ephysics_body_boundary_add(world, EPHYSICS_WORLD_BOUNDARY_TOP,
0, y - 10, x + w, 10);
return body;
}
EAPI EPhysics_Body *
ephysics_body_bottom_boundary_add(EPhysics_World *world)
{
Evas_Coord x, y, w, h;
EPhysics_Body *body;
ephysics_world_render_geometry_get(world, &x, &y, &w, &h);
return _ephysics_body_boundary_add(world, EPHYSICS_WORLD_BOUNDARY_BOTTOM,
body = _ephysics_body_boundary_add(world, EPHYSICS_WORLD_BOUNDARY_BOTTOM,
x, y + h, w, 10);
return body;
}
EAPI EPhysics_Body *
ephysics_body_left_boundary_add(EPhysics_World *world)
{
EPhysics_Body *body;
Evas_Coord x, y, h;
ephysics_world_render_geometry_get(world, &x, &y, NULL, &h);
return _ephysics_body_boundary_add(world, EPHYSICS_WORLD_BOUNDARY_LEFT,
body = _ephysics_body_boundary_add(world, EPHYSICS_WORLD_BOUNDARY_LEFT,
x - 10, 0, 10, y + h);
return body;
}
EAPI EPhysics_Body *
ephysics_body_right_boundary_add(EPhysics_World *world)
{
Evas_Coord x, y, w, h;
EPhysics_Body *body;
ephysics_world_render_geometry_get(world, &x, &y, &w, &h);
return _ephysics_body_boundary_add(world, EPHYSICS_WORLD_BOUNDARY_RIGHT,
body = _ephysics_body_boundary_add(world, EPHYSICS_WORLD_BOUNDARY_RIGHT,
x + w, 0, 10, y + h);
return body;
}
void
@ -1163,8 +1225,10 @@ ephysics_body_del(EPhysics_Body *body)
}
if (body->deleted) return;
ephysics_world_lock_take(body->world);
body->deleted = EINA_TRUE;
ephysics_world_body_del(body->world, body);
ephysics_world_lock_release(body->world);
}
EAPI void
@ -1200,11 +1264,13 @@ ephysics_body_evas_object_set(EPhysics_Body *body, Evas_Object *evas_obj, Eina_B
if (!use_obj_pos)
return;
evas_object_event_callback_add(evas_obj, EVAS_CALLBACK_RESIZE,
_ephysics_body_evas_obj_resize_cb, body);
evas_object_geometry_get(body->evas_obj, &obj_x, &obj_y, &obj_w, &obj_h);
ephysics_world_lock_take(body->world);
_ephysics_body_geometry_set(body, obj_x, obj_y, obj_w, obj_h,
ephysics_world_rate_get(body->world));
ephysics_world_lock_release(body->world);
evas_object_event_callback_add(evas_obj, EVAS_CALLBACK_RESIZE,
_ephysics_body_evas_obj_resize_cb, body);
}
EAPI Evas_Object *
@ -1258,8 +1324,10 @@ ephysics_body_geometry_set(EPhysics_Body *body, Evas_Coord x, Evas_Coord y, Evas
return;
}
ephysics_world_lock_take(body->world);
_ephysics_body_geometry_set(body, x, y, w, h,
ephysics_world_rate_get(body->world));
ephysics_world_lock_release(body->world);
}
EAPI void
@ -1277,7 +1345,9 @@ ephysics_body_resize(EPhysics_Body *body, Evas_Coord w, Evas_Coord h)
return;
}
ephysics_world_lock_take(body->world);
_ephysics_body_resize(body, w, h);
ephysics_world_lock_release(body->world);
}
EAPI void
@ -1289,7 +1359,9 @@ ephysics_body_move(EPhysics_Body *body, Evas_Coord x, Evas_Coord y)
return;
}
ephysics_world_lock_take(body->world);
_ephysics_body_move(body, x, y);
ephysics_world_lock_release(body->world);
}
EAPI void
@ -1329,18 +1401,9 @@ ephysics_body_mass_set(EPhysics_Body *body, double mass)
return;
}
btVector3 inertia(0, 0, 0);
if (body->soft_body)
body->soft_body->setTotalMass(mass);
else
{
body->collision_shape->calculateLocalInertia(mass, inertia);
body->rigid_body->setMassProps(mass, inertia);
body->rigid_body->updateInertiaTensor();
}
body->mass = mass;
DBG("Body %p mass changed to %lf.", body, mass);
ephysics_world_lock_take(body->world);
_ephysics_body_mass_set(body, mass);
ephysics_world_lock_release(body->world);
}
EAPI double
@ -1394,8 +1457,10 @@ ephysics_body_angular_velocity_set(EPhysics_Body *body, double z)
return;
}
ephysics_world_lock_take(body->world);
body->rigid_body->setAngularVelocity(btVector3(0, 0, -z/RAD_TO_DEG));
DBG("Angular velocity of body %p set to %lf", body, z);
ephysics_world_lock_release(body->world);
}
EAPI double
@ -1419,9 +1484,11 @@ ephysics_body_sleeping_threshold_set(EPhysics_Body *body, double linear_threshol
return;
}
ephysics_world_lock_take(body->world);
_ephysics_body_sleeping_threshold_set(body, linear_threshold,
angular_threshold,
ephysics_world_rate_get(body->world));
ephysics_world_lock_release(body->world);
}
EAPI void
@ -1452,8 +1519,10 @@ ephysics_body_stop(EPhysics_Body *body)
return;
}
ephysics_world_lock_take(body->world);
body->rigid_body->setLinearVelocity(btVector3(0, 0, 0));
body->rigid_body->setAngularVelocity(btVector3(0, 0, 0));
ephysics_world_lock_release(body->world);
DBG("Body %p stopped", body);
}
@ -1467,8 +1536,10 @@ ephysics_body_damping_set(EPhysics_Body *body, double linear_damping, double ang
return;
}
ephysics_world_lock_take(body->world);
body->rigid_body->setDamping(btScalar(linear_damping),
btScalar(angular_damping));
ephysics_world_lock_release(body->world);
}
EAPI void
@ -1594,7 +1665,10 @@ ephysics_body_restitution_set(EPhysics_Body *body, double restitution)
return;
}
ephysics_world_lock_take(body->world);
body->rigid_body->setRestitution(btScalar(restitution));
DBG("Body %p restitution set to %lf", body, restitution);
ephysics_world_lock_release(body->world);
}
EAPI double
@ -1618,7 +1692,10 @@ ephysics_body_friction_set(EPhysics_Body *body, double friction)
return;
}
ephysics_world_lock_take(body->world);
body->rigid_body->setFriction(btScalar(friction));
DBG("Body %p friction set to %lf", body, friction);
ephysics_world_lock_release(body->world);
}
EAPI double
@ -1658,8 +1735,10 @@ ephysics_body_central_impulse_apply(EPhysics_Body *body, double x, double y)
rate = ephysics_world_rate_get(body->world);
ephysics_world_lock_take(body->world);
body->rigid_body->activate(1);
body->rigid_body->applyCentralImpulse(btVector3(x / rate, - y / rate, 0));
ephysics_world_lock_release(body->world);
}
EAPI void
@ -1675,10 +1754,12 @@ ephysics_body_impulse_apply(EPhysics_Body *body, double x, double y, Evas_Coord
rate = ephysics_world_rate_get(body->world);
ephysics_world_lock_take(body->world);
body->rigid_body->activate(1);
body->rigid_body->applyImpulse(btVector3(x / rate, - y / rate, 0),
btVector3((double) pos_x / rate,
(double) pos_y / rate, 0));
ephysics_world_lock_release(body->world);
}
EAPI void
@ -1690,7 +1771,9 @@ ephysics_body_linear_movement_enable_set(EPhysics_Body *body, Eina_Bool enable_x
return;
}
ephysics_world_lock_take(body->world);
body->rigid_body->setLinearFactor(btVector3(!!enable_x, !!enable_y, 0));
ephysics_world_lock_release(body->world);
}
EAPI void
@ -1715,8 +1798,10 @@ ephysics_body_torque_impulse_apply(EPhysics_Body *body, double roll)
return;
}
ephysics_world_lock_take(body->world);
body->rigid_body->activate(1);
body->rigid_body->applyTorqueImpulse(btVector3(0, 0, -roll));
ephysics_world_lock_release(body->world);
}
EAPI void
@ -1728,10 +1813,12 @@ ephysics_body_rotation_on_z_axis_enable_set(EPhysics_Body *body, Eina_Bool enabl
return;
}
ephysics_world_lock_take(body->world);
if (!enable)
body->rigid_body->setAngularFactor(btVector3(0, 0, 0));
else
body->rigid_body->setAngularFactor(btVector3(0, 0, 1));
ephysics_world_lock_release(body->world);
}
EAPI Eina_Bool
@ -1777,6 +1864,7 @@ ephysics_body_rotation_set(EPhysics_Body *body, double rotation)
return;
}
ephysics_world_lock_take(body->world);
body->rigid_body->activate(1);
body->rigid_body->getMotionState()->getWorldTransform(trans);
quat.setEuler(0, 0, -rotation / RAD_TO_DEG);
@ -1789,6 +1877,7 @@ ephysics_body_rotation_set(EPhysics_Body *body, double rotation)
body->rigid_body->getMotionState()->setWorldTransform(trans);
DBG("Body %p rotation set to %lf", body, rotation);
ephysics_world_lock_release(body->world);
}
EAPI void
@ -1826,10 +1915,12 @@ ephysics_body_central_force_apply(EPhysics_Body *body, double x, double y)
return;
}
ephysics_world_lock_take(body->world);
rate = ephysics_world_rate_get(body->world);
ephysics_body_forces_apply(body);
body->rigid_body->applyCentralForce(btVector3(x / rate, - y / rate, 0));
_ephysics_body_forces_update(body);
ephysics_world_lock_release(body->world);
}
EAPI void
@ -1844,11 +1935,13 @@ ephysics_body_force_apply(EPhysics_Body *body, double x, double y, Evas_Coord po
}
rate = ephysics_world_rate_get(body->world);
ephysics_world_lock_take(body->world);
ephysics_body_forces_apply(body);
body->rigid_body->applyForce(btVector3(x / rate, - y / rate, 0),
btVector3((double) pos_x / rate,
(double) pos_y / rate, 0));
_ephysics_body_forces_update(body);
ephysics_world_lock_release(body->world);
}
EAPI void
@ -1860,9 +1953,11 @@ ephysics_body_torque_apply(EPhysics_Body *body, double torque)
return;
}
ephysics_world_lock_take(body->world);
ephysics_body_forces_apply(body);
body->rigid_body->applyTorque(btVector3(0, 0, -torque));
_ephysics_body_forces_update(body);
ephysics_world_lock_release(body->world);
}
EAPI void

View File

@ -56,7 +56,6 @@ _ephysics_constraint_p2p_set(EPhysics_Constraint *constraint, double rate)
}
constraint->type = EPHYSICS_CONSTRAINT_P2P;
constraint->world = ephysics_body_world_get(constraint->p2p.body1);
ephysics_world_constraint_add(constraint->world, constraint,
constraint->bt_constraint);
@ -127,6 +126,7 @@ ephysics_constraint_slider_add(EPhysics_Body *body)
return NULL;
}
ephysics_world_lock_take(ephysics_body_world_get(body));
trans.setIdentity();
constraint->bt_constraint = new
btGeneric6DofConstraint(*ephysics_body_rigid_body_get(body), trans,
@ -145,6 +145,7 @@ ephysics_constraint_slider_add(EPhysics_Body *body)
constraint->bt_constraint);
INF("Constraint added.");
ephysics_world_lock_release(ephysics_body_world_get(body));
return constraint;
}
@ -163,9 +164,11 @@ ephysics_constraint_slider_linear_limit_set(EPhysics_Constraint *constraint, Eva
return;
}
ephysics_world_lock_take(constraint->world);
_ephysics_constraint_slider_linear_limit_set(
constraint, left_x, under_y, right_x, above_y,
ephysics_world_rate_get(constraint->world));
ephysics_world_lock_release(constraint->world);
}
EAPI void
@ -219,11 +222,13 @@ ephysics_constraint_slider_angular_limit_set(EPhysics_Constraint *constraint, do
return;
}
ephysics_world_lock_take(constraint->world);
slider_constraint = (btGeneric6DofConstraint *)constraint->bt_constraint;
slider_constraint->setAngularLowerLimit(btVector3(0, 0,
-counter_clock_z/RAD_TO_DEG));
slider_constraint->setAngularUpperLimit(btVector3(0, 0,
clock_wise_z/RAD_TO_DEG));
ephysics_world_lock_release(constraint->world);
}
EAPI void
@ -284,6 +289,7 @@ ephysics_constraint_p2p_add(EPhysics_Body *body1, EPhysics_Body *body2, Evas_Coo
return NULL;
}
constraint->world = ephysics_body_world_get(body1);
constraint->p2p.body1 = body1;
constraint->p2p.body2 = body2;
constraint->p2p.anchor_b1_x = anchor_b1_x;
@ -291,11 +297,17 @@ ephysics_constraint_p2p_add(EPhysics_Body *body1, EPhysics_Body *body2, Evas_Coo
constraint->p2p.anchor_b2_x = anchor_b2_x;
constraint->p2p.anchor_b2_y = anchor_b2_y;
ephysics_world_lock_take(constraint->world);
if (!_ephysics_constraint_p2p_set(
constraint, ephysics_world_rate_get(ephysics_body_world_get(
constraint->p2p.body1))))
return NULL;
{
ephysics_world_lock_release(constraint->world);
free(constraint);
return NULL;
}
ephysics_world_lock_release(constraint->world);
INF("Constraint added.");
return constraint;
}
@ -309,12 +321,14 @@ ephysics_constraint_del(EPhysics_Constraint *constraint)
return;
}
ephysics_world_lock_take(constraint->world);
ephysics_world_constraint_del(constraint->world, constraint,
constraint->bt_constraint);
delete constraint->bt_constraint;
free(constraint);
INF("Constraint deleted.");
ephysics_world_lock_release(constraint->world);
}

View File

@ -121,6 +121,8 @@ btSoftBody *ephysics_body_soft_body_get(const EPhysics_Body *body);
void ephysics_body_active_set(EPhysics_Body *body, Eina_Bool active);
void ephysics_body_recalc(EPhysics_Body *body, double rate);
void ephysics_body_forces_apply(EPhysics_Body *body);
void ephysics_world_lock_take(EPhysics_World *world);
void ephysics_world_lock_release(EPhysics_World *world);
/* Camera */
EPhysics_Camera *ephysics_camera_add(EPhysics_World *world);

View File

@ -12,6 +12,16 @@ extern "C" {
#define DEFAULT_GRAVITY btVector3(0, -9.8, 0)
typedef struct _Simulation_Msg Simulation_Msg;
struct _Simulation_Msg {
EPhysics_Body *body_0;
EPhysics_Body *body_1;
btVector3 pos_a;
btVector3 pos_b;
Eina_Bool tick:1;
};
typedef struct _EPhysics_World_Callback EPhysics_World_Callback;
struct _EPhysics_World_Callback {
@ -41,14 +51,18 @@ struct _EPhysics_World {
Eina_List *to_delete;
Eina_List *cb_to_delete;
Eina_List *constraints;
Ecore_Thread *simulation_th;
Ecore_Thread *cur_th;
int max_sub_steps;
int walking;
int cb_walking;
int soft_body_ref;
int pending_ticks;
double last_update;
double rate;
double fixed_time_step;
double max_sleeping_time;
Eina_Lock mutex;
Eina_Condition condition;
Eina_Bool running:1;
Eina_Bool active:1;
Eina_Bool deleted:1;
@ -57,6 +71,7 @@ struct _EPhysics_World {
Eina_Bool outside_bottom:1;
Eina_Bool outside_left:1;
Eina_Bool outside_right:1;
Eina_Bool pending_simulation:1;
};
static int _ephysics_world_init_count = 0;
@ -100,6 +115,14 @@ _ephysics_world_gravity_set(EPhysics_World *world, double gx, double gy, double
world->world_info->m_gravity = gravity;
}
static void
_ephysics_world_th_cancel(EPhysics_World *world)
{
_worlds = eina_inlist_remove(_worlds, EINA_INLIST_GET(world));
if (!ecore_thread_cancel(world->simulation_th))
eina_condition_signal(&world->condition);
}
static void
_ephysics_world_event_callback_call(EPhysics_World *world, EPhysics_Callback_World_Type type, void *event_info)
{
@ -144,7 +167,7 @@ _ephysics_world_event_callback_del(EPhysics_World *world, EPhysics_World_Callbac
}
static void
_ephysics_world_tick_cb(btDynamicsWorld *dynamics_world, btScalar timeStep __UNUSED__)
_ephysics_world_tick(btDynamicsWorld *dynamics_world)
{
Eina_Bool world_active, camera_moved, tx, ty;
btCollisionObjectArray objects;
@ -195,13 +218,41 @@ _ephysics_world_tick_cb(btDynamicsWorld *dynamics_world, btScalar timeStep __UNU
world, EPHYSICS_CALLBACK_WORLD_CAMERA_MOVED, world->camera);
}
if (world->active == world_active) return;
if (world->active == world_active) goto body_del;
world->active = world_active;
if (world_active) return;
if (world_active) goto body_del;
_ephysics_world_event_callback_call(world, EPHYSICS_CALLBACK_WORLD_STOPPED,
NULL);
body_del:
world->pending_ticks--;
if (!world->pending_ticks)
{
void *bd;
EINA_LIST_FREE(world->to_delete, bd)
ephysics_world_body_del(world, (EPhysics_Body*)bd);
}
if ((world->pending_simulation) && (!world->pending_ticks))
{
world->pending_simulation = EINA_FALSE;
eina_condition_signal(&world->condition);
}
}
static void
_ephysics_world_tick_cb(btDynamicsWorld *dynamics_world, btScalar timeStep __UNUSED__)
{
EPhysics_World *world;
Simulation_Msg *msg;
msg = (Simulation_Msg *) calloc(1, sizeof(Simulation_Msg));
msg->tick = EINA_TRUE;
world = (EPhysics_World *) dynamics_world->getWorldUserInfo();
world->pending_ticks++;
ecore_thread_feedback(world->cur_th, msg);
}
static void
@ -227,7 +278,7 @@ ephysics_world_body_del(EPhysics_World *world, EPhysics_Body *body)
{
EPhysics_Body *bd;
if (world->walking)
if (world->pending_ticks)
{
world->to_delete = eina_list_append(world->to_delete, body);
return EINA_FALSE;
@ -255,8 +306,6 @@ _ephysics_world_free(EPhysics_World *world)
EPhysics_Body *body;
void *constraint;
_worlds = eina_inlist_remove(_worlds, EINA_INLIST_GET(world));
while (world->callbacks)
{
cb = EINA_INLIST_CONTAINER_GET(world->callbacks,
@ -286,6 +335,9 @@ _ephysics_world_free(EPhysics_World *world)
delete world->soft_solver;
delete world->world_info;
eina_condition_free(&world->condition);
eina_lock_free(&world->mutex);
free(world);
INF("World %p deleted.", world);
}
@ -294,46 +346,24 @@ static Eina_Bool
_simulate_worlds(void *data __UNUSED__)
{
EPhysics_World *world;
void *wrld, *bd;
void *wrld;
ephysics_init();
_worlds_walking++;
EINA_INLIST_FOREACH(_worlds, world)
{
double time_now, delta;
EPhysics_Body *body;
if (!world->running)
continue;
world->walking++;
EINA_INLIST_FOREACH(world->bodies, body)
ephysics_body_forces_apply(body);
time_now = ecore_time_get();
delta = time_now - world->last_update;
world->last_update = time_now;
gDeactivationTime = world->max_sleeping_time;
if (world->soft_body_ref)
if (world->pending_ticks)
{
world->dynamics_world->stepSimulation(delta, world->max_sub_steps,
world->fixed_time_step);
world->world_info->m_sparsesdf.GarbageCollect();
world->pending_simulation = EINA_TRUE;
continue;
}
else
((btDiscreteDynamicsWorld *)world->dynamics_world)->stepSimulation(
delta, world->max_sub_steps, world->fixed_time_step);
world->walking--;
world->pending_simulation = EINA_FALSE;
if (!world->walking)
{
EINA_LIST_FREE(world->to_delete, bd)
ephysics_world_body_del(world, (EPhysics_Body*)bd);
}
eina_condition_signal(&world->condition);
}
_worlds_walking--;
@ -344,7 +374,7 @@ _simulate_worlds(void *data __UNUSED__)
}
EINA_LIST_FREE(_worlds_to_delete, wrld)
_ephysics_world_free((EPhysics_World *)wrld);
_ephysics_world_th_cancel((EPhysics_World *)wrld);
ephysics_shutdown();
@ -356,6 +386,8 @@ _ephysics_world_contact_processed_cb(btManifoldPoint &cp, void *b0, void *b1)
{
btRigidBody *rigid_body_0, *rigid_body_1;
EPhysics_Body *body_0, *body_1;
EPhysics_World *world;
Simulation_Msg *msg;
rigid_body_0 = (btRigidBody *) b0;
rigid_body_1 = (btRigidBody *) b1;
@ -363,8 +395,14 @@ _ephysics_world_contact_processed_cb(btManifoldPoint &cp, void *b0, void *b1)
body_0 = (EPhysics_Body *) rigid_body_0->getUserPointer();
body_1 = (EPhysics_Body *) rigid_body_1->getUserPointer();
ephysics_body_contact_processed(body_0, body_1, cp.getPositionWorldOnA());
ephysics_body_contact_processed(body_1, body_0, cp.getPositionWorldOnB());
world = ephysics_body_world_get(body_0);
msg = (Simulation_Msg *) calloc(1, sizeof(Simulation_Msg));
msg->body_0 = body_0;
msg->body_1 = body_1;
msg->pos_a = cp.getPositionWorldOnA();
msg->pos_b = cp.getPositionWorldOnB();
ecore_thread_feedback(world->cur_th, msg);
return EINA_TRUE;
}
@ -485,6 +523,85 @@ ephysics_world_boundary_get(const EPhysics_World *world, EPhysics_World_Boundary
return world->boundaries[boundary];
}
static void
_th_simulate(void *data, Ecore_Thread *th)
{
EPhysics_World *world = (EPhysics_World *) data;
while (1)
{
double time_now, delta;
EPhysics_Body *body;
eina_condition_wait(&world->condition);
if (ecore_thread_check(th))
{
INF("Thread canceled by main loop thread");
eina_lock_release(&world->mutex);
return;
}
world->pending_ticks++;
world->cur_th = th;
EINA_INLIST_FOREACH(world->bodies, body)
ephysics_body_forces_apply(body);
time_now = ecore_time_get();
delta = time_now - world->last_update;
world->last_update = time_now;
gDeactivationTime = world->max_sleeping_time;
if (world->soft_body_ref)
{
world->dynamics_world->stepSimulation(delta, world->max_sub_steps,
world->fixed_time_step);
world->world_info->m_sparsesdf.GarbageCollect();
}
else
((btDiscreteDynamicsWorld *)world->dynamics_world)->stepSimulation(
delta, world->max_sub_steps, world->fixed_time_step);
world->pending_ticks--;
eina_lock_release(&world->mutex);
}
}
static void
_th_msg_cb(void *data, Ecore_Thread *th __UNUSED__, void *msg_data)
{
EPhysics_World *world = (EPhysics_World *) data;
Simulation_Msg *msg = (Simulation_Msg *) msg_data;
if (msg->tick)
_ephysics_world_tick(world->dynamics_world);
else
{
ephysics_body_contact_processed(msg->body_0, msg->body_1, msg->pos_a);
ephysics_body_contact_processed(msg->body_1, msg->body_0, msg->pos_b);
}
free(msg);
}
static void
_th_end_cb(void *data, Ecore_Thread *th)
{
EPhysics_World *world = (EPhysics_World *) data;
INF("World %p simulation thread %p end", world, th);
world->simulation_th = NULL;
_ephysics_world_free(world);
}
static void
_th_cancel_cb(void *data, Ecore_Thread *th)
{
EPhysics_World *world = (EPhysics_World *) data;
INF("World %p simulation thread %p canceled", world, th);
world->simulation_th = NULL;
_ephysics_world_free(world);
}
EAPI EPhysics_World *
ephysics_world_new(void)
{
@ -566,6 +683,15 @@ ephysics_world_new(void)
ERR("Couldn't add world to worlds list.");
goto no_list;
}
world->simulation_th = ecore_thread_feedback_run(
_th_simulate, _th_msg_cb, _th_end_cb, _th_cancel_cb, world, EINA_TRUE);
if (!world->simulation_th)
{
ERR("Failed to create simulation thread.");
goto no_thread;
}
eina_lock_new(&world->mutex);
eina_condition_new(&world->condition, &world->mutex);
world->dynamics_world->getSolverInfo().m_solverMode ^=
EPHYSICS_WORLD_SOLVER_SIMD;
@ -594,6 +720,8 @@ ephysics_world_new(void)
INF("World %p added.", world);
return world;
no_thread:
_worlds = eina_inlist_remove(_worlds, EINA_INLIST_GET(world));
no_list:
delete world->world_info;
no_world_info:
@ -616,7 +744,7 @@ no_camera:
}
EAPI Eina_Bool
ephysics_world_serialize(const EPhysics_World *world, const char *path)
ephysics_world_serialize(EPhysics_World *world, const char *path)
{
btDefaultSerializer *serializer;
FILE *file;
@ -627,10 +755,13 @@ ephysics_world_serialize(const EPhysics_World *world, const char *path)
return EINA_FALSE;
}
eina_lock_take(&world->mutex);
file = fopen(path, "wb");
if (!file)
{
WRN("Could not serialize, could not open file: %s", path);
eina_lock_release(&world->mutex);
return EINA_FALSE;
}
@ -643,6 +774,7 @@ ephysics_world_serialize(const EPhysics_World *world, const char *path)
WRN("Problems on writing to: %s.", path);
fclose(file);
delete serializer;
eina_lock_release(&world->mutex);
return EINA_FALSE;
}
@ -651,44 +783,13 @@ ephysics_world_serialize(const EPhysics_World *world, const char *path)
INF("Serialization of world %p written to file: %s.", world, path);
eina_lock_release(&world->mutex);
return EINA_TRUE;
}
EAPI void
ephysics_world_del(EPhysics_World *world)
static void
_ephysics_world_running_set(EPhysics_World *world, Eina_Bool running)
{
if (!world)
{
ERR("Can't delete world, it wasn't provided.");
return;
}
if (world->deleted) return;
world->deleted = EINA_TRUE;
_ephysics_world_event_callback_call(world, EPHYSICS_CALLBACK_WORLD_DEL,
NULL);
ephysics_world_running_set(world, EINA_FALSE);
if (_worlds_walking > 0)
{
_worlds_to_delete = eina_list_append(_worlds_to_delete, world);
INF("World %p marked to delete.", world);
return;
}
_ephysics_world_free(world);
}
EAPI void
ephysics_world_running_set(EPhysics_World *world, Eina_Bool running)
{
if (!world)
{
ERR("Can't (un)pause world, it wasn't provided.");
return;
}
if ((!!running) == world->running) return;
world->running = !!running;
@ -721,6 +822,50 @@ ephysics_world_running_set(EPhysics_World *world, Eina_Bool running)
_anim_simulate = ecore_animator_add(_simulate_worlds, NULL);
}
EAPI void
ephysics_world_del(EPhysics_World *world)
{
if (!world)
{
ERR("Can't delete world, it wasn't provided.");
return;
}
if (world->deleted) return;
eina_lock_take(&world->mutex);
world->deleted = EINA_TRUE;
_ephysics_world_event_callback_call(world, EPHYSICS_CALLBACK_WORLD_DEL,
NULL);
_ephysics_world_running_set(world, EINA_FALSE);
if (_worlds_walking > 0)
{
_worlds_to_delete = eina_list_append(_worlds_to_delete, world);
INF("World %p marked to delete.", world);
eina_lock_release(&world->mutex);
return;
}
eina_lock_release(&world->mutex);
_ephysics_world_th_cancel(world);
}
EAPI void
ephysics_world_running_set(EPhysics_World *world, Eina_Bool running)
{
if (!world)
{
ERR("Can't (un)pause world, it wasn't provided.");
return;
}
eina_lock_take(&world->mutex);
_ephysics_world_running_set(world, running);
eina_lock_release(&world->mutex);
}
EAPI Eina_Bool
ephysics_world_running_get(const EPhysics_World *world)
{
@ -742,7 +887,9 @@ ephysics_world_max_sleeping_time_set(EPhysics_World *world, double sleeping_time
return;
}
eina_lock_take(&world->mutex);
world->max_sleeping_time = sleeping_time;
eina_lock_release(&world->mutex);
}
EAPI double
@ -766,8 +913,10 @@ ephysics_world_gravity_set(EPhysics_World *world, double gx, double gy)
return;
}
eina_lock_take(&world->mutex);
_ephysics_world_gravity_set(world, gx, gy, world->rate);
DBG("World %p gravity set to X:%lf, Y:%lf.", world, gx, gy);
eina_lock_release(&world->mutex);
}
EAPI void
@ -779,7 +928,9 @@ ephysics_world_constraint_solver_iterations_set(EPhysics_World *world, int itera
return;
}
eina_lock_take(&world->mutex);
world->dynamics_world->getSolverInfo().m_numIterations = iterations;
eina_lock_release(&world->mutex);
}
EAPI int
@ -804,10 +955,12 @@ ephysics_world_constraint_solver_mode_enable_set(EPhysics_World *world, EPhysics
return;
}
eina_lock_take(&world->mutex);
current_solver_mode = world->dynamics_world->getSolverInfo().m_solverMode;
if ((enable && !(current_solver_mode & solver_mode)) ||
(!enable && (current_solver_mode & solver_mode)))
world->dynamics_world->getSolverInfo().m_solverMode ^= solver_mode;
eina_lock_release(&world->mutex);
}
EAPI Eina_Bool
@ -860,6 +1013,7 @@ ephysics_world_rate_set(EPhysics_World *world, double rate)
return;
}
eina_lock_take(&world->mutex);
/* Force to recalculate sizes, velocities and accelerations with new rate */
ephysics_world_gravity_get(world, &gx, &gy);
_ephysics_world_gravity_set(world, gx, gy, rate);
@ -871,6 +1025,7 @@ ephysics_world_rate_set(EPhysics_World *world, double rate)
ephysics_constraint_recalc((EPhysics_Constraint *)constraint, rate);
world->rate = rate;
eina_lock_release(&world->mutex);
}
EAPI double
@ -1050,7 +1205,9 @@ ephysics_world_linear_slop_set(EPhysics_World *world, double linear_slop)
return;
}
eina_lock_take(&world->mutex);
world->dynamics_world->getSolverInfo().m_linearSlop = btScalar(linear_slop);
eina_lock_release(&world->mutex);
}
EAPI double
@ -1202,11 +1359,13 @@ ephysics_world_simulation_set(EPhysics_World *world, double fixed_time_step, int
return;
}
eina_lock_take(&world->mutex);
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);
eina_lock_release(&world->mutex);
}
EAPI void
@ -1222,6 +1381,18 @@ ephysics_world_simulation_get(const EPhysics_World *world, double *fixed_time_st
if (max_sub_steps) *max_sub_steps = world->max_sub_steps;
}
void
ephysics_world_lock_take(EPhysics_World *world)
{
eina_lock_take(&world->mutex);
}
void
ephysics_world_lock_release(EPhysics_World *world)
{
eina_lock_release(&world->mutex);
}
#ifdef __cplusplus
}
#endif