ephysics: use multiple threads
authorBruno Dilly <bdilly@profusion.mobi>
Thu, 4 Oct 2012 22:38:06 +0000 (22:38 +0000)
committerBruno Dilly <bdilly@profusion.mobi>
Thu, 4 Oct 2012 22:38:06 +0000 (22:38 +0000)
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

legacy/ephysics/src/lib/EPhysics.h
legacy/ephysics/src/lib/ephysics_body.cpp
legacy/ephysics/src/lib/ephysics_constraints.cpp
legacy/ephysics/src/lib/ephysics_private.h
legacy/ephysics/src/lib/ephysics_world.cpp

index 5b00eee..2d07668 100644 (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
index 98f3d13..35bf24f 100644 (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;
 }
 
@@ -342,6 +348,24 @@ _ephysics_body_soft_body_constraints_rebuild(EPhysics_Body *body)
 }
 
 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)
 {
    double rate, sx, sy;
@@ -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
index 1263a52..834d923 100644 (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);
 }
 
 
index a9d29b1..2024073 100644 (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);
index 328d894..b77b284 100644 (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;
@@ -101,6 +116,14 @@ _ephysics_world_gravity_set(EPhysics_World *world, double gx, double gy, double
 }
 
 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)
 {
    EPhysics_World_Callback *cb;
@@ -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,9 +783,45 @@ 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;
 }
 
+static void
+_ephysics_world_running_set(EPhysics_World *world, Eina_Bool running)
+{
+   if ((!!running) == world->running) return;
+
+   world->running = !!running;
+
+   if (world->running)
+     {
+        world->last_update = ecore_time_get();
+        _worlds_running++;
+        INF("World unpaused.");
+     }
+   else
+     {
+        _worlds_running--;
+        INF("World paused.");
+     }
+
+   if (!_worlds_running)
+     {
+        if (_anim_simulate)
+          {
+             ecore_animator_del(_anim_simulate);
+             _anim_simulate = NULL;
+          }
+        return;
+     }
+
+   if (_anim_simulate)
+     return;
+
+   _anim_simulate = ecore_animator_add(_simulate_worlds, NULL);
+}
+
 EAPI void
 ephysics_world_del(EPhysics_World *world)
 {
@@ -665,19 +833,23 @@ ephysics_world_del(EPhysics_World *world)
 
    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);
+   _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;
      }
 
-   _ephysics_world_free(world);
+   eina_lock_release(&world->mutex);
+   _ephysics_world_th_cancel(world);
 }
 
 EAPI void
@@ -689,36 +861,9 @@ ephysics_world_running_set(EPhysics_World *world, Eina_Bool running)
         return;
      }
 
-   if ((!!running) == world->running) return;
-
-   world->running = !!running;
-
-   if (world->running)
-     {
-        world->last_update = ecore_time_get();
-        _worlds_running++;
-        INF("World unpaused.");
-     }
-   else
-     {
-        _worlds_running--;
-        INF("World paused.");
-     }
-
-   if (!_worlds_running)
-     {
-        if (_anim_simulate)
-          {
-             ecore_animator_del(_anim_simulate);
-             _anim_simulate = NULL;
-          }
-        return;
-     }
-
-   if (_anim_simulate)
-     return;
-
-   _anim_simulate = ecore_animator_add(_simulate_worlds, NULL);
+   eina_lock_take(&world->mutex);
+   _ephysics_world_running_set(world, running);
+   eina_lock_release(&world->mutex);
 }
 
 EAPI Eina_Bool
@@ -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