osgEarth 2.1.1
|
00001 /* -*-c++-*- */ 00002 /* osgEarth - Dynamic map generation toolkit for OpenSceneGraph 00003 * Copyright 2008-2010 Pelican Mapping 00004 * http://osgearth.org 00005 * 00006 * osgEarth is free software; you can redistribute it and/or modify 00007 * it under the terms of the GNU Lesser General Public License as published by 00008 * the Free Software Foundation; either version 2 of the License, or 00009 * (at your option) any later version. 00010 * 00011 * This program is distributed in the hope that it will be useful, 00012 * but WITHOUT ANY WARRANTY; without even the implied warranty of 00013 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 00014 * GNU Lesser General Public License for more details. 00015 * 00016 * You should have received a copy of the GNU Lesser General Public License 00017 * along with this program. If not, see <http://www.gnu.org/licenses/> 00018 */ 00019 #include "StreamingTile" 00020 #include "StreamingTerrain" 00021 #include "CustomTerrainTechnique" 00022 #include "TransparentLayer" 00023 00024 #include <osgEarth/Registry> 00025 #include <osgEarth/Locators> 00026 #include <osgEarth/Map> 00027 #include <osgEarth/FindNode> 00028 00029 #include <osg/NodeCallback> 00030 #include <osg/NodeVisitor> 00031 #include <osg/Node> 00032 #include <osg/Texture2D> 00033 #include <osgGA/EventVisitor> 00034 00035 #include <OpenThreads/ScopedLock> 00036 00037 using namespace osgEarth; 00038 using namespace OpenThreads; 00039 00040 #define LC "[StreamingTile] " 00041 00042 //---------------------------------------------------------------------------- 00043 00044 namespace 00045 { 00046 // this progress callback checks to see whether the request being serviced is 00047 // out of date with respect to the task service that is running it. It checks 00048 // for a disparity in frame stamps, and reports that the request should be 00049 // canceled if it appears the request has been abandoned by the Tile that 00050 // originally scheduled it. 00051 struct StampedProgressCallback : ProgressCallback 00052 { 00053 public: 00054 StampedProgressCallback(TaskRequest* request, TaskService* service): 00055 _request(request), 00056 _service(service) 00057 { 00058 } 00059 00060 //todo: maybe we should pass TaskRequest in as an argument 00061 bool reportProgress(double current, double total) 00062 { 00063 //Check to see if we were marked cancelled on a previous check 00064 if (_canceled) return _canceled; 00065 00066 _canceled = (_service->getStamp() - _request->getStamp() > 2); 00067 return _canceled; 00068 } 00069 00070 TaskRequest* _request; 00071 TaskService* _service; 00072 }; 00073 00074 00075 // NOTE: Task requests run in background threads. So we pass in a map frame and 00076 // make a clone of it to use in that thread. Each Task must have its own MapFrame 00077 // so it's operating in its own sandbox. 00078 00079 struct TileLayerRequest : public TaskRequest 00080 { 00081 TileLayerRequest( const TileKey& key, const MapFrame& mapf, OSGTileFactory* tileFactory ) 00082 : _key( key ), 00083 _mapf(mapf, "osgterrain.TileLayerRequest"), 00084 _tileFactory(tileFactory), 00085 _numTries(0), 00086 _maxTries(3) { } 00087 00088 TileKey _key; 00089 MapFrame _mapf; 00090 //osg::ref_ptr<Map> _map; 00091 osg::ref_ptr<OSGTileFactory> _tileFactory; 00092 unsigned int _numTries; 00093 unsigned int _maxTries; 00094 }; 00095 00096 struct TileColorLayerRequest : public TileLayerRequest 00097 { 00098 TileColorLayerRequest( const TileKey& key, const MapFrame& mapf, OSGTileFactory* tileFactory, UID layerUID ) 00099 : TileLayerRequest( key, mapf, tileFactory ), _layerUID(layerUID) { } 00100 00101 void operator()( ProgressCallback* progress ) 00102 { 00103 osg::ref_ptr<ImageLayer> imageLayer = _mapf.getImageLayerByUID( _layerUID ); 00104 if ( imageLayer.valid() ) 00105 { 00106 _result = _tileFactory->createImageLayer( _mapf.getMapInfo(), imageLayer.get(), _key, progress ); 00107 if (!wasCanceled()) 00108 { 00109 _numTries++; 00110 } 00111 } 00112 } 00113 UID _layerUID; 00114 }; 00115 00116 struct TileElevationLayerRequest : public TileLayerRequest 00117 { 00118 TileElevationLayerRequest( const TileKey& key, const MapFrame& mapf, OSGTileFactory* tileFactory ) 00119 : TileLayerRequest( key, mapf, tileFactory ) 00120 { 00121 //nop 00122 } 00123 00124 void operator()( ProgressCallback* progress ) 00125 { 00126 _result = _tileFactory->createHeightFieldLayer( _mapf, _key, true ); //exactOnly=true 00127 _numTries++; 00128 } 00129 }; 00130 00131 struct TileElevationPlaceholderLayerRequest : public TileLayerRequest 00132 { 00133 TileElevationPlaceholderLayerRequest( const TileKey& key, const MapFrame& mapf, OSGTileFactory* tileFactory, GeoLocator* keyLocator ) 00134 : TileLayerRequest( key, mapf, tileFactory ), 00135 _parentKey( key.createParentKey() ), 00136 _keyLocator(keyLocator) 00137 { 00138 //nop 00139 } 00140 00141 void setParentHF( osg::HeightField* parentHF ) 00142 { 00143 _parentHF = parentHF; 00144 } 00145 00146 void setNextLOD( int nextLOD ) 00147 { 00148 _nextLOD = nextLOD; 00149 } 00150 00151 void operator()( ProgressCallback* progress ) 00152 { 00153 if ( !progress->isCanceled() ) 00154 { 00155 _result = _tileFactory->createPlaceholderHeightfieldLayer( 00156 _parentHF.get(), 00157 _parentKey, 00158 _key, 00159 _keyLocator.get() ); 00160 } 00161 } 00162 00163 osg::ref_ptr<osg::HeightField> _parentHF; 00164 TileKey _parentKey; 00165 osg::ref_ptr<GeoLocator> _keyLocator; 00166 int _nextLOD; 00167 }; 00168 00169 // A task request that rebuilds a tile's terrain technique in the background. It 00170 // re-compiles the geometry but does NOT apply the updates (since this constitutes 00171 // altering the scene graph and must therefore be done in the update traversal). 00172 struct TileGenRequest : public TaskRequest 00173 { 00174 TileGenRequest( StreamingTile* tile, const TileUpdate& update ) : 00175 _tile( tile ), _update(update) { } 00176 00177 void operator()( ProgressCallback* progress ) 00178 { 00179 if (_tile.valid()) 00180 { 00181 CustomTerrainTechnique* tech = dynamic_cast<CustomTerrainTechnique*>( _tile->getTerrainTechnique() ); 00182 if (tech) 00183 { 00184 tech->compile( _update, progress ); 00185 } 00186 } 00187 00188 //We don't need the tile anymore 00189 _tile = NULL; 00190 } 00191 00192 osg::ref_ptr< StreamingTile > _tile; 00193 TileUpdate _update; 00194 }; 00195 } 00196 00197 //------------------------------------------------------------------------ 00198 00199 StreamingTile::StreamingTile(const TileKey& key, 00200 GeoLocator* keyLocator, 00201 bool quickReleaseGLObjects ) : 00202 00203 Tile( key, keyLocator, quickReleaseGLObjects ), 00204 00205 _requestsInstalled ( false ), 00206 _elevationLayerDirty ( false ), 00207 _colorLayersDirty ( false ), 00208 _elevationLayerUpToDate( true ), 00209 _elevationLOD ( key.getLevelOfDetail() ), 00210 _useTileGenRequest ( true ) 00211 { 00212 // because the lowest LOD (1) is always loaded fully: 00213 _elevationLayerUpToDate = _key.getLevelOfDetail() <= 1; 00214 } 00215 00216 StreamingTile::~StreamingTile() 00217 { 00218 //nop 00219 } 00220 00221 bool 00222 StreamingTile::cancelActiveTasks() 00223 { 00224 // This method ensures that all requests owned by this object are stopped and released 00225 // by the corresponding task service prior to destructing the tile. Called by 00226 // CustomTerrain::updateTileTable(). 00227 00228 bool done = true; 00229 00230 // Cancel all active requests 00231 if ( _requestsInstalled ) 00232 { 00233 for( TaskRequestList::iterator i = _requests.begin(); i != _requests.end(); ++i ) 00234 { 00235 i->get()->cancel(); 00236 } 00237 00238 if ( _elevRequest.valid() ) 00239 { 00240 _elevRequest->cancel(); 00241 } 00242 00243 if (_elevPlaceholderRequest.valid()) 00244 { 00245 _elevPlaceholderRequest->cancel(); 00246 } 00247 00248 if (_tileGenRequest.valid()) 00249 { 00250 _tileGenRequest->cancel(); 00251 } 00252 } 00253 00254 return done; 00255 } 00256 00257 void 00258 StreamingTile::setElevationLOD( int lod ) 00259 { 00260 _elevationLOD = lod; 00261 _elevationLayerUpToDate = _elevationLOD == (int)_key.getLevelOfDetail(); 00262 } 00263 00264 StreamingTerrain* 00265 StreamingTile::getStreamingTerrain() 00266 { 00267 return static_cast<StreamingTerrain*>( getTerrain() ); 00268 } 00269 00270 const StreamingTerrain* 00271 StreamingTile::getStreamingTerrain() const 00272 { 00273 return const_cast<StreamingTile*>(this)->getStreamingTerrain(); 00274 } 00275 00276 void 00277 StreamingTile::setHasElevationHint( bool hint ) 00278 { 00279 _hasElevation = hint; 00280 } 00281 00282 // returns TRUE if it's safe for this tile to load its next elevation data layer. 00283 bool 00284 StreamingTile::readyForNewElevation() 00285 { 00286 bool ready = true; 00287 00288 if ( _elevationLOD == (int)_key.getLevelOfDetail() ) 00289 { 00290 ready = false; 00291 } 00292 else if ( _family[Relative::PARENT].elevLOD < 0 ) 00293 { 00294 ready = false; 00295 } 00296 else 00297 { 00298 for( int i=Relative::PARENT; i<=Relative::SOUTH; i++) 00299 { 00300 if ( _family[i].expected && _family[i].elevLOD >= 0 && _family[i].elevLOD < _elevationLOD ) 00301 { 00302 ready = false; 00303 break; 00304 } 00305 } 00306 00307 // if the next LOD is not the final, but our placeholder is up to date, we're not ready. 00308 if ( ready && _elevationLOD+1 < (int)_key.getLevelOfDetail() && _elevationLOD == _family[Relative::PARENT].elevLOD ) 00309 { 00310 ready = false; 00311 } 00312 } 00313 00314 #ifdef PREEMPTIVE_DEBUG 00315 OE_NOTICE 00316 << "Tile (" << _key.str() << ") at (" << _elevationLOD << "), parent at (" 00317 << _family[PARENT].elevLOD << "), sibs at ("; 00318 if ( _family[WEST].expected ) osg::notify( osg::NOTICE ) << "W=" << _family[WEST].elevLOD << " "; 00319 if ( _family[NORTH].expected ) osg::notify( osg::NOTICE ) << "N=" << _family[NORTH].elevLOD << " "; 00320 if ( _family[EAST].expected ) osg::notify( osg::NOTICE ) << "E=" << _family[EAST].elevLOD << " "; 00321 if ( _family[SOUTH].expected ) osg::notify( osg::NOTICE ) << "S=" << _family[SOUTH].elevLOD << " "; 00322 OE_NOTICE << "), ready = " << (ready? "YES" : "no") << std::endl; 00323 #endif 00324 00325 return ready; 00326 } 00327 00328 00329 00330 // returns TRUE if it's safe for this tile to load its next elevation data layer. 00331 bool 00332 StreamingTile::readyForNewImagery(ImageLayer* layer, int currentLOD) 00333 { 00334 bool ready = true; 00335 00336 if ( currentLOD == (int)_key.getLevelOfDetail() ) 00337 { 00338 ready = false; 00339 } 00340 else if ( _family[Relative::PARENT].getImageLOD( layer->getUID() ) < 0 ) 00341 { 00342 ready = false; 00343 } 00344 else 00345 { 00346 for( int i=Relative::PARENT; i<=Relative::SOUTH; i++) 00347 { 00348 if (_family[i].expected && 00349 _family[i].getImageLOD( layer->getUID() ) >= 0 && 00350 _family[i].getImageLOD( layer->getUID() ) < currentLOD ) 00351 { 00352 ready = false; 00353 break; 00354 } 00355 } 00356 00357 // if the next LOD is not the final, but our placeholder is up to date, we're not ready. 00358 if (ready && 00359 currentLOD + 1 < (int)_key.getLevelOfDetail() && 00360 currentLOD == _family[Relative::PARENT].getImageLOD( layer->getUID() ) ) 00361 { 00362 ready = false; 00363 } 00364 } 00365 00366 return ready; 00367 } 00368 00369 00370 #define PRI_IMAGE_OFFSET 0.1f // priority offset of imagery relative to elevation 00371 #define PRI_LAYER_OFFSET 0.1f // priority offset of image layer(x) vs. image layer(x+1) 00372 00373 void 00374 StreamingTile::installRequests( const MapFrame& mapf, int stamp ) 00375 { 00376 StreamingTerrain* terrain = getStreamingTerrain(); 00377 OSGTileFactory* tileFactory = terrain->getTileFactory(); 00378 00379 bool hasElevationLayer; 00380 { 00381 Threading::ScopedReadLock sharedLock( _tileLayersMutex ); 00382 hasElevationLayer = this->getElevationLayer() != NULL; 00383 } 00384 00385 if ( hasElevationLayer ) 00386 { 00387 resetElevationRequests( mapf ); 00388 } 00389 00390 // safely loop through the map layers and schedule imagery updates for each: 00391 for( ImageLayerVector::const_iterator i = mapf.imageLayers().begin(); i != mapf.imageLayers().end(); ++i ) 00392 { 00393 updateImagery( i->get(), mapf, tileFactory ); 00394 } 00395 00396 _requestsInstalled = true; 00397 } 00398 00399 void 00400 StreamingTile::resetElevationRequests( const MapFrame& mapf ) 00401 { 00402 if (_elevRequest.valid() && _elevRequest->isRunning()) _elevRequest->cancel(); 00403 if (_elevPlaceholderRequest.valid() && _elevPlaceholderRequest->isRunning()) _elevPlaceholderRequest->cancel(); 00404 00405 StreamingTerrain* terrain = getStreamingTerrain(); 00406 00407 // this request will load real elevation data for the tile: 00408 _elevRequest = new TileElevationLayerRequest(_key, mapf, terrain->getTileFactory()); 00409 float priority = (float)_key.getLevelOfDetail(); 00410 _elevRequest->setPriority( priority ); 00411 std::stringstream ss; 00412 ss << "TileElevationLayerRequest " << _key.str() << std::endl; 00413 std::string ssStr; 00414 ssStr = ss.str(); 00415 _elevRequest->setName( ssStr ); 00416 00417 // this request will load placeholder elevation data for the tile: 00418 _elevPlaceholderRequest = new TileElevationPlaceholderLayerRequest( 00419 _key, mapf, terrain->getTileFactory(), _locator.get() ); 00420 00421 _elevPlaceholderRequest->setPriority( priority ); 00422 ss.str(""); 00423 ss << "TileElevationPlaceholderLayerRequest " << _key.str() << std::endl; 00424 ssStr = ss.str(); 00425 _elevPlaceholderRequest->setName( ssStr ); 00426 } 00427 00428 00429 // called from installRequests (cull traversal) or terrainengine (main thread) ... so be careful! 00430 // 00431 // this method queues up a new tile imagery request, superceding any existing request that 00432 // might be in the queue. 00433 void 00434 StreamingTile::updateImagery( ImageLayer* imageLayer, const MapFrame& mapf, OSGTileFactory* tileFactory) 00435 { 00436 StreamingTerrain* terrain = getStreamingTerrain(); 00437 00438 // imagery is slighty higher priority than elevation data 00439 TaskRequest* r = new TileColorLayerRequest( _key, mapf, tileFactory, imageLayer->getUID() ); 00440 std::stringstream ss; 00441 ss << "TileColorLayerRequest " << _key.str() << std::endl; 00442 std::string ssStr; 00443 ssStr = ss.str(); 00444 r->setName( ssStr ); 00445 r->setState( osgEarth::TaskRequest::STATE_IDLE ); 00446 00447 // in image-sequential mode, we want to prioritize lower-LOD imagery since it 00448 // needs to come in before higher-resolution stuff. 00449 if ( terrain->getLoadingPolicy().mode() == LoadingPolicy::MODE_SEQUENTIAL ) 00450 { 00451 r->setPriority( -(float)_key.getLevelOfDetail() + PRI_IMAGE_OFFSET ); 00452 } 00453 00454 // in image-preemptive mode, the highest LOD should get higher load priority: 00455 else // MODE_PREEMPTIVE 00456 { 00457 r->setPriority( PRI_IMAGE_OFFSET + (float)_key.getLevelOfDetail()); 00458 } 00459 00460 r->setProgressCallback( new StampedProgressCallback( 00461 r, 00462 terrain->getImageryTaskService( imageLayer->getUID() ) ) ); 00463 00464 //If we already have a request for this layer, remove it from the list and use the new one 00465 for( TaskRequestList::iterator i = _requests.begin(); i != _requests.end(); ) 00466 { 00467 TileColorLayerRequest* r2 = static_cast<TileColorLayerRequest*>( i->get() ); 00468 if ( r2->_layerUID == imageLayer->getUID() ) 00469 i = _requests.erase( i ); 00470 else 00471 ++i; 00472 } 00473 00474 //Add the new imagery request 00475 _requests.push_back( r ); 00476 } 00477 00478 // This method is called during the UPDATE TRAVERSAL in StreamingTerrain. 00479 void 00480 StreamingTile::servicePendingImageRequests( const MapFrame& mapf, int stamp ) 00481 { 00482 // Don't do anything until we have been added to the scene graph 00483 if ( !_hasBeenTraversed ) return; 00484 00485 // install our requests if they are not already installed: 00486 if ( !_requestsInstalled ) 00487 { 00488 // since we're in the CULL thread, use the cull thread map frame: 00489 installRequests( mapf, stamp ); 00490 } 00491 00492 for( TaskRequestList::iterator i = _requests.begin(); i != _requests.end(); ++i ) 00493 { 00494 TileColorLayerRequest* r = static_cast<TileColorLayerRequest*>( i->get() ); 00495 00496 //If a request has been marked as IDLE, the TaskService has tried to service it 00497 //and it was either deemed out of date or was cancelled, so we need to add it again. 00498 if ( r->isIdle() ) 00499 { 00500 //OE_NOTICE << "Queuing IR (" << _key.str() << ")" << std::endl; 00501 r->setStamp( stamp ); 00502 getStreamingTerrain()->getImageryTaskService( r->_layerUID )->add( r ); 00503 } 00504 else if ( !r->isCompleted() ) 00505 { 00506 r->setStamp( stamp ); 00507 } 00508 } 00509 } 00510 00511 // This method is called from the UPDATE TRAVERSAL, from CustomTerrain::traverse. 00512 void 00513 StreamingTile::servicePendingElevationRequests( const MapFrame& mapf, int stamp, bool tileTableLocked ) 00514 { 00515 //Don't do anything until we have been added to the scene graph 00516 if ( !_hasBeenTraversed ) return; 00517 00518 // install our requests if they are not already installed: 00519 if ( !_requestsInstalled ) 00520 { 00521 installRequests( mapf, stamp ); 00522 } 00523 00524 if ( _hasElevation && !_elevationLayerUpToDate && _elevRequest.valid() && _elevPlaceholderRequest.valid() ) 00525 { 00526 StreamingTerrain* terrain = getStreamingTerrain(); 00527 00528 // update the main elevation request if it's running: 00529 if ( !_elevRequest->isIdle() ) 00530 { 00531 #ifdef PREEMPTIVE_DEBUG 00532 OE_NOTICE << "Tile (" << _key.str() << ") .. ER not idle" << std::endl; 00533 #endif 00534 00535 if ( !_elevRequest->isCompleted() ) 00536 { 00537 _elevRequest->setStamp( stamp ); 00538 } 00539 } 00540 00541 // update the placeholder request if it's running: 00542 else if ( !_elevPlaceholderRequest->isIdle() ) 00543 { 00544 #ifdef PREEMPTIVE_DEBUG 00545 OE_NOTICE << "Tile (" << _key.str() << ") .. PR not idle" << std::endl; 00546 #endif 00547 if ( !_elevPlaceholderRequest->isCompleted() ) 00548 { 00549 _elevPlaceholderRequest->setStamp( stamp ); 00550 } 00551 } 00552 00553 // otherwise, see if it is legal yet to start a new request: 00554 else if ( readyForNewElevation() ) 00555 { 00556 if ( _elevationLOD + 1 == _key.getLevelOfDetail() ) 00557 { 00558 _elevRequest->setStamp( stamp ); 00559 _elevRequest->setProgressCallback( new ProgressCallback() ); 00560 terrain->getElevationTaskService()->add( _elevRequest.get() ); 00561 #ifdef PREEMPTIVE_DEBUG 00562 OE_NOTICE << "..queued FE req for (" << _key.str() << ")" << std::endl; 00563 #endif 00564 } 00565 00566 else if ( _family[Relative::PARENT].elevLOD > _elevationLOD ) 00567 { 00568 osg::ref_ptr<StreamingTile> parentTile; 00569 terrain->getTile( _family[Relative::PARENT].tileID, parentTile, !tileTableLocked ); 00570 00571 if ( _elevationLOD < _family[Relative::PARENT].elevLOD && parentTile.valid() ) 00572 { 00573 TileElevationPlaceholderLayerRequest* er = static_cast<TileElevationPlaceholderLayerRequest*>(_elevPlaceholderRequest.get()); 00574 00575 er->setStamp( stamp ); 00576 er->setProgressCallback( new ProgressCallback() ); 00577 float priority = (float)_key.getLevelOfDetail(); 00578 er->setPriority( priority ); 00579 //TODO: should there be a read lock here when accessing the parent tile's elevation layer? GW 00580 osgTerrain::HeightFieldLayer* hfLayer = static_cast<osgTerrain::HeightFieldLayer*>(parentTile->getElevationLayer()); 00581 er->setParentHF( hfLayer->getHeightField() ); 00582 er->setNextLOD( _family[Relative::PARENT].elevLOD ); 00583 terrain->getElevationTaskService()->add( er ); 00584 #ifdef PREEMPTIVE_DEBUG 00585 OE_NOTICE << "..queued PH req for (" << _key.str() << ")" << std::endl; 00586 #endif 00587 } 00588 00589 else 00590 { 00591 #ifdef PREEMPTIVE_DEBUG 00592 OE_NOTICE << "...tile (" << _key.str() << ") ready, but nothing to do." << std::endl; 00593 #endif 00594 } 00595 } 00596 } 00597 } 00598 } 00599 00600 void 00601 StreamingTile::queueTileUpdate( TileUpdate::Action action, int value ) 00602 { 00603 if ( _useTileGenRequest ) 00604 { 00605 _tileUpdates.push( TileUpdate(action, value) ); 00606 } 00607 else 00608 { 00609 Tile::queueTileUpdate( action, value ); 00610 } 00611 } 00612 00613 // called from the UPDATE TRAVERSAL, because this method can potentially alter 00614 // the scene graph. 00615 bool 00616 StreamingTile::serviceCompletedRequests( const MapFrame& mapf, bool tileTableLocked ) 00617 { 00618 //Don't do anything until we have been added to the scene graph 00619 if (!_hasBeenTraversed) return false; 00620 00621 bool tileModified = false; 00622 00623 if ( !_requestsInstalled ) 00624 return false; 00625 00626 // First service the tile generator: 00627 if ( _tileGenRequest.valid() && _tileGenRequest->isCompleted() ) 00628 { 00629 CustomTerrainTechnique* tech = dynamic_cast<CustomTerrainTechnique*>( getTerrainTechnique() ); 00630 if ( tech ) 00631 { 00632 //TODO: consider waiting to apply if there are still more tile updates in the queue. 00633 if ( _tileUpdates.size() == 0 ) 00634 { 00635 tileModified = tech->applyTileUpdates(); 00636 } 00637 } 00638 _tileGenRequest = 0L; 00639 } 00640 00641 00642 // now deal with imagery. 00643 const LoadingPolicy& lp = getStreamingTerrain()->getLoadingPolicy(); 00644 00645 StreamingTerrain* terrain = getStreamingTerrain(); 00646 00647 //Check each layer independently. 00648 for( ImageLayerVector::const_iterator i = mapf.imageLayers().begin(); i != mapf.imageLayers().end(); ++i ) 00649 { 00650 ImageLayer* imageLayer = i->get(); 00651 00652 bool checkForFinalImagery = false; 00653 00654 CustomColorLayer colorLayer; 00655 if ( getCustomColorLayer( imageLayer->getUID(), colorLayer ) ) 00656 { 00657 if ( lp.mode() == LoadingPolicy::MODE_PREEMPTIVE ) 00658 { 00659 // in preemptive mode, always check for the final imagery - there are no intermediate 00660 // placeholders. 00661 checkForFinalImagery = true; 00662 } 00663 else if (lp.mode() == LoadingPolicy::MODE_SEQUENTIAL && 00664 readyForNewImagery(imageLayer, colorLayer.getLevelOfDetail()) ) 00665 { 00666 // in sequential mode, we have to incrementally increase imagery resolution by 00667 // creating placeholders based of parent tiles, one LOD at a time. 00668 if ( colorLayer.getLevelOfDetail() + 1 < (int)_key.getLevelOfDetail() ) 00669 { 00670 // if the parent's image LOD is higher than ours, replace ours with the parent's 00671 // since it is a higher-resolution placeholder: 00672 if ( _family[Relative::PARENT].getImageLOD(colorLayer.getUID()) > colorLayer.getLevelOfDetail() ) 00673 { 00674 osg::ref_ptr<Tile> parentTile; 00675 getStreamingTerrain()->getTile( _family[Relative::PARENT].tileID, parentTile, !tileTableLocked ); 00676 00677 // Set the color layer to the parent color layer as a placeholder. 00678 CustomColorLayer parentColorLayer; 00679 if ( parentTile->getCustomColorLayer( colorLayer.getUID(), parentColorLayer ) ) 00680 { 00681 this->setCustomColorLayer( parentColorLayer ); 00682 } 00683 00684 // ... and queue up an update request. 00685 queueTileUpdate( TileUpdate::UPDATE_IMAGE_LAYER, colorLayer.getUID() ); 00686 } 00687 } 00688 else 00689 { 00690 // we've gone as far as we can with placeholders; time to check for the 00691 // final imagery tile. 00692 checkForFinalImagery = true; 00693 } 00694 } 00695 } 00696 00697 if ( checkForFinalImagery ) 00698 { 00699 // Then the image requests: 00700 for( TaskRequestList::iterator itr = _requests.begin(); itr != _requests.end(); ) 00701 { 00702 bool increment = true; 00703 TileColorLayerRequest* r = static_cast<TileColorLayerRequest*>( itr->get() ); 00704 //We only care about the current layer we are checking 00705 if ( r->_layerUID == imageLayer->getUID() ) 00706 { 00707 if ( itr->get()->isCompleted() ) 00708 { 00709 if ( r->wasCanceled() ) 00710 { 00711 //Reset the cancelled task to IDLE and give it a new progress callback. 00712 r->setState( TaskRequest::STATE_IDLE ); 00713 r->setProgressCallback( new StampedProgressCallback( 00714 r, terrain->getImageryTaskService( r->_layerUID ))); 00715 r->reset(); 00716 } 00717 else // success.. 00718 { 00719 //See if we even care about the request 00720 if ( !mapf.getImageLayerByUID( r->_layerUID ) ) 00721 { 00722 //The maplayer was probably deleted 00723 OE_DEBUG << "Layer uid=" << r->_layerUID << " no longer exists, ignoring TileColorLayerRequest " << std::endl; 00724 itr = _requests.erase(itr); 00725 increment = false; 00726 } 00727 else 00728 { 00729 CustomColorLayerRef* result = static_cast<CustomColorLayerRef*>( r->getResult() ); 00730 if ( result ) 00731 { 00732 this->setCustomColorLayer( result->_layer ); 00733 00734 queueTileUpdate( TileUpdate::UPDATE_IMAGE_LAYER, r->_layerUID ); 00735 00736 //OE_NOTICE << "Complete IR (" << _key.str() << ") layer=" << r->_layerId << std::endl; 00737 00738 // remove from the list (don't reference "r" after this!) 00739 itr = _requests.erase( itr ); 00740 increment = false; 00741 } 00742 else 00743 { 00744 if (r->_numTries > r->_maxTries) 00745 { 00746 CustomColorLayer oldLayer; 00747 if ( this->getCustomColorLayer( r->_layerUID, oldLayer ) ) 00748 { 00749 // apply the old color layer but with a new LOD. 00750 this->setCustomColorLayer( CustomColorLayer( 00751 oldLayer.getMapLayer(), 00752 oldLayer.getImage(), 00753 oldLayer.getLocator(), 00754 _key.getLevelOfDetail(), 00755 _key )); 00756 00757 itr = _requests.erase( itr ); 00758 increment = false; 00759 OE_DEBUG << "Tried (" << _key.str() << ") (layer uid=" << r->_layerUID << "), too many times, moving on...." << std::endl; 00760 } 00761 } 00762 else 00763 { 00764 OE_DEBUG << "IReq error (" << _key.str() << ") (layer uid=" << r->_layerUID << "), retrying" << std::endl; 00765 00766 //The color layer request failed, probably due to a server error. Reset it. 00767 r->setState( TaskRequest::STATE_IDLE ); 00768 r->reset(); 00769 } 00770 } 00771 } 00772 } 00773 } 00774 } 00775 00776 if ( increment ) 00777 ++itr; 00778 } 00779 } 00780 } 00781 00782 // Finally, the elevation requests: 00783 if ( _hasElevation && !_elevationLayerUpToDate && _elevRequest.valid() && _elevPlaceholderRequest.valid() ) 00784 { 00785 // First, check is the Main elevation request is done. If so, we will now have the final HF data 00786 // and can shut down the elevation requests for this tile. 00787 if ( _elevRequest->isCompleted() ) 00788 { 00789 if ( _elevRequest->wasCanceled() ) 00790 { 00791 // If the request was canceled, reset it to IDLE and reset the callback. On the next 00792 _elevRequest->setState( TaskRequest::STATE_IDLE ); 00793 _elevRequest->setProgressCallback( new ProgressCallback() ); 00794 _elevRequest->reset(); 00795 } 00796 else // success: 00797 { 00798 // if the elevation request succeeded, install the new elevation layer! 00799 TileElevationLayerRequest* r = static_cast<TileElevationLayerRequest*>( _elevRequest.get() ); 00800 osg::ref_ptr<osgTerrain::HeightFieldLayer> newHFLayer = static_cast<osgTerrain::HeightFieldLayer*>( r->getResult() ); 00801 if ( newHFLayer.valid() && newHFLayer->getHeightField() != NULL ) 00802 { 00803 newHFLayer->getHeightField()->setSkirtHeight( 00804 terrain->getTileFactory()->getTerrainOptions().heightFieldSkirtRatio().get() * 00805 this->getBound().radius() ); 00806 00807 // need to write-lock the layer data since we'll be changing it: 00808 { 00809 Threading::ScopedWriteLock lock( _tileLayersMutex ); 00810 this->setElevationLayer( newHFLayer.get() ); 00811 this->dirtyBound(); 00812 } 00813 00814 // the tile needs rebuilding. This will kick off a TileGenRequest. 00815 queueTileUpdate( TileUpdate::UPDATE_ELEVATION ); 00816 00817 // finalize the LOD marker for this tile, so other tiles can see where we are. 00818 _elevationLOD = _key.getLevelOfDetail(); 00819 00820 #ifdef PREEMPTIVE_DEBUG 00821 OE_NOTICE << "Tile (" << _key.str() << ") final HF, LOD (" << _elevationLOD << ")" << std::endl; 00822 #endif 00823 // this was the final elev request, so mark elevation as DONE. 00824 _elevationLayerUpToDate = true; 00825 00826 // GW- just reset these and leave them alone and let cancelRequests() take care of cleanup later. 00827 // done with our Elevation requests! 00828 //_elevRequest = 0L; 00829 //_elevPlaceholderRequest = 0L; 00830 } 00831 else 00832 { 00833 //We've tried to get the tile's elevation but couldn't. Just mark the elevation layer as up to date and move on. 00834 _elevationLOD = _key.getLevelOfDetail(); 00835 _elevationLayerUpToDate = true; 00836 00837 //This code will retry indefinitely. We need to have a way to limit the number of retries since 00838 //it will block neighbor tiles from loading. 00839 //_elevRequest->setState( TaskRequest::STATE_IDLE ); 00840 //_elevRequest->reset(); 00841 } 00842 } 00843 } 00844 00845 else if ( _elevPlaceholderRequest->isCompleted() ) 00846 { 00847 TileElevationPlaceholderLayerRequest* r = 00848 static_cast<TileElevationPlaceholderLayerRequest*>(_elevPlaceholderRequest.get()); 00849 00850 if ( r->wasCanceled() ) 00851 { 00852 r->setState( TaskRequest::STATE_IDLE ); 00853 r->setProgressCallback( new ProgressCallback() ); 00854 r->reset(); 00855 } 00856 else // success: 00857 { 00858 osg::ref_ptr<osgTerrain::HeightFieldLayer> newPhLayer = static_cast<osgTerrain::HeightFieldLayer*>( r->getResult() ); 00859 if ( newPhLayer.valid() && newPhLayer->getHeightField() != NULL ) 00860 { 00861 // install the new elevation layer. 00862 { 00863 Threading::ScopedWriteLock lock( _tileLayersMutex ); 00864 this->setElevationLayer( newPhLayer.get() ); 00865 this->dirtyBound(); 00866 } 00867 00868 // tile needs to be recompiled. 00869 queueTileUpdate( TileUpdate::UPDATE_ELEVATION ); 00870 00871 // update the elevation LOD for this tile, now that the new HF data is installed. This will 00872 // allow other tiles to see where this tile's HF data is. 00873 _elevationLOD = r->_nextLOD; 00874 00875 #ifdef PREEMPTIVE_DEBUG 00876 OE_NOTICE << "..tile (" << _key.str() << ") is now at (" << _elevationLOD << ")" << std::endl; 00877 #endif 00878 } 00879 _elevPlaceholderRequest->setState( TaskRequest::STATE_IDLE ); 00880 _elevPlaceholderRequest->reset(); 00881 } 00882 } 00883 } 00884 00885 // if we have a new TileGenRequest, queue it up now. 00886 if ( _tileUpdates.size() > 0 && !_tileGenRequest.valid() ) // _tileGenNeeded && !_tileGenRequest.valid()) 00887 { 00888 _tileGenRequest = new TileGenRequest( this, _tileUpdates.front() ); 00889 _tileUpdates.pop(); 00890 //OE_NOTICE << "tile (" << _key.str() << ") queuing new tile gen" << std::endl; 00891 getStreamingTerrain()->getTileGenerationTaskService()->add( _tileGenRequest.get() ); 00892 } 00893 00894 return tileModified; 00895 }