root/OpenSceneGraph/trunk/src/osg/PagedLOD.cpp @ 9387

Revision 9387, 10.6 kB (checked in by robert, 6 years ago)

Improved the effectiveness of the new max target number PageLOD's

  • Property svn:eol-style set to native
  • Property svn:keywords set to Author Date Id Revision
Line 
1/* -*-c++-*- OpenSceneGraph - Copyright (C) 1998-2006 Robert Osfield
2 *
3 * This library is open source and may be redistributed and/or modified under
4 * the terms of the OpenSceneGraph Public License (OSGPL) version 0.0 or
5 * (at your option) any later version.  The full license is in LICENSE file
6 * included with this distribution, and on the openscenegraph.org website.
7 *
8 * This library is distributed in the hope that it will be useful,
9 * but WITHOUT ANY WARRANTY; without even the implied warranty of
10 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
11 * OpenSceneGraph Public License for more details.
12*/
13
14#include <osg/PagedLOD>
15#include <osg/CullStack>
16#include <osg/Notify>
17
18#include <algorithm>
19
20using namespace osg;
21
22PagedLOD::PerRangeData::PerRangeData():
23    _priorityOffset(0.0f),
24    _priorityScale(1.0f),
25    _timeStamp(0.0f),
26    _frameNumber(0),
27    _frameNumberOfLastReleaseGLObjects(0) {}
28
29PagedLOD::PerRangeData::PerRangeData(const PerRangeData& prd):
30    _filename(prd._filename),
31    _priorityOffset(prd._priorityOffset),
32    _priorityScale(prd._priorityScale),
33    _timeStamp(prd._timeStamp),
34    _frameNumber(prd._frameNumber),
35    _frameNumberOfLastReleaseGLObjects(prd._frameNumberOfLastReleaseGLObjects),
36    _databaseRequest(prd._databaseRequest) {}
37
38PagedLOD::PerRangeData& PagedLOD::PerRangeData::operator = (const PerRangeData& prd)
39{
40    if (this==&prd) return *this;
41    _filename = prd._filename;
42    _priorityOffset = prd._priorityOffset;
43    _priorityScale = prd._priorityScale;
44    _timeStamp = prd._timeStamp;
45    _frameNumber = prd._frameNumber;
46    _frameNumberOfLastReleaseGLObjects = prd._frameNumberOfLastReleaseGLObjects;
47    _databaseRequest = prd._databaseRequest;
48    return *this;
49}
50
51PagedLOD::PagedLOD()
52{
53    _frameNumberOfLastTraversal = 0;
54    _centerMode = USER_DEFINED_CENTER;
55    _radius = -1;
56    _numChildrenThatCannotBeExpired = 0;
57}
58
59PagedLOD::PagedLOD(const PagedLOD& plod,const CopyOp& copyop):
60    LOD(plod,copyop),
61    _databasePath(plod._databasePath),
62    _frameNumberOfLastTraversal(plod._frameNumberOfLastTraversal),
63    _numChildrenThatCannotBeExpired(plod._numChildrenThatCannotBeExpired),
64    _perRangeDataList(plod._perRangeDataList)
65{
66}
67
68PagedLOD::~PagedLOD()
69{
70}
71
72void PagedLOD::setDatabasePath(const std::string& path)
73{
74    _databasePath = path;
75    if (!_databasePath.empty())
76    {
77        char& lastCharacter = _databasePath[_databasePath.size()-1];
78        const char unixSlash = '/';
79        const char winSlash = '\\';
80
81        if (lastCharacter==winSlash)
82        {
83            lastCharacter = unixSlash;
84        }
85        else if (lastCharacter!=unixSlash)
86        {
87            _databasePath += unixSlash;
88        }
89
90/*
91        // make sure the last character is the appropriate slash
92#ifdef WIN32
93        if (lastCharacter==unixSlash)
94        {
95            lastCharacter = winSlash;
96        }
97        else if (lastCharacter!=winSlash)
98        {
99            _databasePath += winSlash;
100        }
101#else
102        if (lastCharacter==winSlash)
103        {
104            lastCharacter = unixSlash;
105        }
106        else if (lastCharacter!=unixSlash)
107        {
108            _databasePath += unixSlash;
109        }
110#endif
111*/
112    }
113}
114
115
116void PagedLOD::traverse(NodeVisitor& nv)
117{
118    // set the frame number of the traversal so that external nodes can find out how active this
119    // node is.
120    if (nv.getFrameStamp() &&
121        nv.getVisitorType()==osg::NodeVisitor::CULL_VISITOR)
122    {
123        setFrameNumberOfLastTraversal(nv.getFrameStamp()->getFrameNumber());
124    }
125
126    double timeStamp = nv.getFrameStamp()?nv.getFrameStamp()->getReferenceTime():0.0;
127    int frameNumber = nv.getFrameStamp()?nv.getFrameStamp()->getFrameNumber():0;
128    bool updateTimeStamp = nv.getVisitorType()==osg::NodeVisitor::CULL_VISITOR;
129
130    switch(nv.getTraversalMode())
131    {
132        case(NodeVisitor::TRAVERSE_ALL_CHILDREN):
133            std::for_each(_children.begin(),_children.end(),NodeAcceptOp(nv));
134            break;
135        case(NodeVisitor::TRAVERSE_ACTIVE_CHILDREN):
136        {
137            float required_range = 0;
138            if (_rangeMode==DISTANCE_FROM_EYE_POINT)
139            {
140                required_range = nv.getDistanceToViewPoint(getCenter(),true);
141            }
142            else
143            {
144                osg::CullStack* cullStack = dynamic_cast<osg::CullStack*>(&nv);
145                if (cullStack && cullStack->getLODScale()>0.0f)
146                {
147                    required_range = cullStack->clampedPixelSize(getBound()) / cullStack->getLODScale();
148                }
149                else
150                {
151                    // fallback to selecting the highest res tile by
152                    // finding out the max range
153                    for(unsigned int i=0;i<_rangeList.size();++i)
154                    {
155                        required_range = osg::maximum(required_range,_rangeList[i].first);
156                    }
157                }
158            }
159
160            int lastChildTraversed = -1;
161            bool needToLoadChild = false;
162            for(unsigned int i=0;i<_rangeList.size();++i)
163            {
164                if (_rangeList[i].first<=required_range && required_range<_rangeList[i].second)
165                {
166                    if (i<_children.size())
167                    {
168                        if (updateTimeStamp)
169                        {
170                            _perRangeDataList[i]._timeStamp=timeStamp;
171                            _perRangeDataList[i]._frameNumber=frameNumber;
172                        }
173
174                        _children[i]->accept(nv);
175                        lastChildTraversed = (int)i;
176                    }
177                    else
178                    {
179                        needToLoadChild = true;
180                    }
181                }
182            }
183
184            if (needToLoadChild)
185            {
186                unsigned int numChildren = _children.size();
187
188                // select the last valid child.
189                if (numChildren>0 && ((int)numChildren-1)!=lastChildTraversed)
190                {
191                    if (updateTimeStamp)
192                    {
193                        _perRangeDataList[numChildren-1]._timeStamp=timeStamp;
194                        _perRangeDataList[numChildren-1]._frameNumber=frameNumber;
195                    }
196                    _children[numChildren-1]->accept(nv);
197                }
198
199                // now request the loading of the next unloaded child.
200                if (nv.getDatabaseRequestHandler() && numChildren<_perRangeDataList.size())
201                {
202                    // compute priority from where abouts in the required range the distance falls.
203                    float priority = (_rangeList[numChildren].second-required_range)/(_rangeList[numChildren].second-_rangeList[numChildren].first);
204
205                    // invert priority for PIXEL_SIZE_ON_SCREEN mode
206                    if(_rangeMode==PIXEL_SIZE_ON_SCREEN)
207                    {
208                        priority = -priority;
209                    }
210
211                    // modify the priority according to the child's priority offset and scale.
212                    priority = _perRangeDataList[numChildren]._priorityOffset + priority * _perRangeDataList[numChildren]._priorityScale;
213
214                    if (_databasePath.empty())
215                    {
216                        nv.getDatabaseRequestHandler()->requestNodeFile(_perRangeDataList[numChildren]._filename,this,priority,nv.getFrameStamp(), _perRangeDataList[numChildren]._databaseRequest);
217                    }
218                    else
219                    {
220                        // prepend the databasePath to the child's filename.
221                        nv.getDatabaseRequestHandler()->requestNodeFile(_databasePath+_perRangeDataList[numChildren]._filename,this,priority,nv.getFrameStamp(), _perRangeDataList[numChildren]._databaseRequest);
222                    }
223                }
224
225
226            }
227
228
229           break;
230        }
231        default:
232            break;
233    }
234}
235
236
237void PagedLOD::expandPerRangeDataTo(unsigned int pos)
238{
239    if (pos>=_perRangeDataList.size()) _perRangeDataList.resize(pos+1);
240}
241
242bool PagedLOD::addChild( Node *child )
243{
244    if (LOD::addChild(child))
245    {
246        expandPerRangeDataTo(_children.size()-1);
247        return true;
248    }
249    return false;
250}
251
252bool PagedLOD::addChild(Node *child, float min, float max)
253{
254    if (LOD::addChild(child,min,max))
255    {
256        expandPerRangeDataTo(_children.size()-1);
257        return true;
258    }
259    return false;
260}
261
262
263bool PagedLOD::addChild(Node *child, float min, float max,const std::string& filename, float priorityOffset, float priorityScale)
264{
265    if (LOD::addChild(child,min,max))
266    {
267        setFileName(_children.size()-1,filename);
268        setPriorityOffset(_children.size()-1,priorityOffset);
269        setPriorityScale(_children.size()-1,priorityScale);
270        return true;
271    }
272    return false;
273}
274
275bool PagedLOD::removeChildren( unsigned int pos,unsigned int numChildrenToRemove)
276{
277    if (pos<_rangeList.size()) _rangeList.erase(_rangeList.begin()+pos, osg::minimum(_rangeList.begin()+(pos+numChildrenToRemove), _rangeList.end()) );
278    if (pos<_perRangeDataList.size()) _perRangeDataList.erase(_perRangeDataList.begin()+pos, osg::minimum(_perRangeDataList.begin()+ (pos+numChildrenToRemove), _perRangeDataList.end()) );
279
280    return Group::removeChildren(pos,numChildrenToRemove);
281}
282
283bool PagedLOD::removeExpiredChildren(double expiryTime, int expiryFrame, NodeList& removedChildren)
284{
285    if (_children.size()>_numChildrenThatCannotBeExpired)
286    {
287        if (!_perRangeDataList[_children.size()-1]._filename.empty() &&
288            _perRangeDataList[_children.size()-1]._timeStamp<expiryTime &&
289            _perRangeDataList[_children.size()-1]._frameNumber<expiryFrame)
290        {           
291            osg::Node* nodeToRemove = _children[_children.size()-1].get();
292            removedChildren.push_back(nodeToRemove);
293            return Group::removeChildren(_children.size()-1,1);
294        }
295    }
296    return false;
297}
298
299bool PagedLOD::releaseGLObjectsOnExpiredChildren(double releaseTime, int releaseFrame)
300{
301    unsigned int numChildrenReleased = 0;
302
303    unsigned int numChildren = osg::minimum(_perRangeDataList.size(), _children.size());
304    for(unsigned int i=_numChildrenThatCannotBeExpired; i<numChildren; ++i)
305    {
306        if (_perRangeDataList[i]._frameNumberOfLastReleaseGLObjects != _perRangeDataList[i]._frameNumber &&
307            _perRangeDataList[i]._timeStamp<releaseTime &&
308            _perRangeDataList[i]._frameNumber<releaseFrame)
309        {
310            _perRangeDataList[i]._frameNumberOfLastReleaseGLObjects = _perRangeDataList[i]._frameNumber;
311           
312            _children[i]->releaseGLObjects();
313            ++numChildrenReleased;
314        }
315    }
316    return numChildrenReleased>0;
317}
Note: See TracBrowser for help on using the browser.