This commit is contained in:
TheLuda 2008-10-15 18:24:39 +02:00
parent 800ee76535
commit 9116f0286b
29 changed files with 253 additions and 254 deletions

2
.gitignore vendored
View file

@ -1,3 +1,5 @@
compile
FILES
INSTALL INSTALL
*.pyc *.pyc

View file

@ -1,14 +1,14 @@
/** /**
@file AABSPTree.h @file AABSPTree.h
@maintainer Morgan McGuire, matrix@graphics3d.com @maintainer Morgan McGuire, matrix@graphics3d.com
@created 2004-01-11 @created 2004-01-11
@edited 2007-02-16 @edited 2007-02-16
Copyright 2000-2007, Morgan McGuire. Copyright 2000-2007, Morgan McGuire.
All rights reserved. All rights reserved.
*/ */
#ifndef G3D_AABSPTREE_H #ifndef G3D_AABSPTREE_H
@ -89,7 +89,7 @@ namespace G3D {
/** /**
Wraps a pointer value so that it can be treated as the instance itself; Wraps a pointer value so that it can be treated as the instance itself;
convenient for inserting pointers into a Table but using the convenient for inserting pointers into a Table but using the
object equality instead of pointer equality. object equality instead of pointer equality.
*/ */
template<class Type> template<class Type>
@ -136,9 +136,9 @@ namespace G3D {
AABSPTree is as powerful as but more general than a Quad Tree, Oct AABSPTree is as powerful as but more general than a Quad Tree, Oct
Tree, or KD Tree, but less general than an unconstrained BSP tree Tree, or KD Tree, but less general than an unconstrained BSP tree
(which is much slower to create). (which is much slower to create).
Internally, objects Internally, objects
are arranged into an axis-aligned BSP-tree according to their are arranged into an axis-aligned BSP-tree according to their
axis-aligned bounds. This increases the cost of insertion to axis-aligned bounds. This increases the cost of insertion to
O(log n) but allows fast overlap queries. O(log n) but allows fast overlap queries.
@ -158,13 +158,13 @@ namespace G3D {
<B>Moving %Set Members</B> <B>Moving %Set Members</B>
<DT>It is important that objects do not move without updating the <DT>It is important that objects do not move without updating the
AABSPTree. If the axis-aligned bounds of an object are about AABSPTree. If the axis-aligned bounds of an object are about
to change, AABSPTree::remove it before they change and to change, AABSPTree::remove it before they change and
AABSPTree::insert it again afterward. For objects AABSPTree::insert it again afterward. For objects
where the hashCode and == operator are invariant with respect where the hashCode and == operator are invariant with respect
to the 3D position, to the 3D position,
you can use the AABSPTree::update method as a shortcut to you can use the AABSPTree::update method as a shortcut to
insert/remove an object in one step after it has moved. insert/remove an object in one step after it has moved.
Note: Do not mutate any value once it has been inserted into AABSPTree. Values Note: Do not mutate any value once it has been inserted into AABSPTree. Values
are copied interally. All AABSPTree iterators convert to pointers to constant are copied interally. All AABSPTree iterators convert to pointers to constant
@ -185,9 +185,9 @@ namespace G3D {
*/ */
namespace _AABSPTree { namespace _AABSPTree {
/** Wrapper for a value that includes a cache of its bounds. /** Wrapper for a value that includes a cache of its bounds.
Except for the test value used in a set-query operation, there Except for the test value used in a set-query operation, there
is only ever one instance of the handle associated with any is only ever one instance of the handle associated with any
value and the memberTable and Nodes maintain pointers to that value and the memberTable and Nodes maintain pointers to that
heap-allocated value. heap-allocated value.
*/ */
@ -261,10 +261,10 @@ public:
/** Returns the bounds of the sub array. Used by makeNode. */ /** Returns the bounds of the sub array. Used by makeNode. */
static AABox computeBounds( static AABox computeBounds(
const Array<_AABSPTree::Handle<T>*>& point, const Array<_AABSPTree::Handle<T>*>& point,
int beginIndex, int beginIndex,
int endIndex) { int endIndex) {
Vector3 lo = Vector3::inf(); Vector3 lo = Vector3::inf();
Vector3 hi = -lo; Vector3 hi = -lo;
@ -279,11 +279,11 @@ public:
/** Compares centers */ /** Compares centers */
class CenterComparator { class CenterComparator {
public: public:
Vector3::Axis sortAxis; Vector3::Axis sortAxis;
CenterComparator(Vector3::Axis a) : sortAxis(a) {} CenterComparator(Vector3::Axis a) : sortAxis(a) {}
inline int operator()(_AABSPTree::Handle<T>* A, const _AABSPTree::Handle<T>* B) const { inline int operator()(_AABSPTree::Handle<T>* A, const _AABSPTree::Handle<T>* B) const {
float a = A->center[sortAxis]; float a = A->center[sortAxis];
float b = B->center[sortAxis]; float b = B->center[sortAxis];
@ -294,18 +294,18 @@ public:
} else { } else {
return 0; return 0;
} }
} }
}; };
/** Compares bounds for strict >, <, or overlap*/ /** Compares bounds for strict >, <, or overlap*/
class BoundsComparator { class BoundsComparator {
public: public:
Vector3::Axis sortAxis; Vector3::Axis sortAxis;
BoundsComparator(Vector3::Axis a) : sortAxis(a) {} BoundsComparator(Vector3::Axis a) : sortAxis(a) {}
inline int operator()(_AABSPTree::Handle<T>* A, const _AABSPTree::Handle<T>* B) const { inline int operator()(_AABSPTree::Handle<T>* A, const _AABSPTree::Handle<T>* B) const {
const AABox& a = A->bounds; const AABox& a = A->bounds;
const AABox& b = B->bounds; const AABox& b = B->bounds;
@ -316,33 +316,33 @@ public:
} else { } else {
return 0; return 0;
} }
} }
}; };
/** Compares bounds to the sort location */ /** Compares bounds to the sort location */
class Comparator { class Comparator {
public: public:
Vector3::Axis sortAxis; Vector3::Axis sortAxis;
float sortLocation; float sortLocation;
Comparator(Vector3::Axis a, float l) : sortAxis(a), sortLocation(l) {} Comparator(Vector3::Axis a, float l) : sortAxis(a), sortLocation(l) {}
inline int operator()(_AABSPTree::Handle<T>* /*ignore*/, const _AABSPTree::Handle<T>* handle) const { inline int operator()(_AABSPTree::Handle<T>* /*ignore*/, const _AABSPTree::Handle<T>* handle) const {
const AABox& box = handle->bounds; const AABox& box = handle->bounds;
debugAssert(ignore == NULL); debugAssert(ignore == NULL);
if (box.high()[sortAxis] < sortLocation) { if (box.high()[sortAxis] < sortLocation) {
// Box is strictly below the sort location // Box is strictly below the sort location
return -1; return -1;
} else if (box.low()[sortAxis] > sortLocation) { } else if (box.low()[sortAxis] > sortLocation) {
// Box is strictly above the sort location // Box is strictly above the sort location
return 1; return 1;
} else { } else {
// Box overlaps the sort location // Box overlaps the sort location
return 0; return 0;
} }
} }
}; };
// Using System::malloc with this class provided no speed improvement. // Using System::malloc with this class provided no speed improvement.
@ -357,8 +357,8 @@ public:
/** Location along the specified axis */ /** Location along the specified axis */
float splitLocation; float splitLocation;
/** child[0] contains all values strictly /** child[0] contains all values strictly
smaller than splitLocation along splitAxis. smaller than splitLocation along splitAxis.
child[1] contains all values strictly child[1] contains all values strictly
@ -371,15 +371,15 @@ public:
/** Array of values at this node (i.e., values /** Array of values at this node (i.e., values
straddling the split plane + all values if straddling the split plane + all values if
this is a leaf node). this is a leaf node).
This is an array of pointers because that minimizes This is an array of pointers because that minimizes
data movement during tree building, which accounts data movement during tree building, which accounts
for about 15% of the time cost of tree building. for about 15% of the time cost of tree building.
*/ */
Array<_AABSPTree::Handle<T> * > valueArray; Array<_AABSPTree::Handle<T> * > valueArray;
/** For each object in the value array, a copy of its bounds. /** For each object in the value array, a copy of its bounds.
Packing these into an array at the node level Packing these into an array at the node level
instead putting them in the valueArray improves instead putting them in the valueArray improves
cache coherence, which is about a 3x performance cache coherence, which is about a 3x performance
@ -403,7 +403,7 @@ public:
Node(const Node& other) : valueArray(other.valueArray), boundsArray(other.boundsArray) { Node(const Node& other) : valueArray(other.valueArray), boundsArray(other.boundsArray) {
splitAxis = other.splitAxis; splitAxis = other.splitAxis;
splitLocation = other.splitLocation; splitLocation = other.splitLocation;
splitBounds = other.splitBounds; splitBounds = other.splitBounds;
for (int i = 0; i < 2; ++i) { for (int i = 0; i < 2; ++i) {
child[i] = NULL; child[i] = NULL;
} }
@ -450,47 +450,47 @@ public:
} }
} }
void verifyNode(const Vector3& lo, const Vector3& hi) { void verifyNode(const Vector3& lo, const Vector3& hi) {
// debugPrintf("Verifying: split %d @ %f [%f, %f, %f], [%f, %f, %f]\n", // debugPrintf("Verifying: split %d @ %f [%f, %f, %f], [%f, %f, %f]\n",
// splitAxis, splitLocation, lo.x, lo.y, lo.z, hi.x, hi.y, hi.z); // splitAxis, splitLocation, lo.x, lo.y, lo.z, hi.x, hi.y, hi.z);
debugAssert(lo == splitBounds.low()); debugAssert(lo == splitBounds.low());
debugAssert(hi == splitBounds.high()); debugAssert(hi == splitBounds.high());
for (int i = 0; i < valueArray.length(); ++i) { for (int i = 0; i < valueArray.length(); ++i) {
const AABox& b = valueArray[i]->bounds; const AABox& b = valueArray[i]->bounds;
debugAssert(b == boundsArray[i]); debugAssert(b == boundsArray[i]);
for(int axis = 0; axis < 3; ++axis) { for(int axis = 0; axis < 3; ++axis) {
debugAssert(b.low()[axis] <= b.high()[axis]); debugAssert(b.low()[axis] <= b.high()[axis]);
debugAssert(b.low()[axis] >= lo[axis]); debugAssert(b.low()[axis] >= lo[axis]);
debugAssert(b.high()[axis] <= hi[axis]); debugAssert(b.high()[axis] <= hi[axis]);
} }
} }
if (child[0] || child[1]) { if (child[0] || child[1]) {
debugAssert(lo[splitAxis] < splitLocation); debugAssert(lo[splitAxis] < splitLocation);
debugAssert(hi[splitAxis] > splitLocation); debugAssert(hi[splitAxis] > splitLocation);
} }
Vector3 newLo = lo; Vector3 newLo = lo;
newLo[splitAxis] = splitLocation; newLo[splitAxis] = splitLocation;
Vector3 newHi = hi; Vector3 newHi = hi;
newHi[splitAxis] = splitLocation; newHi[splitAxis] = splitLocation;
if (child[0] != NULL) { if (child[0] != NULL) {
child[0]->verifyNode(lo, newHi); child[0]->verifyNode(lo, newHi);
} }
if (child[1] != NULL) { if (child[1] != NULL) {
child[1]->verifyNode(newLo, hi); child[1]->verifyNode(newLo, hi);
} }
} }
#if 0 #if 0
/** /**
Stores the locations of the splitting planes (the structure but not the content) Stores the locations of the splitting planes (the structure but not the content)
so that the tree can be quickly rebuilt from a previous configuration without so that the tree can be quickly rebuilt from a previous configuration without
calling balance. calling balance.
*/ */
static void serializeStructure(const Node* n, BinaryOutput& bo) { static void serializeStructure(const Node* n, BinaryOutput& bo) {
@ -546,7 +546,7 @@ public:
} }
/** Appends all members that intersect the box. /** Appends all members that intersect the box.
If useSphere is true, members that pass the box test If useSphere is true, members that pass the box test
face a second test against the sphere. */ face a second test against the sphere. */
void getIntersectingMembers( void getIntersectingMembers(
@ -604,11 +604,11 @@ public:
// See if the ray will ever hit this node or its children // See if the ray will ever hit this node or its children
Vector3 location; Vector3 location;
bool alreadyInsideBounds = false; bool alreadyInsideBounds = false;
bool rayWillHitBounds = bool rayWillHitBounds =
VMAP::MyCollisionDetection::collisionLocationForMovingPointFixedAABox( VMAP::MyCollisionDetection::collisionLocationForMovingPointFixedAABox(
ray.origin, ray.direction, splitBounds, location, alreadyInsideBounds); ray.origin, ray.direction, splitBounds, location, alreadyInsideBounds);
bool canHitThisNode = (alreadyInsideBounds || bool canHitThisNode = (alreadyInsideBounds ||
(rayWillHitBounds && ((location - ray.origin).squaredLength() < square(distance)))); (rayWillHitBounds && ((location - ray.origin).squaredLength() < square(distance))));
return canHitThisNode; return canHitThisNode;
@ -616,20 +616,20 @@ public:
template<typename RayCallback> template<typename RayCallback>
void intersectRay( void intersectRay(
const Ray& ray, const Ray& ray,
RayCallback& intersectCallback, RayCallback& intersectCallback,
float& distance, float& distance,
bool pStopAtFirstHit, bool pStopAtFirstHit,
bool intersectCallbackIsFast) const { bool intersectCallbackIsFast) const {
float enterDistance = distance; float enterDistance = distance;
if (! intersects(ray, distance)) { if (! intersects(ray, distance)) {
// The ray doesn't hit this node, so it can't hit the children of the node. // The ray doesn't hit this node, so it can't hit the children of the node.
return; return;
} }
// Test for intersection against every object at this node. // Test for intersection against every object at this node.
for (int v = 0; v < valueArray.size(); ++v) { for (int v = 0; v < valueArray.size(); ++v) {
bool canHitThisObject = true; bool canHitThisObject = true;
if (! intersectCallbackIsFast) { if (! intersectCallbackIsFast) {
@ -637,11 +637,11 @@ public:
Vector3 location; Vector3 location;
const AABox& bounds = boundsArray[v]; const AABox& bounds = boundsArray[v];
bool alreadyInsideBounds = false; bool alreadyInsideBounds = false;
bool rayWillHitBounds = bool rayWillHitBounds =
VMAP::MyCollisionDetection::collisionLocationForMovingPointFixedAABox( VMAP::MyCollisionDetection::collisionLocationForMovingPointFixedAABox(
ray.origin, ray.direction, bounds, location, alreadyInsideBounds); ray.origin, ray.direction, bounds, location, alreadyInsideBounds);
canHitThisObject = (alreadyInsideBounds || canHitThisObject = (alreadyInsideBounds ||
(rayWillHitBounds && ((location - ray.origin).squaredLength() < square(distance)))); (rayWillHitBounds && ((location - ray.origin).squaredLength() < square(distance))));
} }
@ -656,7 +656,7 @@ public:
} }
// There are three cases to consider next: // There are three cases to consider next:
// //
// 1. the ray can start on one side of the splitting plane and never enter the other, // 1. the ray can start on one side of the splitting plane and never enter the other,
// 2. the ray can start on one side and enter the other, and // 2. the ray can start on one side and enter the other, and
// 3. the ray can travel exactly down the splitting plane // 3. the ray can travel exactly down the splitting plane
@ -666,7 +666,7 @@ public:
int secondChild = NONE; int secondChild = NONE;
if (ray.origin[splitAxis] < splitLocation) { if (ray.origin[splitAxis] < splitLocation) {
// The ray starts on the small side // The ray starts on the small side
firstChild = 0; firstChild = 0;
@ -702,7 +702,7 @@ public:
} }
if (ray.direction[splitAxis] != 0) { if (ray.direction[splitAxis] != 0) {
// See if there was an intersection before hitting the splitting plane. // See if there was an intersection before hitting the splitting plane.
// If so, there is no need to look on the far side and recursion terminates. // If so, there is no need to look on the far side and recursion terminates.
float distanceToSplittingPlane = (splitLocation - ray.origin[splitAxis]) / ray.direction[splitAxis]; float distanceToSplittingPlane = (splitLocation - ray.origin[splitAxis]) / ray.direction[splitAxis];
if (distanceToSplittingPlane > distance) { if (distanceToSplittingPlane > distance) {
@ -724,43 +724,43 @@ public:
/** /**
Recursively subdivides the subarray. Recursively subdivides the subarray.
Clears the source array as soon as it is no longer needed. Clears the source array as soon as it is no longer needed.
Call assignSplitBounds() on the root node after making a tree. Call assignSplitBounds() on the root node after making a tree.
*/ */
Node* makeNode( Node* makeNode(
Array<_AABSPTree::Handle<T> * >& source, Array<_AABSPTree::Handle<T> * >& source,
int valuesPerNode, int valuesPerNode,
int numMeanSplits, int numMeanSplits,
Array<_AABSPTree::Handle<T> * >& temp) { Array<_AABSPTree::Handle<T> * >& temp) {
Node* node = NULL; Node* node = NULL;
if (source.size() <= valuesPerNode) { if (source.size() <= valuesPerNode) {
// Make a new leaf node // Make a new leaf node
node = new Node(source); node = new Node(source);
// Set the pointers in the memberTable // Set the pointers in the memberTable
for (int i = 0; i < source.size(); ++i) { for (int i = 0; i < source.size(); ++i) {
memberTable.set(Member(source[i]), node); memberTable.set(Member(source[i]), node);
} }
source.clear(); source.clear();
} else { } else {
// Make a new internal node // Make a new internal node
node = new Node(); node = new Node();
const AABox bounds = computeBounds(source, 0, source.size() - 1); const AABox bounds = computeBounds(source, 0, source.size() - 1);
const Vector3 extent = bounds.high() - bounds.low(); const Vector3 extent = bounds.high() - bounds.low();
Vector3::Axis splitAxis = extent.primaryAxis(); Vector3::Axis splitAxis = extent.primaryAxis();
float splitLocation; float splitLocation;
// Arrays for holding the children // Arrays for holding the children
Array<_AABSPTree::Handle<T> * > lt, gt; Array<_AABSPTree::Handle<T> * > lt, gt;
if (numMeanSplits <= 0) { if (numMeanSplits <= 0) {
source.medianPartition(lt, node->valueArray, gt, temp, CenterComparator(splitAxis)); source.medianPartition(lt, node->valueArray, gt, temp, CenterComparator(splitAxis));
@ -788,13 +788,13 @@ public:
// is swapped in in its place. // is swapped in in its place.
gt.fastRemove(i); --i; gt.fastRemove(i); --i;
} }
} }
if ((node->valueArray.size() > (source.size() / 2)) && if ((node->valueArray.size() > (source.size() / 2)) &&
(source.size() > 6)) { (source.size() > 6)) {
// This was a bad partition; we ended up putting the splitting plane right in the middle of most of the // This was a bad partition; we ended up putting the splitting plane right in the middle of most of the
// objects. We could try to split on a different axis, or use a different partition (e.g., the extents mean, // objects. We could try to split on a different axis, or use a different partition (e.g., the extents mean,
// or geometric mean). This implementation falls back on the extents mean, since that case is already handled // or geometric mean). This implementation falls back on the extents mean, since that case is already handled
// below. // below.
numMeanSplits = 1; numMeanSplits = 1;
} }
@ -805,9 +805,9 @@ public:
if (numMeanSplits > 0) { if (numMeanSplits > 0) {
// Split along the mean // Split along the mean
splitLocation = (bounds.high()[splitAxis] + splitLocation = (bounds.high()[splitAxis] +
bounds.low()[splitAxis]) / 2.0; bounds.low()[splitAxis]) / 2.0;
source.partition(NULL, lt, node->valueArray, gt, Comparator(splitAxis, splitLocation)); source.partition(NULL, lt, node->valueArray, gt, Comparator(splitAxis, splitLocation));
// The Comparator ensures that elements are strictly on the correct side of the split // The Comparator ensures that elements are strictly on the correct side of the split
@ -817,7 +817,7 @@ public:
# if defined(G3D_DEBUG) && defined(VERIFY_TREE) # if defined(G3D_DEBUG) && defined(VERIFY_TREE)
debugAssert(lt.size() + node->valueArray.size() + gt.size() == source.size()); debugAssert(lt.size() + node->valueArray.size() + gt.size() == source.size());
// Verify that all objects ended up on the correct side of the split. // Verify that all objects ended up on the correct side of the split.
// (i.e., make sure that the Array partition was correct) // (i.e., make sure that the Array partition was correct)
for (int i = 0; i < lt.size(); ++i) { for (int i = 0; i < lt.size(); ++i) {
const AABox& bounds = lt[i]->bounds; const AABox& bounds = lt[i]->bounds;
debugAssert(bounds.high()[splitAxis] < splitLocation); debugAssert(bounds.high()[splitAxis] < splitLocation);
@ -846,20 +846,20 @@ public:
for (int i = 0; i < node->valueArray.size(); ++i) { for (int i = 0; i < node->valueArray.size(); ++i) {
_AABSPTree::Handle<T> * v = node->valueArray[i]; _AABSPTree::Handle<T> * v = node->valueArray[i];
node->boundsArray[i] = v->bounds; node->boundsArray[i] = v->bounds;
memberTable.set(Member(v), node); memberTable.set(Member(v), node);
} }
if (lt.size() > 0) { if (lt.size() > 0) {
node->child[0] = makeNode(lt, valuesPerNode, numMeanSplits - 1, temp); node->child[0] = makeNode(lt, valuesPerNode, numMeanSplits - 1, temp);
} }
if (gt.size() > 0) { if (gt.size() > 0) {
node->child[1] = makeNode(gt, valuesPerNode, numMeanSplits - 1, temp); node->child[1] = makeNode(gt, valuesPerNode, numMeanSplits - 1, temp);
} }
} }
return node; return node;
} }
/** /**
@ -927,7 +927,7 @@ public:
*/ */
void clear() { void clear() {
typedef typename Table<_internal::Indirector<_AABSPTree::Handle<T> >, Node* >::Iterator It; typedef typename Table<_internal::Indirector<_AABSPTree::Handle<T> >, Node* >::Iterator It;
// Delete all handles stored in the member table // Delete all handles stored in the member table
It cur = memberTable.begin(); It cur = memberTable.begin();
It end = memberTable.end(); It end = memberTable.end();
@ -970,7 +970,7 @@ public:
// Insert into the node // Insert into the node
node->valueArray.append(h); node->valueArray.append(h);
node->boundsArray.append(h->bounds); node->boundsArray.append(h->bounds);
// Insert into the node table // Insert into the node table
Member m(h); Member m(h);
memberTable.set(m, node); memberTable.set(m, node);
@ -1022,8 +1022,8 @@ public:
/** /**
Removes an object from the set in O(1) time. Removes an object from the set in O(1) time.
It is an error to remove members that are not already It is an error to remove members that are not already
present. May unbalance the tree. present. May unbalance the tree.
Removing an element never causes a node (split plane) to be removed... Removing an element never causes a node (split plane) to be removed...
nodes are only changed when the tree is rebalanced. This behavior nodes are only changed when the tree is rebalanced. This behavior
is desirable because it allows the split planes to be serialized, is desirable because it allows the split planes to be serialized,
@ -1075,7 +1075,7 @@ public:
on <I>T</I> are independent of the bounds. In on <I>T</I> are independent of the bounds. In
that case, you may call update(v) to insert an that case, you may call update(v) to insert an
element for the first time and call update(v) element for the first time and call update(v)
again every time it moves to keep the tree again every time it moves to keep the tree
up to date. up to date.
*/ */
void update(const T& value) { void update(const T& value) {
@ -1091,15 +1091,15 @@ public:
have moved substantially from their original positions have moved substantially from their original positions
(which unbalances the tree and causes the spatial (which unbalances the tree and causes the spatial
queries to be slow). queries to be slow).
@param valuesPerNode Maximum number of elements to put at @param valuesPerNode Maximum number of elements to put at
a node. a node.
@param numMeanSplits numMeanSplits = 0 gives a @param numMeanSplits numMeanSplits = 0 gives a
fully axis aligned BSP-tree, where the balance operation attempts to balance fully axis aligned BSP-tree, where the balance operation attempts to balance
the tree so that every splitting plane has an equal number of left the tree so that every splitting plane has an equal number of left
and right children (i.e. it is a <B>median</B> split along that axis). and right children (i.e. it is a <B>median</B> split along that axis).
This tends to maximize average performance. This tends to maximize average performance.
You can override this behavior by You can override this behavior by
setting a number of <B>mean</B> (average) splits. numMeanSplits = MAX_INT setting a number of <B>mean</B> (average) splits. numMeanSplits = MAX_INT
@ -1126,7 +1126,7 @@ public:
} }
Array<_AABSPTree::Handle<T> * > temp; Array<_AABSPTree::Handle<T> * > temp;
// Make a new root. Work with a copy of the value array because // Make a new root. Work with a copy of the value array because
// makeNode clears the source array as it progresses // makeNode clears the source array as it progresses
Array<_AABSPTree::Handle<T> * > copy(oldRoot->valueArray); Array<_AABSPTree::Handle<T> * > copy(oldRoot->valueArray);
root = makeNode(copy, valuesPerNode, numMeanSplits, temp); root = makeNode(copy, valuesPerNode, numMeanSplits, temp);
@ -1195,7 +1195,7 @@ protected:
public: public:
/** /**
Returns all members inside the set of planes. Returns all members inside the set of planes.
@param members The results are appended to this array. @param members The results are appended to this array.
*/ */
void getIntersectingMembers(const Array<Plane>& plane, Array<T>& members) const { void getIntersectingMembers(const Array<Plane>& plane, Array<T>& members) const {
@ -1221,7 +1221,7 @@ public:
*/ */
void getIntersectingMembers(const GCamera::Frustum& frustum, Array<T>& members) const { void getIntersectingMembers(const GCamera::Frustum& frustum, Array<T>& members) const {
Array<Plane> plane; Array<Plane> plane;
for (int i = 0; i < frustum.faceArray.size(); ++i) { for (int i = 0; i < frustum.faceArray.size(); ++i) {
plane.append(frustum.faceArray[i].plane); plane.append(frustum.faceArray[i].plane);
} }
@ -1260,14 +1260,14 @@ public:
// caller uses post increment (which they shouldn't!). // caller uses post increment (which they shouldn't!).
Array<Node*> stack; Array<Node*> stack;
/** The next index of current->valueArray to return. /** The next index of current->valueArray to return.
Undefined when isEnd is true.*/ Undefined when isEnd is true.*/
int nextValueArrayIndex; int nextValueArrayIndex;
BoxIntersectionIterator() : isEnd(true) {} BoxIntersectionIterator() : isEnd(true) {}
BoxIntersectionIterator(const AABox& b, const Node* root) : BoxIntersectionIterator(const AABox& b, const Node* root) :
isEnd(root == NULL), box(b), isEnd(root == NULL), box(b),
node(const_cast<Node*>(root)), nextValueArrayIndex(-1) { node(const_cast<Node*>(root)), nextValueArrayIndex(-1) {
// We intentionally start at the "-1" index of the current // We intentionally start at the "-1" index of the current
@ -1290,10 +1290,10 @@ public:
} else if (other.isEnd) { } else if (other.isEnd) {
return false; return false;
} else { } else {
// Two non-end iterators; see if they match. This is kind of // Two non-end iterators; see if they match. This is kind of
// silly; users shouldn't call == on iterators in general unless // silly; users shouldn't call == on iterators in general unless
// one of them is the end iterator. // one of them is the end iterator.
if ((box != other.box) || (node != other.node) || if ((box != other.box) || (node != other.node) ||
(nextValueArrayIndex != other.nextValueArrayIndex) || (nextValueArrayIndex != other.nextValueArrayIndex) ||
(stack.length() != other.stack.length())) { (stack.length() != other.stack.length())) {
return false; return false;
@ -1317,51 +1317,51 @@ public:
BoxIntersectionIterator& operator++() { BoxIntersectionIterator& operator++() {
++nextValueArrayIndex; ++nextValueArrayIndex;
bool foundIntersection = false; bool foundIntersection = false;
while (! isEnd && ! foundIntersection) { while (! isEnd && ! foundIntersection) {
// Search for the next node if we've exhausted this one // Search for the next node if we've exhausted this one
while ((! isEnd) && (nextValueArrayIndex >= node->valueArray.length())) { while ((! isEnd) && (nextValueArrayIndex >= node->valueArray.length())) {
// If we entered this loop, then the iterator has exhausted the elements at // If we entered this loop, then the iterator has exhausted the elements at
// node (possibly because it just switched to a child node with no members). // node (possibly because it just switched to a child node with no members).
// This loop continues until it finds a node with members or reaches // This loop continues until it finds a node with members or reaches
// the end of the whole intersection search. // the end of the whole intersection search.
// If the right child overlaps the box, push it onto the stack for // If the right child overlaps the box, push it onto the stack for
// processing. // processing.
if ((node->child[1] != NULL) && if ((node->child[1] != NULL) &&
(box.high()[node->splitAxis] > node->splitLocation)) { (box.high()[node->splitAxis] > node->splitLocation)) {
stack.push(node->child[1]); stack.push(node->child[1]);
} }
// If the left child overlaps the box, push it onto the stack for
// processing.
if ((node->child[0] != NULL) &&
(box.low()[node->splitAxis] < node->splitLocation)) {
stack.push(node->child[0]);
}
if (stack.length() > 0) { // If the left child overlaps the box, push it onto the stack for
// Go on to the next node (which may be either one of the ones we // processing.
// just pushed, or one from farther back the tree). if ((node->child[0] != NULL) &&
node = stack.pop(); (box.low()[node->splitAxis] < node->splitLocation)) {
nextValueArrayIndex = 0; stack.push(node->child[0]);
} else { }
// That was the last node; we're done iterating
isEnd = true;
}
}
// Search for the next intersection at this node until we run out of children if (stack.length() > 0) {
while (! isEnd && ! foundIntersection && (nextValueArrayIndex < node->valueArray.length())) { // Go on to the next node (which may be either one of the ones we
if (box.intersects(node->boundsArray[nextValueArrayIndex])) { // just pushed, or one from farther back the tree).
foundIntersection = true; node = stack.pop();
} else { nextValueArrayIndex = 0;
++nextValueArrayIndex; } else {
// If we exhaust this node, we'll loop around the master loop // That was the last node; we're done iterating
// to find a new node. isEnd = true;
} }
} }
// Search for the next intersection at this node until we run out of children
while (! isEnd && ! foundIntersection && (nextValueArrayIndex < node->valueArray.length())) {
if (box.intersects(node->boundsArray[nextValueArrayIndex])) {
foundIntersection = true;
} else {
++nextValueArrayIndex;
// If we exhaust this node, we'll loop around the master loop
// to find a new node.
}
}
} }
return *this; return *this;
@ -1431,7 +1431,7 @@ public:
Invoke a callback for every member along a ray until the closest intersection is found. Invoke a callback for every member along a ray until the closest intersection is found.
@param callback either a function or an instance of a class with an overloaded operator() of the form: @param callback either a function or an instance of a class with an overloaded operator() of the form:
<code>void callback(const Ray& ray, const T& object, float& distance)</code>. If the ray hits the object <code>void callback(const Ray& ray, const T& object, float& distance)</code>. If the ray hits the object
before travelling distance <code>distance</code>, updates <code>distance</code> with the new distance to before travelling distance <code>distance</code>, updates <code>distance</code> with the new distance to
the intersection, otherwise leaves it unmodified. A common example is: the intersection, otherwise leaves it unmodified. A common example is:
@ -1482,12 +1482,12 @@ public:
*/ */
template<typename RayCallback> template<typename RayCallback>
void intersectRay( void intersectRay(
const Ray& ray, const Ray& ray,
RayCallback& intersectCallback, RayCallback& intersectCallback,
float& distance, float& distance,
bool pStopAtFirstHit, bool pStopAtFirstHit,
bool intersectCallbackIsFast = false) const { bool intersectCallbackIsFast = false) const {
root->intersectRay(ray, intersectCallback, distance, pStopAtFirstHit, intersectCallbackIsFast); root->intersectRay(ray, intersectCallback, distance, pStopAtFirstHit, intersectCallbackIsFast);
} }
@ -1509,7 +1509,7 @@ public:
#if 0 #if 0
/** /**
Stores the locations of the splitting planes (the structure but not the content) Stores the locations of the splitting planes (the structure but not the content)
so that the tree can be quickly rebuilt from a previous configuration without so that the tree can be quickly rebuilt from a previous configuration without
calling balance. calling balance.
*/ */
void serializeStructure(BinaryOutput& bo) const { void serializeStructure(BinaryOutput& bo) const {
@ -1593,9 +1593,9 @@ public:
/** /**
C++ STL style iterator method. Returns the first member. C++ STL style iterator method. Returns the first member.
Use preincrement (++entry) to get to the next element (iteration Use preincrement (++entry) to get to the next element (iteration
order is arbitrary). order is arbitrary).
Do not modify the set while iterating. Do not modify the set while iterating.
*/ */
Iterator begin() const { Iterator begin() const {
@ -1615,6 +1615,3 @@ public:
} }
#endif #endif

View file

@ -1,4 +1,4 @@
/* /*
* Copyright (C) 2005-2008 MaNGOS <http://getmangos.com/> * Copyright (C) 2005-2008 MaNGOS <http://getmangos.com/>
* *
* This program is free software; you can redistribute it and/or modify * This program is free software; you can redistribute it and/or modify
@ -82,11 +82,11 @@ namespace VMAP
// See if the ray will ever hit this node or its children // See if the ray will ever hit this node or its children
Vector3 location; Vector3 location;
bool alreadyInsideBounds = false; bool alreadyInsideBounds = false;
bool rayWillHitBounds = bool rayWillHitBounds =
MyCollisionDetection::collisionLocationForMovingPointFixedAABox( MyCollisionDetection::collisionLocationForMovingPointFixedAABox(
pRay.origin, pRay.direction, pBox, location, alreadyInsideBounds); pRay.origin, pRay.direction, pBox, location, alreadyInsideBounds);
bool canHitThisNode = (alreadyInsideBounds || bool canHitThisNode = (alreadyInsideBounds ||
(rayWillHitBounds && ((location - pRay.origin).squaredLength() < (pMaxDist * pMaxDist)))); (rayWillHitBounds && ((location - pRay.origin).squaredLength() < (pMaxDist * pMaxDist))));
return canHitThisNode; return canHitThisNode;

View file

@ -1,4 +1,4 @@
/* /*
* Copyright (C) 2005-2008 MaNGOS <http://getmangos.com/> * Copyright (C) 2005-2008 MaNGOS <http://getmangos.com/>
* *
* This program is free software; you can redistribute it and/or modify * This program is free software; you can redistribute it and/or modify

View file

@ -1,4 +1,4 @@
/* /*
* Copyright (C) 2005-2008 MaNGOS <http://getmangos.com/> * Copyright (C) 2005-2008 MaNGOS <http://getmangos.com/>
* *
* This program is free software; you can redistribute it and/or modify * This program is free software; you can redistribute it and/or modify

View file

@ -1,4 +1,4 @@
/* /*
* Copyright (C) 2005-2008 MaNGOS <http://getmangos.com/> * Copyright (C) 2005-2008 MaNGOS <http://getmangos.com/>
* *
* This program is free software; you can redistribute it and/or modify * This program is free software; you can redistribute it and/or modify

View file

@ -1,4 +1,4 @@
/* /*
* Copyright (C) 2005-2008 MaNGOS <http://getmangos.com/> * Copyright (C) 2005-2008 MaNGOS <http://getmangos.com/>
* *
* This program is free software; you can redistribute it and/or modify * This program is free software; you can redistribute it and/or modify
@ -23,7 +23,7 @@ using namespace G3D;
namespace VMAP namespace VMAP
{ {
bool CommandFileRW::appendCmd(const Command& bool CommandFileRW::appendCmd(const Command&
#ifdef _DEBUG #ifdef _DEBUG
pCommand pCommand
#endif #endif
@ -53,7 +53,7 @@ namespace VMAP
//========================================================= //=========================================================
bool CommandFileRW::appendCmds(const Array<Command>& bool CommandFileRW::appendCmds(const Array<Command>&
#ifdef _DEBUG #ifdef _DEBUG
pCmdArray pCmdArray
#endif #endif

View file

@ -1,4 +1,4 @@
/* /*
* Copyright (C) 2005-2008 MaNGOS <http://getmangos.com/> * Copyright (C) 2005-2008 MaNGOS <http://getmangos.com/>
* *
* This program is free software; you can redistribute it and/or modify * This program is free software; you can redistribute it and/or modify

View file

@ -1,4 +1,4 @@
/* /*
* Copyright (C) 2005-2008 MaNGOS <http://getmangos.com/> * Copyright (C) 2005-2008 MaNGOS <http://getmangos.com/>
* *
* This program is free software; you can redistribute it and/or modify * This program is free software; you can redistribute it and/or modify

View file

@ -27,30 +27,30 @@ AM_CPPFLAGS = $(MANGOS_INCLUDES) -I$(top_builddir)/src/shared -I$(srcdir) -I$(sr
noinst_LIBRARIES = libmangosvmaps.a noinst_LIBRARIES = libmangosvmaps.a
libmangosvmaps_a_SOURCES = \ libmangosvmaps_a_SOURCES = \
AABSPTree.h \ AABSPTree.h \
BaseModel.cpp \ BaseModel.cpp \
BaseModel.h \ BaseModel.h \
CoordModelMapping.cpp \ CoordModelMapping.cpp \
CoordModelMapping.h \ CoordModelMapping.h \
DebugCmdLogger.cpp \ DebugCmdLogger.cpp \
DebugCmdLogger.h \ DebugCmdLogger.h \
IVMapManager.h \ IVMapManager.h \
ManagedModelContainer.cpp \ ManagedModelContainer.cpp \
ManagedModelContainer.h \ ManagedModelContainer.h \
ModelContainer.cpp \ ModelContainer.cpp \
ModelContainer.h \ ModelContainer.h \
NodeValueAccess.h \ NodeValueAccess.h \
ShortBox.h \ ShortBox.h \
ShortVector.h \ ShortVector.h \
SubModel.cpp \ SubModel.cpp \
SubModel.h \ SubModel.h \
TileAssembler.cpp \ TileAssembler.cpp \
TileAssembler.h \ TileAssembler.h \
TreeNode.cpp \ TreeNode.cpp \
TreeNode.h \ TreeNode.h \
VMapDefinitions.h \ VMapDefinitions.h \
VMapFactory.cpp \ VMapFactory.cpp \
VMapFactory.h \ VMapFactory.h \
VMapManager.cpp \ VMapManager.cpp \
VMapManager.h \ VMapManager.h \
VMapTools.h VMapTools.h

View file

@ -1,4 +1,4 @@
/* /*
* Copyright (C) 2005-2008 MaNGOS <http://getmangos.com/> * Copyright (C) 2005-2008 MaNGOS <http://getmangos.com/>
* *
* This program is free software; you can redistribute it and/or modify * This program is free software; you can redistribute it and/or modify

View file

@ -1,4 +1,4 @@
/* /*
* Copyright (C) 2005-2008 MaNGOS <http://getmangos.com/> * Copyright (C) 2005-2008 MaNGOS <http://getmangos.com/>
* *
* This program is free software; you can redistribute it and/or modify * This program is free software; you can redistribute it and/or modify

View file

@ -1,4 +1,4 @@
/* /*
* Copyright (C) 2005-2008 MaNGOS <http://getmangos.com/> * Copyright (C) 2005-2008 MaNGOS <http://getmangos.com/>
* *
* This program is free software; you can redistribute it and/or modify * This program is free software; you can redistribute it and/or modify
@ -66,7 +66,7 @@ namespace VMAP
nSubModels += pNode.valueArray.size(); nSubModels += pNode.valueArray.size();
for(int i=0;i<pNode.valueArray.size(); i++) for(int i=0;i<pNode.valueArray.size(); i++)
{ {
G3D::_AABSPTree::Handle<SubModel*>* h= pNode.valueArray[i]; G3D::_AABSPTree::Handle<SubModel*>* h= pNode.valueArray[i];
SubModel *m = h->value; SubModel *m = h->value;
// add the internal nodes as well // add the internal nodes as well
nNodes += m->getNNodes(); nNodes += m->getNNodes();

View file

@ -1,4 +1,4 @@
/* /*
* Copyright (C) 2005-2008 MaNGOS <http://getmangos.com/> * Copyright (C) 2005-2008 MaNGOS <http://getmangos.com/>
* *
* This program is free software; you can redistribute it and/or modify * This program is free software; you can redistribute it and/or modify

View file

@ -1,4 +1,4 @@
/* /*
* Copyright (C) 2005-2008 MaNGOS <http://getmangos.com/> * Copyright (C) 2005-2008 MaNGOS <http://getmangos.com/>
* *
* This program is free software; you can redistribute it and/or modify * This program is free software; you can redistribute it and/or modify

View file

@ -1,4 +1,4 @@
/* /*
* Copyright (C) 2005-2008 MaNGOS <http://getmangos.com/> * Copyright (C) 2005-2008 MaNGOS <http://getmangos.com/>
* *
* This program is free software; you can redistribute it and/or modify * This program is free software; you can redistribute it and/or modify

View file

@ -1,4 +1,4 @@
/* /*
* Copyright (C) 2005-2008 MaNGOS <http://getmangos.com/> * Copyright (C) 2005-2008 MaNGOS <http://getmangos.com/>
* *
* This program is free software; you can redistribute it and/or modify * This program is free software; you can redistribute it and/or modify

View file

@ -1,4 +1,4 @@
/* /*
* Copyright (C) 2005-2008 MaNGOS <http://getmangos.com/> * Copyright (C) 2005-2008 MaNGOS <http://getmangos.com/>
* *
* This program is free software; you can redistribute it and/or modify * This program is free software; you can redistribute it and/or modify

View file

@ -1,4 +1,4 @@
/* /*
* Copyright (C) 2005-2008 MaNGOS <http://getmangos.com/> * Copyright (C) 2005-2008 MaNGOS <http://getmangos.com/>
* *
* This program is free software; you can redistribute it and/or modify * This program is free software; you can redistribute it and/or modify

View file

@ -1,4 +1,4 @@
/* /*
* Copyright (C) 2005-2008 MaNGOS <http://getmangos.com/> * Copyright (C) 2005-2008 MaNGOS <http://getmangos.com/>
* *
* This program is free software; you can redistribute it and/or modify * This program is free software; you can redistribute it and/or modify

View file

@ -1,4 +1,4 @@
/* /*
* Copyright (C) 2005-2008 MaNGOS <http://getmangos.com/> * Copyright (C) 2005-2008 MaNGOS <http://getmangos.com/>
* *
* This program is free software; you can redistribute it and/or modify * This program is free software; you can redistribute it and/or modify

View file

@ -1,4 +1,4 @@
/* /*
* Copyright (C) 2005-2008 MaNGOS <http://getmangos.com/> * Copyright (C) 2005-2008 MaNGOS <http://getmangos.com/>
* *
* This program is free software; you can redistribute it and/or modify * This program is free software; you can redistribute it and/or modify

View file

@ -1,4 +1,4 @@
/* /*
* Copyright (C) 2005-2008 MaNGOS <http://getmangos.com/> * Copyright (C) 2005-2008 MaNGOS <http://getmangos.com/>
* *
* This program is free software; you can redistribute it and/or modify * This program is free software; you can redistribute it and/or modify
@ -107,11 +107,11 @@ namespace VMAP
// See if the ray will ever hit this node or its children // See if the ray will ever hit this node or its children
G3D::Vector3 location; G3D::Vector3 location;
bool alreadyInsideBounds = false; bool alreadyInsideBounds = false;
bool rayWillHitBounds = bool rayWillHitBounds =
MyCollisionDetection::collisionLocationForMovingPointFixedAABox( MyCollisionDetection::collisionLocationForMovingPointFixedAABox(
ray.origin, ray.direction, iBounds, location, alreadyInsideBounds); ray.origin, ray.direction, iBounds, location, alreadyInsideBounds);
bool canHitThisNode = (alreadyInsideBounds || bool canHitThisNode = (alreadyInsideBounds ||
(rayWillHitBounds && ((location - ray.origin).squaredLength() < (distance*distance)))); (rayWillHitBounds && ((location - ray.origin).squaredLength() < (distance*distance))));
return canHitThisNode; return canHitThisNode;
@ -119,8 +119,8 @@ namespace VMAP
template<typename RayCallback, typename TNode, typename TValue> template<typename RayCallback, typename TNode, typename TValue>
void intersectRay( void intersectRay(
const G3D::Ray& ray, const G3D::Ray& ray,
RayCallback& intersectCallback, RayCallback& intersectCallback,
float& distance, float& distance,
const NodeValueAccess<TNode, TValue>& pNodeValueAccess, const NodeValueAccess<TNode, TValue>& pNodeValueAccess,
bool pStopAtFirstHit, bool pStopAtFirstHit,
@ -132,7 +132,7 @@ namespace VMAP
} }
// Test for intersection against every object at this node. // Test for intersection against every object at this node.
for (unsigned int v = iStartPosition; v < (iNumberOfValues+iStartPosition); ++v) { for (unsigned int v = iStartPosition; v < (iNumberOfValues+iStartPosition); ++v) {
const TValue& nodeValue = pNodeValueAccess.getValue(v); const TValue& nodeValue = pNodeValueAccess.getValue(v);
bool canHitThisObject = true; bool canHitThisObject = true;
if (! intersectCallbackIsFast) { if (! intersectCallbackIsFast) {
@ -140,11 +140,11 @@ namespace VMAP
G3D::Vector3 location; G3D::Vector3 location;
const G3D::AABox& bounds = nodeValue.getAABoxBounds(); const G3D::AABox& bounds = nodeValue.getAABoxBounds();
bool alreadyInsideBounds = false; bool alreadyInsideBounds = false;
bool rayWillHitBounds = bool rayWillHitBounds =
MyCollisionDetection::collisionLocationForMovingPointFixedAABox( MyCollisionDetection::collisionLocationForMovingPointFixedAABox(
ray.origin, ray.direction, bounds, location, alreadyInsideBounds); ray.origin, ray.direction, bounds, location, alreadyInsideBounds);
canHitThisObject = (alreadyInsideBounds || canHitThisObject = (alreadyInsideBounds ||
(rayWillHitBounds && ((location - ray.origin).squaredLength() < (distance*distance)))); (rayWillHitBounds && ((location - ray.origin).squaredLength() < (distance*distance))));
} }
@ -158,7 +158,7 @@ namespace VMAP
} }
// There are three cases to consider next: // There are three cases to consider next:
// //
// 1. the ray can start on one side of the splitting plane and never enter the other, // 1. the ray can start on one side of the splitting plane and never enter the other,
// 2. the ray can start on one side and enter the other, and // 2. the ray can start on one side and enter the other, and
// 3. the ray can travel exactly down the splitting plane // 3. the ray can travel exactly down the splitting plane
@ -203,7 +203,7 @@ namespace VMAP
return; return;
} }
if (ray.direction[iSplitAxis] != 0) { if (ray.direction[iSplitAxis] != 0) {
// See if there was an intersection before hitting the splitting plane. // See if there was an intersection before hitting the splitting plane.
// If so, there is no need to look on the far side and recursion terminates. // If so, there is no need to look on the far side and recursion terminates.
float distanceToSplittingPlane = (iSplitLocation - ray.origin[iSplitAxis]) / ray.direction[iSplitAxis]; float distanceToSplittingPlane = (iSplitLocation - ray.origin[iSplitAxis]) / ray.direction[iSplitAxis];
if (distanceToSplittingPlane > distance) { if (distanceToSplittingPlane > distance) {

View file

@ -1,4 +1,4 @@
/* /*
* Copyright (C) 2005-2008 MaNGOS <http://getmangos.com/> * Copyright (C) 2005-2008 MaNGOS <http://getmangos.com/>
* *
* This program is free software; you can redistribute it and/or modify * This program is free software; you can redistribute it and/or modify

View file

@ -1,4 +1,4 @@
/* /*
* Copyright (C) 2005-2008 MaNGOS <http://getmangos.com/> * Copyright (C) 2005-2008 MaNGOS <http://getmangos.com/>
* *
* This program is free software; you can redistribute it and/or modify * This program is free software; you can redistribute it and/or modify

View file

@ -1,4 +1,4 @@
/* /*
* Copyright (C) 2005-2008 MaNGOS <http://getmangos.com/> * Copyright (C) 2005-2008 MaNGOS <http://getmangos.com/>
* *
* This program is free software; you can redistribute it and/or modify * This program is free software; you can redistribute it and/or modify

View file

@ -1,4 +1,4 @@
/* /*
* Copyright (C) 2005-2008 MaNGOS <http://getmangos.com/> * Copyright (C) 2005-2008 MaNGOS <http://getmangos.com/>
* *
* This program is free software; you can redistribute it and/or modify * This program is free software; you can redistribute it and/or modify

View file

@ -1,4 +1,4 @@
/* /*
* Copyright (C) 2005-2008 MaNGOS <http://getmangos.com/> * Copyright (C) 2005-2008 MaNGOS <http://getmangos.com/>
* *
* This program is free software; you can redistribute it and/or modify * This program is free software; you can redistribute it and/or modify

View file

@ -1,4 +1,4 @@
/* /*
* Copyright (C) 2005-2008 MaNGOS <http://getmangos.com/> * Copyright (C) 2005-2008 MaNGOS <http://getmangos.com/>
* *
* This program is free software; you can redistribute it and/or modify * This program is free software; you can redistribute it and/or modify
@ -32,7 +32,7 @@ The collision detection is modified to return true, if we are inside an object.
namespace VMAP namespace VMAP
{ {
template<class TValue> template<class TValue>
class IntersectionCallBack { class IntersectionCallBack {
public: public:
TValue* closestEntity; TValue* closestEntity;