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