[dali_2.3.21] Merge branch 'devel/master'
[platform/core/uifw/dali-toolkit.git] / dali-physics / third-party / bullet3 / src / BulletCollision / Gimpact / gim_tri_collision.cpp
1
2 /*! \file gim_tri_collision.h
3 \author Francisco Leon Najera
4 */
5 /*
6 -----------------------------------------------------------------------------
7 This source file is part of GIMPACT Library.
8
9 For the latest info, see http://gimpact.sourceforge.net/
10
11 Copyright (c) 2006 Francisco Leon Najera. C.C. 80087371.
12 email: projectileman@yahoo.com
13
14  This library is free software; you can redistribute it and/or
15  modify it under the terms of EITHER:
16    (1) The GNU Lesser General Public License as published by the Free
17        Software Foundation; either version 2.1 of the License, or (at
18        your option) any later version. The text of the GNU Lesser
19        General Public License is included with this library in the
20        file GIMPACT-LICENSE-LGPL.TXT.
21    (2) The BSD-style license that is included with this library in
22        the file GIMPACT-LICENSE-BSD.TXT.
23    (3) The zlib/libpng license that is included with this library in
24        the file GIMPACT-LICENSE-ZLIB.TXT.
25
26  This library is distributed in the hope that it will be useful,
27  but WITHOUT ANY WARRANTY; without even the implied warranty of
28  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the files
29  GIMPACT-LICENSE-LGPL.TXT, GIMPACT-LICENSE-ZLIB.TXT and GIMPACT-LICENSE-BSD.TXT for more details.
30
31 -----------------------------------------------------------------------------
32 */
33
34 #include "gim_tri_collision.h"
35
36 #define TRI_LOCAL_EPSILON 0.000001f
37 #define MIN_EDGE_EDGE_DIS 0.00001f
38
39 class GIM_TRIANGLE_CALCULATION_CACHE
40 {
41 public:
42         GREAL margin;
43         btVector3 tu_vertices[3];
44         btVector3 tv_vertices[3];
45         btVector4 tu_plane;
46         btVector4 tv_plane;
47         btVector3 closest_point_u;
48         btVector3 closest_point_v;
49         btVector3 edge_edge_dir;
50         btVector3 distances;
51         GREAL du[4];
52         GREAL du0du1;
53         GREAL du0du2;
54         GREAL dv[4];
55         GREAL dv0dv1;
56         GREAL dv0dv2;
57         btVector3 temp_points[MAX_TRI_CLIPPING];
58         btVector3 temp_points1[MAX_TRI_CLIPPING];
59         btVector3 contact_points[MAX_TRI_CLIPPING];
60
61         //! if returns false, the faces are paralele
62         SIMD_FORCE_INLINE bool compute_intervals(
63                 const GREAL &D0,
64                 const GREAL &D1,
65                 const GREAL &D2,
66                 const GREAL &D0D1,
67                 const GREAL &D0D2,
68                 GREAL &scale_edge0,
69                 GREAL &scale_edge1,
70                 GUINT &edge_index0,
71                 GUINT &edge_index1)
72         {
73                 if (D0D1 > 0.0f)
74                 {
75                         /* here we know that D0D2<=0.0 */
76                         /* that is D0, D1 are on the same side, D2 on the other or on the plane */
77                         scale_edge0 = -D2 / (D0 - D2);
78                         scale_edge1 = -D1 / (D2 - D1);
79                         edge_index0 = 2;
80                         edge_index1 = 1;
81                 }
82                 else if (D0D2 > 0.0f)
83                 {
84                         /* here we know that d0d1<=0.0 */
85                         scale_edge0 = -D0 / (D1 - D0);
86                         scale_edge1 = -D1 / (D2 - D1);
87                         edge_index0 = 0;
88                         edge_index1 = 1;
89                 }
90                 else if (D1 * D2 > 0.0f || D0 != 0.0f)
91                 {
92                         /* here we know that d0d1<=0.0 or that D0!=0.0 */
93                         scale_edge0 = -D0 / (D1 - D0);
94                         scale_edge1 = -D2 / (D0 - D2);
95                         edge_index0 = 0;
96                         edge_index1 = 2;
97                 }
98                 else
99                 {
100                         return false;
101                 }
102                 return true;
103         }
104
105         //! clip triangle
106         /*!
107         */
108         SIMD_FORCE_INLINE GUINT clip_triangle(
109                 const btVector4 &tri_plane,
110                 const btVector3 *tripoints,
111                 const btVector3 *srcpoints,
112                 btVector3 *clip_points)
113         {
114                 // edge 0
115
116                 btVector4 edgeplane;
117
118                 EDGE_PLANE(tripoints[0], tripoints[1], tri_plane, edgeplane);
119
120                 GUINT clipped_count = PLANE_CLIP_TRIANGLE3D(
121                         edgeplane, srcpoints[0], srcpoints[1], srcpoints[2], temp_points);
122
123                 if (clipped_count == 0) return 0;
124
125                 // edge 1
126
127                 EDGE_PLANE(tripoints[1], tripoints[2], tri_plane, edgeplane);
128
129                 clipped_count = PLANE_CLIP_POLYGON3D(
130                         edgeplane, temp_points, clipped_count, temp_points1);
131
132                 if (clipped_count == 0) return 0;
133
134                 // edge 2
135
136                 EDGE_PLANE(tripoints[2], tripoints[0], tri_plane, edgeplane);
137
138                 clipped_count = PLANE_CLIP_POLYGON3D(
139                         edgeplane, temp_points1, clipped_count, clip_points);
140
141                 return clipped_count;
142
143                 /*GUINT i0 = (tri_plane.closestAxis()+1)%3;
144                 GUINT i1 = (i0+1)%3;
145                 // edge 0
146                 btVector3 temp_points[MAX_TRI_CLIPPING];
147                 btVector3 temp_points1[MAX_TRI_CLIPPING];
148
149                 GUINT clipped_count= PLANE_CLIP_TRIANGLE_GENERIC(
150                         0,srcpoints[0],srcpoints[1],srcpoints[2],temp_points,
151                         DISTANCE_EDGE(tripoints[0],tripoints[1],i0,i1));
152                 
153                 
154                 if(clipped_count == 0) return 0;
155
156                 // edge 1
157                 clipped_count = PLANE_CLIP_POLYGON_GENERIC(
158                         0,temp_points,clipped_count,temp_points1,
159                         DISTANCE_EDGE(tripoints[1],tripoints[2],i0,i1));
160
161                 if(clipped_count == 0) return 0;
162
163                 // edge 2
164                 clipped_count = PLANE_CLIP_POLYGON_GENERIC(
165                         0,temp_points1,clipped_count,clipped_points,
166                         DISTANCE_EDGE(tripoints[2],tripoints[0],i0,i1));
167
168                 return clipped_count;*/
169         }
170
171         SIMD_FORCE_INLINE void sort_isect(
172                 GREAL &isect0, GREAL &isect1, GUINT &e0, GUINT &e1, btVector3 &vec0, btVector3 &vec1)
173         {
174                 if (isect1 < isect0)
175                 {
176                         //swap
177                         GIM_SWAP_NUMBERS(isect0, isect1);
178                         GIM_SWAP_NUMBERS(e0, e1);
179                         btVector3 tmp = vec0;
180                         vec0 = vec1;
181                         vec1 = tmp;
182                 }
183         }
184
185         //! Test verifying interval intersection with the direction between planes
186         /*!
187         \pre tv_plane and tu_plane must be set
188         \post
189         distances[2] is set with the distance
190         closest_point_u, closest_point_v, edge_edge_dir are set too
191         \return
192         - 0: faces are paralele
193         - 1: face U casts face V
194         - 2: face V casts face U
195         - 3: nearest edges
196         */
197         SIMD_FORCE_INLINE GUINT cross_line_intersection_test()
198         {
199                 // Compute direction of intersection line
200                 edge_edge_dir = tu_plane.cross(tv_plane);
201                 GREAL Dlen;
202                 VEC_LENGTH(edge_edge_dir, Dlen);
203
204                 if (Dlen < 0.0001)
205                 {
206                         return 0;  //faces near paralele
207                 }
208
209                 edge_edge_dir *= 1 / Dlen;  //normalize
210
211                 // Compute interval for triangle 1
212                 GUINT tu_e0, tu_e1;              //edge indices
213                 GREAL tu_scale_e0, tu_scale_e1;  //edge scale
214                 if (!compute_intervals(du[0], du[1], du[2],
215                                                            du0du1, du0du2, tu_scale_e0, tu_scale_e1, tu_e0, tu_e1)) return 0;
216
217                 // Compute interval for triangle 2
218                 GUINT tv_e0, tv_e1;              //edge indices
219                 GREAL tv_scale_e0, tv_scale_e1;  //edge scale
220
221                 if (!compute_intervals(dv[0], dv[1], dv[2],
222                                                            dv0dv1, dv0dv2, tv_scale_e0, tv_scale_e1, tv_e0, tv_e1)) return 0;
223
224                 //proyected vertices
225                 btVector3 up_e0 = tu_vertices[tu_e0].lerp(tu_vertices[(tu_e0 + 1) % 3], tu_scale_e0);
226                 btVector3 up_e1 = tu_vertices[tu_e1].lerp(tu_vertices[(tu_e1 + 1) % 3], tu_scale_e1);
227
228                 btVector3 vp_e0 = tv_vertices[tv_e0].lerp(tv_vertices[(tv_e0 + 1) % 3], tv_scale_e0);
229                 btVector3 vp_e1 = tv_vertices[tv_e1].lerp(tv_vertices[(tv_e1 + 1) % 3], tv_scale_e1);
230
231                 //proyected intervals
232                 GREAL isect_u[] = {up_e0.dot(edge_edge_dir), up_e1.dot(edge_edge_dir)};
233                 GREAL isect_v[] = {vp_e0.dot(edge_edge_dir), vp_e1.dot(edge_edge_dir)};
234
235                 sort_isect(isect_u[0], isect_u[1], tu_e0, tu_e1, up_e0, up_e1);
236                 sort_isect(isect_v[0], isect_v[1], tv_e0, tv_e1, vp_e0, vp_e1);
237
238                 const GREAL midpoint_u = 0.5f * (isect_u[0] + isect_u[1]);  // midpoint
239                 const GREAL midpoint_v = 0.5f * (isect_v[0] + isect_v[1]);  // midpoint
240
241                 if (midpoint_u < midpoint_v)
242                 {
243                         if (isect_u[1] >= isect_v[1])  // face U casts face V
244                         {
245                                 return 1;
246                         }
247                         else if (isect_v[0] <= isect_u[0])  // face V casts face U
248                         {
249                                 return 2;
250                         }
251                         // closest points
252                         closest_point_u = up_e1;
253                         closest_point_v = vp_e0;
254                         // calc edges and separation
255
256                         if (isect_u[1] + MIN_EDGE_EDGE_DIS < isect_v[0])  //calc distance between two lines instead
257                         {
258                                 SEGMENT_COLLISION(
259                                         tu_vertices[tu_e1], tu_vertices[(tu_e1 + 1) % 3],
260                                         tv_vertices[tv_e0], tv_vertices[(tv_e0 + 1) % 3],
261                                         closest_point_u,
262                                         closest_point_v);
263
264                                 edge_edge_dir = closest_point_u - closest_point_v;
265                                 VEC_LENGTH(edge_edge_dir, distances[2]);
266                                 edge_edge_dir *= 1.0f / distances[2];  // normalize
267                         }
268                         else
269                         {
270                                 distances[2] = isect_v[0] - isect_u[1];  //distance negative
271                                                                                                                  //edge_edge_dir *= -1.0f; //normal pointing from V to U
272                         }
273                 }
274                 else
275                 {
276                         if (isect_v[1] >= isect_u[1])  // face V casts face U
277                         {
278                                 return 2;
279                         }
280                         else if (isect_u[0] <= isect_v[0])  // face U casts face V
281                         {
282                                 return 1;
283                         }
284                         // closest points
285                         closest_point_u = up_e0;
286                         closest_point_v = vp_e1;
287                         // calc edges and separation
288
289                         if (isect_v[1] + MIN_EDGE_EDGE_DIS < isect_u[0])  //calc distance between two lines instead
290                         {
291                                 SEGMENT_COLLISION(
292                                         tu_vertices[tu_e0], tu_vertices[(tu_e0 + 1) % 3],
293                                         tv_vertices[tv_e1], tv_vertices[(tv_e1 + 1) % 3],
294                                         closest_point_u,
295                                         closest_point_v);
296
297                                 edge_edge_dir = closest_point_u - closest_point_v;
298                                 VEC_LENGTH(edge_edge_dir, distances[2]);
299                                 edge_edge_dir *= 1.0f / distances[2];  // normalize
300                         }
301                         else
302                         {
303                                 distances[2] = isect_u[0] - isect_v[1];  //distance negative
304                                                                                                                  //edge_edge_dir *= -1.0f; //normal pointing from V to U
305                         }
306                 }
307                 return 3;
308         }
309
310         //! collides by two sides
311         SIMD_FORCE_INLINE bool triangle_collision(
312                 const btVector3 &u0,
313                 const btVector3 &u1,
314                 const btVector3 &u2,
315                 GREAL margin_u,
316                 const btVector3 &v0,
317                 const btVector3 &v1,
318                 const btVector3 &v2,
319                 GREAL margin_v,
320                 GIM_TRIANGLE_CONTACT_DATA &contacts)
321         {
322                 margin = margin_u + margin_v;
323
324                 tu_vertices[0] = u0;
325                 tu_vertices[1] = u1;
326                 tu_vertices[2] = u2;
327
328                 tv_vertices[0] = v0;
329                 tv_vertices[1] = v1;
330                 tv_vertices[2] = v2;
331
332                 //create planes
333                 // plane v vs U points
334
335                 TRIANGLE_PLANE(tv_vertices[0], tv_vertices[1], tv_vertices[2], tv_plane);
336
337                 du[0] = DISTANCE_PLANE_POINT(tv_plane, tu_vertices[0]);
338                 du[1] = DISTANCE_PLANE_POINT(tv_plane, tu_vertices[1]);
339                 du[2] = DISTANCE_PLANE_POINT(tv_plane, tu_vertices[2]);
340
341                 du0du1 = du[0] * du[1];
342                 du0du2 = du[0] * du[2];
343
344                 if (du0du1 > 0.0f && du0du2 > 0.0f)  // same sign on all of them + not equal 0 ?
345                 {
346                         if (du[0] < 0)  //we need test behind the triangle plane
347                         {
348                                 distances[0] = GIM_MAX3(du[0], du[1], du[2]);
349                                 distances[0] = -distances[0];
350                                 if (distances[0] > margin) return false;  //never intersect
351
352                                 //reorder triangle v
353                                 VEC_SWAP(tv_vertices[0], tv_vertices[1]);
354                                 VEC_SCALE_4(tv_plane, -1.0f, tv_plane);
355                         }
356                         else
357                         {
358                                 distances[0] = GIM_MIN3(du[0], du[1], du[2]);
359                                 if (distances[0] > margin) return false;  //never intersect
360                         }
361                 }
362                 else
363                 {
364                         //Look if we need to invert the triangle
365                         distances[0] = (du[0] + du[1] + du[2]) / 3.0f;  //centroid
366
367                         if (distances[0] < 0.0f)
368                         {
369                                 //reorder triangle v
370                                 VEC_SWAP(tv_vertices[0], tv_vertices[1]);
371                                 VEC_SCALE_4(tv_plane, -1.0f, tv_plane);
372
373                                 distances[0] = GIM_MAX3(du[0], du[1], du[2]);
374                                 distances[0] = -distances[0];
375                         }
376                         else
377                         {
378                                 distances[0] = GIM_MIN3(du[0], du[1], du[2]);
379                         }
380                 }
381
382                 // plane U vs V points
383
384                 TRIANGLE_PLANE(tu_vertices[0], tu_vertices[1], tu_vertices[2], tu_plane);
385
386                 dv[0] = DISTANCE_PLANE_POINT(tu_plane, tv_vertices[0]);
387                 dv[1] = DISTANCE_PLANE_POINT(tu_plane, tv_vertices[1]);
388                 dv[2] = DISTANCE_PLANE_POINT(tu_plane, tv_vertices[2]);
389
390                 dv0dv1 = dv[0] * dv[1];
391                 dv0dv2 = dv[0] * dv[2];
392
393                 if (dv0dv1 > 0.0f && dv0dv2 > 0.0f)  // same sign on all of them + not equal 0 ?
394                 {
395                         if (dv[0] < 0)  //we need test behind the triangle plane
396                         {
397                                 distances[1] = GIM_MAX3(dv[0], dv[1], dv[2]);
398                                 distances[1] = -distances[1];
399                                 if (distances[1] > margin) return false;  //never intersect
400
401                                 //reorder triangle u
402                                 VEC_SWAP(tu_vertices[0], tu_vertices[1]);
403                                 VEC_SCALE_4(tu_plane, -1.0f, tu_plane);
404                         }
405                         else
406                         {
407                                 distances[1] = GIM_MIN3(dv[0], dv[1], dv[2]);
408                                 if (distances[1] > margin) return false;  //never intersect
409                         }
410                 }
411                 else
412                 {
413                         //Look if we need to invert the triangle
414                         distances[1] = (dv[0] + dv[1] + dv[2]) / 3.0f;  //centroid
415
416                         if (distances[1] < 0.0f)
417                         {
418                                 //reorder triangle v
419                                 VEC_SWAP(tu_vertices[0], tu_vertices[1]);
420                                 VEC_SCALE_4(tu_plane, -1.0f, tu_plane);
421
422                                 distances[1] = GIM_MAX3(dv[0], dv[1], dv[2]);
423                                 distances[1] = -distances[1];
424                         }
425                         else
426                         {
427                                 distances[1] = GIM_MIN3(dv[0], dv[1], dv[2]);
428                         }
429                 }
430
431                 GUINT bl;
432                 /* bl = cross_line_intersection_test();
433                 if(bl==3)
434                 {
435                         //take edge direction too
436                         bl = distances.maxAxis();
437                 }
438                 else
439                 {*/
440                 bl = 0;
441                 if (distances[0] < distances[1]) bl = 1;
442                 //}
443
444                 if (bl == 2)  //edge edge separation
445                 {
446                         if (distances[2] > margin) return false;
447
448                         contacts.m_penetration_depth = -distances[2] + margin;
449                         contacts.m_points[0] = closest_point_v;
450                         contacts.m_point_count = 1;
451                         VEC_COPY(contacts.m_separating_normal, edge_edge_dir);
452
453                         return true;
454                 }
455
456                 //clip face against other
457
458                 GUINT point_count;
459                 //TODO
460                 if (bl == 0)  //clip U points against V
461                 {
462                         point_count = clip_triangle(tv_plane, tv_vertices, tu_vertices, contact_points);
463                         if (point_count == 0) return false;
464                         contacts.merge_points(tv_plane, margin, contact_points, point_count);
465                 }
466                 else  //clip V points against U
467                 {
468                         point_count = clip_triangle(tu_plane, tu_vertices, tv_vertices, contact_points);
469                         if (point_count == 0) return false;
470                         contacts.merge_points(tu_plane, margin, contact_points, point_count);
471                         contacts.m_separating_normal *= -1.f;
472                 }
473                 if (contacts.m_point_count == 0) return false;
474                 return true;
475         }
476 };
477
478 /*class GIM_TRIANGLE_CALCULATION_CACHE
479 {
480 public:
481         GREAL margin;
482         GUINT clipped_count;
483         btVector3 tu_vertices[3];
484         btVector3 tv_vertices[3];
485         btVector3 temp_points[MAX_TRI_CLIPPING];
486         btVector3 temp_points1[MAX_TRI_CLIPPING];
487         btVector3 clipped_points[MAX_TRI_CLIPPING];
488         GIM_TRIANGLE_CONTACT_DATA contacts1;
489         GIM_TRIANGLE_CONTACT_DATA contacts2;
490
491
492         //! clip triangle
493         GUINT clip_triangle(
494                 const btVector4 & tri_plane,
495                 const btVector3 * tripoints,
496                 const btVector3 * srcpoints,
497                 btVector3 * clipped_points)
498         {
499                 // edge 0
500
501                 btVector4 edgeplane;
502
503                 EDGE_PLANE(tripoints[0],tripoints[1],tri_plane,edgeplane);
504
505                 GUINT clipped_count = PLANE_CLIP_TRIANGLE3D(
506                         edgeplane,srcpoints[0],srcpoints[1],srcpoints[2],temp_points);
507
508                 if(clipped_count == 0) return 0;
509
510                 // edge 1
511
512                 EDGE_PLANE(tripoints[1],tripoints[2],tri_plane,edgeplane);
513
514                 clipped_count = PLANE_CLIP_POLYGON3D(
515                         edgeplane,temp_points,clipped_count,temp_points1);
516
517                 if(clipped_count == 0) return 0;
518
519                 // edge 2
520
521                 EDGE_PLANE(tripoints[2],tripoints[0],tri_plane,edgeplane);
522
523                 clipped_count = PLANE_CLIP_POLYGON3D(
524                         edgeplane,temp_points1,clipped_count,clipped_points);
525
526                 return clipped_count;
527         }
528
529
530
531
532         //! collides only on one side
533         bool triangle_collision(
534                                         const btVector3 & u0,
535                                         const btVector3 & u1,
536                                         const btVector3 & u2,
537                                         GREAL margin_u,
538                                         const btVector3 & v0,
539                                         const btVector3 & v1,
540                                         const btVector3 & v2,
541                                         GREAL margin_v,
542                                         GIM_TRIANGLE_CONTACT_DATA & contacts)
543         {
544
545                 margin = margin_u + margin_v;
546
547                 
548                 tu_vertices[0] = u0;
549                 tu_vertices[1] = u1;
550                 tu_vertices[2] = u2;
551
552                 tv_vertices[0] = v0;
553                 tv_vertices[1] = v1;
554                 tv_vertices[2] = v2;
555
556                 //create planes
557                 // plane v vs U points
558
559
560                 TRIANGLE_PLANE(tv_vertices[0],tv_vertices[1],tv_vertices[2],contacts1.m_separating_normal);
561
562                 clipped_count = clip_triangle(
563                         contacts1.m_separating_normal,tv_vertices,tu_vertices,clipped_points);
564
565                 if(clipped_count == 0 )
566                 {
567                          return false;//Reject
568                 }
569
570                 //find most deep interval face1
571                 contacts1.merge_points(contacts1.m_separating_normal,margin,clipped_points,clipped_count);
572                 if(contacts1.m_point_count == 0) return false; // too far
573
574                 //Normal pointing to triangle1
575                 //contacts1.m_separating_normal *= -1.f;
576
577                 //Clip tri1 by tri2 edges
578
579                 TRIANGLE_PLANE(tu_vertices[0],tu_vertices[1],tu_vertices[2],contacts2.m_separating_normal);
580
581                 clipped_count = clip_triangle(
582                         contacts2.m_separating_normal,tu_vertices,tv_vertices,clipped_points);
583
584                 if(clipped_count == 0 )
585                 {
586                          return false;//Reject
587                 }
588
589                 //find most deep interval face1
590                 contacts2.merge_points(contacts2.m_separating_normal,margin,clipped_points,clipped_count);
591                 if(contacts2.m_point_count == 0) return false; // too far
592
593                 contacts2.m_separating_normal *= -1.f;
594
595                 ////check most dir for contacts
596                 if(contacts2.m_penetration_depth<contacts1.m_penetration_depth)
597                 {
598                         contacts.copy_from(contacts2);
599                 }
600                 else
601                 {
602                         contacts.copy_from(contacts1);
603                 }
604                 return true;
605         }
606
607
608 };*/
609
610 bool GIM_TRIANGLE::collide_triangle_hard_test(
611         const GIM_TRIANGLE &other,
612         GIM_TRIANGLE_CONTACT_DATA &contact_data) const
613 {
614         GIM_TRIANGLE_CALCULATION_CACHE calc_cache;
615         return calc_cache.triangle_collision(
616                 m_vertices[0], m_vertices[1], m_vertices[2], m_margin,
617                 other.m_vertices[0], other.m_vertices[1], other.m_vertices[2], other.m_margin,
618                 contact_data);
619 }