167 lines
5.2 KiB
C++
Executable File
167 lines
5.2 KiB
C++
Executable File
//-----------------------------------------------------------------------------
|
|
// 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);
|
|
}
|