summaryrefslogtreecommitdiff
path: root/indra/llmath/lloctree.h
diff options
context:
space:
mode:
Diffstat (limited to 'indra/llmath/lloctree.h')
-rwxr-xr-x[-rw-r--r--]indra/llmath/lloctree.h542
1 files changed, 340 insertions, 202 deletions
diff --git a/indra/llmath/lloctree.h b/indra/llmath/lloctree.h
index 2f34fb1bb0..280d2653d3 100644..100755
--- a/indra/llmath/lloctree.h
+++ b/indra/llmath/lloctree.h
@@ -2,31 +2,25 @@
* @file lloctree.h
* @brief Octree declaration.
*
- * $LicenseInfo:firstyear=2005&license=viewergpl$
- *
- * Copyright (c) 2005-2009, Linden Research, Inc.
- *
+ * $LicenseInfo:firstyear=2005&license=viewerlgpl$
* Second Life Viewer Source Code
- * The source code in this file ("Source Code") is provided by Linden Lab
- * to you under the terms of the GNU General Public License, version 2.0
- * ("GPL"), unless you have obtained a separate licensing agreement
- * ("Other License"), formally executed by you and Linden Lab. Terms of
- * the GPL can be found in doc/GPL-license.txt in this distribution, or
- * online at http://secondlifegrid.net/programs/open_source/licensing/gplv2
+ * Copyright (C) 2010, Linden Research, Inc.
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation;
+ * version 2.1 of the License only.
*
- * There are special exceptions to the terms and conditions of the GPL as
- * it is applied to this Source Code. View the full text of the exception
- * in the file doc/FLOSS-exception.txt in this software distribution, or
- * online at
- * http://secondlifegrid.net/programs/open_source/licensing/flossexception
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
*
- * By copying, modifying or distributing this software, you acknowledge
- * that you have read and understood your obligations described above,
- * and agree to abide by those obligations.
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*
- * ALL LINDEN LAB SOURCE CODE IS PROVIDED "AS IS." LINDEN LAB MAKES NO
- * WARRANTIES, EXPRESS, IMPLIED OR OTHERWISE, REGARDING ITS ACCURACY,
- * COMPLETENESS OR PERFORMANCE.
+ * Linden Research, Inc., 945 Battery Street, San Francisco, CA 94111 USA
* $/LicenseInfo$
*/
@@ -35,21 +29,21 @@
#include "lltreenode.h"
#include "v3math.h"
+#include "llvector4a.h"
#include <vector>
-#include <set>
-#if LL_RELEASE_WITH_DEBUG_INFO || LL_DEBUG
-#define OCT_ERRS LL_ERRS("OctreeErrors")
-#else
#define OCT_ERRS LL_WARNS("OctreeErrors")
-#endif
-#define LL_OCTREE_PARANOIA_CHECK 0
+
+extern U32 gOctreeMaxCapacity;
+extern float gOctreeMinSize;
+
+/*#define LL_OCTREE_PARANOIA_CHECK 0
#if LL_DARWIN
#define LL_OCTREE_MAX_CAPACITY 32
#else
#define LL_OCTREE_MAX_CAPACITY 128
-#endif
+#endif*/
template <class T> class LLOctreeNode;
@@ -73,39 +67,63 @@ public:
};
template <class T>
+class LLOctreeTravelerDepthFirst : public LLOctreeTraveler<T>
+{
+public:
+ virtual void traverse(const LLOctreeNode<T>* node);
+};
+
+template <class T>
class LLOctreeNode : public LLTreeNode<T>
{
public:
+
typedef LLOctreeTraveler<T> oct_traveler;
typedef LLTreeTraveler<T> tree_traveler;
- typedef typename std::set<LLPointer<T> > element_list;
- typedef typename std::set<LLPointer<T> >::iterator element_iter;
- typedef typename std::set<LLPointer<T> >::const_iterator const_element_iter;
+ typedef std::vector< LLPointer<T> > element_list; // note: don't remove the whitespace between "> >"
+ typedef LLPointer<T>* element_iter;
+ typedef const LLPointer<T>* const_element_iter;
typedef typename std::vector<LLTreeListener<T>*>::iterator tree_listener_iter;
- typedef typename std::vector<LLOctreeNode<T>* > child_list;
+ typedef LLOctreeNode<T>** child_list;
+ typedef LLOctreeNode<T>** child_iter;
+
typedef LLTreeNode<T> BaseType;
typedef LLOctreeNode<T> oct_node;
typedef LLOctreeListener<T> oct_listener;
- static const U8 OCTANT_POSITIVE_X = 0x01;
- static const U8 OCTANT_POSITIVE_Y = 0x02;
- static const U8 OCTANT_POSITIVE_Z = 0x04;
-
- LLOctreeNode( LLVector3d center,
- LLVector3d size,
+ void* operator new(size_t size)
+ {
+ return ll_aligned_malloc_16(size);
+ }
+
+ void operator delete(void* ptr)
+ {
+ ll_aligned_free_16(ptr);
+ }
+
+ LLOctreeNode( const LLVector4a& center,
+ const LLVector4a& size,
BaseType* parent,
U8 octant = 255)
: mParent((oct_node*)parent),
- mCenter(center),
- mSize(size),
mOctant(octant)
{
+ llassert(size[0] >= gOctreeMinSize*0.5f);
+ //always keep a NULL terminated list to avoid out of bounds exceptions in debug builds
+ mData.push_back(NULL);
+ mDataEnd = &mData[0];
+
+ mCenter = center;
+ mSize = size;
+
updateMinMax();
if ((mOctant == 255) && mParent)
{
- mOctant = ((oct_node*) mParent)->getOctant(mCenter.mdV);
+ mOctant = ((oct_node*) mParent)->getOctant(mCenter);
}
+ mElementCount = 0;
+
clearChildren();
}
@@ -113,6 +131,16 @@ public:
{
BaseType::destroyListeners();
+ for (U32 i = 0; i < mElementCount; ++i)
+ {
+ mData[i]->setBinIndex(-1);
+ mData[i] = NULL;
+ }
+
+ mData.clear();
+ mData.push_back(NULL);
+ mDataEnd = &mData[0];
+
for (U32 i = 0; i < getChildCount(); i++)
{
delete getChild(i);
@@ -120,40 +148,24 @@ public:
}
inline const BaseType* getParent() const { return mParent; }
- inline void setParent(BaseType* parent) { mParent = (oct_node*) parent; }
- inline const LLVector3d& getCenter() const { return mCenter; }
- inline const LLVector3d& getSize() const { return mSize; }
- inline void setCenter(LLVector3d center) { mCenter = center; }
- inline void setSize(LLVector3d size) { mSize = size; }
- inline oct_node* getNodeAt(T* data) { return getNodeAt(data->getPositionGroup(), data->getBinRadius()); }
- inline U8 getOctant() const { return mOctant; }
- inline void setOctant(U8 octant) { mOctant = octant; }
+ inline void setParent(BaseType* parent) { mParent = (oct_node*) parent; }
+ inline const LLVector4a& getCenter() const { return mCenter; }
+ inline const LLVector4a& getSize() const { return mSize; }
+ inline void setCenter(const LLVector4a& center) { mCenter = center; }
+ inline void setSize(const LLVector4a& size) { mSize = size; }
+ inline oct_node* getNodeAt(T* data) { return getNodeAt(data->getPositionGroup(), data->getBinRadius()); }
+ inline U8 getOctant() const { return mOctant; }
inline const oct_node* getOctParent() const { return (const oct_node*) getParent(); }
inline oct_node* getOctParent() { return (oct_node*) getParent(); }
- U8 getOctant(const F64 pos[]) const //get the octant pos is in
+ U8 getOctant(const LLVector4a& pos) const //get the octant pos is in
{
- U8 ret = 0;
-
- if (pos[0] > mCenter.mdV[0])
- {
- ret |= OCTANT_POSITIVE_X;
- }
- if (pos[1] > mCenter.mdV[1])
- {
- ret |= OCTANT_POSITIVE_Y;
- }
- if (pos[2] > mCenter.mdV[2])
- {
- ret |= OCTANT_POSITIVE_Z;
- }
-
- return ret;
+ return (U8) (pos.greaterThan(mCenter).getGatheredBits() & 0x7);
}
- inline bool isInside(const LLVector3d& pos, const F64& rad) const
+ inline bool isInside(const LLVector4a& pos, const F32& rad) const
{
- return rad <= mSize.mdV[0]*2.0 && isInside(pos);
+ return rad <= mSize[0]*2.f && isInside(pos);
}
inline bool isInside(T* data) const
@@ -161,29 +173,27 @@ public:
return isInside(data->getPositionGroup(), data->getBinRadius());
}
- bool isInside(const LLVector3d& pos) const
+ bool isInside(const LLVector4a& pos) const
{
- const F64& x = pos.mdV[0];
- const F64& y = pos.mdV[1];
- const F64& z = pos.mdV[2];
-
- if (x > mMax.mdV[0] || x <= mMin.mdV[0] ||
- y > mMax.mdV[1] || y <= mMin.mdV[1] ||
- z > mMax.mdV[2] || z <= mMin.mdV[2])
+ S32 gt = pos.greaterThan(mMax).getGatheredBits() & 0x7;
+ if (gt)
{
return false;
}
-
+
+ S32 lt = pos.lessEqual(mMin).getGatheredBits() & 0x7;
+ if (lt)
+ {
+ return false;
+ }
+
return true;
}
void updateMinMax()
{
- for (U32 i = 0; i < 3; i++)
- {
- mMax.mdV[i] = mCenter.mdV[i] + mSize.mdV[i];
- mMin.mdV[i] = mCenter.mdV[i] - mSize.mdV[i];
- }
+ mMax.setAdd(mCenter, mSize);
+ mMin.setSub(mCenter, mSize);
}
inline oct_listener* getOctListener(U32 index)
@@ -196,44 +206,49 @@ public:
return contains(xform->getBinRadius());
}
- bool contains(F64 radius)
+ bool contains(F32 radius)
{
if (mParent == NULL)
{ //root node contains nothing
return false;
}
- F64 size = mSize.mdV[0];
- F64 p_size = size * 2.0;
+ F32 size = mSize[0];
+ F32 p_size = size * 2.f;
- return (radius <= 0.001 && size <= 0.001) ||
+ return (radius <= gOctreeMinSize && size <= gOctreeMinSize) ||
(radius <= p_size && radius > size);
}
- static void pushCenter(LLVector3d &center, const LLVector3d &size, const T* data)
+ static void pushCenter(LLVector4a &center, const LLVector4a &size, const T* data)
{
- const LLVector3d& pos = data->getPositionGroup();
- for (U32 i = 0; i < 3; i++)
- {
- if (pos.mdV[i] > center.mdV[i])
- {
- center.mdV[i] += size.mdV[i];
- }
- else
- {
- center.mdV[i] -= size.mdV[i];
- }
- }
+ const LLVector4a& pos = data->getPositionGroup();
+
+ LLVector4Logical gt = pos.greaterThan(center);
+
+ LLVector4a up;
+ up = _mm_and_ps(size, gt);
+
+ LLVector4a down;
+ down = _mm_andnot_ps(gt, size);
+
+ center.add(up);
+ center.sub(down);
}
void accept(oct_traveler* visitor) { visitor->visit(this); }
- virtual bool isLeaf() const { return mChild.empty(); }
+ virtual bool isLeaf() const { return mChildCount == 0; }
- U32 getElementCount() const { return mData.size(); }
+ U32 getElementCount() const { return mElementCount; }
+ bool isEmpty() const { return mElementCount == 0; }
element_list& getData() { return mData; }
const element_list& getData() const { return mData; }
-
- U32 getChildCount() const { return mChild.size(); }
+ element_iter getDataBegin() { return &mData[0]; }
+ element_iter getDataEnd() { return mDataEnd; }
+ const_element_iter getDataBegin() const { return &mData[0]; }
+ const_element_iter getDataEnd() const { return mDataEnd; }
+
+ U32 getChildCount() const { return mChildCount; }
oct_node* getChild(U32 index) { return mChild[index]; }
const oct_node* getChild(U32 index) const { return mChild[index]; }
child_list& getChildren() { return mChild; }
@@ -242,32 +257,49 @@ public:
void accept(tree_traveler* visitor) const { visitor->visit(this); }
void accept(oct_traveler* visitor) const { visitor->visit(this); }
- oct_node* getNodeAt(const LLVector3d& pos, const F64& rad)
+ void validateChildMap()
+ {
+ for (U32 i = 0; i < 8; i++)
+ {
+ U8 idx = mChildMap[i];
+ if (idx != 255)
+ {
+ LLOctreeNode<T>* child = mChild[idx];
+
+ if (child->getOctant() != i)
+ {
+ LL_ERRS() << "Invalid child map, bad octant data." << LL_ENDL;
+ }
+
+ if (getOctant(child->getCenter()) != child->getOctant())
+ {
+ LL_ERRS() << "Invalid child octant compared to position data." << LL_ENDL;
+ }
+ }
+ }
+ }
+
+
+ oct_node* getNodeAt(const LLVector4a& pos, const F32& rad)
{
LLOctreeNode<T>* node = this;
if (node->isInside(pos, rad))
{
//do a quick search by octant
- U8 octant = node->getOctant(pos.mdV);
- BOOL keep_going = TRUE;
-
+ U8 octant = node->getOctant(pos);
+
//traverse the tree until we find a node that has no node
//at the appropriate octant or is smaller than the object.
//by definition, that node is the smallest node that contains
// the data
- while (keep_going && node->getSize().mdV[0] >= rad)
+ U8 next_node = node->mChildMap[octant];
+
+ while (next_node != 255 && node->getSize()[0] >= rad)
{
- keep_going = FALSE;
- for (U32 i = 0; i < node->getChildCount() && !keep_going; i++)
- {
- if (node->getChild(i)->getOctant() == octant)
- {
- node = node->getChild(i);
- octant = node->getOctant(pos.mdV);
- keep_going = TRUE;
- }
- }
+ node = node->getChild(next_node);
+ octant = node->getOctant(pos);
+ next_node = node->mChildMap[octant];
}
}
else if (!node->contains(rad) && node->getParent())
@@ -280,9 +312,9 @@ public:
virtual bool insert(T* data)
{
- if (data == NULL)
+ if (data == NULL || data->getBinIndex() != -1)
{
- //OCT_ERRS << "!!! INVALID ELEMENT ADDED TO OCTREE BRANCH !!!" << llendl;
+ OCT_ERRS << "!!! INVALID ELEMENT ADDED TO OCTREE BRANCH !!!" << LL_ENDL;
return false;
}
LLOctreeNode<T>* parent = getOctParent();
@@ -290,21 +322,14 @@ public:
//is it here?
if (isInside(data->getPositionGroup()))
{
- if (getElementCount() < LL_OCTREE_MAX_CAPACITY &&
- (contains(data->getBinRadius()) ||
- (data->getBinRadius() > getSize().mdV[0] &&
- parent && parent->getElementCount() >= LL_OCTREE_MAX_CAPACITY)))
+ if ((((getElementCount() < gOctreeMaxCapacity || getSize()[0] <= gOctreeMinSize) && contains(data->getBinRadius())) ||
+ (data->getBinRadius() > getSize()[0] && parent && parent->getElementCount() >= gOctreeMaxCapacity)))
{ //it belongs here
-#if LL_OCTREE_PARANOIA_CHECK
- //if this is a redundant insertion, error out (should never happen)
- if (mData.find(data) != mData.end())
- {
- llwarns << "Redundant octree insertion detected. " << data << llendl;
- return false;
- }
-#endif
-
- mData.insert(data);
+ mData.push_back(NULL);
+ mData[mElementCount] = data;
+ mElementCount++;
+ mDataEnd = &mData[mElementCount];
+ data->setBinIndex(mElementCount-1);
BaseType::insert(data);
return true;
}
@@ -323,18 +348,28 @@ public:
}
//it's here, but no kids are in the right place, make a new kid
- LLVector3d center(getCenter());
- LLVector3d size(getSize()*0.5);
+ LLVector4a center = getCenter();
+ LLVector4a size = getSize();
+ size.mul(0.5f);
//push center in direction of data
LLOctreeNode<T>::pushCenter(center, size, data);
// handle case where floating point number gets too small
- if( llabs(center.mdV[0] - getCenter().mdV[0]) < F_APPROXIMATELY_ZERO &&
- llabs(center.mdV[1] - getCenter().mdV[1]) < F_APPROXIMATELY_ZERO &&
- llabs(center.mdV[2] - getCenter().mdV[2]) < F_APPROXIMATELY_ZERO)
+ LLVector4a val;
+ val.setSub(center, getCenter());
+ val.setAbs(val);
+ LLVector4a min_diff(gOctreeMinSize);
+
+ S32 lt = val.lessThan(min_diff).getGatheredBits() & 0x7;
+
+ if( lt == 0x7 )
{
- mData.insert(data);
+ mData.push_back(NULL);
+ mData[mElementCount] = data;
+ mElementCount++;
+ mDataEnd = &mData[mElementCount];
+ data->setBinIndex(mElementCount-1);
BaseType::insert(data);
return true;
}
@@ -343,21 +378,22 @@ public:
if (getChildCount() == 8)
{
//this really isn't possible, something bad has happened
- OCT_ERRS << "Octree detected floating point error and gave up." << llendl;
+ OCT_ERRS << "Octree detected floating point error and gave up." << LL_ENDL;
return false;
}
//make sure no existing node matches this position
for (U32 i = 0; i < getChildCount(); i++)
{
- if (mChild[i]->getCenter() == center)
+ if (mChild[i]->getCenter().equals3(center))
{
- OCT_ERRS << "Octree detected duplicate child center and gave up." << llendl;
+ OCT_ERRS << "Octree detected duplicate child center and gave up." << LL_ENDL;
return false;
}
}
#endif
+ llassert(size[0] >= gOctreeMinSize*0.5f);
//make the new kid
child = new LLOctreeNode<T>(center, size, this);
addChild(child);
@@ -368,7 +404,7 @@ public:
else
{
//it's not in here, give it to the root
- //OCT_ERRS << "Octree insertion failed, starting over from root!" << llendl;
+ OCT_ERRS << "Octree insertion failed, starting over from root!" << LL_ENDL;
oct_node* node = this;
@@ -384,22 +420,58 @@ public:
return false;
}
+ void _remove(T* data, S32 i)
+ { //precondition -- mElementCount > 0, idx is in range [0, mElementCount)
+
+ mElementCount--;
+ data->setBinIndex(-1);
+
+ if (mElementCount > 0)
+ {
+ if (mElementCount != i)
+ {
+ mData[i] = mData[mElementCount]; //might unref data, do not access data after this point
+ mData[i]->setBinIndex(i);
+ }
+
+ mData[mElementCount] = NULL;
+ mData.pop_back();
+ mDataEnd = &mData[mElementCount];
+ }
+ else
+ {
+ mData.clear();
+ mData.push_back(NULL);
+ mDataEnd = &mData[0];
+ }
+
+ this->notifyRemoval(data);
+ checkAlive();
+ }
+
bool remove(T* data)
{
- if (mData.find(data) != mData.end())
- { //we have data
- mData.erase(data);
- notifyRemoval(data);
- checkAlive();
- return true;
- }
- else if (isInside(data))
+ S32 i = data->getBinIndex();
+
+ if (i >= 0 && i < mElementCount)
+ {
+ if (mData[i] == data)
+ { //found it
+ _remove(data, i);
+ llassert(data->getBinIndex() == -1);
+ return true;
+ }
+ }
+
+ if (isInside(data))
{
oct_node* dest = getNodeAt(data);
if (dest != this)
{
- return dest->remove(data);
+ bool ret = dest->remove(data);
+ llassert(data->getBinIndex() == -1);
+ return ret;
}
}
@@ -416,20 +488,22 @@ public:
}
//node is now root
- llwarns << "!!! OCTREE REMOVING FACE BY ADDRESS, SEVERE PERFORMANCE PENALTY |||" << llendl;
+ LL_WARNS() << "!!! OCTREE REMOVING ELEMENT BY ADDRESS, SEVERE PERFORMANCE PENALTY |||" << LL_ENDL;
node->removeByAddress(data);
+ llassert(data->getBinIndex() == -1);
return true;
}
void removeByAddress(T* data)
{
- if (mData.find(data) != mData.end())
+ for (U32 i = 0; i < mElementCount; ++i)
{
- mData.erase(data);
- notifyRemoval(data);
- llwarns << "FOUND!" << llendl;
- checkAlive();
- return;
+ if (mData[i] == data)
+ { //we have data
+ _remove(data, i);
+ LL_WARNS() << "FOUND!" << LL_ENDL;
+ return;
+ }
}
for (U32 i = 0; i < getChildCount(); i++)
@@ -441,7 +515,10 @@ public:
void clearChildren()
{
- mChild.clear();
+ mChildCount = 0;
+
+ U32* foo = (U32*) mChildMap;
+ foo[0] = foo[1] = 0xFFFFFFFF;
}
void validate()
@@ -452,7 +529,7 @@ public:
mChild[i]->validate();
if (mChild[i]->getParent() != this)
{
- llerrs << "Octree child has invalid parent." << llendl;
+ LL_ERRS() << "Octree child has invalid parent." << LL_ENDL;
}
}
#endif
@@ -475,25 +552,34 @@ public:
void addChild(oct_node* child, BOOL silent = FALSE)
{
#if LL_OCTREE_PARANOIA_CHECK
+
+ if (child->getSize().equals3(getSize()))
+ {
+ OCT_ERRS << "Child size is same as parent size!" << LL_ENDL;
+ }
+
for (U32 i = 0; i < getChildCount(); i++)
{
- if(mChild[i]->getSize() != child->getSize())
+ if(!mChild[i]->getSize().equals3(child->getSize()))
{
- OCT_ERRS <<"Invalid octree child size." << llendl;
+ OCT_ERRS <<"Invalid octree child size." << LL_ENDL;
}
- if (mChild[i]->getCenter() == child->getCenter())
+ if (mChild[i]->getCenter().equals3(child->getCenter()))
{
- OCT_ERRS <<"Duplicate octree child position." << llendl;
+ OCT_ERRS <<"Duplicate octree child position." << LL_ENDL;
}
}
if (mChild.size() >= 8)
{
- OCT_ERRS <<"Octree node has too many children... why?" << llendl;
+ OCT_ERRS <<"Octree node has too many children... why?" << LL_ENDL;
}
#endif
- mChild.push_back(child);
+ mChildMap[child->getOctant()] = mChildCount;
+
+ mChild[mChildCount] = child;
+ ++mChildCount;
child->setParent(this);
if (!silent)
@@ -506,20 +592,33 @@ public:
}
}
- void removeChild(U8 index, BOOL destroy = FALSE)
+ void removeChild(S32 index, BOOL destroy = FALSE)
{
for (U32 i = 0; i < this->getListenerCount(); i++)
{
oct_listener* listener = getOctListener(i);
listener->handleChildRemoval(this, getChild(index));
}
-
+
if (destroy)
{
mChild[index]->destroy();
delete mChild[index];
}
- mChild.erase(mChild.begin() + index);
+
+ --mChildCount;
+
+ mChild[index] = mChild[mChildCount];
+
+
+ //rebuild child map
+ U32* foo = (U32*) mChildMap;
+ foo[0] = foo[1] = 0xFFFFFFFF;
+
+ for (U32 i = 0; i < mChildCount; ++i)
+ {
+ mChildMap[mChild[i]->getOctant()] = i;
+ }
checkAlive();
}
@@ -547,19 +646,35 @@ public:
}
}
- //OCT_ERRS << "Octree failed to delete requested child." << llendl;
+ OCT_ERRS << "Octree failed to delete requested child." << LL_ENDL;
}
protected:
- child_list mChild;
- element_list mData;
+ typedef enum
+ {
+ CENTER = 0,
+ SIZE = 1,
+ MAX = 2,
+ MIN = 3
+ } eDName;
+
+ LLVector4a mCenter;
+ LLVector4a mSize;
+ LLVector4a mMax;
+ LLVector4a mMin;
+
oct_node* mParent;
- LLVector3d mCenter;
- LLVector3d mSize;
- LLVector3d mMax;
- LLVector3d mMin;
U8 mOctant;
-};
+
+ LLOctreeNode<T>* mChild[8];
+ U8 mChildMap[8];
+ U32 mChildCount;
+
+ element_list mData;
+ element_iter mDataEnd;
+ U32 mElementCount;
+
+};
//just like a regular node, except it might expand on insert and compress on balance
template <class T>
@@ -569,9 +684,9 @@ public:
typedef LLOctreeNode<T> BaseType;
typedef LLOctreeNode<T> oct_node;
- LLOctreeRoot( LLVector3d center,
- LLVector3d size,
- BaseType* parent)
+ LLOctreeRoot(const LLVector4a& center,
+ const LLVector4a& size,
+ BaseType* parent)
: BaseType(center, size, parent)
{
}
@@ -596,12 +711,14 @@ public:
//(don't notify listeners of addition)
for (U32 i = 0; i < child->getChildCount(); i++)
{
- addChild(child->getChild(i), TRUE);
+ this->addChild(child->getChild(i), TRUE);
}
//destroy child
child->clearChildren();
delete child;
+
+ return false;
}
return true;
@@ -612,31 +729,36 @@ public:
{
if (data == NULL)
{
- //OCT_ERRS << "!!! INVALID ELEMENT ADDED TO OCTREE ROOT !!!" << llendl;
+ OCT_ERRS << "!!! INVALID ELEMENT ADDED TO OCTREE ROOT !!!" << LL_ENDL;
return false;
}
if (data->getBinRadius() > 4096.0)
{
- //OCT_ERRS << "!!! ELEMENT EXCEEDS MAXIMUM SIZE IN OCTREE ROOT !!!" << llendl;
+ OCT_ERRS << "!!! ELEMENT EXCEEDS MAXIMUM SIZE IN OCTREE ROOT !!!" << LL_ENDL;
return false;
}
- const F64 MAX_MAG = 1024.0*1024.0;
+ LLVector4a MAX_MAG;
+ MAX_MAG.splat(1024.f*1024.f);
- const LLVector3d& v = data->getPositionGroup();
- if (!(fabs(v.mdV[0]-this->mCenter.mdV[0]) < MAX_MAG &&
- fabs(v.mdV[1]-this->mCenter.mdV[1]) < MAX_MAG &&
- fabs(v.mdV[2]-this->mCenter.mdV[2]) < MAX_MAG))
+ const LLVector4a& v = data->getPositionGroup();
+
+ LLVector4a val;
+ val.setSub(v, BaseType::mCenter);
+ val.setAbs(val);
+ S32 lt = val.lessThan(MAX_MAG).getGatheredBits() & 0x7;
+
+ if (lt != 0x7)
{
- //OCT_ERRS << "!!! ELEMENT EXCEEDS RANGE OF SPATIAL PARTITION !!!" << llendl;
+ //OCT_ERRS << "!!! ELEMENT EXCEEDS RANGE OF SPATIAL PARTITION !!!" << LL_ENDL;
return false;
}
- if (this->getSize().mdV[0] > data->getBinRadius() && isInside(data->getPositionGroup()))
+ if (this->getSize()[0] > data->getBinRadius() && this->isInside(data->getPositionGroup()))
{
//we got it, just act like a branch
- oct_node* node = getNodeAt(data);
+ oct_node* node = this->getNodeAt(data);
if (node == this)
{
LLOctreeNode<T>::insert(data);
@@ -649,33 +771,38 @@ public:
else if (this->getChildCount() == 0)
{
//first object being added, just wrap it up
- while (!(this->getSize().mdV[0] > data->getBinRadius() && isInside(data->getPositionGroup())))
+ while (!(this->getSize()[0] > data->getBinRadius() && this->isInside(data->getPositionGroup())))
{
- LLVector3d center, size;
+ LLVector4a center, size;
center = this->getCenter();
size = this->getSize();
LLOctreeNode<T>::pushCenter(center, size, data);
this->setCenter(center);
- this->setSize(size*2);
+ size.mul(2.f);
+ this->setSize(size);
this->updateMinMax();
}
LLOctreeNode<T>::insert(data);
}
else
{
- while (!(this->getSize().mdV[0] > data->getBinRadius() && isInside(data->getPositionGroup())))
+ while (!(this->getSize()[0] > data->getBinRadius() && this->isInside(data->getPositionGroup())))
{
//the data is outside the root node, we need to grow
- LLVector3d center(this->getCenter());
- LLVector3d size(this->getSize());
+ LLVector4a center(this->getCenter());
+ LLVector4a size(this->getSize());
//expand this node
- LLVector3d newcenter(center);
+ LLVector4a newcenter(center);
LLOctreeNode<T>::pushCenter(newcenter, size, data);
this->setCenter(newcenter);
- this->setSize(size*2);
+ LLVector4a size2 = size;
+ size2.mul(2.f);
+ this->setSize(size2);
this->updateMinMax();
+ llassert(size[0] >= gOctreeMinSize);
+
//copy our children to a new branch
LLOctreeNode<T>* newnode = new LLOctreeNode<T>(center, size, this);
@@ -687,7 +814,7 @@ public:
//clear our children and add the root copy
this->clearChildren();
- addChild(newnode);
+ this->addChild(newnode);
}
//insert the data
@@ -710,4 +837,15 @@ void LLOctreeTraveler<T>::traverse(const LLOctreeNode<T>* node)
traverse(node->getChild(i));
}
}
+
+template <class T>
+void LLOctreeTravelerDepthFirst<T>::traverse(const LLOctreeNode<T>* node)
+{
+ for (U32 i = 0; i < node->getChildCount(); i++)
+ {
+ traverse(node->getChild(i));
+ }
+ node->accept(this);
+}
+
#endif