#include using namespace osg; PagedLOD::PerRangeData::PerRangeData(): _priorityOffset(0.0f), _priorityScale(0.0f), _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; } PagedLOD::PagedLOD() { _frameNumberOfLastTraversal = 0; _centerMode = USER_DEFINED_CENTER; _radius = -1; _numChildrenThatCannotBeExpired = 0; } PagedLOD::PagedLOD(const PagedLOD& plod,const CopyOp& copyop): LOD(plod,copyop), _frameNumberOfLastTraversal(plod._frameNumberOfLastTraversal), _numChildrenThatCannotBeExpired(plod._numChildrenThatCannotBeExpired), _perRangeDataList(plod._perRangeDataList) { } void PagedLOD::setDatabasePath(const std::string& path) { _databasePath = path; if (!_databasePath.empty()) { char& lastCharacter = _databasePath[_databasePath.size()-1]; const char unixSlash = '/'; const char winSlash = '\\'; // 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 } } void PagedLOD::traverse(NodeVisitor& nv) { // 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()); 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): { float distance = nv.getDistanceToEyePoint(getCenter(),true); int lastChildTraversed = -1; bool needToLoadChild = false; for(unsigned int i=0;i<_rangeList.size();++i) { if (_rangeList[i].first<=distance && distance<_rangeList[i].second) { if (i<_children.size()) { if (updateTimeStamp) _perRangeDataList[i]._timeStamp=timeStamp; _children[i]->accept(nv); lastChildTraversed = (int)i; } else { needToLoadChild = true; } } } if (needToLoadChild) { unsigned int numChildren = _children.size(); // select the last valid child. if (numChildren>0 && ((int)numChildren-1)!=lastChildTraversed) { if (updateTimeStamp) _perRangeDataList[numChildren-1]._timeStamp=timeStamp; _children[numChildren-1]->accept(nv); } // now request the loading of the next unload child. if (nv.getDatabaseRequestHandler() && numChildren<_perRangeDataList.size()) { // compute priority from where abouts in the required range the distance falls. float priority = (_rangeList[numChildren].second-distance)/(_rangeList[numChildren].second-_rangeList[numChildren].first); // modify the priority according to the child's priority offset and scale. priority = _perRangeDataList[numChildren]._priorityOffset + priority * _perRangeDataList[numChildren]._priorityScale; if (_databasePath.empty()) { nv.getDatabaseRequestHandler()->requestNodeFile(_perRangeDataList[numChildren]._filename,this,priority,nv.getFrameStamp()); } else { // prepend the databasePath to the childs filename. nv.getDatabaseRequestHandler()->requestNodeFile(_databasePath+_perRangeDataList[numChildren]._filename,this,priority,nv.getFrameStamp()); } } } break; } default: break; } } void PagedLOD::childRemoved(unsigned int pos, unsigned int numChildrenToRemove) { LOD::childRemoved(pos, numChildrenToRemove); } void PagedLOD::childInserted(unsigned int pos) { LOD::childInserted(pos); } void PagedLOD::rangeRemoved(unsigned int pos, unsigned int numChildrenToRemove) { LOD::rangeRemoved(pos, numChildrenToRemove); } void PagedLOD::rangeInserted(unsigned int pos) { LOD::rangeInserted(pos); expandPerRangeDataTo(pos); } void PagedLOD::expandPerRangeDataTo(unsigned int pos) { if (pos>=_perRangeDataList.size()) _perRangeDataList.resize(pos+1); } bool PagedLOD::addChild( Node *child ) { if (LOD::addChild(child)) { expandPerRangeDataTo(_children.size()); return true; } return false; } bool PagedLOD::addChild(Node *child, float min, float max) { if (LOD::addChild(child,min,max)) { expandPerRangeDataTo(_children.size()); return true; } return false; } bool PagedLOD::addChild(Node *child, float min, float max,const std::string& filename, float priorityOffset, float priorityScale) { if (LOD::addChild(child,min,max)) { setFileName(_children.size()-1,filename); setPriorityOffset(_children.size()-1,priorityOffset); setPriorityScale(_children.size()-1,priorityScale); return true; } return false; } bool PagedLOD::removeChild( Node *child ) { // find the child's position. unsigned int pos=getChildIndex(child); if (pos==_children.size()) return false; if (pos<_rangeList.size()) _rangeList.erase(_rangeList.begin()+pos); if (pos<_perRangeDataList.size()) _perRangeDataList.erase(_perRangeDataList.begin()+pos); return Group::removeChild(child); } bool PagedLOD::removeExpiredChildren(double expiryTime,NodeList& removedChildren) { if (_children.size()>_numChildrenThatCannotBeExpired) { if (!_perRangeDataList[_children.size()-1]._filename.empty() && _perRangeDataList[_children.size()-1]._timeStamp