1 #ifdef HAVE_CONFIG_H
2 # include <config.h>
3 #endif
4 
5 #include <Evas.h>
6 #include <Ecore.h>
7 
8 #pragma GCC diagnostic push
9 #pragma GCC diagnostic ignored "-Wshadow"
10 
11 #include <BulletCollision/CollisionShapes/btShapeHull.h>
12 #include <LinearMath/btGeometryUtil.h>
13 
14 #pragma GCC diagnostic pop
15 
16 #include <math.h>
17 
18 #include "ephysics_trimesh.h"
19 #include "ephysics_private.h"
20 #include "ephysics_body_materials.h"
21 
22 #ifdef  __cplusplus
23 extern "C" {
24 #endif
25 
26 #define BODY_CLOTH_CHECK() \
27    do { \
28      if (body->type == EPHYSICS_BODY_TYPE_CLOTH) \
29        { \
30           WRN("Not supported for cloth"); \
31           return; \
32        } \
33    } while(0)
34 
35 typedef struct _EPhysics_Body_Callback EPhysics_Body_Callback;
36 typedef struct _EPhysics_Body_Evas_Stacking EPhysics_Body_Evas_Stacking;
37 typedef struct _EPhysics_Body_Soft_Body_Slice EPhysics_Body_Soft_Body_Slice;
38 typedef struct _EPhysics_Body_Face_Obj EPhysics_Body_Face_Obj;
39 typedef struct _EPhysics_Quaternion EPhysics_Quaternion;
40 
41 struct _EPhysics_Body_Callback {
42      EINA_INLIST;
43      void (*func) (void *data, EPhysics_Body *body, void *event_info);
44      void *data;
45      EPhysics_Callback_Body_Type type;
46      Eina_Bool deleted:1;
47 };
48 
49 struct _EPhysics_Body_Collision {
50      EPhysics_Body *contact_body;
51      Evas_Coord x;
52      Evas_Coord y;
53      Evas_Coord z;
54 };
55 
56 struct _EPhysics_Body_Evas_Stacking {
57      Evas_Object *evas;
58      float stacking;
59 };
60 
61 struct _EPhysics_Body_Soft_Body_Slice
62 {
63      Evas_Object *evas_obj;
64      int index;
65      struct {
66           double x;
67           double y;
68      } p[3];
69      float stacking;
70 };
71 
72 struct _EPhysics_Body_Face_Obj {
73     EPhysics_Body_Face face;
74     Evas_Object *obj;
75 };
76 
77 static void
_ephysics_body_cloth_anchor_mass_reset(EPhysics_Body * body)78 _ephysics_body_cloth_anchor_mass_reset(EPhysics_Body *body)
79 {
80    double anchor_mass;
81    anchor_mass = 1 / (body->soft_body->m_nodes.size() * 0.025);
82 
83    for (int i = 0; i < body->soft_body->m_anchors.size(); i++)
84      body->soft_body->m_anchors[i].m_node->m_im = anchor_mass;
85 
86    DBG("Cloth anchors mass reset.");
87 }
88 
89 EAPI void
_ephysics_body_soft_body_light_apply(Evas_Map * m,Evas_Coord lx,Evas_Coord ly,Evas_Coord lz,int lr,int lg,int lb,int ar,int ag,int ab,Evas_Coord bx,Evas_Coord by,Evas_Coord bz)90 _ephysics_body_soft_body_light_apply(Evas_Map *m, Evas_Coord lx, Evas_Coord ly, Evas_Coord lz, int lr, int lg, int lb, int ar, int ag, int ab, Evas_Coord bx, Evas_Coord by, Evas_Coord bz)
91 {
92    double x, y, z, nx, ny, nz, ln, br;
93    Evas_Coord mx, my, mz, mr, mg, mb, ma;
94    int i;
95 
96    for (i = 0; i < 4; i++)
97      {
98 
99         evas_map_point_coord_get(m, i, &mx, &my, &mz);
100         evas_map_point_color_get(m, i, NULL, NULL, NULL, &ma);
101 
102         x = mx;
103         y = my;
104         z = mz;
105 
106         nx = sqrt(pow(bx - x, 2));
107         ny = sqrt(pow(by - y, 2));
108         nz = sqrt(pow(bz - z, 2));
109         ln = nx + ny + nz;
110 
111         if (ln != 0.0)
112           {
113              nx /= ln;
114              ny /= ln;
115              nz /= ln;
116           }
117 
118         x = lx - bx;
119         y = ly - by;
120         z = lz - bz;
121 
122         ln = pow(x, 2) + pow(y, 2) + pow(z, 2);
123         ln = sqrt(ln);
124 
125         if (ln != 0.0)
126           {
127              x /= ln;
128              y /= ln;
129              z /= ln;
130           }
131 
132         br = (nx * x) + (ny * y) + (nz * z);
133         if (br < 0.0) br = 0.0;
134 
135         mr = ar + ((lr - ar) * br);
136         mg = ag + ((lg - ag) * br);
137         mb = ab + ((lb - ab) * br);
138 
139         evas_map_point_color_set(m, i, mr, mg, mb, ma);
140      }
141 }
142 
143 static void
_ephysics_body_soft_body_slices_apply(EPhysics_Body * body,Evas_Object * evas_obj,Eina_List * slices)144 _ephysics_body_soft_body_slices_apply(EPhysics_Body *body, Evas_Object *evas_obj, Eina_List *slices)
145 {
146    double rate;
147    void *list_data;
148    Eina_List *l;
149    Evas_Coord wy, wh, y0, y1, y2, x0, x1, x2, z0, z1, z2, w, h, bx, by, bz;
150    Evas_Map *map;
151    btVector3 p0, p1, p2;
152    btSoftBody::tFaceArray faces;
153    EPhysics_Body_Soft_Body_Slice *slice;
154    int lr, lg, lb, ar, ag, ab;
155    Evas_Coord lx, ly, lz;
156    Eina_Bool light = EINA_FALSE;
157    EPhysics_Camera *camera;
158 
159    int px, py, pz, foc;
160    Eina_Bool perspective = EINA_FALSE;
161 
162    camera = ephysics_world_camera_get(body->world);
163    rate = ephysics_world_rate_get(body->world);
164    ephysics_world_render_geometry_get(body->world, NULL, &wy, NULL, NULL, &wh,
165                                       NULL);
166    evas_object_geometry_get(evas_obj, NULL, NULL, &w, &h);
167 
168    ephysics_body_geometry_get(body, &bx, &by, &bz, NULL, NULL, NULL);
169 
170    if ((body->light_apply) ||
171        (ephysics_world_light_all_bodies_get(body->world)))
172      {
173         ephysics_world_point_light_position_get(body->world, &lx, &ly, &lz);
174         ephysics_world_point_light_color_get(body->world, &lr, &lg, &lb);
175         ephysics_world_ambient_light_color_get(body->world, &ar, &ag, &ab);
176         light = EINA_TRUE;
177      }
178 
179    if (ephysics_camera_perspective_enabled_get(camera))
180      {
181         ephysics_camera_perspective_get(camera, &px, &py, &pz, &foc);
182         perspective = EINA_TRUE;
183      }
184 
185    EINA_LIST_FOREACH(slices, l, list_data)
186      {
187         slice = (EPhysics_Body_Soft_Body_Slice *)list_data;
188 
189         faces = body->soft_body->m_faces;
190         p0 = faces[slice->index].m_n[0]->m_x;
191         p1 = faces[slice->index].m_n[1]->m_x;
192         p2 = faces[slice->index].m_n[2]->m_x;
193 
194         slice->stacking = p0.z() + p1.z() + p2.z();
195 
196         map = evas_map_new(4);
197 
198         evas_map_point_image_uv_set(map, 0, slice->p[0].x * w,
199                                     slice->p[0].y * h);
200         evas_map_point_image_uv_set(map, 1, slice->p[1].x * w,
201                                     slice->p[1].y * h);
202         evas_map_point_image_uv_set(map, 2, slice->p[2].x * w,
203                                     slice->p[2].y * h);
204         evas_map_point_image_uv_set(map, 3, slice->p[2].x * w,
205                                     slice->p[2].y * h);
206 
207         x0 = p0.x() * rate;
208         x1 = p1.x() * rate;
209         x2 = p2.x() * rate;
210 
211         y0 = wh + wy - (p0.y() * rate);
212         y1 = wh + wy - (p1.y() * rate);
213         y2 = wh + wy - (p2.y() * rate);
214 
215         z0 = p0.z() * rate;
216         z1 = p1.z() * rate;
217         z2 = p2.z() * rate;
218 
219         evas_map_point_coord_set(map, 0, x0, y0, z0);
220         evas_map_point_coord_set(map, 1, x1, y1, z1);
221         evas_map_point_coord_set(map, 2, x2, y2, z2);
222         evas_map_point_coord_set(map, 3, x2, y2, z2);
223 
224         if (perspective)
225           evas_map_util_3d_perspective(map, px, py, pz, foc);
226 
227         if (body->back_face_culling)
228           {
229              if (evas_map_util_clockwise_get(map))
230                   evas_object_show(slice->evas_obj);
231              else
232                {
233                   evas_map_free(map);
234                   evas_object_hide(slice->evas_obj);
235                   continue;
236                }
237           }
238 
239         if (light)
240           _ephysics_body_soft_body_light_apply(map, lx, ly, lz, lr, lg, lb, ar,
241                                                ag, ab, bx, by, bz);
242 
243         evas_object_map_set(slice->evas_obj, map);
244         evas_object_map_enable_set(slice->evas_obj, EINA_TRUE);
245         evas_map_free(map);
246      }
247 }
248 
249 static inline double
_ephysics_body_soft_body_slice_calc(double val,double delta,double max)250 _ephysics_body_soft_body_slice_calc(double val, double delta, double max)
251 {
252    double ret = val + delta / max;
253    if (ret < 0)
254      ret = 0;
255    else if (ret > 1)
256      ret = 1;
257    return ret;
258 }
259 
260 static EPhysics_Body_Soft_Body_Slice *
_ephysics_body_soft_body_slice_new(EPhysics_Body * body,double delta,double max,int index)261 _ephysics_body_soft_body_slice_new(EPhysics_Body *body, double delta, double max, int index)
262 {
263    EPhysics_Body_Soft_Body_Slice *slice;
264    btSoftBody::tFaceArray faces;
265 
266    slice = (EPhysics_Body_Soft_Body_Slice *)calloc(
267       1, sizeof(EPhysics_Body_Soft_Body_Slice));
268    if (!slice)
269      {
270         ERR("Couldn't allocate EPhysics_Soft_Body_Slice memory.");
271         return NULL;
272      }
273 
274    faces = body->soft_body->m_faces;
275 
276    slice->index = index;
277    if (!faces.size()) return slice;
278    slice->p[0].x = _ephysics_body_soft_body_slice_calc(
279       faces[slice->index].m_n[0]->m_x.x(), delta, max);
280    slice->p[0].y = 1 - _ephysics_body_soft_body_slice_calc(
281       faces[slice->index].m_n[0]->m_x.y(), delta, max);
282    slice->p[1].x = _ephysics_body_soft_body_slice_calc(
283       faces[slice->index].m_n[1]->m_x.x(), delta, max);
284    slice->p[1].y = 1 - _ephysics_body_soft_body_slice_calc(
285       faces[slice->index].m_n[1]->m_x.y(), delta, max);
286    slice->p[2].x = _ephysics_body_soft_body_slice_calc(
287       faces[slice->index].m_n[2]->m_x.x(), delta, max);
288    slice->p[2].y = 1 - _ephysics_body_soft_body_slice_calc(
289       faces[slice->index].m_n[2]->m_x.y(), delta, max);
290 
291    return slice;
292 }
293 
294 static Eina_List *
_ephysics_body_soft_body_slices_get(EPhysics_Body * body)295 _ephysics_body_soft_body_slices_get(EPhysics_Body *body)
296 {
297    Eina_List *l, *slices_list, *slices = NULL;
298    void *ldata, *slice_data;
299    EPhysics_Body_Face_Slice *face_slice;
300 
301    EINA_LIST_FOREACH(body->faces_slices, l, ldata)
302      {
303         face_slice = (EPhysics_Body_Face_Slice *)ldata;
304         EINA_LIST_FOREACH(face_slice->slices, slices_list, slice_data)
305              slices = eina_list_append(slices, slice_data);
306      }
307 
308    return slices;
309 }
310 
311 EAPI int
ephysics_body_soft_body_slice_index_get(EPhysics_Body * body,Evas_Object * slice)312 ephysics_body_soft_body_slice_index_get(EPhysics_Body *body, Evas_Object *slice)
313 {
314    Eina_List *slices;
315    void *ldata;
316    EPhysics_Body_Soft_Body_Slice *slice_data;
317 
318    if (!body)
319      {
320         ERR("Can't get soft body slice index, body is null.");
321         return -1;
322      }
323 
324    if (body->type == EPHYSICS_BODY_TYPE_RIGID)
325      {
326         ERR("Can't get soft body slice index, operation not allowed for rigid"
327             " bodies.");
328         return -1;
329      }
330 
331    slices = _ephysics_body_soft_body_slices_get(body);
332    EINA_LIST_FREE(slices, ldata)
333      {
334         slice_data = (EPhysics_Body_Soft_Body_Slice *)ldata;
335         if (slice_data->evas_obj == slice)
336           return slice_data->index;
337      }
338 
339    return -1;
340 }
341 
342 static void
_ephysics_body_soft_body_slice_del_cb(void * data,Evas * evas EINA_UNUSED,Evas_Object * obj,void * event_info EINA_UNUSED)343 _ephysics_body_soft_body_slice_del_cb(void *data, Evas *evas EINA_UNUSED, Evas_Object *obj, void *event_info EINA_UNUSED)
344 {
345    EPhysics_Body_Soft_Body_Slice *slice = (EPhysics_Body_Soft_Body_Slice *)data;
346    slice->evas_obj = NULL;
347    evas_object_event_callback_del(obj, EVAS_CALLBACK_DEL,
348                                   _ephysics_body_soft_body_slice_del_cb);
349 }
350 
351 static void
_ephysics_body_soft_body_slices_init(EPhysics_Body * body,Evas_Object * obj,Eina_List * slices)352 _ephysics_body_soft_body_slices_init(EPhysics_Body *body, Evas_Object *obj, Eina_List *slices)
353 {
354    EPhysics_Body_Soft_Body_Slice *slice = NULL;
355    btVector3 p0, p1, p2;
356    void *slice_data;
357    Evas_Coord w, h;
358    Eina_List *l;
359    Evas *evas;
360    Evas_Object *parent;
361 
362    evas = evas_object_evas_get(obj);
363    evas_object_geometry_get(obj, NULL, NULL, &w, &h);
364 
365    parent = evas_object_smart_parent_get(obj);
366    EINA_LIST_FOREACH(slices, l, slice_data)
367      {
368         slice = (EPhysics_Body_Soft_Body_Slice *) slice_data;
369         slice->evas_obj = evas_object_image_filled_add(evas);
370         evas_object_layer_set(slice->evas_obj,
371                               evas_object_layer_get(obj));
372         evas_object_image_source_set(slice->evas_obj, obj);
373         evas_object_image_source_events_set(slice->evas_obj, EINA_TRUE);
374         evas_object_resize(slice->evas_obj, w, h);
375         evas_object_show(slice->evas_obj);
376         evas_object_image_smooth_scale_set(slice->evas_obj, EINA_TRUE);
377         evas_object_event_callback_add(slice->evas_obj, EVAS_CALLBACK_DEL,
378                                        _ephysics_body_soft_body_slice_del_cb,
379                                        slice);
380 
381         if (parent) evas_object_smart_member_add(slice->evas_obj, parent);
382      }
383 
384    if (slice)
385      evas_object_image_source_visible_set(slice->evas_obj, EINA_FALSE);
386 
387    _ephysics_body_soft_body_slices_apply(body, obj, slices);
388 }
389 
390 static void
_ephysics_body_soft_body_slices_free(Eina_List * slices)391 _ephysics_body_soft_body_slices_free(Eina_List *slices)
392 {
393    EPhysics_Body_Soft_Body_Slice *slice;
394    void *slice_data;
395 
396    EINA_LIST_FREE(slices, slice_data)
397      {
398         slice = (EPhysics_Body_Soft_Body_Slice *)slice_data;
399         if (slice->evas_obj)
400           evas_object_del(slice->evas_obj);
401         free(slice);
402      }
403 }
404 
405 static void
_ephysics_body_soft_body_slices_clean(Eina_List * slices)406 _ephysics_body_soft_body_slices_clean(Eina_List *slices)
407 {
408    EPhysics_Body_Soft_Body_Slice *slice;
409    void *slice_data;
410    Eina_List *l;
411 
412    EINA_LIST_FOREACH(slices, l, slice_data)
413      {
414         slice = (EPhysics_Body_Soft_Body_Slice *)slice_data;
415         if (slice->evas_obj)
416           evas_object_del(slice->evas_obj);
417      }
418 }
419 
420 static btTransform
_ephysics_body_transform_get(const EPhysics_Body * body)421 _ephysics_body_transform_get(const EPhysics_Body *body)
422 {
423    btTransform trans;
424    btVector3 center;
425    btScalar radius;
426 
427    if (body->type == EPHYSICS_BODY_TYPE_RIGID)
428      {
429         body->rigid_body->getMotionState()->getWorldTransform(trans);
430         return trans;
431      }
432 
433    body->soft_body->getCollisionShape()->getBoundingSphere(center, radius);
434    trans.setIdentity();
435    trans.setOrigin(center);
436    return trans;
437 }
438 
439 static int
_ephysics_body_evas_stacking_sort_cb(const void * d1,const void * d2)440 _ephysics_body_evas_stacking_sort_cb(const void *d1, const void *d2)
441 {
442    const EPhysics_Body_Evas_Stacking *stacking1, *stacking2;
443 
444    stacking1 = (const EPhysics_Body_Evas_Stacking *)d1;
445    stacking2 = (const EPhysics_Body_Evas_Stacking *)d2;
446 
447    if (!stacking1) return 1;
448    if (!stacking2) return -1;
449 
450    if (stacking1->stacking < stacking2->stacking) return -1;
451    if (stacking1->stacking > stacking2->stacking) return 1;
452 
453    return 0;
454 }
455 
456 static EPhysics_Body_Evas_Stacking *
_ephysics_body_evas_stacking_new(Evas_Object * obj,float index)457 _ephysics_body_evas_stacking_new(Evas_Object *obj, float index)
458 {
459    EPhysics_Body_Evas_Stacking *stacking;
460 
461    stacking = (EPhysics_Body_Evas_Stacking *)calloc(
462                 1, sizeof(EPhysics_Body_Evas_Stacking));
463 
464    if (!stacking)
465      {
466         ERR("Could not allocate ephysics soft body evas stacking data.");
467         return NULL;
468      }
469 
470    stacking->evas = obj;
471    stacking->stacking = index;
472    return stacking;
473 }
474 
475 void
ephysics_body_evas_objects_restack(EPhysics_World * world)476 ephysics_body_evas_objects_restack(EPhysics_World *world)
477 {
478    void *data, *slice_data, *stack_data;
479    EPhysics_Body *body;
480    btTransform trans;
481    EPhysics_Body_Evas_Stacking *stacking;
482    EPhysics_Body_Soft_Body_Slice *slice;
483    Eina_List *l, *slices, *bodies, *stack_list = NULL;
484    Evas_Object *prev_obj = NULL;
485    Eina_Hash *hash;
486    Eina_Iterator *it;
487    int layer;
488    Eina_List *ll = NULL;
489 
490    bodies = ephysics_world_bodies_get(world);
491 
492    if (!eina_list_count(bodies))
493      return;
494 
495    hash = eina_hash_int32_new(NULL);
496 
497    EINA_LIST_FREE(bodies, data)
498      {
499         body = (EPhysics_Body *)data;
500         if (body->deleted) continue;
501 
502         if (body->type == EPHYSICS_BODY_TYPE_RIGID)
503           {
504              if (!body->evas_obj) continue;
505              trans = _ephysics_body_transform_get(body);
506              stacking = _ephysics_body_evas_stacking_new(body->evas_obj,
507                                                          trans.getOrigin().z());
508              if (!stacking) goto error;
509 
510              layer = evas_object_layer_get(stacking->evas);
511              stack_list = (Eina_List *)eina_hash_find(hash, &layer);
512              stack_list = eina_list_append(stack_list, stacking);
513              eina_hash_set(hash, &layer, stack_list);
514 
515              continue;
516           }
517 
518         slices = _ephysics_body_soft_body_slices_get(body);
519         if (!slices) continue;
520 
521         EINA_LIST_FREE(slices, slice_data)
522           {
523              slice = (EPhysics_Body_Soft_Body_Slice *)slice_data;
524 
525              stacking = _ephysics_body_evas_stacking_new(slice->evas_obj,
526                                                          slice->stacking);
527              if (!stacking) goto error;
528 
529              layer = evas_object_layer_get(stacking->evas);
530              stack_list = (Eina_List *)eina_hash_find(hash, &layer);
531              stack_list = eina_list_append(stack_list, stacking);
532              eina_hash_set(hash, &layer, stack_list);
533           }
534      }
535 
536 
537    it = eina_hash_iterator_data_new(hash);
538    while (eina_iterator_next(it, &data))
539      {
540         stack_list = (Eina_List *)data;
541         stack_list = eina_list_sort(stack_list, eina_list_count(stack_list),
542                                     _ephysics_body_evas_stacking_sort_cb);
543         prev_obj = NULL;
544 
545         ll = eina_list_append(ll, stack_list);
546 
547         EINA_LIST_FOREACH(stack_list, l, stack_data)
548           {
549              stacking = (EPhysics_Body_Evas_Stacking *)stack_data;
550 
551              if (prev_obj)
552                evas_object_stack_below(stacking->evas, prev_obj);
553 
554              prev_obj = stacking->evas;
555           }
556      }
557 
558    eina_iterator_free(it);
559 
560    EINA_LIST_FREE(ll, stack_data)
561      {
562         stack_list = (Eina_List *) stack_data;
563         eina_hash_del_by_data(hash, stack_list);
564         EINA_LIST_FREE(stack_list, slice_data)
565           free(slice_data);
566      }
567 
568    eina_hash_free(hash);
569    return;
570 
571  error:
572    ERR("Could not allocate evas stacking data memory.");
573    eina_hash_free(hash);
574 }
575 
576 static void
_ephysics_body_transform_set(EPhysics_Body * body,btTransform trans)577 _ephysics_body_transform_set(EPhysics_Body *body, btTransform trans)
578 {
579    btTransform origin;
580 
581    if (body->type != EPHYSICS_BODY_TYPE_RIGID)
582      {
583         origin = _ephysics_body_transform_get(body);
584         body->soft_body->translate(trans.getOrigin() - origin.getOrigin());
585         return;
586      }
587    body->rigid_body->getMotionState()->setWorldTransform(trans);
588 }
589 
590 void
ephysics_body_activate(const EPhysics_Body * body,Eina_Bool activate)591 ephysics_body_activate(const EPhysics_Body *body, Eina_Bool activate)
592 {
593    if (body->type == EPHYSICS_BODY_TYPE_RIGID)
594      {
595         body->rigid_body->activate(activate);
596         return;
597      }
598 
599    body->soft_body->activate(activate);
600 }
601 
602 static void
_ephysics_body_forces_update(EPhysics_Body * body)603 _ephysics_body_forces_update(EPhysics_Body *body)
604 {
605    body->force.x = body->rigid_body->getTotalForce().getX();
606    body->force.y = body->rigid_body->getTotalForce().getY();
607    body->force.z = body->rigid_body->getTotalForce().getZ();
608    body->force.torque_x = body->rigid_body->getTotalTorque().getX();
609    body->force.torque_y = body->rigid_body->getTotalTorque().getY();
610    body->force.torque_z = body->rigid_body->getTotalTorque().getZ();
611    body->rigid_body->clearForces();
612 
613    DBG("forces updated: %lf, %lf, %lf", body->force.x, body->force.y,
614        body->force.z);
615    DBG("torque updated: %lf, %lf, %lf", body->force.torque_x,
616        body->force.torque_y, body->force.torque_z);
617 }
618 
619 static inline void
_ephysics_body_sleeping_threshold_set(EPhysics_Body * body,double linear_threshold,double angular_threshold,double rate)620 _ephysics_body_sleeping_threshold_set(EPhysics_Body *body, double linear_threshold, double angular_threshold, double rate)
621 {
622    body->rigid_body->setSleepingThresholds(linear_threshold / rate,
623                                            angular_threshold / RAD_TO_DEG);
624 }
625 
626 static inline void
_ephysics_body_linear_velocity_set(EPhysics_Body * body,double x,double y,double z,double rate)627 _ephysics_body_linear_velocity_set(EPhysics_Body *body, double x, double y, double z, double rate)
628 {
629    btVector3 linear_velocity = btVector3(x / rate, -y / rate, z / rate);
630 
631    ephysics_body_activate(body, EINA_TRUE);
632    if (body->rigid_body)
633      body->rigid_body->setLinearVelocity(linear_velocity);
634 
635    if (body->soft_body)
636      {
637         for (int i = 0; i < body->soft_body->m_nodes.size(); i++)
638           body->soft_body->m_nodes[i].m_v = linear_velocity;
639      }
640 }
641 
642 static void
_ephysics_body_event_callback_del(EPhysics_Body * body,EPhysics_Body_Callback * cb)643 _ephysics_body_event_callback_del(EPhysics_Body *body, EPhysics_Body_Callback *cb)
644 {
645    if (cb->deleted) return;
646 
647    cb->deleted = EINA_TRUE;
648 
649    if (body->walking)
650      {
651         body->to_delete = eina_list_append(body->to_delete, cb);
652         return;
653      }
654 
655    body->callbacks = eina_inlist_remove(body->callbacks, EINA_INLIST_GET(cb));
656    free(cb);
657 }
658 
659 static Eina_Bool
_ephysics_body_event_callback_call(EPhysics_Body * body,EPhysics_Callback_Body_Type type,void * event_info)660 _ephysics_body_event_callback_call(EPhysics_Body *body, EPhysics_Callback_Body_Type type, void *event_info)
661 {
662    Eina_Bool called = EINA_FALSE;
663    EPhysics_Body_Callback *cb;
664    void *clb;
665 
666    body->walking++;
667    EINA_INLIST_FOREACH(body->callbacks, cb)
668      {
669         if ((cb->type == type) && (!cb->deleted))
670           {
671              cb->func(cb->data, body, event_info);
672              called = EINA_TRUE;
673           }
674      }
675    body->walking--;
676 
677    if (body->walking > 0) return called;
678 
679    EINA_LIST_FREE(body->to_delete, clb)
680      {
681         cb = (EPhysics_Body_Callback *) clb;
682         body->callbacks = eina_inlist_remove(body->callbacks,
683                                              EINA_INLIST_GET(cb));
684         free(cb);
685      }
686 
687    return called;
688 }
689 
690 void
ephysics_body_active_set(EPhysics_Body * body,Eina_Bool active)691 ephysics_body_active_set(EPhysics_Body *body, Eina_Bool active)
692 {
693    if (body->active == !!active) return;
694    body->active = !!active;
695    if (active) return;
696 
697    _ephysics_body_event_callback_call(body, EPHYSICS_CALLBACK_BODY_STOPPED,
698                                       (void *) body->evas_obj);
699 };
700 
701 Eina_Bool
ephysics_body_filter_collision(EPhysics_Body * body0,EPhysics_Body * body1)702 ephysics_body_filter_collision(EPhysics_Body *body0, EPhysics_Body *body1)
703 {
704    Eina_List *l;
705    void *grp;
706 
707    if ((!body0->collision_groups) || (!body1->collision_groups))
708      return EINA_TRUE;
709 
710    EINA_LIST_FOREACH(body0->collision_groups, l, grp)
711      {
712         if (eina_list_data_find(body1->collision_groups, grp))
713           return EINA_TRUE;
714      }
715 
716    return EINA_FALSE;
717 }
718 
719 EAPI Eina_Bool
ephysics_body_collision_group_add(EPhysics_Body * body,const char * group)720 ephysics_body_collision_group_add(EPhysics_Body *body, const char *group)
721 {
722    Eina_Stringshare *group_str;
723 
724    if (!body)
725      {
726         ERR("Can't add body collision group, body is null.");
727         return EINA_FALSE;
728      }
729 
730    ephysics_world_lock_take(body->world);
731    group_str = eina_stringshare_add(group);
732    if (eina_list_data_find(body->collision_groups, group_str))
733      {
734         INF("Body already added to group: %s", group);
735         eina_stringshare_del(group_str);
736         ephysics_world_lock_release(body->world);
737         return EINA_TRUE;
738      }
739 
740    body->collision_groups = eina_list_append(body->collision_groups, group_str);
741    ephysics_world_lock_release(body->world);
742    return EINA_TRUE;
743 }
744 
745 EAPI Eina_Bool
ephysics_body_collision_group_del(EPhysics_Body * body,const char * group)746 ephysics_body_collision_group_del(EPhysics_Body *body, const char *group)
747 {
748    Eina_Stringshare *group_str;
749 
750    if (!body)
751      {
752         ERR("Can't remove body collision group, body is null.");
753         return EINA_FALSE;
754      }
755 
756    ephysics_world_lock_take(body->world);
757    group_str = eina_stringshare_add(group);
758    if (!eina_list_data_find(body->collision_groups, group_str))
759      {
760         INF("Body isn't part of group: %s", group);
761         eina_stringshare_del(group_str);
762         ephysics_world_lock_release(body->world);
763         return EINA_TRUE;
764      }
765 
766    body->collision_groups = eina_list_remove(body->collision_groups, group_str);
767    eina_stringshare_del(group_str);
768    ephysics_world_lock_release(body->world);
769    return EINA_TRUE;
770 }
771 
772 EAPI const Eina_List *
ephysics_body_collision_group_list_get(const EPhysics_Body * body)773 ephysics_body_collision_group_list_get(const EPhysics_Body *body)
774 {
775    if (!body)
776      {
777         ERR("Can't get the body's collision group, body is null.");
778         return NULL;
779      }
780 
781    return body->collision_groups;
782 }
783 
784 static EPhysics_Body *
_ephysics_body_new(EPhysics_World * world,btScalar mass,double cm_x,double cm_y,double cm_z)785 _ephysics_body_new(EPhysics_World *world, btScalar mass, double cm_x, double cm_y, double cm_z)
786 {
787    EPhysics_Body *body;
788    double rate;
789 
790    body = (EPhysics_Body *) calloc(1, sizeof(EPhysics_Body));
791    if (!body)
792      {
793         ERR("Couldn't create a new body instance.");
794         return NULL;
795      }
796 
797    rate = ephysics_world_rate_get(world);
798    body->scale[0] = 1;
799    body->scale[1] = 1;
800    body->scale[2] = 1;
801    body->size.w = rate;
802    body->size.h = rate;
803    body->size.d = rate;
804    body->mass = mass;
805    body->world = world;
806    body->cm.x = cm_x;
807    body->cm.y = cm_y;
808    body->cm.z = cm_z;
809 
810    return body;
811 }
812 
813 static EPhysics_Body *
_ephysics_body_rigid_body_add(EPhysics_World * world,btCollisionShape * collision_shape,const char * type,double cm_x,double cm_y,double cm_z)814 _ephysics_body_rigid_body_add(EPhysics_World *world, btCollisionShape *collision_shape, const char *type, double cm_x, double cm_y, double cm_z)
815 {
816    btRigidBody::btRigidBodyConstructionInfo *rigid_body_ci;
817    btDefaultMotionState *motion_state;
818    btRigidBody *rigid_body;
819    EPhysics_Body *body;
820    btScalar mass = 1;
821    btVector3 inertia;
822 
823    if (!collision_shape)
824      {
825         ERR("Couldn't create a %s shape.", type);
826         return NULL;
827      }
828 
829    body = _ephysics_body_new(world, mass, cm_x, cm_y, cm_z);
830    if (!body)
831      {
832         ERR("Couldn't create a new body instance.");
833         goto err_body;
834      }
835 
836    motion_state = new btDefaultMotionState();
837    if (!motion_state)
838      {
839         ERR("Couldn't create a motion state.");
840         goto err_motion_state;
841      }
842 
843    inertia = btVector3(0, 0, 0);
844    collision_shape->calculateLocalInertia(mass, inertia);
845 
846    rigid_body_ci = new btRigidBody::btRigidBodyConstructionInfo(
847       mass, motion_state, collision_shape, inertia);
848    if (!rigid_body_ci)
849      {
850         ERR("Couldn't create a rigid body construction info.");
851         goto err_rigid_body_ci;
852      }
853 
854    rigid_body = new btRigidBody(*rigid_body_ci);
855    if (!rigid_body)
856      {
857         ERR("Couldn't create a rigid body.");
858         goto err_rigid_body;
859      }
860 
861    body->type = EPHYSICS_BODY_TYPE_RIGID;
862    body->collision_shape = collision_shape;
863    body->rigid_body = rigid_body;
864    body->rigid_body->setUserPointer(body);
865    body->rigid_body->setLinearFactor(btVector3(1, 1, 0));
866    body->rigid_body->setAngularFactor(btVector3(0, 0, 1));
867 
868    if (!ephysics_world_body_add(body->world, body))
869      {
870         ERR("Couldn't add body to world's bodies list");
871         goto err_world_add;
872      }
873 
874    delete rigid_body_ci;
875 
876    INF("Body %p of type %s added.", body, type);
877    return body;
878 
879 err_world_add:
880    delete rigid_body;
881 err_rigid_body:
882    delete rigid_body_ci;
883 err_rigid_body_ci:
884    delete motion_state;
885 err_motion_state:
886    free(body);
887 err_body:
888    delete collision_shape;
889    return NULL;
890 }
891 
892 static void
_ephysics_body_efl_canvas_object_del_cb(void * data,Evas * e EINA_UNUSED,Evas_Object * obj EINA_UNUSED,void * event_info EINA_UNUSED)893 _ephysics_body_efl_canvas_object_del_cb(void *data, Evas *e EINA_UNUSED, Evas_Object *obj EINA_UNUSED, void *event_info EINA_UNUSED)
894 {
895    EPhysics_Body *body = (EPhysics_Body *) data;
896 
897    if (body->default_face)
898      _ephysics_body_soft_body_slices_clean(body->default_face->slices);
899 
900    body->evas_obj = NULL;
901    DBG("Evas object deleted. Updating body: %p", body);
902 }
903 
904 static void
_ephysics_body_soft_body_anchors_rebuild(int node,btRigidBody * rigid_body,btSoftBody * soft_body)905 _ephysics_body_soft_body_anchors_rebuild(int node, btRigidBody *rigid_body, btSoftBody *soft_body)
906 {
907    btTransform world_trans = rigid_body->getWorldTransform();
908    btVector3 local = world_trans.inverse() * soft_body->m_nodes[node].m_x;
909 
910    for (int i = 0; i < soft_body->m_anchors.size(); i++)
911      {
912         if (soft_body->m_anchors[i].m_node == &soft_body->m_nodes[node])
913           soft_body->m_anchors[i].m_local = local;
914      }
915 }
916 
917 void
ephysics_body_soft_body_bending_constraints_generate(EPhysics_Body * body)918 ephysics_body_soft_body_bending_constraints_generate(EPhysics_Body *body)
919 {
920    btSoftBody *soft_body = body->soft_body;
921 
922    for (; body->bending_constraints; body->bending_constraints--)
923      soft_body->generateBendingConstraints(2, soft_body->m_materials
924                                            [body->material_index]);
925 }
926 
927 static void
_ephysics_body_cloth_constraints_rebuild(EPhysics_Body * body)928 _ephysics_body_cloth_constraints_rebuild(EPhysics_Body *body)
929 {
930    btRigidBody *rigid_body;
931    btSoftBody *soft_body;
932    btSoftBody::Node *node;
933    btSoftBody::Anchor anchor;
934    int anchors_size = body->soft_body->m_anchors.size();
935 
936    soft_body = body->soft_body;
937 
938    if (anchors_size)
939      {
940         rigid_body = soft_body->m_anchors[0].m_body;
941         for (int m = 0; m < anchors_size; m++)
942           {
943              anchor = soft_body->m_anchors[m];
944              node = anchor.m_node;
945              for (int n = 0; n < soft_body->m_nodes.size(); n++)
946                {
947                   if (node == &soft_body->m_nodes[n])
948                     _ephysics_body_soft_body_anchors_rebuild(n, rigid_body,
949                                                              soft_body);
950                }
951           }
952      }
953    soft_body->generateClusters(0);
954    ephysics_body_soft_body_bending_constraints_generate(body);
955 }
956 
957 static void
_ephysics_body_soft_body_constraints_rebuild(EPhysics_Body * body)958 _ephysics_body_soft_body_constraints_rebuild(EPhysics_Body *body)
959 {
960    btSoftBody *soft_body = body->soft_body;
961    btRigidBody *rigid_body = body->rigid_body;
962 
963    if (soft_body->m_anchors.size() > 0)
964      {
965         for (int i = 0; i < soft_body->m_nodes.size(); i++)
966           _ephysics_body_soft_body_anchors_rebuild(i, rigid_body, soft_body);
967      }
968    else
969      {
970         for (int i = 0; i < soft_body->m_nodes.size(); i++)
971           soft_body->appendAnchor(i, rigid_body);
972      }
973 
974    soft_body->generateClusters(0);
975    ephysics_body_soft_body_bending_constraints_generate(body);
976 }
977 
978 inline static double
_ephysics_body_volume_get(const EPhysics_Body * body)979 _ephysics_body_volume_get(const EPhysics_Body *body)
980 {
981    btVector3 vector = body->collision_shape->getLocalScaling();
982    return vector.x() * vector.y() * vector.z();
983 }
984 
985 void
_ephysics_body_soft_body_dragging_set(EPhysics_Body * body,int triangle)986 _ephysics_body_soft_body_dragging_set(EPhysics_Body *body, int triangle)
987 {
988    btSoftBody::Face face;
989    btSoftBody::Node *node;
990 
991    body->dragging_data.triangle = triangle;
992    body->dragging_data.dragging = EINA_TRUE;
993 
994    face = body->soft_body->m_faces[triangle];
995    node = face.m_n[0];
996    body->dragging_data.mass = node->m_im;
997 }
998 
999 static void
_ephysics_body_soft_body_mass_set(EPhysics_Body * body,double mass)1000 _ephysics_body_soft_body_mass_set(EPhysics_Body *body, double mass)
1001 {
1002    int valid_nodes;
1003    btSoftBody::Node node;
1004    double inverse_mass = 0.0;
1005 
1006    if (body->type == EPHYSICS_BODY_TYPE_SOFT)
1007      body->soft_body->setTotalMass(mass);
1008    else if (mass > 0.0)
1009      {
1010         valid_nodes = 0;
1011         for (int i = 0; i < body->soft_body->m_nodes.size(); i++)
1012           {
1013              node = body->soft_body->m_nodes[i];
1014              if (node.m_im && !node.m_battach)
1015                valid_nodes++;
1016           }
1017 
1018         if (valid_nodes > 0)
1019           {
1020              inverse_mass = 1 / (mass / valid_nodes);
1021              if (body->dragging_data.dragging)
1022                {
1023                   valid_nodes++;
1024                   inverse_mass = 1 / (mass / valid_nodes);
1025                   body->dragging_data.mass = inverse_mass;
1026                }
1027           }
1028 
1029         for (int i = 0; i < body->soft_body->m_nodes.size(); i++)
1030           {
1031              node = body->soft_body->m_nodes[i];
1032              if (node.m_im && !node.m_battach)
1033                node.m_im = inverse_mass;
1034           }
1035      }
1036 }
1037 
1038 static void
_ephysics_body_mass_set(EPhysics_Body * body,double mass)1039 _ephysics_body_mass_set(EPhysics_Body *body, double mass)
1040 {
1041    btVector3 inertia(0, 0, 0);
1042 
1043    if (body->density)
1044      mass = body->density * _ephysics_body_volume_get(body);
1045 
1046    if (body->soft_body)
1047      _ephysics_body_soft_body_mass_set(body, mass);
1048    else
1049      {
1050         body->collision_shape->calculateLocalInertia(mass, inertia);
1051         body->rigid_body->setMassProps(mass, inertia);
1052         body->rigid_body->updateInertiaTensor();
1053      }
1054 
1055    body->mass = mass;
1056    DBG("Body %p mass changed to %lf.", body, mass);
1057 }
1058 
1059 static void
_ephysics_body_geometry_set(EPhysics_Body * body,Evas_Coord x,Evas_Coord y,Evas_Coord z,Evas_Coord w,Evas_Coord h,Evas_Coord d,double rate)1060 _ephysics_body_geometry_set(EPhysics_Body *body, Evas_Coord x, Evas_Coord y, Evas_Coord z, Evas_Coord w, Evas_Coord h, Evas_Coord d, double rate)
1061 {
1062    double mx, my, mz, sx, sy, sz;
1063    btTransform trans;
1064    int wy, height;
1065    btVector3 body_scale, old_scale;
1066 
1067    ephysics_world_render_geometry_get(body->world, NULL, &wy, NULL,
1068                                       NULL, &height, NULL);
1069    height += wy;
1070 
1071    mx = (x + w * body->cm.x) / rate;
1072    my = (height - (y + h * body->cm.y)) / rate;
1073    mz = (z + d * body->cm.z) / rate;
1074    sx = (w <= 0) ? 1 : w / rate;
1075    sy = (h <= 0) ? 1 : h / rate;
1076    sz = (d <= 0) ? 1 : d / rate;
1077 
1078    trans = _ephysics_body_transform_get(body);
1079    trans.setOrigin(btVector3(mx, my, mz));
1080    body_scale = btVector3(sx, sy, sz);
1081    old_scale = btVector3(body->scale[0], body->scale[1], body->scale[2]);
1082 
1083    if (body->type == EPHYSICS_BODY_TYPE_SOFT)
1084      {
1085         body->soft_body->scale(btVector3(1, 1, 1) / old_scale);
1086         body->soft_body->scale(body_scale);
1087         body->rigid_body->proceedToTransform(trans);
1088         _ephysics_body_transform_set(body, trans);
1089         _ephysics_body_soft_body_constraints_rebuild(body);
1090      }
1091    else if (body->type == EPHYSICS_BODY_TYPE_CLOTH)
1092      {
1093         body->soft_body->setTotalMass(body->mass, true);
1094         body->soft_body->scale(btVector3(1, 1, 1) / old_scale);
1095         body->soft_body->scale(body_scale);
1096         _ephysics_body_transform_set(body, trans);
1097         _ephysics_body_cloth_constraints_rebuild(body);
1098         body->soft_body->setTotalMass(body->mass, false);
1099         _ephysics_body_cloth_anchor_mass_reset(body);
1100      }
1101    else
1102      {
1103         body->collision_shape->setLocalScaling(body_scale);
1104         body->rigid_body->proceedToTransform(trans);
1105 
1106         if (!body->rigid_body->isStaticObject())
1107           _ephysics_body_mass_set(body, ephysics_body_mass_get(body));
1108      }
1109 
1110    _ephysics_body_transform_set(body, trans);
1111    ephysics_body_activate(body, EINA_TRUE);
1112 
1113    body->size.w = w;
1114    body->size.h = h;
1115    body->size.d = d;
1116    body->scale[0] = sx;
1117    body->scale[1] = sy;
1118    body->scale[2] = sz;
1119 
1120    DBG("Body %p position changed to (%lf, %lf, %lf).", body, mx, my, mz);
1121    DBG("Body %p scale changed to (%lf, %lf, %lf).", body, sx, sy, sz);
1122 }
1123 
1124 static void
_ephysics_body_resize(EPhysics_Body * body,Evas_Coord w,Evas_Coord h,Evas_Coord d)1125 _ephysics_body_resize(EPhysics_Body *body, Evas_Coord w, Evas_Coord h, Evas_Coord d)
1126 {
1127    Evas_Coord bx, by, bz;
1128    double rate, sx, sy, sz;
1129    btVector3 body_scale, center;
1130    btTransform trans;
1131 
1132    rate = ephysics_world_rate_get(body->world);
1133    sx = w / rate;
1134    sy = h / rate;
1135    sz = d / rate;
1136 
1137    DBG("Body %p scale changed to (%lf, %lf, %lf).", body, sx, sy, sz);
1138 
1139    body_scale = btVector3(sx, sy, sz);
1140    if (body->type == EPHYSICS_BODY_TYPE_SOFT)
1141      {
1142         btVector3 old_scale(body->scale[0], body->scale[1], body->scale[2]);
1143         trans = _ephysics_body_transform_get(body);
1144 
1145         body->soft_body->scale(btVector3(1, 1, 1) / old_scale);
1146         body->soft_body->scale(body_scale);
1147 
1148         _ephysics_body_transform_set(body, trans);
1149         body->rigid_body->proceedToTransform(trans);
1150 
1151         _ephysics_body_soft_body_constraints_rebuild(body);
1152      }
1153    else if (body->type == EPHYSICS_BODY_TYPE_CLOTH)
1154      {
1155         ephysics_body_geometry_get(body, &bx, &by, &bz, NULL, NULL, NULL);
1156         _ephysics_body_geometry_set(body, bx, by, bz, w, h, d, rate);
1157         return;
1158      }
1159    else
1160      {
1161         body->collision_shape->setLocalScaling(body_scale);
1162 
1163         if(!body->rigid_body->isStaticObject())
1164           _ephysics_body_mass_set(body, ephysics_body_mass_get(body));
1165      }
1166 
1167    body->size.w = w;
1168    body->size.h = h;
1169    body->size.d = d;
1170    body->scale[0] = sx;
1171    body->scale[1] = sy;
1172    body->scale[2] = sz;
1173 
1174    ephysics_body_activate(body, EINA_TRUE);
1175 }
1176 
1177 static void
_ephysics_body_move(EPhysics_Body * body,Evas_Coord x,Evas_Coord y,Evas_Coord z)1178 _ephysics_body_move(EPhysics_Body *body, Evas_Coord x, Evas_Coord y, Evas_Coord z)
1179 {
1180    double rate, mx, my, mz;
1181    btTransform trans;
1182    int wy, height;
1183    btVector3 body_scale;
1184 
1185    rate = ephysics_world_rate_get(body->world);
1186    ephysics_world_render_geometry_get(body->world, NULL, &wy, NULL,
1187                                       NULL, &height, NULL);
1188    height += wy;
1189 
1190    mx = (x + body->size.w * body->cm.x) / rate;
1191    my = (height - (y + body->size.h * body->cm.y)) / rate;
1192    mz = (z + body->size.d * body->cm.z) / rate;
1193 
1194    trans = _ephysics_body_transform_get(body);
1195    trans.setOrigin(btVector3(mx, my, mz));
1196 
1197    if (body->type == EPHYSICS_BODY_TYPE_CLOTH)
1198      _ephysics_body_transform_set(body, trans);
1199    else if (body->type == EPHYSICS_BODY_TYPE_SOFT)
1200      {
1201         _ephysics_body_transform_set(body, trans);
1202         body->rigid_body->proceedToTransform(trans);
1203         body->rigid_body->getMotionState()->setWorldTransform(trans);
1204      }
1205    else
1206      {
1207         body->rigid_body->proceedToTransform(trans);
1208         body->rigid_body->getMotionState()->setWorldTransform(trans);
1209      }
1210 
1211    ephysics_body_activate(body, EINA_TRUE);
1212 
1213    DBG("Body %p position changed to (%lf, %lf, %lf).", body, mx, my, mz);
1214 }
1215 
1216 static void
_ephysics_body_efl_canvas_object_resize_cb(void * data,Evas * e EINA_UNUSED,Evas_Object * obj,void * event_info EINA_UNUSED)1217 _ephysics_body_efl_canvas_object_resize_cb(void *data, Evas *e EINA_UNUSED, Evas_Object *obj, void *event_info EINA_UNUSED)
1218 {
1219    EPhysics_Body *body = (EPhysics_Body *) data;
1220    int w, h;
1221 
1222    evas_object_geometry_get(obj, NULL, NULL, &w, &h);
1223    if ((w == body->size.w) && (h == body->size.h))
1224      return;
1225 
1226    DBG("Resizing body %p to w=%i, h=%i, d=%i", body, w, h, body->size.d);
1227 
1228    ephysics_world_lock_take(body->world);
1229    _ephysics_body_resize(body, w, h, body->size.d);
1230 
1231    if (body->type == EPHYSICS_BODY_TYPE_CLOTH)
1232      {
1233         _ephysics_body_soft_body_slices_clean(body->default_face->slices);
1234         _ephysics_body_soft_body_slices_init(body, body->evas_obj,
1235                                              body->default_face->slices);
1236      }
1237 
1238    ephysics_world_lock_release(body->world);
1239 }
1240 
1241  static void
_ephysics_body_soft_body_evas_restack_cb(void * data,Evas * evas EINA_UNUSED,Evas_Object * obj,void * event_info EINA_UNUSED)1242 _ephysics_body_soft_body_evas_restack_cb(void *data, Evas *evas EINA_UNUSED, Evas_Object *obj, void *event_info EINA_UNUSED)
1243 {
1244    EPhysics_Body *body = (EPhysics_Body *)data;
1245    Eina_List *slices;
1246    void *ldata;
1247    EPhysics_Body_Soft_Body_Slice *slice;
1248    short layer = evas_object_layer_get(obj);
1249 
1250    slices = _ephysics_body_soft_body_slices_get(body);
1251    EINA_LIST_FREE(slices, ldata)
1252      {
1253         slice = (EPhysics_Body_Soft_Body_Slice *)ldata;
1254         evas_object_layer_set(slice->evas_obj, layer);
1255      }
1256    DBG("Body's slices layer reset to: %d", layer);
1257 }
1258 
1259 static void
_ephysics_body_face_slice_del(EPhysics_Body_Face_Slice * face_slice)1260 _ephysics_body_face_slice_del(EPhysics_Body_Face_Slice *face_slice)
1261 {
1262    _ephysics_body_soft_body_slices_free(face_slice->slices);
1263    free(face_slice->points_deform);
1264    free(face_slice);
1265 }
1266 
1267 static EPhysics_Body_Face_Slice *
_ephysics_body_face_slice_add(EPhysics_Body * body,EPhysics_Body_Face face)1268 _ephysics_body_face_slice_add(EPhysics_Body *body, EPhysics_Body_Face face)
1269 {
1270    EPhysics_Body_Face_Slice *face_slice;
1271 
1272    face_slice = (EPhysics_Body_Face_Slice *)calloc(1,
1273                                                sizeof(EPhysics_Body_Face_Slice));
1274    if (!face_slice)
1275      return NULL;
1276 
1277    face_slice->face = face;
1278    body->faces_slices = eina_list_append(body->faces_slices, face_slice);
1279    face_slice->body = body;
1280    return face_slice;
1281    DBG("New face slice added to body %p", body);
1282 }
1283 
1284 static EPhysics_Body_Face_Slice *
_ephysics_body_face_slice_get(EPhysics_Body * body,EPhysics_Body_Face face)1285 _ephysics_body_face_slice_get(EPhysics_Body *body, EPhysics_Body_Face face)
1286 {
1287    Eina_List *l;
1288    void *ldata;
1289    EPhysics_Body_Face_Slice *face_slice = NULL;
1290 
1291    EINA_LIST_FOREACH(body->faces_slices, l, ldata)
1292      {
1293         if (((EPhysics_Body_Face_Slice *)ldata)->face == face)
1294           {
1295              face_slice = (EPhysics_Body_Face_Slice *)ldata;
1296              break;
1297           }
1298      }
1299 
1300    return face_slice;
1301 }
1302 
1303 static EPhysics_Body_Face_Obj *
_ephysics_body_face_evas_object_get(EPhysics_Body * body,EPhysics_Body_Face face)1304 _ephysics_body_face_evas_object_get(EPhysics_Body *body, EPhysics_Body_Face face)
1305 {
1306    Eina_List *l;
1307    void *ldata;
1308    EPhysics_Body_Face_Obj *face_obj;
1309 
1310    EINA_LIST_FOREACH(body->face_objs, l, ldata)
1311      {
1312         face_obj = (EPhysics_Body_Face_Obj *)ldata;
1313         if (face_obj->face == face)
1314           return face_obj;
1315      }
1316 
1317    DBG("Could not find requested face");
1318    return NULL;
1319 }
1320 
1321 static void
_ephysics_body_del(EPhysics_Body * body)1322 _ephysics_body_del(EPhysics_Body *body)
1323 {
1324    EPhysics_Body_Callback *cb;
1325    void *ldata;
1326    void *group;
1327    EPhysics_Body_Face_Slice *face_slice;
1328 
1329    if (body->evas_obj)
1330      {
1331         evas_object_event_callback_del(body->evas_obj, EVAS_CALLBACK_DEL,
1332                                        _ephysics_body_efl_canvas_object_del_cb);
1333         evas_object_event_callback_del(body->evas_obj, EVAS_CALLBACK_RESIZE,
1334                                        _ephysics_body_efl_canvas_object_resize_cb);
1335 
1336         if (body->faces_slices)
1337           evas_object_event_callback_del(body->evas_obj, EVAS_CALLBACK_RESTACK,
1338                                        _ephysics_body_soft_body_evas_restack_cb);
1339      }
1340 
1341    while (body->callbacks)
1342      {
1343         cb = EINA_INLIST_CONTAINER_GET(body->callbacks,
1344                                        EPhysics_Body_Callback);
1345         body->callbacks = eina_inlist_remove(body->callbacks, body->callbacks);
1346         free(cb);
1347      }
1348 
1349    ephysics_constraint_body_del(body);
1350 
1351    EINA_LIST_FREE(body->collision_groups, group)
1352       eina_stringshare_del((Eina_Stringshare *)group);
1353 
1354    EINA_LIST_FREE(body->faces_slices, ldata)
1355      {
1356         face_slice = (EPhysics_Body_Face_Slice *)ldata;
1357         if (_ephysics_body_face_evas_object_get(body, face_slice->face))
1358           ephysics_body_face_evas_object_unset(body, face_slice->face);
1359         _ephysics_body_face_slice_del(face_slice);
1360      }
1361 
1362    if (body->rigid_body)
1363      {
1364         delete body->rigid_body->getMotionState();
1365         delete body->collision_shape;
1366         delete body->rigid_body;
1367      }
1368 
1369    delete body->soft_body;
1370 
1371    free(body);
1372 }
1373 
1374 static void
_ephysics_body_evas_object_map_apply(EPhysics_Body * body,Evas_Map * map,Evas_Object * obj,Eina_Bool bfc,Eina_Bool update_cw)1375 _ephysics_body_evas_object_map_apply(EPhysics_Body *body, Evas_Map *map, Evas_Object *obj, Eina_Bool bfc, Eina_Bool update_cw)
1376 {
1377    EPhysics_Camera *camera = ephysics_world_camera_get(body->world);
1378 
1379    if (ephysics_camera_perspective_enabled_get(camera))
1380      {
1381         int px, py, z0, foc;
1382         ephysics_camera_perspective_get(camera, &px, &py, &z0, &foc);
1383         evas_map_util_3d_perspective(map, px, py, z0, foc);
1384      }
1385 
1386    if (bfc)
1387      {
1388         if (evas_map_util_clockwise_get(map))
1389           {
1390              if (update_cw)
1391                body->clockwise = EINA_TRUE;
1392              evas_object_show(obj);
1393           }
1394         else
1395           {
1396              if (update_cw)
1397                body->clockwise = EINA_FALSE;
1398              evas_map_free(map);
1399              evas_object_hide(obj);
1400              return;
1401           }
1402      }
1403    else
1404        evas_object_show(obj);
1405 
1406    if ((body->light_apply) ||
1407        (ephysics_world_light_all_bodies_get(body->world)))
1408      {
1409         int lr, lg, lb, ar, ag, ab;
1410         Evas_Coord lx, ly, lz;
1411 
1412         ephysics_world_point_light_position_get(body->world, &lx, &ly, &lz);
1413         ephysics_world_point_light_color_get(body->world, &lr, &lg, &lb);
1414         ephysics_world_ambient_light_color_get(body->world, &ar, &ag, &ab);
1415         evas_map_util_3d_lighting(map, lx, ly, lz, lr, lg, lb, ar, ag, ab);
1416      }
1417 
1418    evas_object_map_set(obj, map);
1419    evas_object_map_enable_set(obj, EINA_TRUE);
1420    evas_map_free(map);
1421 }
1422 
1423 static void
_ephysics_cloth_face_objs_update(EPhysics_Body * body EINA_UNUSED)1424 _ephysics_cloth_face_objs_update(EPhysics_Body *body EINA_UNUSED)
1425 {
1426 
1427 }
1428 
1429 static void
_ephysics_cylinder_face_objs_update(EPhysics_Body * body)1430 _ephysics_cylinder_face_objs_update(EPhysics_Body *body)
1431 {
1432    int bx, by, x, y, z, wx, wy, wh, cx, cy;
1433    EPhysics_Body_Face_Obj *face_obj;
1434    EPhysics_Camera *camera;
1435    btQuaternion quat;
1436    btTransform trans;
1437    Evas_Map *map;
1438    Eina_List *l;
1439    double rate;
1440    void *ldata;
1441 
1442    ephysics_world_render_geometry_get(body->world, &wx, &wy, NULL,
1443                                       NULL, &wh, NULL);
1444    camera = ephysics_world_camera_get(body->world);
1445    ephysics_camera_position_get(camera, &cx, &cy);
1446    cx -= wx;
1447    cy -= wy;
1448 
1449    rate = ephysics_world_rate_get(body->world);
1450    trans = _ephysics_body_transform_get(body);
1451 
1452    bx = (int) (trans.getOrigin().getX() * rate) - cx;
1453    by = wh + wy - (int) (trans.getOrigin().getY() * rate) - cy;
1454    x = bx - body->size.w / 2;
1455    y = by - body->size.h / 2;
1456    z = (int) (trans.getOrigin().getZ() * rate);
1457 
1458    quat = trans.getRotation();
1459    quat.normalize();
1460 
1461    EINA_LIST_FOREACH(body->face_objs, l, ldata)
1462      {
1463         Evas_Object *obj;
1464         Evas_Coord w, h;
1465 
1466         face_obj = (EPhysics_Body_Face_Obj *)ldata;
1467         obj = face_obj->obj;
1468 
1469         evas_object_geometry_get(obj, NULL, NULL, &w, &h);
1470         evas_object_move(obj, x, y);
1471         if ((!w) || (!h))
1472           {
1473              DBG("Evas object with no geometry: %p, w=%i h=%i", obj, w, h);
1474              continue;
1475           }
1476 
1477         map = evas_map_new(4);
1478 
1479         switch(face_obj->face)
1480           {
1481            case EPHYSICS_BODY_CYLINDER_FACE_MIDDLE_FRONT:
1482               evas_map_util_points_populate_from_object_full(map, obj, z);
1483               break;
1484            case EPHYSICS_BODY_CYLINDER_FACE_MIDDLE_BACK:
1485               evas_map_util_points_populate_from_object_full(map, obj, z + 1);
1486               evas_map_util_3d_rotate(map, 0, 180, 0, bx, by, z + 1);
1487               break;
1488            case EPHYSICS_BODY_CYLINDER_FACE_FRONT:
1489               evas_map_util_points_populate_from_object_full(
1490                  map, obj, z - body->size.d / 2);
1491               break;
1492            case EPHYSICS_BODY_CYLINDER_FACE_BACK:
1493               evas_map_util_points_populate_from_object_full(
1494                  map, obj, z + body->size.d / 2);
1495               evas_map_util_3d_rotate(map, 0, 180, 0, bx, by,
1496                                       z + body->size.d / 2);
1497               break;
1498            default:
1499               WRN("Face %i not updated", face_obj->face);
1500               evas_map_free(map);
1501               continue;
1502           }
1503 
1504         evas_map_util_quat_rotate(map, quat.x(), -quat.y(), quat.z(), -quat.w(),
1505                                   bx, by, z);
1506 
1507         _ephysics_body_evas_object_map_apply(body, map, obj, EINA_TRUE,
1508                                           EINA_FALSE);
1509      }
1510 }
1511 
1512 static void
_ephysics_box_face_objs_update(EPhysics_Body * body)1513 _ephysics_box_face_objs_update(EPhysics_Body *body)
1514 {
1515    EPhysics_Body_Face_Obj *face_obj;
1516    int i, x, y, z, wx, wy, wh, cx, cy;
1517    EPhysics_Camera *camera;
1518    Evas_Coord v[8][3];
1519    btQuaternion quat;
1520    btTransform trans;
1521    btBoxShape *shape;
1522    Evas_Map *map;
1523    Eina_List *l;
1524    double rate;
1525    void *ldata;
1526 
1527    ephysics_world_render_geometry_get(body->world, &wx, &wy, NULL,
1528                                       NULL, &wh, NULL);
1529    camera = ephysics_world_camera_get(body->world);
1530    ephysics_camera_position_get(camera, &cx, &cy);
1531    cx -= wx;
1532    cy -= wy;
1533 
1534    rate = ephysics_world_rate_get(body->world);
1535    trans = _ephysics_body_transform_get(body);
1536 
1537    x = (int) (trans.getOrigin().getX() * rate) - cx;
1538    y = wh + wy - (int) (trans.getOrigin().getY() * rate) - cy;
1539    z = (int) (trans.getOrigin().getZ() * rate);
1540 
1541    shape = (btBoxShape *) body->collision_shape;
1542    for (i = 0; i < 8; i++)
1543      {
1544         btVector3 vertice;
1545         shape->getVertex(i, vertice);
1546         v[i][0] = vertice.getX() * rate + x;
1547         v[i][1] = - vertice.getY() * rate + y;
1548         v[i][2] = vertice.getZ() * rate + z;
1549      }
1550 
1551    quat = trans.getRotation();
1552    quat.normalize();
1553 
1554    EINA_LIST_FOREACH(body->face_objs, l, ldata)
1555      {
1556         Evas_Object *obj;
1557         Evas_Coord w, h;
1558 
1559         face_obj = (EPhysics_Body_Face_Obj *)ldata;
1560         obj = face_obj->obj;
1561         evas_object_geometry_get(obj, NULL, NULL, &w, &h);
1562 
1563         map = evas_map_new(4);
1564         evas_map_point_image_uv_set(map, 0, 0, 0);
1565         evas_map_point_image_uv_set(map, 1, w, 0);
1566         evas_map_point_image_uv_set(map, 2, w, h);
1567         evas_map_point_image_uv_set(map, 3, 0, h);
1568 
1569         switch(face_obj->face)
1570           {
1571            case EPHYSICS_BODY_BOX_FACE_MIDDLE_FRONT:
1572               evas_map_point_coord_set(map, 0, v[5][0], v[5][1], z);
1573               evas_map_point_coord_set(map, 1, v[4][0], v[4][1], z);
1574               evas_map_point_coord_set(map, 2, v[6][0], v[6][1], z);
1575               evas_map_point_coord_set(map, 3, v[7][0], v[7][1], z);
1576               break;
1577            case EPHYSICS_BODY_BOX_FACE_MIDDLE_BACK:
1578               evas_map_point_coord_set(map, 0, v[0][0], v[0][1], z);
1579               evas_map_point_coord_set(map, 1, v[1][0], v[1][1], z);
1580               evas_map_point_coord_set(map, 2, v[3][0], v[3][1], z);
1581               evas_map_point_coord_set(map, 3, v[2][0], v[2][1], z);
1582               break;
1583            case EPHYSICS_BODY_BOX_FACE_FRONT:
1584               evas_map_point_coord_set(map, 0, v[5][0], v[5][1], v[5][2]);
1585               evas_map_point_coord_set(map, 1, v[4][0], v[4][1], v[4][2]);
1586               evas_map_point_coord_set(map, 2, v[6][0], v[6][1], v[6][2]);
1587               evas_map_point_coord_set(map, 3, v[7][0], v[7][1], v[7][2]);
1588               break;
1589            case EPHYSICS_BODY_BOX_FACE_BACK:
1590               evas_map_point_coord_set(map, 0, v[0][0], v[0][1], v[0][2]);
1591               evas_map_point_coord_set(map, 1, v[1][0], v[1][1], v[1][2]);
1592               evas_map_point_coord_set(map, 2, v[3][0], v[3][1], v[3][2]);
1593               evas_map_point_coord_set(map, 3, v[2][0], v[2][1], v[2][2]);
1594               break;
1595            case EPHYSICS_BODY_BOX_FACE_RIGHT:
1596               evas_map_point_coord_set(map, 0, v[4][0], v[4][1], v[4][2]);
1597               evas_map_point_coord_set(map, 1, v[0][0], v[0][1], v[0][2]);
1598               evas_map_point_coord_set(map, 2, v[2][0], v[2][1], v[2][2]);
1599               evas_map_point_coord_set(map, 3, v[6][0], v[6][1], v[6][2]);
1600               break;
1601            case EPHYSICS_BODY_BOX_FACE_LEFT:
1602               evas_map_point_coord_set(map, 0, v[1][0], v[1][1], v[1][2]);
1603               evas_map_point_coord_set(map, 1, v[5][0], v[5][1], v[5][2]);
1604               evas_map_point_coord_set(map, 2, v[7][0], v[7][1], v[7][2]);
1605               evas_map_point_coord_set(map, 3, v[3][0], v[3][1], v[3][2]);
1606               break;
1607            case EPHYSICS_BODY_BOX_FACE_TOP:
1608               evas_map_point_coord_set(map, 0, v[1][0], v[1][1], v[1][2]);
1609               evas_map_point_coord_set(map, 1, v[0][0], v[0][1], v[0][2]);
1610               evas_map_point_coord_set(map, 2, v[4][0], v[4][1], v[4][2]);
1611               evas_map_point_coord_set(map, 3, v[5][0], v[5][1], v[5][2]);
1612               break;
1613            case EPHYSICS_BODY_BOX_FACE_BOTTOM:
1614               evas_map_point_coord_set(map, 0, v[7][0], v[7][1], v[7][2]);
1615               evas_map_point_coord_set(map, 1, v[6][0], v[6][1], v[6][2]);
1616               evas_map_point_coord_set(map, 2, v[2][0], v[2][1], v[2][2]);
1617               evas_map_point_coord_set(map, 3, v[3][0], v[3][1], v[3][2]);
1618               break;
1619            default:
1620               WRN("Face %i not updated", face_obj->face);
1621               evas_map_free(map);
1622               continue;
1623           }
1624 
1625         evas_map_util_quat_rotate(map, quat.x(), -quat.y(), quat.z(), -quat.w(),
1626                                   x, y, z);
1627         _ephysics_body_evas_object_map_apply(body, map, obj, EINA_TRUE,
1628                                           EINA_FALSE);
1629      }
1630 }
1631 
1632 static void
_ephysics_body_evas_object_update(EPhysics_Body * body,Evas_Object * evas_obj)1633 _ephysics_body_evas_object_update(EPhysics_Body *body, Evas_Object *evas_obj)
1634 {
1635    int bx, by, x, y, z, w, h, wx, wy, wh, cx, cy;
1636    EPhysics_Camera *camera;
1637    btTransform trans;
1638    btQuaternion quat;
1639    Evas_Map *map;
1640    double rate;
1641 
1642    trans = _ephysics_body_transform_get(body);
1643    ephysics_world_render_geometry_get(body->world, &wx, &wy, NULL,
1644                                       NULL, &wh, NULL);
1645    camera = ephysics_world_camera_get(body->world);
1646    ephysics_camera_position_get(camera, &cx, &cy);
1647    cx -= wx;
1648    cy -= wy;
1649 
1650    evas_object_geometry_get(evas_obj, NULL, NULL, &w, &h);
1651    rate = ephysics_world_rate_get(body->world);
1652    bx = (int) (trans.getOrigin().getX() * rate) - cx;
1653    by = wh + wy - (int) (trans.getOrigin().getY() * rate) - cy;
1654    x = bx - w * body->cm.x;
1655    y = by - h * body->cm.y;
1656    z = (int) (trans.getOrigin().getZ() * rate);
1657 
1658    evas_object_move(evas_obj, x, y);
1659 
1660    if ((!w) || (!h))
1661      {
1662         DBG("Evas object with no geometry: %p, w=%i h=%i", evas_obj, w, h);
1663         return;
1664      }
1665 
1666    if (body->type != EPHYSICS_BODY_TYPE_RIGID)
1667      {
1668         if (!body->back_face_culling)
1669           evas_object_show(body->evas_obj);
1670         _ephysics_body_soft_body_slices_apply(body, body->evas_obj,
1671                                               body->default_face->slices);
1672         return;
1673      }
1674 
1675    map = evas_map_new(4);
1676    evas_map_util_points_populate_from_object(map, body->evas_obj);
1677 
1678    quat = trans.getRotation();
1679    quat.normalize();
1680    evas_map_util_quat_rotate(map, quat.x(), -quat.y(), quat.z(), -quat.w(),
1681                              bx, by, z);
1682 
1683    _ephysics_body_evas_object_map_apply(body, map, evas_obj,
1684                                      body->back_face_culling, EINA_TRUE);
1685 }
1686 
1687 static void
_ephysics_body_soft_body_update(EPhysics_Body * body)1688 _ephysics_body_soft_body_update(EPhysics_Body *body)
1689 {
1690    Eina_List *l;
1691    void *ldata;
1692    EPhysics_Body_Face_Slice *face_slice;
1693    EPhysics_Body_Face_Obj *face_obj;
1694 
1695    EINA_LIST_FOREACH(body->faces_slices, l, ldata)
1696      {
1697         face_slice = (EPhysics_Body_Face_Slice *)ldata;
1698         face_obj = _ephysics_body_face_evas_object_get(body,
1699                                                        face_slice->face);
1700         if (!face_obj) continue;
1701         _ephysics_body_soft_body_slices_apply(body, face_obj->obj,
1702                                               face_slice->slices);
1703      }
1704 }
1705 
1706 static void
_ephysics_body_evas_object_default_update(EPhysics_Body * body)1707 _ephysics_body_evas_object_default_update(EPhysics_Body *body)
1708 {
1709    if (body->face_objs)
1710      {
1711         if (body->type == EPHYSICS_BODY_TYPE_CLOTH)
1712           _ephysics_cloth_face_objs_update(body);
1713         else if (body->type == EPHYSICS_BODY_TYPE_RIGID)
1714           {
1715              if (body->shape == EPHYSICS_BODY_SHAPE_CYLINDER)
1716                _ephysics_cylinder_face_objs_update(body);
1717              else if (body->shape == EPHYSICS_BODY_SHAPE_BOX)
1718                _ephysics_box_face_objs_update(body);
1719           }
1720         else if (body->type == EPHYSICS_BODY_TYPE_SOFT)
1721           _ephysics_body_soft_body_update(body);
1722 
1723         if (body->evas_obj)
1724             evas_object_hide(body->evas_obj);
1725 
1726         return;
1727      }
1728 
1729    if (!body->evas_obj)
1730      return;
1731 
1732    _ephysics_body_evas_object_update(body, body->evas_obj);
1733 }
1734 
1735 static void
_ephysics_body_outside_render_area_check(EPhysics_Body * body)1736 _ephysics_body_outside_render_area_check(EPhysics_Body *body)
1737 {
1738    int wx, wy, wz, ww, wh, wd, bx, by, bz, bw, bh, bd;
1739 
1740    ephysics_world_render_geometry_get(body->world, &wx, &wy, &wz,
1741                                       &ww, &wh, &wd);
1742    ephysics_body_geometry_get(body, &bx, &by, &bz, &bw, &bh, &bd);
1743 
1744    // FIXME: check what should be done regarding rotated bodies
1745    if (((ephysics_world_bodies_outside_top_autodel_get(body->world)) &&
1746         (by + bh < wy)) ||
1747        ((ephysics_world_bodies_outside_bottom_autodel_get(body->world)) &&
1748         (by > wy + wh)) ||
1749        ((ephysics_world_bodies_outside_left_autodel_get(body->world)) &&
1750         (bx + bh < wx)) ||
1751        ((ephysics_world_bodies_outside_right_autodel_get(body->world)) &&
1752         (bx > wx + ww)) ||
1753        ((ephysics_world_bodies_outside_front_autodel_get(body->world)) &&
1754         (bz + bd < wz)) ||
1755        ((ephysics_world_bodies_outside_back_autodel_get(body->world)) &&
1756         (bz > wz + wd)))
1757      {
1758         DBG("Body %p out of render area", body);
1759         ephysics_body_del(body);
1760      }
1761 }
1762 
1763 void
ephysics_body_forces_apply(EPhysics_Body * body)1764 ephysics_body_forces_apply(EPhysics_Body *body)
1765 {
1766    if (!((body->force.x) || (body->force.y) || (body->force.z) ||
1767          (body->force.torque_x) || (body->force.torque_y) ||
1768          (body->force.torque_z)))
1769      return;
1770 
1771    DBG("body: %p, applying forces: %lf, %lf, %lf", body, body->force.x,
1772        body->force.y, body->force.z);
1773 
1774    ephysics_body_activate(body, EINA_TRUE);
1775    body->rigid_body->applyCentralForce(btVector3(body->force.x,
1776                                                  body->force.y,
1777                                                  body->force.z));
1778    body->rigid_body->applyTorque(btVector3(body->force.torque_x,
1779                                            body->force.torque_y,
1780                                            body->force.torque_z));
1781 }
1782 
1783 void
ephysics_body_recalc(EPhysics_Body * body,double rate)1784 ephysics_body_recalc(EPhysics_Body *body, double rate)
1785 {
1786    Evas_Coord x, y, z, w, h, d;
1787    double vx, vy, vz, lt, at;
1788 
1789    ephysics_body_geometry_get(body, &x, &y, &z, &w, &h, &d);
1790    ephysics_body_linear_velocity_get(body, &vx, &vy, &vz);
1791    ephysics_body_sleeping_threshold_get(body, &lt, &at);
1792 
1793    _ephysics_body_geometry_set(body, x, y, z, w, h, d, rate);
1794    _ephysics_body_linear_velocity_set(body, vx, vy, vz, rate);
1795    _ephysics_body_sleeping_threshold_set(body, lt, at, rate);
1796 }
1797 
1798 void
ephysics_body_evas_object_update_select(EPhysics_Body * body)1799 ephysics_body_evas_object_update_select(EPhysics_Body *body)
1800 {
1801    Eina_Bool callback_called = EINA_FALSE;
1802 
1803    if (!body || body->deleted)
1804      return;
1805 
1806    callback_called = _ephysics_body_event_callback_call(
1807       body, EPHYSICS_CALLBACK_BODY_UPDATE, (void *) body->evas_obj);
1808 
1809    if (!callback_called)
1810      _ephysics_body_evas_object_default_update(body);
1811 
1812    if (ephysics_world_bodies_outside_autodel_get(body->world))
1813      _ephysics_body_outside_render_area_check(body);
1814 }
1815 
1816 EAPI void
ephysics_body_collision_position_get(const EPhysics_Body_Collision * collision,Evas_Coord * x,Evas_Coord * y,Evas_Coord * z)1817 ephysics_body_collision_position_get(const EPhysics_Body_Collision *collision, Evas_Coord *x, Evas_Coord *y, Evas_Coord *z)
1818 {
1819    if (!collision)
1820      {
1821         ERR("Can't get body's collision data, collision is null.");
1822         return;
1823      }
1824 
1825    if (x) *x = collision->x;
1826    if (y) *y = collision->y;
1827    if (z) *z = collision->z;
1828 }
1829 
1830 EAPI EPhysics_Body *
ephysics_body_collision_contact_body_get(const EPhysics_Body_Collision * collision)1831 ephysics_body_collision_contact_body_get(const EPhysics_Body_Collision *collision)
1832 {
1833    if (!collision)
1834      {
1835         ERR("Can't get body's collision contact body, collision is null.");
1836         return NULL;
1837      }
1838 
1839    return collision->contact_body;
1840 }
1841 
1842 void
ephysics_body_contact_processed(EPhysics_Body * body,EPhysics_Body * contact_body,btVector3 position)1843 ephysics_body_contact_processed(EPhysics_Body *body, EPhysics_Body *contact_body, btVector3 position)
1844 {
1845    EPhysics_Body_Collision *collision;
1846    EPhysics_World *world;;
1847    double rate;
1848    int wy, wh;
1849 
1850    if ((!body) || (!contact_body) || (body->collision_cb < 1))
1851      return;
1852 
1853    collision = (EPhysics_Body_Collision *)calloc(
1854       1, sizeof(EPhysics_Body_Collision));
1855 
1856    if (!collision)
1857      {
1858         ERR("Can't allocate collision data structure.");
1859         return;
1860      }
1861 
1862    world = contact_body->world;
1863    ephysics_world_render_geometry_get(world, NULL, &wy, NULL, NULL, &wh, NULL);
1864    rate = ephysics_world_rate_get(world);
1865 
1866    collision->contact_body = contact_body;
1867    collision->x = position.getX() * rate;
1868    collision->y = wh + wy - (position.getY() * rate);
1869    collision->z = position.getZ() * rate;
1870 
1871    _ephysics_body_event_callback_call(body, EPHYSICS_CALLBACK_BODY_COLLISION,
1872                                       (void *) collision);
1873 
1874    free(collision);
1875 }
1876 
1877 btRigidBody *
ephysics_body_rigid_body_get(const EPhysics_Body * body)1878 ephysics_body_rigid_body_get(const EPhysics_Body *body)
1879 {
1880    return body->rigid_body;
1881 }
1882 
1883 btSoftBody *
ephysics_body_soft_body_get(const EPhysics_Body * body)1884 ephysics_body_soft_body_get(const EPhysics_Body *body)
1885 {
1886    return body->soft_body;
1887 }
1888 
1889 EAPI void
ephysics_body_soft_body_anchor_hardness_set(EPhysics_Body * body,double hardness)1890 ephysics_body_soft_body_anchor_hardness_set(EPhysics_Body *body, double hardness)
1891 {
1892    if (!body)
1893      {
1894         ERR("Can't set soft body's anchor hardness, body is null.");
1895         return;
1896      }
1897 
1898    if (!body->soft_body)
1899      {
1900         ERR("Can't set soft body's anchor hardness, body seems not to be a soft"
1901             " body.");
1902         return;
1903      }
1904 
1905    if (hardness < 0 || hardness > 100)
1906      {
1907         ERR("Can't set soft body's anchor hardness, it must be between 0 and"
1908             " 100.");
1909         return;
1910      }
1911 
1912    ephysics_world_lock_take(body->world);
1913    body->anchor_hardness = EINA_TRUE;
1914    body->soft_body->m_cfg.kAHR = 1 - (hardness / 100);
1915    ephysics_world_lock_release(body->world);
1916    DBG("Soft body anchor hardness set to: %lf", hardness);
1917 }
1918 
1919 EAPI double
ephysics_body_soft_body_anchor_hardness_get(EPhysics_Body * body)1920 ephysics_body_soft_body_anchor_hardness_get(EPhysics_Body *body)
1921 {
1922    if (!body)
1923      {
1924         ERR("Can't get soft body's anchor hardness, body is null.");
1925         return -1;
1926      }
1927 
1928    if (!body->soft_body)
1929      {
1930         ERR("Can't get soft body's anchor hardness, body seems not to be a soft"
1931             " body.");
1932         return -1;
1933      }
1934 
1935    return body->soft_body->m_cfg.kAHR * 100;
1936 }
1937 
1938 EAPI void
ephysics_body_soft_body_drag_coefficient_set(EPhysics_Body * body,double coefficient)1939 ephysics_body_soft_body_drag_coefficient_set(EPhysics_Body *body, double coefficient)
1940 {
1941    if (!body)
1942      {
1943         ERR("Can't set soft body's drag coefficient, body is null.");
1944         return;
1945      }
1946 
1947    if (!body->soft_body)
1948      {
1949         ERR("Can't set soft body's drag coefficient, body seems not to be a soft"
1950             " body.");
1951         return;
1952      }
1953 
1954    body->soft_body->m_cfg.kDG = coefficient;
1955    DBG("Soft body drag coefficient set to: %lf", coefficient);
1956 }
1957 
1958 EAPI double
ephysics_body_soft_body_drag_coefficient_get(const EPhysics_Body * body)1959 ephysics_body_soft_body_drag_coefficient_get(const EPhysics_Body *body)
1960 {
1961    if (!body)
1962      {
1963         ERR("Can't get soft body's drag coefficient, body is null.");
1964         return -1;
1965      }
1966 
1967    if (!body->soft_body)
1968      {
1969         ERR("Can't get soft body's drag coefficient, body seems not to be a soft"
1970             " body.");
1971         return -1;
1972      }
1973 
1974    return body->soft_body->m_cfg.kDG;
1975 }
1976 
1977 static void
_ephysics_body_soft_body_hardness_set(EPhysics_Body * body,double hardness)1978 _ephysics_body_soft_body_hardness_set(EPhysics_Body *body, double hardness)
1979 {
1980    int m = body->material_index;
1981    btSoftBody *soft_body = body->soft_body;
1982 
1983    if (!body->anchor_hardness)
1984      {
1985         if (body->type == EPHYSICS_BODY_TYPE_CLOTH)
1986           soft_body->m_cfg.kAHR = 0.8;
1987         else
1988           soft_body->m_cfg.kAHR = (hardness / 1000) * 0.6;
1989      }
1990 
1991    soft_body->m_materials[m]->m_kVST = (hardness / 1000);
1992    soft_body->m_materials[m]->m_kLST = (hardness / 1000);
1993    soft_body->m_materials[m]->m_kAST = (hardness / 1000);
1994 
1995    DBG("Soft body %p hardness set to %lf.", body, hardness);
1996 }
1997 
1998 EAPI void
ephysics_body_soft_body_hardness_set(EPhysics_Body * body,double hardness)1999 ephysics_body_soft_body_hardness_set(EPhysics_Body *body, double hardness)
2000 {
2001    if (!body)
2002      {
2003         ERR("Can't set soft body's hardness, body is null.");
2004         return;
2005      }
2006 
2007    if (!body->soft_body)
2008      {
2009         ERR("Can't set soft body's hardness, body seems not to be a soft body.");
2010         return;
2011      }
2012 
2013    if (hardness < 0 || hardness > 100)
2014      {
2015         ERR("Can't set soft body's hardness, it must be between 0 and 100.");
2016         return;
2017      }
2018 
2019    ephysics_world_lock_take(body->world);
2020    _ephysics_body_soft_body_hardness_set(body, hardness);
2021    ephysics_world_lock_release(body->world);
2022 }
2023 
2024 EAPI void
ephysics_body_soft_body_dragging_set(EPhysics_Body * body,int triangle)2025 ephysics_body_soft_body_dragging_set(EPhysics_Body *body, int triangle)
2026 {
2027    if (!body)
2028      {
2029         ERR("Can't set soft body dragging status, body is null.");
2030         return;
2031      }
2032 
2033    if (body->type == EPHYSICS_BODY_TYPE_RIGID)
2034      {
2035         ERR("Can set soft body dragging status, body must not be a rigid body.");
2036         return;
2037      }
2038 
2039    if (triangle < 0 || triangle >= body->soft_body->m_faces.size())
2040      {
2041         ERR("Could not move soft body triangle, provided body triangle index "
2042             "ranges from 0 to %d", body->soft_body->m_faces.size());
2043         return;
2044      }
2045 
2046    ephysics_world_lock_take(body->world);
2047    _ephysics_body_soft_body_dragging_set(body, triangle);
2048    ephysics_world_lock_release(body->world);
2049 
2050    DBG("Body %p appended to world's dragging bodies list.", body);
2051 }
2052 
2053 EAPI void
ephysics_body_soft_body_dragging_unset(EPhysics_Body * body)2054 ephysics_body_soft_body_dragging_unset(EPhysics_Body *body)
2055 {
2056    btSoftBody::Face face;
2057    btSoftBody::Node *node;
2058 
2059    if (!body)
2060      {
2061         ERR("Can't unset soft body dragging status, body is null.");
2062         return;
2063      }
2064 
2065    if (body->type == EPHYSICS_BODY_TYPE_RIGID)
2066      {
2067         ERR("Can unset soft body dragging status, body must not be a rigid"
2068             " body.");
2069         return;
2070      }
2071 
2072    if (!body->dragging_data.dragging)
2073      {
2074         INF("Dragging isn't set");
2075         return;
2076      }
2077 
2078    ephysics_world_lock_take(body->world);
2079    face = body->soft_body->m_faces[body->dragging_data.triangle];
2080    node = face.m_n[0];
2081    node->m_im = body->dragging_data.mass;
2082 
2083    body->dragging_data.mass = 0;
2084    body->dragging_data.dragging = EINA_FALSE;
2085    body->dragging_data.triangle = 0;
2086    ephysics_world_lock_release(body->world);
2087 }
2088 
2089 EAPI double
ephysics_body_soft_body_hardness_get(const EPhysics_Body * body)2090 ephysics_body_soft_body_hardness_get(const EPhysics_Body *body)
2091 {
2092    if (!body)
2093      {
2094         ERR("Can't get soft body's hardness, body is null.");
2095         return 0;
2096      }
2097 
2098    if (!body->soft_body)
2099      {
2100         ERR("Can't get soft body's hardness, body seems not to be a soft body.");
2101         return 0;
2102      }
2103 
2104    return (body->soft_body->m_materials[body->material_index]->m_kVST * 100);
2105 }
2106 
2107 static void
_ephysics_body_soft_body_default_config(EPhysics_Body * body,btSoftBody * soft_body)2108 _ephysics_body_soft_body_default_config(EPhysics_Body *body, btSoftBody *soft_body)
2109 {
2110    body->bending_constraints = 1;
2111    body->soft_body = soft_body;
2112    body->soft_body->getCollisionShape()->setMargin(btScalar(0.02));
2113    body->soft_body->setUserPointer(body);
2114    body->soft_body->setTotalMass(body->mass);
2115 
2116    body->soft_body->m_cfg.collisions += btSoftBody::fCollision::SDF_RS;
2117    body->soft_body->m_cfg.collisions += btSoftBody::fCollision::VF_SS;
2118    _ephysics_body_soft_body_hardness_set(body, 100);
2119 }
2120 
2121 static EPhysics_Body *
_ephysics_body_soft_body_add(EPhysics_World * world,btCollisionShape * collision_shape,btSoftBody * soft_body)2122 _ephysics_body_soft_body_add(EPhysics_World *world, btCollisionShape *collision_shape, btSoftBody *soft_body)
2123 {
2124    EPhysics_Body *body;
2125 
2126    body = _ephysics_body_rigid_body_add(world, collision_shape, "soft box", 0.5,
2127                                         0.5, 0.5);
2128    if (!body) return NULL;
2129 
2130    body->material_index = 0;
2131    body->type = EPHYSICS_BODY_TYPE_SOFT;
2132    _ephysics_body_soft_body_default_config(body, soft_body);
2133 
2134    body->rigid_body->setCollisionFlags(
2135       btCollisionObject::CF_NO_CONTACT_RESPONSE);
2136 
2137    _ephysics_body_soft_body_constraints_rebuild(body);
2138    ephysics_world_soft_body_add(world, body);
2139 
2140    return body;
2141 }
2142 
2143 EAPI void
ephysics_body_cloth_anchor_full_add(EPhysics_Body * body1,EPhysics_Body * body2,EPhysics_Body_Cloth_Anchor_Side side)2144 ephysics_body_cloth_anchor_full_add(EPhysics_Body *body1, EPhysics_Body *body2, EPhysics_Body_Cloth_Anchor_Side side)
2145 {
2146    int rows;
2147    int columns;
2148 
2149    if (!body1 || !body2)
2150      {
2151         ERR("Could not add anchors, body1 or body2 is null");
2152         return;
2153      }
2154 
2155    if (body1->type != EPHYSICS_BODY_TYPE_CLOTH ||
2156        body2->type != EPHYSICS_BODY_TYPE_RIGID)
2157      {
2158         ERR("Cloth anchors are allowed only between cloth and rigid body.");
2159         return;
2160      }
2161 
2162    if ((side < 0) || (side >= EPHYSICS_BODY_CLOTH_ANCHOR_SIDE_LAST))
2163      {
2164         ERR("Could not add anchors, side is invalid.");
2165         return;
2166      }
2167 
2168    rows = body1->cloth_rows + 1;
2169    columns = body1->cloth_columns + 1;
2170 
2171    if (side == EPHYSICS_BODY_CLOTH_ANCHOR_SIDE_RIGHT)
2172      {
2173         for (int i = 0; i < rows; i++)
2174           body1->soft_body->appendAnchor(i, body2->rigid_body);
2175         goto mass_reset;
2176      }
2177 
2178    if (side == EPHYSICS_BODY_CLOTH_ANCHOR_SIDE_LEFT)
2179      {
2180         for (int i = 1; i <= rows; i++)
2181           body1->soft_body->appendAnchor((rows * columns) - i,
2182                                          body2->rigid_body);
2183         goto mass_reset;
2184      }
2185 
2186    if (side == EPHYSICS_BODY_CLOTH_ANCHOR_SIDE_BOTTOM)
2187      {
2188         for (int i = 0; i <= rows; i++)
2189           body1->soft_body->appendAnchor(i * rows, body2->rigid_body);
2190         goto mass_reset;
2191      }
2192 
2193    if (side == EPHYSICS_BODY_CLOTH_ANCHOR_SIDE_TOP)
2194      {
2195         for (int i = 0; i < columns; i++)
2196           body1->soft_body->appendAnchor((rows - 1) + rows * i,
2197                                          body2->rigid_body);
2198      }
2199 
2200  mass_reset:
2201    _ephysics_body_cloth_anchor_mass_reset(body1);
2202 }
2203 
2204 EAPI void
ephysics_body_cloth_anchor_add(EPhysics_Body * body1,EPhysics_Body * body2,int node)2205 ephysics_body_cloth_anchor_add(EPhysics_Body *body1, EPhysics_Body *body2, int node)
2206 {
2207    if (!body1 || !body2)
2208      {
2209         ERR("Could not add anchors, body1 or body2 is null");
2210         return;
2211      }
2212 
2213    if (body1->type != EPHYSICS_BODY_TYPE_CLOTH ||
2214        body2->type != EPHYSICS_BODY_TYPE_RIGID)
2215      {
2216         ERR("Cloth anchors are allowed only between cloth and rigid body.");
2217         return;
2218      }
2219 
2220    body1->soft_body->appendAnchor(node, body2->rigid_body);
2221    _ephysics_body_cloth_anchor_mass_reset(body1);
2222 }
2223 
2224 EAPI void
ephysics_body_cloth_anchor_del(EPhysics_Body * body)2225 ephysics_body_cloth_anchor_del(EPhysics_Body *body)
2226 {
2227    if (!body)
2228      {
2229         ERR("Could not delete anchor, body is null.");
2230         return;
2231      }
2232 
2233    if (body->type != EPHYSICS_BODY_TYPE_CLOTH)
2234      {
2235         ERR("Could not delete anchors, body is not a cloth.");
2236         return;
2237      }
2238 
2239    body->soft_body->m_anchors.resize(0);
2240    body->soft_body->setTotalMass(body->mass);
2241 }
2242 
2243 static Eina_List *
_ephysics_body_slices_add(EPhysics_Body * body,int slices_cnt,int * points,double delta,double max)2244 _ephysics_body_slices_add(EPhysics_Body *body, int slices_cnt, int *points, double delta, double max)
2245 {
2246    Eina_List *slices = NULL;
2247    EPhysics_Body_Soft_Body_Slice *slice;
2248    btSoftBody::tFaceArray faces;
2249 
2250    for (int i = 0; i < slices_cnt; i++)
2251      {
2252         faces = body->soft_body->m_faces;
2253 
2254         slice = _ephysics_body_soft_body_slice_new(body, delta, max,
2255                                                    points[i]);
2256         if (!slice) goto no_slices;
2257 
2258         slices = eina_list_append(slices, slice);
2259      }
2260    return slices;
2261 
2262  no_slices:
2263    _ephysics_body_soft_body_slices_clean(slices);
2264    return NULL;
2265 }
2266 
2267 EAPI void
ephysics_body_soft_body_position_iterations_set(EPhysics_Body * body,int iterations)2268 ephysics_body_soft_body_position_iterations_set(EPhysics_Body *body, int iterations)
2269 {
2270    if (!body)
2271      {
2272         ERR("Could not set the number of iterations for position solver, body "
2273             "is null.");
2274         return;
2275      }
2276 
2277    if (body->type == EPHYSICS_BODY_TYPE_RIGID)
2278      {
2279         ERR("Could not set the number of iterations for position solver, body "
2280             "must be a soft body or a cloth");
2281         return;
2282      }
2283 
2284    body->soft_body->m_cfg.piterations = iterations;
2285    DBG("Soft body position solver iterations set to: %d", iterations);
2286 }
2287 
2288 EAPI int
ephysics_body_soft_body_position_iterations_get(EPhysics_Body * body)2289 ephysics_body_soft_body_position_iterations_get(EPhysics_Body *body)
2290 {
2291    if (!body)
2292      {
2293         ERR("Could not get the number of iterations for position solver, body "
2294             "is null.");
2295         return 0;
2296      }
2297 
2298    if (body->type == EPHYSICS_BODY_TYPE_RIGID)
2299      {
2300         ERR("Could not get the number of iterations for position solver, body "
2301             "must be a soft body or a cloth");
2302         return 0;
2303      }
2304 
2305    return body->soft_body->m_cfg.piterations;
2306 }
2307 
2308 EAPI void
ephysics_body_soft_body_bending_constraints_add(EPhysics_Body * body,int number)2309 ephysics_body_soft_body_bending_constraints_add(EPhysics_Body *body, int number)
2310 {
2311    if (!body)
2312      {
2313         ERR("Could add new bending constraint, body is null.");
2314         return;
2315      }
2316 
2317    if (number <= 0)
2318      {
2319         ERR("Could not add new bending constraints, number must be greater"
2320             " than 0");
2321         return;
2322      }
2323 
2324    body->bending_constraints += number;
2325    DBG("Added new bending constraints to body: %p", body);
2326 }
2327 
2328 EAPI EPhysics_Body *
ephysics_body_cloth_add(EPhysics_World * world,unsigned short rows,unsigned short columns)2329 ephysics_body_cloth_add(EPhysics_World *world, unsigned short rows, unsigned short columns)
2330 {
2331    EPhysics_Body *body;
2332    EPhysics_Body_Face_Slice *face_slice;
2333    btSoftBodyWorldInfo *world_info;
2334    btSoftBody *soft_body;
2335    const int body_rows = (!rows) ? 15 : rows;
2336    const int body_columns = (!columns) ? 15 : columns;
2337 
2338    if (!world)
2339      {
2340         ERR("Can't add circle, world is null.");
2341         return NULL;
2342      }
2343 
2344    world_info = ephysics_world_info_get(world);
2345    soft_body = btSoftBodyHelpers::CreatePatch(*world_info,
2346                                               btVector3(2, 2, 0),
2347                                               btVector3(2, 1, 0),
2348                                               btVector3(1, 2, 0),
2349                                               btVector3(1, 1, 0),
2350                                               body_rows + 1, body_columns + 1,
2351                                               0, false);
2352 
2353    if (!soft_body)
2354      {
2355         ERR("Couldn't create a new soft body.");
2356         return NULL;
2357      }
2358 
2359    body = _ephysics_body_new(world, 1, 0.5, 0.5, 0.5);
2360    if (!body)
2361      goto no_body;
2362 
2363    soft_body->setPose(false, true);
2364 
2365    soft_body->appendMaterial();
2366    body->material_index = 1;
2367    soft_body->m_cfg.piterations = body_rows / 5;
2368 
2369    _ephysics_body_soft_body_default_config(body, soft_body);
2370    _ephysics_body_cloth_constraints_rebuild(body);
2371 
2372    face_slice = _ephysics_body_face_slice_add(body,
2373                                               EPHYSICS_BODY_CLOTH_FACE_FRONT);
2374    if (!face_slice)
2375      {
2376         ERR("Could not allocate face slice data structure.");
2377         goto no_face_slice;
2378      }
2379 
2380    face_slice->slices_cnt = soft_body->m_faces.size();
2381    face_slice->points_deform = (int *)malloc(face_slice->slices_cnt *
2382                                              sizeof(int));
2383    if (!face_slice->points_deform)
2384      {
2385         ERR("Couldn't create points of deformation.");
2386         goto no_deform;
2387      }
2388 
2389    for (int i = 0; i < face_slice->slices_cnt; i++)
2390      face_slice->points_deform[i] = i;
2391 
2392    face_slice->slices = _ephysics_body_slices_add(body, face_slice->slices_cnt,
2393                                                   face_slice->points_deform, -1,
2394                                                   1);
2395    if (!face_slice->slices)
2396      {
2397         ERR("Couldn't create slices.");
2398         goto no_slices;
2399      }
2400 
2401    body->default_face = face_slice;
2402 
2403    body->cloth_columns = body_columns;
2404    body->cloth_rows = body_rows;
2405    body->type = EPHYSICS_BODY_TYPE_CLOTH;
2406 
2407    ephysics_world_soft_body_add(world, body);
2408 
2409    return body;
2410 
2411 no_slices:
2412 no_deform:
2413    _ephysics_body_face_slice_del(face_slice);
2414  no_face_slice:
2415    free(body);
2416 no_body:
2417    delete soft_body;
2418    return NULL;
2419 }
2420 
2421 static void
_ephysics_body_soft_body_single_face_transform(btSoftBody * soft_body,int face_idx,int node_idx,btTransform trans)2422 _ephysics_body_soft_body_single_face_transform(btSoftBody *soft_body, int face_idx, int node_idx, btTransform trans)
2423 {
2424    btSoftBody::Node *node;
2425    ATTRIBUTE_ALIGNED16(btDbvtVolume) vol;
2426    const btScalar margin = soft_body->getCollisionShape()->getMargin();
2427 
2428    node = soft_body->m_faces[face_idx].m_n[node_idx];
2429 
2430    if (node->m_battach)
2431      return;
2432 
2433    node->m_x = trans * node->m_x;
2434    node->m_q = trans * node->m_q;
2435    node->m_n = trans.getBasis() * node->m_n;
2436    vol = btDbvtVolume::FromCR(node->m_x, margin);
2437    soft_body->m_ndbvt.update(node->m_leaf, vol);
2438 }
2439 
2440 void
ephysics_body_soft_body_dragging_apply(EPhysics_Body * body)2441 ephysics_body_soft_body_dragging_apply(EPhysics_Body *body)
2442 {
2443    btSoftBody::Face face;
2444    btSoftBody::Node *node;
2445 
2446    face = body->soft_body->m_faces[body->dragging_data.triangle];
2447    node = face.m_n[0];
2448    node->m_v *= 0;
2449    node->m_im *= 0;
2450 }
2451 
2452 EAPI void
ephysics_body_soft_body_triangle_move(EPhysics_Body * body,int idx,Evas_Coord x,Evas_Coord y,Evas_Coord z)2453 ephysics_body_soft_body_triangle_move(EPhysics_Body *body, int idx, Evas_Coord x, Evas_Coord y, Evas_Coord z)
2454 {
2455    btScalar xx, yy, zz;
2456    Evas_Coord wh, wy;
2457    double rate;
2458    btVector3 new_pos;
2459    btTransform diff;
2460    btSoftBody::Face face;
2461    btSoftBody::Node *node;
2462 
2463    if (body->type == EPHYSICS_BODY_TYPE_RIGID)
2464      {
2465         ERR("Could not move soft body triangle, body must be soft or cloth.");
2466         return;
2467      }
2468 
2469    if (idx < 0 || idx >= body->soft_body->m_faces.size())
2470      {
2471         ERR("Could not move soft body triangle, provided body triangle index "
2472             "ranges from 0 to %d", body->soft_body->m_faces.size());
2473         return;
2474      }
2475 
2476    rate = ephysics_world_rate_get(body->world);
2477    ephysics_world_render_geometry_get(body->world, NULL, &wy, NULL, NULL, &wh,
2478                                       NULL);
2479 
2480    xx = x / rate;
2481    yy = ((wh + wy) -  y) / rate;
2482    zz = z / rate;
2483 
2484    new_pos = btVector3(xx, yy, zz);
2485    ephysics_world_lock_take(body->world);
2486 
2487    face = body->soft_body->m_faces[idx];
2488 
2489    node = face.m_n[0];
2490    diff.setIdentity();
2491    diff.setOrigin(new_pos - node->m_x);
2492    _ephysics_body_soft_body_single_face_transform(body->soft_body, idx, 0, diff);
2493 
2494    diff.setOrigin(diff.getOrigin() * 0.1);
2495    for (int m = 0; m < body->soft_body->m_faces.size(); m++)
2496      {
2497         if (m == idx) continue;
2498         _ephysics_body_soft_body_single_face_transform(body->soft_body, m, 0,
2499                                                        diff);
2500      }
2501 
2502    body->soft_body->updateClusters();
2503    body->soft_body->updateBounds();
2504    body->soft_body->updateNormals();
2505    body->soft_body->updatePose();
2506    ephysics_world_lock_release(body->world);
2507 }
2508 
2509 EAPI Eina_List *
ephysics_body_soft_body_triangles_inside_get(const EPhysics_Body * body,Evas_Coord x,Evas_Coord y,Evas_Coord z,Evas_Coord w,Evas_Coord h,Evas_Coord d)2510 ephysics_body_soft_body_triangles_inside_get(const EPhysics_Body *body, Evas_Coord x, Evas_Coord y, Evas_Coord z, Evas_Coord w, Evas_Coord h, Evas_Coord d)
2511 {
2512    Eina_List *face_list = NULL;
2513    btSoftBody::Face *bt_face;
2514    btSoftBody::Node *node;
2515    int out, *idx;
2516    btScalar nx, ny, nz, xx, yy, zz, dd, ww, hh;
2517    Evas_Coord wy, wh;
2518    double rate;
2519 
2520    if (body->type == EPHYSICS_BODY_TYPE_RIGID)
2521      {
2522         ERR("Can't get triangle indexes, operation not permited to rigid"
2523             " bodies.");
2524         return NULL;
2525      }
2526 
2527    ephysics_world_lock_take(body->world);
2528    rate = ephysics_world_rate_get(body->world);
2529    ephysics_world_render_geometry_get(body->world, NULL, &wy, NULL, NULL, &wh,
2530                                       NULL);
2531    xx = x / rate;
2532    yy = (wy + (wh -  y)) / rate;
2533    zz = z / rate;
2534    dd = d / rate;
2535    ww = w / rate;
2536    hh = h / rate;
2537 
2538    for (int m = 0; m < body->soft_body->m_faces.size(); m++)
2539      {
2540         out = 0;
2541         bt_face = &body->soft_body->m_faces[m];
2542         for (int n = 0; n < 3; n++)
2543           {
2544              node = bt_face->m_n[n];
2545              nx = node->m_x.x();
2546              ny = node->m_x.y();
2547              nz = node->m_x.z();
2548 
2549              if ((nz < zz || nz > zz + dd) || (nx < xx || nx > xx + ww) ||
2550                  (ny > yy || ny < yy - hh))
2551                out++;
2552           }
2553 
2554         if (!out)
2555           {
2556              idx = (int *)malloc(sizeof(int));
2557              *idx = m;
2558              face_list = eina_list_append(face_list, idx);
2559           }
2560      }
2561 
2562    ephysics_world_lock_release(body->world);
2563 
2564    return face_list;
2565 }
2566 
2567 static void
_ephysics_body_soft_body_triangle_impulse_apply(EPhysics_Body * body,int idx,double x,double y,double z)2568 _ephysics_body_soft_body_triangle_impulse_apply(EPhysics_Body *body, int idx, double x, double y, double z)
2569 {
2570    btSoftBody::Face face;
2571    btSoftBody::Node *node;
2572    double rate;
2573    btVector3 impulse;
2574 
2575    rate = ephysics_world_rate_get(body->world);
2576    impulse = btVector3(x / rate, - y / rate, z / rate);
2577 
2578    face = body->soft_body->m_faces[idx];
2579    for (int i = 0; i < 3; i++)
2580      {
2581         node = face.m_n[i];
2582         node->m_v = impulse * node->m_im;
2583      }
2584 
2585    DBG("Impulse applied to soft body node(%d): %lf, %lf, %lf", idx, impulse.x(),
2586        impulse.y(), impulse.z());
2587 }
2588 
2589 EAPI void
ephysics_body_soft_body_triangle_impulse_apply(EPhysics_Body * body,int idx,double x,double y,double z)2590 ephysics_body_soft_body_triangle_impulse_apply(EPhysics_Body * body, int idx, double x, double y, double z)
2591 {
2592 
2593    if (body->type == EPHYSICS_BODY_TYPE_RIGID)
2594      {
2595         ERR("Can't apply impulse, operation not permited to rigid bodies.");
2596         return;
2597      }
2598 
2599    if (idx < 0 || idx >= body->soft_body->m_faces.size())
2600      {
2601         ERR("Could not apply impulse, provided body triangle index ranges from"
2602             " 0 to %d", body->soft_body->m_faces.size());
2603         return;
2604      }
2605 
2606    ephysics_world_lock_take(body->world);
2607    _ephysics_body_soft_body_triangle_impulse_apply(body, idx, x, y, z);
2608    ephysics_world_lock_release(body->world);
2609 }
2610 
2611 EAPI void
ephysics_body_soft_body_triangle_list_impulse_apply(EPhysics_Body * body,Eina_List * triangles,double x,double y,double z)2612 ephysics_body_soft_body_triangle_list_impulse_apply(EPhysics_Body *body, Eina_List *triangles, double x, double y, double z)
2613 {
2614    Eina_List *l;
2615    void *ldata;
2616    int idx, faces_cnt;
2617 
2618    if (body->type == EPHYSICS_BODY_TYPE_RIGID)
2619      {
2620         ERR("Can't apply impulse, operation not permited to rigid bodies.");
2621         return;
2622      }
2623 
2624    faces_cnt = body->soft_body->m_faces.size();
2625    ephysics_world_lock_take(body->world);
2626    EINA_LIST_FOREACH(triangles, l, ldata)
2627      {
2628         idx = *(int *)ldata;
2629         if (idx < 0 || idx >= faces_cnt)
2630           {
2631              INF("Could not apply impulse to triangle %d, provided body"
2632                  " triangle index ranges from 0 to %d", idx, faces_cnt);
2633              continue;
2634           }
2635 
2636         _ephysics_body_soft_body_triangle_impulse_apply(body, idx, x, y, z);
2637         DBG("Applied impulse on body %p, triangle: %d", body, idx);
2638      }
2639    ephysics_world_lock_release(body->world);
2640 }
2641 
2642 EAPI int
ephysics_body_soft_body_triangle_index_get(EPhysics_Body * body,Evas_Coord x,Evas_Coord y)2643 ephysics_body_soft_body_triangle_index_get(EPhysics_Body *body, Evas_Coord x, Evas_Coord y)
2644 {
2645    int w, h, r, c, index = -1;
2646 
2647    if (!body->evas_obj)
2648      {
2649         ERR("No evas object associated to body");
2650         return -1;
2651      }
2652 
2653    if (body->type == EPHYSICS_BODY_TYPE_RIGID)
2654      {
2655         ERR("Can't get node index, operation not permited to rigid bodies");
2656         return -1;
2657      }
2658 
2659    if (body->type == EPHYSICS_BODY_TYPE_SOFT)
2660      {
2661         ERR("Can't get node index, not implemented for soft bodies yet.");
2662         return -1;
2663      }
2664 
2665    evas_object_geometry_get(body->evas_obj, NULL, NULL, &w, &h);
2666    r = y * body->cloth_rows / h;
2667    c = (w - x) * body->cloth_columns / w;
2668 
2669    index = 2 * r + c * body->cloth_rows * 2;
2670 
2671    return index;
2672 }
2673 
2674 static EPhysics_Body_Face_Slice *
_ephysics_body_soft_sphere_face_slices_add(EPhysics_Body * body,EPhysics_Body_Face face,btVector3 center)2675 _ephysics_body_soft_sphere_face_slices_add(EPhysics_Body *body, EPhysics_Body_Face face, btVector3 center)
2676 {
2677    btSoftBody::Face *bt_face;
2678    btSoftBody::Node *node;
2679    int out;
2680    btScalar depth_limit;
2681    Eina_List *face_list = NULL;
2682    void *data;
2683    int *idx, i = 0;
2684    EPhysics_Body_Face_Slice *face_slice;
2685 
2686    depth_limit = center.z();
2687 
2688    for (int m = 0; m < body->soft_body->m_faces.size(); m++)
2689      {
2690         out = 0;
2691         bt_face = &body->soft_body->m_faces[m];
2692         for (int n = 0; n < 3; n++)
2693           {
2694              node = bt_face->m_n[n];
2695              if ((face == EPHYSICS_BODY_SPHERE_FACE_FRONT &&
2696                   node->m_x.z() > depth_limit) ||
2697                  (face == EPHYSICS_BODY_SPHERE_FACE_BACK &&
2698                   node->m_x.z() < depth_limit))
2699                out++;
2700           }
2701 
2702         if (out < 2)
2703           {
2704              idx = (int *)malloc(sizeof(int));
2705              if (!idx)
2706                goto no_deform;
2707              *idx = m;
2708              face_list = eina_list_append(face_list, idx);
2709           }
2710      }
2711 
2712    face_slice = _ephysics_body_face_slice_add(body, face);
2713    if (!face_slice)
2714      {
2715         ERR("Could not allocate face slice data structure.");
2716         goto no_deform;
2717      }
2718 
2719    face_slice->slices_cnt = eina_list_count(face_list);
2720    face_slice->points_deform = (int *)malloc(face_slice->slices_cnt *
2721                                              sizeof(int));
2722    if (!face_slice->points_deform)
2723         goto no_points_deform;
2724 
2725    EINA_LIST_FREE(face_list, data)
2726      {
2727         face_slice->points_deform[i] = *((int *)data);
2728         i++;
2729      }
2730 
2731    face_slice->slices = _ephysics_body_slices_add(body, face_slice->slices_cnt,
2732                                              face_slice->points_deform, -0.5, 1);
2733    if (!face_slice->slices)
2734      {
2735         ERR("Couldn't create slices.");
2736         goto no_points_deform;
2737      }
2738    return face_slice;
2739 
2740 no_points_deform:
2741    _ephysics_body_face_slice_del(face_slice);
2742 no_deform:
2743    EINA_LIST_FREE(face_list, data)
2744      free(data);
2745    return NULL;
2746 }
2747 
2748 EAPI EPhysics_Body *
ephysics_body_soft_sphere_add(EPhysics_World * world,int granularity)2749 ephysics_body_soft_sphere_add(EPhysics_World *world, int granularity)
2750 {
2751    EPhysics_Body *body;
2752    EPhysics_Body_Face_Slice *front_face, *back_face;
2753    btCollisionShape *shape;
2754    btSoftBodyWorldInfo *world_info;
2755    btSoftBody *soft_body;
2756    btVector3 center, radius;
2757    int body_granularity = (!granularity) ? 100 : granularity;
2758 
2759 
2760    if (!world)
2761      {
2762         ERR("Can't add soft sphere, world is null.");
2763         return NULL;
2764      }
2765 
2766    ephysics_world_lock_take(world);
2767    shape = new btCylinderShapeZ(btVector3(0.25, 0.25, 0.25));
2768 
2769    if (!shape)
2770      {
2771         ERR("Couldn't create a new cylinder shape.");
2772         goto no_collision_shape;
2773      }
2774 
2775    world_info = ephysics_world_info_get(world);
2776    center = btVector3(1, 1, 1);
2777    radius = btVector3(0.5, 0.5, 0.5);
2778    soft_body = btSoftBodyHelpers::CreateEllipsoid(*world_info, center, radius,
2779                                                   body_granularity);
2780 
2781    if (!soft_body)
2782      {
2783         ERR("Couldn't create a new soft body.");
2784         goto no_soft_body;
2785      }
2786 
2787    body = _ephysics_body_soft_body_add(world, shape, soft_body);
2788    if (!body)
2789      goto no_body;
2790 
2791    body->soft_body->setPose(false, true);
2792 
2793    front_face = _ephysics_body_soft_sphere_face_slices_add(body,
2794                              EPHYSICS_BODY_SPHERE_FACE_FRONT, center);
2795    if (!front_face)
2796      {
2797         ERR("Could not create points of deformation mapping for front face.");
2798         goto no_front_face;
2799      }
2800    body->default_face = front_face;
2801 
2802    back_face = _ephysics_body_soft_sphere_face_slices_add(body,
2803                               EPHYSICS_BODY_SPHERE_FACE_BACK, center);
2804    if (!back_face)
2805      {
2806         ERR("Could not create points of deformation mapping for back face.");
2807         goto no_back_face;
2808      }
2809 
2810    body->shape = EPHYSICS_BODY_SHAPE_SPHERE;
2811    ephysics_world_lock_release(world);
2812    return body;
2813 
2814 no_back_face:
2815    _ephysics_body_face_slice_del(front_face);
2816 no_front_face:
2817    ephysics_world_body_del(world, body);
2818 no_body:
2819    delete soft_body;
2820 no_soft_body:
2821    delete shape;
2822 no_collision_shape:
2823    ephysics_world_lock_release(world);
2824    return NULL;
2825 }
2826 
2827 EAPI EPhysics_Body *
ephysics_body_soft_cylinder_add(EPhysics_World * world)2828 ephysics_body_soft_cylinder_add(EPhysics_World *world)
2829 {
2830    EPhysics_Body *body;
2831    EPhysics_Body_Face_Slice *face_slice;
2832    btCollisionShape *shape;
2833    btSoftBodyWorldInfo *world_info;
2834    btSoftBody *soft_body;
2835    int points[19] = {16, 58, 44, 79, 97, 35, 6, 27, 45, 1, 38, 18, 21, 10, 26,
2836                      7, 86, 37, 55};
2837 
2838    if (!world)
2839      {
2840         ERR("Can't add circle, world is null.");
2841         return NULL;
2842      }
2843 
2844    ephysics_world_lock_take(world);
2845    shape = new btCylinderShapeZ(btVector3(0.5, 0.5, 0.5));
2846 
2847    if (!shape)
2848      {
2849         ERR("Couldn't create a new cylinder shape.");
2850         goto no_collision_shape;
2851      }
2852 
2853    world_info = ephysics_world_info_get(world);
2854    soft_body = btSoftBodyHelpers::CreateFromTriMesh(*world_info,
2855                         cylinder_vertices, &cylinder_indices[0][0],
2856                         CYLINDER_NUM_TRIANGLES);
2857    if (!soft_body)
2858      {
2859         ERR("Couldn't create a new soft body.");
2860         goto no_soft_body;
2861      }
2862 
2863    body = _ephysics_body_soft_body_add(world, shape, soft_body);
2864    if (!body)
2865      goto no_body;
2866 
2867    body->shape = EPHYSICS_BODY_SHAPE_CYLINDER;
2868 
2869    face_slice = _ephysics_body_face_slice_add(body,
2870                                         EPHYSICS_BODY_CYLINDER_FACE_FRONT);
2871    if (!face_slice)
2872      {
2873         ERR("Could not allocate face slice data structure.");
2874         goto no_face_slice;
2875      }
2876 
2877    face_slice->slices_cnt = 19;
2878    face_slice->points_deform = (int *)malloc(face_slice->slices_cnt *
2879                                              sizeof(int));
2880    if (!face_slice->points_deform)
2881      {
2882         ERR("Couldn't create points of deformation.");
2883         goto no_deform;
2884      }
2885 
2886    for (int i = 0; i < face_slice->slices_cnt; i++)
2887      face_slice->points_deform[i] = points[i];
2888 
2889    face_slice->slices = _ephysics_body_slices_add(body, face_slice->slices_cnt,
2890                                                  face_slice->points_deform, 0.55,
2891                                                   1.1);
2892    if (!face_slice->slices)
2893      {
2894         ERR("Couldn't create slices.");
2895         goto no_slices;
2896      }
2897 
2898    body->default_face = face_slice;
2899 
2900    ephysics_world_lock_release(world);
2901    return body;
2902 
2903 no_slices:
2904 no_deform:
2905    _ephysics_body_face_slice_del(face_slice);
2906 no_face_slice:
2907    ephysics_world_body_del(world, body);
2908 no_body:
2909    delete soft_body;
2910 no_soft_body:
2911    delete shape;
2912 no_collision_shape:
2913    ephysics_world_lock_release(world);
2914    return NULL;
2915 }
2916 
2917 EAPI EPhysics_Body *
ephysics_body_sphere_add(EPhysics_World * world)2918 ephysics_body_sphere_add(EPhysics_World *world)
2919 {
2920    btCollisionShape *collision_shape;
2921    EPhysics_Body *body;
2922 
2923    if (!world)
2924      {
2925         ERR("Can't add sphere, world is null.");
2926         return NULL;
2927      }
2928 
2929    collision_shape = new btSphereShape(0.5);
2930    if (!collision_shape)
2931      {
2932         ERR("Couldn't create a new sphere shape.");
2933         return NULL;
2934      }
2935 
2936    ephysics_world_lock_take(world);
2937    body = _ephysics_body_rigid_body_add(world, collision_shape, "sphere", 0.5,
2938                                         0.5, 0.5);
2939    body->shape = EPHYSICS_BODY_SHAPE_SPHERE;
2940    ephysics_world_lock_release(world);
2941    return body;
2942 }
2943 
2944 EAPI EPhysics_Body *
ephysics_body_cylinder_add(EPhysics_World * world)2945 ephysics_body_cylinder_add(EPhysics_World *world)
2946 {
2947    btCollisionShape *collision_shape;
2948    EPhysics_Body *body;
2949 
2950    if (!world)
2951      {
2952         ERR("Can't add cylinder, world is null.");
2953         return NULL;
2954      }
2955 
2956    collision_shape = new btCylinderShapeZ(btVector3(0.5, 0.5, 0.5));
2957    if (!collision_shape)
2958      {
2959         ERR("Couldn't create a new cylinder shape.");
2960         return NULL;
2961      }
2962 
2963    ephysics_world_lock_take(world);
2964    body = _ephysics_body_rigid_body_add(world, collision_shape, "cylinder", 0.5,
2965                                         0.5, 0.5);
2966    body->shape = EPHYSICS_BODY_SHAPE_CYLINDER;
2967    ephysics_world_lock_release(world);
2968    return body;
2969 }
2970 
2971 EAPI EPhysics_Body *
ephysics_body_soft_box_add(EPhysics_World * world)2972 ephysics_body_soft_box_add(EPhysics_World *world)
2973 {
2974    EPhysics_Body *body;
2975    EPhysics_Body_Face_Slice *face_slice = NULL;
2976    btCollisionShape *shape;
2977    btSoftBodyWorldInfo *world_info;
2978    btSoftBody *soft_body;
2979    int points[16] = {14, 85, 88, 28, 41, 55, 10, 24, 93, 79, 56, 86, 91, 8,
2980                      27, 1};
2981 
2982 
2983    if (!world)
2984      {
2985         ERR("Can't add circle, world is null.");
2986         return NULL;
2987      }
2988 
2989    ephysics_world_lock_take(world);
2990    shape = new btBoxShape(btVector3(0.25, 0.25, 0.25));
2991    if (!shape)
2992      {
2993         ERR("Couldn't create a new box shape.");
2994         goto no_collision_shape;
2995      }
2996 
2997    world_info = ephysics_world_info_get(world);
2998    soft_body = btSoftBodyHelpers::CreateFromTriMesh(*world_info,
2999                                             cube_vertices, &cube_indices[0][0],
3000                                             CUBE_NUM_TRIANGLES);
3001    if (!soft_body)
3002      {
3003         ERR("Couldn't create a new soft body.");
3004         goto no_soft_body;
3005      }
3006 
3007    body = _ephysics_body_soft_body_add(world, shape, soft_body);
3008    if (!body)
3009      goto no_body;
3010 
3011    body->shape = EPHYSICS_BODY_SHAPE_BOX;
3012 
3013    face_slice = _ephysics_body_face_slice_add(body,
3014                                               EPHYSICS_BODY_BOX_FACE_FRONT);
3015    if (!face_slice)
3016      {
3017         ERR("Could not allocate face slice data structure.");
3018         goto no_face_slice;
3019      }
3020 
3021    face_slice->slices_cnt = 16;
3022    face_slice->points_deform = (int *)malloc(face_slice->slices_cnt *
3023                                              sizeof(int));
3024    if (!face_slice->points_deform)
3025      {
3026         ERR("Couldn't create points of deformation.");
3027         goto no_deform;
3028      }
3029 
3030    for (int i = 0; i < face_slice->slices_cnt; i++)
3031      face_slice->points_deform[i] = points[i];
3032 
3033    face_slice->slices = _ephysics_body_slices_add(body, face_slice->slices_cnt,
3034                                                  face_slice->points_deform, 0.55,
3035                                                   1.1);
3036    if (!face_slice->slices)
3037      {
3038         ERR("Couldn't create slices.");
3039         goto no_slices;
3040      }
3041 
3042    body->default_face = face_slice;
3043 
3044    ephysics_world_lock_release(world);
3045    return body;
3046 
3047 no_slices:
3048 no_face_slice:
3049    if (face_slice) _ephysics_body_face_slice_del(face_slice);
3050 no_deform:
3051    ephysics_world_body_del(world, body);
3052 no_body:
3053    delete soft_body;
3054 no_soft_body:
3055    delete shape;
3056 no_collision_shape:
3057    ephysics_world_lock_release(world);
3058    return NULL;
3059 }
3060 
3061 EAPI EPhysics_Body *
ephysics_body_box_add(EPhysics_World * world)3062 ephysics_body_box_add(EPhysics_World *world)
3063 {
3064    btCollisionShape *collision_shape;
3065    EPhysics_Body *body;
3066 
3067    if (!world)
3068      {
3069         ERR("Can't add box, world is null.");
3070         return NULL;
3071      }
3072 
3073    collision_shape = new btBoxShape(btVector3(0.5, 0.5, 0.5));
3074 
3075    ephysics_world_lock_take(world);
3076    body = _ephysics_body_rigid_body_add(world, collision_shape, "box", 0.5,
3077                                         0.5, 0.5);
3078    body->shape = EPHYSICS_BODY_SHAPE_BOX;
3079    ephysics_world_lock_release(world);
3080    return body;
3081 }
3082 
3083 EAPI EPhysics_Body *
ephysics_body_shape_add(EPhysics_World * world,EPhysics_Shape * shape)3084 ephysics_body_shape_add(EPhysics_World *world, EPhysics_Shape *shape)
3085 {
3086    double max_x, max_y, max_z, min_x, min_y, min_z, cm_x, cm_y, cm_z,
3087           range_x, range_y, range_z;
3088    btConvexHullShape *full_shape, *simplified_shape;
3089    btAlignedObjectArray<btVector3> vertexes, planes;
3090    const Eina_Inlist *points;
3091    EPhysics_Point *point;
3092    EPhysics_Body *body;
3093    int array_size, i;
3094    btShapeHull *hull;
3095    btVector3 point3d;
3096    btScalar margin;
3097 
3098    if (!world)
3099      {
3100         ERR("Can't add shape, world is null.");
3101         return NULL;
3102      }
3103 
3104    if (!shape)
3105      {
3106         ERR("Can't add shape, shape is null.");
3107         return NULL;
3108      }
3109 
3110    points = ephysics_shape_points_get(shape);
3111    if (eina_inlist_count(points) < 3)
3112      {
3113         ERR("At least 3 points are required to add a shape");
3114         return NULL;
3115      }
3116 
3117    full_shape = new btConvexHullShape();
3118    if (!full_shape)
3119      {
3120         ERR("Couldn't create a generic convex shape.");
3121         return NULL;
3122      }
3123 
3124    point = EINA_INLIST_CONTAINER_GET(points, EPhysics_Point);
3125    max_x = min_x = point->x;
3126    max_y = min_y = point->y;
3127    max_z = min_z = point->z;
3128    cm_x = cm_y = cm_z = 0;
3129 
3130    /* FIXME : only vertices should be used to calculate the center of mass */
3131    EINA_INLIST_FOREACH(points, point)
3132      {
3133         if (point->x > max_x) max_x = point->x;
3134         if (point->x < min_x) min_x = point->x;
3135         if (point->y > max_y) max_y = point->y;
3136         if (point->y < min_y) min_y = point->y;
3137         if (point->z > max_z) max_z = point->z;
3138         if (point->z < min_z) min_z = point->z;
3139 
3140         cm_x += point->x;
3141         cm_y += point->y;
3142         cm_z += point->z;
3143      }
3144 
3145    cm_x /= eina_inlist_count(points);
3146    cm_y /= eina_inlist_count(points);
3147    cm_z /= eina_inlist_count(points);
3148    range_x = max_x - min_x;
3149    range_y = max_y - min_y;
3150    range_z = max_z - min_z;
3151 
3152    EINA_INLIST_FOREACH(points, point)
3153      {
3154         double x, y, z;
3155 
3156         x = (point->x - cm_x) / range_x;
3157         y = - (point->y - cm_y) / range_y;
3158         z = (point->z - cm_z) / range_z;
3159 
3160         point3d = btVector3(x, y, z);
3161         vertexes.push_back(point3d);
3162      }
3163 
3164    /* Shrink convex shape to consider margin. Otherwise it would have a gap */
3165    btGeometryUtil::getPlaneEquationsFromVertices(vertexes, planes);
3166    array_size = planes.size();
3167    for (i = 0; i < array_size; ++i)
3168      planes[i][3] += full_shape->getMargin();
3169 
3170    vertexes.clear();
3171    btGeometryUtil::getVerticesFromPlaneEquations(planes, vertexes);
3172 
3173    array_size = vertexes.size();
3174    for (i = 0; i < array_size; ++i)
3175      full_shape->addPoint(vertexes[i]);
3176 
3177    hull = new btShapeHull(full_shape);
3178    if (!hull)
3179      {
3180         delete full_shape;
3181         ERR("Couldn't create a shape hull.");
3182         return NULL;
3183      }
3184 
3185    margin = full_shape->getMargin();
3186    hull->buildHull(margin);
3187    simplified_shape = new btConvexHullShape(&(hull->getVertexPointer()->getX()),
3188                                             hull->numVertices());
3189    delete hull;
3190    delete full_shape;
3191    if (!simplified_shape)
3192      {
3193         ERR("Couldn't create a simplified shape.");
3194         return NULL;
3195      }
3196 
3197    ephysics_world_lock_take(world);
3198    body = _ephysics_body_rigid_body_add(world,
3199                                         (btCollisionShape *)simplified_shape,
3200                                         "generic", (cm_x - min_x) / range_x,
3201                                         1 - (cm_y - min_y) / range_y,
3202                                         (cm_z - min_z) / range_z);
3203    body->shape = EPHYSICS_BODY_SHAPE_CUSTOM;
3204    ephysics_world_lock_release(world);
3205    return body;
3206 }
3207 
3208 void
ephysics_body_world_boundaries_resize(EPhysics_World * world)3209 ephysics_body_world_boundaries_resize(EPhysics_World *world)
3210 {
3211    Evas_Coord x, y, z, w, h, d;
3212    EPhysics_Body *bound;
3213 
3214    ephysics_world_render_geometry_get(world, &x, &y, &z, &w, &h, &d);
3215 
3216    bound = ephysics_world_boundary_get(world, EPHYSICS_WORLD_BOUNDARY_BOTTOM);
3217    if (bound)
3218      ephysics_body_geometry_set(bound, x, y + h, z, w, 10, d);
3219 
3220    bound = ephysics_world_boundary_get(world, EPHYSICS_WORLD_BOUNDARY_RIGHT);
3221    if (bound)
3222      ephysics_body_geometry_set(bound, x + w, y, z, 10, h, d);
3223 
3224    bound = ephysics_world_boundary_get(world, EPHYSICS_WORLD_BOUNDARY_LEFT);
3225    if (bound)
3226      ephysics_body_geometry_set(bound,  x - 10, y, z, 10, h, d);
3227 
3228    bound = ephysics_world_boundary_get(world, EPHYSICS_WORLD_BOUNDARY_TOP);
3229    if (bound)
3230      ephysics_body_geometry_set(bound, x, y - 10, z, w, 10, d);
3231 
3232    bound = ephysics_world_boundary_get(world, EPHYSICS_WORLD_BOUNDARY_FRONT);
3233    if (bound)
3234      ephysics_body_geometry_set(bound, x, y, z - 10, w, h, 10);
3235 
3236    bound = ephysics_world_boundary_get(world, EPHYSICS_WORLD_BOUNDARY_BACK);
3237    if (bound)
3238      ephysics_body_geometry_set(bound, x, y, z + d, w, h, 10);
3239 }
3240 
3241 static EPhysics_Body *
_ephysics_body_boundary_add(EPhysics_World * world,EPhysics_World_Boundary boundary,Evas_Coord x,Evas_Coord y,Evas_Coord z,Evas_Coord w,Evas_Coord h,Evas_Coord d)3242 _ephysics_body_boundary_add(EPhysics_World *world, EPhysics_World_Boundary boundary, Evas_Coord x, Evas_Coord y, Evas_Coord z, Evas_Coord w, Evas_Coord h, Evas_Coord d)
3243 {
3244    EPhysics_Body *body;
3245 
3246    if (!world)
3247      {
3248         ERR("Can't add boundary, world is null.");
3249         return NULL;
3250      }
3251 
3252    body = ephysics_world_boundary_get(world, boundary);
3253    if (body)
3254      return body;
3255 
3256    body = ephysics_body_box_add(world);
3257    if (!body)
3258      return NULL;
3259 
3260    body->boundary = EINA_TRUE;
3261    ephysics_body_mass_set(body, 0);
3262    ephysics_world_boundary_set(world, boundary, body);
3263 
3264    if ((w <= 0) || (h <= 0) || (d <= 0))
3265      INF("Boundary added with default geometry. Render geometry not set yet");
3266    else
3267      ephysics_body_geometry_set(body, x, y, z, w, h, d);
3268 
3269    return body;
3270 }
3271 
3272 EAPI EPhysics_Body *
ephysics_body_top_boundary_add(EPhysics_World * world)3273 ephysics_body_top_boundary_add(EPhysics_World *world)
3274 {
3275    Evas_Coord x, y, z, w, d;
3276    EPhysics_Body *body;
3277 
3278    ephysics_world_render_geometry_get(world, &x, &y, &z, &w, NULL, &d);
3279    body =  _ephysics_body_boundary_add(world, EPHYSICS_WORLD_BOUNDARY_TOP,
3280                                        x, y - 10, z, w, 10, d);
3281    return body;
3282 }
3283 
3284 EAPI EPhysics_Body *
ephysics_body_bottom_boundary_add(EPhysics_World * world)3285 ephysics_body_bottom_boundary_add(EPhysics_World *world)
3286 {
3287    Evas_Coord x, y, z, w, h, d;
3288    EPhysics_Body *body;
3289 
3290    ephysics_world_render_geometry_get(world, &x, &y, &z, &w, &h, &d);
3291    body = _ephysics_body_boundary_add(world, EPHYSICS_WORLD_BOUNDARY_BOTTOM,
3292                                       x, y + h, z, w, 10, d);
3293    return body;
3294 }
3295 
3296 EAPI EPhysics_Body *
ephysics_body_left_boundary_add(EPhysics_World * world)3297 ephysics_body_left_boundary_add(EPhysics_World *world)
3298 {
3299    Evas_Coord x, y, z, h, d;
3300    EPhysics_Body *body;
3301 
3302    ephysics_world_render_geometry_get(world, &x, &y, &z, NULL, &h, &d);
3303    body = _ephysics_body_boundary_add(world, EPHYSICS_WORLD_BOUNDARY_LEFT,
3304                                       x - 10, y, z, 10, h, d);
3305    return body;
3306 }
3307 
3308 EAPI EPhysics_Body *
ephysics_body_right_boundary_add(EPhysics_World * world)3309 ephysics_body_right_boundary_add(EPhysics_World *world)
3310 {
3311    Evas_Coord x, y, z, w, h, d;
3312    EPhysics_Body *body;
3313 
3314    ephysics_world_render_geometry_get(world, &x, &y, &z, &w, &h, &d);
3315    body = _ephysics_body_boundary_add(world, EPHYSICS_WORLD_BOUNDARY_RIGHT,
3316                                       x + w, y, z, 10, h, d);
3317    return body;
3318 }
3319 
3320 EAPI EPhysics_Body *
ephysics_body_front_boundary_add(EPhysics_World * world)3321 ephysics_body_front_boundary_add(EPhysics_World *world)
3322 {
3323    Evas_Coord x, y, z, w, h;
3324    EPhysics_Body *body;
3325 
3326    ephysics_world_render_geometry_get(world, &x, &y, &z, &w, &h, NULL);
3327    body = _ephysics_body_boundary_add(world, EPHYSICS_WORLD_BOUNDARY_FRONT,
3328                                       x, y, z - 10, w, h, 10);
3329    return body;
3330 }
3331 
3332 EAPI EPhysics_Body *
ephysics_body_back_boundary_add(EPhysics_World * world)3333 ephysics_body_back_boundary_add(EPhysics_World *world)
3334 {
3335    Evas_Coord x, y, z, w, h, d;
3336    EPhysics_Body *body;
3337 
3338    ephysics_world_render_geometry_get(world, &x, &y, &z, &w, &h, &d);
3339    body = _ephysics_body_boundary_add(world, EPHYSICS_WORLD_BOUNDARY_BACK,
3340                                       x, y, z + d, w, h, 10);
3341    return body;
3342 }
3343 
3344 void
ephysics_orphan_body_del(EPhysics_Body * body)3345 ephysics_orphan_body_del(EPhysics_Body *body)
3346 {
3347    _ephysics_body_event_callback_call(body, EPHYSICS_CALLBACK_BODY_DEL,
3348                                       (void *) body->evas_obj);
3349    INF("Body %p deleted.", body);
3350    _ephysics_body_del(body);
3351 }
3352 
3353 EAPI void
ephysics_body_del(EPhysics_Body * body)3354 ephysics_body_del(EPhysics_Body *body)
3355 {
3356    EPhysics_World *world;
3357 
3358    if (!body)
3359      {
3360         ERR("Can't delete body, it wasn't provided.");
3361         return;
3362      }
3363 
3364    if (body->deleted) return;
3365 
3366    world = body->world;
3367    ephysics_world_lock_take(world);
3368    body->deleted = EINA_TRUE;
3369    ephysics_world_body_del(world, body);
3370    ephysics_world_lock_release(world);
3371 }
3372 
3373 EAPI void
ephysics_body_evas_object_set(EPhysics_Body * body,Evas_Object * evas_obj,Eina_Bool use_obj_pos)3374 ephysics_body_evas_object_set(EPhysics_Body *body, Evas_Object *evas_obj, Eina_Bool use_obj_pos)
3375 {
3376    int obj_x, obj_y, obj_w, obj_h, bz, bd;
3377    double rate;
3378 
3379    if (!body)
3380      {
3381         ERR("Can't set evas object to body, the last wasn't provided.");
3382         return;
3383      }
3384 
3385    if (!evas_obj)
3386      {
3387         ERR("Can't set evas object to body, the first wasn't provided.");
3388         return;
3389      }
3390 
3391    if (body->evas_obj)
3392      {
3393         evas_object_map_enable_set(body->evas_obj, EINA_FALSE);
3394         evas_object_event_callback_del(body->evas_obj, EVAS_CALLBACK_DEL,
3395                                        _ephysics_body_efl_canvas_object_del_cb);
3396         evas_object_event_callback_del(body->evas_obj, EVAS_CALLBACK_RESIZE,
3397                                        _ephysics_body_efl_canvas_object_resize_cb);
3398         if (body->default_face)
3399           {
3400              evas_object_event_callback_del(body->evas_obj,
3401                                        EVAS_CALLBACK_RESTACK,
3402                                        _ephysics_body_soft_body_evas_restack_cb);
3403              _ephysics_body_soft_body_slices_clean(body->default_face->slices);
3404           }
3405      }
3406 
3407    body->evas_obj = evas_obj;
3408    evas_object_event_callback_add(evas_obj, EVAS_CALLBACK_DEL,
3409                                   _ephysics_body_efl_canvas_object_del_cb, body);
3410 
3411    if (body->soft_body)
3412      {
3413         evas_object_geometry_get(body->evas_obj, &obj_x, &obj_y, &obj_w, &obj_h);
3414         if (!obj_w && !obj_h) evas_object_resize(body->evas_obj, 1, 1);
3415 
3416         evas_object_event_callback_add(body->evas_obj, EVAS_CALLBACK_RESTACK,
3417                                  _ephysics_body_soft_body_evas_restack_cb, body);
3418         _ephysics_body_soft_body_slices_init(body, body->evas_obj,
3419                                              body->default_face->slices);
3420      }
3421 
3422    if (!use_obj_pos)
3423      return;
3424 
3425    rate = ephysics_world_rate_get(body->world);
3426    evas_object_geometry_get(body->evas_obj, &obj_x, &obj_y, &obj_w, &obj_h);
3427    ephysics_body_geometry_get(body, NULL, NULL, &bz, NULL, NULL, &bd);
3428 
3429    ephysics_world_lock_take(body->world);
3430    _ephysics_body_geometry_set(body, obj_x, obj_y, bz, obj_w, obj_h, bd, rate);
3431    ephysics_world_lock_release(body->world);
3432    evas_object_event_callback_add(body->evas_obj, EVAS_CALLBACK_RESIZE,
3433                                   _ephysics_body_efl_canvas_object_resize_cb, body);
3434 }
3435 
3436 EAPI Evas_Object *
ephysics_body_evas_object_unset(EPhysics_Body * body)3437 ephysics_body_evas_object_unset(EPhysics_Body *body)
3438 {
3439    Evas_Object *obj;
3440 
3441    if (!body)
3442      {
3443         ERR("Can't unset evas object from body, it wasn't provided.");
3444         return NULL;
3445      }
3446 
3447    obj = body->evas_obj;
3448    body->evas_obj = NULL;
3449 
3450    if (obj)
3451      {
3452         evas_object_event_callback_del(obj, EVAS_CALLBACK_DEL,
3453                                        _ephysics_body_efl_canvas_object_del_cb);
3454         evas_object_event_callback_del(obj, EVAS_CALLBACK_RESIZE,
3455                                        _ephysics_body_efl_canvas_object_resize_cb);
3456         evas_object_map_enable_set(obj, EINA_FALSE);
3457      }
3458 
3459    if (body->default_face)
3460      {
3461         evas_object_event_callback_del(body->evas_obj,
3462                                        EVAS_CALLBACK_RESTACK,
3463                                        _ephysics_body_soft_body_evas_restack_cb);
3464         _ephysics_body_soft_body_slices_clean(body->default_face->slices);
3465      }
3466 
3467    return obj;
3468 }
3469 
3470 EAPI Evas_Object *
ephysics_body_evas_object_get(const EPhysics_Body * body)3471 ephysics_body_evas_object_get(const EPhysics_Body *body)
3472 {
3473    if (!body)
3474      {
3475         ERR("Can't get evas object from body, it wasn't provided.");
3476         return NULL;
3477      }
3478 
3479    return body->evas_obj;
3480 }
3481 
3482 EAPI void
ephysics_body_geometry_set(EPhysics_Body * body,Evas_Coord x,Evas_Coord y,Evas_Coord z,Evas_Coord w,Evas_Coord h,Evas_Coord d)3483 ephysics_body_geometry_set(EPhysics_Body *body, Evas_Coord x, Evas_Coord y, Evas_Coord z, Evas_Coord w, Evas_Coord h, Evas_Coord d)
3484 {
3485    if (!body)
3486      {
3487         ERR("Can't set body geometry, body is null.");
3488         return;
3489      }
3490 
3491    INF("Body: %p geometry set to x=%i y=%i z=%i w=%i h=%i d=%i.",
3492        body, x, y, z, w, h, d);
3493 
3494    if ((w <= 0) || (h <= 0) || (d <= 0))
3495      {
3496         ERR("Width, height and depth must to be a non-null, positive value.");
3497         return;
3498      }
3499 
3500    ephysics_world_lock_take(body->world);
3501    _ephysics_body_geometry_set(body, x, y, z, w, h, d,
3502                                ephysics_world_rate_get(body->world));
3503    ephysics_world_lock_release(body->world);
3504 }
3505 
3506 EAPI void
ephysics_body_resize(EPhysics_Body * body,Evas_Coord w,Evas_Coord h,Evas_Coord d)3507 ephysics_body_resize(EPhysics_Body *body, Evas_Coord w, Evas_Coord h, Evas_Coord d)
3508 {
3509    if (!body)
3510      {
3511         ERR("Can't set body size, body is null.");
3512         return;
3513      }
3514 
3515    if ((w <= 0) || (h <= 0) || (d <= 0))
3516      {
3517         ERR("Width, height and depth must to be a non-null, positive value.");
3518         return;
3519      }
3520 
3521    ephysics_world_lock_take(body->world);
3522    _ephysics_body_resize(body, w, h, d);
3523    ephysics_world_lock_release(body->world);
3524 }
3525 
3526 EAPI void
ephysics_body_move(EPhysics_Body * body,Evas_Coord x,Evas_Coord y,Evas_Coord z)3527 ephysics_body_move(EPhysics_Body *body, Evas_Coord x, Evas_Coord y, Evas_Coord z)
3528 {
3529    if (!body)
3530      {
3531         ERR("Can't set body position, body is null.");
3532         return;
3533      }
3534 
3535    ephysics_world_lock_take(body->world);
3536    _ephysics_body_move(body, x, y, z);
3537    ephysics_world_lock_release(body->world);
3538 }
3539 
3540 EAPI void
ephysics_body_geometry_get(const EPhysics_Body * body,Evas_Coord * x,Evas_Coord * y,Evas_Coord * z,Evas_Coord * w,Evas_Coord * h,Evas_Coord * d)3541 ephysics_body_geometry_get(const EPhysics_Body *body, Evas_Coord *x, Evas_Coord *y, Evas_Coord *z, Evas_Coord *w, Evas_Coord *h, Evas_Coord *d)
3542 {
3543    btTransform trans;
3544    btVector3 scale;
3545    double rate;
3546    int wy, height;
3547 
3548    if (!body)
3549      {
3550         ERR("Can't get body position, body is null.");
3551         return;
3552      }
3553 
3554    trans = _ephysics_body_transform_get(body);
3555    scale = btVector3(body->scale[0], body->scale[1], body->scale[2]);
3556 
3557    rate = ephysics_world_rate_get(body->world);
3558    ephysics_world_render_geometry_get(body->world, NULL, &wy, NULL,
3559                                       NULL, &height, NULL);
3560    height += wy;
3561 
3562    if (x) *x = round((trans.getOrigin().getX() - scale[0] / 2) * rate);
3563    if (y) *y = height - round((trans.getOrigin().getY() + scale[1] / 2)
3564                               * rate);
3565    if (z) *z = round((trans.getOrigin().getZ() - scale[2] / 2) * rate);
3566    if (w) *w = body->size.w;
3567    if (h) *h = body->size.h;
3568    if (d) *d = body->size.d;
3569 }
3570 
3571 EAPI void
ephysics_body_mass_set(EPhysics_Body * body,double mass)3572 ephysics_body_mass_set(EPhysics_Body *body, double mass)
3573 {
3574    if (!body)
3575      {
3576         ERR("Can't set body mass, body is null.");
3577         return;
3578      }
3579 
3580    if (mass < 0)
3581      {
3582         ERR("Can't set body's mass, it must to be non-negative.");
3583         return;
3584      }
3585 
3586    ephysics_world_lock_take(body->world);
3587    body->material = EPHYSICS_BODY_MATERIAL_CUSTOM;
3588    body->density = 0;
3589    _ephysics_body_mass_set(body, mass);
3590    ephysics_world_lock_release(body->world);
3591 }
3592 
3593 EAPI double
ephysics_body_mass_get(const EPhysics_Body * body)3594 ephysics_body_mass_get(const EPhysics_Body *body)
3595 {
3596    if (!body)
3597      {
3598         ERR("Can't get body mass, body is null.");
3599         return 0;
3600      }
3601 
3602    return body->mass;
3603 }
3604 
3605 EAPI void
ephysics_body_linear_velocity_set(EPhysics_Body * body,double x,double y,double z)3606 ephysics_body_linear_velocity_set(EPhysics_Body *body, double x, double y, double z)
3607 {
3608    if (!body)
3609      {
3610         ERR("Can't set body linear velocity, body is null.");
3611         return;
3612      }
3613 
3614    _ephysics_body_linear_velocity_set(body, x, y, z,
3615                                       ephysics_world_rate_get(body->world));
3616    DBG("Linear velocity of body %p set to (%lf, %lf, %lf).", body, x, y, z);
3617 }
3618 
3619 static void
_ephysics_body_soft_body_linear_velocity_get(const EPhysics_Body * body,double * x,double * y,double * z,double rate)3620 _ephysics_body_soft_body_linear_velocity_get(const EPhysics_Body *body, double *x, double *y, double *z, double rate)
3621 {
3622    btVector3 total_velocity = btVector3(0, 0, 0);
3623    int nodes_size = body->soft_body->m_nodes.size();
3624 
3625    for (int i = 0; i < nodes_size; i++)
3626      total_velocity += body->soft_body->m_nodes[i].m_v;
3627 
3628    total_velocity /= nodes_size;
3629    if (x) *x = total_velocity.getX() * rate;
3630    if (y) *y = -total_velocity.getY() * rate;
3631    if (z) *z = total_velocity.getZ() * rate;
3632 }
3633 
3634 EAPI void
ephysics_body_linear_velocity_get(const EPhysics_Body * body,double * x,double * y,double * z)3635 ephysics_body_linear_velocity_get(const EPhysics_Body *body, double *x, double *y, double *z)
3636 {
3637    double rate;
3638 
3639    if (!body)
3640      {
3641         ERR("Can't get linear velocity, body is null.");
3642         return;
3643      }
3644 
3645    rate = ephysics_world_rate_get(body->world);
3646    if (body->rigid_body)
3647      {
3648         if (x) *x = body->rigid_body->getLinearVelocity().getX() * rate;
3649         if (y) *y = -body->rigid_body->getLinearVelocity().getY() * rate;
3650         if (z) *z = body->rigid_body->getLinearVelocity().getZ() * rate;
3651         return;
3652      }
3653    _ephysics_body_soft_body_linear_velocity_get(body, x, y, z, rate);
3654 }
3655 
3656 EAPI void
ephysics_body_angular_velocity_set(EPhysics_Body * body,double x,double y,double z)3657 ephysics_body_angular_velocity_set(EPhysics_Body *body, double x, double y, double z)
3658 {
3659    if (!body)
3660      {
3661         ERR("Can't set angular velocity, body is null.");
3662         return;
3663      }
3664 
3665    BODY_CLOTH_CHECK();
3666 
3667    ephysics_world_lock_take(body->world);
3668    ephysics_body_activate(body, EINA_TRUE);
3669    body->rigid_body->setAngularVelocity(btVector3(-x / RAD_TO_DEG,
3670                                                   -y / RAD_TO_DEG,
3671                                                   -z/RAD_TO_DEG));
3672 
3673    DBG("Angular velocity of body %p set to (%lf, %lf, %lf).", body, x, y, z);
3674    ephysics_world_lock_release(body->world);
3675 }
3676 
3677 EAPI void
ephysics_body_angular_velocity_get(const EPhysics_Body * body,double * x,double * y,double * z)3678 ephysics_body_angular_velocity_get(const EPhysics_Body *body, double *x, double *y, double *z)
3679 {
3680    if (!body)
3681      {
3682         ERR("Can't get angular velocity, body is null.");
3683         return;
3684      }
3685 
3686    BODY_CLOTH_CHECK();
3687 
3688    if (x) *x = -body->rigid_body->getAngularVelocity().getX() * RAD_TO_DEG;
3689    if (y) *y = -body->rigid_body->getAngularVelocity().getY() * RAD_TO_DEG;
3690    if (z) *z = -body->rigid_body->getAngularVelocity().getZ() * RAD_TO_DEG;
3691 }
3692 
3693 EAPI void
ephysics_body_sleeping_threshold_set(EPhysics_Body * body,double linear_threshold,double angular_threshold)3694 ephysics_body_sleeping_threshold_set(EPhysics_Body *body, double linear_threshold, double angular_threshold)
3695 {
3696    if (!body)
3697      {
3698         ERR("Can't set sleeping thresholds, body is null.");
3699         return;
3700      }
3701 
3702    BODY_CLOTH_CHECK();
3703 
3704    ephysics_world_lock_take(body->world);
3705    _ephysics_body_sleeping_threshold_set(body, linear_threshold,
3706                                          angular_threshold,
3707                                          ephysics_world_rate_get(body->world));
3708    ephysics_world_lock_release(body->world);
3709 }
3710 
3711 EAPI void
ephysics_body_sleeping_threshold_get(const EPhysics_Body * body,double * linear_threshold,double * angular_threshold)3712 ephysics_body_sleeping_threshold_get(const EPhysics_Body *body, double *linear_threshold, double *angular_threshold)
3713 {
3714    double rate;
3715 
3716    if (!body)
3717      {
3718         ERR("Can't get linear sleeping threshold, body is null.");
3719         return;
3720      }
3721 
3722    BODY_CLOTH_CHECK();
3723 
3724    rate = ephysics_world_rate_get(body->world);
3725    if (linear_threshold)
3726      *linear_threshold = body->rigid_body->getLinearSleepingThreshold() * rate;
3727    if (angular_threshold)
3728      *angular_threshold = body->rigid_body->getAngularSleepingThreshold() *
3729         RAD_TO_DEG;
3730 }
3731 
3732 EAPI void
ephysics_body_stop(EPhysics_Body * body)3733 ephysics_body_stop(EPhysics_Body *body)
3734 {
3735    if (!body)
3736      {
3737         ERR("Can't stop a null body.");
3738         return;
3739      }
3740 
3741    ephysics_world_lock_take(body->world);
3742    if (body->rigid_body)
3743      {
3744         body->rigid_body->setLinearVelocity(btVector3(0, 0, 0));
3745         body->rigid_body->setAngularVelocity(btVector3(0, 0, 0));
3746      }
3747 
3748    if (body->soft_body)
3749      {
3750         for (int i = 0; i < body->soft_body->m_nodes.size(); i++)
3751           {
3752              body->soft_body->m_nodes[i].m_v *= 0;
3753              body->soft_body->m_nodes[i].m_f *= 0;
3754           }
3755      }
3756    ephysics_world_lock_release(body->world);
3757 
3758    DBG("Body %p stopped", body);
3759 }
3760 
3761 EAPI void
ephysics_body_damping_set(EPhysics_Body * body,double linear_damping,double angular_damping)3762 ephysics_body_damping_set(EPhysics_Body *body, double linear_damping, double angular_damping)
3763 {
3764    if (!body)
3765      {
3766         ERR("Can't set body damping, body is null.");
3767         return;
3768      }
3769 
3770    BODY_CLOTH_CHECK();
3771 
3772    ephysics_world_lock_take(body->world);
3773    body->rigid_body->setDamping(btScalar(linear_damping),
3774                                 btScalar(angular_damping));
3775    ephysics_world_lock_release(body->world);
3776 }
3777 
3778 EAPI void
ephysics_body_damping_get(const EPhysics_Body * body,double * linear_damping,double * angular_damping)3779 ephysics_body_damping_get(const EPhysics_Body *body, double *linear_damping, double *angular_damping)
3780 {
3781    if (!body)
3782      {
3783         ERR("Can't get damping, body is null.");
3784         return;
3785      }
3786 
3787    BODY_CLOTH_CHECK();
3788 
3789    if (linear_damping) *linear_damping = body->rigid_body->getLinearDamping();
3790    if (angular_damping) *angular_damping =
3791      body->rigid_body->getAngularDamping();
3792 }
3793 
3794 EAPI void
ephysics_body_evas_object_update(EPhysics_Body * body)3795 ephysics_body_evas_object_update(EPhysics_Body *body)
3796 {
3797    if (!body)
3798      {
3799         ERR("Couldn't update a null body.");
3800         return;
3801      }
3802 
3803    _ephysics_body_evas_object_default_update(body);
3804 }
3805 
3806 EAPI void
ephysics_body_event_callback_add(EPhysics_Body * body,EPhysics_Callback_Body_Type type,EPhysics_Body_Event_Cb func,const void * data)3807 ephysics_body_event_callback_add(EPhysics_Body *body, EPhysics_Callback_Body_Type type, EPhysics_Body_Event_Cb func, const void *data)
3808 {
3809    EPhysics_Body_Callback *cb;
3810 
3811    if (!body)
3812      {
3813         ERR("Can't set body event callback, body is null.");
3814         return;
3815      }
3816 
3817    if (!func)
3818      {
3819         ERR("Can't set body event callback, function is null.");
3820         return;
3821      }
3822 
3823    if ((type < 0) || (type >= EPHYSICS_CALLBACK_BODY_LAST))
3824      {
3825         ERR("Can't set body event callback, callback type is wrong.");
3826         return;
3827      }
3828 
3829    cb = (EPhysics_Body_Callback *)calloc(1, sizeof(EPhysics_Body_Callback));
3830    if (!cb)
3831      {
3832         ERR("Can't set body event callback, can't create cb instance.");
3833         return;
3834      }
3835 
3836    cb->func = func;
3837    cb->type = type;
3838    cb->data = (void *)data;
3839 
3840    body->callbacks = eina_inlist_append(body->callbacks, EINA_INLIST_GET(cb));
3841    if (type == EPHYSICS_CALLBACK_BODY_COLLISION)
3842        body->collision_cb++;
3843 }
3844 
3845 EAPI void *
ephysics_body_event_callback_del(EPhysics_Body * body,EPhysics_Callback_Body_Type type,EPhysics_Body_Event_Cb func)3846 ephysics_body_event_callback_del(EPhysics_Body *body, EPhysics_Callback_Body_Type type, EPhysics_Body_Event_Cb func)
3847 {
3848    EPhysics_Body_Callback *cb;
3849    void *cb_data = NULL;
3850 
3851    if (!body)
3852      {
3853         ERR("Can't delete body event callback, body is null.");
3854         return NULL;
3855      }
3856 
3857    EINA_INLIST_FOREACH(body->callbacks, cb)
3858      {
3859         if ((cb->type != type) || (cb->func != func))
3860           continue;
3861 
3862         cb_data = cb->data;
3863         _ephysics_body_event_callback_del(body, cb);
3864         if (type == EPHYSICS_CALLBACK_BODY_COLLISION)
3865             body->collision_cb--;
3866         break;
3867      }
3868 
3869    return cb_data;
3870 }
3871 
3872 EAPI void *
ephysics_body_event_callback_del_full(EPhysics_Body * body,EPhysics_Callback_Body_Type type,EPhysics_Body_Event_Cb func,void * data)3873 ephysics_body_event_callback_del_full(EPhysics_Body *body, EPhysics_Callback_Body_Type type, EPhysics_Body_Event_Cb func, void *data)
3874 {
3875    EPhysics_Body_Callback *cb;
3876    void *cb_data = NULL;
3877 
3878    if (!body)
3879      {
3880         ERR("Can't delete body event callback, body is null.");
3881         return NULL;
3882      }
3883 
3884    EINA_INLIST_FOREACH(body->callbacks, cb)
3885      {
3886         if ((cb->type != type) || (cb->func != func) || (cb->data != data))
3887           continue;
3888 
3889         cb_data = cb->data;
3890         _ephysics_body_event_callback_del(body, cb);
3891         break;
3892      }
3893 
3894    return cb_data;
3895 }
3896 
3897 static void
_ephysics_body_restitution_set(EPhysics_Body * body,double restitution)3898 _ephysics_body_restitution_set(EPhysics_Body *body, double restitution)
3899 {
3900    DBG("Body %p restitution set to %lf", body, restitution);
3901    if (body->type == EPHYSICS_BODY_TYPE_RIGID)
3902      {
3903         body->rigid_body->setRestitution(btScalar(restitution));
3904         return;
3905      }
3906 
3907    body->soft_body->setRestitution(btScalar(restitution));
3908 }
3909 
3910 EAPI void
ephysics_body_restitution_set(EPhysics_Body * body,double restitution)3911 ephysics_body_restitution_set(EPhysics_Body *body, double restitution)
3912 {
3913    if (!body)
3914      {
3915         ERR("Can't set body restitution, body is null.");
3916         return;
3917      }
3918 
3919    ephysics_world_lock_take(body->world);
3920    body->material = EPHYSICS_BODY_MATERIAL_CUSTOM;
3921    _ephysics_body_restitution_set(body, restitution);
3922    ephysics_world_lock_release(body->world);
3923 }
3924 
3925 EAPI double
ephysics_body_restitution_get(const EPhysics_Body * body)3926 ephysics_body_restitution_get(const EPhysics_Body *body)
3927 {
3928    if (!body)
3929      {
3930         ERR("Can't get body restitution, body is null.");
3931         return 0;
3932      }
3933 
3934    if (body->type == EPHYSICS_BODY_TYPE_RIGID)
3935      return body->rigid_body->getRestitution();
3936 
3937    return body->soft_body->getRestitution();
3938 }
3939 
3940 static void
_ephysics_body_friction_set(EPhysics_Body * body,double friction)3941 _ephysics_body_friction_set(EPhysics_Body *body, double friction)
3942 {
3943    DBG("Body %p friction set to %lf", body, friction);
3944    if (body->type == EPHYSICS_BODY_TYPE_RIGID)
3945      {
3946         body->rigid_body->setFriction(btScalar(friction));
3947         return;
3948      }
3949 
3950    body->soft_body->setFriction(btScalar(friction));
3951 }
3952 
3953 EAPI void
ephysics_body_friction_set(EPhysics_Body * body,double friction)3954 ephysics_body_friction_set(EPhysics_Body *body, double friction)
3955 {
3956    if (!body)
3957      {
3958         ERR("Can't set body friction, body is null.");
3959         return;
3960      }
3961 
3962    ephysics_world_lock_take(body->world);
3963    body->material = EPHYSICS_BODY_MATERIAL_CUSTOM;
3964    _ephysics_body_friction_set(body, friction);
3965    ephysics_world_lock_release(body->world);
3966 }
3967 
3968 EAPI double
ephysics_body_friction_get(const EPhysics_Body * body)3969 ephysics_body_friction_get(const EPhysics_Body *body)
3970 {
3971    if (!body)
3972      {
3973         ERR("Can't get body friction, body is null.");
3974         return 0;
3975      }
3976 
3977    if (body->type == EPHYSICS_BODY_TYPE_RIGID)
3978      return body->rigid_body->getFriction();
3979 
3980    return body->soft_body->getFriction();
3981 }
3982 
3983 EAPI EPhysics_World *
ephysics_body_world_get(const EPhysics_Body * body)3984 ephysics_body_world_get(const EPhysics_Body *body)
3985 {
3986    if (!body)
3987      {
3988         ERR("Can't get the world a null body belongs to.");
3989         return NULL;
3990      }
3991 
3992    return body->world;
3993 }
3994 
3995 static void
_ephysics_body_soft_body_central_impulse_apply(EPhysics_Body * body,btVector3 impulse)3996 _ephysics_body_soft_body_central_impulse_apply(EPhysics_Body *body, btVector3 impulse)
3997 {
3998    btSoftBody::Face *face;
3999 
4000    for (int m = 0; m < body->soft_body->m_faces.size(); m++)
4001      {
4002         face = &body->soft_body->m_faces[m];
4003         for (int n = 0; n < 3; n++)
4004              face->m_n[n]->m_v += impulse * face->m_n[n]->m_im;
4005      }
4006 }
4007 
4008 EAPI void
ephysics_body_central_impulse_apply(EPhysics_Body * body,double x,double y,double z)4009 ephysics_body_central_impulse_apply(EPhysics_Body *body, double x, double y, double z)
4010 {
4011    double rate;
4012    btVector3 impulse;
4013 
4014    if (!body)
4015      {
4016         ERR("Can't apply impulse to a null body.");
4017         return;
4018      }
4019 
4020    rate = ephysics_world_rate_get(body->world);
4021 
4022    ephysics_world_lock_take(body->world);
4023    ephysics_body_activate(body, EINA_TRUE);
4024 
4025    impulse = btVector3(x / rate, - y / rate, z / rate);
4026 
4027    if (body->type == EPHYSICS_BODY_TYPE_CLOTH)
4028      _ephysics_body_soft_body_central_impulse_apply(body, impulse);
4029    else
4030      body->rigid_body->applyCentralImpulse(impulse);
4031 
4032    ephysics_world_lock_release(body->world);
4033 }
4034 
4035 EAPI void
ephysics_body_impulse_apply(EPhysics_Body * body,double x,double y,double z,Evas_Coord pos_x,Evas_Coord pos_y,Evas_Coord pos_z)4036 ephysics_body_impulse_apply(EPhysics_Body *body, double x, double y, double z, Evas_Coord pos_x, Evas_Coord pos_y, Evas_Coord pos_z)
4037 {
4038    double rate;
4039 
4040    if (!body)
4041      {
4042         ERR("Can't apply impulse to a null body.");
4043         return;
4044      }
4045 
4046    rate = ephysics_world_rate_get(body->world);
4047 
4048    ephysics_world_lock_take(body->world);
4049    ephysics_body_activate(body, EINA_TRUE);
4050    body->rigid_body->applyImpulse(btVector3(x / rate, - y / rate, z / rate),
4051                                   btVector3((double) pos_x / rate,
4052                                             (double) pos_y / rate,
4053                                             (double) pos_z / rate));
4054    ephysics_world_lock_release(body->world);
4055 }
4056 
4057 EAPI void
ephysics_body_linear_movement_enable_set(EPhysics_Body * body,Eina_Bool enable_x,Eina_Bool enable_y,Eina_Bool enable_z)4058 ephysics_body_linear_movement_enable_set(EPhysics_Body *body, Eina_Bool enable_x, Eina_Bool enable_y, Eina_Bool enable_z)
4059 {
4060    if (!body)
4061      {
4062         ERR("Can't set linear factor on a null body.");
4063         return;
4064      }
4065 
4066    BODY_CLOTH_CHECK();
4067 
4068    ephysics_world_lock_take(body->world);
4069    body->rigid_body->setLinearFactor(btVector3(!!enable_x, !!enable_y,
4070                                                !!enable_z));
4071    ephysics_world_lock_release(body->world);
4072 }
4073 
4074 EAPI void
ephysics_body_linear_movement_enable_get(const EPhysics_Body * body,Eina_Bool * enable_x,Eina_Bool * enable_y,Eina_Bool * enable_z)4075 ephysics_body_linear_movement_enable_get(const EPhysics_Body *body, Eina_Bool *enable_x, Eina_Bool *enable_y, Eina_Bool *enable_z)
4076 {
4077    if (!body)
4078      {
4079         ERR("Can't check if linear factor is enabled, body is null.");
4080         return;
4081      }
4082 
4083    BODY_CLOTH_CHECK();
4084 
4085    if (enable_x) *enable_x = !!body->rigid_body->getLinearFactor().x();
4086    if (enable_y) *enable_y = !!body->rigid_body->getLinearFactor().y();
4087    if (enable_z) *enable_z = !!body->rigid_body->getLinearFactor().z();
4088 }
4089 
4090 EAPI void
ephysics_body_torque_impulse_apply(EPhysics_Body * body,double pitch,double yaw,double roll)4091 ephysics_body_torque_impulse_apply(EPhysics_Body *body, double pitch, double yaw, double roll)
4092 {
4093    if (!body)
4094      {
4095         ERR("Can't apply torque impulse to a null body.");
4096         return;
4097      }
4098 
4099    ephysics_world_lock_take(body->world);
4100    ephysics_body_activate(body, EINA_TRUE);
4101    body->rigid_body->applyTorqueImpulse(btVector3(-pitch, -yaw, -roll));
4102    ephysics_world_lock_release(body->world);
4103 }
4104 
4105 EAPI void
ephysics_body_angular_movement_enable_set(EPhysics_Body * body,Eina_Bool enable_x,Eina_Bool enable_y,Eina_Bool enable_z)4106 ephysics_body_angular_movement_enable_set(EPhysics_Body *body, Eina_Bool enable_x, Eina_Bool enable_y, Eina_Bool enable_z)
4107 {
4108    if (!body)
4109      {
4110         ERR("Can't set rotation on a null body.");
4111         return;
4112      }
4113 
4114    BODY_CLOTH_CHECK();
4115 
4116    ephysics_world_lock_take(body->world);
4117    body->rigid_body->setAngularFactor(btVector3(!!enable_x, !!enable_y,
4118                                                 !!enable_z));
4119    ephysics_world_lock_release(body->world);
4120 }
4121 
4122 EAPI void
ephysics_body_angular_movement_enable_get(const EPhysics_Body * body,Eina_Bool * enable_x,Eina_Bool * enable_y,Eina_Bool * enable_z)4123 ephysics_body_angular_movement_enable_get(const EPhysics_Body *body, Eina_Bool *enable_x, Eina_Bool *enable_y, Eina_Bool *enable_z)
4124 {
4125    if (!body)
4126      {
4127         ERR("Can't check if rotation is enabled, body is null.");
4128         return;
4129      }
4130 
4131    BODY_CLOTH_CHECK();
4132 
4133    if (enable_x) *enable_x = !!body->rigid_body->getAngularFactor().x();
4134    if (enable_y) *enable_y = !!body->rigid_body->getAngularFactor().y();
4135    if (enable_z) *enable_z = !!body->rigid_body->getAngularFactor().z();
4136 }
4137 
4138 EAPI EPhysics_Quaternion *
ephysics_body_rotation_get(const EPhysics_Body * body,EPhysics_Quaternion * rotation)4139 ephysics_body_rotation_get(const EPhysics_Body *body, EPhysics_Quaternion *rotation)
4140 {
4141    EPhysics_Quaternion *quat;
4142    btTransform trans;
4143 
4144    if (!body)
4145      {
4146         ERR("Can't get rotation, body is null.");
4147         return NULL;
4148      }
4149 
4150    if (!rotation)
4151      {
4152         quat = ephysics_quaternion_new();
4153         if (!quat) return NULL;
4154      }
4155    else
4156      quat = rotation;
4157 
4158    trans = _ephysics_body_transform_get(body);
4159    quat->x = trans.getRotation().x();
4160    quat->y = trans.getRotation().y();
4161    quat->z = trans.getRotation().z();
4162    quat->w = trans.getRotation().getW();
4163 
4164    return quat;
4165 }
4166 
4167 static void
_ephysics_body_soft_body_rotation_set(EPhysics_Body * body,btTransform trans)4168 _ephysics_body_soft_body_rotation_set(EPhysics_Body *body, btTransform trans)
4169 {
4170    btSoftBody::Node *node;
4171    const btScalar margin= body->soft_body->getCollisionShape()->getMargin();
4172    ATTRIBUTE_ALIGNED16(btDbvtVolume) vol;
4173 
4174    for (int i = 0; i < body->soft_body->m_nodes.size(); i++)
4175      {
4176         node = &body->soft_body->m_nodes[i];
4177         node->m_n = (trans.getBasis() * btVector3(1, 1, 1));
4178         vol = btDbvtVolume::FromCR(node->m_x, margin);
4179 
4180         body->soft_body->m_ndbvt.update(node->m_leaf, vol);
4181      }
4182 
4183    body->soft_body->updateNormals();
4184    body->soft_body->updateBounds();
4185    body->soft_body->updateConstants();
4186 }
4187 
4188 EAPI void
ephysics_body_rotation_set(EPhysics_Body * body,EPhysics_Quaternion * quat)4189 ephysics_body_rotation_set(EPhysics_Body *body, EPhysics_Quaternion *quat)
4190 {
4191    btQuaternion bt_quat;
4192    btTransform trans;
4193    double x, y, z, w;
4194 
4195    if (!body)
4196      {
4197         ERR("Can't set rotation, body is null.");
4198         return;
4199      }
4200 
4201    if (!quat)
4202      {
4203         ERR("Can't set rotation, quaternion is null.");
4204         return;
4205      }
4206 
4207    ephysics_quaternion_get(quat, &x, &y, &z, &w);
4208 
4209    ephysics_world_lock_take(body->world);
4210    ephysics_body_activate(body, EINA_TRUE);
4211 
4212    bt_quat = btQuaternion(x, y, z, w);
4213    trans = _ephysics_body_transform_get(body);
4214    trans.setRotation(bt_quat);
4215 
4216    if (body->soft_body)
4217      _ephysics_body_soft_body_rotation_set(body, trans);
4218    else
4219      {
4220         body->rigid_body->proceedToTransform(trans);
4221         body->rigid_body->getMotionState()->setWorldTransform(trans);
4222      }
4223 
4224    ephysics_world_lock_release(body->world);
4225 }
4226 
4227 EAPI void
ephysics_body_data_set(EPhysics_Body * body,void * data)4228 ephysics_body_data_set(EPhysics_Body *body, void *data)
4229 {
4230    if (!body)
4231      {
4232         ERR("Can't set data, body is null.");
4233         return;
4234      }
4235 
4236    body->data = data;
4237 }
4238 
4239 EAPI void *
ephysics_body_data_get(const EPhysics_Body * body)4240 ephysics_body_data_get(const EPhysics_Body *body)
4241 {
4242    if (!body)
4243      {
4244         ERR("Can't get data, body is null.");
4245         return NULL;
4246      }
4247 
4248    return body->data;
4249 }
4250 
4251 EAPI void
ephysics_body_central_force_apply(EPhysics_Body * body,double x,double y,double z)4252 ephysics_body_central_force_apply(EPhysics_Body *body, double x, double y, double z)
4253 {
4254    double rate;
4255 
4256    if (!body)
4257      {
4258         ERR("Can't apply force to a null body.");
4259         return;
4260      }
4261 
4262    ephysics_world_lock_take(body->world);
4263    rate = ephysics_world_rate_get(body->world);
4264    ephysics_body_forces_apply(body);
4265    body->rigid_body->applyCentralForce(btVector3(x / rate, - y / rate,
4266                                                  z / rate));
4267    _ephysics_body_forces_update(body);
4268    ephysics_world_lock_release(body->world);
4269 }
4270 
4271 EAPI void
ephysics_body_force_apply(EPhysics_Body * body,double x,double y,double z,Evas_Coord pos_x,Evas_Coord pos_y,Evas_Coord pos_z)4272 ephysics_body_force_apply(EPhysics_Body *body, double x, double y, double z, Evas_Coord pos_x, Evas_Coord pos_y, Evas_Coord pos_z)
4273 {
4274    double rate;
4275 
4276    if (!body)
4277      {
4278         ERR("Can't apply force to a null body.");
4279         return;
4280      }
4281 
4282    rate = ephysics_world_rate_get(body->world);
4283    ephysics_world_lock_take(body->world);
4284    ephysics_body_forces_apply(body);
4285    body->rigid_body->applyForce(btVector3(x / rate, - y / rate, z / rate),
4286                                 btVector3((double) pos_x / rate,
4287                                           (double) pos_y / rate,
4288                                           (double) pos_z / rate));
4289    _ephysics_body_forces_update(body);
4290    ephysics_world_lock_release(body->world);
4291 }
4292 
4293 EAPI void
ephysics_body_torque_apply(EPhysics_Body * body,double torque_x,double torque_y,double torque_z)4294 ephysics_body_torque_apply(EPhysics_Body *body, double torque_x, double torque_y, double torque_z)
4295 {
4296    if (!body)
4297      {
4298         ERR("Can't apply force to a null body.");
4299         return;
4300      }
4301 
4302    ephysics_world_lock_take(body->world);
4303    ephysics_body_forces_apply(body);
4304    body->rigid_body->applyTorque(btVector3(-torque_x, -torque_y, -torque_z));
4305    _ephysics_body_forces_update(body);
4306    ephysics_world_lock_release(body->world);
4307 }
4308 
4309 EAPI void
ephysics_body_forces_get(const EPhysics_Body * body,double * x,double * y,double * z)4310 ephysics_body_forces_get(const EPhysics_Body *body, double *x, double *y, double *z)
4311 {
4312    double rate, gx, gy, gz;
4313 
4314    if (!body)
4315      {
4316         ERR("Can't get forces from a null body.");
4317         return;
4318      }
4319 
4320    rate = ephysics_world_rate_get(body->world);
4321    ephysics_world_gravity_get(body->world, &gx, &gy, &gz);
4322 
4323    if (x) *x = body->force.x * rate + gx;
4324    if (y) *y = -body->force.y * rate + gy;
4325    if (z) *z = body->force.z * rate + gz;
4326 }
4327 
4328 EAPI void
ephysics_body_torques_get(const EPhysics_Body * body,double * x,double * y,double * z)4329 ephysics_body_torques_get(const EPhysics_Body *body, double *x, double *y, double *z)
4330 {
4331    if (!body)
4332      {
4333         ERR("Can't get torques from a null body.");
4334         return;
4335      }
4336 
4337    if (x) *x = -body->force.torque_x;
4338    if (y) *y = -body->force.torque_y;
4339    if (z) *z = -body->force.torque_z;
4340 }
4341 
4342 EAPI void
ephysics_body_forces_clear(EPhysics_Body * body)4343 ephysics_body_forces_clear(EPhysics_Body *body)
4344 {
4345    if (!body)
4346      {
4347         ERR("Can't clear forces of a null body.");
4348         return;
4349      }
4350 
4351    body->force.x = 0;
4352    body->force.y = 0;
4353    body->force.z = 0;
4354    body->force.torque_x = 0;
4355    body->force.torque_y = 0;
4356    body->force.torque_z = 0;
4357 }
4358 
4359 EAPI void
ephysics_body_center_mass_get(const EPhysics_Body * body,double * x,double * y,double * z)4360 ephysics_body_center_mass_get(const EPhysics_Body *body, double *x, double *y, double *z)
4361 {
4362    if (!body)
4363      {
4364         ERR("Can't get center of mass from a null body.");
4365         return;
4366      }
4367 
4368    if (x) *x = body->cm.x;
4369    if (y) *y = body->cm.y;
4370    if (z) *z = body->cm.z;
4371 }
4372 
4373 EAPI void
ephysics_body_density_set(EPhysics_Body * body,double density)4374 ephysics_body_density_set(EPhysics_Body *body, double density)
4375 {
4376    if (!body)
4377      {
4378         ERR("Can't set the density of a null body's material.");
4379         return;
4380      }
4381 
4382    body->material = EPHYSICS_BODY_MATERIAL_CUSTOM;
4383    body->density = density;
4384    ephysics_world_lock_take(body->world);
4385    _ephysics_body_mass_set(body, 0);
4386    ephysics_world_lock_release(body->world);
4387 }
4388 
4389 EAPI double
ephysics_body_density_get(const EPhysics_Body * body)4390 ephysics_body_density_get(const EPhysics_Body *body)
4391 {
4392    if (!body)
4393      {
4394         ERR("Can't get the density of a null body's material.");
4395         return 0;
4396      }
4397 
4398    return body->density;
4399 }
4400 
4401 EAPI void
ephysics_body_material_set(EPhysics_Body * body,EPhysics_Body_Material material)4402 ephysics_body_material_set(EPhysics_Body *body, EPhysics_Body_Material material)
4403 {
4404    if (!body)
4405      {
4406         ERR("Can't set body's material.");
4407         return;
4408      }
4409 
4410    if (material >= EPHYSICS_BODY_MATERIAL_LAST)
4411      {
4412         ERR("Invalid material.");
4413         return;
4414      }
4415 
4416    if (material != ephysics_material_props[material].material)
4417      {
4418         ERR("Material properties weren't found.");
4419         return;
4420      }
4421 
4422    if (material == EPHYSICS_BODY_MATERIAL_CUSTOM)
4423      {
4424         body->material = material;
4425         return;
4426      }
4427 
4428    ephysics_world_lock_take(body->world);
4429    body->density = ephysics_material_props[material].density;
4430    _ephysics_body_mass_set(body, 0);
4431    _ephysics_body_friction_set(body,
4432                                ephysics_material_props[material].friction);
4433    _ephysics_body_restitution_set(
4434       body, ephysics_material_props[material].restitution);
4435    body->material = material;
4436    ephysics_world_lock_release(body->world);
4437 }
4438 
4439 EAPI EPhysics_Body_Material
ephysics_body_material_get(const EPhysics_Body * body)4440 ephysics_body_material_get(const EPhysics_Body *body)
4441 {
4442    if (!body)
4443      {
4444         ERR("Can't get body's material.");
4445         return EPHYSICS_BODY_MATERIAL_LAST;
4446      }
4447 
4448    return body->material;
4449 }
4450 
4451 EAPI void
ephysics_body_light_set(EPhysics_Body * body,Eina_Bool enable)4452 ephysics_body_light_set(EPhysics_Body *body, Eina_Bool enable)
4453 {
4454    if (!body)
4455      {
4456         ERR("No body, no light.");
4457         return;
4458      }
4459 
4460    body->light_apply = !!enable;
4461 }
4462 
4463 EAPI Eina_Bool
ephysics_body_light_get(const EPhysics_Body * body)4464 ephysics_body_light_get(const EPhysics_Body *body)
4465 {
4466    if (!body)
4467      {
4468         ERR("No body, no light.");
4469         return EINA_FALSE;
4470      }
4471 
4472    return body->light_apply;
4473 }
4474 
4475 EAPI double
ephysics_body_volume_get(const EPhysics_Body * body)4476 ephysics_body_volume_get(const EPhysics_Body *body)
4477 {
4478    if (!body)
4479      {
4480         ERR("No body, no volume.");
4481         return -1;
4482      }
4483    return _ephysics_body_volume_get(body);
4484 }
4485 
4486 EAPI void
ephysics_body_back_face_culling_set(EPhysics_Body * body,Eina_Bool enable)4487 ephysics_body_back_face_culling_set(EPhysics_Body *body, Eina_Bool enable)
4488 {
4489    if (!body)
4490      {
4491         ERR("Body is NULL.");
4492         return;
4493      }
4494    body->back_face_culling = !!enable;
4495 }
4496 
4497 EAPI Eina_Bool
ephysics_body_back_face_culling_get(const EPhysics_Body * body)4498 ephysics_body_back_face_culling_get(const EPhysics_Body *body)
4499 {
4500    if (!body)
4501      {
4502         ERR("Body is NULL.");
4503         return EINA_FALSE;
4504      }
4505    return body->back_face_culling;
4506 }
4507 
4508 EAPI Eina_Bool
ephysics_body_clockwise_get(const EPhysics_Body * body)4509 ephysics_body_clockwise_get(const EPhysics_Body *body)
4510 {
4511    if (!body)
4512      {
4513         ERR("Body is NULL.");
4514         return EINA_FALSE;
4515      }
4516    return body->clockwise;
4517 }
4518 
4519 static void
_ephysics_body_face_obj_del_cb(void * data,Evas * e EINA_UNUSED,Evas_Object * obj,void * event_info EINA_UNUSED)4520 _ephysics_body_face_obj_del_cb(void *data, Evas *e EINA_UNUSED, Evas_Object *obj, void *event_info EINA_UNUSED)
4521 {
4522    EPhysics_Body *body = (EPhysics_Body *) data;
4523    EPhysics_Body_Face_Obj *face_obj;
4524    Eina_List *l;
4525    void *ldata;
4526 
4527    EINA_LIST_FOREACH(body->face_objs, l, ldata)
4528      {
4529         face_obj = (EPhysics_Body_Face_Obj *)ldata;
4530         if (face_obj->obj == obj)
4531           {
4532              body->face_objs = eina_list_remove(body->face_objs, face_obj);
4533              free(face_obj);
4534              return;
4535           }
4536      }
4537 }
4538 
4539 static void
_ephysics_body_face_obj_unset(Evas_Object * obj,Evas_Object_Event_Cb resize_func)4540 _ephysics_body_face_obj_unset(Evas_Object *obj, Evas_Object_Event_Cb resize_func)
4541 {
4542    evas_object_map_enable_set(obj, EINA_FALSE);
4543    evas_object_event_callback_del(obj, EVAS_CALLBACK_DEL,
4544                                   _ephysics_body_face_obj_del_cb);
4545    evas_object_event_callback_del(obj, EVAS_CALLBACK_RESIZE, resize_func);
4546 }
4547 
4548 static void
_ephysics_body_face_evas_object_del(EPhysics_Body * body,EPhysics_Body_Face_Obj * face_obj,Evas_Object_Event_Cb resize_func)4549 _ephysics_body_face_evas_object_del(EPhysics_Body *body, EPhysics_Body_Face_Obj *face_obj, Evas_Object_Event_Cb resize_func)
4550 {
4551    _ephysics_body_face_obj_unset(face_obj->obj, resize_func);
4552    body->face_objs = eina_list_remove(body->face_objs, face_obj);
4553    free(face_obj);
4554 }
4555 
4556 static void
_ephysics_body_face_evas_object_add(EPhysics_Body * body,EPhysics_Body_Face face,Evas_Object * evas_obj,Evas_Object_Event_Cb resize_func)4557 _ephysics_body_face_evas_object_add(EPhysics_Body *body, EPhysics_Body_Face face, Evas_Object *evas_obj, Evas_Object_Event_Cb resize_func)
4558 {
4559    EPhysics_Body_Face_Obj *face_obj;
4560    Eina_List *l;
4561    void *ldata;
4562 
4563    EINA_LIST_FOREACH(body->face_objs, l, ldata)
4564      {
4565         face_obj = (EPhysics_Body_Face_Obj *)ldata;
4566         if (face_obj->face == face)
4567           {
4568              _ephysics_body_face_obj_unset(face_obj->obj, resize_func);
4569              face_obj->obj = evas_obj;
4570              return;
4571           }
4572      }
4573 
4574    face_obj = (EPhysics_Body_Face_Obj *)calloc(1,
4575                                                sizeof(EPhysics_Body_Face_Obj));
4576    if (!face_obj)
4577      {
4578         ERR("Failed to create face object");
4579         return;
4580      }
4581 
4582    face_obj->face = face;
4583    face_obj->obj = evas_obj;
4584    body->face_objs = eina_list_append(body->face_objs, face_obj);
4585 }
4586 
4587 static void
_ephysics_body_box_face_obj_resize_cb(void * data,Evas * e EINA_UNUSED,Evas_Object * obj,void * event_info EINA_UNUSED)4588 _ephysics_body_box_face_obj_resize_cb(void *data, Evas *e EINA_UNUSED, Evas_Object *obj, void *event_info EINA_UNUSED)
4589 {
4590    EPhysics_Body_Face face = EPHYSICS_BODY_FACE_LAST;
4591    EPhysics_Body *body = (EPhysics_Body *) data;
4592    EPhysics_Body_Face_Obj *face_obj;
4593    int w, h, bw, bh, bd;
4594    Eina_List *l;
4595    void *ldata;
4596 
4597    evas_object_geometry_get(obj, NULL, NULL, &w, &h);
4598    EINA_LIST_FOREACH(body->face_objs, l, ldata)
4599      {
4600         face_obj = (EPhysics_Body_Face_Obj *)ldata;
4601         if (face_obj->obj == obj)
4602           {
4603              face = face_obj->face;
4604              break;
4605           }
4606      }
4607 
4608    switch(face)
4609      {
4610       case EPHYSICS_BODY_BOX_FACE_FRONT:
4611       case EPHYSICS_BODY_BOX_FACE_BACK:
4612       case EPHYSICS_BODY_BOX_FACE_MIDDLE_FRONT:
4613       case EPHYSICS_BODY_BOX_FACE_MIDDLE_BACK:
4614          if ((w == body->size.w) && (h == body->size.h))
4615            return;
4616          bw = w;
4617          bh = h;
4618          bd = body->size.d;
4619          break;
4620       case EPHYSICS_BODY_BOX_FACE_RIGHT:
4621       case EPHYSICS_BODY_BOX_FACE_LEFT:
4622          if ((w == body->size.d) && (h == body->size.h))
4623            return;
4624          bw = body->size.w;
4625          bh = h;
4626          bd = w;
4627          break;
4628       case EPHYSICS_BODY_BOX_FACE_TOP:
4629       case EPHYSICS_BODY_BOX_FACE_BOTTOM:
4630          if ((w == body->size.w) && (h == body->size.d))
4631            return;
4632          bw = w;
4633          bh = body->size.h;
4634          bd = h;
4635       default:
4636          return;
4637      }
4638 
4639    DBG("Resizing body %p to w=%i, h=%i, d=%i", body, bw, bh, bd);
4640    ephysics_world_lock_take(body->world);
4641    _ephysics_body_resize(body, bw, bh, bd);
4642    ephysics_world_lock_release(body->world);
4643 }
4644 
4645 static void
_ephysics_body_box_face_evas_object_set(EPhysics_Body * body,EPhysics_Body_Face face,Evas_Object * evas_obj,Eina_Bool use_obj_pos)4646 _ephysics_body_box_face_evas_object_set(EPhysics_Body *body, EPhysics_Body_Face face, Evas_Object *evas_obj, Eina_Bool use_obj_pos)
4647 {
4648    int obj_x, obj_y, obj_w, obj_h, bx, by, bz, bw, bh, bd;
4649    double rate;
4650 
4651    if ((face < EPHYSICS_BODY_BOX_FACE_MIDDLE_FRONT) ||
4652        (face > EPHYSICS_BODY_BOX_FACE_BOTTOM))
4653      {
4654         ERR("Can't set evas object to body, face is invalid.");
4655         return;
4656      }
4657 
4658    if (body->soft_body)
4659      {
4660         ERR("Not implemented for soft bodies yet.");
4661         return;
4662      }
4663 
4664    _ephysics_body_face_evas_object_add(body, face, evas_obj,
4665                                        _ephysics_body_box_face_obj_resize_cb);
4666    evas_object_event_callback_add(evas_obj, EVAS_CALLBACK_DEL,
4667                                   _ephysics_body_face_obj_del_cb, body);
4668 
4669    if (!use_obj_pos)
4670      return;
4671 
4672    rate = ephysics_world_rate_get(body->world);
4673    evas_object_geometry_get(evas_obj, &obj_x, &obj_y, &obj_w, &obj_h);
4674    ephysics_body_geometry_get(body, &bx, &by, &bz, &bw, &bh, &bd);
4675 
4676    ephysics_world_lock_take(body->world);
4677 
4678    switch(face)
4679      {
4680       case EPHYSICS_BODY_BOX_FACE_FRONT:
4681       case EPHYSICS_BODY_BOX_FACE_BACK:
4682       case EPHYSICS_BODY_BOX_FACE_MIDDLE_FRONT:
4683       case EPHYSICS_BODY_BOX_FACE_MIDDLE_BACK:
4684          _ephysics_body_geometry_set(body, obj_x, obj_y, bz,
4685                                      obj_w, obj_h, bd, rate);
4686          break;
4687       case EPHYSICS_BODY_BOX_FACE_RIGHT:
4688       case EPHYSICS_BODY_BOX_FACE_LEFT:
4689          _ephysics_body_geometry_set(body, bx, by, bz,
4690                                      bw, obj_h, obj_w, rate);
4691          break;
4692       case EPHYSICS_BODY_BOX_FACE_TOP:
4693       case EPHYSICS_BODY_BOX_FACE_BOTTOM:
4694          _ephysics_body_geometry_set(body, bx, by, bz,
4695                                      obj_w, bh, obj_h, rate);
4696          break;
4697       default:
4698          break;
4699      }
4700 
4701    ephysics_world_lock_release(body->world);
4702    evas_object_event_callback_add(evas_obj, EVAS_CALLBACK_RESIZE,
4703                                   _ephysics_body_box_face_obj_resize_cb,
4704                                   body);
4705 }
4706 
4707 static Evas_Object *
_ephysics_body_box_face_evas_object_get(const EPhysics_Body * body,EPhysics_Body_Face face)4708 _ephysics_body_box_face_evas_object_get(const EPhysics_Body *body, EPhysics_Body_Face face)
4709 {
4710    EPhysics_Body_Face_Obj *face_obj;
4711    Eina_List *l;
4712    void *ldata;
4713 
4714    if ((face < EPHYSICS_BODY_BOX_FACE_MIDDLE_FRONT) ||
4715        (face > EPHYSICS_BODY_BOX_FACE_BOTTOM))
4716      {
4717         ERR("Can't get evas object from body, face is invalid.");
4718         return NULL;
4719      }
4720 
4721    EINA_LIST_FOREACH(body->face_objs, l, ldata)
4722      {
4723         face_obj = (EPhysics_Body_Face_Obj *)ldata;
4724         if (face_obj->face == face)
4725           return face_obj->obj;
4726      }
4727 
4728    ERR("Couldn't find an object associated to face %i.", face);
4729    return NULL;
4730 }
4731 
4732 static Evas_Object *
_ephysics_body_box_face_evas_object_unset(EPhysics_Body * body,EPhysics_Body_Face face)4733 _ephysics_body_box_face_evas_object_unset(EPhysics_Body *body, EPhysics_Body_Face face)
4734 {
4735    EPhysics_Body_Face_Obj *face_obj;
4736    Eina_List *l;
4737    void *ldata;
4738 
4739    if ((face < EPHYSICS_BODY_BOX_FACE_MIDDLE_FRONT) ||
4740        (face > EPHYSICS_BODY_BOX_FACE_BOTTOM))
4741      {
4742         ERR("Can't unset evas object from body, face is invalid.");
4743         return NULL;
4744      }
4745 
4746    EINA_LIST_FOREACH(body->face_objs, l, ldata)
4747      {
4748         face_obj = (EPhysics_Body_Face_Obj *)ldata;
4749         if (face_obj->face == face)
4750           {
4751              Evas_Object *obj = face_obj->obj;
4752              _ephysics_body_face_obj_unset(
4753                 obj, _ephysics_body_box_face_obj_resize_cb);
4754              body->face_objs = eina_list_remove(body->face_objs, face_obj);
4755              free(face_obj);
4756              return obj;
4757           }
4758      }
4759 
4760    ERR("Couldn't find an object associated to face %i.", face);
4761    return NULL;
4762 }
4763 
4764 static void
_ephysics_body_cylinder_face_obj_resize_cb(void * data,Evas * e EINA_UNUSED,Evas_Object * obj,void * event_info EINA_UNUSED)4765 _ephysics_body_cylinder_face_obj_resize_cb(void *data, Evas *e EINA_UNUSED, Evas_Object *obj, void *event_info EINA_UNUSED)
4766 {
4767    EPhysics_Body_Face face = EPHYSICS_BODY_FACE_LAST;
4768    EPhysics_Body *body = (EPhysics_Body *) data;
4769    EPhysics_Body_Face_Obj *face_obj;
4770    int w, h, bw, bh, bd;
4771    Eina_List *l;
4772    void *ldata;
4773 
4774    evas_object_geometry_get(obj, NULL, NULL, &w, &h);
4775    EINA_LIST_FOREACH(body->face_objs, l, ldata)
4776      {
4777         face_obj = (EPhysics_Body_Face_Obj *)ldata;
4778         if (face_obj->obj == obj)
4779           {
4780              face = face_obj->face;
4781              break;
4782           }
4783      }
4784 
4785    switch(face)
4786      {
4787       case EPHYSICS_BODY_CYLINDER_FACE_FRONT:
4788       case EPHYSICS_BODY_CYLINDER_FACE_BACK:
4789       case EPHYSICS_BODY_CYLINDER_FACE_MIDDLE_FRONT:
4790       case EPHYSICS_BODY_CYLINDER_FACE_MIDDLE_BACK:
4791          if ((w == body->size.w) && (h == body->size.h))
4792            return;
4793          bw = w;
4794          bh = h;
4795          bd = body->size.d;
4796          break;
4797       case EPHYSICS_BODY_CYLINDER_FACE_CURVED:
4798          if (h == body->size.d)
4799            return;
4800          bw = body->size.w;
4801          bh = body->size.h;
4802          bd = h;
4803       default:
4804          return;
4805      }
4806 
4807    DBG("Resizing body %p to w=%i, h=%i, d=%i", body, bw, bh, bd);
4808    ephysics_world_lock_take(body->world);
4809    _ephysics_body_resize(body, bw, bh, bd);
4810    ephysics_world_lock_release(body->world);
4811 }
4812 
4813 static void
_ephysics_body_cylinder_face_evas_object_set(EPhysics_Body * body,EPhysics_Body_Face face,Evas_Object * evas_obj,Eina_Bool use_obj_pos)4814 _ephysics_body_cylinder_face_evas_object_set(EPhysics_Body *body, EPhysics_Body_Face face, Evas_Object *evas_obj, Eina_Bool use_obj_pos)
4815 {
4816    int obj_x, obj_y, obj_w, obj_h, bx, by, bz, bw, bh, bd;
4817    double rate;
4818 
4819    if ((face < EPHYSICS_BODY_CYLINDER_FACE_MIDDLE_FRONT) ||
4820        (face > EPHYSICS_BODY_CYLINDER_FACE_CURVED))
4821      {
4822         ERR("Can't set evas object to body, face is invalid.");
4823         return;
4824      }
4825 
4826    if (body->soft_body)
4827      {
4828         ERR("Not implemented for soft bodies yet.");
4829         return;
4830      }
4831 
4832    _ephysics_body_face_evas_object_add(
4833       body, face, evas_obj, _ephysics_body_cylinder_face_obj_resize_cb);
4834    evas_object_event_callback_add(evas_obj, EVAS_CALLBACK_DEL,
4835                                   _ephysics_body_face_obj_del_cb, body);
4836 
4837    if (!use_obj_pos)
4838      return;
4839 
4840    rate = ephysics_world_rate_get(body->world);
4841    evas_object_geometry_get(evas_obj, &obj_x, &obj_y, &obj_w, &obj_h);
4842    ephysics_body_geometry_get(body, &bx, &by, &bz, &bw, &bh, &bd);
4843 
4844    ephysics_world_lock_take(body->world);
4845 
4846    switch(face)
4847      {
4848       case EPHYSICS_BODY_CYLINDER_FACE_FRONT:
4849       case EPHYSICS_BODY_CYLINDER_FACE_BACK:
4850       case EPHYSICS_BODY_CYLINDER_FACE_MIDDLE_FRONT:
4851       case EPHYSICS_BODY_CYLINDER_FACE_MIDDLE_BACK:
4852          _ephysics_body_geometry_set(body, obj_x, obj_y, bz,
4853                                      obj_w, obj_h, bd, rate);
4854          break;
4855       case EPHYSICS_BODY_CYLINDER_FACE_CURVED:
4856          _ephysics_body_geometry_set(body, bx, by, bz,
4857                                      bw, bh, obj_h, rate);
4858       default:
4859          break;
4860      }
4861 
4862    ephysics_world_lock_release(body->world);
4863    evas_object_event_callback_add(evas_obj, EVAS_CALLBACK_RESIZE,
4864                                   _ephysics_body_cylinder_face_obj_resize_cb,
4865                                   body);
4866 }
4867 
4868 static Evas_Object *
_ephysics_body_cylinder_face_evas_object_get(const EPhysics_Body * body,EPhysics_Body_Face face)4869 _ephysics_body_cylinder_face_evas_object_get(const EPhysics_Body *body, EPhysics_Body_Face face)
4870 {
4871    EPhysics_Body_Face_Obj *face_obj;
4872    Eina_List *l;
4873    void *ldata;
4874 
4875    if ((face < EPHYSICS_BODY_CYLINDER_FACE_MIDDLE_FRONT) ||
4876        (face > EPHYSICS_BODY_CYLINDER_FACE_CURVED))
4877      {
4878         ERR("Can't get evas object from body, face is invalid.");
4879         return NULL;
4880      }
4881 
4882    EINA_LIST_FOREACH(body->face_objs, l, ldata)
4883      {
4884         face_obj = (EPhysics_Body_Face_Obj *)ldata;
4885         if (face_obj->face == face)
4886           return face_obj->obj;
4887      }
4888 
4889    ERR("Couldn't find an object associated to face %i.", face);
4890    return NULL;
4891 }
4892 
4893 static Evas_Object *
_ephysics_body_cylinder_face_evas_object_unset(EPhysics_Body * body,EPhysics_Body_Face face)4894 _ephysics_body_cylinder_face_evas_object_unset(EPhysics_Body *body, EPhysics_Body_Face face)
4895 {
4896    EPhysics_Body_Face_Obj *face_obj;
4897    Eina_List *l;
4898    void *ldata;
4899 
4900    if ((face < EPHYSICS_BODY_CYLINDER_FACE_MIDDLE_FRONT) ||
4901        (face > EPHYSICS_BODY_CYLINDER_FACE_CURVED))
4902      {
4903         ERR("Can't unset evas object from body, face is invalid.");
4904         return NULL;
4905      }
4906 
4907    EINA_LIST_FOREACH(body->face_objs, l, ldata)
4908      {
4909         face_obj = (EPhysics_Body_Face_Obj *)ldata;
4910         if (face_obj->face == face)
4911           {
4912              Evas_Object *obj = face_obj->obj;
4913              _ephysics_body_face_obj_unset(
4914                 obj, _ephysics_body_cylinder_face_obj_resize_cb);
4915              body->face_objs = eina_list_remove(body->face_objs, face_obj);
4916              free(face_obj);
4917              return obj;
4918           }
4919      }
4920 
4921    ERR("Couldn't find an object associated to face %i.", face);
4922    return NULL;
4923 }
4924 
4925 static void
_ephysics_body_soft_body_face_resize_cb(void * data,Evas * e EINA_UNUSED,Evas_Object * obj,void * event_info EINA_UNUSED)4926 _ephysics_body_soft_body_face_resize_cb(void *data, Evas *e EINA_UNUSED, Evas_Object *obj, void *event_info EINA_UNUSED)
4927 {
4928    int w, h;
4929    EPhysics_Body_Face_Obj *face;
4930    EPhysics_Body_Face_Slice *face_slice = (EPhysics_Body_Face_Slice *)data;
4931    EPhysics_Body *body = face_slice->body;
4932 
4933    evas_object_geometry_get(obj, NULL, NULL, &w, &h);
4934    if ((w == body->size.w) && (h == body->size.h))
4935      return;
4936 
4937    DBG("Resizing body %p to w=%i, h=%i, d=%i", body, w, h, body->size.d);
4938 
4939    face = _ephysics_body_face_evas_object_get(body, face_slice->face);
4940 
4941    ephysics_world_lock_take(body->world);
4942    _ephysics_body_resize(body, w, h, body->size.d);
4943 
4944    if (body->type == EPHYSICS_BODY_TYPE_CLOTH)
4945      {
4946         _ephysics_body_soft_body_slices_clean(face_slice->slices);
4947         _ephysics_body_soft_body_slices_init(body, face->obj,
4948                                              face_slice->slices);
4949      }
4950 
4951    ephysics_world_lock_release(body->world);
4952 }
4953 
4954 static void
_ephysics_body_cloth_face_evas_object_set(EPhysics_Body * body,EPhysics_Body_Face face,Evas_Object * evas_obj,Eina_Bool use_obj_pos)4955 _ephysics_body_cloth_face_evas_object_set(EPhysics_Body *body, EPhysics_Body_Face face, Evas_Object *evas_obj, Eina_Bool use_obj_pos)
4956 {
4957    EPhysics_Body_Face_Slice *face_slice;
4958    int obj_x, obj_y, obj_w, obj_h, bz, bd;
4959    double rate;
4960 
4961    if ((face < EPHYSICS_BODY_CLOTH_FACE_FRONT) ||
4962        (face > EPHYSICS_BODY_CLOTH_FACE_BACK))
4963      {
4964         ERR("Can't set evas object to body, face is invalid.");
4965         return;
4966      }
4967 
4968    _ephysics_body_face_evas_object_add(body, face, evas_obj,
4969                                        _ephysics_body_soft_body_face_resize_cb);
4970    evas_object_event_callback_add(evas_obj, EVAS_CALLBACK_DEL,
4971                                   _ephysics_body_face_obj_del_cb, body);
4972 
4973    if (!use_obj_pos)
4974      return;
4975 
4976    face_slice = _ephysics_body_face_slice_get(body, face);
4977 
4978    rate = ephysics_world_rate_get(body->world);
4979    evas_object_geometry_get(evas_obj, &obj_x, &obj_y, &obj_w, &obj_h);
4980 
4981    ephysics_world_lock_take(body->world);
4982    ephysics_body_geometry_get(body, NULL, NULL, &bz, NULL, NULL, &bd);
4983    _ephysics_body_geometry_set(body, obj_x, obj_y, bz, obj_w, obj_h, bd, rate);
4984    ephysics_world_lock_release(body->world);
4985    evas_object_event_callback_add(evas_obj, EVAS_CALLBACK_RESIZE,
4986                                   _ephysics_body_soft_body_face_resize_cb,
4987                                   face_slice);
4988 }
4989 
4990 static Evas_Object *
_ephysics_body_cloth_face_evas_object_get(const EPhysics_Body * body,EPhysics_Body_Face face)4991 _ephysics_body_cloth_face_evas_object_get(const EPhysics_Body *body, EPhysics_Body_Face face)
4992 {
4993    EPhysics_Body_Face_Obj *face_obj;
4994    Eina_List *l;
4995    void *ldata;
4996 
4997    if ((face < EPHYSICS_BODY_CLOTH_FACE_FRONT) ||
4998        (face > EPHYSICS_BODY_CLOTH_FACE_BACK))
4999      {
5000         ERR("Can't get evas object from body, face is invalid.");
5001         return NULL;
5002      }
5003 
5004    EINA_LIST_FOREACH(body->face_objs, l, ldata)
5005      {
5006         face_obj = (EPhysics_Body_Face_Obj *)ldata;
5007         if (face_obj->face == face)
5008           return face_obj->obj;
5009      }
5010 
5011    ERR("Couldn't find an object associated to face %i.", face);
5012    return NULL;
5013 }
5014 
5015 static Evas_Object *
_ephysics_body_cloth_face_evas_object_unset(EPhysics_Body * body,EPhysics_Body_Face face)5016 _ephysics_body_cloth_face_evas_object_unset(EPhysics_Body *body, EPhysics_Body_Face face)
5017 {
5018    EPhysics_Body_Face_Obj *face_obj;
5019    Eina_List *l;
5020    void *ldata;
5021 
5022    if ((face < EPHYSICS_BODY_CLOTH_FACE_FRONT) ||
5023        (face > EPHYSICS_BODY_CLOTH_FACE_BACK))
5024      {
5025         ERR("Can't unset evas object from body, face is invalid.");
5026         return NULL;
5027      }
5028 
5029    EINA_LIST_FOREACH(body->face_objs, l, ldata)
5030      {
5031         face_obj = (EPhysics_Body_Face_Obj *)ldata;
5032         if (face_obj->face == face)
5033           {
5034              Evas_Object *obj = face_obj->obj;
5035              _ephysics_body_face_obj_unset(
5036                 obj, _ephysics_body_soft_body_face_resize_cb);
5037              body->face_objs = eina_list_remove(body->face_objs, face_obj);
5038              free(face_obj);
5039              return obj;
5040           }
5041      }
5042 
5043    ERR("Couldn't find an object associated to face %i.", face);
5044    return NULL;
5045 }
5046 
5047 static void
_ephysics_body_soft_sphere_face_obj_resize_cb(void * data,Evas * e EINA_UNUSED,Evas_Object * obj,void * event_info EINA_UNUSED)5048 _ephysics_body_soft_sphere_face_obj_resize_cb(void *data, Evas *e EINA_UNUSED, Evas_Object *obj, void *event_info EINA_UNUSED)
5049 {
5050    EPhysics_Body *body = (EPhysics_Body *) data;
5051    Evas_Coord bd, w, h;
5052 
5053    evas_object_geometry_get(obj, NULL, NULL, &w, &h);
5054    ephysics_body_geometry_get(body, NULL, NULL, NULL, NULL, NULL, &bd);
5055    ephysics_world_lock_take(body->world);
5056    ephysics_body_resize(body, w, h, bd);
5057    ephysics_world_lock_release(body->world);
5058 }
5059 
5060 static void
_ephysics_body_soft_sphere_face_evas_object_del_cb(void * data,Evas * evas EINA_UNUSED,Evas_Object * obj EINA_UNUSED,void * event_info EINA_UNUSED)5061 _ephysics_body_soft_sphere_face_evas_object_del_cb(void *data, Evas *evas EINA_UNUSED, Evas_Object *obj EINA_UNUSED, void *event_info EINA_UNUSED)
5062 {
5063    Eina_List *l;
5064    void *ldata;
5065    EPhysics_Body_Face_Obj *face_obj = NULL;
5066    EPhysics_Body_Face_Slice *face_slice = (EPhysics_Body_Face_Slice *)data;
5067    EPhysics_Body *body = face_slice->body;
5068 
5069    EINA_LIST_FOREACH(body->face_objs, l, ldata)
5070      {
5071         if (((EPhysics_Body_Face_Obj *)ldata)->face == face_slice->face)
5072           {
5073              face_obj = (EPhysics_Body_Face_Obj *)ldata;
5074              break;
5075           }
5076      }
5077    if (!face_obj) return;
5078 
5079    _ephysics_body_face_evas_object_del(body, face_obj,
5080                                   _ephysics_body_soft_sphere_face_obj_resize_cb);
5081    _ephysics_body_soft_body_slices_clean(face_slice->slices);
5082 
5083    DBG("Soft sphere's face cleaned up.");
5084 }
5085 
5086 static void
_ephysics_body_soft_sphere_face_evas_object_clean(EPhysics_Body * body,EPhysics_Body_Face_Obj * face_obj,Eina_List * slices)5087 _ephysics_body_soft_sphere_face_evas_object_clean(EPhysics_Body *body, EPhysics_Body_Face_Obj *face_obj, Eina_List *slices)
5088 {
5089    evas_object_map_enable_set(face_obj->obj, EINA_FALSE);
5090    evas_object_event_callback_del(face_obj->obj, EVAS_CALLBACK_DEL,
5091                              _ephysics_body_soft_sphere_face_evas_object_del_cb);
5092 
5093    evas_object_event_callback_del(face_obj->obj, EVAS_CALLBACK_RESTACK,
5094                                   _ephysics_body_soft_body_evas_restack_cb);
5095    _ephysics_body_soft_body_slices_clean(slices);
5096 
5097    _ephysics_body_face_evas_object_del(body, face_obj,
5098                                   _ephysics_body_soft_sphere_face_obj_resize_cb);
5099 }
5100 
5101 static void
_ephysics_body_soft_sphere_face_evas_object_set(EPhysics_Body * body,EPhysics_Body_Face face,Evas_Object * evas_obj,Eina_Bool use_obj_pos)5102 _ephysics_body_soft_sphere_face_evas_object_set(EPhysics_Body *body, EPhysics_Body_Face face, Evas_Object *evas_obj, Eina_Bool use_obj_pos)
5103 {
5104    int obj_x, obj_y, obj_w, obj_h, bz, bd;
5105    double rate;
5106    EPhysics_Body_Face_Slice *face_slice = NULL;
5107    EPhysics_Body_Face_Obj *face_obj;
5108 
5109    if ((face < EPHYSICS_BODY_SPHERE_FACE_FRONT) ||
5110        (face > EPHYSICS_BODY_SPHERE_FACE_BACK))
5111      {
5112         ERR("Can't set evas object to body, face is invalid.");
5113         return;
5114      }
5115 
5116    if (!body)
5117      {
5118         ERR("Can't set evas object to body, the last wasn't provided.");
5119         return;
5120      }
5121 
5122    if (!evas_obj)
5123      {
5124         ERR("Can't set evas object to body, the first wasn't provided.");
5125         return;
5126      }
5127 
5128    face_slice = _ephysics_body_face_slice_get(body, face);
5129    if (!face_slice)
5130      {
5131         ERR("Could not find pre initialized face slice for the wanted face.");
5132         return;
5133      }
5134 
5135    face_obj = _ephysics_body_face_evas_object_get(body, face);
5136 
5137    if (face_obj)
5138         _ephysics_body_soft_sphere_face_evas_object_clean(body, face_obj,
5139                                                           face_slice->slices);
5140 
5141    evas_object_geometry_get(evas_obj, NULL, NULL, &obj_w, &obj_h);
5142    if (!obj_w && !obj_h) evas_object_resize(evas_obj, 1, 1);
5143 
5144    _ephysics_body_face_evas_object_add(body, face, evas_obj,
5145                                   _ephysics_body_soft_sphere_face_obj_resize_cb);
5146 
5147    evas_object_event_callback_add(evas_obj, EVAS_CALLBACK_DEL,
5148                  _ephysics_body_soft_sphere_face_evas_object_del_cb, face_slice);
5149 
5150    evas_object_event_callback_add(evas_obj, EVAS_CALLBACK_RESTACK,
5151                                   _ephysics_body_soft_body_evas_restack_cb,
5152                                   body);
5153 
5154    _ephysics_body_soft_body_slices_init(body, evas_obj, face_slice->slices);
5155 
5156    if (!use_obj_pos)
5157      return;
5158 
5159    rate = ephysics_world_rate_get(body->world);
5160    evas_object_geometry_get(evas_obj, &obj_x, &obj_y, &obj_w, &obj_h);
5161    ephysics_body_geometry_get(body, NULL, NULL, &bz, NULL, NULL, &bd);
5162 
5163    ephysics_world_lock_take(body->world);
5164    _ephysics_body_geometry_set(body, obj_x, obj_y, bz, obj_w, obj_h, bd, rate);
5165    ephysics_world_lock_release(body->world);
5166    evas_object_event_callback_add(evas_obj, EVAS_CALLBACK_RESIZE,
5167                                   _ephysics_body_efl_canvas_object_resize_cb, body);
5168 
5169    DBG("Soft sphere's face evas object set.");
5170 }
5171 
5172 static Evas_Object *
_ephysics_body_soft_sphere_face_evas_object_get(const EPhysics_Body * body,EPhysics_Body_Face face)5173 _ephysics_body_soft_sphere_face_evas_object_get(const EPhysics_Body *body, EPhysics_Body_Face face)
5174 {
5175    EPhysics_Body_Face_Obj *face_obj = NULL;
5176 
5177    if ((face < EPHYSICS_BODY_SPHERE_FACE_FRONT) ||
5178        (face > EPHYSICS_BODY_SPHERE_FACE_BACK))
5179      {
5180         ERR("Can't get evas object from body, face is invalid.");
5181         return NULL;
5182      }
5183 
5184    face_obj = _ephysics_body_face_evas_object_get((EPhysics_Body *)body, face);
5185    if (face_obj) return face_obj->obj;
5186 
5187    ERR("Couldn't find an object associated to face %i.", face);
5188    return NULL;
5189 }
5190 
5191 static Evas_Object *
_ephysics_body_soft_sphere_face_evas_object_unset(EPhysics_Body * body,EPhysics_Body_Face face)5192 _ephysics_body_soft_sphere_face_evas_object_unset(EPhysics_Body *body, EPhysics_Body_Face face)
5193 {
5194    EPhysics_Body_Face_Slice *face_slice;
5195    EPhysics_Body_Face_Obj *face_obj = NULL;
5196    Evas_Object *obj;
5197 
5198    if ((face < EPHYSICS_BODY_SPHERE_FACE_FRONT) ||
5199        (face > EPHYSICS_BODY_SPHERE_FACE_BACK))
5200      {
5201         ERR("Can't unset evas object from body, face is invalid.");
5202         return NULL;
5203      }
5204 
5205    face_obj = _ephysics_body_face_evas_object_get(body, face);
5206 
5207    if (!face_obj) return NULL;
5208 
5209    obj = face_obj->obj;
5210    face_slice = _ephysics_body_face_slice_get(body, face);
5211    _ephysics_body_soft_sphere_face_evas_object_clean(body, face_obj,
5212                                                    face_slice->slices);
5213 
5214    DBG("EPhysics Body face unset.");
5215    return obj;
5216 }
5217 
5218 EAPI void
ephysics_body_face_evas_object_set(EPhysics_Body * body,EPhysics_Body_Face face,Evas_Object * evas_obj,Eina_Bool use_obj_pos)5219 ephysics_body_face_evas_object_set(EPhysics_Body *body, EPhysics_Body_Face face, Evas_Object *evas_obj, Eina_Bool use_obj_pos)
5220 {
5221    if (!body)
5222      {
5223         ERR("Can't set evas object to body, the last wasn't provided.");
5224         return;
5225      }
5226 
5227    if (!evas_obj)
5228      {
5229         ERR("Can't set evas object to body, the first wasn't provided.");
5230         return;
5231      }
5232 
5233    if (body->type == EPHYSICS_BODY_TYPE_CLOTH)
5234      return _ephysics_body_cloth_face_evas_object_set(body, face, evas_obj,
5235                                                       use_obj_pos);
5236    if (body->type == EPHYSICS_BODY_TYPE_RIGID &&
5237        body->shape == EPHYSICS_BODY_SHAPE_CYLINDER)
5238      return _ephysics_body_cylinder_face_evas_object_set(body, face, evas_obj,
5239                                                          use_obj_pos);
5240    if (body->type == EPHYSICS_BODY_TYPE_RIGID &&
5241        body->shape == EPHYSICS_BODY_SHAPE_BOX)
5242      return _ephysics_body_box_face_evas_object_set(body, face, evas_obj,
5243                                                     use_obj_pos);
5244    if (body->type == EPHYSICS_BODY_TYPE_SOFT &&
5245        body->shape == EPHYSICS_BODY_SHAPE_SPHERE)
5246      return _ephysics_body_soft_sphere_face_evas_object_set(body, face, evas_obj,
5247                                                             use_obj_pos);
5248 
5249    ERR("Can't handle body %p type.", body);
5250 }
5251 
5252 EAPI Evas_Object *
ephysics_body_face_evas_object_get(const EPhysics_Body * body,EPhysics_Body_Face face)5253 ephysics_body_face_evas_object_get(const EPhysics_Body *body, EPhysics_Body_Face face)
5254 {
5255    if (!body)
5256      {
5257         ERR("Can't get evas object from body, it wasn't provided.");
5258         return NULL;
5259      }
5260 
5261    if (body->type == EPHYSICS_BODY_TYPE_CLOTH)
5262      return _ephysics_body_cloth_face_evas_object_get(body, face);
5263    if (body->type == EPHYSICS_BODY_TYPE_RIGID &&
5264        body->shape == EPHYSICS_BODY_SHAPE_CYLINDER)
5265      return _ephysics_body_cylinder_face_evas_object_get(body, face);
5266    if (body->type == EPHYSICS_BODY_TYPE_RIGID &&
5267        body->shape == EPHYSICS_BODY_SHAPE_BOX)
5268      return _ephysics_body_box_face_evas_object_get(body, face);
5269    if (body->type == EPHYSICS_BODY_TYPE_SOFT &&
5270        body->shape == EPHYSICS_BODY_SHAPE_SPHERE)
5271      return _ephysics_body_soft_sphere_face_evas_object_get(body, face);
5272 
5273    ERR("Can't handle body %p type.", body);
5274    return NULL;
5275 }
5276 
5277 EAPI Evas_Object *
ephysics_body_face_evas_object_unset(EPhysics_Body * body,EPhysics_Body_Face face)5278 ephysics_body_face_evas_object_unset(EPhysics_Body *body, EPhysics_Body_Face face)
5279 {
5280    if (!body)
5281      {
5282         ERR("Can't unset evas object from body, it wasn't provided.");
5283         return NULL;
5284      }
5285 
5286    if (body->type == EPHYSICS_BODY_TYPE_CLOTH)
5287      return _ephysics_body_cloth_face_evas_object_unset(body, face);
5288    if (body->type == EPHYSICS_BODY_TYPE_RIGID &&
5289        body->shape == EPHYSICS_BODY_SHAPE_CYLINDER)
5290      return _ephysics_body_cylinder_face_evas_object_unset(body, face);
5291    if (body->type == EPHYSICS_BODY_TYPE_RIGID &&
5292        body->shape == EPHYSICS_BODY_SHAPE_BOX)
5293      return _ephysics_body_box_face_evas_object_unset(body, face);
5294    if (body->type == EPHYSICS_BODY_TYPE_SOFT &&
5295        body->shape == EPHYSICS_BODY_SHAPE_SPHERE)
5296      return _ephysics_body_soft_sphere_face_evas_object_unset(body, face);
5297 
5298    ERR("Can't handle body %p type.", body);
5299    return NULL;
5300 }
5301 
5302 #ifdef  __cplusplus
5303 }
5304 #endif
5305