2005-04-15 05:41:28 +08:00
|
|
|
/* -*-c++-*- OpenSceneGraph - Copyright (C) 1998-2005 Robert Osfield
|
2004-11-20 19:48:28 +08:00
|
|
|
*
|
|
|
|
* This library is open source and may be redistributed and/or modified under
|
|
|
|
* the terms of the OpenSceneGraph Public License (OSGPL) version 0.0 or
|
|
|
|
* (at your option) any later version. The full license is in LICENSE file
|
|
|
|
* included with this distribution, and on the openscenegraph.org website.
|
|
|
|
*
|
|
|
|
* This library is distributed in the hope that it will be useful,
|
|
|
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
|
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
|
|
* OpenSceneGraph Public License for more details.
|
|
|
|
*/
|
|
|
|
|
2003-07-08 22:44:00 +08:00
|
|
|
#include <osg/PagedLOD>
|
2004-11-20 19:48:28 +08:00
|
|
|
#include <osg/CullStack>
|
2004-11-20 20:08:33 +08:00
|
|
|
#include <osg/Notify>
|
2003-07-08 22:44:00 +08:00
|
|
|
|
2005-04-08 20:22:03 +08:00
|
|
|
#include <algorithm>
|
|
|
|
|
2003-07-08 22:44:00 +08:00
|
|
|
using namespace osg;
|
|
|
|
|
2004-01-07 16:39:33 +08:00
|
|
|
PagedLOD::PerRangeData::PerRangeData():
|
|
|
|
_priorityOffset(0.0f),
|
2004-11-20 20:08:33 +08:00
|
|
|
_priorityScale(1.0f),
|
2004-01-07 16:39:33 +08:00
|
|
|
_timeStamp(0.0f) {}
|
|
|
|
|
|
|
|
PagedLOD::PerRangeData::PerRangeData(const PerRangeData& prd):
|
|
|
|
_filename(prd._filename),
|
|
|
|
_priorityOffset(prd._priorityOffset),
|
|
|
|
_priorityScale(prd._priorityScale),
|
|
|
|
_timeStamp(prd._timeStamp) {}
|
|
|
|
|
|
|
|
PagedLOD::PerRangeData& PagedLOD::PerRangeData::operator = (const PerRangeData& prd)
|
|
|
|
{
|
|
|
|
if (this==&prd) return *this;
|
|
|
|
_filename = prd._filename;
|
|
|
|
_priorityOffset = prd._priorityOffset;
|
|
|
|
_priorityScale = prd._priorityScale;
|
|
|
|
_timeStamp = prd._timeStamp;
|
|
|
|
return *this;
|
|
|
|
}
|
|
|
|
|
2003-07-10 22:53:07 +08:00
|
|
|
PagedLOD::PagedLOD()
|
|
|
|
{
|
2004-09-22 01:26:08 +08:00
|
|
|
_frameNumberOfLastTraversal = 0;
|
2003-07-10 22:53:07 +08:00
|
|
|
_centerMode = USER_DEFINED_CENTER;
|
2003-12-09 20:08:27 +08:00
|
|
|
_radius = -1;
|
|
|
|
_numChildrenThatCannotBeExpired = 0;
|
2003-07-10 22:53:07 +08:00
|
|
|
}
|
|
|
|
|
2003-07-08 22:44:00 +08:00
|
|
|
PagedLOD::PagedLOD(const PagedLOD& plod,const CopyOp& copyop):
|
2003-12-09 20:08:27 +08:00
|
|
|
LOD(plod,copyop),
|
2004-09-22 01:26:08 +08:00
|
|
|
_frameNumberOfLastTraversal(plod._frameNumberOfLastTraversal),
|
2003-12-09 20:08:27 +08:00
|
|
|
_numChildrenThatCannotBeExpired(plod._numChildrenThatCannotBeExpired),
|
2004-01-06 04:45:28 +08:00
|
|
|
_perRangeDataList(plod._perRangeDataList)
|
2003-07-08 22:44:00 +08:00
|
|
|
{
|
|
|
|
}
|
|
|
|
|
2004-10-06 17:31:34 +08:00
|
|
|
void PagedLOD::setDatabasePath(const std::string& path)
|
|
|
|
{
|
|
|
|
_databasePath = path;
|
|
|
|
if (!_databasePath.empty())
|
|
|
|
{
|
|
|
|
char& lastCharacter = _databasePath[_databasePath.size()-1];
|
|
|
|
const char unixSlash = '/';
|
|
|
|
const char winSlash = '\\';
|
2004-11-12 16:55:11 +08:00
|
|
|
|
|
|
|
if (lastCharacter==winSlash)
|
|
|
|
{
|
|
|
|
lastCharacter = unixSlash;
|
|
|
|
}
|
|
|
|
else if (lastCharacter!=unixSlash)
|
|
|
|
{
|
|
|
|
_databasePath += unixSlash;
|
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
2004-10-06 17:31:34 +08:00
|
|
|
// make sure the last character is the appropriate slash
|
|
|
|
#ifdef WIN32
|
|
|
|
if (lastCharacter==unixSlash)
|
|
|
|
{
|
|
|
|
lastCharacter = winSlash;
|
|
|
|
}
|
|
|
|
else if (lastCharacter!=winSlash)
|
|
|
|
{
|
|
|
|
_databasePath += winSlash;
|
|
|
|
}
|
|
|
|
#else
|
|
|
|
if (lastCharacter==winSlash)
|
|
|
|
{
|
|
|
|
lastCharacter = unixSlash;
|
|
|
|
}
|
|
|
|
else if (lastCharacter!=unixSlash)
|
|
|
|
{
|
|
|
|
_databasePath += unixSlash;
|
|
|
|
}
|
|
|
|
#endif
|
2004-11-12 16:55:11 +08:00
|
|
|
*/
|
2004-10-06 17:31:34 +08:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2003-12-09 20:08:27 +08:00
|
|
|
|
2003-07-08 22:44:00 +08:00
|
|
|
void PagedLOD::traverse(NodeVisitor& nv)
|
|
|
|
{
|
2004-09-22 01:26:08 +08:00
|
|
|
// set the frame number of the traversal so that external nodes can find out how active this
|
|
|
|
// node is.
|
|
|
|
if (nv.getFrameStamp()) setFrameNumberOfLastTraversal(nv.getFrameStamp()->getFrameNumber());
|
2003-07-08 22:44:00 +08:00
|
|
|
|
|
|
|
double timeStamp = nv.getFrameStamp()?nv.getFrameStamp()->getReferenceTime():0.0;
|
|
|
|
bool updateTimeStamp = nv.getVisitorType()==osg::NodeVisitor::CULL_VISITOR;
|
|
|
|
|
|
|
|
switch(nv.getTraversalMode())
|
|
|
|
{
|
|
|
|
case(NodeVisitor::TRAVERSE_ALL_CHILDREN):
|
|
|
|
std::for_each(_children.begin(),_children.end(),NodeAcceptOp(nv));
|
|
|
|
break;
|
|
|
|
case(NodeVisitor::TRAVERSE_ACTIVE_CHILDREN):
|
|
|
|
{
|
2004-11-20 19:48:28 +08:00
|
|
|
float required_range = 0;
|
|
|
|
if (_rangeMode==DISTANCE_FROM_EYE_POINT)
|
|
|
|
{
|
|
|
|
required_range = nv.getDistanceToEyePoint(getCenter(),true);
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
osg::CullStack* cullStack = dynamic_cast<osg::CullStack*>(&nv);
|
2005-11-22 18:26:27 +08:00
|
|
|
if (cullStack && cullStack->getLODScale()>0.0f)
|
2004-11-20 19:48:28 +08:00
|
|
|
{
|
2005-11-22 18:08:00 +08:00
|
|
|
required_range = cullStack->clampedPixelSize(getBound()) / cullStack->getLODScale();
|
2004-11-20 19:48:28 +08:00
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
// fallback to selecting the highest res tile by
|
|
|
|
// finding out the max range
|
|
|
|
for(unsigned int i=0;i<_rangeList.size();++i)
|
|
|
|
{
|
2005-11-22 18:26:27 +08:00
|
|
|
required_range = osg::maximum(required_range,_rangeList[i].first);
|
2004-11-20 19:48:28 +08:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2003-12-21 07:25:05 +08:00
|
|
|
int lastChildTraversed = -1;
|
|
|
|
bool needToLoadChild = false;
|
|
|
|
for(unsigned int i=0;i<_rangeList.size();++i)
|
2003-07-08 22:44:00 +08:00
|
|
|
{
|
2004-11-20 19:48:28 +08:00
|
|
|
if (_rangeList[i].first<=required_range && required_range<_rangeList[i].second)
|
2003-07-08 22:44:00 +08:00
|
|
|
{
|
2003-12-21 07:25:05 +08:00
|
|
|
if (i<_children.size())
|
|
|
|
{
|
2004-01-06 04:45:28 +08:00
|
|
|
if (updateTimeStamp) _perRangeDataList[i]._timeStamp=timeStamp;
|
2003-07-08 22:44:00 +08:00
|
|
|
|
2003-12-21 07:25:05 +08:00
|
|
|
_children[i]->accept(nv);
|
|
|
|
lastChildTraversed = (int)i;
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
needToLoadChild = true;
|
|
|
|
}
|
2003-07-08 22:44:00 +08:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2003-12-21 07:25:05 +08:00
|
|
|
if (needToLoadChild)
|
2003-07-08 22:44:00 +08:00
|
|
|
{
|
2003-12-21 07:25:05 +08:00
|
|
|
unsigned int numChildren = _children.size();
|
|
|
|
|
2003-07-08 22:44:00 +08:00
|
|
|
// select the last valid child.
|
2003-12-21 07:25:05 +08:00
|
|
|
if (numChildren>0 && ((int)numChildren-1)!=lastChildTraversed)
|
2003-07-08 22:44:00 +08:00
|
|
|
{
|
2004-01-06 04:45:28 +08:00
|
|
|
if (updateTimeStamp) _perRangeDataList[numChildren-1]._timeStamp=timeStamp;
|
2003-07-08 22:44:00 +08:00
|
|
|
_children[numChildren-1]->accept(nv);
|
|
|
|
}
|
|
|
|
|
2005-09-28 21:33:58 +08:00
|
|
|
// now request the loading of the next unloaded child.
|
2004-01-06 04:45:28 +08:00
|
|
|
if (nv.getDatabaseRequestHandler() && numChildren<_perRangeDataList.size())
|
2003-07-08 22:44:00 +08:00
|
|
|
{
|
2004-01-06 04:51:30 +08:00
|
|
|
// compute priority from where abouts in the required range the distance falls.
|
2004-11-20 19:48:28 +08:00
|
|
|
float priority = (_rangeList[numChildren].second-required_range)/(_rangeList[numChildren].second-_rangeList[numChildren].first);
|
2004-01-06 04:51:30 +08:00
|
|
|
|
2005-09-28 21:33:58 +08:00
|
|
|
// invert priority for PIXEL_SIZE_ON_SCREEN mode
|
|
|
|
if(_rangeMode==PIXEL_SIZE_ON_SCREEN)
|
|
|
|
{
|
|
|
|
priority = -priority;
|
|
|
|
}
|
|
|
|
|
2004-01-06 04:51:30 +08:00
|
|
|
// modify the priority according to the child's priority offset and scale.
|
|
|
|
priority = _perRangeDataList[numChildren]._priorityOffset + priority * _perRangeDataList[numChildren]._priorityScale;
|
2004-11-20 20:08:33 +08:00
|
|
|
|
2004-10-06 17:31:34 +08:00
|
|
|
if (_databasePath.empty())
|
|
|
|
{
|
|
|
|
nv.getDatabaseRequestHandler()->requestNodeFile(_perRangeDataList[numChildren]._filename,this,priority,nv.getFrameStamp());
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
2005-09-28 21:33:58 +08:00
|
|
|
// prepend the databasePath to the child's filename.
|
2004-10-06 17:31:34 +08:00
|
|
|
nv.getDatabaseRequestHandler()->requestNodeFile(_databasePath+_perRangeDataList[numChildren]._filename,this,priority,nv.getFrameStamp());
|
|
|
|
}
|
2003-07-08 22:44:00 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
default:
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2003-12-09 20:08:27 +08:00
|
|
|
|
2004-01-06 04:45:28 +08:00
|
|
|
void PagedLOD::expandPerRangeDataTo(unsigned int pos)
|
|
|
|
{
|
|
|
|
if (pos>=_perRangeDataList.size()) _perRangeDataList.resize(pos+1);
|
|
|
|
}
|
|
|
|
|
2003-07-08 22:44:00 +08:00
|
|
|
bool PagedLOD::addChild( Node *child )
|
|
|
|
{
|
|
|
|
if (LOD::addChild(child))
|
|
|
|
{
|
2005-07-15 04:32:25 +08:00
|
|
|
expandPerRangeDataTo(_children.size()-1);
|
2003-07-08 22:44:00 +08:00
|
|
|
return true;
|
|
|
|
}
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
|
|
|
bool PagedLOD::addChild(Node *child, float min, float max)
|
|
|
|
{
|
|
|
|
if (LOD::addChild(child,min,max))
|
|
|
|
{
|
2005-07-15 04:32:25 +08:00
|
|
|
expandPerRangeDataTo(_children.size()-1);
|
2003-07-08 22:44:00 +08:00
|
|
|
return true;
|
|
|
|
}
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2004-01-06 04:45:28 +08:00
|
|
|
bool PagedLOD::addChild(Node *child, float min, float max,const std::string& filename, float priorityOffset, float priorityScale)
|
2003-07-08 22:44:00 +08:00
|
|
|
{
|
|
|
|
if (LOD::addChild(child,min,max))
|
|
|
|
{
|
2004-01-06 04:45:28 +08:00
|
|
|
setFileName(_children.size()-1,filename);
|
|
|
|
setPriorityOffset(_children.size()-1,priorityOffset);
|
|
|
|
setPriorityScale(_children.size()-1,priorityScale);
|
2003-07-08 22:44:00 +08:00
|
|
|
return true;
|
|
|
|
}
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
2006-05-02 17:45:31 +08:00
|
|
|
bool PagedLOD::removeChildren( unsigned int pos,unsigned int numChildrenToRemove)
|
2003-07-08 22:44:00 +08:00
|
|
|
{
|
2006-05-02 17:45:31 +08:00
|
|
|
if (pos<_rangeList.size()) _rangeList.erase(_rangeList.begin()+pos, osg::minimum(_rangeList.begin()+(pos+numChildrenToRemove), _rangeList.end()) );
|
|
|
|
if (pos<_perRangeDataList.size()) _perRangeDataList.erase(_perRangeDataList.begin()+pos, osg::minimum(_perRangeDataList.begin()+ (pos+numChildrenToRemove), _perRangeDataList.end()) );
|
|
|
|
|
|
|
|
return Group::removeChildren(pos,numChildrenToRemove);
|
2003-07-08 22:44:00 +08:00
|
|
|
}
|
|
|
|
|
2004-09-22 01:26:08 +08:00
|
|
|
bool PagedLOD::removeExpiredChildren(double expiryTime,NodeList& removedChildren)
|
2003-07-08 22:44:00 +08:00
|
|
|
{
|
2004-02-02 00:13:07 +08:00
|
|
|
if (_children.size()>_numChildrenThatCannotBeExpired)
|
2003-07-08 22:44:00 +08:00
|
|
|
{
|
2004-02-02 00:13:07 +08:00
|
|
|
if (!_perRangeDataList[_children.size()-1]._filename.empty() && _perRangeDataList[_children.size()-1]._timeStamp<expiryTime)
|
2003-07-08 22:44:00 +08:00
|
|
|
{
|
2004-08-02 21:57:47 +08:00
|
|
|
osg::Node* nodeToRemove = _children[_children.size()-1].get();
|
|
|
|
removedChildren.push_back(nodeToRemove);
|
2004-09-22 01:26:08 +08:00
|
|
|
return Group::removeChild(nodeToRemove);
|
2003-07-08 22:44:00 +08:00
|
|
|
}
|
|
|
|
}
|
2004-09-22 01:26:08 +08:00
|
|
|
return false;
|
2003-07-08 22:44:00 +08:00
|
|
|
}
|