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