Initial commit
This commit is contained in:
166
Torque/SDK/engine/terrain/bvQuadTree.cc
Normal file
166
Torque/SDK/engine/terrain/bvQuadTree.cc
Normal file
@@ -0,0 +1,166 @@
|
||||
//-----------------------------------------------------------------------------
|
||||
// Torque Game Engine
|
||||
// Copyright (C) GarageGames.com, Inc.
|
||||
//-----------------------------------------------------------------------------
|
||||
|
||||
#include "terrain/bvQuadTree.h"
|
||||
#include "console/console.h"
|
||||
|
||||
BVQuadTree::BVQuadTree(BitVector *bv)
|
||||
{
|
||||
if (bv != NULL)
|
||||
init(*bv);
|
||||
else
|
||||
{
|
||||
BitVector localBV;
|
||||
localBV.setSize(4);
|
||||
localBV.set();
|
||||
init(localBV);
|
||||
}
|
||||
}
|
||||
|
||||
BVQuadTree::~BVQuadTree()
|
||||
{
|
||||
while (mQTHierarchy.size() > 0)
|
||||
{
|
||||
delete mQTHierarchy.last();
|
||||
mQTHierarchy.pop_back();
|
||||
}
|
||||
}
|
||||
|
||||
bool BVQuadTree::isSet(const Point2F &pos, S32 level) const
|
||||
{
|
||||
AssertFatal(pos.x >= 0. && pos.x <= 1., "BVQuadTree::isSet: x must be in range [0,1]");
|
||||
AssertFatal(pos.y >= 0. && pos.y <= 1., "BVQuadTree::isSet: y must be in range [0,1]");
|
||||
AssertFatal(level >= 0, "BVQuadTree:isSet: level must be greater than or equal to zero");
|
||||
|
||||
if (level >= mQTHierarchy.size())
|
||||
// force to be within resolution of QT
|
||||
level = mQTHierarchy.size() - 1;
|
||||
if (level < 0)
|
||||
level = 0;
|
||||
|
||||
F32 dimension = F32(1 << level);
|
||||
U32 offset = U32((F32(U32(pos.y * dimension)) + pos.x) * dimension);
|
||||
return(mQTHierarchy[level]->test(offset));
|
||||
}
|
||||
|
||||
bool BVQuadTree::isClear(const Point2F &pos, S32 level) const
|
||||
{
|
||||
AssertFatal(pos.x >= 0. && pos.x <= 1., "BVQuadTree::isClear: x must be in range [0,1]");
|
||||
AssertFatal(pos.y >= 0. && pos.y <= 1., "BVQuadTree::isClear: y must be in range [0,1]");
|
||||
AssertFatal(level >= 0, "BVQuadTree:isClear: level must be greater than or equal to zero");
|
||||
|
||||
if (level >= mQTHierarchy.size())
|
||||
// force to be within resolution of QT
|
||||
level = mQTHierarchy.size() - 1;
|
||||
if (level < 0)
|
||||
level = 0;
|
||||
|
||||
F32 dimension = F32(1 << level);
|
||||
U32 offset = U32((F32(U32(pos.y * dimension)) + pos.x) * dimension);
|
||||
return(mQTHierarchy[level]->test(offset) == false);
|
||||
}
|
||||
|
||||
/* Initialize the quadtree with the provided bit vector. Note that the bit vector
|
||||
* denotes data at each corner of the quadtree cell. Hence the dimension for the
|
||||
* deepest quadtree level must be 1 less than that of the bit vector.
|
||||
*/
|
||||
void BVQuadTree::init(const BitVector &bv)
|
||||
{
|
||||
while (mQTHierarchy.size() > 0)
|
||||
{
|
||||
delete mQTHierarchy.last();
|
||||
mQTHierarchy.pop_back();
|
||||
}
|
||||
|
||||
// get the width/height of the square bit vector
|
||||
U32 bvDim = (U32)mSqrt((F32)bv.getSize());
|
||||
U32 qtDim = bvDim - 1; // here's where we correct dimension...
|
||||
|
||||
AssertFatal(((mSqrt((F32)bv.getSize()) - 1) == (F32)qtDim) && (isPow2(qtDim) == true), "BVQuadTree::init: bit vector size must be power of 4");
|
||||
|
||||
// find the power of two we're starting at
|
||||
mResolution = qtDim;
|
||||
U32 level = 0;
|
||||
while ((1 << (level + 1)) <= qtDim)
|
||||
level++;
|
||||
BitVector *initBV = new BitVector;
|
||||
|
||||
AssertFatal(initBV != NULL, "BVQuadTree::init: failed to allocate highest detail bit vector");
|
||||
|
||||
initBV->setSize(qtDim * qtDim);
|
||||
initBV->clear();
|
||||
for (S32 i = 0; i < qtDim; i++)
|
||||
for (S32 j = 0; j < qtDim; j++)
|
||||
{
|
||||
S32 k = i * bvDim + j;
|
||||
if (bv.test(k) || bv.test(k + 1) || bv.test(k + bvDim) || bv.test(k + bvDim + 1))
|
||||
initBV->set(i * qtDim + j);
|
||||
}
|
||||
mQTHierarchy.push_back(initBV);
|
||||
if (level > 0)
|
||||
buildHierarchy(level - 1);
|
||||
}
|
||||
|
||||
#ifdef BV_QUADTREE_DEBUG
|
||||
void BVQuadTree::dump() const
|
||||
{
|
||||
char str[256];
|
||||
U32 strlen;
|
||||
for (U32 i = 0; i < mQTHierarchy.size(); i++)
|
||||
{
|
||||
U32 dimension = 1 << i;
|
||||
Con::printf("level %d:", i);
|
||||
for (U32 y = 0; y < dimension; y++)
|
||||
{
|
||||
U32 yOffset = y * dimension;
|
||||
str[0] = '\0';
|
||||
for (U32 x = 0; x < dimension; x++)
|
||||
{
|
||||
U32 offset = yOffset + x;
|
||||
strlen = dStrlen(str);
|
||||
if (strlen < 252)
|
||||
dSprintf(str + strlen, 256 - strlen, mQTHierarchy[i]->isSet(offset) ? "1 " : "0 ");
|
||||
else
|
||||
{
|
||||
dSprintf(str + strlen, 256 - strlen, "...");
|
||||
break;
|
||||
}
|
||||
}
|
||||
Con::printf("%s", str);
|
||||
}
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
void BVQuadTree::buildHierarchy(U32 level)
|
||||
{
|
||||
BitVector *priorBV = mQTHierarchy.first();
|
||||
BitVector *levelBV = new BitVector;
|
||||
|
||||
AssertFatal(levelBV != NULL, "BVQuadTree::buildHierarchy: failed to allocate bit vector");
|
||||
|
||||
U32 levelDim = (1 << level);
|
||||
levelBV->setSize(levelDim * levelDim);
|
||||
levelBV->clear();
|
||||
U32 yOffset, offset, yPriorOffset, priorOffset;
|
||||
// COULD THIS BE DONE WITH A SINGLE LOOP?
|
||||
for (U32 y = 0; y < levelDim; y++)
|
||||
{
|
||||
yOffset = y * levelDim;
|
||||
yPriorOffset = yOffset << 2;
|
||||
for (U32 x = 0; x < levelDim; x++)
|
||||
{
|
||||
offset = yOffset + x;
|
||||
priorOffset = yPriorOffset + (x << 1);
|
||||
if (priorBV->test(priorOffset) || priorBV->test(priorOffset + 1) ||
|
||||
priorBV->test(priorOffset + (levelDim << 1)) ||
|
||||
priorBV->test(priorOffset + (levelDim << 1) + 1))
|
||||
levelBV->set(offset);
|
||||
}
|
||||
}
|
||||
mQTHierarchy.push_front(levelBV);
|
||||
if (level > 0)
|
||||
buildHierarchy(level - 1);
|
||||
}
|
||||
Reference in New Issue
Block a user