mirror of
https://github.com/OpenMW/openmw.git
synced 2025-01-16 17:29:55 +00:00
Add preloading implementation to QuadTreeWorld
This commit is contained in:
parent
9db71e3f62
commit
4baa795152
7 changed files with 82 additions and 10 deletions
|
@ -108,7 +108,7 @@ void QuadTreeNode::traverse(osg::NodeVisitor &nv)
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
if ((mLodCallback && mLodCallback->isSufficientDetail(this, nv)) || !getNumChildren())
|
if ((mLodCallback && mLodCallback->isSufficientDetail(this, nv.getEyePoint())) || !getNumChildren())
|
||||||
getView(nv)->add(this, true);
|
getView(nv)->add(this, true);
|
||||||
else
|
else
|
||||||
osg::Group::traverse(nv);
|
osg::Group::traverse(nv);
|
||||||
|
|
|
@ -23,7 +23,7 @@ namespace Terrain
|
||||||
public:
|
public:
|
||||||
virtual ~LodCallback() {}
|
virtual ~LodCallback() {}
|
||||||
|
|
||||||
virtual bool isSufficientDetail(QuadTreeNode *node, osg::NodeVisitor &nv) = 0;
|
virtual bool isSufficientDetail(QuadTreeNode *node, const osg::Vec3f& eyePoint) = 0;
|
||||||
};
|
};
|
||||||
|
|
||||||
class ViewDataMap;
|
class ViewDataMap;
|
||||||
|
|
|
@ -70,9 +70,9 @@ namespace Terrain
|
||||||
class DefaultLodCallback : public LodCallback
|
class DefaultLodCallback : public LodCallback
|
||||||
{
|
{
|
||||||
public:
|
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 nativeLodLevel = Log2(static_cast<unsigned int>(node->getSize()*4));
|
||||||
int lodLevel = Log2(static_cast<unsigned int>(dist/2048.0));
|
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())
|
if (!node->hasValidBounds())
|
||||||
return;
|
return;
|
||||||
|
|
||||||
visible = visible && !cv->isCulled(node->getBoundingBox());
|
if (nv && nv->getVisitorType() == osg::NodeVisitor::CULL_VISITOR)
|
||||||
bool stopTraversal = (node->getLodCallback() && node->getLodCallback()->isSufficientDetail(node, *cv)) || !node->getNumChildren();
|
visible = visible && !static_cast<osgUtil::CullVisitor*>(nv)->isCulled(node->getBoundingBox());
|
||||||
|
|
||||||
|
bool stopTraversal = (node->getLodCallback() && node->getLodCallback()->isSufficientDetail(node, eyePoint)) || !node->getNumChildren();
|
||||||
|
|
||||||
if (stopTraversal)
|
if (stopTraversal)
|
||||||
vd->add(node, visible);
|
vd->add(node, visible);
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
for (unsigned int i=0; i<node->getNumChildren(); ++i)
|
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)
|
if (nv.getVisitorType() == osg::NodeVisitor::CULL_VISITOR)
|
||||||
{
|
{
|
||||||
osgUtil::CullVisitor* cv = static_cast<osgUtil::CullVisitor*>(&nv);
|
osgUtil::CullVisitor* cv = static_cast<osgUtil::CullVisitor*>(&nv);
|
||||||
traverse(mRootNode.get(), vd, cv, true);
|
traverse(mRootNode.get(), vd, cv, cv->getEyePoint(), true);
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
mRootNode->traverse(nv);
|
mRootNode->traverse(nv);
|
||||||
|
@ -374,6 +376,31 @@ void QuadTreeWorld::enable(bool enabled)
|
||||||
mRootNode->setNodeMask(enabled ? ~0 : 0);
|
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);
|
virtual void enable(bool enabled);
|
||||||
|
|
||||||
|
View* createView();
|
||||||
|
void removeView(View* view);
|
||||||
|
void preload(View* view, const osg::Vec3f& eyePoint);
|
||||||
|
|
||||||
private:
|
private:
|
||||||
void ensureQuadTreeBuilt();
|
void ensureQuadTreeBuilt();
|
||||||
|
|
||||||
|
|
|
@ -12,6 +12,11 @@ ViewData::ViewData()
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
ViewData::~ViewData()
|
||||||
|
{
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
void ViewData::add(QuadTreeNode *node, bool visible)
|
void ViewData::add(QuadTreeNode *node, bool visible)
|
||||||
{
|
{
|
||||||
unsigned int index = mNumEntries++;
|
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)
|
void ViewDataMap::clearUnusedViews(unsigned int frame)
|
||||||
{
|
{
|
||||||
for (Map::iterator it = mViews.begin(); it != mViews.end(); )
|
for (Map::iterator it = mViews.begin(); it != mViews.end(); )
|
||||||
|
|
|
@ -6,15 +6,18 @@
|
||||||
|
|
||||||
#include <osg/Node>
|
#include <osg/Node>
|
||||||
|
|
||||||
|
#include "world.hpp"
|
||||||
|
|
||||||
namespace Terrain
|
namespace Terrain
|
||||||
{
|
{
|
||||||
|
|
||||||
class QuadTreeNode;
|
class QuadTreeNode;
|
||||||
|
|
||||||
class ViewData
|
class ViewData : public View
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
ViewData();
|
ViewData();
|
||||||
|
~ViewData();
|
||||||
|
|
||||||
void add(QuadTreeNode* node, bool visible);
|
void add(QuadTreeNode* node, bool visible);
|
||||||
|
|
||||||
|
@ -42,6 +45,7 @@ namespace Terrain
|
||||||
Entry& getEntry(unsigned int i);
|
Entry& getEntry(unsigned int i);
|
||||||
|
|
||||||
bool getPersistent() const { return mPersistent; }
|
bool getPersistent() const { return mPersistent; }
|
||||||
|
void setPersistent(bool persistent) { mPersistent = persistent; }
|
||||||
|
|
||||||
osg::Object* getViewer() const { return mViewer.get(); }
|
osg::Object* getViewer() const { return mViewer.get(); }
|
||||||
void setViewer(osg::Object* viewer) { mViewer = viewer; }
|
void setViewer(osg::Object* viewer) { mViewer = viewer; }
|
||||||
|
@ -66,6 +70,7 @@ namespace Terrain
|
||||||
ViewData* getViewData(osg::Object* viewer, bool ref);
|
ViewData* getViewData(osg::Object* viewer, bool ref);
|
||||||
|
|
||||||
ViewData* createOrReuseView();
|
ViewData* createOrReuseView();
|
||||||
|
void removeView(ViewData* view);
|
||||||
|
|
||||||
void clearUnusedViews(unsigned int frame);
|
void clearUnusedViews(unsigned int frame);
|
||||||
|
|
||||||
|
|
|
@ -28,6 +28,19 @@ namespace Terrain
|
||||||
class ChunkManager;
|
class ChunkManager;
|
||||||
class CompositeMapRenderer;
|
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
|
* @brief The basic interface for a terrain world. How the terrain chunks are paged and displayed
|
||||||
* is up to the implementation.
|
* is up to the implementation.
|
||||||
|
@ -66,6 +79,17 @@ namespace Terrain
|
||||||
|
|
||||||
virtual void enable(bool enabled) {}
|
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; }
|
Storage* getStorage() { return mStorage; }
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
|
|
Loading…
Reference in a new issue