Hi Robert,

The attached files add the ability to control when a paged child becomes 
eligible for expiry based on time and/or elapsed frames.

I found that some of the items that had been paged in were being expired on the 
first frame that they were not visible (as the cache was full). This resulted 
in excessive paging every time the view was moved. With the following changes I 
could only allow children to be expired if they had not been used for e.g. 30 
seconds or 60 frames.

The changes were made against trunk revision 12822.

Cheers,

Brad


-------------------------------------------------------------------------
DISCLAIMER: This e-mail transmission and any documents, files and 
previous e-mail messages attached to it are private and confidential.  
They may contain proprietary or copyright material or information that 
is subject to legal professional privilege.  They are for the use of 
the intended recipient only.  Any unauthorised viewing, use, disclosure, 
copying, alteration, storage or distribution of, or reliance on, this 
message is strictly prohibited.  No part may be reproduced, adapted or 
transmitted without the written permission of the owner.  If you have 
received this transmission in error, or are not an authorised recipient, 
please immediately notify the sender by return email, delete this 
message and all copies from your e-mail system, and destroy any printed 
copies.  Receipt by anyone other than the intended recipient should not 
be deemed a waiver of any privilege or protection.  Thales Australia 
does not warrant or represent that this e-mail or any documents, files 
and previous e-mail messages attached are error or virus free.  

-------------------------------------------------------------------------

Attachment: PagedLOD
Description: PagedLOD

/* -*-c++-*- OpenSceneGraph - Copyright (C) 1998-2006 Robert Osfield
 *
 * 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.
*/

#include <osg/PagedLOD>
#include <osg/CullStack>
#include <osg/Notify>

#include <algorithm>

using namespace osg;

PagedLOD::PerRangeData::PerRangeData():
    _priorityOffset(0.0f),
    _priorityScale(1.0f),
    _minExpiryTime(0.0f),
    _minExpiryFrames(0),
    _timeStamp(0.0f),
    _frameNumber(0),
    _frameNumberOfLastReleaseGLObjects(0) {}

PagedLOD::PerRangeData::PerRangeData(const PerRangeData& prd):
    _filename(prd._filename),
    _priorityOffset(prd._priorityOffset),
    _priorityScale(prd._priorityScale),
    _minExpiryTime(prd._minExpiryTime),
    _minExpiryFrames(prd._minExpiryFrames),
    _timeStamp(prd._timeStamp),
    _frameNumber(prd._frameNumber),
    _frameNumberOfLastReleaseGLObjects(prd._frameNumberOfLastReleaseGLObjects),
    _databaseRequest(prd._databaseRequest) {}

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;
    _frameNumber = prd._frameNumber;
    _frameNumberOfLastReleaseGLObjects = prd._frameNumberOfLastReleaseGLObjects;
    _databaseRequest = prd._databaseRequest;
    _minExpiryTime = prd._minExpiryTime;
    _minExpiryFrames = prd._minExpiryFrames;
    return *this;
}

PagedLOD::PagedLOD()
{
    _frameNumberOfLastTraversal = 0;
    _centerMode = USER_DEFINED_CENTER;
    _radius = -1;
    _numChildrenThatCannotBeExpired = 0;
    _disableExternalChildrenPaging = false;
}

PagedLOD::PagedLOD(const PagedLOD& plod,const CopyOp& copyop):
    LOD(plod,copyop),
    _databaseOptions(plod._databaseOptions),
    _databasePath(plod._databasePath),
    _frameNumberOfLastTraversal(plod._frameNumberOfLastTraversal),
    _numChildrenThatCannotBeExpired(plod._numChildrenThatCannotBeExpired),
    _disableExternalChildrenPaging(plod._disableExternalChildrenPaging),
    _perRangeDataList(plod._perRangeDataList)
{
}

PagedLOD::~PagedLOD()
{
}

