Add preloading implementation to QuadTreeWorld

pull/185/head
scrawl 7 years ago
parent 9db71e3f62
commit 4baa795152

@ -108,7 +108,7 @@ void QuadTreeNode::traverse(osg::NodeVisitor &nv)
return;
}
if ((mLodCallback && mLodCallback->isSufficientDetail(this, nv)) || !getNumChildren())
if ((mLodCallback && mLodCallback->isSufficientDetail(this, nv.getEyePoint())) || !getNumChildren())
getView(nv)->add(this, true);
else
osg::Group::traverse(nv);

@ -23,7 +23,7 @@ namespace Terrain
public:
virtual ~LodCallback() {}
virtual bool isSufficientDetail(QuadTreeNode *node, osg::NodeVisitor &nv) = 0;
virtual bool isSufficientDetail(QuadTreeNode *node, const osg::Vec3f& eyePoint) = 0;
};
class ViewDataMap;

@ -70,9 +70,9 @@ namespace Terrain
class DefaultLodCallback : public LodCallback
{
public:
virtual bool isSufficientDetail(QuadTreeNode* node, osg::NodeVisitor& nv)
virtual bool isSufficientDetail(QuadTreeNode* node, const osg::Vec3f& eyePoint)
{
float dist = distance(node->getBoundingBox(), nv.getEyePoint());
float dist = distance(node->getBoundingBox(), eyePoint);
int nativeLodLevel = Log2(static_cast<unsigned int>(node->getSize()*4));
int lodLevel = Log2(static_cast<unsigned int>(dist/2048.0));
@ -238,20 +238,22 @@ QuadTreeWorld::~QuadTreeWorld()
}
void traverse(QuadTreeNode* node, ViewData* vd, osgUtil::CullVisitor* cv, bool visible)
void traverse(QuadTreeNode* node, ViewData* vd, osg::NodeVisitor* nv, const osg::Vec3f& eyePoint, bool visible)
{
if (!node->hasValidBounds())
return;
visible = visible && !cv->isCulled(node->getBoundingBox());
bool stopTraversal = (node->getLodCallback() && node->getLodCallback()->isSufficientDetail(node, *cv)) || !node->getNumChildren();
if (nv && nv->getVisitorType() == osg::NodeVisitor::CULL_VISITOR)
visible = visible && !static_cast<osgUtil::CullVisitor*>(nv)->isCulled(node->getBoundingBox());
bool stopTraversal = (node->getLodCallback() && node->getLodCallback()->isSufficientDetail(node, eyePoint)) || !node->getNumChildren();
if (stopTraversal)
vd->add(node, visible);
else
{
for (unsigned int i=0; i<node->getNumChildren(); ++i)
traverse(node->getChild(i), vd, cv, visible);
traverse(node->getChild(i), vd, nv, eyePoint, visible);
}
}
@ -313,7 +315,7 @@ void QuadTreeWorld::accept(osg::NodeVisitor &nv)
if (nv.getVisitorType() == osg::NodeVisitor::CULL_VISITOR)
{
osgUtil::CullVisitor* cv = static_cast<osgUtil::CullVisitor*>(&nv);
traverse(mRootNode.get(), vd, cv, true);
traverse(mRootNode.get(), vd, cv, cv->getEyePoint(), true);
}
else
mRootNode->traverse(nv);
@ -374,6 +376,31 @@ void QuadTreeWorld::enable(bool enabled)
mRootNode->setNodeMask(enabled ? ~0 : 0);
}
View* QuadTreeWorld::createView()
{
ViewData* vd = mViewDataMap->createOrReuseView();
vd->setPersistent(true);
return vd;
}
void QuadTreeWorld::removeView(View *view)
{
mViewDataMap->removeView(static_cast<ViewData*>(view));
}
void QuadTreeWorld::preload(View *view, const osg::Vec3f &eyePoint)
{
ensureQuadTreeBuilt();
ViewData* vd = static_cast<ViewData*>(view);
traverse(mRootNode.get(), vd, NULL, eyePoint, false);
for (unsigned int i=0; i<vd->getNumEntries(); ++i)
{
ViewData::Entry& entry = vd->getEntry(i);
loadRenderingNode(entry, vd, mChunkManager.get());
}
}
}

@ -28,6 +28,10 @@ namespace Terrain
virtual void enable(bool enabled);
View* createView();
void removeView(View* view);
void preload(View* view, const osg::Vec3f& eyePoint);
private:
void ensureQuadTreeBuilt();

@ -12,6 +12,11 @@ ViewData::ViewData()
}
ViewData::~ViewData()
{
}
void ViewData::add(QuadTreeNode *node, bool visible)
{
unsigned int index = mNumEntries++;
@ -121,6 +126,13 @@ ViewData *ViewDataMap::createOrReuseView()
}
}
void ViewDataMap::removeView(ViewData* vd)
{
vd->setPersistent(false);
vd->clear();
mUnusedViews.push_back(vd);
}
void ViewDataMap::clearUnusedViews(unsigned int frame)
{
for (Map::iterator it = mViews.begin(); it != mViews.end(); )

@ -6,15 +6,18 @@
#include <osg/Node>
#include "world.hpp"
namespace Terrain
{
class QuadTreeNode;
class ViewData
class ViewData : public View
{
public:
ViewData();
~ViewData();
void add(QuadTreeNode* node, bool visible);
@ -42,6 +45,7 @@ namespace Terrain
Entry& getEntry(unsigned int i);
bool getPersistent() const { return mPersistent; }
void setPersistent(bool persistent) { mPersistent = persistent; }
osg::Object* getViewer() const { return mViewer.get(); }
void setViewer(osg::Object* viewer) { mViewer = viewer; }
@ -66,6 +70,7 @@ namespace Terrain
ViewData* getViewData(osg::Object* viewer, bool ref);
ViewData* createOrReuseView();
void removeView(ViewData* view);
void clearUnusedViews(unsigned int frame);

@ -28,6 +28,19 @@ namespace Terrain
class ChunkManager;
class CompositeMapRenderer;
/**
* @brief A View is a collection of rendering objects that are visible from a given camera/intersection.
* The base View class is part of the interface for usage in conjunction with preload feature.
*/
class View
{
public:
virtual ~View() {}
/// Reset internal structure so that the next addition to the view will override the previous frame's contents.
virtual void reset(unsigned int frame) = 0;
};
/**
* @brief The basic interface for a terrain world. How the terrain chunks are paged and displayed
* is up to the implementation.
@ -66,6 +79,17 @@ namespace Terrain
virtual void enable(bool enabled) {}
/// Create a View to use with preload feature. If a View is returned, it will remain valid until the user calls 'removeView' or the World is destroyed.
/// @note Not thread safe.
virtual View* createView() { return NULL; }
/// Remove a View that was previously created with 'createView'.
/// @note Not thread safe.
virtual void removeView(View* view) {}
/// @note Thread safe, as long as you do not attempt to load into the same view from multiple threads.
virtual void preload(View* view, const osg::Vec3f& eyePoint) {}
Storage* getStorage() { return mStorage; }
protected:

Loading…
Cancel
Save