bool CacheSeed::cacheTile(const MapFrame& mapf, const TileKey& key ) const { bool gotData = false; for( ImageLayerVector::const_iterator i = mapf.imageLayers().begin(); i != mapf.imageLayers().end(); i++ ) { ImageLayer* layer = i->get(); if ( layer->isKeyValid( key ) ) { GeoImage image = layer->createImage( key ); if ( image.valid() ) gotData = true; } } if ( mapf.elevationLayers().size() > 0 ) { osg::ref_ptr<osg::HeightField> hf; mapf.getHeightField( key, false, hf ); if ( hf.valid() ) gotData = true; } return gotData; }
void StreamingTile::installRequests( const MapFrame& mapf, int stamp ) { StreamingTerrainNode* terrain = getStreamingTerrain(); OSGTileFactory* tileFactory = terrain->getTileFactory(); bool hasElevationLayer; { Threading::ScopedReadLock sharedLock( _tileLayersMutex ); hasElevationLayer = this->getElevationLayer() != NULL; } if ( hasElevationLayer ) { resetElevationRequests( mapf ); } // safely loop through the map layers and schedule imagery updates for each: for( ImageLayerVector::const_iterator i = mapf.imageLayers().begin(); i != mapf.imageLayers().end(); ++i ) { updateImagery( i->get(), mapf, tileFactory ); } _requestsInstalled = true; }
void StreamingTerrainNode::updateTaskServiceThreads( const MapFrame& mapf ) { //Get the maximum elevation weight float elevationWeight = 0.0f; for (ElevationLayerVector::const_iterator itr = mapf.elevationLayers().begin(); itr != mapf.elevationLayers().end(); ++itr) { ElevationLayer* layer = itr->get(); float w = layer->getElevationLayerOptions().loadingWeight().value(); if (w > elevationWeight) elevationWeight = w; } float totalImageWeight = 0.0f; for (ImageLayerVector::const_iterator itr = mapf.imageLayers().begin(); itr != mapf.imageLayers().end(); ++itr) { totalImageWeight += itr->get()->getImageLayerOptions().loadingWeight().value(); } float totalWeight = elevationWeight + totalImageWeight; if (elevationWeight > 0.0f) { //Determine how many threads each layer gets int numElevationThreads = (int)osg::round((float)_numLoadingThreads * (elevationWeight / totalWeight )); OE_INFO << LC << "Elevation Threads = " << numElevationThreads << std::endl; getElevationTaskService()->setNumThreads( numElevationThreads ); } for (ImageLayerVector::const_iterator itr = mapf.imageLayers().begin(); itr != mapf.imageLayers().end(); ++itr) { const TerrainLayerOptions& opt = itr->get()->getImageLayerOptions(); int imageThreads = (int)osg::round((float)_numLoadingThreads * (opt.loadingWeight().value() / totalWeight )); OE_INFO << LC << "Image Threads for " << itr->get()->getName() << " = " << imageThreads << std::endl; getImageryTaskService( itr->get()->getUID() )->setNumThreads( imageThreads ); } }
void TileModelFactory::createTileModel(const TileKey& key, const MapFrame& frame, bool accumulate, osg::ref_ptr<TileModel>& out_model, ProgressCallback* progress) { osg::ref_ptr<TileModel> model = new TileModel( frame.getRevision(), frame.getMapInfo() ); model->_useParentData = _terrainReqs->parentTexturesRequired(); model->_tileKey = key; model->_tileLocator = GeoLocator::createForKey(key, frame.getMapInfo()); OE_START_TIMER(fetch_imagery); // Fetch the image data and make color layers. unsigned index = 0; unsigned order = 0; for( ImageLayerVector::const_iterator i = frame.imageLayers().begin(); i != frame.imageLayers().end(); ++i ) { ImageLayer* layer = i->get(); if ( layer->getEnabled() && layer->isKeyInRange(key) ) { BuildColorData build; build.init( key, layer, order, frame.getMapInfo(), _terrainOptions, _liveTiles.get(), model.get() ); bool addedToModel = build.execute(progress); if ( addedToModel ) { // only bump the order if we added something to the data model. order++; } } } if (progress) progress->stats()["fetch_imagery_time"] += OE_STOP_TIMER(fetch_imagery); // make an elevation layer. OE_START_TIMER(fetch_elevation); buildElevation(key, frame, accumulate, _terrainReqs->elevationTexturesRequired(), model.get(), progress); if (progress) progress->stats()["fetch_elevation_time"] += OE_STOP_TIMER(fetch_elevation); // make a normal map layer (if necessary) if ( _terrainReqs->normalTexturesRequired() ) { OE_START_TIMER(fetch_normalmap); buildNormalMap(key, frame, accumulate, model.get(), progress); if (progress) progress->stats()["fetch_normalmap_time"] += OE_STOP_TIMER(fetch_normalmap); } // If nothing was added, not even a fallback heightfield, something went // horribly wrong. Leave without a tile model. Chances are that a parent tile // not not found in the live-tile registry. if ( model->_colorData.size() == 0 && !model->_elevationData.getHeightField() ) { return; } // OK we are making a tile, so if there's no heightfield yet, make an empty one (and mark it // as fallback data of course) if ( !model->_elevationData.getHeightField() ) { osg::HeightField* hf = HeightFieldUtils::createReferenceHeightField( key.getExtent(), 15, 15 ); model->_elevationData = TileModel::ElevationData( hf, GeoLocator::createForKey(key, frame.getMapInfo()), true ); } // look up the parent model and cache it. osg::ref_ptr<TileNode> parentTile; if ( _liveTiles->get(key.createParentKey(), parentTile) ) { model->_parentModel = parentTile->getTileModel(); } out_model = model.release(); }
void TileModelFactory::createTileModel(const TileKey& key, const MapFrame& frame, osg::ref_ptr<TileModel>& out_model) //, //bool& out_hasRealData) { osg::ref_ptr<TileModel> model = new TileModel( frame.getRevision(), frame.getMapInfo() ); model->_tileKey = key; model->_tileLocator = GeoLocator::createForKey(key, frame.getMapInfo()); // Fetch the image data and make color layers. unsigned order = 0; for( ImageLayerVector::const_iterator i = frame.imageLayers().begin(); i != frame.imageLayers().end(); ++i ) { ImageLayer* layer = i->get(); if ( layer->getEnabled() ) { BuildColorData build; build.init( key, layer, order, frame.getMapInfo(), _terrainOptions, model.get() ); bool addedToModel = build.execute(); if ( addedToModel ) { // only bump the order if we added something to the data model. order++; } } } // make an elevation layer. BuildElevationData build; build.init( key, frame, _terrainOptions, model.get(), _hfCache ); build.execute(); // Bail out now if there's no data to be had. if ( model->_colorData.size() == 0 && !model->_elevationData.getHeightField() ) { return; } // OK we are making a tile, so if there's no heightfield yet, make an empty one (and mark it // as fallback data of course) if ( !model->_elevationData.getHeightField() ) { osg::HeightField* hf = HeightFieldUtils::createReferenceHeightField( key.getExtent(), 15, 15 ); model->_elevationData = TileModel::ElevationData( hf, GeoLocator::createForKey(key, frame.getMapInfo()), true ); } // look up the parent model and cache it. osg::ref_ptr<TileNode> parentTile; if ( _liveTiles->get(key.createParentKey(), parentTile) ) model->_parentModel = parentTile->getTileModel(); out_model = model.release(); }
// called from the UPDATE TRAVERSAL, because this method can potentially alter // the scene graph. bool StreamingTile::serviceCompletedRequests( const MapFrame& mapf, bool tileTableLocked ) { //Don't do anything until we have been added to the scene graph if (!_hasBeenTraversed) return false; bool tileModified = false; if ( !_requestsInstalled ) return false; // First service the tile generator: if ( _tileGenRequest.valid() && _tileGenRequest->isCompleted() ) { CustomTerrainTechnique* tech = dynamic_cast<CustomTerrainTechnique*>( getTerrainTechnique() ); if ( tech ) { //TODO: consider waiting to apply if there are still more tile updates in the queue. if ( _tileUpdates.size() == 0 ) { tileModified = tech->applyTileUpdates(); } } _tileGenRequest = 0L; } // now deal with imagery. const LoadingPolicy& lp = getStreamingTerrain()->getLoadingPolicy(); StreamingTerrainNode* terrain = getStreamingTerrain(); //Check each layer independently. for( ImageLayerVector::const_iterator i = mapf.imageLayers().begin(); i != mapf.imageLayers().end(); ++i ) { ImageLayer* imageLayer = i->get(); bool checkForFinalImagery = false; CustomColorLayer colorLayer; if ( getCustomColorLayer( imageLayer->getUID(), colorLayer ) ) { if ( lp.mode() == LoadingPolicy::MODE_PREEMPTIVE ) { // in preemptive mode, always check for the final imagery - there are no intermediate // placeholders. checkForFinalImagery = true; } else if (lp.mode() == LoadingPolicy::MODE_SEQUENTIAL && readyForNewImagery(imageLayer, colorLayer.getLevelOfDetail()) ) { // in sequential mode, we have to incrementally increase imagery resolution by // creating placeholders based of parent tiles, one LOD at a time. if ( colorLayer.getLevelOfDetail() + 1 < (int)_key.getLevelOfDetail() ) { // if the parent's image LOD is higher than ours, replace ours with the parent's // since it is a higher-resolution placeholder: if ( _family[Relative::PARENT].getImageLOD(colorLayer.getUID()) > colorLayer.getLevelOfDetail() ) { osg::ref_ptr<Tile> parentTile; getStreamingTerrain()->getTile( _family[Relative::PARENT].tileID, parentTile, !tileTableLocked ); // Set the color layer to the parent color layer as a placeholder. CustomColorLayer parentColorLayer; if ( parentTile->getCustomColorLayer( colorLayer.getUID(), parentColorLayer ) ) { this->setCustomColorLayer( parentColorLayer ); } // ... and queue up an update request. queueTileUpdate( TileUpdate::UPDATE_IMAGE_LAYER, colorLayer.getUID() ); } } else { // we've gone as far as we can with placeholders; time to check for the // final imagery tile. checkForFinalImagery = true; } } } if ( checkForFinalImagery ) { // Then the image requests: for( TaskRequestList::iterator itr = _requests.begin(); itr != _requests.end(); ) { bool increment = true; TileColorLayerRequest* r = static_cast<TileColorLayerRequest*>( itr->get() ); //We only care about the current layer we are checking if ( r->_layerUID == imageLayer->getUID() ) { if ( itr->get()->isCompleted() ) { if ( r->wasCanceled() ) { //Reset the cancelled task to IDLE and give it a new progress callback. r->setState( TaskRequest::STATE_IDLE ); r->setProgressCallback( new StampedProgressCallback( r, terrain->getImageryTaskService( r->_layerUID ))); r->reset(); } else // success.. { //See if we even care about the request if ( !mapf.getImageLayerByUID( r->_layerUID ) ) { //The maplayer was probably deleted OE_DEBUG << "Layer uid=" << r->_layerUID << " no longer exists, ignoring TileColorLayerRequest " << std::endl; itr = _requests.erase(itr); increment = false; } else { CustomColorLayerRef* result = static_cast<CustomColorLayerRef*>( r->getResult() ); if ( result ) { this->setCustomColorLayer( result->_layer ); queueTileUpdate( TileUpdate::UPDATE_IMAGE_LAYER, r->_layerUID ); //OE_NOTICE << "Complete IR (" << _key.str() << ") layer=" << r->_layerId << std::endl; // remove from the list (don't reference "r" after this!) itr = _requests.erase( itr ); increment = false; } else { if (r->_numTries > r->_maxTries) { CustomColorLayer oldLayer; if ( this->getCustomColorLayer( r->_layerUID, oldLayer ) ) { // apply the old color layer but with a new LOD. this->setCustomColorLayer( CustomColorLayer( oldLayer.getMapLayer(), oldLayer.getImage(), oldLayer.getLocator(), _key.getLevelOfDetail(), _key )); itr = _requests.erase( itr ); increment = false; OE_DEBUG << "Tried (" << _key.str() << ") (layer uid=" << r->_layerUID << "), too many times, moving on...." << std::endl; } } else { OE_DEBUG << "IReq error (" << _key.str() << ") (layer uid=" << r->_layerUID << "), retrying" << std::endl; //The color layer request failed, probably due to a server error. Reset it. r->setState( TaskRequest::STATE_IDLE ); r->reset(); } } } } } } if ( increment ) ++itr; } } } // Finally, the elevation requests: if ( _hasElevation && !_elevationLayerUpToDate && _elevRequest.valid() && _elevPlaceholderRequest.valid() ) { // First, check is the Main elevation request is done. If so, we will now have the final HF data // and can shut down the elevation requests for this tile. if ( _elevRequest->isCompleted() ) { if ( _elevRequest->wasCanceled() ) { // If the request was canceled, reset it to IDLE and reset the callback. On the next _elevRequest->setState( TaskRequest::STATE_IDLE ); _elevRequest->setProgressCallback( new ProgressCallback() ); _elevRequest->reset(); } else // success: { // if the elevation request succeeded, install the new elevation layer! TileElevationLayerRequest* r = static_cast<TileElevationLayerRequest*>( _elevRequest.get() ); osg::ref_ptr<osgTerrain::HeightFieldLayer> newHFLayer = static_cast<osgTerrain::HeightFieldLayer*>( r->getResult() ); if ( newHFLayer.valid() && newHFLayer->getHeightField() != NULL ) { newHFLayer->getHeightField()->setSkirtHeight( terrain->getTileFactory()->getTerrainOptions().heightFieldSkirtRatio().get() * this->getBound().radius() ); // need to write-lock the layer data since we'll be changing it: { Threading::ScopedWriteLock lock( _tileLayersMutex ); this->setElevationLayer( newHFLayer.get() ); this->dirtyBound(); } // the tile needs rebuilding. This will kick off a TileGenRequest. queueTileUpdate( TileUpdate::UPDATE_ELEVATION ); // finalize the LOD marker for this tile, so other tiles can see where we are. _elevationLOD = _key.getLevelOfDetail(); #ifdef PREEMPTIVE_DEBUG OE_NOTICE << "Tile (" << _key.str() << ") final HF, LOD (" << _elevationLOD << ")" << std::endl; #endif // this was the final elev request, so mark elevation as DONE. _elevationLayerUpToDate = true; // GW- just reset these and leave them alone and let cancelRequests() take care of cleanup later. // done with our Elevation requests! //_elevRequest = 0L; //_elevPlaceholderRequest = 0L; } else { //We've tried to get the tile's elevation but couldn't. Just mark the elevation layer as up to date and move on. _elevationLOD = _key.getLevelOfDetail(); _elevationLayerUpToDate = true; //This code will retry indefinitely. We need to have a way to limit the number of retries since //it will block neighbor tiles from loading. //_elevRequest->setState( TaskRequest::STATE_IDLE ); //_elevRequest->reset(); } } } else if ( _elevPlaceholderRequest->isCompleted() ) { TileElevationPlaceholderLayerRequest* r = static_cast<TileElevationPlaceholderLayerRequest*>(_elevPlaceholderRequest.get()); if ( r->wasCanceled() ) { r->setState( TaskRequest::STATE_IDLE ); r->setProgressCallback( new ProgressCallback() ); r->reset(); } else // success: { osg::ref_ptr<osgTerrain::HeightFieldLayer> newPhLayer = static_cast<osgTerrain::HeightFieldLayer*>( r->getResult() ); if ( newPhLayer.valid() && newPhLayer->getHeightField() != NULL ) { // install the new elevation layer. { Threading::ScopedWriteLock lock( _tileLayersMutex ); this->setElevationLayer( newPhLayer.get() ); this->dirtyBound(); } // tile needs to be recompiled. queueTileUpdate( TileUpdate::UPDATE_ELEVATION ); // update the elevation LOD for this tile, now that the new HF data is installed. This will // allow other tiles to see where this tile's HF data is. _elevationLOD = r->_nextLOD; #ifdef PREEMPTIVE_DEBUG OE_NOTICE << "..tile (" << _key.str() << ") is now at (" << _elevationLOD << ")" << std::endl; #endif } _elevPlaceholderRequest->setState( TaskRequest::STATE_IDLE ); _elevPlaceholderRequest->reset(); } } } // if we have a new TileGenRequest, queue it up now. if ( _tileUpdates.size() > 0 && !_tileGenRequest.valid() ) // _tileGenNeeded && !_tileGenRequest.valid()) { _tileGenRequest = new TileGenRequest( this, _tileUpdates.front() ); _tileUpdates.pop(); //OE_NOTICE << "tile (" << _key.str() << ") queuing new tile gen" << std::endl; getStreamingTerrain()->getTileGenerationTaskService()->add( _tileGenRequest.get() ); } return tileModified; }