1
#ifndef GIM_BOX_SET_H_INCLUDED
2
#define GIM_BOX_SET_H_INCLUDED
4
/*! \file gim_box_set.h
5
\author Francisco Leon Najera
8
-----------------------------------------------------------------------------
9
This source file is part of GIMPACT Library.
11
For the latest info, see http://gimpact.sourceforge.net/
13
Copyright (c) 2006 Francisco Leon Najera. C.C. 80087371.
14
email: projectileman@yahoo.com
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.
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.
33
-----------------------------------------------------------------------------
37
#include "gim_array.h"
38
#include "gim_radixsort.h"
39
#include "gim_box_collision.h"
40
#include "gim_tri_collision.h"
52
GIM_PAIR(const GIM_PAIR & p)
54
m_index1 = p.m_index1;
55
m_index2 = p.m_index2;
58
GIM_PAIR(GUINT index1, GUINT index2)
66
class gim_pair_set: public gim_array<GIM_PAIR>
69
gim_pair_set():gim_array<GIM_PAIR>(32)
72
inline void push_pair(GUINT index1,GUINT index2)
74
push_back(GIM_PAIR(index1,index2));
77
inline void push_pair_inv(GUINT index1,GUINT index2)
79
push_back(GIM_PAIR(index2,index1));
84
//! Prototype Base class for primitive classification
86
This class is a wrapper for primitive collections.
87
This tells relevant info for the Bounding Box set classes, which take care of space classification.
88
This 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.
90
class GIM_PRIMITIVE_MANAGER_PROTOTYPE
94
virtual ~GIM_PRIMITIVE_MANAGER_PROTOTYPE() {}
95
//! determines if this manager consist on only triangles, which special case will be optimized
96
virtual bool is_trimesh() = 0;
97
virtual GUINT get_primitive_count() = 0;
98
virtual void get_primitive_box(GUINT prim_index ,GIM_AABB & primbox) = 0;
99
virtual void get_primitive_triangle(GUINT prim_index,GIM_TRIANGLE & triangle) = 0;
109
//! Node Structure for trees
110
struct GIM_BOX_TREE_NODE
113
GUINT m_left;//!< Left subtree
114
GUINT m_right;//!< Right subtree
115
GUINT m_escapeIndex;//!< Scape index for traversing
116
GUINT m_data;//!< primitive index if apply
126
SIMD_FORCE_INLINE bool is_leaf_node() const
128
return (!m_left && !m_right);
132
//! Basic Box tree structure
137
gim_array<GIM_BOX_TREE_NODE> m_node_array;
139
GUINT _sort_and_calc_splitting_index(
140
gim_array<GIM_AABB_DATA> & primitive_boxes,
141
GUINT startIndex, GUINT endIndex, GUINT splitAxis);
143
GUINT _calc_splitting_axis(gim_array<GIM_AABB_DATA> & primitive_boxes, GUINT startIndex, GUINT endIndex);
145
void _build_sub_tree(gim_array<GIM_AABB_DATA> & primitive_boxes, GUINT startIndex, GUINT endIndex);
152
//! prototype functions for box tree management
154
void build_tree(gim_array<GIM_AABB_DATA> & primitive_boxes);
156
SIMD_FORCE_INLINE void clearNodes()
158
m_node_array.clear();
163
SIMD_FORCE_INLINE GUINT getNodeCount() const
168
//! tells if the node is a leaf
169
SIMD_FORCE_INLINE bool isLeafNode(GUINT nodeindex) const
171
return m_node_array[nodeindex].is_leaf_node();
174
SIMD_FORCE_INLINE GUINT getNodeData(GUINT nodeindex) const
176
return m_node_array[nodeindex].m_data;
179
SIMD_FORCE_INLINE void getNodeBound(GUINT nodeindex, GIM_AABB & bound) const
181
bound = m_node_array[nodeindex].m_bound;
184
SIMD_FORCE_INLINE void setNodeBound(GUINT nodeindex, const GIM_AABB & bound)
186
m_node_array[nodeindex].m_bound = bound;
189
SIMD_FORCE_INLINE GUINT getLeftNodeIndex(GUINT nodeindex) const
191
return m_node_array[nodeindex].m_left;
194
SIMD_FORCE_INLINE GUINT getRightNodeIndex(GUINT nodeindex) const
196
return m_node_array[nodeindex].m_right;
199
SIMD_FORCE_INLINE GUINT getScapeNodeIndex(GUINT nodeindex) const
201
return m_node_array[nodeindex].m_escapeIndex;
208
//! Generic Box Tree Template
210
This class offers an structure for managing a box tree of primitives.
211
Requires a Primitive prototype (like GIM_PRIMITIVE_MANAGER_PROTOTYPE ) and
212
a Box tree structure ( like GIM_BOX_TREE).
214
template<typename _GIM_PRIMITIVE_MANAGER_PROTOTYPE, typename _GIM_BOX_TREE_PROTOTYPE>
215
class GIM_BOX_TREE_TEMPLATE_SET
218
_GIM_PRIMITIVE_MANAGER_PROTOTYPE m_primitive_manager;
219
_GIM_BOX_TREE_PROTOTYPE m_box_tree;
222
SIMD_FORCE_INLINE void refit()
224
GUINT nodecount = getNodeCount();
227
if(isLeafNode(nodecount))
230
m_primitive_manager.get_primitive_box(getNodeData(nodecount),leafbox);
231
setNodeBound(nodecount,leafbox);
236
GUINT childindex = getLeftNodeIndex(nodecount);
238
getNodeBound(childindex,bound);
240
childindex = getRightNodeIndex(nodecount);
242
getNodeBound(childindex,bound2);
245
setNodeBound(nodecount,bound);
251
GIM_BOX_TREE_TEMPLATE_SET()
255
SIMD_FORCE_INLINE GIM_AABB getGlobalBox() const
258
getNodeBound(0, totalbox);
262
SIMD_FORCE_INLINE void setPrimitiveManager(const _GIM_PRIMITIVE_MANAGER_PROTOTYPE & primitive_manager)
264
m_primitive_manager = primitive_manager;
267
const _GIM_PRIMITIVE_MANAGER_PROTOTYPE & getPrimitiveManager() const
269
return m_primitive_manager;
272
_GIM_PRIMITIVE_MANAGER_PROTOTYPE & getPrimitiveManager()
274
return m_primitive_manager;
277
//! node manager prototype functions
280
//! this attemps to refit the box set.
281
SIMD_FORCE_INLINE void update()
286
//! this rebuild the entire set
287
SIMD_FORCE_INLINE void buildSet()
289
//obtain primitive boxes
290
gim_array<GIM_AABB_DATA> primitive_boxes;
291
primitive_boxes.resize(m_primitive_manager.get_primitive_count(),false);
293
for (GUINT i = 0;i<primitive_boxes.size() ;i++ )
295
m_primitive_manager.get_primitive_box(i,primitive_boxes[i].m_bound);
296
primitive_boxes[i].m_data = i;
299
m_box_tree.build_tree(primitive_boxes);
302
//! returns the indices of the primitives in the m_primitive_manager
303
SIMD_FORCE_INLINE bool boxQuery(const GIM_AABB & box, gim_array<GUINT> & collided_results) const
306
GUINT numNodes = getNodeCount();
308
while (curIndex < numNodes)
311
getNodeBound(curIndex,bound);
313
//catch bugs in tree data
315
bool aabbOverlap = bound.has_collision(box);
316
bool isleafnode = isLeafNode(curIndex);
318
if (isleafnode && aabbOverlap)
320
collided_results.push_back(getNodeData(curIndex));
323
if (aabbOverlap || isleafnode)
331
curIndex+= getScapeNodeIndex(curIndex);
334
if(collided_results.size()>0) return true;
338
//! returns the indices of the primitives in the m_primitive_manager
339
SIMD_FORCE_INLINE bool boxQueryTrans(const GIM_AABB & box,
340
const btTransform & transform, gim_array<GUINT> & collided_results) const
342
GIM_AABB transbox=box;
343
transbox.appy_transform(transform);
344
return boxQuery(transbox,collided_results);
347
//! returns the indices of the primitives in the m_primitive_manager
348
SIMD_FORCE_INLINE bool rayQuery(
349
const btVector3 & ray_dir,const btVector3 & ray_origin ,
350
gim_array<GUINT> & collided_results) const
353
GUINT numNodes = getNodeCount();
355
while (curIndex < numNodes)
358
getNodeBound(curIndex,bound);
360
//catch bugs in tree data
362
bool aabbOverlap = bound.collide_ray(ray_origin,ray_dir);
363
bool isleafnode = isLeafNode(curIndex);
365
if (isleafnode && aabbOverlap)
367
collided_results.push_back(getNodeData( curIndex));
370
if (aabbOverlap || isleafnode)
378
curIndex+= getScapeNodeIndex(curIndex);
381
if(collided_results.size()>0) return true;
385
//! tells if this set has hierarcht
386
SIMD_FORCE_INLINE bool hasHierarchy() const
391
//! tells if this set is a trimesh
392
SIMD_FORCE_INLINE bool isTrimesh() const
394
return m_primitive_manager.is_trimesh();
398
SIMD_FORCE_INLINE GUINT getNodeCount() const
400
return m_box_tree.getNodeCount();
403
//! tells if the node is a leaf
404
SIMD_FORCE_INLINE bool isLeafNode(GUINT nodeindex) const
406
return m_box_tree.isLeafNode(nodeindex);
409
SIMD_FORCE_INLINE GUINT getNodeData(GUINT nodeindex) const
411
return m_box_tree.getNodeData(nodeindex);
414
SIMD_FORCE_INLINE void getNodeBound(GUINT nodeindex, GIM_AABB & bound) const
416
m_box_tree.getNodeBound(nodeindex, bound);
419
SIMD_FORCE_INLINE void setNodeBound(GUINT nodeindex, const GIM_AABB & bound)
421
m_box_tree.setNodeBound(nodeindex, bound);
424
SIMD_FORCE_INLINE GUINT getLeftNodeIndex(GUINT nodeindex) const
426
return m_box_tree.getLeftNodeIndex(nodeindex);
429
SIMD_FORCE_INLINE GUINT getRightNodeIndex(GUINT nodeindex) const
431
return m_box_tree.getRightNodeIndex(nodeindex);
434
SIMD_FORCE_INLINE GUINT getScapeNodeIndex(GUINT nodeindex) const
436
return m_box_tree.getScapeNodeIndex(nodeindex);
439
SIMD_FORCE_INLINE void getNodeTriangle(GUINT nodeindex,GIM_TRIANGLE & triangle) const
441
m_primitive_manager.get_primitive_triangle(getNodeData(nodeindex),triangle);
446
//! Class for Box Tree Sets
448
this has the GIM_BOX_TREE implementation for bounding boxes.
450
template<typename _GIM_PRIMITIVE_MANAGER_PROTOTYPE>
451
class GIM_BOX_TREE_SET: public GIM_BOX_TREE_TEMPLATE_SET< _GIM_PRIMITIVE_MANAGER_PROTOTYPE, GIM_BOX_TREE>
461
/// GIM_BOX_SET collision methods
462
template<typename BOX_SET_CLASS0,typename BOX_SET_CLASS1>
463
class GIM_TREE_TREE_COLLIDER
466
gim_pair_set * m_collision_pairs;
467
BOX_SET_CLASS0 * m_boxset0;
468
BOX_SET_CLASS1 * m_boxset1;
475
bool node0_has_triangle;
476
bool node1_has_triangle;
479
GIM_BOX_BOX_TRANSFORM_CACHE trans_cache_1to0;
480
btTransform trans_cache_0to1;
482
btVector4 m_tri0_plane;
484
btVector4 m_tri1_plane;
488
GIM_TREE_TREE_COLLIDER()
490
current_node0 = G_UINT_INFINITY;
491
current_node1 = G_UINT_INFINITY;
494
SIMD_FORCE_INLINE void retrieve_node0_triangle(GUINT node0)
496
if(node0_has_triangle) return;
497
m_boxset0->getNodeTriangle(node0,m_tri0);
499
m_tri0.m_vertices[0] = trans_cache_0to1(m_tri0.m_vertices[0]);
500
m_tri0.m_vertices[1] = trans_cache_0to1(m_tri0.m_vertices[1]);
501
m_tri0.m_vertices[2] = trans_cache_0to1(m_tri0.m_vertices[2]);
502
m_tri0.get_plane(m_tri0_plane);
504
node0_has_triangle = true;
507
SIMD_FORCE_INLINE void retrieve_node1_triangle(GUINT node1)
509
if(node1_has_triangle) return;
510
m_boxset1->getNodeTriangle(node1,m_tri1);
512
m_tri1.m_vertices[0] = trans_cache_1to0.transform(m_tri1.m_vertices[0]);
513
m_tri1.m_vertices[1] = trans_cache_1to0.transform(m_tri1.m_vertices[1]);
514
m_tri1.m_vertices[2] = trans_cache_1to0.transform(m_tri1.m_vertices[2]);
515
m_tri1.get_plane(m_tri1_plane);
517
node1_has_triangle = true;
520
SIMD_FORCE_INLINE void retrieve_node0_info(GUINT node0)
522
if(node0 == current_node0) return;
523
m_boxset0->getNodeBound(node0,m_box0);
524
node0_is_leaf = m_boxset0->isLeafNode(node0);
525
node0_has_triangle = false;
526
current_node0 = node0;
529
SIMD_FORCE_INLINE void retrieve_node1_info(GUINT node1)
531
if(node1 == current_node1) return;
532
m_boxset1->getNodeBound(node1,m_box1);
533
node1_is_leaf = m_boxset1->isLeafNode(node1);
534
node1_has_triangle = false;
535
current_node1 = node1;
538
SIMD_FORCE_INLINE bool node_collision(GUINT node0 ,GUINT node1)
540
retrieve_node0_info(node0);
541
retrieve_node1_info(node1);
542
bool result = m_box0.overlapping_trans_cache(m_box1,trans_cache_1to0,true);
543
if(!result) return false;
545
if(t0_is_trimesh && node0_is_leaf)
547
//perform primitive vs box collision
548
retrieve_node0_triangle(node0);
549
//do triangle vs box collision
550
m_box1.increment_margin(m_tri0.m_margin);
552
result = m_box1.collide_triangle_exact(
553
m_tri0.m_vertices[0],m_tri0.m_vertices[1],m_tri0.m_vertices[2],m_tri0_plane);
555
m_box1.increment_margin(-m_tri0.m_margin);
557
if(!result) return false;
560
else if(t1_is_trimesh && node1_is_leaf)
562
//perform primitive vs box collision
563
retrieve_node1_triangle(node1);
564
//do triangle vs box collision
565
m_box0.increment_margin(m_tri1.m_margin);
567
result = m_box0.collide_triangle_exact(
568
m_tri1.m_vertices[0],m_tri1.m_vertices[1],m_tri1.m_vertices[2],m_tri1_plane);
570
m_box0.increment_margin(-m_tri1.m_margin);
572
if(!result) return false;
578
//stackless collision routine
579
void find_collision_pairs()
581
gim_pair_set stack_collisions;
582
stack_collisions.reserve(32);
585
stack_collisions.push_pair(0,0);
588
while(stack_collisions.size())
590
//retrieve the last pair and pop
591
GUINT node0 = stack_collisions.back().m_index1;
592
GUINT node1 = stack_collisions.back().m_index2;
593
stack_collisions.pop_back();
594
if(node_collision(node0,node1)) // a collision is found
600
m_collision_pairs->push_pair(m_boxset0->getNodeData(node0),m_boxset1->getNodeData(node1));
605
stack_collisions.push_pair(node0,m_boxset1->getLeftNodeIndex(node1));
608
stack_collisions.push_pair(node0,m_boxset1->getRightNodeIndex(node1));
616
stack_collisions.push_pair(m_boxset0->getLeftNodeIndex(node0),node1);
618
stack_collisions.push_pair(m_boxset0->getRightNodeIndex(node0),node1);
622
GUINT left0 = m_boxset0->getLeftNodeIndex(node0);
623
GUINT right0 = m_boxset0->getRightNodeIndex(node0);
624
GUINT left1 = m_boxset1->getLeftNodeIndex(node1);
625
GUINT right1 = m_boxset1->getRightNodeIndex(node1);
627
stack_collisions.push_pair(left0,left1);
629
stack_collisions.push_pair(left0,right1);
631
stack_collisions.push_pair(right0,left1);
633
stack_collisions.push_pair(right0,right1);
635
}// else if node1 is not a leaf
636
}// else if node0 is not a leaf
638
}// if(node_collision(node0,node1))
639
}//while(stack_collisions.size())
642
void find_collision(BOX_SET_CLASS0 * boxset1, const btTransform & trans1,
643
BOX_SET_CLASS1 * boxset2, const btTransform & trans2,
644
gim_pair_set & collision_pairs, bool complete_primitive_tests = true)
646
m_collision_pairs = &collision_pairs;
650
trans_cache_1to0.calc_from_homogenic(trans1,trans2);
652
trans_cache_0to1 = trans2.inverse();
653
trans_cache_0to1 *= trans1;
656
if(complete_primitive_tests)
658
t0_is_trimesh = boxset1->getPrimitiveManager().is_trimesh();
659
t1_is_trimesh = boxset2->getPrimitiveManager().is_trimesh();
663
t0_is_trimesh = false;
664
t1_is_trimesh = false;
667
find_collision_pairs();
672
#endif // GIM_BOXPRUNING_H_INCLUDED