Something went wrong. Try again.
OpenMW is an open implementation of the Morrowind engine
Something went wrong. Try again.
6.6 kB · 233 lines
C++
123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234#include "viewdata.hpp"
#include "quadtreenode.hpp"
#include <algorithm>
namespace Terrain{
ViewData::ViewData() : mNumEntries(0) , mLastUsageTimeStamp(0.0) , mChanged(false) , mHasViewPoint(false) , mWorldUpdateRevision(0) { }
ViewData::~ViewData() {}
void ViewData::copyFrom(const ViewData& other) { mNumEntries = other.mNumEntries; mEntries = other.mEntries; mChanged = other.mChanged; mHasViewPoint = other.mHasViewPoint; mViewPoint = other.mViewPoint; mActiveGrid = other.mActiveGrid; mWorldUpdateRevision = other.mWorldUpdateRevision; mNodes = other.mNodes; }
void ViewData::add(QuadTreeNode* node) { unsigned int index = mNumEntries++;
if (index + 1 > mEntries.size()) mEntries.resize(index + 1);
ViewDataEntry& entry = mEntries[index]; if (entry.set(node)) { mChanged = true; mNodes.clear(); } }
void ViewData::setViewPoint(const osg::Vec3f& viewPoint) { mViewPoint = viewPoint; mHasViewPoint = true; }
// NOTE: As a performance optimisation, we cache mRenderingNodes from previous frames here. // If this cache becomes invalid (e.g. through mWorldUpdateRevision), we need to use clear() instead of reset(). void ViewData::reset() { // clear any unused entries for (unsigned int i = mNumEntries; i < mEntries.size(); ++i) mEntries[i].set(nullptr);
// reset index for next frame mNumEntries = 0; mChanged = false; mNodes.clear(); }
void ViewData::clear() { for (unsigned int i = 0; i < mEntries.size(); ++i) mEntries[i].set(nullptr); mNumEntries = 0; mLastUsageTimeStamp = 0; mChanged = false; mHasViewPoint = false; mNodes.clear(); }
bool ViewData::suitableToUse(const osg::Vec4i& activeGrid) const { return hasViewPoint() && activeGrid == mActiveGrid && getNumEntries(); }
bool ViewData::contains(const QuadTreeNode* node) const { return std::binary_search(mNodes.begin(), mNodes.end(), node); }
void ViewData::buildNodeIndex() { if (!mNodes.empty()) return;
mNodes.reserve(mNumEntries); for (std::size_t i = 0; i < mNumEntries; ++i) if (const QuadTreeNode* node = mEntries[i].mNode) mNodes.push_back(node);
std::sort(mNodes.begin(), mNodes.end()); }
void ViewData::removeNodeFromIndex(const QuadTreeNode* node) { const auto it = std::lower_bound(mNodes.begin(), mNodes.end(), node); if (it == mNodes.end() || *it != node) return; mNodes.erase(it); }
ViewDataEntry::ViewDataEntry() : mNode(nullptr) , mLodFlags(0) { }
bool ViewDataEntry::set(QuadTreeNode* node) { if (node == mNode) return false; else { mNode = node; // clear cached data mRenderingNode = nullptr; return true; } }
ViewData* ViewDataMap::getViewData( osg::Object* viewer, const osg::Vec3f& viewPoint, const osg::Vec4i& activeGrid, bool& needsUpdate) { ViewerMap::const_iterator found = mViewers.find(viewer); ViewData* vd = nullptr; if (found == mViewers.end()) { vd = createOrReuseView(); mViewers[viewer] = vd; } else vd = found->second; needsUpdate = false;
if (!(vd->suitableToUse(activeGrid) && (vd->getViewPoint() - viewPoint).length2() < mReuseDistance * mReuseDistance && vd->getWorldUpdateRevision() >= mWorldUpdateRevision)) { float shortestDist = viewer ? mReuseDistance * mReuseDistance : std::numeric_limits<float>::max(); const ViewData* mostSuitableView = nullptr; for (const ViewData* other : mUsedViews) { if (other->suitableToUse(activeGrid) && other->getWorldUpdateRevision() >= mWorldUpdateRevision) { float dist = (viewPoint - other->getViewPoint()).length2(); if (dist < shortestDist) { shortestDist = dist; mostSuitableView = other; } } } if (mostSuitableView && mostSuitableView != vd) { vd->copyFrom(*mostSuitableView); return vd; } else if (!mostSuitableView) { if (vd->getWorldUpdateRevision() != mWorldUpdateRevision) { vd->setWorldUpdateRevision(mWorldUpdateRevision); vd->clear(); } vd->setViewPoint(viewPoint); vd->setActiveGrid(activeGrid); needsUpdate = true; } } return vd; }
ViewData* ViewDataMap::createOrReuseView() { ViewData* vd = nullptr; if (mUnusedViews.size()) { vd = mUnusedViews.front(); mUnusedViews.pop_front(); } else { mViewVector.emplace_back(); vd = &mViewVector.back(); } mUsedViews.push_back(vd); vd->setWorldUpdateRevision(mWorldUpdateRevision); return vd; }
ViewData* ViewDataMap::createIndependentView() const { ViewData* vd = new ViewData; vd->setWorldUpdateRevision(mWorldUpdateRevision); return vd; }
void ViewDataMap::clearUnusedViews(double referenceTime) { for (ViewerMap::iterator it = mViewers.begin(); it != mViewers.end();) { if (it->second->getLastUsageTimeStamp() + mExpiryDelay < referenceTime) mViewers.erase(it++); else ++it; } for (std::deque<ViewData*>::iterator it = mUsedViews.begin(); it != mUsedViews.end();) { if ((*it)->getLastUsageTimeStamp() + mExpiryDelay < referenceTime) { (*it)->clear(); mUnusedViews.push_back(*it); it = mUsedViews.erase(it); } else ++it; } }
void ViewDataMap::rebuildViews() { ++mWorldUpdateRevision; }
}