Blender V2.61 - r43446

gim_box_set.h

Go to the documentation of this file.
00001 #ifndef GIM_BOX_SET_H_INCLUDED
00002 #define GIM_BOX_SET_H_INCLUDED
00003 
00007 /*
00008 -----------------------------------------------------------------------------
00009 This source file is part of GIMPACT Library.
00010 
00011 For the latest info, see http://gimpact.sourceforge.net/
00012 
00013 Copyright (c) 2006 Francisco Leon Najera. C.C. 80087371.
00014 email: projectileman@yahoo.com
00015 
00016  This library is free software; you can redistribute it and/or
00017  modify it under the terms of EITHER:
00018    (1) The GNU Lesser General Public License as published by the Free
00019        Software Foundation; either version 2.1 of the License, or (at
00020        your option) any later version. The text of the GNU Lesser
00021        General Public License is included with this library in the
00022        file GIMPACT-LICENSE-LGPL.TXT.
00023    (2) The BSD-style license that is included with this library in
00024        the file GIMPACT-LICENSE-BSD.TXT.
00025    (3) The zlib/libpng license that is included with this library in
00026        the file GIMPACT-LICENSE-ZLIB.TXT.
00027 
00028  This library is distributed in the hope that it will be useful,
00029  but WITHOUT ANY WARRANTY; without even the implied warranty of
00030  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the files
00031  GIMPACT-LICENSE-LGPL.TXT, GIMPACT-LICENSE-ZLIB.TXT and GIMPACT-LICENSE-BSD.TXT for more details.
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     //stackless refit
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                 //get left bound
00236                 GUINT childindex = getLeftNodeIndex(nodecount);
00237                 GIM_AABB bound;
00238                 getNodeBound(childindex,bound);
00239                 //get right bound
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         //obtain primitive boxes
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             //catch bugs in tree data
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                 //next subnode
00326                 curIndex++;
00327             }
00328             else
00329             {
00330                 //skip node
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             //catch bugs in tree data
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                 //next subnode
00373                 curIndex++;
00374             }
00375             else
00376             {
00377                 //skip node
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         //transform triangle
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         //transform triangle
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             //perform primitive vs box collision
00548             retrieve_node0_triangle(node0);
00549             //do triangle vs box collision
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             //perform primitive vs box collision
00563             retrieve_node1_triangle(node1);
00564             //do triangle vs box collision
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     //stackless collision routine
00579     void find_collision_pairs()
00580     {
00581         gim_pair_set stack_collisions;
00582         stack_collisions.reserve(32);
00583 
00584         //add the first pair
00585         stack_collisions.push_pair(0,0);
00586 
00587 
00588         while(stack_collisions.size())
00589         {
00590             //retrieve the last pair and pop
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)) // a collision is found
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                         //collide left
00605                         stack_collisions.push_pair(node0,m_boxset1->getLeftNodeIndex(node1));
00606 
00607                         //collide right
00608                         stack_collisions.push_pair(node0,m_boxset1->getRightNodeIndex(node1));
00609                     }
00610                 }
00611                 else
00612                 {
00613                     if(node1_is_leaf)
00614                     {
00615                         //collide left
00616                         stack_collisions.push_pair(m_boxset0->getLeftNodeIndex(node0),node1);
00617                         //collide right
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                         //collide left
00627                         stack_collisions.push_pair(left0,left1);
00628                         //collide right
00629                         stack_collisions.push_pair(left0,right1);
00630                         //collide left
00631                         stack_collisions.push_pair(right0,left1);
00632                         //collide right
00633                         stack_collisions.push_pair(right0,right1);
00634 
00635                     }// else if node1 is not a leaf
00636                 }// else if node0 is not a leaf
00637 
00638             }// if(node_collision(node0,node1))
00639         }//while(stack_collisions.size())
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