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

Revision 10174, 10.7 kB (checked in by robert, 6 years ago)

Moved Registry::ReadFileCallback? + WriteFileCallback?, and osgDB::ReaderWriter::Options into their own separate Options file and into the osgDB namespace.

Introduced a new callback osgDB::FindFileCallback? that overrides the default behavior of findDataFile/findLibraryFile.

Introduced support for assigning ReaderWriter::Options directory to PagedLOD.

Introduced new osgDB::FileLocationCallback? for assistancing the DatabasePager? to know when a file is hosted on a local or remote file system.

  • 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    _databaseOptions(plod._databaseOptions),
62    _databasePath(plod._databasePath),
63    _frameNumberOfLastTraversal(plod._frameNumberOfLastTraversal),
64    _numChildrenThatCannotBeExpired(plod._numChildrenThatCannotBeExpired),
65    _perRangeDataList(plod._perRangeDataList)
66{
67}
68
69PagedLOD::~PagedLOD()
70{
71}
72
73void PagedLOD::setDatabasePath(const std::string& path)
74{
75    _databasePath = path;
76    if (!_databasePath.empty())
77    {
78        char& lastCharacter = _databasePath[_databasePath.size()-1];
79        const char unixSlash = '/';
80        const char winSlash = '\\';
81
82        if (lastCharacter==winSlash)
83        {
84            lastCharacter = unixSlash;
85        }
86        else if (lastCharacter!=unixSlash)
87        {
88            _databasePath += unixSlash;
89        }
90
91/*
92        // make sure the last character is the appropriate slash
93#ifdef WIN32
94        if (lastCharacter==unixSlash)
95        {
96            lastCharacter = winSlash;
97        }
98        else if (lastCharacter!=winSlash)
99        {
100            _databasePath += winSlash;
101        }
102#else
103        if (lastCharacter==winSlash)
104        {
105            lastCharacter = unixSlash;
106        }
107        else if (lastCharacter!=unixSlash)
108        {
109            _databasePath += unixSlash;
110        }
111#endif
112*/
113    }
114}
115
116
117void PagedLOD::traverse(NodeVisitor& nv)
118{
119    // set the frame number of the traversal so that external nodes can find out how active this
120    // node is.
121    if (nv.getFrameStamp() &&
122        nv.getVisitorType()==osg::NodeVisitor::CULL_VISITOR)
123    {
124        setFrameNumberOfLastTraversal(nv.getFrameStamp()->getFrameNumber());
125    }
126
127    double timeStamp = nv.getFrameStamp()?nv.getFrameStamp()->getReferenceTime():0.0;
128    int frameNumber = nv.getFrameStamp()?nv.getFrameStamp()->getFrameNumber():0;
129    bool updateTimeStamp = nv.getVisitorType()==osg::NodeVisitor::CULL_VISITOR;
130
131    switch(nv.getTraversalMode())
132    {
133        case(NodeVisitor::TRAVERSE_ALL_CHILDREN):
134            std::for_each(_children.begin(),_children.end(),NodeAcceptOp(nv));
135            break;
136        case(NodeVisitor::TRAVERSE_ACTIVE_CHILDREN):
137        {
138            float required_range = 0;
139            if (_rangeMode==DISTANCE_FROM_EYE_POINT)
140            {
141                required_range = nv.getDistanceToViewPoint(getCenter(),true);
142            }
143            else
144            {
145                osg::CullStack* cullStack = dynamic_cast<osg::CullStack*>(&nv);
146                if (cullStack && cullStack->getLODScale()>0.0f)
147                {
148                    required_range = cullStack->clampedPixelSize(getBound()) / cullStack->getLODScale();
149                }
150                else
151                {
152                    // fallback to selecting the highest res tile by
153                    // finding out the max range
154                    for(unsigned int i=0;i<_rangeList.size();++i)
155                    {
156                        required_range = osg::maximum(required_range,_rangeList[i].first);
157                    }
158                }
159            }
160
161            int lastChildTraversed = -1;
162            bool needToLoadChild = false;
163            for(unsigned int i=0;i<_rangeList.size();++i)
164            {
165                if (_rangeList[i].first<=required_range && required_range<_rangeList[i].second)
166                {
167                    if (i<_children.size())
168                    {
169                        if (updateTimeStamp)
170                        {
171                            _perRangeDataList[i]._timeStamp=timeStamp;
172                            _perRangeDataList[i]._frameNumber=frameNumber;
173                        }
174
175                        _children[i]->accept(nv);
176                        lastChildTraversed = (int)i;
177                    }
178                    else
179                    {
180                        needToLoadChild = true;
181                    }
182                }
183            }
184
185            if (needToLoadChild)
186            {
187                unsigned int numChildren = _children.size();
188
189                // select the last valid child.
190                if (numChildren>0 && ((int)numChildren-1)!=lastChildTraversed)
191                {
192                    if (updateTimeStamp)
193                    {
194                        _perRangeDataList[numChildren-1]._timeStamp=timeStamp;
195                        _perRangeDataList[numChildren-1]._frameNumber=frameNumber;
196                    }
197                    _children[numChildren-1]->accept(nv);
198                }
199
200                // now request the loading of the next unloaded child.
201                if (nv.getDatabaseRequestHandler() && numChildren<_perRangeDataList.size())
202                {
203                    // compute priority from where abouts in the required range the distance falls.
204                    float priority = (_rangeList[numChildren].second-required_range)/(_rangeList[numChildren].second-_rangeList[numChildren].first);
205
206                    // invert priority for PIXEL_SIZE_ON_SCREEN mode
207                    if(_rangeMode==PIXEL_SIZE_ON_SCREEN)
208                    {
209                        priority = -priority;
210                    }
211
212                    // modify the priority according to the child's priority offset and scale.
213                    priority = _perRangeDataList[numChildren]._priorityOffset + priority * _perRangeDataList[numChildren]._priorityScale;
214
215                    if (_databasePath.empty())
216                    {
217                        nv.getDatabaseRequestHandler()->requestNodeFile(_perRangeDataList[numChildren]._filename,this,priority,nv.getFrameStamp(), _perRangeDataList[numChildren]._databaseRequest, _databaseOptions.get());
218                    }
219                    else
220                    {
221                        // prepend the databasePath to the child's filename.
222                        nv.getDatabaseRequestHandler()->requestNodeFile(_databasePath+_perRangeDataList[numChildren]._filename,this,priority,nv.getFrameStamp(), _perRangeDataList[numChildren]._databaseRequest, _databaseOptions.get());
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.