You cannot select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
openmw/components/terrain/quadtreenode.cpp

150 lines
4.2 KiB
C++

#include "quadtreenode.hpp"
#include <cassert>
#include <osgUtil/CullVisitor>
#include "defs.hpp"
#include "viewdata.hpp"
namespace Terrain
{
float distance(const osg::BoundingBox& box, const osg::Vec3f& v)
{
if (box.contains(v))
return 0;
else
{
osg::Vec3f maxDist(0, 0, 0);
if (v.x() < box.xMin())
maxDist.x() = box.xMin() - v.x();
else if (v.x() > box.xMax())
maxDist.x() = v.x() - box.xMax();
if (v.y() < box.yMin())
maxDist.y() = box.yMin() - v.y();
else if (v.y() > box.yMax())
maxDist.y() = v.y() - box.yMax();
if (v.z() < box.zMin())
maxDist.z() = box.zMin() - v.z();
else if (v.z() > box.zMax())
maxDist.z() = v.z() - box.zMax();
return maxDist.length();
}
}
ChildDirection reflect(ChildDirection dir, Direction dir2)
{
assert(dir != Root);
const int lookupTable[4][4] = {
// NW NE SW SE
{ SW, SE, NW, NE }, // N
{ NE, NW, SE, SW }, // E
{ SW, SE, NW, NE }, // S
{ NE, NW, SE, SW } // W
};
return (ChildDirection)lookupTable[dir2][dir];
}
bool adjacent(ChildDirection dir, Direction dir2)
{
assert(dir != Root);
const bool lookupTable[4][4] = {
// NW NE SW SE
{ true, true, false, false }, // N
{ false, true, false, true }, // E
{ false, false, true, true }, // S
{ true, false, true, false } // W
};
return lookupTable[dir2][dir];
}
QuadTreeNode* searchNeighbour(QuadTreeNode* currentNode, Direction dir)
{
if (currentNode->getDirection() == Root)
return nullptr; // Arrived at root node, the root node does not have neighbours
QuadTreeNode* nextNode;
if (adjacent(currentNode->getDirection(), dir))
nextNode = searchNeighbour(currentNode->getParent(), dir);
else
nextNode = currentNode->getParent();
if (nextNode && nextNode->getNumChildren())
return nextNode->getChild(reflect(currentNode->getDirection(), dir));
else
return nullptr;
}
QuadTreeNode::QuadTreeNode(QuadTreeNode* parent, ChildDirection direction, float size, const osg::Vec2f& center)
: mParent(parent)
, mDirection(direction)
, mValidBounds(false)
, mSize(size)
, mCenter(center)
{
for (unsigned int i = 0; i < 4; ++i)
mNeighbours[i] = nullptr;
}
QuadTreeNode::~QuadTreeNode() {}
QuadTreeNode* QuadTreeNode::getNeighbour(Direction dir)
{
return mNeighbours[dir];
}
float QuadTreeNode::distance(const osg::Vec3f& v) const
{
const osg::BoundingBox& box = getBoundingBox();
return Terrain::distance(box, v);
}
void QuadTreeNode::initNeighbours()
{
for (int i = 0; i < 4; ++i)
mNeighbours[i] = searchNeighbour(this, (Direction)i);
for (unsigned int i = 0; i < getNumChildren(); ++i)
getChild(i)->initNeighbours();
}
void QuadTreeNode::traverseNodes(ViewData* vd, const osg::Vec3f& viewPoint, LodCallback* lodCallback)
{
if (!hasValidBounds())
return;
LodCallback::ReturnValue lodResult = lodCallback->isSufficientDetail(this, distance(viewPoint));
if (lodResult == LodCallback::StopTraversal)
return;
else if (lodResult == LodCallback::Deeper && getNumChildren())
{
for (unsigned int i = 0; i < getNumChildren(); ++i)
getChild(i)->traverseNodes(vd, viewPoint, lodCallback);
}
else
vd->add(this);
}
void QuadTreeNode::setBoundingBox(const osg::BoundingBox& boundingBox)
{
mBoundingBox = boundingBox;
mValidBounds = boundingBox.valid();
}
const osg::BoundingBox& QuadTreeNode::getBoundingBox() const
{
return mBoundingBox;
}
float QuadTreeNode::getSize() const
{
return mSize;
}
const osg::Vec2f& QuadTreeNode::getCenter() const
{
return mCenter;
}
}