void PagedLOD::setDatabasePath(const std::string& path)
{
    _databasePath = path;
    if (!_databasePath.empty())
    {
        char& lastCharacter = _databasePath[_databasePath.size()-1];
        const char unixSlash = '/';
        const char winSlash = '\\';

        if (lastCharacter==winSlash)
        {
            lastCharacter = unixSlash;
        }
        else if (lastCharacter!=unixSlash)
        {
            _databasePath += unixSlash;
        }

/*
        // 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() && 
        nv.getVisitorType()==osg::NodeVisitor::CULL_VISITOR) 
    {
        setFrameNumberOfLastTraversal(nv.getFrameStamp()->getFrameNumber());
    }

    double timeStamp = 
nv.getFrameStamp()?nv.getFrameStamp()->getReferenceTime():0.0;
    unsigned int frameNumber = 
nv.getFrameStamp()?nv.getFrameStamp()->getFrameNumber():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 required_range = 0;
            if (_rangeMode==DISTANCE_FROM_EYE_POINT)
            {
                required_range = nv.getDistanceToViewPoint(getCenter(),true);
            }
            else
            {
                osg::CullStack* cullStack = dynamic_cast<osg::CullStack*>(&nv);
                if (cullStack && cullStack->getLODScale()>0.0f)
                {
                    required_range = cullStack->clampedPixelSize(getBound()) / 
cullStack->getLODScale();
                }
                else
                {
                    // fallback to selecting the highest res tile by
                    // finding out the max range
                    for(unsigned int i=0;i<_rangeList.size();++i)
                    {
                        required_range = 
osg::maximum(required_range,_rangeList[i].first);
                    }
                }
            }

            int lastChildTraversed = -1;
            bool needToLoadChild = false;
            for(unsigned int i=0;i<_rangeList.size();++i)
            {
                if (_rangeList[i].first<=required_range && 
required_range<_rangeList[i].second)
                {
                    if (i<_children.size())
                    {
                        if (updateTimeStamp)
                        {
                            _perRangeDataList[i]._timeStamp=timeStamp;
                            _perRangeDataList[i]._frameNumber=frameNumber;
                        }

                        _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;
                        
_perRangeDataList[numChildren-1]._frameNumber=frameNumber;
                    }
                    _children[numChildren-1]->accept(nv);
                }

                // now request the loading of the next unloaded child.
                if (!_disableExternalChildrenPaging &&
                    nv.getDatabaseRequestHandler() &&
                    numChildren<_perRangeDataList.size())
                {
                    // compute priority from where abouts in the required range 
the distance falls.
                    float priority = 
(_rangeList[numChildren].second-required_range)/(_rangeList[numChildren].second-_rangeList[numChildren].first);

                    // invert priority for PIXEL_SIZE_ON_SCREEN mode
                    if(_rangeMode==PIXEL_SIZE_ON_SCREEN)
                    {
                        priority = -priority;
                    }

                    // 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,nv.getNodePath(),priority,nv.getFrameStamp(),
 _perRangeDataList[numChildren]._databaseRequest, _databaseOptions.get());
                    }
                    else
                    {
                        // prepend the databasePath to the child's filename.
                        
nv.getDatabaseRequestHandler()->requestNodeFile(_databasePath+_perRangeDataList[numChildren]._filename,nv.getNodePath(),priority,nv.getFrameStamp(),
 _perRangeDataList[numChildren]._databaseRequest, _databaseOptions.get());
                    }
                }

            }


           break;
        }
        default:
            break;
    }
}


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()-1);
        return true;
    }
    return false;
}

bool PagedLOD::addChild(Node *child, float min, float max)
{
    if (LOD::addChild(child,min,max))
    {
        expandPerRangeDataTo(_children.size()-1);
        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::removeChildren( unsigned int pos,unsigned int 
numChildrenToRemove)
{
    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);
}

bool PagedLOD::removeExpiredChildren(double expiryTime, unsigned int 
expiryFrame, NodeList& removedChildren)
{
    if (_children.size()>_numChildrenThatCannotBeExpired)
    {
        unsigned cindex = _children.size() - 1;
        if (!_perRangeDataList[cindex]._filename.empty() &&
            _perRangeDataList[cindex]._timeStamp + 
_perRangeDataList[cindex]._minExpiryTime < expiryTime &&
            _perRangeDataList[cindex]._frameNumber + 
_perRangeDataList[cindex]._minExpiryFrames < expiryFrame)
        {            
            osg::Node* nodeToRemove = _children[cindex].get();
            removedChildren.push_back(nodeToRemove);
            return Group::removeChildren(cindex,1);
        }
    }
    return false;
}
_______________________________________________
osg-submissions mailing list
[email protected]
http://lists.openscenegraph.org/listinfo.cgi/osg-submissions-openscenegraph.org

Reply via email to