1 #include "viewdata.hpp"
2 
3 #include "quadtreenode.hpp"
4 
5 namespace Terrain
6 {
7 
ViewData()8 ViewData::ViewData()
9     : mNumEntries(0)
10     , mLastUsageTimeStamp(0.0)
11     , mChanged(false)
12     , mHasViewPoint(false)
13     , mWorldUpdateRevision(0)
14 {
15 
16 }
17 
~ViewData()18 ViewData::~ViewData()
19 {
20 
21 }
22 
copyFrom(const ViewData & other)23 void ViewData::copyFrom(const ViewData& other)
24 {
25     mNumEntries = other.mNumEntries;
26     mEntries = other.mEntries;
27     mChanged = other.mChanged;
28     mHasViewPoint = other.mHasViewPoint;
29     mViewPoint = other.mViewPoint;
30     mActiveGrid = other.mActiveGrid;
31     mWorldUpdateRevision = other.mWorldUpdateRevision;
32 }
33 
add(QuadTreeNode * node)34 void ViewData::add(QuadTreeNode *node)
35 {
36     unsigned int index = mNumEntries++;
37 
38     if (index+1 > mEntries.size())
39         mEntries.resize(index+1);
40 
41     Entry& entry = mEntries[index];
42     if (entry.set(node))
43         mChanged = true;
44 }
45 
getNumEntries() const46 unsigned int ViewData::getNumEntries() const
47 {
48     return mNumEntries;
49 }
50 
getEntry(unsigned int i)51 ViewData::Entry &ViewData::getEntry(unsigned int i)
52 {
53     return mEntries[i];
54 }
55 
hasChanged() const56 bool ViewData::hasChanged() const
57 {
58     return mChanged;
59 }
60 
hasViewPoint() const61 bool ViewData::hasViewPoint() const
62 {
63     return mHasViewPoint;
64 }
65 
setViewPoint(const osg::Vec3f & viewPoint)66 void ViewData::setViewPoint(const osg::Vec3f &viewPoint)
67 {
68     mViewPoint = viewPoint;
69     mHasViewPoint = true;
70 }
71 
getViewPoint() const72 const osg::Vec3f& ViewData::getViewPoint() const
73 {
74     return mViewPoint;
75 }
76 
reset()77 void ViewData::reset()
78 {
79     // clear any unused entries
80     for (unsigned int i=mNumEntries; i<mEntries.size(); ++i)
81         mEntries[i].set(nullptr);
82 
83     // reset index for next frame
84     mNumEntries = 0;
85     mChanged = false;
86 }
87 
clear()88 void ViewData::clear()
89 {
90     for (unsigned int i=0; i<mEntries.size(); ++i)
91         mEntries[i].set(nullptr);
92     mNumEntries = 0;
93     mLastUsageTimeStamp = 0;
94     mChanged = false;
95     mHasViewPoint = false;
96 }
97 
suitableToUse(const osg::Vec4i & activeGrid) const98 bool ViewData::suitableToUse(const osg::Vec4i &activeGrid) const
99 {
100     return hasViewPoint() && activeGrid == mActiveGrid && getNumEntries();
101 }
102 
contains(QuadTreeNode * node) const103 bool ViewData::contains(QuadTreeNode *node) const
104 {
105     for (unsigned int i=0; i<mNumEntries; ++i)
106         if (mEntries[i].mNode == node)
107             return true;
108     return false;
109 }
110 
Entry()111 ViewData::Entry::Entry()
112     : mNode(nullptr)
113     , mLodFlags(0)
114 {
115 
116 }
117 
set(QuadTreeNode * node)118 bool ViewData::Entry::set(QuadTreeNode *node)
119 {
120     if (node == mNode)
121         return false;
122     else
123     {
124         mNode = node;
125         // clear cached data
126         mRenderingNode = nullptr;
127         return true;
128     }
129 }
130 
getViewData(osg::Object * viewer,const osg::Vec3f & viewPoint,const osg::Vec4i & activeGrid,bool & needsUpdate)131 ViewData *ViewDataMap::getViewData(osg::Object *viewer, const osg::Vec3f& viewPoint, const osg::Vec4i &activeGrid, bool& needsUpdate)
132 {
133     ViewerMap::const_iterator found = mViewers.find(viewer);
134     ViewData* vd = nullptr;
135     if (found == mViewers.end())
136     {
137         vd = createOrReuseView();
138         mViewers[viewer] = vd;
139     }
140     else
141         vd = found->second;
142     needsUpdate = false;
143 
144     if (!vd->suitableToUse(activeGrid) || (vd->getViewPoint()-viewPoint).length2() >= mReuseDistance*mReuseDistance || vd->getWorldUpdateRevision() < mWorldUpdateRevision)
145     {
146         float shortestDist = viewer ? mReuseDistance*mReuseDistance : std::numeric_limits<float>::max();
147         const ViewData* mostSuitableView = nullptr;
148         for (const ViewData* other : mUsedViews)
149         {
150             if (other->suitableToUse(activeGrid) && other->getWorldUpdateRevision() >= mWorldUpdateRevision)
151             {
152                 float dist = (viewPoint-other->getViewPoint()).length2();
153                 if (dist < shortestDist)
154                 {
155                     shortestDist = dist;
156                     mostSuitableView = other;
157                 }
158             }
159         }
160         if (mostSuitableView && mostSuitableView != vd)
161         {
162             vd->copyFrom(*mostSuitableView);
163             return vd;
164         }
165         else if (!mostSuitableView)
166         {
167             vd->setViewPoint(viewPoint);
168             needsUpdate = true;
169         }
170     }
171     if (!vd->suitableToUse(activeGrid))
172     {
173         vd->setViewPoint(viewPoint);
174         vd->setActiveGrid(activeGrid);
175         needsUpdate = true;
176     }
177     return vd;
178 }
179 
storeView(const ViewData * view,double referenceTime)180 bool ViewDataMap::storeView(const ViewData* view, double referenceTime)
181 {
182     if (view->getWorldUpdateRevision() < mWorldUpdateRevision)
183         return false;
184     ViewData* store = createOrReuseView();
185     store->copyFrom(*view);
186     store->setLastUsageTimeStamp(referenceTime);
187     return true;
188 }
189 
createOrReuseView()190 ViewData *ViewDataMap::createOrReuseView()
191 {
192     ViewData* vd = nullptr;
193     if (mUnusedViews.size())
194     {
195         vd = mUnusedViews.front();
196         mUnusedViews.pop_front();
197     }
198     else
199     {
200         mViewVector.emplace_back();
201         vd = &mViewVector.back();
202     }
203     mUsedViews.push_back(vd);
204     vd->setWorldUpdateRevision(mWorldUpdateRevision);
205     return vd;
206 }
207 
createIndependentView() const208 ViewData *ViewDataMap::createIndependentView() const
209 {
210     ViewData* vd = new ViewData;
211     vd->setWorldUpdateRevision(mWorldUpdateRevision);
212     return vd;
213 }
214 
clearUnusedViews(double referenceTime)215 void ViewDataMap::clearUnusedViews(double referenceTime)
216 {
217     for (ViewerMap::iterator it = mViewers.begin(); it != mViewers.end(); )
218     {
219         if (it->second->getLastUsageTimeStamp() + mExpiryDelay < referenceTime)
220             mViewers.erase(it++);
221         else
222             ++it;
223     }
224     for (std::deque<ViewData*>::iterator it = mUsedViews.begin(); it != mUsedViews.end(); )
225     {
226         if ((*it)->getLastUsageTimeStamp() + mExpiryDelay < referenceTime)
227         {
228             (*it)->clear();
229             mUnusedViews.push_back(*it);
230             it = mUsedViews.erase(it);
231         }
232         else
233             ++it;
234     }
235 }
236 
rebuildViews()237 void ViewDataMap::rebuildViews()
238 {
239     ++mWorldUpdateRevision;
240 }
241 
242 }
243