Пример #1
0
void TerrainTile::traverse(osg::NodeVisitor& nv)
{
    if (!_hasBeenTraversal)
    {
        if (!_terrain)
        {
            osg::NodePath& nodePath = nv.getNodePath();
            if (!nodePath.empty())
            {
                for(osg::NodePath::reverse_iterator itr = nodePath.rbegin();
                    itr != nodePath.rend() && !_terrain;
                    ++itr)
                {
                    osgTerrain::Terrain* ts = dynamic_cast<Terrain*>(*itr);
                    if (ts)
                    {
                        OSG_INFO<<"Assigning terrain system "<<ts<<std::endl;
                        setTerrain(ts);
                    }
                }
            }
        }

        init(getDirtyMask(), false);

        _hasBeenTraversal = true;
    }

    if (nv.getVisitorType()==osg::NodeVisitor::CULL_VISITOR)
    {
        osg::ClusterCullingCallback* ccc = dynamic_cast<osg::ClusterCullingCallback*>(getCullCallback());
        if (ccc)
        {
            if (ccc->cull(&nv,0,static_cast<State *>(0))) return;
        }
    }

    if (_terrainTechnique.valid())
    {
        _terrainTechnique->traverse(nv);
    }
    else
    {
        osg::Group::traverse(nv);
    }
}
Пример #2
0
void VolumeTile::traverse(osg::NodeVisitor& nv)
{
    if (!_hasBeenTraversal)
    {
        if (!_volume)
        {
            osg::NodePath& nodePath = nv.getNodePath();
            if (!nodePath.empty())
            {
                for(osg::NodePath::reverse_iterator itr = nodePath.rbegin();
                    itr != nodePath.rend() && !_volume;
                    ++itr)
                {
                    osgVolume::Volume* volume = dynamic_cast<Volume*>(*itr);
                    if (volume)
                    {
                        OSG_INFO<<"Assigning volume system "<<volume<<std::endl;
                        setVolume(volume);
                    }
                }
            }
        }

        _hasBeenTraversal = true;
    }

    if (nv.getVisitorType()==osg::NodeVisitor::UPDATE_VISITOR &&
        _layer->requiresUpdateTraversal())
    {
        _layer->update(nv);
    }

    if (_volumeTechnique.valid())
    {
        _volumeTechnique->traverse(nv);
    }
    else
    {
        osg::Group::traverse(nv);
    }
}
Пример #3
0
void
DrapingCullSet::accept(osg::NodeVisitor& nv)
{
    if ( nv.getVisitorType() == nv.CULL_VISITOR )
    {
        osgUtil::CullVisitor* cv = static_cast<osgUtil::CullVisitor*>( &nv );

        // We will use the visitor's path to prevent doubely-applying the statesets
        // of common ancestors
        const osg::NodePath& nvPath = nv.getNodePath();

        int frame = nv.getFrameStamp() ? nv.getFrameStamp()->getFrameNumber() : 0u;

        for( std::vector<Entry>::iterator entry = _entries.begin(); entry != _entries.end(); ++entry )
        {
            if ( frame - entry->_frame > 1 )
                continue;

            // If there's an active (non-identity matrix), apply it
            if ( entry->_matrix.valid() )
            {
                entry->_matrix->postMult( *cv->getModelViewMatrix() );
                cv->pushModelViewMatrix( entry->_matrix.get(), osg::Transform::RELATIVE_RF );
            }

            // After pushing the matrix, we can perform the culling bounds test.
            if ( !cv->isCulled( entry->_node->getBound() ) )
            {
                // Apply the statesets in the entry's node path, but skip over the ones that are
                // shared with the current visitor's path since they are already in effect.
                // Count them so we can pop them later.
                int numStateSets = 0;
                osg::RefNodePath nodePath;
                if ( entry->_path.getRefNodePath(nodePath) )
                {
                    for(unsigned i=0; i<nodePath.size(); ++i)
                    {
                        if (nodePath[i].valid())
                        {
                            if (i >= nvPath.size() || nvPath[i] != nodePath[i].get())
                            {
                                osg::StateSet* stateSet = nodePath[i]->getStateSet();
                                if ( stateSet )
                                {
                                    cv->pushStateSet( stateSet );
                                    ++numStateSets;
                                }
                            }
                        }
                    }
                }

                // Cull the DrapeableNode's children (but not the DrapeableNode itself!)
                // TODO: make sure we aren't skipping any cull callbacks, etc. by calling traverse 
                // instead of accept. (Cannot call accept b/c that calls traverse)
                for(unsigned i=0; i<entry->_node->getNumChildren(); ++i)
                {
                    entry->_node->getChild(i)->accept( nv );
                }
            
                // pop the same number we pushed
                for(int i=0; i<numStateSets; ++i)
                {
                    cv->popStateSet();
                }
            }

            // pop the model view:
            if ( entry->_matrix.valid() )
            {
                cv->popModelViewMatrix();
            }
        }

        // mark this set so it will reset for the next frame
        _frameCulled = true;
    }

    else
    {
        for( std::vector<Entry>::iterator entry = _entries.begin(); entry != _entries.end(); ++entry )
        {
            
        }
    }
}
Пример #4
0
void SoundNode::traverse(osg::NodeVisitor &nv)
{
    // continue only if the visitor actually is a cull visitor
    if (nv.getVisitorType() == osg::NodeVisitor::CULL_VISITOR)
    {
        // Make sure we only execute this once during this frame.
        // There could be two or more culls for stereo/multipipe...
        if (!m_sound_state.valid()) {
            // call the inherited method
            osg::notify(osg::DEBUG_INFO) << "SoundNode::traverse() No soundstate attached to soundnode" << std::endl;
            Node::traverse(nv);
            return;
        }
        if ( m_sound_state.valid() && nv.getTraversalNumber() != m_last_traversal_number && nv.getFrameStamp())
        {

            m_last_traversal_number = nv.getTraversalNumber();

            // retrieve the current time
            double t = nv.getFrameStamp()->getReferenceTime();
            double time = t - m_last_time;

            if(time >= m_sound_manager->getUpdateFrequency()) {

                osg::Matrix m;
                m = osg::computeLocalToWorld(nv.getNodePath());

                osg::Vec3 pos = m.getTrans();

                m_sound_state->setPosition(pos);

                //Calculate velocity
                osg::Vec3 velocity(0,0,0);

                if (m_first_run) {
                    m_first_run = false;
                    m_last_time = t;
                    m_last_pos = pos;
                }
                else {
                    velocity = pos - m_last_pos;
                    m_last_pos = pos;
                    m_last_time = t;
                    velocity /= time;
                }

                if(m_sound_manager->getClampVelocity()) {
                    float max_vel = m_sound_manager->getMaxVelocity();
                    float len = velocity.length();
                    if ( len > max_vel) {
                        velocity.normalize();
                        velocity *= max_vel;
                    }
                }

                m_sound_state->setVelocity(velocity);

                //Get new direction
                osg::Vec3 dir(0,1,0);

                dir = dir * m;
                dir.normalize();
                m_sound_state->setDirection(dir);      

                // Only do occlusion calculations if the sound is playing
                if (m_sound_state->getPlay() && m_occlude_callback.valid())
                    m_occlude_callback->apply(m_sound_manager->getListenerMatrix(), pos, m_sound_state.get());
            } // if
        }
    } // if cullvisitor

    // call the inherited method
    Node::traverse(nv);
}
Пример #5
0
void
ClampingCullSet::accept(osg::NodeVisitor& nv)
{
    if ( nv.getVisitorType() == nv.CULL_VISITOR )
    {
        ProxyCullVisitor* cv = dynamic_cast<ProxyCullVisitor*>(&nv);

        // We will use the visitor's path to prevent doubely-applying the statesets
        // of common ancestors
        const osg::NodePath& nvPath = nv.getNodePath();

        int frame = nv.getFrameStamp() ? nv.getFrameStamp()->getFrameNumber() : 0u;

        unsigned passed = 0u;

        for( std::vector<Entry>::iterator entry = _entries.begin(); entry != _entries.end(); ++entry )
        {
            if ( frame - entry->_frame > 1 )
                continue;

            // If there's an active (non-identity matrix), apply it
            if ( entry->_matrix.valid() )
            {
                entry->_matrix->postMult( *cv->getModelViewMatrix() );
                cv->pushModelViewMatrix( entry->_matrix.get(), osg::Transform::RELATIVE_RF );
            }

            // After pushing the matrix, we can perform the culling bounds test.
            if (!cv->isCulledByProxyFrustum(*entry->_node.get()))
            {
                // Apply the statesets in the entry's node path, but skip over the ones that are
                // shared with the current visitor's path since they are already in effect.
                // Count them so we can pop them later.
                int numStateSets = 0;
                osg::RefNodePath nodePath;
                if ( entry->_path.getRefNodePath(nodePath) )
                {
                    for(unsigned i=0; i<nodePath.size(); ++i)
                    {
                        if (nodePath[i].valid())
                        {
                            if (i >= nvPath.size() || nvPath[i] != nodePath[i].get())
                            {
                                osg::StateSet* stateSet = nodePath[i]->getStateSet();
                                if ( stateSet )
                                {
                                    cv->getCullVisitor()->pushStateSet( stateSet );
                                    ++numStateSets;
                                }
                            }
                        }
                    }
                }

                // Cull the DrapeableNode's children (but not the DrapeableNode itself!)
                for(unsigned i=0; i<entry->_node->getNumChildren(); ++i)
                {
                    entry->_node->getChild(i)->accept( nv );
                }
            
                // pop the same number we pushed
                for(int i=0; i<numStateSets; ++i)
                {
                    cv->getCullVisitor()->popStateSet();
                }

                ++passed;
            }

            // pop the model view:
            if ( entry->_matrix.valid() )
            {
                cv->popModelViewMatrix();
            }
            
            //Registry::instance()->startActivity("ClampingCullSet", Stringify() << std::hex << this << std::dec << " / " << passed << "/" << _entries.size());
        }

        // mark this set so it will reset for the next frame
        _frameCulled = true;
    }
}
Пример #6
0
// MOST of this is copied and pasted from OSG's osg::PagedLOD::traverse,
// except where otherwise noted with an "osgEarth" comment.
void
TilePagedLOD::traverse(osg::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());
        
        // osgEarth: update our progress tracker to prevent tile cancelation.
        if (_progress.valid())
        {
            _progress->update( 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(osg::NodeVisitor::TRAVERSE_ALL_CHILDREN):
            std::for_each(_children.begin(),_children.end(),osg::NodeAcceptOp(nv));
            break;
        case(osg::NodeVisitor::TRAVERSE_ACTIVE_CHILDREN):
        {
            osg::ref_ptr<MPTerrainEngineNode> engine;
            MPTerrainEngineNode::getEngineByUID( _engineUID, engine );
            if (!engine.valid())
                return;

            // Compute the required range.
            float required_range = -1.0;
            if (engine->getComputeRangeCallback())
            {                
                required_range = (*engine->getComputeRangeCallback())(this, nv);
            }            

            // If we don't have a callback or it return a negative number fallback on the original calculation.
            if (required_range < 0.0)
            {
                if (_rangeMode==DISTANCE_FROM_EYE_POINT)
                {
                    required_range = nv.getDistanceToViewPoint(getCenter(),true);

                    if (_rangeFactor.isSet())
                        required_range /= _rangeFactor.get();
                }
                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;
                    }
                }
            }

#ifdef INHERIT_VIEWPOINT_CAMERAS_CANNOT_SUBDIVIDE
            // Prevents an INHERIT_VIEWPOINT camera from invoking tile subdivision
            if (needToLoadChild)
            {
                osgUtil::CullVisitor* cv = dynamic_cast<osgUtil::CullVisitor*>(&nv);
                if ( cv && cv->getCurrentCamera() && cv->getCurrentCamera()->getReferenceFrame() == osg::Camera::ABSOLUTE_RF_INHERIT_VIEWPOINT )
                    needToLoadChild = false;
            }
#endif

            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())
                {
                    // osgEarth: Perform a tile visibility check before requesting the new tile.
                    // Intersect the tile's earth-aligned bounding box with the current culling frustum.
                    bool tileIsVisible = true;

                    if (nv.getVisitorType() == nv.CULL_VISITOR &&
                        numChildren < _childBBoxes.size() &&
                        _childBBoxes[numChildren].valid())
                    {
                        osgUtil::CullVisitor* cv = Culling::asCullVisitor( nv );
                        // wish that CullStack::createOrReuseRefMatrix() was public
                        osg::ref_ptr<osg::RefMatrix> mvm = new osg::RefMatrix(*cv->getModelViewMatrix());
                        mvm->preMult( _childBBoxMatrices[numChildren] );
                        cv->pushModelViewMatrix( mvm.get(), osg::Transform::RELATIVE_RF );
                        tileIsVisible = !cv->isCulled( _childBBoxes[numChildren] );
                        cv->popModelViewMatrix();
                    }

                    if ( tileIsVisible )
                    {
                        // [end:osgEarth]

                        // 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 PrecipitationEffect::traverse(osg::NodeVisitor& nv)
{
    if (nv.getVisitorType() == osg::NodeVisitor::UPDATE_VISITOR)
    {
        if (_dirty) update();

        if (nv.getFrameStamp())
        {
            double currentTime = nv.getFrameStamp()->getSimulationTime();
            if (_previousFrameTime==FLT_MAX) _previousFrameTime = currentTime;

            double delta = currentTime - _previousFrameTime;
            _origin += _wind * delta;
            _previousFrameTime = currentTime;
        }

        return;
    }

    if (nv.getVisitorType() == osg::NodeVisitor::NODE_VISITOR)
    {
        if (_dirty) update();

        osgUtil::GLObjectsVisitor* globjVisitor = dynamic_cast<osgUtil::GLObjectsVisitor*>(&nv);
        if (globjVisitor)
        {
            if (globjVisitor->getMode() & osgUtil::GLObjectsVisitor::COMPILE_STATE_ATTRIBUTES)
            {
                compileGLObjects(globjVisitor->getRenderInfo());
            }
        }

        return;
    }


    if (nv.getVisitorType() != osg::NodeVisitor::CULL_VISITOR)
    {
        return;
    }

    osgUtil::CullVisitor* cv = dynamic_cast<osgUtil::CullVisitor*>(&nv);
    if (!cv)
    {
        return;
    }

    ViewIdentifier viewIndentifier(cv, nv.getNodePath());

    {
        PrecipitationDrawableSet* precipitationDrawableSet = 0;

        {
            OpenThreads::ScopedLock<OpenThreads::Mutex> lock(_mutex);
            precipitationDrawableSet = &(_viewDrawableMap[viewIndentifier]);

            if (!precipitationDrawableSet->_quadPrecipitationDrawable)
            {
                precipitationDrawableSet->_quadPrecipitationDrawable = new PrecipitationDrawable;
                precipitationDrawableSet->_quadPrecipitationDrawable->setRequiresPreviousMatrix(true);
                precipitationDrawableSet->_quadPrecipitationDrawable->setGeometry(_quadGeometry.get());
                precipitationDrawableSet->_quadPrecipitationDrawable->setStateSet(_quadStateSet.get());
                precipitationDrawableSet->_quadPrecipitationDrawable->setDrawType(GL_QUADS);

                precipitationDrawableSet->_linePrecipitationDrawable = new PrecipitationDrawable;
                precipitationDrawableSet->_linePrecipitationDrawable->setRequiresPreviousMatrix(true);
                precipitationDrawableSet->_linePrecipitationDrawable->setGeometry(_lineGeometry.get());
                precipitationDrawableSet->_linePrecipitationDrawable->setStateSet(_lineStateSet.get());
                precipitationDrawableSet->_linePrecipitationDrawable->setDrawType(GL_LINES);

                precipitationDrawableSet->_pointPrecipitationDrawable = new PrecipitationDrawable;
                precipitationDrawableSet->_pointPrecipitationDrawable->setRequiresPreviousMatrix(false);
                precipitationDrawableSet->_pointPrecipitationDrawable->setGeometry(_pointGeometry.get());
                precipitationDrawableSet->_pointPrecipitationDrawable->setStateSet(_pointStateSet.get());
                precipitationDrawableSet->_pointPrecipitationDrawable->setDrawType(GL_POINTS);
            }
        }

        cull(*precipitationDrawableSet, cv);

        cv->pushStateSet(_stateset.get());
        float depth = 0.0f;

        if (!precipitationDrawableSet->_quadPrecipitationDrawable->getCurrentCellMatrixMap().empty())
        {
            cv->pushStateSet(precipitationDrawableSet->_quadPrecipitationDrawable->getStateSet());
            cv->addDrawableAndDepth(precipitationDrawableSet->_quadPrecipitationDrawable.get(),cv->getModelViewMatrix(),depth);
            cv->popStateSet();
        }

        if (!precipitationDrawableSet->_linePrecipitationDrawable->getCurrentCellMatrixMap().empty())
        {
            cv->pushStateSet(precipitationDrawableSet->_linePrecipitationDrawable->getStateSet());
            cv->addDrawableAndDepth(precipitationDrawableSet->_linePrecipitationDrawable.get(),cv->getModelViewMatrix(),depth);
            cv->popStateSet();
        }

        if (!precipitationDrawableSet->_pointPrecipitationDrawable->getCurrentCellMatrixMap().empty())
        {
            cv->pushStateSet(precipitationDrawableSet->_pointPrecipitationDrawable->getStateSet());
            cv->addDrawableAndDepth(precipitationDrawableSet->_pointPrecipitationDrawable.get(),cv->getModelViewMatrix(),depth);
            cv->popStateSet();
        }

        cv->popStateSet();

    }
}
Пример #8
0
void Widget::updateFocus(osg::NodeVisitor& nv)
{
    osgGA::EventVisitor* ev = nv.asEventVisitor();
    osgGA::GUIActionAdapter* aa = ev ? ev->getActionAdapter() : 0;
    if (ev && aa)
    {
        osgGA::EventQueue::Events& events = ev->getEvents();
        for(osgGA::EventQueue::Events::iterator itr = events.begin();
            itr != events.end();
            ++itr)
        {
            osgGA::GUIEventAdapter* ea = (*itr)->asGUIEventAdapter();
            if (ea)
            {
                bool previousFocus = _hasEventFocus;
                if (_focusBehaviour==CLICK_TO_FOCUS)
                {
                    if (ea->getEventType()==osgGA::GUIEventAdapter::PUSH)
                    {
                        int numButtonsPressed = 0;
                        if (ea->getButtonMask()&osgGA::GUIEventAdapter::LEFT_MOUSE_BUTTON) ++numButtonsPressed;
                        if (ea->getButtonMask()&osgGA::GUIEventAdapter::MIDDLE_MOUSE_BUTTON) ++numButtonsPressed;
                        if (ea->getButtonMask()&osgGA::GUIEventAdapter::RIGHT_MOUSE_BUTTON) ++numButtonsPressed;

                        if (numButtonsPressed==1)
                        {
                            osgUtil::LineSegmentIntersector::Intersections intersections;
                            bool withinWidget = aa->computeIntersections(*ea, nv.getNodePath(), intersections);
                            if (withinWidget) _hasEventFocus = true;
                            else _hasEventFocus = false;
                        }
                    }
                }
                else if (_focusBehaviour==FOCUS_FOLLOWS_POINTER)
                {
                    bool checkWithinWidget = false;
                    if (!_hasEventFocus)
                    {
                        checkWithinWidget = (ea->getEventType()!=osgGA::GUIEventAdapter::FRAME) && ea->getButtonMask()==0;
                    }
                    else
                    {
                        // if mouse move or mouse release check to see if mouse still within widget to retain focus
                        if (ea->getEventType()==osgGA::GUIEventAdapter::MOVE)
                        {
                            checkWithinWidget = true;
                        }
                        else if (ea->getEventType()==osgGA::GUIEventAdapter::RELEASE)
                        {
                            // if no buttons pressed then check
                            if (ea->getButtonMask()==0) checkWithinWidget = true;
                        }
                    }

                    if (checkWithinWidget)
                    {
                        osgUtil::LineSegmentIntersector::Intersections intersections;
                        bool withinWidget = aa->computeIntersections(*ea, nv.getNodePath(), intersections);

                        _hasEventFocus = withinWidget;
                    }
                }

                if (previousFocus != _hasEventFocus)
                {
                    if (_hasEventFocus)
                    {
                        enter();
#if 0
                        if (view->getCameraManipulator())
                        {
                            view->getCameraManipulator()->finishAnimation();
                            view->requestContinuousUpdate( false );
                        }
#endif
                    }
                    else
                    {
                        leave();
                    }
                }

            }
        }
    }
}
Пример #9
0
void TXPPagedLOD::traverse(osg::NodeVisitor& nv)
{

    //TileMapper* tileMapper = dynamic_cast<TileMapper*>(nv.getUserData());
    //Modified by Brad Anderegg (May-27-08) because the black listing process appears to make tiles switch lods
    //when they clearly shouldnt, in the worst cases a tile will page out that is right in front of you.
    bool forceUseOfFirstChild = /*tileMapper ? (tileMapper->isNodeBlackListed(this)) :*/ false;

    double timeStamp = nv.getFrameStamp()?nv.getFrameStamp()->getReferenceTime():0.0;
    bool updateTimeStamp = nv.getVisitorType()==osg::NodeVisitor::CULL_VISITOR;
    unsigned int frameNumber = nv.getFrameStamp()?nv.getFrameStamp()->getFrameNumber():0;

    // 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());
    }

    switch(nv.getTraversalMode())
    {
        case(osg::NodeVisitor::TRAVERSE_ALL_CHILDREN):
            std::for_each(_children.begin(),_children.end(),osg::NodeAcceptOp(nv));
            break;
        case(osg::NodeVisitor::TRAVERSE_ACTIVE_CHILDREN):
        {
            float distance = nv.getDistanceToEyePoint(getCenter(),true);

            int lastChildTraversed = -1;
            bool needToLoadChild = false;

            unsigned maxRangeSize = _rangeList.size();
            if (maxRangeSize!=0 && forceUseOfFirstChild)
                maxRangeSize=1;

            for(unsigned int i=0;i<maxRangeSize;++i)
            {
                if (forceUseOfFirstChild ||
                    (_rangeList[i].first<=distance && distance<_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();

                //std::cout<<"PagedLOD::traverse() - falling back "<<std::endl;
                // select the last valid child.
                if (numChildren>0 && ((int)numChildren-1)!=lastChildTraversed)
                {
                    //std::cout<<"    to child "<<numChildren-1<<std::endl;
                    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;

                    //std::cout<<"    requesting child "<<_fileNameList[numChildren]<<" priotity = "<<priority<<std::endl;
                    nv.getDatabaseRequestHandler()->requestNodeFile(_perRangeDataList[numChildren]._filename,
                                                                    nv.getNodePath(),
                                                                    priority,
                                                                    nv.getFrameStamp(),
                                                                    _perRangeDataList[numChildren]._databaseRequest);
                }


            }


           break;
        }
        default:
            break;
    }
}