void MPTerrainEngineNode::traverse(osg::NodeVisitor& nv) { if ( nv.getVisitorType() == nv.CULL_VISITOR ) { // since the root tiles are manually added, the pager never has a change to // register the PagedLODs in their children. So we have to do it manually here. if ( !_rootTilesRegistered ) { Threading::ScopedMutexLock lock(_rootTilesRegisteredMutex); if ( !_rootTilesRegistered ) { osgDB::DatabasePager* pager = dynamic_cast<osgDB::DatabasePager*>(nv.getDatabaseRequestHandler()); if ( pager ) { //OE_WARN << "Registering plods." << std::endl; pager->registerPagedLODs( _terrain ); _rootTilesRegistered = true; } } } } #if 0 static int c = 0; if ( ++c % 60 == 0 ) OE_NOTICE << LC << "Live tiles = " << _liveTiles->size() << std::endl; #endif TerrainEngineNode::traverse( nv ); }
void MPTerrainEngineNode::traverse(osg::NodeVisitor& nv) { if ( nv.getVisitorType() == nv.CULL_VISITOR ) { #if 0 // believe this is now unnecessary // since the root tiles are manually added, the pager never has a chance to // register the PagedLODs in their children. So we have to do it manually here. if ( !_rootTilesRegistered ) { Threading::ScopedMutexLock lock(_rootTilesRegisteredMutex); if ( !_rootTilesRegistered ) { osgDB::DatabasePager* pager = dynamic_cast<osgDB::DatabasePager*>(nv.getDatabaseRequestHandler()); if ( pager ) { //OE_WARN << "Registering plods." << std::endl; pager->registerPagedLODs( _terrain ); _rootTilesRegistered = true; } } } #endif // Inform the registry of the current frame so that Tiles have access // to the information. if ( _liveTiles.valid() && nv.getFrameStamp() ) { _liveTiles->setTraversalFrame( nv.getFrameStamp()->getFrameNumber() ); } } #if 0 static int c = 0; if ( ++c % 60 == 0 ) { OE_NOTICE << LC << "Live = " << _liveTiles->size() << ", Dead = " << _deadTiles->size() << std::endl; _liveTiles->run( CheckForOrphans() ); } #endif TerrainEngineNode::traverse( nv ); }
bool PagerLoader::load(Loader::Request* request, float priority, osg::NodeVisitor& nv) { // check that the request is not already completed but unmerged: //if ( request && !request->isMerging() && nv.getDatabaseRequestHandler() ) if ( request && !request->isMerging() && !request->isFinished() && nv.getDatabaseRequestHandler() ) { //OE_INFO << LC << "load (" << request->getTileKey().str() << ")" << std::endl; unsigned fn = 0; if ( nv.getFrameStamp() ) { fn = nv.getFrameStamp()->getFrameNumber(); request->setFrameNumber( fn ); } bool addToRequestSet = false; // lock the request since multiple cull traversals might hit this function. request->lock(); { request->setState(Request::RUNNING); // remember the last tick at which this request was submitted request->_lastTick = osg::Timer::instance()->tick(); // update the priority request->_priority = priority; // timestamp it request->setFrameNumber( fn ); // incremenet the load count. request->_loadCount++; // if this is the first load request since idle, we need to remember this request. addToRequestSet = (request->_loadCount == 1); } request->unlock(); char filename[64]; sprintf(filename, "%u.%u.osgearth_rex_loader", request->_uid, _engineUID); //std::string filename = Stringify() << request->_uid << "." << _engineUID << ".osgearth_rex_loader"; // scale from LOD to 0..1 range, more or less // TODO: need to balance this with normal PagedLOD priority setup float scaledPriority = priority / 20.0f; nv.getDatabaseRequestHandler()->requestNodeFile( filename, _myNodePath, priority, nv.getFrameStamp(), request->_internalHandle, _dboptions.get() ); // remember the request: if ( true ) // addToRequestSet // Not sure whether we need to keep doing this in order keep it sorted -- check it out. { Threading::ScopedMutexLock lock( _requestsMutex ); _requests[request->getUID()] = request; } return true; } return false; }
// 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 RexTerrainEngineNode::traverse(osg::NodeVisitor& nv) { if ( nv.getVisitorType() == nv.CULL_VISITOR ) { // Inform the registry of the current frame so that Tiles have access // to the information. if ( _liveTiles.valid() && nv.getFrameStamp() ) { _liveTiles->setTraversalFrame( nv.getFrameStamp()->getFrameNumber() ); } } #if 0 static int c = 0; if ( ++c % 60 == 0 ) { OE_NOTICE << LC << "Live = " << _liveTiles->size() << ", Dead = " << _deadTiles->size() << std::endl; _liveTiles->run( CheckForOrphans() ); } #endif if ( nv.getVisitorType() == nv.CULL_VISITOR && _loader.valid() ) // ensures that postInitialize has run { osgUtil::CullVisitor* cv = static_cast<osgUtil::CullVisitor*>(&nv); this->getEngineContext()->startCull( cv ); TerrainCuller culler; culler.setFrameStamp(new osg::FrameStamp(*nv.getFrameStamp())); culler.setDatabaseRequestHandler(nv.getDatabaseRequestHandler()); culler.pushReferenceViewPoint(cv->getReferenceViewPoint()); culler.pushViewport(cv->getViewport()); culler.pushProjectionMatrix(cv->getProjectionMatrix()); culler.pushModelViewMatrix(cv->getModelViewMatrix(), cv->getCurrentCamera()->getReferenceFrame()); culler._camera = cv->getCurrentCamera(); culler._context = this->getEngineContext(); culler.setup(*_update_mapf, this->getEngineContext()->getRenderBindings(), getSurfaceStateSet()); // Assemble the terrain drawable: _terrain->accept(culler); // If we're using geometry pooling, optimize the drawable for shared state: if (getEngineContext()->getGeometryPool()->isEnabled()) { culler._terrain.sortDrawCommands(); } // The common stateset for the terrain: cv->pushStateSet(_terrain->getOrCreateStateSet()); // Push all the layers to draw on to the cull visitor, // keeping track of render order. LayerDrawable* lastLayer = 0L; unsigned order = 0; bool surfaceStateSetPushed = false; // OE_INFO << "CULL:\n"; for(LayerDrawableList::iterator i = culler._terrain.layers().begin(); i != culler._terrain.layers().end(); ++i) { if (!i->get()->_tiles.empty()) { lastLayer = i->get(); lastLayer->_order = -1; // if this is a RENDERTYPE_TILE, we need to activate the default surface state set. if (lastLayer->_layer && lastLayer->_layer->getRenderType() == Layer::RENDERTYPE_TILE) { lastLayer->_order = order++; if (!surfaceStateSetPushed) cv->pushStateSet(getSurfaceStateSet()); surfaceStateSetPushed = true; } else if (surfaceStateSetPushed) { cv->popStateSet(); surfaceStateSetPushed = false; } // OE_INFO << " Apply: " << (lastLayer->_layer ? lastLayer->_layer->getName() : "-1") << std::endl; cv->apply(*lastLayer); } } // The last layer to render must clear up the OSG state, // otherwise it will be corrupt and can lead to crashing. if (lastLayer) { lastLayer->_clearOsgState = true; } if (surfaceStateSetPushed) { cv->popStateSet(); surfaceStateSetPushed = false; } // pop the common terrain state set cv->popStateSet(); this->getEngineContext()->endCull( cv ); // traverse all the other children (geometry pool, loader/unloader, etc.) for (unsigned i = 0; i<getNumChildren(); ++i) { if (getChild(i) != _terrain.get()) getChild(i)->accept(nv); } } //else { TerrainEngineNode::traverse( nv ); } }
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; } }
void RexTerrainEngineNode::traverse(osg::NodeVisitor& nv) { if (nv.getVisitorType() == nv.UPDATE_VISITOR) { if (_renderModelUpdateRequired) { UpdateRenderModels visitor(_mapFrame); _terrain->accept(visitor); _renderModelUpdateRequired = false; } TerrainEngineNode::traverse( nv ); } else if ( nv.getVisitorType() == nv.CULL_VISITOR ) { // Inform the registry of the current frame so that Tiles have access // to the information. if ( _liveTiles.valid() && nv.getFrameStamp() ) { _liveTiles->setTraversalFrame( nv.getFrameStamp()->getFrameNumber() ); } osgUtil::CullVisitor* cv = static_cast<osgUtil::CullVisitor*>(&nv); getEngineContext()->startCull( cv ); TerrainCuller culler; culler.setFrameStamp(new osg::FrameStamp(*nv.getFrameStamp())); culler.setDatabaseRequestHandler(nv.getDatabaseRequestHandler()); culler.pushReferenceViewPoint(cv->getReferenceViewPoint()); culler.pushViewport(cv->getViewport()); culler.pushProjectionMatrix(cv->getProjectionMatrix()); culler.pushModelViewMatrix(cv->getModelViewMatrix(), cv->getCurrentCamera()->getReferenceFrame()); culler._camera = cv->getCurrentCamera(); culler._context = this->getEngineContext(); // Prepare the culler with the set of renderable layers: culler.setup(_mapFrame, this->getEngineContext()->getRenderBindings()); // Assemble the terrain drawable: _terrain->accept(culler); // If we're using geometry pooling, optimize the drawable for shared state: if (getEngineContext()->getGeometryPool()->isEnabled()) { culler._terrain.sortDrawCommands(); } // The common stateset for the terrain: cv->pushStateSet(_terrain->getOrCreateStateSet()); // Push all the layers to draw on to the cull visitor, // keeping track of render order. LayerDrawable* lastLayer = 0L; unsigned order = 0; bool surfaceStateSetPushed = false; //OE_INFO << "CULL\n"; for(LayerDrawableList::iterator i = culler._terrain.layers().begin(); i != culler._terrain.layers().end(); ++i) { if (!i->get()->_tiles.empty()) { lastLayer = i->get(); lastLayer->_order = -1; // if this is a RENDERTYPE_TILE, we need to activate the default surface state set. if (lastLayer->_renderType == Layer::RENDERTYPE_TILE) { lastLayer->_order = order++; if (!surfaceStateSetPushed) cv->pushStateSet(getSurfaceStateSet()); surfaceStateSetPushed = true; } else if (surfaceStateSetPushed) { cv->popStateSet(); surfaceStateSetPushed = false; } //OE_INFO << " Apply: " << (lastLayer->_layer ? lastLayer->_layer->getName() : "-1") << "; tiles=" << lastLayer->_tiles.size() << std::endl; cv->apply(*lastLayer); } } // The last layer to render must clear up the OSG state, // otherwise it will be corrupt and can lead to crashing. if (lastLayer) { lastLayer->_clearOsgState = true; } if (surfaceStateSetPushed) { cv->popStateSet(); surfaceStateSetPushed = false; } // pop the common terrain state set cv->popStateSet(); this->getEngineContext()->endCull( cv ); // If the culler found any orphaned data, we need to update the render model // during the next update cycle. if (culler._orphanedPassesDetected > 0u) { _renderModelUpdateRequired = true; OE_INFO << LC << "Detected " << culler._orphanedPassesDetected << " orphaned rendering passes\n"; } // we don't call this b/c we don't want _terrain //TerrainEngineNode::traverse(nv); // traverse all the other children (geometry pool, loader/unloader, etc.) _geometryPool->accept(nv); _loader->accept(nv); _unloader->accept(nv); _releaser->accept(nv); _rasterizer->accept(nv); } else { TerrainEngineNode::traverse( nv ); } }