00001 #ifndef GIM_BOX_SET_H_INCLUDED
00002 #define GIM_BOX_SET_H_INCLUDED
00003
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021
00022
00023
00024
00025
00026
00027
00028
00029
00030
00031
00032
00033
00034
00035
00036
00037 #include "gim_array.h"
00038 #include "gim_radixsort.h"
00039 #include "gim_box_collision.h"
00040 #include "gim_tri_collision.h"
00041
00042
00043
00045 struct GIM_PAIR
00046 {
00047 GUINT m_index1;
00048 GUINT m_index2;
00049 GIM_PAIR()
00050 {}
00051
00052 GIM_PAIR(const GIM_PAIR & p)
00053 {
00054 m_index1 = p.m_index1;
00055 m_index2 = p.m_index2;
00056 }
00057
00058 GIM_PAIR(GUINT index1, GUINT index2)
00059 {
00060 m_index1 = index1;
00061 m_index2 = index2;
00062 }
00063 };
00064
00066 class gim_pair_set: public gim_array<GIM_PAIR>
00067 {
00068 public:
00069 gim_pair_set():gim_array<GIM_PAIR>(32)
00070 {
00071 }
00072 inline void push_pair(GUINT index1,GUINT index2)
00073 {
00074 push_back(GIM_PAIR(index1,index2));
00075 }
00076
00077 inline void push_pair_inv(GUINT index1,GUINT index2)
00078 {
00079 push_back(GIM_PAIR(index2,index1));
00080 }
00081 };
00082
00083
00085
00090 class GIM_PRIMITIVE_MANAGER_PROTOTYPE
00091 {
00092 public:
00093
00094 virtual ~GIM_PRIMITIVE_MANAGER_PROTOTYPE() {}
00096 virtual bool is_trimesh() = 0;
00097 virtual GUINT get_primitive_count() = 0;
00098 virtual void get_primitive_box(GUINT prim_index ,GIM_AABB & primbox) = 0;
00099 virtual void get_primitive_triangle(GUINT prim_index,GIM_TRIANGLE & triangle) = 0;
00100 };
00101
00102
00103 struct GIM_AABB_DATA
00104 {
00105 GIM_AABB m_bound;
00106 GUINT m_data;
00107 };
00108
00110 struct GIM_BOX_TREE_NODE
00111 {
00112 GIM_AABB m_bound;
00113 GUINT m_left;
00114 GUINT m_right;
00115 GUINT m_escapeIndex;
00116 GUINT m_data;
00117
00118 GIM_BOX_TREE_NODE()
00119 {
00120 m_left = 0;
00121 m_right = 0;
00122 m_escapeIndex = 0;
00123 m_data = 0;
00124 }
00125
00126 SIMD_FORCE_INLINE bool is_leaf_node() const
00127 {
00128 return (!m_left && !m_right);
00129 }
00130 };
00131
00133 class GIM_BOX_TREE
00134 {
00135 protected:
00136 GUINT m_num_nodes;
00137 gim_array<GIM_BOX_TREE_NODE> m_node_array;
00138 protected:
00139 GUINT _sort_and_calc_splitting_index(
00140 gim_array<GIM_AABB_DATA> & primitive_boxes,
00141 GUINT startIndex, GUINT endIndex, GUINT splitAxis);
00142
00143 GUINT _calc_splitting_axis(gim_array<GIM_AABB_DATA> & primitive_boxes, GUINT startIndex, GUINT endIndex);
00144
00145 void _build_sub_tree(gim_array<GIM_AABB_DATA> & primitive_boxes, GUINT startIndex, GUINT endIndex);
00146 public:
00147 GIM_BOX_TREE()
00148 {
00149 m_num_nodes = 0;
00150 }
00151
00154 void build_tree(gim_array<GIM_AABB_DATA> & primitive_boxes);
00155
00156 SIMD_FORCE_INLINE void clearNodes()
00157 {
00158 m_node_array.clear();
00159 m_num_nodes = 0;
00160 }
00161
00163 SIMD_FORCE_INLINE GUINT getNodeCount() const
00164 {
00165 return m_num_nodes;
00166 }
00167
00169 SIMD_FORCE_INLINE bool isLeafNode(GUINT nodeindex) const
00170 {
00171 return m_node_array[nodeindex].is_leaf_node();
00172 }
00173
00174 SIMD_FORCE_INLINE GUINT getNodeData(GUINT nodeindex) const
00175 {
00176 return m_node_array[nodeindex].m_data;
00177 }
00178
00179 SIMD_FORCE_INLINE void getNodeBound(GUINT nodeindex, GIM_AABB & bound) const
00180 {
00181 bound = m_node_array[nodeindex].m_bound;
00182 }
00183
00184 SIMD_FORCE_INLINE void setNodeBound(GUINT nodeindex, const GIM_AABB & bound)
00185 {
00186 m_node_array[nodeindex].m_bound = bound;
00187 }
00188
00189 SIMD_FORCE_INLINE GUINT getLeftNodeIndex(GUINT nodeindex) const
00190 {
00191 return m_node_array[nodeindex].m_left;
00192 }
00193
00194 SIMD_FORCE_INLINE GUINT getRightNodeIndex(GUINT nodeindex) const
00195 {
00196 return m_node_array[nodeindex].m_right;
00197 }
00198
00199 SIMD_FORCE_INLINE GUINT getScapeNodeIndex(GUINT nodeindex) const
00200 {
00201 return m_node_array[nodeindex].m_escapeIndex;
00202 }
00203
00205 };
00206
00207
00209
00214 template<typename _GIM_PRIMITIVE_MANAGER_PROTOTYPE, typename _GIM_BOX_TREE_PROTOTYPE>
00215 class GIM_BOX_TREE_TEMPLATE_SET
00216 {
00217 protected:
00218 _GIM_PRIMITIVE_MANAGER_PROTOTYPE m_primitive_manager;
00219 _GIM_BOX_TREE_PROTOTYPE m_box_tree;
00220 protected:
00221
00222 SIMD_FORCE_INLINE void refit()
00223 {
00224 GUINT nodecount = getNodeCount();
00225 while(nodecount--)
00226 {
00227 if(isLeafNode(nodecount))
00228 {
00229 GIM_AABB leafbox;
00230 m_primitive_manager.get_primitive_box(getNodeData(nodecount),leafbox);
00231 setNodeBound(nodecount,leafbox);
00232 }
00233 else
00234 {
00235
00236 GUINT childindex = getLeftNodeIndex(nodecount);
00237 GIM_AABB bound;
00238 getNodeBound(childindex,bound);
00239
00240 childindex = getRightNodeIndex(nodecount);
00241 GIM_AABB bound2;
00242 getNodeBound(childindex,bound2);
00243 bound.merge(bound2);
00244
00245 setNodeBound(nodecount,bound);
00246 }
00247 }
00248 }
00249 public:
00250
00251 GIM_BOX_TREE_TEMPLATE_SET()
00252 {
00253 }
00254
00255 SIMD_FORCE_INLINE GIM_AABB getGlobalBox() const
00256 {
00257 GIM_AABB totalbox;
00258 getNodeBound(0, totalbox);
00259 return totalbox;
00260 }
00261
00262 SIMD_FORCE_INLINE void setPrimitiveManager(const _GIM_PRIMITIVE_MANAGER_PROTOTYPE & primitive_manager)
00263 {
00264 m_primitive_manager = primitive_manager;
00265 }
00266
00267 const _GIM_PRIMITIVE_MANAGER_PROTOTYPE & getPrimitiveManager() const
00268 {
00269 return m_primitive_manager;
00270 }
00271
00272 _GIM_PRIMITIVE_MANAGER_PROTOTYPE & getPrimitiveManager()
00273 {
00274 return m_primitive_manager;
00275 }
00276
00279
00281 SIMD_FORCE_INLINE void update()
00282 {
00283 refit();
00284 }
00285
00287 SIMD_FORCE_INLINE void buildSet()
00288 {
00289
00290 gim_array<GIM_AABB_DATA> primitive_boxes;
00291 primitive_boxes.resize(m_primitive_manager.get_primitive_count(),false);
00292
00293 for (GUINT i = 0;i<primitive_boxes.size() ;i++ )
00294 {
00295 m_primitive_manager.get_primitive_box(i,primitive_boxes[i].m_bound);
00296 primitive_boxes[i].m_data = i;
00297 }
00298
00299 m_box_tree.build_tree(primitive_boxes);
00300 }
00301
00303 SIMD_FORCE_INLINE bool boxQuery(const GIM_AABB & box, gim_array<GUINT> & collided_results) const
00304 {
00305 GUINT curIndex = 0;
00306 GUINT numNodes = getNodeCount();
00307
00308 while (curIndex < numNodes)
00309 {
00310 GIM_AABB bound;
00311 getNodeBound(curIndex,bound);
00312
00313
00314
00315 bool aabbOverlap = bound.has_collision(box);
00316 bool isleafnode = isLeafNode(curIndex);
00317
00318 if (isleafnode && aabbOverlap)
00319 {
00320 collided_results.push_back(getNodeData(curIndex));
00321 }
00322
00323 if (aabbOverlap || isleafnode)
00324 {
00325
00326 curIndex++;
00327 }
00328 else
00329 {
00330
00331 curIndex+= getScapeNodeIndex(curIndex);
00332 }
00333 }
00334 if(collided_results.size()>0) return true;
00335 return false;
00336 }
00337
00339 SIMD_FORCE_INLINE bool boxQueryTrans(const GIM_AABB & box,
00340 const btTransform & transform, gim_array<GUINT> & collided_results) const
00341 {
00342 GIM_AABB transbox=box;
00343 transbox.appy_transform(transform);
00344 return boxQuery(transbox,collided_results);
00345 }
00346
00348 SIMD_FORCE_INLINE bool rayQuery(
00349 const btVector3 & ray_dir,const btVector3 & ray_origin ,
00350 gim_array<GUINT> & collided_results) const
00351 {
00352 GUINT curIndex = 0;
00353 GUINT numNodes = getNodeCount();
00354
00355 while (curIndex < numNodes)
00356 {
00357 GIM_AABB bound;
00358 getNodeBound(curIndex,bound);
00359
00360
00361
00362 bool aabbOverlap = bound.collide_ray(ray_origin,ray_dir);
00363 bool isleafnode = isLeafNode(curIndex);
00364
00365 if (isleafnode && aabbOverlap)
00366 {
00367 collided_results.push_back(getNodeData( curIndex));
00368 }
00369
00370 if (aabbOverlap || isleafnode)
00371 {
00372
00373 curIndex++;
00374 }
00375 else
00376 {
00377
00378 curIndex+= getScapeNodeIndex(curIndex);
00379 }
00380 }
00381 if(collided_results.size()>0) return true;
00382 return false;
00383 }
00384
00386 SIMD_FORCE_INLINE bool hasHierarchy() const
00387 {
00388 return true;
00389 }
00390
00392 SIMD_FORCE_INLINE bool isTrimesh() const
00393 {
00394 return m_primitive_manager.is_trimesh();
00395 }
00396
00398 SIMD_FORCE_INLINE GUINT getNodeCount() const
00399 {
00400 return m_box_tree.getNodeCount();
00401 }
00402
00404 SIMD_FORCE_INLINE bool isLeafNode(GUINT nodeindex) const
00405 {
00406 return m_box_tree.isLeafNode(nodeindex);
00407 }
00408
00409 SIMD_FORCE_INLINE GUINT getNodeData(GUINT nodeindex) const
00410 {
00411 return m_box_tree.getNodeData(nodeindex);
00412 }
00413
00414 SIMD_FORCE_INLINE void getNodeBound(GUINT nodeindex, GIM_AABB & bound) const
00415 {
00416 m_box_tree.getNodeBound(nodeindex, bound);
00417 }
00418
00419 SIMD_FORCE_INLINE void setNodeBound(GUINT nodeindex, const GIM_AABB & bound)
00420 {
00421 m_box_tree.setNodeBound(nodeindex, bound);
00422 }
00423
00424 SIMD_FORCE_INLINE GUINT getLeftNodeIndex(GUINT nodeindex) const
00425 {
00426 return m_box_tree.getLeftNodeIndex(nodeindex);
00427 }
00428
00429 SIMD_FORCE_INLINE GUINT getRightNodeIndex(GUINT nodeindex) const
00430 {
00431 return m_box_tree.getRightNodeIndex(nodeindex);
00432 }
00433
00434 SIMD_FORCE_INLINE GUINT getScapeNodeIndex(GUINT nodeindex) const
00435 {
00436 return m_box_tree.getScapeNodeIndex(nodeindex);
00437 }
00438
00439 SIMD_FORCE_INLINE void getNodeTriangle(GUINT nodeindex,GIM_TRIANGLE & triangle) const
00440 {
00441 m_primitive_manager.get_primitive_triangle(getNodeData(nodeindex),triangle);
00442 }
00443
00444 };
00445
00447
00450 template<typename _GIM_PRIMITIVE_MANAGER_PROTOTYPE>
00451 class GIM_BOX_TREE_SET: public GIM_BOX_TREE_TEMPLATE_SET< _GIM_PRIMITIVE_MANAGER_PROTOTYPE, GIM_BOX_TREE>
00452 {
00453 public:
00454
00455 };
00456
00457
00458
00459
00460
00462 template<typename BOX_SET_CLASS0,typename BOX_SET_CLASS1>
00463 class GIM_TREE_TREE_COLLIDER
00464 {
00465 public:
00466 gim_pair_set * m_collision_pairs;
00467 BOX_SET_CLASS0 * m_boxset0;
00468 BOX_SET_CLASS1 * m_boxset1;
00469 GUINT current_node0;
00470 GUINT current_node1;
00471 bool node0_is_leaf;
00472 bool node1_is_leaf;
00473 bool t0_is_trimesh;
00474 bool t1_is_trimesh;
00475 bool node0_has_triangle;
00476 bool node1_has_triangle;
00477 GIM_AABB m_box0;
00478 GIM_AABB m_box1;
00479 GIM_BOX_BOX_TRANSFORM_CACHE trans_cache_1to0;
00480 btTransform trans_cache_0to1;
00481 GIM_TRIANGLE m_tri0;
00482 btVector4 m_tri0_plane;
00483 GIM_TRIANGLE m_tri1;
00484 btVector4 m_tri1_plane;
00485
00486
00487 public:
00488 GIM_TREE_TREE_COLLIDER()
00489 {
00490 current_node0 = G_UINT_INFINITY;
00491 current_node1 = G_UINT_INFINITY;
00492 }
00493 protected:
00494 SIMD_FORCE_INLINE void retrieve_node0_triangle(GUINT node0)
00495 {
00496 if(node0_has_triangle) return;
00497 m_boxset0->getNodeTriangle(node0,m_tri0);
00498
00499 m_tri0.m_vertices[0] = trans_cache_0to1(m_tri0.m_vertices[0]);
00500 m_tri0.m_vertices[1] = trans_cache_0to1(m_tri0.m_vertices[1]);
00501 m_tri0.m_vertices[2] = trans_cache_0to1(m_tri0.m_vertices[2]);
00502 m_tri0.get_plane(m_tri0_plane);
00503
00504 node0_has_triangle = true;
00505 }
00506
00507 SIMD_FORCE_INLINE void retrieve_node1_triangle(GUINT node1)
00508 {
00509 if(node1_has_triangle) return;
00510 m_boxset1->getNodeTriangle(node1,m_tri1);
00511
00512 m_tri1.m_vertices[0] = trans_cache_1to0.transform(m_tri1.m_vertices[0]);
00513 m_tri1.m_vertices[1] = trans_cache_1to0.transform(m_tri1.m_vertices[1]);
00514 m_tri1.m_vertices[2] = trans_cache_1to0.transform(m_tri1.m_vertices[2]);
00515 m_tri1.get_plane(m_tri1_plane);
00516
00517 node1_has_triangle = true;
00518 }
00519
00520 SIMD_FORCE_INLINE void retrieve_node0_info(GUINT node0)
00521 {
00522 if(node0 == current_node0) return;
00523 m_boxset0->getNodeBound(node0,m_box0);
00524 node0_is_leaf = m_boxset0->isLeafNode(node0);
00525 node0_has_triangle = false;
00526 current_node0 = node0;
00527 }
00528
00529 SIMD_FORCE_INLINE void retrieve_node1_info(GUINT node1)
00530 {
00531 if(node1 == current_node1) return;
00532 m_boxset1->getNodeBound(node1,m_box1);
00533 node1_is_leaf = m_boxset1->isLeafNode(node1);
00534 node1_has_triangle = false;
00535 current_node1 = node1;
00536 }
00537
00538 SIMD_FORCE_INLINE bool node_collision(GUINT node0 ,GUINT node1)
00539 {
00540 retrieve_node0_info(node0);
00541 retrieve_node1_info(node1);
00542 bool result = m_box0.overlapping_trans_cache(m_box1,trans_cache_1to0,true);
00543 if(!result) return false;
00544
00545 if(t0_is_trimesh && node0_is_leaf)
00546 {
00547
00548 retrieve_node0_triangle(node0);
00549
00550 m_box1.increment_margin(m_tri0.m_margin);
00551
00552 result = m_box1.collide_triangle_exact(
00553 m_tri0.m_vertices[0],m_tri0.m_vertices[1],m_tri0.m_vertices[2],m_tri0_plane);
00554
00555 m_box1.increment_margin(-m_tri0.m_margin);
00556
00557 if(!result) return false;
00558 return true;
00559 }
00560 else if(t1_is_trimesh && node1_is_leaf)
00561 {
00562
00563 retrieve_node1_triangle(node1);
00564
00565 m_box0.increment_margin(m_tri1.m_margin);
00566
00567 result = m_box0.collide_triangle_exact(
00568 m_tri1.m_vertices[0],m_tri1.m_vertices[1],m_tri1.m_vertices[2],m_tri1_plane);
00569
00570 m_box0.increment_margin(-m_tri1.m_margin);
00571
00572 if(!result) return false;
00573 return true;
00574 }
00575 return true;
00576 }
00577
00578
00579 void find_collision_pairs()
00580 {
00581 gim_pair_set stack_collisions;
00582 stack_collisions.reserve(32);
00583
00584
00585 stack_collisions.push_pair(0,0);
00586
00587
00588 while(stack_collisions.size())
00589 {
00590
00591 GUINT node0 = stack_collisions.back().m_index1;
00592 GUINT node1 = stack_collisions.back().m_index2;
00593 stack_collisions.pop_back();
00594 if(node_collision(node0,node1))
00595 {
00596 if(node0_is_leaf)
00597 {
00598 if(node1_is_leaf)
00599 {
00600 m_collision_pairs->push_pair(m_boxset0->getNodeData(node0),m_boxset1->getNodeData(node1));
00601 }
00602 else
00603 {
00604
00605 stack_collisions.push_pair(node0,m_boxset1->getLeftNodeIndex(node1));
00606
00607
00608 stack_collisions.push_pair(node0,m_boxset1->getRightNodeIndex(node1));
00609 }
00610 }
00611 else
00612 {
00613 if(node1_is_leaf)
00614 {
00615
00616 stack_collisions.push_pair(m_boxset0->getLeftNodeIndex(node0),node1);
00617
00618 stack_collisions.push_pair(m_boxset0->getRightNodeIndex(node0),node1);
00619 }
00620 else
00621 {
00622 GUINT left0 = m_boxset0->getLeftNodeIndex(node0);
00623 GUINT right0 = m_boxset0->getRightNodeIndex(node0);
00624 GUINT left1 = m_boxset1->getLeftNodeIndex(node1);
00625 GUINT right1 = m_boxset1->getRightNodeIndex(node1);
00626
00627 stack_collisions.push_pair(left0,left1);
00628
00629 stack_collisions.push_pair(left0,right1);
00630
00631 stack_collisions.push_pair(right0,left1);
00632
00633 stack_collisions.push_pair(right0,right1);
00634
00635 }
00636 }
00637
00638 }
00639 }
00640 }
00641 public:
00642 void find_collision(BOX_SET_CLASS0 * boxset1, const btTransform & trans1,
00643 BOX_SET_CLASS1 * boxset2, const btTransform & trans2,
00644 gim_pair_set & collision_pairs, bool complete_primitive_tests = true)
00645 {
00646 m_collision_pairs = &collision_pairs;
00647 m_boxset0 = boxset1;
00648 m_boxset1 = boxset2;
00649
00650 trans_cache_1to0.calc_from_homogenic(trans1,trans2);
00651
00652 trans_cache_0to1 = trans2.inverse();
00653 trans_cache_0to1 *= trans1;
00654
00655
00656 if(complete_primitive_tests)
00657 {
00658 t0_is_trimesh = boxset1->getPrimitiveManager().is_trimesh();
00659 t1_is_trimesh = boxset2->getPrimitiveManager().is_trimesh();
00660 }
00661 else
00662 {
00663 t0_is_trimesh = false;
00664 t1_is_trimesh = false;
00665 }
00666
00667 find_collision_pairs();
00668 }
00669 };
00670
00671
00672 #endif // GIM_BOXPRUNING_H_INCLUDED
00673
00674