3 -----------------------------------------------------------------------------
4 This source file is part of GIMPACT Library.
6 For the latest info, see http://gimpact.sourceforge.net/
8 Copyright (c) 2006 Francisco Leon. C.C. 80087371.
9 email: projectileman@yahoo.com
11 This library is free software; you can redistribute it and/or
12 modify it under the terms of EITHER:
13 (1) The GNU Lesser General Public License as published by the Free
14 Software Foundation; either version 2.1 of the License, or (at
15 your option) any later version. The text of the GNU Lesser
16 General Public License is included with this library in the
17 file GIMPACT-LICENSE-LGPL.TXT.
18 (2) The BSD-style license that is included with this library in
19 the file GIMPACT-LICENSE-BSD.TXT.
21 This library is distributed in the hope that it will be useful,
22 but WITHOUT ANY WARRANTY; without even the implied warranty of
23 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the files
24 GIMPACT-LICENSE-LGPL.TXT and GIMPACT-LICENSE-BSD.TXT for more details.
26 -----------------------------------------------------------------------------
30 #include "GIMPACT/gim_boxpruning.h"
34 //! Allocate memory for all aabb set.
35 void gim_aabbset_alloc(GIM_AABB_SET
* aabbset
, GUINT32 count
)
37 aabbset
->m_count
= count
;
38 aabbset
->m_boxes
= (aabb3f
*)gim_alloc(sizeof(aabb3f
)*count
);
40 if(count
<GIM_MIN_SORTED_BIPARTITE_PRUNING_BOXES
)
42 aabbset
->m_maxcoords
= 0;
43 aabbset
->m_sorted_mincoords
= 0;
47 aabbset
->m_maxcoords
= (GUINT32
*)gim_alloc(sizeof(GUINT32
)*aabbset
->m_count
);
48 aabbset
->m_sorted_mincoords
= (GIM_RSORT_TOKEN
*)gim_alloc(sizeof(GIM_RSORT_TOKEN
)*aabbset
->m_count
);
50 aabbset
->m_shared
= 0;
51 INVALIDATE_AABB(aabbset
->m_global_bound
);
54 //! Destroys the aabb set.
55 void gim_aabbset_destroy(GIM_AABB_SET
* aabbset
)
58 if(aabbset
->m_shared
==0)
60 gim_free(aabbset
->m_boxes
,0);
61 gim_free(aabbset
->m_maxcoords
,0);
62 gim_free(aabbset
->m_sorted_mincoords
,0);
65 aabbset
->m_sorted_mincoords
= 0;
66 aabbset
->m_maxcoords
= 0;
69 void gim_aabbset_calc_global_bound(GIM_AABB_SET
* aabbset
)
71 aabb3f
* paabb
= aabbset
->m_boxes
;
72 aabb3f
* globalbox
= &aabbset
->m_global_bound
;
73 AABB_COPY((*globalbox
),(*paabb
));
75 GUINT32 count
= aabbset
->m_count
-1;
79 MERGEBOXES(*globalbox
,*paabb
)
86 //! Sorts the boxes for box prunning.
88 1) find the integer representation of the aabb coords
89 2) Sorts the min coords
90 3) Calcs the global bound
91 \pre aabbset must be allocated. And the boxes must be already set.
93 \param calc_global_bound If 1 , calcs the global bound
94 \post If aabbset->m_sorted_mincoords == 0, then it allocs the sorted coordinates
96 void gim_aabbset_sort(GIM_AABB_SET
* aabbset
, char calc_global_bound
)
98 if(aabbset
->m_sorted_mincoords
== 0)
100 aabbset
->m_maxcoords
= (GUINT32
*)gim_alloc(sizeof(GUINT32
)*aabbset
->m_count
);
101 aabbset
->m_sorted_mincoords
= (GIM_RSORT_TOKEN
*)gim_alloc(sizeof(GIM_RSORT_TOKEN
)*aabbset
->m_count
);
104 GUINT32 i
, count
= aabbset
->m_count
;
105 aabb3f
* paabb
= aabbset
->m_boxes
;
106 GUINT32
* maxcoords
= aabbset
->m_maxcoords
;
107 GIM_RSORT_TOKEN
* sorted_tokens
= aabbset
->m_sorted_mincoords
;
109 if(count
<860)//Calibrated on a Pentium IV
115 GIM_CONVERT_VEC3F_GUINT_XZ_UPPER(paabb
[i
].maxX
,paabb
[i
].maxZ
,maxcoords
[i
]);
116 GIM_CONVERT_VEC3F_GUINT_XZ(paabb
[i
].minX
,paabb
[i
].minZ
,sorted_tokens
[i
].m_key
);
117 sorted_tokens
[i
].m_value
= i
;
119 GIM_QUICK_SORT_ARRAY(GIM_RSORT_TOKEN
, sorted_tokens
, count
, RSORT_TOKEN_COMPARATOR
,GIM_DEF_EXCHANGE_MACRO
);
124 GIM_RSORT_TOKEN
* unsorted
= (GIM_RSORT_TOKEN
*)gim_alloc(sizeof(GIM_RSORT_TOKEN
)*count
);
128 GIM_CONVERT_VEC3F_GUINT_XZ_UPPER(paabb
[i
].maxX
,paabb
[i
].maxZ
,maxcoords
[i
]);
129 GIM_CONVERT_VEC3F_GUINT_XZ(paabb
[i
].minX
,paabb
[i
].minZ
,unsorted
[i
].m_key
);
130 unsorted
[i
].m_value
= i
;
132 GIM_RADIX_SORT_RTOKENS(unsorted
,sorted_tokens
,count
);
133 gim_free(unsorted
,0);
136 if(calc_global_bound
) gim_aabbset_calc_global_bound(aabbset
);
141 /*#define PUSH_PAIR(i,j,pairset)\
143 GIM_PAIR _pair={i,j};\
144 GIM_DYNARRAY_PUSH_ITEM(GIM_PAIR,pairset,_pair);\
147 #define PUSH_PAIR(i,j,pairset)\
149 GIM_DYNARRAY_PUSH_EMPTY(GIM_PAIR,pairset);\
150 GIM_PAIR * _pair = GIM_DYNARRAY_POINTER(GIM_PAIR,pairset) + (pairset).m_size - 1;\
151 _pair->m_index1 = i;\
152 _pair->m_index2 = j;\
155 #define PUSH_PAIR_INV(i,j,pairset)\
157 GIM_DYNARRAY_PUSH_EMPTY(GIM_PAIR,pairset);\
158 GIM_PAIR * _pair = GIM_DYNARRAY_POINTER(GIM_PAIR,pairset) + (pairset).m_size - 1;\
159 _pair->m_index1 = j;\
160 _pair->m_index2 = i;\
163 #define FIND_OVERLAPPING_FOWARD(\
173 GUINT32 _i = test_count;\
175 GIM_RSORT_TOKEN * _psorted_tokens = sorted_tokens;\
176 while(_i>0 && max_coord_uint >= _psorted_tokens->m_key)\
178 AABBCOLLISION(_intersected,test_aabb,aabbarray[_psorted_tokens->m_value]);\
181 push_pair_macro(curr_index, _psorted_tokens->m_value,pairset);\
188 //! log(N) Complete box pruning. Returns a list of overlapping pairs of boxes, each box of the pair belongs to the same set.
190 \pre aabbset must be allocated and sorted, the boxes must be already set.
191 \param aabbset Must be sorted. Global bound isn't required
192 \param collision_pairs Array of GIM_PAIR elements. Must be initialized before (Reserve size ~ 100)
194 void gim_aabbset_self_intersections_sorted(GIM_AABB_SET
* aabbset
, GDYNAMIC_ARRAY
* collision_pairs
)
196 collision_pairs
->m_size
= 0;
197 GUINT32 count
= aabbset
->m_count
;
198 aabb3f
* paabb
= aabbset
->m_boxes
;
199 GUINT32
* maxcoords
= aabbset
->m_maxcoords
;
200 GIM_RSORT_TOKEN
* sorted_tokens
= aabbset
->m_sorted_mincoords
;
204 ///current cache variables
205 GUINT32 curr_index
= sorted_tokens
->m_value
;
206 GUINT32 max_coord_uint
= maxcoords
[curr_index
];
207 AABB_COPY(test_aabb
,paabb
[curr_index
]);
212 FIND_OVERLAPPING_FOWARD( curr_index
, count
, test_aabb
, max_coord_uint
, sorted_tokens
, paabb
, (*collision_pairs
),PUSH_PAIR
);
216 //! NxN Complete box pruning. Returns a list of overlapping pairs of boxes, each box of the pair belongs to the same set.
218 \pre aabbset must be allocated, the boxes must be already set.
219 \param aabbset Global bound isn't required. Doen't need to be sorted.
220 \param collision_pairs Array of GIM_PAIR elements. Must be initialized before (Reserve size ~ 100)
222 void gim_aabbset_self_intersections_brute_force(GIM_AABB_SET
* aabbset
, GDYNAMIC_ARRAY
* collision_pairs
)
224 collision_pairs
->m_size
= 0;
226 GUINT32 count
= aabbset
->m_count
;
227 aabb3f
* paabb
= aabbset
->m_boxes
;
229 for (i
=0;i
< count
-1 ;i
++ )
231 for (j
=i
+1;j
<count
;j
++ )
233 AABBCOLLISION(intersected
,paabb
[i
],paabb
[j
]);
236 PUSH_PAIR(i
,j
,(*collision_pairs
));
242 //! log(N) Bipartite box pruning. Returns a list of overlapping pairs of boxes, each box of the pair belongs to a different set.
244 \pre aabbset1 and aabbset2 must be allocated and sorted, the boxes must be already set.
245 \param aabbset1 Must be sorted, Global bound is required.
246 \param aabbset2 Must be sorted, Global bound is required.
247 \param collision_pairs Array of GIM_PAIR elements. Must be initialized before (Reserve size ~ 100)
249 void gim_aabbset_bipartite_intersections_sorted(GIM_AABB_SET
* aabbset1
, GIM_AABB_SET
* aabbset2
, GDYNAMIC_ARRAY
* collision_pairs
)
252 collision_pairs
->m_size
= 0;
254 AABBCOLLISION(intersected
,aabbset1
->m_global_bound
,aabbset2
->m_global_bound
);
255 if(intersected
== 0) return;
257 GUINT32 count1
= aabbset1
->m_count
;
258 aabb3f
* paabb1
= aabbset1
->m_boxes
;
259 GUINT32
* maxcoords1
= aabbset1
->m_maxcoords
;
260 GIM_RSORT_TOKEN
* sorted_tokens1
= aabbset1
->m_sorted_mincoords
;
262 GUINT32 count2
= aabbset2
->m_count
;
263 aabb3f
* paabb2
= aabbset2
->m_boxes
;
264 GUINT32
* maxcoords2
= aabbset2
->m_maxcoords
;
265 GIM_RSORT_TOKEN
* sorted_tokens2
= aabbset2
->m_sorted_mincoords
;
269 GUINT32 max_coord_uint
;
273 //Find Set intersection
275 BOXINTERSECTION(aabbset1
->m_global_bound
,aabbset2
->m_global_bound
, int_abbb
);
278 GIM_RSORT_TOKEN
* classified_tokens1
= (GIM_RSORT_TOKEN
*) gim_alloc(sizeof(GIM_RSORT_TOKEN
)*count1
);
279 GUINT32 i
,classified_count1
= 0,classified_count2
= 0;
282 for (i
=0;i
<count1
;i
++ )
284 curr_index
= sorted_tokens1
[i
].m_value
;
285 AABBCOLLISION(intersected
,paabb1
[curr_index
],int_abbb
);
288 classified_tokens1
[classified_count1
] = sorted_tokens1
[i
];
293 if(classified_count1
==0)
295 gim_free(classified_tokens1
,0);
300 GIM_RSORT_TOKEN
* classified_tokens2
= (GIM_RSORT_TOKEN
*) gim_alloc(sizeof(GIM_RSORT_TOKEN
)*count2
);
302 for (i
=0;i
<count2
;i
++ )
304 curr_index
= sorted_tokens2
[i
].m_value
;
305 AABBCOLLISION(intersected
,paabb2
[curr_index
],int_abbb
);
308 classified_tokens2
[classified_count2
] = sorted_tokens2
[i
];
313 if(classified_count2
==0)
315 gim_free(classified_tokens1
,0);
316 gim_free(classified_tokens2
,0);
320 sorted_tokens1
= classified_tokens1
;
321 sorted_tokens2
= classified_tokens2
;
323 while(classified_count1
>0&&classified_count2
>0)
325 if(sorted_tokens1
->m_key
<= sorted_tokens2
->m_key
)
327 ///current cache variables
328 curr_index
= sorted_tokens1
->m_value
;
329 max_coord_uint
= maxcoords1
[curr_index
];
330 AABB_COPY(test_aabb
,paabb1
[curr_index
]);
334 FIND_OVERLAPPING_FOWARD( curr_index
, classified_count2
, test_aabb
, max_coord_uint
, sorted_tokens2
, paabb2
, (*collision_pairs
), PUSH_PAIR
);
338 ///current cache variables
339 curr_index
= sorted_tokens2
->m_value
;
340 max_coord_uint
= maxcoords2
[curr_index
];
341 AABB_COPY(test_aabb
,paabb2
[curr_index
]);
345 FIND_OVERLAPPING_FOWARD( curr_index
, classified_count1
, test_aabb
, max_coord_uint
, sorted_tokens1
, paabb1
, (*collision_pairs
), PUSH_PAIR_INV
);
348 gim_free(classified_tokens1
,0);
349 gim_free(classified_tokens2
,0);
352 //! NxM Bipartite box pruning. Returns a list of overlapping pairs of boxes, each box of the pair belongs to a different set.
354 \pre aabbset1 and aabbset2 must be allocated and sorted, the boxes must be already set.
355 \param aabbset1 Must be sorted, Global bound is required.
356 \param aabbset2 Must be sorted, Global bound is required.
357 \param collision_pairs Array of GIM_PAIR elements. Must be initialized before (Reserve size ~ 100)
359 void gim_aabbset_bipartite_intersections_brute_force(GIM_AABB_SET
* aabbset1
,GIM_AABB_SET
* aabbset2
, GDYNAMIC_ARRAY
* collision_pairs
)
362 collision_pairs
->m_size
= 0;
363 AABBCOLLISION(intersected
,aabbset1
->m_global_bound
,aabbset2
->m_global_bound
);
364 if(intersected
== 0) return;
367 //Find Set intersection
368 BOXINTERSECTION(aabbset1
->m_global_bound
,aabbset2
->m_global_bound
, int_abbb
);
371 GUINT32 classified_count
= 0;
373 GUINT32 count
= aabbset1
->m_count
;
374 aabb3f
* paabb1
= aabbset1
->m_boxes
;
375 aabb3f
* paabb2
= aabbset2
->m_boxes
;
377 GUINT32
* classified
= (GUINT32
*) gim_alloc(sizeof(GUINT32
)*count
);
379 for (i
=0;i
<count
;i
++ )
381 AABBCOLLISION(intersected
,paabb1
[i
],int_abbb
);
384 classified
[classified_count
] = i
;
389 if(classified_count
==0)
391 gim_free(classified
,0);
396 count
= aabbset2
->m_count
;
397 for (i
=0;i
<count
;i
++)
399 AABBCOLLISION(intersected
,paabb2
[i
],int_abbb
);
402 for (j
=0;j
<classified_count
;j
++)
404 AABBCOLLISION(intersected
,paabb2
[i
],paabb1
[classified
[j
]]);
407 PUSH_PAIR(classified
[j
],i
,(*collision_pairs
));
412 gim_free(classified
,0);
416 //! Initalizes the set. Sort Boxes if needed.
418 \pre aabbset must be allocated. And the boxes must be already set.
419 \post If the set has less of GIM_MIN_SORTED_BIPARTITE_PRUNING_BOXES boxes, only calcs the global box,
420 else it Sorts the entire set( Only applicable for large sets)
422 void gim_aabbset_update(GIM_AABB_SET
* aabbset
)
424 if(aabbset
->m_count
< GIM_MIN_SORTED_BIPARTITE_PRUNING_BOXES
)
425 {//Brute force approach
426 gim_aabbset_calc_global_bound(aabbset
);
429 {//Sorted force approach
430 gim_aabbset_sort(aabbset
,1);
434 //! Complete box pruning. Returns a list of overlapping pairs of boxes, each box of the pair belongs to the same set.
436 This function sorts the set and then it calls to gim_aabbset_self_intersections_brute_force or gim_aabbset_self_intersections_sorted.
438 \param aabbset Set of boxes. Sorting isn't required.
439 \param collision_pairs Array of GIM_PAIR elements. Must be initialized before (Reserve size ~ 100)
440 \pre aabbset must be allocated and initialized.
441 \post If aabbset->m_count >= GIM_MIN_SORTED_PRUNING_BOXES, then it calls to gim_aabbset_sort and then to gim_aabbset_self_intersections_sorted.
443 void gim_aabbset_self_intersections(GIM_AABB_SET
* aabbset
, GDYNAMIC_ARRAY
* collision_pairs
)
445 if(aabbset
->m_count
< GIM_MIN_SORTED_PRUNING_BOXES
)
446 {//Brute force approach
447 gim_aabbset_self_intersections_brute_force(aabbset
,collision_pairs
);
450 {//Sorted force approach
451 gim_aabbset_sort(aabbset
,0);
452 gim_aabbset_self_intersections_sorted(aabbset
,collision_pairs
);
456 //! Collides two sets. Returns a list of overlapping pairs of boxes, each box of the pair belongs to a different set.
458 \pre aabbset1 and aabbset2 must be allocated and updated. See .
459 \param aabbset1 Must be sorted, Global bound is required.
460 \param aabbset2 Must be sorted, Global bound is required.
461 \param collision_pairs Array of GIM_PAIR elements. Must be initialized before (Reserve size ~ 100)
463 void gim_aabbset_bipartite_intersections(GIM_AABB_SET
* aabbset1
, GIM_AABB_SET
* aabbset2
, GDYNAMIC_ARRAY
* collision_pairs
)
465 if(aabbset1
->m_sorted_mincoords
== 0||aabbset2
->m_sorted_mincoords
== 0)
466 {//Brute force approach
467 gim_aabbset_bipartite_intersections_brute_force(aabbset1
,aabbset2
,collision_pairs
);
470 {//Sorted force approach
471 gim_aabbset_bipartite_intersections_sorted(aabbset1
,aabbset2
,collision_pairs
);
475 void gim_aabbset_box_collision(aabb3f
*test_aabb
, GIM_AABB_SET
* aabbset
, GDYNAMIC_ARRAY
* collided
)
477 collided
->m_size
= 0;
479 AABBCOLLISION(intersected
,aabbset
->m_global_bound
,(*test_aabb
));
480 if(intersected
== 0) return;
483 GUINT32 count
= aabbset
->m_count
;
484 aabb3f
* paabb
= aabbset
->m_boxes
;
486 AABB_COPY(_testaabb
,*test_aabb
);
488 for (i
=0;i
< count
;i
++ )
490 AABBCOLLISION(intersected
,paabb
[i
],_testaabb
);
493 GIM_DYNARRAY_PUSH_ITEM(GUINT32
,(*collided
),i
);
498 void gim_aabbset_ray_collision(vec3f vorigin
,vec3f vdir
, GREAL tmax
, GIM_AABB_SET
* aabbset
, GDYNAMIC_ARRAY
* collided
)
500 collided
->m_size
= 0;
503 BOX_INTERSECTS_RAY(aabbset
->m_global_bound
, vorigin
, vdir
, tparam
, tmax
,intersected
);
504 if(intersected
==0) return;
507 GUINT32 count
= aabbset
->m_count
;
508 aabb3f
* paabb
= aabbset
->m_boxes
;
510 for (i
=0;i
< count
;i
++ )
512 BOX_INTERSECTS_RAY(paabb
[i
], vorigin
, vdir
, tparam
, tmax
,intersected
);
515 GIM_DYNARRAY_PUSH_ITEM(GUINT32
,(*collided
),i
);