1 #ifdef HAVE_CONFIG_H
2 # include <config.h>
3 #endif
4 
5 #include <Ecore.h>
6 #include <Evas.h>
7 
8 #include "ephysics_private.h"
9 
10 #ifdef  __cplusplus
11 extern "C" {
12 #endif
13 
14 #define DEFAULT_GRAVITY btVector3(0, -9.8, 0)
15 
16 typedef struct _Simulation_Msg Simulation_Msg;
17 
18 struct _Simulation_Msg {
19      EPhysics_Body *body_0;
20      EPhysics_Body *body_1;
21      btVector3 pos_a;
22      btVector3 pos_b;
23      Eina_Bool tick:1;
24 };
25 
26 typedef struct _EPhysics_World_Callback EPhysics_World_Callback;
27 
28 struct _EPhysics_World_Callback {
29      EINA_INLIST;
30      void (*func) (void *data, EPhysics_World *world, void *event_info);
31      void *data;
32      EPhysics_Callback_World_Type type;
33      Eina_Bool deleted:1;
34 };
35 
36 struct _EPhysics_World {
37      EINA_INLIST;
38 
39      struct {
40           Evas_Coord x;
41           Evas_Coord y;
42           Evas_Coord z;
43           Evas_Coord w;
44           Evas_Coord h;
45           Evas_Coord d;
46      } geometry;
47 
48      btBroadphaseInterface *broadphase;
49      btDefaultCollisionConfiguration *collision;
50      btCollisionDispatcher *dispatcher;
51      btSequentialImpulseConstraintSolver *solver;
52      btSoftRigidDynamicsWorld *dynamics_world;
53      btSoftBodyWorldInfo *world_info;
54      btSoftBodySolver *soft_solver;
55      btOverlapFilterCallback *filter_cb;
56 
57      EPhysics_Body *boundaries[6];
58      EPhysics_Camera *camera;
59      Eina_Inlist *callbacks;
60      Eina_Inlist *bodies;
61      Eina_List *to_delete;
62      Eina_List *cb_to_delete;
63      Eina_List *constraints;
64      Ecore_Thread *simulation_th;
65      Ecore_Thread *cur_th;
66      int max_sub_steps;
67      int cb_walking;
68      int soft_body_ref;
69      int pending_ticks;
70      double last_update;
71      double rate;
72      double fixed_time_step;
73      double max_sleeping_time;
74      Eina_Lock mutex;
75      Eina_Condition condition;
76 
77      struct {
78           Evas_Coord lx;
79           Evas_Coord ly;
80           Evas_Coord lz;
81           int lr;
82           int lg;
83           int lb;
84           int ar;
85           int ag;
86           int ab;
87           Eina_Bool all_bodies:1;
88      } light;
89 
90      Eina_Bool running:1;
91      Eina_Bool ticked:1;
92      Eina_Bool active:1;
93      Eina_Bool deleted:1;
94      Eina_Bool outside_autodel:1;
95      Eina_Bool outside_top:1;
96      Eina_Bool outside_bottom:1;
97      Eina_Bool outside_left:1;
98      Eina_Bool outside_right:1;
99      Eina_Bool outside_front:1;
100      Eina_Bool outside_back:1;
101      Eina_Bool pending_simulation:1;
102      Eina_Bool stacking:1;
103      Eina_Bool force_update:1;
104 };
105 
106 static int _ephysics_world_init_count = 0;
107 static int _worlds_running = 0;
108 static Eina_Inlist *_worlds = NULL;
109 static Eina_List *_worlds_to_delete = NULL;
110 static Ecore_Animator *_anim_simulate = NULL;
111 static int _worlds_walking = 0;
112 
113 void
ephysics_world_force_update_set(EPhysics_World * world,Eina_Bool force_update)114 ephysics_world_force_update_set(EPhysics_World *world, Eina_Bool force_update)
115 {
116    world->force_update = force_update;
117 }
118 
119 btSoftBodyWorldInfo *
ephysics_world_info_get(const EPhysics_World * world)120 ephysics_world_info_get(const EPhysics_World *world)
121 {
122    return world->world_info;
123 }
124 
125 struct _ephysics_world_ovelap_filter_cb : public btOverlapFilterCallback
126 {
needBroadphaseCollision_ephysics_world_ovelap_filter_cb127    virtual bool needBroadphaseCollision(btBroadphaseProxy* proxy0,
128                                         btBroadphaseProxy* proxy1) const
129    {
130       btCollisionObject *coll0 = (btCollisionObject *)proxy0->m_clientObject;
131       btCollisionObject *coll1 = (btCollisionObject *)proxy1->m_clientObject;
132 
133       EPhysics_Body *body0 = (EPhysics_Body *)coll0->getUserPointer();
134       EPhysics_Body *body1 = (EPhysics_Body *)coll1->getUserPointer();
135 
136       if ((!body0 || !body1) || (ephysics_body_filter_collision(body0, body1)))
137         return EINA_TRUE;
138 
139       return EINA_FALSE;
140    }
141 };
142 
143 static inline void
_ephysics_world_gravity_set(EPhysics_World * world,double gx,double gy,double gz,double rate)144 _ephysics_world_gravity_set(EPhysics_World *world, double gx, double gy, double gz, double rate)
145 {
146    btVector3 gravity;
147 
148    gravity = btVector3(gx / rate, -gy / rate, gz / rate);
149    world->dynamics_world->setGravity(gravity);
150    world->world_info->m_gravity = gravity;
151 }
152 
153 static void
_ephysics_world_th_cancel(EPhysics_World * world)154 _ephysics_world_th_cancel(EPhysics_World *world)
155 {
156    _worlds = eina_inlist_remove(_worlds, EINA_INLIST_GET(world));
157    if (!ecore_thread_cancel(world->simulation_th))
158      eina_condition_signal(&world->condition);
159 }
160 
161 static void
_ephysics_world_event_callback_call(EPhysics_World * world,EPhysics_Callback_World_Type type,void * event_info)162 _ephysics_world_event_callback_call(EPhysics_World *world, EPhysics_Callback_World_Type type, void *event_info)
163 {
164    EPhysics_World_Callback *cb;
165    void *clb;
166 
167    world->cb_walking++;
168    EINA_INLIST_FOREACH(world->callbacks, cb)
169      {
170         if ((cb->type == type) && (!cb->deleted))
171           cb->func(cb->data, world, event_info);
172      }
173    world->cb_walking--;
174 
175    if (world->cb_walking > 0) return;
176 
177    EINA_LIST_FREE(world->cb_to_delete, clb)
178      {
179         cb = (EPhysics_World_Callback *)clb;
180         world->callbacks = eina_inlist_remove(world->callbacks,
181                                               EINA_INLIST_GET(cb));
182         free(cb);
183      }
184 }
185 
186 static void
_ephysics_world_event_callback_del(EPhysics_World * world,EPhysics_World_Callback * cb)187 _ephysics_world_event_callback_del(EPhysics_World *world, EPhysics_World_Callback *cb)
188 {
189    if (cb->deleted) return;
190 
191    cb->deleted = EINA_TRUE;
192 
193    if (world->cb_walking)
194      {
195         world->cb_to_delete = eina_list_append(world->cb_to_delete, cb);
196         return;
197      }
198 
199    world->callbacks = eina_inlist_remove(world->callbacks,
200                                          EINA_INLIST_GET(cb));
201    free(cb);
202 }
203 
204 static void
_ephysics_world_tick(btDynamicsWorld * dynamics_world)205 _ephysics_world_tick(btDynamicsWorld *dynamics_world)
206 {
207    Eina_Bool world_active, camera_moved, tx, ty;
208    btCollisionObjectArray objects;
209    btCollisionObject *collision;
210    EPhysics_World *world;
211    EPhysics_Body *body;
212    btRigidBody *rigid_body;
213 
214    world = (EPhysics_World *) dynamics_world->getWorldUserInfo();
215 
216    world_active = EINA_FALSE;
217 
218    ephysics_camera_tracked_body_get(world->camera, &body, &tx, &ty);
219    if ((body) && (tx || ty))
220      {
221         rigid_body = ephysics_body_rigid_body_get(body);
222         if ((rigid_body) && (rigid_body->isActive()))
223           ephysics_camera_target_moved(world->camera, body);
224      }
225 
226    camera_moved = ephysics_camera_moved_get(world->camera);
227 
228    objects = dynamics_world->getCollisionObjectArray();
229    for (int i = 0; i < objects.size(); i++)
230      {
231         collision = objects[i];
232 
233         if (!collision)
234           continue;
235 
236         body = (EPhysics_Body *) collision->getUserPointer();
237         if (collision->isActive())
238           {
239              ephysics_body_active_set(body, EINA_TRUE);
240              ephysics_body_evas_object_update_select(body);
241              world_active = EINA_TRUE;
242           }
243         else
244           {
245              ephysics_body_active_set(body, EINA_FALSE);
246              if (camera_moved || world->force_update)
247                ephysics_body_evas_object_update_select(body);
248           }
249      }
250 
251    if (world->stacking)
252      ephysics_body_evas_objects_restack(world);
253 
254    world->force_update = EINA_FALSE;
255    if (camera_moved)
256      {
257         ephysics_camera_moved_set(world->camera, EINA_FALSE);
258         _ephysics_world_event_callback_call(
259            world, EPHYSICS_CALLBACK_WORLD_CAMERA_MOVED, world->camera);
260      }
261 
262    if (world->active == world_active) goto body_del;
263    world->active = world_active;
264    if (world_active) goto body_del;
265 
266    _ephysics_world_event_callback_call(world, EPHYSICS_CALLBACK_WORLD_STOPPED,
267                                        NULL);
268 
269 body_del:
270    if (world_active)
271      _ephysics_world_event_callback_call(world, EPHYSICS_CALLBACK_WORLD_UPDATE,
272                                          NULL);
273    world->pending_ticks--;
274    if (!world->pending_ticks)
275      {
276         void *bd;
277         EINA_LIST_FREE(world->to_delete, bd)
278            ephysics_world_body_del(world, (EPhysics_Body*)bd);
279      }
280 
281    if ((world->pending_simulation) && (!world->pending_ticks))
282      {
283         world->pending_simulation = EINA_FALSE;
284         eina_condition_signal(&world->condition);
285      }
286 }
287 
288 static void
_ephysics_world_tick_dispatch(EPhysics_World * world)289 _ephysics_world_tick_dispatch(EPhysics_World *world)
290 {
291    Simulation_Msg *msg;
292 
293    if (!world->ticked)
294      return;
295 
296    world->ticked = EINA_FALSE;
297    world->pending_ticks++;
298 
299    msg = (Simulation_Msg *) calloc(1, sizeof(Simulation_Msg));
300    msg->tick = EINA_TRUE;
301    ecore_thread_feedback(world->cur_th, msg);
302 }
303 
304 static void
_ephysics_world_tick_cb(btDynamicsWorld * dynamics_world,btScalar timeStep EINA_UNUSED)305 _ephysics_world_tick_cb(btDynamicsWorld *dynamics_world, btScalar timeStep EINA_UNUSED)
306 {
307    EPhysics_World *world;
308    world = (EPhysics_World *) dynamics_world->getWorldUserInfo();
309    world->ticked = EINA_TRUE;
310 }
311 
312 static void
_ephysics_world_body_del(EPhysics_World * world,EPhysics_Body * body)313 _ephysics_world_body_del(EPhysics_World *world, EPhysics_Body *body)
314 {
315    btSoftBody *soft_body;
316 
317    if (ephysics_body_rigid_body_get(body))
318      world->dynamics_world->removeRigidBody(ephysics_body_rigid_body_get(body));
319 
320    soft_body = ephysics_body_soft_body_get(body);
321    if (soft_body)
322      {
323         world->dynamics_world->removeSoftBody(soft_body);
324         --world->soft_body_ref;
325      }
326 
327    world->bodies = eina_inlist_remove(world->bodies, EINA_INLIST_GET(body));
328    ephysics_orphan_body_del(body);
329 }
330 
331 static void
_ephysics_world_boundary_del(EPhysics_World * world,EPhysics_Body * body)332 _ephysics_world_boundary_del(EPhysics_World *world, EPhysics_Body *body)
333 {
334    int i;
335 
336    for (i = 0; i < EPHYSICS_WORLD_BOUNDARY_LAST; i++)
337      {
338         if (world->boundaries[i] == body)
339           {
340              world->boundaries[i] = NULL;
341              return;
342           }
343      }
344 }
345 
346 Eina_Bool
ephysics_world_body_del(EPhysics_World * world,EPhysics_Body * body)347 ephysics_world_body_del(EPhysics_World *world, EPhysics_Body *body)
348 {
349    EPhysics_Body *bd;
350 
351    if (body->boundary)
352      _ephysics_world_boundary_del(world, body);
353 
354    if (world->pending_ticks)
355      {
356         world->to_delete = eina_list_append(world->to_delete, body);
357         return EINA_FALSE;
358      }
359 
360    _ephysics_world_body_del(world, body);
361 
362    /* Activate all the bodies after a body is deleted.
363       Otherwise it can lead to scenarios when a body 1, below body 2 is deleted
364       and body 2 will stay freezed in the air. Gravity won't start to
365       act over it until it's activated again. */
366    EINA_INLIST_FOREACH(world->bodies, bd)
367      ephysics_body_activate(bd, EINA_TRUE);
368 
369    return EINA_TRUE;
370 }
371 
372 static void
_ephysics_world_free(EPhysics_World * world)373 _ephysics_world_free(EPhysics_World *world)
374 {
375    EPhysics_World_Callback *cb;
376    EPhysics_Body *body;
377    void *constraint;
378 
379    while (world->callbacks)
380      {
381         cb = EINA_INLIST_CONTAINER_GET(world->callbacks,
382                                        EPhysics_World_Callback);
383         world->callbacks = eina_inlist_remove(world->callbacks,
384                                               world->callbacks);
385         free(cb);
386      }
387 
388    while (world->bodies)
389      {
390         body = EINA_INLIST_CONTAINER_GET(world->bodies, EPhysics_Body);
391         _ephysics_world_body_del(world, body);
392      }
393 
394    EINA_LIST_FREE(world->constraints, constraint)
395       ephysics_constraint_del((EPhysics_Constraint *)constraint);
396 
397    ephysics_camera_del(world->camera);
398 
399    delete world->filter_cb;
400    delete world->dynamics_world;
401    delete world->solver;
402    delete world->broadphase;
403    delete world->dispatcher;
404    delete world->collision;
405    delete world->soft_solver;
406    delete world->world_info;
407 
408    eina_condition_free(&world->condition);
409    eina_lock_free(&world->mutex);
410 
411    INF("World %p deleted.", world);
412    free(world);
413    ephysics_dom_count_dec();
414 }
415 
416 static Eina_Bool
_simulate_worlds(void * data EINA_UNUSED)417 _simulate_worlds(void *data EINA_UNUSED)
418 {
419    EPhysics_World *world;
420    void *wrld;
421 
422    ephysics_init();
423    _worlds_walking++;
424    EINA_INLIST_FOREACH(_worlds, world)
425      {
426         if (!world->running)
427           continue;
428 
429         if (world->pending_ticks)
430           {
431              world->pending_simulation = EINA_TRUE;
432              continue;
433           }
434 
435         world->pending_simulation = EINA_FALSE;
436 
437         eina_condition_signal(&world->condition);
438      }
439    _worlds_walking--;
440 
441    if (_worlds_walking > 0)
442      {
443         ephysics_shutdown();
444         return EINA_TRUE;
445      }
446 
447    EINA_LIST_FREE(_worlds_to_delete, wrld)
448       _ephysics_world_th_cancel((EPhysics_World *)wrld);
449 
450    ephysics_shutdown();
451 
452    return EINA_TRUE;
453 }
454 
455 static bool
_ephysics_world_contact_processed_cb(btManifoldPoint & cp,void * b0,void * b1)456 _ephysics_world_contact_processed_cb(btManifoldPoint &cp, void *b0, void *b1)
457 {
458    btRigidBody *rigid_body_0, *rigid_body_1;
459    EPhysics_Body *body_0, *body_1;
460    EPhysics_World *world;
461    Simulation_Msg *msg;
462 
463    rigid_body_0 = (btRigidBody *) b0;
464    rigid_body_1 = (btRigidBody *) b1;
465 
466    body_0 = (EPhysics_Body *) rigid_body_0->getUserPointer();
467    body_1 = (EPhysics_Body *) rigid_body_1->getUserPointer();
468 
469    world = ephysics_body_world_get(body_0);
470 
471    msg = (Simulation_Msg *) calloc(1, sizeof(Simulation_Msg));
472    msg->body_0 = body_0;
473    msg->body_1 = body_1;
474    msg->pos_a = cp.getPositionWorldOnA();
475    msg->pos_b = cp.getPositionWorldOnB();
476    ecore_thread_feedback(world->cur_th, msg);
477 
478    return EINA_TRUE;
479 }
480 
481 Eina_Bool
ephysics_world_body_add(EPhysics_World * world,EPhysics_Body * body)482 ephysics_world_body_add(EPhysics_World *world, EPhysics_Body *body)
483 {
484    if (!eina_inlist_find(world->bodies, EINA_INLIST_GET(body)))
485        world->bodies = eina_inlist_append(world->bodies, EINA_INLIST_GET(body));
486 
487    if (eina_error_get())
488      {
489         ERR("Couldn't add body to bodies list.");
490         return EINA_FALSE;
491      }
492 
493    world->dynamics_world->addRigidBody(ephysics_body_rigid_body_get(body));
494    return EINA_TRUE;
495 }
496 
497 Eina_Bool
ephysics_world_soft_body_add(EPhysics_World * world,EPhysics_Body * body)498 ephysics_world_soft_body_add(EPhysics_World *world, EPhysics_Body *body)
499 {
500    if (!eina_inlist_find(world->bodies, EINA_INLIST_GET(body)))
501        world->bodies = eina_inlist_append(world->bodies, EINA_INLIST_GET(body));
502 
503    if (eina_error_get())
504      {
505         ERR("Couldn't add body to bodies list.");
506         return EINA_FALSE;
507      }
508 
509    ++world->soft_body_ref;
510    world->dynamics_world->addSoftBody(ephysics_body_soft_body_get(body));
511    return EINA_TRUE;
512 }
513 
514 Eina_List *
ephysics_world_constraints_get(EPhysics_World * world)515 ephysics_world_constraints_get(EPhysics_World *world)
516 {
517    return world->constraints;
518 }
519 
520 void
ephysics_world_constraint_add(EPhysics_World * world,EPhysics_Constraint * constraint,btGeneric6DofConstraint * bt_constraint)521 ephysics_world_constraint_add(EPhysics_World *world, EPhysics_Constraint *constraint, btGeneric6DofConstraint *bt_constraint)
522 {
523    world->dynamics_world->addConstraint(bt_constraint, true);
524    world->constraints = eina_list_append(world->constraints, constraint);
525 }
526 
527 void
ephysics_world_constraint_del(EPhysics_World * world,EPhysics_Constraint * constraint,btGeneric6DofConstraint * bt_constraint)528 ephysics_world_constraint_del(EPhysics_World *world, EPhysics_Constraint *constraint, btGeneric6DofConstraint *bt_constraint)
529 {
530    world->dynamics_world->removeConstraint(bt_constraint);
531    world->constraints = eina_list_remove(world->constraints, constraint);
532 }
533 
534 int
ephysics_world_init(void)535 ephysics_world_init(void)
536 {
537    if (++_ephysics_world_init_count != 1)
538      return _ephysics_world_init_count;
539 
540    gContactProcessedCallback = _ephysics_world_contact_processed_cb;
541 
542    INF("EPhysics World initialized.");
543 
544    return _ephysics_world_init_count;
545 }
546 
547 int
ephysics_world_shutdown(void)548 ephysics_world_shutdown(void)
549 {
550    if (--_ephysics_world_init_count != 0)
551      return _ephysics_world_init_count;
552 
553    if (_anim_simulate)
554      {
555         ecore_animator_del(_anim_simulate);
556         _anim_simulate = NULL;
557      }
558 
559    while (_worlds)
560      {
561         EPhysics_World *world = EINA_INLIST_CONTAINER_GET(
562            _worlds, EPhysics_World);
563         ephysics_world_del(world);
564      }
565 
566    _worlds_running = 0;
567 
568    INF("EPhysics World shutdown.");
569 
570    return _ephysics_world_init_count;
571 }
572 
573 void
ephysics_world_boundary_set(EPhysics_World * world,EPhysics_World_Boundary boundary,EPhysics_Body * body)574 ephysics_world_boundary_set(EPhysics_World *world, EPhysics_World_Boundary boundary, EPhysics_Body *body)
575 {
576    world->boundaries[boundary] = body;
577 }
578 
579 EPhysics_Body *
ephysics_world_boundary_get(const EPhysics_World * world,EPhysics_World_Boundary boundary)580 ephysics_world_boundary_get(const EPhysics_World *world, EPhysics_World_Boundary boundary)
581 {
582    return world->boundaries[boundary];
583 }
584 
585 static void
_th_simulate(void * data,Ecore_Thread * th)586 _th_simulate(void *data, Ecore_Thread *th)
587 {
588    EPhysics_World *world = (EPhysics_World *) data;
589 
590    while (1)
591      {
592         double time_now, delta;
593         EPhysics_Body *body;
594 
595         eina_condition_wait(&world->condition);
596         if (ecore_thread_check(th))
597           {
598              INF("Thread canceled by main loop thread");
599              eina_lock_release(&world->mutex);
600              return;
601           }
602 
603         world->pending_ticks++;
604         world->cur_th = th;
605 
606         EINA_INLIST_FOREACH(world->bodies, body)
607           {
608              ephysics_body_forces_apply(body);
609              if (body->dragging_data.dragging)
610                ephysics_body_soft_body_dragging_apply(body);
611 
612              if (body->bending_constraints)
613                ephysics_body_soft_body_bending_constraints_generate(body);
614           }
615 
616         time_now = ecore_time_get();
617         delta = time_now - world->last_update;
618         world->last_update = time_now;
619 
620         gDeactivationTime = world->max_sleeping_time;
621 
622         if (world->soft_body_ref)
623           {
624              world->dynamics_world->stepSimulation(delta, world->max_sub_steps,
625                                                 world->fixed_time_step);
626              world->world_info->m_sparsesdf.GarbageCollect();
627           }
628         else
629           ((btDiscreteDynamicsWorld *)world->dynamics_world)->stepSimulation(
630              delta, world->max_sub_steps, world->fixed_time_step);
631 
632         _ephysics_world_tick_dispatch(world);
633         world->pending_ticks--;
634         eina_lock_release(&world->mutex);
635      }
636 }
637 
638 static void
_th_msg_cb(void * data,Ecore_Thread * th EINA_UNUSED,void * msg_data)639 _th_msg_cb(void *data, Ecore_Thread *th EINA_UNUSED, void *msg_data)
640 {
641    EPhysics_World *world = (EPhysics_World *) data;
642    Simulation_Msg *msg = (Simulation_Msg *) msg_data;
643 
644    if (msg->tick)
645      _ephysics_world_tick(world->dynamics_world);
646    else
647      {
648         ephysics_body_contact_processed(msg->body_0, msg->body_1, msg->pos_a);
649         ephysics_body_contact_processed(msg->body_1, msg->body_0, msg->pos_b);
650      }
651    free(msg);
652 }
653 
654 static void
_th_end_cb(void * data,Ecore_Thread * th)655 _th_end_cb(void *data, Ecore_Thread *th)
656 {
657    EPhysics_World *world = (EPhysics_World *) data;
658    INF("World %p simulation thread %p end", world, th);
659    world->simulation_th = NULL;
660    _ephysics_world_free(world);
661 }
662 
663 static void
_th_cancel_cb(void * data,Ecore_Thread * th)664 _th_cancel_cb(void *data, Ecore_Thread *th)
665 {
666    EPhysics_World *world = (EPhysics_World *) data;
667    INF("World %p simulation thread %p canceled", world, th);
668    world->simulation_th = NULL;
669    _ephysics_world_free(world);
670 }
671 
672 EAPI EPhysics_World *
ephysics_world_new(void)673 ephysics_world_new(void)
674 {
675    EPhysics_World *world;
676 
677    world = (EPhysics_World *) calloc(1, sizeof(EPhysics_World));
678    if (!world)
679      {
680         ERR("Couldn't create a new world instance.");
681         return NULL;
682      }
683 
684    world->camera = ephysics_camera_add(world);
685    if (!world->camera)
686      {
687         ERR("Couldn't create a camera for this world.");
688         goto no_camera;
689      }
690 
691    world->broadphase = new btDbvtBroadphase();
692    if (!world->broadphase)
693      {
694         ERR("Couldn't set broadphase.");
695         goto no_broadphase;
696      }
697 
698    world->collision = new btSoftBodyRigidBodyCollisionConfiguration();
699    if (!world->collision)
700      {
701         ERR("Couldn't configure collision.");
702         goto no_collision;
703      }
704 
705    world->dispatcher = new btCollisionDispatcher(world->collision);
706    if (!world->dispatcher)
707      {
708         ERR("Couldn't create dispatcher.");
709         goto no_dispatcher;
710      }
711 
712    world->solver = new btSequentialImpulseConstraintSolver;
713    if (!world->solver)
714      {
715         ERR("Couldn't create solver.");
716         goto no_solver;
717      }
718 
719    world->soft_solver = new btDefaultSoftBodySolver();
720    if (!world->soft_solver)
721      {
722         ERR("Couldn't create soft body solver.");
723         goto no_soft_solver;
724      }
725 
726    world->dynamics_world = new btSoftRigidDynamicsWorld(
727       world->dispatcher, world->broadphase, world->solver,
728       world->collision, world->soft_solver);
729    if (!world->dynamics_world)
730      {
731         ERR("Couldn't create dynamic world.");
732         goto no_world;
733      }
734 
735    world->world_info = new btSoftBodyWorldInfo();
736    if (!world->world_info)
737      {
738         ERR("Couldn't create soft body world info.");
739         goto no_world_info;
740      }
741 
742    world->world_info->m_gravity = DEFAULT_GRAVITY;
743    world->world_info->m_broadphase = world->broadphase;
744    world->world_info->m_dispatcher = world->dispatcher;
745    world->world_info->m_sparsesdf.Initialize();
746 
747    _worlds = eina_inlist_append(_worlds, EINA_INLIST_GET(world));
748    if (eina_error_get())
749      {
750         ERR("Couldn't add world to worlds list.");
751         goto no_list;
752      }
753    world->simulation_th = ecore_thread_feedback_run(
754       _th_simulate, _th_msg_cb, _th_end_cb, _th_cancel_cb, world, EINA_TRUE);
755    if (!world->simulation_th)
756      {
757         ERR("Failed to create simulation thread.");
758         goto no_thread;
759      }
760    eina_lock_new(&world->mutex);
761    eina_condition_new(&world->condition, &world->mutex);
762 
763    world->dynamics_world->getSolverInfo().m_solverMode ^=
764       EPHYSICS_WORLD_SOLVER_SIMD;
765    world->dynamics_world->setGravity(DEFAULT_GRAVITY);
766 
767    world->filter_cb = new _ephysics_world_ovelap_filter_cb();
768    if (!world->filter_cb)
769      INF("Couldn't initialize the collision filter.");
770    else
771      world->dynamics_world->getPairCache()->setOverlapFilterCallback(
772         world->filter_cb);
773 
774    world->light.lr = 255;
775    world->light.lg = 255;
776    world->light.lb = 255;
777    world->light.lz = -200;
778 
779    world->stacking = EINA_TRUE;
780    world->rate = 30;
781    world->max_sub_steps = 3;
782    world->fixed_time_step = 1/60.f;
783    world->dynamics_world->setInternalTickCallback(_ephysics_world_tick_cb,
784                                                   (void *) world);
785 
786    world->max_sleeping_time = 2.0;
787    world->running = EINA_TRUE;
788    world->last_update = ecore_time_get();
789    _worlds_running++;
790    if (!_anim_simulate)
791      _anim_simulate = ecore_animator_add(_simulate_worlds, NULL);
792 
793    ephysics_dom_count_inc();
794    INF("World %p added.", world);
795    return world;
796 
797 no_thread:
798    _worlds = eina_inlist_remove(_worlds, EINA_INLIST_GET(world));
799 no_list:
800    delete world->world_info;
801 no_world_info:
802    delete world->dynamics_world;
803 no_world:
804    delete world->soft_solver;
805 no_soft_solver:
806    delete world->solver;
807 no_solver:
808    delete world->dispatcher;
809 no_dispatcher:
810    delete world->collision;
811 no_collision:
812    delete world->broadphase;
813 no_broadphase:
814    ephysics_camera_del(world->camera);
815 no_camera:
816    free(world);
817    return NULL;
818 }
819 
820 EAPI Eina_Bool
ephysics_world_serialize(EPhysics_World * world,const char * path)821 ephysics_world_serialize(EPhysics_World *world, const char *path)
822 {
823    btDefaultSerializer *serializer;
824    FILE *file;
825 
826    if (!world)
827      {
828         WRN("Could not serialize, world not provided.");
829         return EINA_FALSE;
830       }
831 
832    eina_lock_take(&world->mutex);
833 
834    file = fopen(path, "wb");
835    if (!file)
836      {
837         WRN("Could not serialize, could not open file: %s", path);
838         eina_lock_release(&world->mutex);
839         return EINA_FALSE;
840      }
841 
842    serializer = new btDefaultSerializer();
843    world->dynamics_world->serialize(serializer);
844 
845    if (!fwrite(serializer->getBufferPointer(),
846               serializer->getCurrentBufferSize(), 1, file))
847      {
848         WRN("Problems on writing to: %s.", path);
849         fclose(file);
850         delete serializer;
851         eina_lock_release(&world->mutex);
852         return EINA_FALSE;
853      }
854 
855    fclose(file);
856    delete serializer;
857 
858    INF("Serialization of world %p written to file: %s.", world, path);
859 
860    eina_lock_release(&world->mutex);
861    return EINA_TRUE;
862 }
863 
864 static void
_ephysics_world_running_set(EPhysics_World * world,Eina_Bool running)865 _ephysics_world_running_set(EPhysics_World *world, Eina_Bool running)
866 {
867    if ((!!running) == world->running) return;
868 
869    world->running = !!running;
870 
871    if (world->running)
872      {
873         world->last_update = ecore_time_get();
874         _worlds_running++;
875         INF("World unpaused.");
876      }
877    else
878      {
879         _worlds_running--;
880         INF("World paused.");
881      }
882 
883    if (!_worlds_running)
884      {
885         if (_anim_simulate)
886           {
887              ecore_animator_del(_anim_simulate);
888              _anim_simulate = NULL;
889           }
890         return;
891      }
892 
893    if (_anim_simulate)
894      return;
895 
896    _anim_simulate = ecore_animator_add(_simulate_worlds, NULL);
897 }
898 
899 EAPI void
ephysics_world_del(EPhysics_World * world)900 ephysics_world_del(EPhysics_World *world)
901 {
902    if (!world)
903      {
904         ERR("Can't delete world, it wasn't provided.");
905         return;
906      }
907 
908    if (world->deleted) return;
909 
910    eina_lock_take(&world->mutex);
911 
912    world->deleted = EINA_TRUE;
913    _ephysics_world_event_callback_call(world, EPHYSICS_CALLBACK_WORLD_DEL,
914                                        NULL);
915    _ephysics_world_running_set(world, EINA_FALSE);
916 
917    if (_worlds_walking > 0)
918      {
919         _worlds_to_delete = eina_list_append(_worlds_to_delete, world);
920         INF("World %p marked to delete.", world);
921         eina_lock_release(&world->mutex);
922         return;
923      }
924 
925    eina_lock_release(&world->mutex);
926    _ephysics_world_th_cancel(world);
927 }
928 
929 EAPI void
ephysics_world_running_set(EPhysics_World * world,Eina_Bool running)930 ephysics_world_running_set(EPhysics_World *world, Eina_Bool running)
931 {
932    if (!world)
933      {
934         ERR("Can't (un)pause world, it wasn't provided.");
935         return;
936      }
937 
938    eina_lock_take(&world->mutex);
939    _ephysics_world_running_set(world, running);
940    eina_lock_release(&world->mutex);
941 }
942 
943 EAPI Eina_Bool
ephysics_world_running_get(const EPhysics_World * world)944 ephysics_world_running_get(const EPhysics_World *world)
945 {
946    if (!world)
947      {
948 	ERR("No world, no running status for you.");
949 	return EINA_FALSE;
950      }
951 
952    return world->running;
953 }
954 
955 EAPI void
ephysics_world_max_sleeping_time_set(EPhysics_World * world,double sleeping_time)956 ephysics_world_max_sleeping_time_set(EPhysics_World *world, double sleeping_time)
957 {
958    if (!world)
959      {
960 	ERR("Can't set the world's max sleeping time, world is null.");
961 	return;
962      }
963 
964    eina_lock_take(&world->mutex);
965    world->max_sleeping_time = sleeping_time;
966    eina_lock_release(&world->mutex);
967 }
968 
969 EAPI double
ephysics_world_max_sleeping_time_get(const EPhysics_World * world)970 ephysics_world_max_sleeping_time_get(const EPhysics_World *world)
971 {
972    if (!world)
973      {
974 	ERR("Can't get the world's max sleeping time, world is null.");
975 	return 0;
976      }
977 
978    return world->max_sleeping_time;
979 }
980 
981 EAPI void
ephysics_world_gravity_set(EPhysics_World * world,double gx,double gy,double gz)982 ephysics_world_gravity_set(EPhysics_World *world, double gx, double gy, double gz)
983 {
984    EPhysics_Body *bd;
985 
986    if (!world)
987      {
988         ERR("Can't set gravity, no world provided.");
989         return;
990      }
991 
992    eina_lock_take(&world->mutex);
993    EINA_INLIST_FOREACH(world->bodies, bd)
994       ephysics_body_activate(bd, EINA_TRUE);
995    _ephysics_world_gravity_set(world, gx, gy, gz, world->rate);
996    DBG("World %p gravity set to X:%lf, Y:%lf, Z: %lf.", world, gx, gy, gz);
997    eina_lock_release(&world->mutex);
998 }
999 
1000 EAPI void
ephysics_world_constraint_solver_iterations_set(EPhysics_World * world,int iterations)1001 ephysics_world_constraint_solver_iterations_set(EPhysics_World *world, int iterations)
1002 {
1003    if (!world)
1004      {
1005         ERR("Can't set constraint solver iterations, world is null.");
1006         return;
1007      }
1008 
1009    eina_lock_take(&world->mutex);
1010    world->dynamics_world->getSolverInfo().m_numIterations = iterations;
1011    eina_lock_release(&world->mutex);
1012 }
1013 
1014 EAPI int
ephysics_world_constraint_solver_iterations_get(const EPhysics_World * world)1015 ephysics_world_constraint_solver_iterations_get(const EPhysics_World *world)
1016 {
1017    if (!world)
1018      {
1019         ERR("Can't get constraint solver iterations, world is null.");
1020         return 0;
1021      }
1022 
1023    return world->dynamics_world->getSolverInfo().m_numIterations;
1024 }
1025 
1026 EAPI void
ephysics_world_constraint_solver_mode_enable_set(EPhysics_World * world,EPhysics_World_Solver_Mode solver_mode,Eina_Bool enable)1027 ephysics_world_constraint_solver_mode_enable_set(EPhysics_World *world, EPhysics_World_Solver_Mode solver_mode, Eina_Bool enable)
1028 {
1029    int current_solver_mode;
1030     if (!world)
1031      {
1032         ERR("Can't enable/disable constraint solver mode, world is null.");
1033         return;
1034      }
1035 
1036    eina_lock_take(&world->mutex);
1037    current_solver_mode = world->dynamics_world->getSolverInfo().m_solverMode;
1038    if ((enable && !(current_solver_mode & solver_mode)) ||
1039        (!enable && (current_solver_mode & solver_mode)))
1040      world->dynamics_world->getSolverInfo().m_solverMode ^= solver_mode;
1041    eina_lock_release(&world->mutex);
1042 }
1043 
1044 EAPI Eina_Bool
ephysics_world_constraint_solver_mode_enable_get(const EPhysics_World * world,EPhysics_World_Solver_Mode solver_mode)1045 ephysics_world_constraint_solver_mode_enable_get(const EPhysics_World *world, EPhysics_World_Solver_Mode solver_mode)
1046 {
1047      if (!world)
1048      {
1049         ERR("Can't get constraint solver mode status, world is null.");
1050         return EINA_FALSE;
1051      }
1052 
1053      return world->dynamics_world->getSolverInfo().m_solverMode & solver_mode;
1054 }
1055 
1056 EAPI void
ephysics_world_gravity_get(const EPhysics_World * world,double * gx,double * gy,double * gz)1057 ephysics_world_gravity_get(const EPhysics_World *world, double *gx, double *gy, double *gz)
1058 {
1059    btVector3 vector;
1060 
1061    if (!world)
1062      {
1063 	ERR("No world, can't get gravity.");
1064 	return;
1065      }
1066 
1067    vector = world->dynamics_world->getGravity();
1068 
1069    if (gx) *gx = vector.x() * world->rate;
1070    if (gy) *gy = -vector.y() * world->rate;
1071    if (gz) *gz = vector.z() * world->rate;
1072 }
1073 
1074 EAPI void
ephysics_world_rate_set(EPhysics_World * world,double rate)1075 ephysics_world_rate_set(EPhysics_World *world, double rate)
1076 {
1077    EPhysics_Body *body;
1078    double gx, gy, gz;
1079    void *constraint;
1080    Eina_List *l;
1081 
1082    if (!world)
1083      {
1084 	ERR("No world, can't set rate.");
1085 	return;
1086      }
1087 
1088    if (rate <= 0)
1089      {
1090 	ERR("Rate should be a positive value. Keeping the old value: %lf.",
1091             world->rate);
1092         return;
1093      }
1094 
1095    eina_lock_take(&world->mutex);
1096    /* Force to recalculate sizes, velocities and accelerations with new rate */
1097    ephysics_world_gravity_get(world, &gx, &gy, &gz);
1098    _ephysics_world_gravity_set(world, gx, gy, gz, rate);
1099 
1100    EINA_INLIST_FOREACH(world->bodies, body)
1101       ephysics_body_recalc(body, rate);
1102 
1103    EINA_LIST_FOREACH(world->constraints, l, constraint)
1104         ephysics_constraint_recalc((EPhysics_Constraint *)constraint, rate);
1105 
1106    world->rate = rate;
1107    eina_lock_release(&world->mutex);
1108 }
1109 
1110 EAPI double
ephysics_world_rate_get(const EPhysics_World * world)1111 ephysics_world_rate_get(const EPhysics_World *world)
1112 {
1113    if (!world)
1114      {
1115 	ERR("No world, can't get rate.");
1116 	return 0;
1117      }
1118 
1119    return world->rate;
1120 }
1121 
1122 EAPI EPhysics_Camera *
ephysics_world_camera_get(const EPhysics_World * world)1123 ephysics_world_camera_get(const EPhysics_World *world)
1124 {
1125    if (!world)
1126      {
1127 	ERR("No world, no camera for you.");
1128 	return NULL;
1129      }
1130 
1131    return world->camera;
1132 }
1133 
1134 EAPI void
ephysics_world_event_callback_add(EPhysics_World * world,EPhysics_Callback_World_Type type,EPhysics_World_Event_Cb func,const void * data)1135 ephysics_world_event_callback_add(EPhysics_World *world, EPhysics_Callback_World_Type type, EPhysics_World_Event_Cb func, const void *data)
1136 {
1137    EPhysics_World_Callback *cb;
1138 
1139    if (!world)
1140      {
1141         ERR("Can't set world event callback, world is null.");
1142         return;
1143      }
1144 
1145    if (!func)
1146      {
1147         ERR("Can't set world event callback, function is null.");
1148         return;
1149      }
1150 
1151    if ((type < 0) || (type >= EPHYSICS_CALLBACK_WORLD_LAST))
1152      {
1153         ERR("Can't set world event callback, callback type is wrong.");
1154         return;
1155      }
1156 
1157    cb = (EPhysics_World_Callback *)calloc(1, sizeof(EPhysics_World_Callback));
1158    if (!cb)
1159      {
1160         ERR("Can't set world event callback, can't create cb instance.");
1161         return;
1162      }
1163 
1164    cb->func = func;
1165    cb->type = type;
1166    cb->data = (void *) data;
1167 
1168    world->callbacks = eina_inlist_append(world->callbacks, EINA_INLIST_GET(cb));
1169 }
1170 
1171 EAPI void *
ephysics_world_event_callback_del(EPhysics_World * world,EPhysics_Callback_World_Type type,EPhysics_World_Event_Cb func)1172 ephysics_world_event_callback_del(EPhysics_World *world, EPhysics_Callback_World_Type type, EPhysics_World_Event_Cb func)
1173 {
1174    EPhysics_World_Callback *cb;
1175    void *cb_data = NULL;
1176 
1177    if (!world)
1178      {
1179         ERR("Can't delete world event callback, world is null.");
1180         return NULL;
1181      }
1182 
1183    EINA_INLIST_FOREACH(world->callbacks, cb)
1184      {
1185         if ((cb->type != type) || (cb->func != func))
1186           continue;
1187 
1188         cb_data = cb->data;
1189         _ephysics_world_event_callback_del(world, cb);
1190         break;
1191      }
1192 
1193    return cb_data;
1194 }
1195 
1196 EAPI void *
ephysics_world_event_callback_del_full(EPhysics_World * world,EPhysics_Callback_World_Type type,EPhysics_World_Event_Cb func,void * data)1197 ephysics_world_event_callback_del_full(EPhysics_World *world, EPhysics_Callback_World_Type type, EPhysics_World_Event_Cb func, void *data)
1198 {
1199    EPhysics_World_Callback *cb;
1200    void *cb_data = NULL;
1201 
1202    if (!world)
1203      {
1204         ERR("Can't delete world event callback, world is null.");
1205         return NULL;
1206      }
1207 
1208    EINA_INLIST_FOREACH(world->callbacks, cb)
1209      {
1210         if ((cb->type != type) || (cb->func != func) || (cb->data != data))
1211           continue;
1212 
1213         cb_data = cb->data;
1214         _ephysics_world_event_callback_del(world, cb);
1215         break;
1216      }
1217 
1218    return cb_data;
1219 }
1220 
1221 EAPI Eina_List *
ephysics_world_bodies_get(const EPhysics_World * world)1222 ephysics_world_bodies_get(const EPhysics_World *world)
1223 {
1224    Eina_List *list = NULL;
1225    EPhysics_Body *body;
1226 
1227    if (!world)
1228      {
1229         ERR("Couldn't get the bodies list, no world provided.");
1230         return NULL;
1231      }
1232 
1233    EINA_INLIST_FOREACH(world->bodies, body)
1234       list = eina_list_append(list, body);
1235 
1236    return list;
1237 }
1238 
1239 EAPI void
ephysics_world_render_geometry_set(EPhysics_World * world,Evas_Coord x,Evas_Coord y,Evas_Coord z,Evas_Coord w,Evas_Coord h,Evas_Coord d)1240 ephysics_world_render_geometry_set(EPhysics_World *world, Evas_Coord x, Evas_Coord y, Evas_Coord z, Evas_Coord w, Evas_Coord h, Evas_Coord d)
1241 {
1242    if (!world)
1243      {
1244         ERR("Can't set geometry, world wasn't provided.");
1245         return;
1246      }
1247 
1248    if ((w <= 0) || (h <= 0) || (d <= 0))
1249      {
1250         ERR("Invalid width or height sizes. They must to be positive values.");
1251         return;
1252      }
1253 
1254    world->geometry.x = x;
1255    world->geometry.y = y;
1256    world->geometry.z = z;
1257    world->geometry.w = w;
1258    world->geometry.h = h;
1259    world->geometry.d = d;
1260 
1261    INF("World %p render geometry set: x=%i y=%i z=%i w=%i h=%i d=%i",
1262        world, x, y, z, w, h, d);
1263 
1264    ephysics_camera_perspective_set(world->camera, x + w / 2, y + h / 2,
1265                                    z + d / 2, 10 * (z + d));
1266 
1267    ephysics_body_world_boundaries_resize(world);
1268    ephysics_camera_position_set(world->camera, x, y);
1269 }
1270 
1271 EAPI void
ephysics_world_render_geometry_get(const EPhysics_World * world,Evas_Coord * x,Evas_Coord * y,Evas_Coord * z,Evas_Coord * w,Evas_Coord * h,Evas_Coord * d)1272 ephysics_world_render_geometry_get(const EPhysics_World *world, Evas_Coord *x, Evas_Coord *y, Evas_Coord *z, Evas_Coord *w, Evas_Coord *h, Evas_Coord *d)
1273 {
1274    if (!world)
1275      {
1276         ERR("Can't get geometry, world is null.");
1277         return;
1278      }
1279 
1280    if (x) *x = world->geometry.x;
1281    if (y) *y = world->geometry.y;
1282    if (z) *z = world->geometry.z;
1283    if (w) *w = world->geometry.w;
1284    if (h) *h = world->geometry.h;
1285    if (d) *d = world->geometry.d;
1286 }
1287 
1288 EAPI void
ephysics_world_linear_slop_set(EPhysics_World * world,double linear_slop)1289 ephysics_world_linear_slop_set(EPhysics_World *world, double linear_slop)
1290 {
1291    if (!world)
1292      {
1293         ERR("Can't set linear slop, world is null.");
1294         return;
1295      }
1296 
1297    eina_lock_take(&world->mutex);
1298    world->dynamics_world->getSolverInfo().m_linearSlop = btScalar(linear_slop);
1299    eina_lock_release(&world->mutex);
1300 }
1301 
1302 EAPI double
ephysics_world_linear_slop_get(const EPhysics_World * world)1303 ephysics_world_linear_slop_get(const EPhysics_World *world)
1304 {
1305    if (!world)
1306      {
1307         ERR("Can't get linear slop, world is null.");
1308         return 0;
1309      }
1310 
1311    return world->dynamics_world->getSolverInfo().m_linearSlop;
1312 }
1313 
1314 EAPI void
ephysics_world_bodies_outside_top_autodel_set(EPhysics_World * world,Eina_Bool autodel)1315 ephysics_world_bodies_outside_top_autodel_set(EPhysics_World *world, Eina_Bool autodel)
1316 {
1317    if (!world)
1318      {
1319         ERR("Can't set autodelete mode, world is null.");
1320         return;
1321      }
1322 
1323    world->outside_top = !!autodel;
1324    world->outside_autodel = world->outside_top || world->outside_bottom ||
1325       world->outside_left || world->outside_right ||
1326       world->outside_front || world->outside_back;
1327 }
1328 
1329 EAPI Eina_Bool
ephysics_world_bodies_outside_top_autodel_get(const EPhysics_World * world)1330 ephysics_world_bodies_outside_top_autodel_get(const EPhysics_World *world)
1331 {
1332    if (!world)
1333      {
1334         ERR("Can't get autodelete mode, world is null.");
1335         return EINA_FALSE;
1336      }
1337 
1338    return world->outside_top;
1339 }
1340 
1341 EAPI void
ephysics_world_bodies_outside_bottom_autodel_set(EPhysics_World * world,Eina_Bool autodel)1342 ephysics_world_bodies_outside_bottom_autodel_set(EPhysics_World *world, Eina_Bool autodel)
1343 {
1344    if (!world)
1345      {
1346         ERR("Can't set autodelete mode, world is null.");
1347         return;
1348      }
1349 
1350    world->outside_bottom = !!autodel;
1351    world->outside_autodel = world->outside_top || world->outside_bottom ||
1352       world->outside_left || world->outside_right ||
1353       world->outside_front || world->outside_back;
1354 }
1355 
1356 EAPI Eina_Bool
ephysics_world_bodies_outside_bottom_autodel_get(const EPhysics_World * world)1357 ephysics_world_bodies_outside_bottom_autodel_get(const EPhysics_World *world)
1358 {
1359    if (!world)
1360      {
1361         ERR("Can't get autodelete mode, world is null.");
1362         return EINA_FALSE;
1363      }
1364 
1365    return world->outside_bottom;
1366 }
1367 
1368 EAPI void
ephysics_world_bodies_outside_left_autodel_set(EPhysics_World * world,Eina_Bool autodel)1369 ephysics_world_bodies_outside_left_autodel_set(EPhysics_World *world, Eina_Bool autodel)
1370 {
1371    if (!world)
1372      {
1373         ERR("Can't set autodelete mode, world is null.");
1374         return;
1375      }
1376 
1377    world->outside_left = !!autodel;
1378    world->outside_autodel = world->outside_top || world->outside_bottom ||
1379       world->outside_left || world->outside_right ||
1380       world->outside_front || world->outside_back;
1381 }
1382 
1383 EAPI Eina_Bool
ephysics_world_bodies_outside_left_autodel_get(const EPhysics_World * world)1384 ephysics_world_bodies_outside_left_autodel_get(const EPhysics_World *world)
1385 {
1386    if (!world)
1387      {
1388         ERR("Can't get autodelete mode, world is null.");
1389         return EINA_FALSE;
1390      }
1391 
1392    return world->outside_left;
1393 }
1394 
1395 EAPI void
ephysics_world_bodies_outside_right_autodel_set(EPhysics_World * world,Eina_Bool autodel)1396 ephysics_world_bodies_outside_right_autodel_set(EPhysics_World *world, Eina_Bool autodel)
1397 {
1398    if (!world)
1399      {
1400         ERR("Can't set autodelete mode, world is null.");
1401         return;
1402      }
1403 
1404    world->outside_right = !!autodel;
1405    world->outside_autodel = world->outside_top || world->outside_bottom ||
1406       world->outside_left || world->outside_right ||
1407       world->outside_front || world->outside_back;
1408 }
1409 
1410 EAPI Eina_Bool
ephysics_world_bodies_outside_right_autodel_get(const EPhysics_World * world)1411 ephysics_world_bodies_outside_right_autodel_get(const EPhysics_World *world)
1412 {
1413    if (!world)
1414      {
1415         ERR("Can't get autodelete mode, world is null.");
1416         return EINA_FALSE;
1417      }
1418 
1419    return world->outside_right;
1420 }
1421 
1422 EAPI void
ephysics_world_bodies_outside_front_autodel_set(EPhysics_World * world,Eina_Bool autodel)1423 ephysics_world_bodies_outside_front_autodel_set(EPhysics_World *world, Eina_Bool autodel)
1424 {
1425    if (!world)
1426      {
1427         ERR("Can't set autodelete mode, world is null.");
1428         return;
1429      }
1430 
1431    world->outside_front = !!autodel;
1432    world->outside_autodel = world->outside_top || world->outside_bottom ||
1433       world->outside_left || world->outside_right ||
1434       world->outside_front || world->outside_back;
1435 }
1436 
1437 EAPI Eina_Bool
ephysics_world_bodies_outside_front_autodel_get(const EPhysics_World * world)1438 ephysics_world_bodies_outside_front_autodel_get(const EPhysics_World *world)
1439 {
1440    if (!world)
1441      {
1442         ERR("Can't get autodelete mode, world is null.");
1443         return EINA_FALSE;
1444      }
1445 
1446    return world->outside_front;
1447 }
1448 
1449 EAPI void
ephysics_world_bodies_outside_back_autodel_set(EPhysics_World * world,Eina_Bool autodel)1450 ephysics_world_bodies_outside_back_autodel_set(EPhysics_World *world, Eina_Bool autodel)
1451 {
1452    if (!world)
1453      {
1454         ERR("Can't set autodelete mode, world is null.");
1455         return;
1456      }
1457 
1458    world->outside_back = !!autodel;
1459    world->outside_autodel = world->outside_top || world->outside_bottom ||
1460       world->outside_left || world->outside_right ||
1461       world->outside_front || world->outside_back;
1462 }
1463 
1464 EAPI Eina_Bool
ephysics_world_bodies_outside_back_autodel_get(const EPhysics_World * world)1465 ephysics_world_bodies_outside_back_autodel_get(const EPhysics_World *world)
1466 {
1467    if (!world)
1468      {
1469         ERR("Can't get autodelete mode, world is null.");
1470         return EINA_FALSE;
1471      }
1472 
1473    return world->outside_back;
1474 }
1475 
1476 EAPI Eina_Bool
ephysics_world_bodies_outside_autodel_get(const EPhysics_World * world)1477 ephysics_world_bodies_outside_autodel_get(const EPhysics_World *world)
1478 {
1479    if (!world)
1480      {
1481         ERR("Can't get autodelete mode, world is null.");
1482         return EINA_FALSE;
1483      }
1484 
1485    return world->outside_autodel;
1486 }
1487 
1488 EAPI void
ephysics_world_simulation_set(EPhysics_World * world,double fixed_time_step,int max_sub_steps)1489 ephysics_world_simulation_set(EPhysics_World *world, double fixed_time_step, int max_sub_steps)
1490 {
1491    if (!world)
1492      {
1493         ERR("Can't set simulation, no world provided.");
1494         return;
1495      }
1496 
1497    if (max_sub_steps < 1)
1498      {
1499         ERR("At least one sub step for simulation is required.");
1500         return;
1501      }
1502 
1503    if (ecore_animator_frametime_get() >= max_sub_steps * fixed_time_step)
1504      {
1505         ERR("Assure frametime < max sub steps * fixed time step.");
1506         return;
1507      }
1508 
1509    eina_lock_take(&world->mutex);
1510    world->max_sub_steps = max_sub_steps;
1511    world->fixed_time_step = fixed_time_step;
1512 
1513    DBG("World %p simulation set to fixed time step: %lf, max substeps:%i.",
1514        world, fixed_time_step, max_sub_steps);
1515    eina_lock_release(&world->mutex);
1516 }
1517 
1518 EAPI void
ephysics_world_simulation_get(const EPhysics_World * world,double * fixed_time_step,int * max_sub_steps)1519 ephysics_world_simulation_get(const EPhysics_World *world, double *fixed_time_step, int *max_sub_steps)
1520 {
1521    if (!world)
1522      {
1523 	ERR("No world, can't get simulation configuration.");
1524 	return;
1525      }
1526 
1527    if (fixed_time_step) *fixed_time_step = world->fixed_time_step;
1528    if (max_sub_steps) *max_sub_steps = world->max_sub_steps;
1529 }
1530 
1531 void
ephysics_world_lock_take(EPhysics_World * world)1532 ephysics_world_lock_take(EPhysics_World *world)
1533 {
1534    eina_lock_take(&world->mutex);
1535 }
1536 
1537 void
ephysics_world_lock_release(EPhysics_World * world)1538 ephysics_world_lock_release(EPhysics_World *world)
1539 {
1540    eina_lock_release(&world->mutex);
1541 }
1542 
1543 EAPI void
ephysics_world_point_light_position_set(EPhysics_World * world,Evas_Coord lx,Evas_Coord ly,Evas_Coord lz)1544 ephysics_world_point_light_position_set(EPhysics_World *world, Evas_Coord lx, Evas_Coord ly, Evas_Coord lz)
1545 {
1546    if (!world)
1547      {
1548 	ERR("No world, can't set light properties.");
1549 	return;
1550      }
1551 
1552    world->light.lx = lx;
1553    world->light.ly = ly;
1554    world->light.lz = lz;
1555    world->force_update = EINA_TRUE;
1556 }
1557 
1558 EAPI void
ephysics_world_point_light_color_set(EPhysics_World * world,int lr,int lg,int lb)1559 ephysics_world_point_light_color_set(EPhysics_World *world, int lr, int lg, int lb)
1560 {
1561    if (!world)
1562      {
1563 	ERR("No world, can't set light properties.");
1564 	return;
1565      }
1566 
1567    world->light.lr = lr;
1568    world->light.lg = lg;
1569    world->light.lb = lb;
1570    world->force_update = EINA_TRUE;
1571 }
1572 
1573 EAPI void
ephysics_world_ambient_light_color_set(EPhysics_World * world,int ar,int ag,int ab)1574 ephysics_world_ambient_light_color_set(EPhysics_World *world, int ar, int ag, int ab)
1575 {
1576    if (!world)
1577      {
1578 	ERR("No world, can't set light properties.");
1579 	return;
1580      }
1581 
1582    world->light.ar = ar;
1583    world->light.ag = ag;
1584    world->light.ab = ab;
1585    world->force_update = EINA_TRUE;
1586 }
1587 
1588 EAPI void
ephysics_world_ambient_light_color_get(const EPhysics_World * world,int * ar,int * ag,int * ab)1589 ephysics_world_ambient_light_color_get(const EPhysics_World *world, int *ar, int *ag, int *ab)
1590 {
1591    if (!world)
1592      {
1593 	ERR("No world, can't get light properties.");
1594 	return;
1595      }
1596 
1597    if (ar) *ar = world->light.ar;
1598    if (ag) *ag = world->light.ag;
1599    if (ab) *ab = world->light.ab;
1600 }
1601 
1602 EAPI void
ephysics_world_point_light_color_get(const EPhysics_World * world,int * lr,int * lg,int * lb)1603 ephysics_world_point_light_color_get(const EPhysics_World *world, int *lr, int *lg, int *lb)
1604 {
1605    if (!world)
1606      {
1607 	ERR("No world, can't get light properties.");
1608 	return;
1609      }
1610 
1611    if (lr) *lr = world->light.lr;
1612    if (lg) *lg = world->light.lg;
1613    if (lb) *lb = world->light.lb;
1614 }
1615 
1616 EAPI void
ephysics_world_point_light_position_get(const EPhysics_World * world,Evas_Coord * lx,Evas_Coord * ly,Evas_Coord * lz)1617 ephysics_world_point_light_position_get(const EPhysics_World *world, Evas_Coord *lx, Evas_Coord *ly, Evas_Coord *lz)
1618 {
1619    if (!world)
1620      {
1621 	ERR("No world, can't get light properties.");
1622 	return;
1623      }
1624 
1625    if (lx) *lx = world->light.lx;
1626    if (ly) *ly = world->light.ly;
1627    if (lz) *lz = world->light.lz;
1628 }
1629 
1630 EAPI void
ephysics_world_light_all_bodies_set(EPhysics_World * world,Eina_Bool enable)1631 ephysics_world_light_all_bodies_set(EPhysics_World *world, Eina_Bool enable)
1632 {
1633    if (!world)
1634      {
1635 	ERR("No world, can't set light property.");
1636 	return;
1637      }
1638 
1639    world->light.all_bodies = !!enable;
1640    world->force_update = EINA_TRUE;
1641 }
1642 
1643 EAPI Eina_Bool
ephysics_world_light_all_bodies_get(const EPhysics_World * world)1644 ephysics_world_light_all_bodies_get(const EPhysics_World *world)
1645 {
1646    if (!world)
1647      {
1648 	ERR("No world, can't get light property.");
1649 	return EINA_FALSE;
1650      }
1651 
1652    return world->light.all_bodies;
1653 }
1654 
1655 EAPI void
ephysics_world_stack_enable_set(EPhysics_World * world,Eina_Bool enabled)1656 ephysics_world_stack_enable_set(EPhysics_World *world, Eina_Bool enabled)
1657 {
1658    if (!world)
1659      {
1660         ERR("Can't enable / disable stacking, world wasn't provided.");
1661         return;
1662      }
1663    world->stacking = !!enabled;
1664 }
1665 
1666 EAPI Eina_Bool
ephysics_world_stack_enable_get(const EPhysics_World * world)1667 ephysics_world_stack_enable_get(const EPhysics_World *world)
1668 {
1669    if (!world)
1670      {
1671 	ERR("No world, no stacking status for you.");
1672 	return EINA_FALSE;
1673      }
1674 
1675    return world->stacking;
1676 }
1677 
1678 #ifdef  __cplusplus
1679 }
1680 #endif
1681