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
*
* @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
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;
}
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;
}
}
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;
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;
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);
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
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.");
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
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);
return NULL;
}
+ ephysics_world_lock_take(world);
shape = new btCylinderShapeZ(btVector3(0.25, 0.25, 0.25));
if (!shape)
{
body->points_deform[3][1] = 3;
body->points_deform[3][2] = 76;
+ ephysics_world_lock_release(world);
return body;
no_body:
no_soft_body:
delete shape;
no_collision_shape:
+ ephysics_world_lock_release(world);
return NULL;
}
ephysics_body_circle_add(EPhysics_World *world)
{
btCollisionShape *collision_shape;
+ EPhysics_Body *body;
if (!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 *
return NULL;
}
+ ephysics_world_lock_take(world);
shape = new btBoxShape(btVector3(0.25, 0.25, 0.25));
if (!shape)
{
body->points_deform[3][1] = 62;
body->points_deform[3][2] = 8;
+ ephysics_world_lock_release(world);
return body;
no_body:
no_soft_body:
delete shape;
no_collision_shape:
+ ephysics_world_lock_release(world);
return NULL;
}
ephysics_body_box_add(EPhysics_World *world)
{
btCollisionShape *collision_shape;
+ EPhysics_Body *body;
if (!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 *
btAlignedObjectArray<btVector3> vertexes, planes;
const Eina_Inlist *points;
EPhysics_Point *point;
+ EPhysics_Body *body;
int array_size, i;
btShapeHull *hull;
btVector3 point3d;
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
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
}
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
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 *
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
return;
}
+ ephysics_world_lock_take(body->world);
_ephysics_body_resize(body, w, h);
+ ephysics_world_lock_release(body->world);
}
EAPI void
return;
}
+ ephysics_world_lock_take(body->world);
_ephysics_body_move(body, x, y);
+ ephysics_world_lock_release(body->world);
}
EAPI void
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
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
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
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);
}
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
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
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
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
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
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
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
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
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);
body->rigid_body->getMotionState()->setWorldTransform(trans);
DBG("Body %p rotation set to %lf", body, rotation);
+ ephysics_world_lock_release(body->world);
}
EAPI void
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
}
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
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
}
constraint->type = EPHYSICS_CONSTRAINT_P2P;
- constraint->world = ephysics_body_world_get(constraint->p2p.body1);
ephysics_world_constraint_add(constraint->world, constraint,
constraint->bt_constraint);
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,
constraint->bt_constraint);
INF("Constraint added.");
+ ephysics_world_lock_release(ephysics_body_world_get(body));
return constraint;
}
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
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
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;
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;
}
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);
}
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);
#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 {
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;
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;
}
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;
}
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;
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
{
EPhysics_Body *bd;
- if (world->walking)
+ if (world->pending_ticks)
{
world->to_delete = eina_list_append(world->to_delete, body);
return EINA_FALSE;
EPhysics_Body *body;
void *constraint;
- _worlds = eina_inlist_remove(_worlds, EINA_INLIST_GET(world));
-
while (world->callbacks)
{
cb = EINA_INLIST_CONTAINER_GET(world->callbacks,
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);
}
_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--;
}
EINA_LIST_FREE(_worlds_to_delete, wrld)
- _ephysics_world_free((EPhysics_World *)wrld);
+ _ephysics_world_th_cancel((EPhysics_World *)wrld);
ephysics_shutdown();
{
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;
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;
}
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)
{
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;
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:
}
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;
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;
}
WRN("Problems on writing to: %s.", path);
fclose(file);
delete serializer;
+ eina_lock_release(&world->mutex);
return EINA_FALSE;
}
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)
{
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
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
return;
}
+ eina_lock_take(&world->mutex);
world->max_sleeping_time = sleeping_time;
+ eina_lock_release(&world->mutex);
}
EAPI double
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
return;
}
+ eina_lock_take(&world->mutex);
world->dynamics_world->getSolverInfo().m_numIterations = iterations;
+ eina_lock_release(&world->mutex);
}
EAPI int
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
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);
ephysics_constraint_recalc((EPhysics_Constraint *)constraint, rate);
world->rate = rate;
+ eina_lock_release(&world->mutex);
}
EAPI double
return;
}
+ eina_lock_take(&world->mutex);
world->dynamics_world->getSolverInfo().m_linearSlop = btScalar(linear_slop);
+ eina_lock_release(&world->mutex);
}
EAPI double
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
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