Planet
navi homePPSaboutscreenshotsdownloaddevelopmentforum

source: code/branches/masterserver2/src/external/bullet/BulletCollision/Gimpact/gim_box_set.h @ 8740

Last change on this file since 8740 was 5781, checked in by rgrieder, 15 years ago

Reverted trunk again. We might want to find a way to delete these revisions again (x3n's changes are still available as diff in the commit mails).

  • Property svn:eol-style set to native
File size: 16.3 KB
Line 
1#ifndef GIM_BOX_SET_H_INCLUDED
2#define GIM_BOX_SET_H_INCLUDED
3
4/*! \file gim_box_set.h
5\author Francisco Len Nßjera
6*/
7/*
8-----------------------------------------------------------------------------
9This source file is part of GIMPACT Library.
10
11For the latest info, see http://gimpact.sourceforge.net/
12
13Copyright (c) 2006 Francisco Leon Najera. C.C. 80087371.
14email: projectileman@yahoo.com
15
16 This library is free software; you can redistribute it and/or
17 modify it under the terms of EITHER:
18   (1) The GNU Lesser General Public License as published by the Free
19       Software Foundation; either version 2.1 of the License, or (at
20       your option) any later version. The text of the GNU Lesser
21       General Public License is included with this library in the
22       file GIMPACT-LICENSE-LGPL.TXT.
23   (2) The BSD-style license that is included with this library in
24       the file GIMPACT-LICENSE-BSD.TXT.
25   (3) The zlib/libpng license that is included with this library in
26       the file GIMPACT-LICENSE-ZLIB.TXT.
27
28 This library is distributed in the hope that it will be useful,
29 but WITHOUT ANY WARRANTY; without even the implied warranty of
30 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the files
31 GIMPACT-LICENSE-LGPL.TXT, GIMPACT-LICENSE-ZLIB.TXT and GIMPACT-LICENSE-BSD.TXT for more details.
32
33-----------------------------------------------------------------------------
34*/
35
36
37#include "gim_array.h"
38#include "gim_radixsort.h"
39#include "gim_box_collision.h"
40#include "gim_tri_collision.h"
41
42
43
44//! Overlapping pair
45struct GIM_PAIR
46{
47    GUINT m_index1;
48    GUINT m_index2;
49    GIM_PAIR()
50    {}
51
52    GIM_PAIR(const GIM_PAIR & p)
53    {
54        m_index1 = p.m_index1;
55        m_index2 = p.m_index2;
56        }
57
58        GIM_PAIR(GUINT index1, GUINT index2)
59    {
60        m_index1 = index1;
61        m_index2 = index2;
62        }
63};
64
65//! A pairset array
66class gim_pair_set: public gim_array<GIM_PAIR>
67{
68public:
69        gim_pair_set():gim_array<GIM_PAIR>(32)
70        {
71        }
72        inline void push_pair(GUINT index1,GUINT index2)
73        {
74                push_back(GIM_PAIR(index1,index2));
75        }
76
77        inline void push_pair_inv(GUINT index1,GUINT index2)
78        {
79                push_back(GIM_PAIR(index2,index1));
80        }
81};
82
83
84//! Prototype Base class for primitive classification
85/*!
86This class is a wrapper for primitive collections.
87This tells relevant info for the Bounding Box set classes, which take care of space classification.
88This class can manage Compound shapes and trimeshes, and if it is managing trimesh then the  Hierarchy Bounding Box classes will take advantage of primitive Vs Box overlapping tests for getting optimal results and less Per Box compairisons.
89*/
90class GIM_PRIMITIVE_MANAGER_PROTOTYPE
91{
92public:
93
94        //! determines if this manager consist on only triangles, which special case will be optimized
95        virtual bool is_trimesh() = 0;
96        virtual GUINT get_primitive_count() = 0;
97        virtual void get_primitive_box(GUINT prim_index ,GIM_AABB & primbox) = 0;
98        virtual void get_primitive_triangle(GUINT prim_index,GIM_TRIANGLE & triangle) = 0;
99};
100
101
102struct GIM_AABB_DATA
103{
104        GIM_AABB m_bound;
105        GUINT m_data;
106};
107
108//! Node Structure for trees
109struct GIM_BOX_TREE_NODE
110{
111        GIM_AABB m_bound;
112        GUINT m_left;//!< Left subtree
113        GUINT m_right;//!< Right subtree
114        GUINT m_escapeIndex;//!< Scape index for traversing
115        GUINT m_data;//!< primitive index if apply
116
117        GIM_BOX_TREE_NODE()
118        {
119            m_left = 0;
120            m_right = 0;
121            m_escapeIndex = 0;
122            m_data = 0;
123        }
124
125        SIMD_FORCE_INLINE bool is_leaf_node() const
126        {
127            return  (!m_left && !m_right);
128        }
129};
130
131//! Basic Box tree structure
132class GIM_BOX_TREE
133{
134protected:
135        GUINT m_num_nodes;
136        gim_array<GIM_BOX_TREE_NODE> m_node_array;
137protected:
138        GUINT _sort_and_calc_splitting_index(
139                gim_array<GIM_AABB_DATA> & primitive_boxes,
140                 GUINT startIndex,  GUINT endIndex, GUINT splitAxis);
141
142        GUINT _calc_splitting_axis(gim_array<GIM_AABB_DATA> & primitive_boxes, GUINT startIndex,  GUINT endIndex);
143
144        void _build_sub_tree(gim_array<GIM_AABB_DATA> & primitive_boxes, GUINT startIndex,  GUINT endIndex);
145public:
146        GIM_BOX_TREE()
147        {
148                m_num_nodes = 0;
149        }
150
151        //! prototype functions for box tree management
152        //!@{
153        void build_tree(gim_array<GIM_AABB_DATA> & primitive_boxes);
154
155        SIMD_FORCE_INLINE void clearNodes()
156        {
157                m_node_array.clear();
158                m_num_nodes = 0;
159        }
160
161        //! node count
162        SIMD_FORCE_INLINE GUINT getNodeCount() const
163        {
164                return m_num_nodes;
165        }
166
167        //! tells if the node is a leaf
168        SIMD_FORCE_INLINE bool isLeafNode(GUINT nodeindex) const
169        {
170                return m_node_array[nodeindex].is_leaf_node();
171        }
172
173        SIMD_FORCE_INLINE GUINT getNodeData(GUINT nodeindex) const
174        {
175                return m_node_array[nodeindex].m_data;
176        }
177
178        SIMD_FORCE_INLINE void getNodeBound(GUINT nodeindex, GIM_AABB & bound) const
179        {
180                bound = m_node_array[nodeindex].m_bound;
181        }
182
183        SIMD_FORCE_INLINE void setNodeBound(GUINT nodeindex, const GIM_AABB & bound)
184        {
185                m_node_array[nodeindex].m_bound = bound;
186        }
187
188        SIMD_FORCE_INLINE GUINT getLeftNodeIndex(GUINT nodeindex)  const
189        {
190                return m_node_array[nodeindex].m_left;
191        }
192
193        SIMD_FORCE_INLINE GUINT getRightNodeIndex(GUINT nodeindex)  const
194        {
195                return m_node_array[nodeindex].m_right;
196        }
197
198        SIMD_FORCE_INLINE GUINT getScapeNodeIndex(GUINT nodeindex) const
199        {
200                return m_node_array[nodeindex].m_escapeIndex;
201        }
202
203        //!@}
204};
205
206
207//! Generic Box Tree Template
208/*!
209This class offers an structure for managing a box tree of primitives.
210Requires a Primitive prototype (like GIM_PRIMITIVE_MANAGER_PROTOTYPE ) and
211a Box tree structure ( like GIM_BOX_TREE).
212*/
213template<typename _GIM_PRIMITIVE_MANAGER_PROTOTYPE, typename _GIM_BOX_TREE_PROTOTYPE>
214class GIM_BOX_TREE_TEMPLATE_SET
215{
216protected:
217        _GIM_PRIMITIVE_MANAGER_PROTOTYPE m_primitive_manager;
218        _GIM_BOX_TREE_PROTOTYPE m_box_tree;
219protected:
220        //stackless refit
221        SIMD_FORCE_INLINE void refit()
222        {
223                GUINT nodecount = getNodeCount();
224                while(nodecount--)
225                {
226                        if(isLeafNode(nodecount))
227                        {
228                                GIM_AABB leafbox;
229                                m_primitive_manager.get_primitive_box(getNodeData(nodecount),leafbox);
230                                setNodeBound(nodecount,leafbox);
231                        }
232                        else
233                        {
234                                //get left bound
235                                GUINT childindex = getLeftNodeIndex(nodecount);
236                                GIM_AABB bound;
237                                getNodeBound(childindex,bound);
238                                //get right bound
239                                childindex = getRightNodeIndex(nodecount);
240                                GIM_AABB bound2;
241                                getNodeBound(childindex,bound2);
242                                bound.merge(bound2);
243
244                                setNodeBound(nodecount,bound);
245                        }
246                }
247        }
248public:
249
250        GIM_BOX_TREE_TEMPLATE_SET()
251        {
252        }
253
254        SIMD_FORCE_INLINE GIM_AABB getGlobalBox()  const
255        {
256                GIM_AABB totalbox;
257                getNodeBound(0, totalbox);
258                return totalbox;
259        }
260
261        SIMD_FORCE_INLINE void setPrimitiveManager(const _GIM_PRIMITIVE_MANAGER_PROTOTYPE & primitive_manager)
262        {
263                m_primitive_manager = primitive_manager;
264        }
265
266        const _GIM_PRIMITIVE_MANAGER_PROTOTYPE & getPrimitiveManager() const
267        {
268                return m_primitive_manager;
269        }
270
271        _GIM_PRIMITIVE_MANAGER_PROTOTYPE & getPrimitiveManager()
272        {
273                return m_primitive_manager;
274        }
275
276//! node manager prototype functions
277///@{
278
279        //! this attemps to refit the box set.
280        SIMD_FORCE_INLINE void update()
281        {
282                refit();
283        }
284
285        //! this rebuild the entire set
286        SIMD_FORCE_INLINE void buildSet()
287        {
288                //obtain primitive boxes
289                gim_array<GIM_AABB_DATA> primitive_boxes;
290                primitive_boxes.resize(m_primitive_manager.get_primitive_count(),false);
291
292                for (GUINT i = 0;i<primitive_boxes.size() ;i++ )
293                {
294                         m_primitive_manager.get_primitive_box(i,primitive_boxes[i].m_bound);
295                         primitive_boxes[i].m_data = i;
296                }
297
298                m_box_tree.build_tree(primitive_boxes);
299        }
300
301        //! returns the indices of the primitives in the m_primitive_manager
302        SIMD_FORCE_INLINE bool boxQuery(const GIM_AABB & box, gim_array<GUINT> & collided_results) const
303        {
304                GUINT curIndex = 0;
305                GUINT numNodes = getNodeCount();
306
307                while (curIndex < numNodes)
308                {
309                        GIM_AABB bound;
310                        getNodeBound(curIndex,bound);
311
312                        //catch bugs in tree data
313
314                        bool aabbOverlap = bound.has_collision(box);
315                        bool isleafnode = isLeafNode(curIndex);
316
317                        if (isleafnode && aabbOverlap)
318                        {
319                                collided_results.push_back(getNodeData(curIndex));
320                        }
321
322                        if (aabbOverlap || isleafnode)
323                        {
324                                //next subnode
325                                curIndex++;
326                        }
327                        else
328                        {
329                                //skip node
330                                curIndex+= getScapeNodeIndex(curIndex);
331                        }
332                }
333                if(collided_results.size()>0) return true;
334                return false;
335        }
336
337        //! returns the indices of the primitives in the m_primitive_manager
338        SIMD_FORCE_INLINE bool boxQueryTrans(const GIM_AABB & box,
339                 const btTransform & transform, gim_array<GUINT> & collided_results) const
340        {
341                GIM_AABB transbox=box;
342                transbox.appy_transform(transform);
343                return boxQuery(transbox,collided_results);
344        }
345
346        //! returns the indices of the primitives in the m_primitive_manager
347        SIMD_FORCE_INLINE bool rayQuery(
348                const btVector3 & ray_dir,const btVector3 & ray_origin ,
349                gim_array<GUINT> & collided_results) const
350        {
351                GUINT curIndex = 0;
352                GUINT numNodes = getNodeCount();
353
354                while (curIndex < numNodes)
355                {
356                        GIM_AABB bound;
357                        getNodeBound(curIndex,bound);
358
359                        //catch bugs in tree data
360
361                        bool aabbOverlap = bound.collide_ray(ray_origin,ray_dir);
362                        bool isleafnode = isLeafNode(curIndex);
363
364                        if (isleafnode && aabbOverlap)
365                        {
366                                collided_results.push_back(getNodeData( curIndex));
367                        }
368
369                        if (aabbOverlap || isleafnode)
370                        {
371                                //next subnode
372                                curIndex++;
373                        }
374                        else
375                        {
376                                //skip node
377                                curIndex+= getScapeNodeIndex(curIndex);
378                        }
379                }
380                if(collided_results.size()>0) return true;
381                return false;
382        }
383
384        //! tells if this set has hierarcht
385        SIMD_FORCE_INLINE bool hasHierarchy() const
386        {
387                return true;
388        }
389
390        //! tells if this set is a trimesh
391        SIMD_FORCE_INLINE bool isTrimesh()  const
392        {
393                return m_primitive_manager.is_trimesh();
394        }
395
396        //! node count
397        SIMD_FORCE_INLINE GUINT getNodeCount() const
398        {
399                return m_box_tree.getNodeCount();
400        }
401
402        //! tells if the node is a leaf
403        SIMD_FORCE_INLINE bool isLeafNode(GUINT nodeindex) const
404        {
405                return m_box_tree.isLeafNode(nodeindex);
406        }
407
408        SIMD_FORCE_INLINE GUINT getNodeData(GUINT nodeindex) const
409        {
410                return m_box_tree.getNodeData(nodeindex);
411        }
412
413        SIMD_FORCE_INLINE void getNodeBound(GUINT nodeindex, GIM_AABB & bound)  const
414        {
415                m_box_tree.getNodeBound(nodeindex, bound);
416        }
417
418        SIMD_FORCE_INLINE void setNodeBound(GUINT nodeindex, const GIM_AABB & bound)
419        {
420                m_box_tree.setNodeBound(nodeindex, bound);
421        }
422
423        SIMD_FORCE_INLINE GUINT getLeftNodeIndex(GUINT nodeindex) const
424        {
425                return m_box_tree.getLeftNodeIndex(nodeindex);
426        }
427
428        SIMD_FORCE_INLINE GUINT getRightNodeIndex(GUINT nodeindex) const
429        {
430                return m_box_tree.getRightNodeIndex(nodeindex);
431        }
432
433        SIMD_FORCE_INLINE GUINT getScapeNodeIndex(GUINT nodeindex) const
434        {
435                return m_box_tree.getScapeNodeIndex(nodeindex);
436        }
437
438        SIMD_FORCE_INLINE void getNodeTriangle(GUINT nodeindex,GIM_TRIANGLE & triangle) const
439        {
440                m_primitive_manager.get_primitive_triangle(getNodeData(nodeindex),triangle);
441        }
442
443};
444
445//! Class for Box Tree Sets
446/*!
447this has the GIM_BOX_TREE implementation for bounding boxes.
448*/
449template<typename _GIM_PRIMITIVE_MANAGER_PROTOTYPE>
450class GIM_BOX_TREE_SET: public GIM_BOX_TREE_TEMPLATE_SET< _GIM_PRIMITIVE_MANAGER_PROTOTYPE, GIM_BOX_TREE>
451{
452public:
453
454};
455
456
457
458
459
460/// GIM_BOX_SET collision methods
461template<typename BOX_SET_CLASS0,typename BOX_SET_CLASS1>
462class GIM_TREE_TREE_COLLIDER
463{
464public:
465        gim_pair_set * m_collision_pairs;
466        BOX_SET_CLASS0 * m_boxset0;
467        BOX_SET_CLASS1 * m_boxset1;
468        GUINT current_node0;
469        GUINT current_node1;
470        bool node0_is_leaf;
471        bool node1_is_leaf;
472        bool t0_is_trimesh;
473        bool t1_is_trimesh;
474        bool node0_has_triangle;
475        bool node1_has_triangle;
476        GIM_AABB m_box0;
477        GIM_AABB m_box1;
478        GIM_BOX_BOX_TRANSFORM_CACHE trans_cache_1to0;
479        btTransform trans_cache_0to1;
480        GIM_TRIANGLE m_tri0;
481        btVector4 m_tri0_plane;
482        GIM_TRIANGLE m_tri1;
483        btVector4 m_tri1_plane;
484
485
486public:
487        GIM_TREE_TREE_COLLIDER()
488        {
489                current_node0 = G_UINT_INFINITY;
490                current_node1 = G_UINT_INFINITY;
491        }
492protected:
493        SIMD_FORCE_INLINE void retrieve_node0_triangle(GUINT node0)
494        {
495                if(node0_has_triangle) return;
496                m_boxset0->getNodeTriangle(node0,m_tri0);
497                //transform triangle
498                m_tri0.m_vertices[0] = trans_cache_0to1(m_tri0.m_vertices[0]);
499                m_tri0.m_vertices[1] = trans_cache_0to1(m_tri0.m_vertices[1]);
500                m_tri0.m_vertices[2] = trans_cache_0to1(m_tri0.m_vertices[2]);
501                m_tri0.get_plane(m_tri0_plane);
502
503                node0_has_triangle = true;
504        }
505
506        SIMD_FORCE_INLINE void retrieve_node1_triangle(GUINT node1)
507        {
508                if(node1_has_triangle) return;
509                m_boxset1->getNodeTriangle(node1,m_tri1);
510                //transform triangle
511                m_tri1.m_vertices[0] = trans_cache_1to0.transform(m_tri1.m_vertices[0]);
512                m_tri1.m_vertices[1] = trans_cache_1to0.transform(m_tri1.m_vertices[1]);
513                m_tri1.m_vertices[2] = trans_cache_1to0.transform(m_tri1.m_vertices[2]);
514                m_tri1.get_plane(m_tri1_plane);
515
516                node1_has_triangle = true;
517        }
518
519        SIMD_FORCE_INLINE void retrieve_node0_info(GUINT node0)
520        {
521                if(node0 == current_node0) return;
522                m_boxset0->getNodeBound(node0,m_box0);
523                node0_is_leaf = m_boxset0->isLeafNode(node0);
524                node0_has_triangle = false;
525                current_node0 = node0;
526        }
527
528        SIMD_FORCE_INLINE void retrieve_node1_info(GUINT node1)
529        {
530                if(node1 == current_node1) return;
531                m_boxset1->getNodeBound(node1,m_box1);
532                node1_is_leaf = m_boxset1->isLeafNode(node1);
533                node1_has_triangle = false;
534                current_node1 = node1;
535        }
536
537        SIMD_FORCE_INLINE bool node_collision(GUINT node0 ,GUINT node1)
538        {
539                retrieve_node0_info(node0);
540                retrieve_node1_info(node1);
541                bool result = m_box0.overlapping_trans_cache(m_box1,trans_cache_1to0,true);
542                if(!result) return false;
543
544                if(t0_is_trimesh && node0_is_leaf)
545                {
546                        //perform primitive vs box collision
547                        retrieve_node0_triangle(node0);
548                        //do triangle vs box collision
549                        m_box1.increment_margin(m_tri0.m_margin);
550
551                        result = m_box1.collide_triangle_exact(
552                                m_tri0.m_vertices[0],m_tri0.m_vertices[1],m_tri0.m_vertices[2],m_tri0_plane);
553
554                        m_box1.increment_margin(-m_tri0.m_margin);
555
556                        if(!result) return false;
557                        return true;
558                }
559                else if(t1_is_trimesh && node1_is_leaf)
560                {
561                        //perform primitive vs box collision
562                        retrieve_node1_triangle(node1);
563                        //do triangle vs box collision
564                        m_box0.increment_margin(m_tri1.m_margin);
565
566                        result = m_box0.collide_triangle_exact(
567                                m_tri1.m_vertices[0],m_tri1.m_vertices[1],m_tri1.m_vertices[2],m_tri1_plane);
568
569                        m_box0.increment_margin(-m_tri1.m_margin);
570
571                        if(!result) return false;
572                        return true;
573                }
574                return true;
575        }
576
577        //stackless collision routine
578        void find_collision_pairs()
579        {
580                gim_pair_set stack_collisions;
581                stack_collisions.reserve(32);
582
583                //add the first pair
584                stack_collisions.push_pair(0,0);
585
586
587                while(stack_collisions.size())
588                {
589                        //retrieve the last pair and pop
590                        GUINT node0 = stack_collisions.back().m_index1;
591                        GUINT node1 = stack_collisions.back().m_index2;
592                        stack_collisions.pop_back();
593                        if(node_collision(node0,node1)) // a collision is found
594                        {
595                                if(node0_is_leaf)
596                                {
597                                        if(node1_is_leaf)
598                                        {
599                                                m_collision_pairs->push_pair(m_boxset0->getNodeData(node0),m_boxset1->getNodeData(node1));
600                                        }
601                                        else
602                                        {
603                                                //collide left
604                                                stack_collisions.push_pair(node0,m_boxset1->getLeftNodeIndex(node1));
605
606                                                //collide right
607                                                stack_collisions.push_pair(node0,m_boxset1->getRightNodeIndex(node1));
608                                        }
609                                }
610                                else
611                                {
612                                        if(node1_is_leaf)
613                                        {
614                                                //collide left
615                                                stack_collisions.push_pair(m_boxset0->getLeftNodeIndex(node0),node1);
616                                                //collide right
617                                                stack_collisions.push_pair(m_boxset0->getRightNodeIndex(node0),node1);
618                                        }
619                                        else
620                                        {
621                                                GUINT left0 = m_boxset0->getLeftNodeIndex(node0);
622                                                GUINT right0 = m_boxset0->getRightNodeIndex(node0);
623                                                GUINT left1 = m_boxset1->getLeftNodeIndex(node1);
624                                                GUINT right1 = m_boxset1->getRightNodeIndex(node1);
625                                                //collide left
626                                                stack_collisions.push_pair(left0,left1);
627                                                //collide right
628                                                stack_collisions.push_pair(left0,right1);
629                                                //collide left
630                                                stack_collisions.push_pair(right0,left1);
631                                                //collide right
632                                                stack_collisions.push_pair(right0,right1);
633
634                                        }// else if node1 is not a leaf
635                                }// else if node0 is not a leaf
636
637                        }// if(node_collision(node0,node1))
638                }//while(stack_collisions.size())
639        }
640public:
641        void find_collision(BOX_SET_CLASS0 * boxset1, const btTransform & trans1,
642                BOX_SET_CLASS1 * boxset2, const btTransform & trans2,
643                gim_pair_set & collision_pairs, bool complete_primitive_tests = true)
644        {
645                m_collision_pairs = &collision_pairs;
646                m_boxset0 = boxset1;
647                m_boxset1 = boxset2;
648
649                trans_cache_1to0.calc_from_homogenic(trans1,trans2);
650
651                trans_cache_0to1 =  trans2.inverse();
652                trans_cache_0to1 *= trans1;
653
654
655                if(complete_primitive_tests)
656                {
657                        t0_is_trimesh = boxset1->getPrimitiveManager().is_trimesh();
658                        t1_is_trimesh = boxset2->getPrimitiveManager().is_trimesh();
659                }
660                else
661                {
662                        t0_is_trimesh = false;
663                        t1_is_trimesh = false;
664                }
665
666                find_collision_pairs();
667        }
668};
669
670
671#endif // GIM_BOXPRUNING_H_INCLUDED
Note: See TracBrowser for help on using the repository browser.