From 4baa795152688dfc9a4b8bb9e26f7c7bb4dc28ec Mon Sep 17 00:00:00 2001 From: scrawl Date: Thu, 9 Mar 2017 04:17:25 +0100 Subject: [PATCH] Add preloading implementation to QuadTreeWorld --- components/terrain/quadtreenode.cpp | 2 +- components/terrain/quadtreenode.hpp | 2 +- components/terrain/quadtreeworld.cpp | 41 +++++++++++++++++++++++----- components/terrain/quadtreeworld.hpp | 4 +++ components/terrain/viewdata.cpp | 12 ++++++++ components/terrain/viewdata.hpp | 7 ++++- components/terrain/world.hpp | 24 ++++++++++++++++ 7 files changed, 82 insertions(+), 10 deletions(-) diff --git a/components/terrain/quadtreenode.cpp b/components/terrain/quadtreenode.cpp index caf967e224..3f61e8b760 100644 --- a/components/terrain/quadtreenode.cpp +++ b/components/terrain/quadtreenode.cpp @@ -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); diff --git a/components/terrain/quadtreenode.hpp b/components/terrain/quadtreenode.hpp index ca0ee97c42..30e998119f 100644 --- a/components/terrain/quadtreenode.hpp +++ b/components/terrain/quadtreenode.hpp @@ -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; diff --git a/components/terrain/quadtreeworld.cpp b/components/terrain/quadtreeworld.cpp index 6d8e384003..cb49f33920 100644 --- a/components/terrain/quadtreeworld.cpp +++ b/components/terrain/quadtreeworld.cpp @@ -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(node->getSize()*4)); int lodLevel = Log2(static_cast(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(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; igetNumChildren(); ++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(&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(view)); +} + +void QuadTreeWorld::preload(View *view, const osg::Vec3f &eyePoint) +{ + ensureQuadTreeBuilt(); + + ViewData* vd = static_cast(view); + traverse(mRootNode.get(), vd, NULL, eyePoint, false); + + for (unsigned int i=0; igetNumEntries(); ++i) + { + ViewData::Entry& entry = vd->getEntry(i); + loadRenderingNode(entry, vd, mChunkManager.get()); + } +} } diff --git a/components/terrain/quadtreeworld.hpp b/components/terrain/quadtreeworld.hpp index 5838bcaa94..edd9779d69 100644 --- a/components/terrain/quadtreeworld.hpp +++ b/components/terrain/quadtreeworld.hpp @@ -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(); diff --git a/components/terrain/viewdata.cpp b/components/terrain/viewdata.cpp index bd7e0b819d..1e7245a15c 100644 --- a/components/terrain/viewdata.cpp +++ b/components/terrain/viewdata.cpp @@ -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(); ) diff --git a/components/terrain/viewdata.hpp b/components/terrain/viewdata.hpp index 49b3722c87..c06e1dfff3 100644 --- a/components/terrain/viewdata.hpp +++ b/components/terrain/viewdata.hpp @@ -6,15 +6,18 @@ #include +#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); diff --git a/components/terrain/world.hpp b/components/terrain/world.hpp index 7abc9a4caf..6cba6c5b63 100644 --- a/components/terrain/world.hpp +++ b/components/terrain/world.hpp @@ -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: