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