Something went wrong. Try again.
OpenMW is an open implementation of the Morrowind engine
Something went wrong. Try again.
4.3 kB · 149 lines
C++
123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150#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; }
}