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 #if 0 00020 #include "CustomTerrain" 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 00038 using namespace osgEarth; 00039 using namespace OpenThreads; 00040 00041 #define LC "[CustomTerrain] " 00042 00043 // setting this will enable "fast GL object release" - the engine will activity 00044 // track tiles that expire from the scene graph, and will explicity force them 00045 // to deallocate their GL objects (instead of waiting for OSG to "lazily" 00046 // release them). This is helpful for freeing up memory more quickly when 00047 // aggresively navigating a map. 00048 #define QUICK_RELEASE_GL_OBJECTS 1 00049 00050 //#define PREEMPTIVE_DEBUG 1 00051 00052 //---------------------------------------------------------------------------- 00053 00054 // this progress callback checks to see whether the request being serviced is 00055 // out of date with respect to the task service that is running it. It checks 00056 // for a disparity in frame stamps, and reports that the request should be 00057 // canceled if it appears the request has been abandoned by the Tile that 00058 // originally scheduled it. 00059 struct StampedProgressCallback : ProgressCallback 00060 { 00061 public: 00062 StampedProgressCallback(TaskRequest* request, TaskService* service): 00063 _request(request), 00064 _service(service) 00065 { 00066 } 00067 00068 //todo: maybe we should pass TaskRequest in as an argument 00069 bool reportProgress(double current, double total) 00070 { 00071 //Check to see if we were marked cancelled on a previous check 00072 if (_canceled) return _canceled; 00073 00074 _canceled = (_service->getStamp() - _request->getStamp() > 2); 00075 return _canceled; 00076 } 00077 00078 TaskRequest* _request; 00079 TaskService* _service; 00080 }; 00081 00082 //---------------------------------------------------------------------------- 00083 00084 // NOTE: Task requests run in background threads. So we pass in a map frame and 00085 // make a clone of it to use in that thread. Each Task must have its own MapFrame 00086 // so it's operating in its own sandbox. 00087 00088 struct TileLayerRequest : public TaskRequest 00089 { 00090 TileLayerRequest( const TileKey& key, const MapFrame& mapf, OSGTileFactory* tileFactory ) 00091 : _key( key ), 00092 _mapf(mapf, "osgterrain.TileLayerRequest"), 00093 _tileFactory(tileFactory), 00094 _numTries(0), 00095 _maxTries(3) { } 00096 00097 TileKey _key; 00098 MapFrame _mapf; 00099 //osg::ref_ptr<Map> _map; 00100 osg::ref_ptr<OSGTileFactory> _tileFactory; 00101 unsigned int _numTries; 00102 unsigned int _maxTries; 00103 }; 00104 00105 struct TileColorLayerRequest : public TileLayerRequest 00106 { 00107 TileColorLayerRequest( const TileKey& key, const MapFrame& mapf, OSGTileFactory* tileFactory, UID layerUID ) 00108 : TileLayerRequest( key, mapf, tileFactory ), _layerUID(layerUID) { } 00109 00110 void operator()( ProgressCallback* progress ) 00111 { 00112 osg::ref_ptr<ImageLayer> imageLayer = _mapf.getImageLayerByUID( _layerUID ); 00113 if ( imageLayer.valid() ) 00114 { 00115 _result = _tileFactory->createImageLayer( _mapf.getMapInfo(), imageLayer.get(), _key, progress ); 00116 if (!wasCanceled()) 00117 { 00118 _numTries++; 00119 } 00120 } 00121 } 00122 UID _layerUID; 00123 }; 00124 00125 struct TileElevationLayerRequest : public TileLayerRequest 00126 { 00127 TileElevationLayerRequest( const TileKey& key, const MapFrame& mapf, OSGTileFactory* tileFactory ) 00128 : TileLayerRequest( key, mapf, tileFactory ) 00129 { 00130 //nop 00131 } 00132 00133 void operator()( ProgressCallback* progress ) 00134 { 00135 _result = _tileFactory->createHeightFieldLayer( _mapf, _key, true ); //exactOnly=true 00136 _numTries++; 00137 } 00138 }; 00139 00140 struct TileElevationPlaceholderLayerRequest : public TileLayerRequest 00141 { 00142 TileElevationPlaceholderLayerRequest( const TileKey& key, const MapFrame& mapf, OSGTileFactory* tileFactory, GeoLocator* keyLocator ) 00143 : TileLayerRequest( key, mapf, tileFactory ), 00144 _parentKey( key.createParentKey() ), 00145 _keyLocator(keyLocator) 00146 { 00147 //nop 00148 } 00149 00150 void setParentHF( osg::HeightField* parentHF ) 00151 { 00152 _parentHF = parentHF; 00153 } 00154 00155 void setNextLOD( int nextLOD ) 00156 { 00157 _nextLOD = nextLOD; 00158 } 00159 00160 void operator()( ProgressCallback* progress ) 00161 { 00162 if ( !progress->isCanceled() ) 00163 { 00164 _result = _tileFactory->createPlaceholderHeightfieldLayer( 00165 _parentHF.get(), 00166 _parentKey, 00167 _key, 00168 _keyLocator.get() ); 00169 } 00170 } 00171 00172 osg::ref_ptr<osg::HeightField> _parentHF; 00173 TileKey _parentKey; 00174 osg::ref_ptr<GeoLocator> _keyLocator; 00175 int _nextLOD; 00176 }; 00177 00178 // A task request that rebuilds a tile's terrain technique in the background. It 00179 // re-compiles the geometry but does NOT apply the updates (since this constitutes 00180 // altering the scene graph and must therefore be done in the update traversal). 00181 struct TileGenRequest : public TaskRequest 00182 { 00183 TileGenRequest( CustomTile* tile, const TileUpdate& update ) : 00184 _tile( tile ), _update(update) { } 00185 00186 void operator()( ProgressCallback* progress ) 00187 { 00188 if (_tile.valid()) 00189 { 00190 CustomTerrainTechnique* tech = dynamic_cast<CustomTerrainTechnique*>( _tile->getTerrainTechnique() ); 00191 if (tech) 00192 { 00193 tech->compile( _update, progress ); 00194 } 00195 } 00196 00197 //We don't need the tile anymore 00198 _tile = NULL; 00199 } 00200 00201 osg::ref_ptr< CustomTile > _tile; 00202 TileUpdate _update; 00203 }; 00204 00205 00206 /*****************************************************************************/ 00207 00208 CustomTile::CustomTile( const TileKey& key, GeoLocator* keyLocator, bool quickReleaseGLObjects ) : 00209 _terrainRevision( -1 ), 00210 _tileRevision( 0 ), 00211 _useLayerRequests( false ), // always set this to false here; use setUseLayerRequests() to enable 00212 _requestsInstalled( false ), 00213 _usePerLayerUpdates( false ), // only matters when _useLayerRequests==true 00214 _elevationLayerDirty( false ), 00215 _colorLayersDirty( false ), 00216 _elevationLayerUpToDate( true ), 00217 _elevationLOD( key.getLevelOfDetail() ), 00218 _hasBeenTraversed(false), 00219 _useTileGenRequest( true ), 00220 //_tileGenNeeded( false ), 00221 _quickReleaseGLObjects( quickReleaseGLObjects ), 00222 _key( key ), 00223 _keyLocator( keyLocator ), 00224 _verticalScale(1.0f), 00225 _mask( 0L ) 00226 { 00227 this->setLocator( keyLocator ); 00228 00229 this->setThreadSafeRefUnref( true ); 00230 00231 this->setTileID( key.getTileId() ); 00232 00233 this->setName( key.str() ); 00234 00235 // because the lowest LOD (1) is always loaded fully: 00236 _elevationLayerUpToDate = _key.getLevelOfDetail() <= 1; 00237 00238 // initially bump the update requirement so that this tile will receive an update 00239 // traversal the first time through. It is on the first update traversal that we 00240 // know the tile is in the scene graph and that it can be registered with the terrain. 00241 ADJUST_UPDATE_TRAV_COUNT( this, 1 ); 00242 } 00243 00244 CustomTile::~CustomTile() 00245 { 00246 //OE_NOTICE << "Destroying CustomTile " << this->getKey()->str() << std::endl; 00247 } 00248 00249 bool 00250 CustomTile::cancelRequests() 00251 { 00252 // This method ensures that all requests owned by this object are stopped and released 00253 // by the corresponding task service prior to destructing the tile. Called by 00254 // CustomTerrain::updateTileTable(). 00255 00256 bool done = true; 00257 00258 // Cancel all active requests 00259 if ( _requestsInstalled ) 00260 { 00261 for( TaskRequestList::iterator i = _requests.begin(); i != _requests.end(); ++i ) 00262 { 00263 i->get()->cancel(); 00264 } 00265 00266 if ( _elevRequest.valid() ) 00267 { 00268 _elevRequest->cancel(); 00269 } 00270 00271 if (_elevPlaceholderRequest.valid()) 00272 { 00273 _elevPlaceholderRequest->cancel(); 00274 } 00275 00276 if (_tileGenRequest.valid()) 00277 { 00278 _tileGenRequest->cancel(); 00279 } 00280 } 00281 00282 return done; 00283 } 00284 00285 00286 Threading::ReadWriteMutex& 00287 CustomTile::getTileLayersMutex() 00288 { 00289 return _tileLayersMutex; 00290 } 00291 00292 const TileKey& 00293 CustomTile::getKey() const 00294 { 00295 return _key; 00296 } 00297 00298 void 00299 CustomTile::setElevationLOD( int lod ) 00300 { 00301 _elevationLOD = lod; 00302 _elevationLayerUpToDate = _elevationLOD == (int)_key.getLevelOfDetail(); 00303 00304 //Should probably just reset the placeholder requests 00305 //if (_elevPlaceholderRequest.valid()) _elevPlaceholderRequest->setState( TaskRequest::STATE_IDLE ); 00306 //if (_elevRequest.valid()) _elevRequest->setState( TaskRequest::STATE_IDLE ); 00307 //resetElevationRequests(); 00308 } 00309 00310 int 00311 CustomTile::getElevationLOD() const 00312 { 00313 return _elevationLOD; 00314 } 00315 00316 bool 00317 CustomTile::getHasBeenTraversed() const 00318 { 00319 return _hasBeenTraversed; 00320 } 00321 00322 CustomTerrain* 00323 CustomTile::getCustomTerrain() 00324 { 00325 if ( !_CustomTerrain.valid() ) 00326 _CustomTerrain = getTerrain(); 00327 return static_cast<CustomTerrain*>( _CustomTerrain.get() ); 00328 // _CustomTerrain = static_cast<CustomTerrain*>(getTerrain()); 00329 //return _CustomTerrain.get(); 00330 } 00331 00332 const CustomTerrain* 00333 CustomTile::getCustomTerrain() const 00334 { 00335 return const_cast<CustomTile*>(this)->getCustomTerrain(); 00336 } 00337 00338 void 00339 CustomTile::setUseLayerRequests( bool value ) 00340 { 00341 _useLayerRequests = value; 00342 } 00343 00344 int 00345 CustomTile::getTerrainRevision() const 00346 { 00347 return _terrainRevision; 00348 } 00349 00350 void 00351 CustomTile::setTerrainRevision( int revision ) 00352 { 00353 _terrainRevision = revision; 00354 } 00355 00356 bool 00357 CustomTile::isInSyncWithTerrain() const 00358 { 00359 return _terrainRevision == getCustomTerrain()->getRevision(); 00360 } 00361 00362 int 00363 CustomTile::getTileRevision() const 00364 { 00365 return _tileRevision; 00366 } 00367 00368 void 00369 CustomTile::incrementTileRevision() 00370 { 00371 _tileRevision++; 00372 } 00373 00374 void 00375 CustomTile::setHasElevationHint( bool hint ) 00376 { 00377 _hasElevation = hint; 00378 } 00379 00380 bool 00381 CustomTile::isElevationLayerUpToDate() const 00382 { 00383 return _elevationLayerUpToDate; 00384 } 00385 00386 bool 00387 CustomTile::getUseTileGenRequest() const 00388 { 00389 return _useTileGenRequest; 00390 } 00391 00392 float 00393 CustomTile::getVerticalScale() const 00394 { 00395 return _verticalScale; 00396 } 00397 00398 void 00399 CustomTile::setVerticalScale(float verticalScale) 00400 { 00401 if (_verticalScale != verticalScale) 00402 { 00403 _verticalScale = verticalScale; 00404 dirtyBound(); 00405 } 00406 } 00407 00408 void 00409 CustomTile::setCustomColorLayer( const CustomColorLayer& layer, bool writeLock ) 00410 { 00411 if ( writeLock ) 00412 { 00413 Threading::ScopedWriteLock exclusiveTileLock( _tileLayersMutex ); 00414 setCustomColorLayer( layer, false ); 00415 } 00416 else 00417 { 00418 int delta = 0; 00419 ColorLayersByUID::const_iterator i = _colorLayers.find(layer.getUID()); 00420 if ( i != _colorLayers.end() && i->second.getMapLayer()->isDynamic() ) 00421 --delta; 00422 00423 _colorLayers[layer.getUID()] = layer; 00424 00425 if ( layer.getMapLayer()->isDynamic() ) 00426 ++delta; 00427 00428 if ( delta != 0 ) 00429 ADJUST_UPDATE_TRAV_COUNT( this, delta ); 00430 } 00431 } 00432 00433 void 00434 CustomTile::removeCustomColorLayer( UID layerUID, bool writeLock ) 00435 { 00436 if ( writeLock ) 00437 { 00438 Threading::ScopedWriteLock exclusiveTileLock( _tileLayersMutex ); 00439 removeCustomColorLayer( layerUID, false ); 00440 } 00441 else 00442 { 00443 ColorLayersByUID::iterator i = _colorLayers.find(layerUID); 00444 if ( i != _colorLayers.end() ) 00445 { 00446 if ( i->second.getMapLayer()->isDynamic() ) 00447 ADJUST_UPDATE_TRAV_COUNT( this, -1 ); 00448 00449 _colorLayers.erase( i ); 00450 } 00451 } 00452 } 00453 00454 bool 00455 CustomTile::getCustomColorLayer( UID layerUID, CustomColorLayer& out, bool readLock ) const 00456 { 00457 if ( readLock ) 00458 { 00459 Threading::ScopedReadLock sharedTileLock( const_cast<CustomTile*>(this)->_tileLayersMutex ); 00460 return getCustomColorLayer( layerUID, out, false ); 00461 } 00462 else 00463 { 00464 ColorLayersByUID::const_iterator i = _colorLayers.find( layerUID ); 00465 if ( i != _colorLayers.end() ) 00466 { 00467 out = i->second; 00468 return true; 00469 } 00470 } 00471 return false; 00472 } 00473 00474 void 00475 CustomTile::getCustomColorLayers( ColorLayersByUID& out, bool readLock ) const 00476 { 00477 if ( readLock ) 00478 { 00479 Threading::ScopedReadLock sharedTileLock( const_cast<CustomTile*>(this)->_tileLayersMutex ); 00480 return getCustomColorLayers( out, false ); 00481 } 00482 else 00483 out = _colorLayers; 00484 } 00485 00486 void 00487 CustomTile::setCustomColorLayers( const ColorLayersByUID& in, bool writeLock ) 00488 { 00489 if ( writeLock ) 00490 { 00491 Threading::ScopedWriteLock exclusiveLock( _tileLayersMutex ); 00492 setCustomColorLayers( in, false ); 00493 } 00494 else 00495 { 00496 int delta = 0; 00497 for( ColorLayersByUID::const_iterator i = _colorLayers.begin(); i != _colorLayers.end(); ++i ) 00498 if ( i->second.getMapLayer()->isDynamic() ) 00499 --delta; 00500 00501 _colorLayers = in; 00502 00503 for( ColorLayersByUID::const_iterator i = _colorLayers.begin(); i != _colorLayers.end(); ++i ) 00504 if ( i->second.getMapLayer()->isDynamic() ) 00505 ++delta; 00506 00507 if ( delta != 0 ) 00508 ADJUST_UPDATE_TRAV_COUNT( this, delta ); 00509 } 00510 } 00511 00512 osg::BoundingSphere 00513 CustomTile::computeBound() const 00514 { 00515 //Overriden computeBound that takes into account the vertical scale. 00516 //OE_NOTICE << "CustomTile::computeBound verticalScale = " << _verticalScale << std::endl; 00517 00518 osg::BoundingSphere bs; 00519 00520 if (_elevationLayer.valid()) 00521 { 00522 if (!_elevationLayer->getLocator()) return bs; 00523 00524 osg::BoundingBox bb; 00525 unsigned int numColumns = _elevationLayer->getNumColumns(); 00526 unsigned int numRows = _elevationLayer->getNumRows(); 00527 for(unsigned int r=0;r<numRows;++r) 00528 { 00529 for(unsigned int c=0;c<numColumns;++c) 00530 { 00531 float value = 0.0f; 00532 bool validValue = _elevationLayer->getValidValue(c,r, value); 00533 if (validValue) 00534 { 00535 //Multiply by the vertical scale. 00536 value *= _verticalScale; 00537 osg::Vec3d ndc, v; 00538 ndc.x() = ((double)c)/(double)(numColumns-1), 00539 ndc.y() = ((double)r)/(double)(numRows-1); 00540 ndc.z() = value; 00541 00542 if (_elevationLayer->getLocator()->convertLocalToModel(ndc, v)) 00543 { 00544 bb.expandBy(v); 00545 } 00546 } 00547 } 00548 } 00549 bs.expandBy(bb); 00550 00551 } 00552 else 00553 { 00554 for(ColorLayersByUID::const_iterator i = _colorLayers.begin(); i != _colorLayers.end(); ++i ) 00555 { 00556 bs.expandBy( i->second.computeBound() ); //(*i)->computeBound(false) ); 00557 } 00558 } 00559 00560 return bs; 00561 00562 } 00563 00564 // returns TRUE if it's safe for this tile to load its next elevation data layer. 00565 bool 00566 CustomTile::readyForNewElevation() 00567 { 00568 bool ready = true; 00569 00570 if ( _elevationLOD == (int)_key.getLevelOfDetail() ) 00571 { 00572 ready = false; 00573 } 00574 else if ( _family[Relative::PARENT].elevLOD < 0 ) 00575 { 00576 ready = false; 00577 } 00578 else 00579 { 00580 for( int i=Relative::PARENT; i<=Relative::SOUTH; i++) 00581 { 00582 if ( _family[i].expected && _family[i].elevLOD >= 0 && _family[i].elevLOD < _elevationLOD ) 00583 { 00584 ready = false; 00585 break; 00586 } 00587 } 00588 00589 // if the next LOD is not the final, but our placeholder is up to date, we're not ready. 00590 if ( ready && _elevationLOD+1 < (int)_key.getLevelOfDetail() && _elevationLOD == _family[Relative::PARENT].elevLOD ) 00591 { 00592 ready = false; 00593 } 00594 } 00595 00596 #ifdef PREEMPTIVE_DEBUG 00597 OE_NOTICE 00598 << "Tile (" << _key.str() << ") at (" << _elevationLOD << "), parent at (" 00599 << _family[PARENT].elevLOD << "), sibs at ("; 00600 if ( _family[WEST].expected ) osg::notify( osg::NOTICE ) << "W=" << _family[WEST].elevLOD << " "; 00601 if ( _family[NORTH].expected ) osg::notify( osg::NOTICE ) << "N=" << _family[NORTH].elevLOD << " "; 00602 if ( _family[EAST].expected ) osg::notify( osg::NOTICE ) << "E=" << _family[EAST].elevLOD << " "; 00603 if ( _family[SOUTH].expected ) osg::notify( osg::NOTICE ) << "S=" << _family[SOUTH].elevLOD << " "; 00604 OE_NOTICE << "), ready = " << (ready? "YES" : "no") << std::endl; 00605 #endif 00606 00607 return ready; 00608 } 00609 00610 00611 00612 // returns TRUE if it's safe for this tile to load its next elevation data layer. 00613 bool 00614 CustomTile::readyForNewImagery(ImageLayer* layer, int currentLOD) 00615 { 00616 bool ready = true; 00617 00618 if ( currentLOD == (int)_key.getLevelOfDetail() ) 00619 { 00620 ready = false; 00621 } 00622 else if ( _family[Relative::PARENT].getImageLOD( layer->getUID() ) < 0 ) 00623 { 00624 ready = false; 00625 } 00626 else 00627 { 00628 for( int i=Relative::PARENT; i<=Relative::SOUTH; i++) 00629 { 00630 if (_family[i].expected && 00631 _family[i].getImageLOD( layer->getUID() ) >= 0 && 00632 _family[i].getImageLOD( layer->getUID() ) < currentLOD ) 00633 { 00634 ready = false; 00635 break; 00636 } 00637 } 00638 00639 // if the next LOD is not the final, but our placeholder is up to date, we're not ready. 00640 if (ready && 00641 currentLOD + 1 < (int)_key.getLevelOfDetail() && 00642 currentLOD == _family[Relative::PARENT].getImageLOD( layer->getUID() ) ) 00643 { 00644 ready = false; 00645 } 00646 } 00647 00648 return ready; 00649 } 00650 00651 00652 #define PRI_IMAGE_OFFSET 0.1f // priority offset of imagery relative to elevation 00653 #define PRI_LAYER_OFFSET 0.1f // priority offset of image layer(x) vs. image layer(x+1) 00654 00655 void 00656 CustomTile::installRequests( const MapFrame& mapf, int stamp ) 00657 { 00658 CustomTerrain* terrain = getCustomTerrain(); 00659 00660 OSGTileFactory* tileFactory = terrain->getTileFactory(); 00661 00662 bool hasElevationLayer; 00663 { 00664 Threading::ScopedReadLock sharedLock( _tileLayersMutex ); 00665 hasElevationLayer = this->getElevationLayer() != NULL; 00666 } 00667 00668 if ( hasElevationLayer ) 00669 { 00670 resetElevationRequests( mapf ); 00671 } 00672 00673 // safely loop through the map layers and schedule imagery updates for each: 00674 for( ImageLayerVector::const_iterator i = mapf.imageLayers().begin(); i != mapf.imageLayers().end(); ++i ) 00675 { 00676 updateImagery( i->get(), mapf, tileFactory ); 00677 } 00678 00679 _requestsInstalled = true; 00680 } 00681 00682 void 00683 CustomTile::resetElevationRequests( const MapFrame& mapf ) 00684 { 00685 if (_elevRequest.valid() && _elevRequest->isRunning()) _elevRequest->cancel(); 00686 if (_elevPlaceholderRequest.valid() && _elevPlaceholderRequest->isRunning()) _elevPlaceholderRequest->cancel(); 00687 00688 // this request will load real elevation data for the tile: 00689 _elevRequest = new TileElevationLayerRequest(_key, mapf, getCustomTerrain()->getTileFactory()); 00690 float priority = (float)_key.getLevelOfDetail(); 00691 _elevRequest->setPriority( priority ); 00692 std::stringstream ss; 00693 ss << "TileElevationLayerRequest " << _key.str() << std::endl; 00694 std::string ssStr; 00695 ssStr = ss.str(); 00696 _elevRequest->setName( ssStr ); 00697 00698 // this request will load placeholder elevation data for the tile: 00699 _elevPlaceholderRequest = new TileElevationPlaceholderLayerRequest( 00700 _key, mapf, getCustomTerrain()->getTileFactory(), _keyLocator.get() ); 00701 _elevPlaceholderRequest->setPriority( priority ); 00702 ss.str(""); 00703 ss << "TileElevationPlaceholderLayerRequest " << _key.str() << std::endl; 00704 ssStr = ss.str(); 00705 _elevPlaceholderRequest->setName( ssStr ); 00706 } 00707 00708 00709 // called from installRequests (cull traversal) or terrainengine (main thread) ... so be careful! 00710 // 00711 // this method queues up a new tile imagery request, superceding any existing request that 00712 // might be in the queue. 00713 void 00714 CustomTile::updateImagery( ImageLayer* imageLayer, const MapFrame& mapf, OSGTileFactory* tileFactory) 00715 { 00716 CustomTerrain* terrain = getCustomTerrain(); 00717 00718 // imagery is slighty higher priority than elevation data 00719 TaskRequest* r = new TileColorLayerRequest( _key, mapf, tileFactory, imageLayer->getUID() ); 00720 std::stringstream ss; 00721 ss << "TileColorLayerRequest " << _key.str() << std::endl; 00722 std::string ssStr; 00723 ssStr = ss.str(); 00724 r->setName( ssStr ); 00725 r->setState( osgEarth::TaskRequest::STATE_IDLE ); 00726 00727 // in image-sequential mode, we want to prioritize lower-LOD imagery since it 00728 // needs to come in before higher-resolution stuff. 00729 if ( terrain->getLoadingPolicy().mode() == LoadingPolicy::MODE_SEQUENTIAL ) 00730 { 00731 r->setPriority( -(float)_key.getLevelOfDetail() + PRI_IMAGE_OFFSET ); 00732 } 00733 // in image-preemptive mode, the highest LOD should get higher load priority: 00734 else // MODE_PREEMPTIVE 00735 { 00736 r->setPriority( PRI_IMAGE_OFFSET + (float)_key.getLevelOfDetail()); 00737 } 00738 00739 r->setProgressCallback( new StampedProgressCallback( 00740 r, 00741 terrain->getImageryTaskService( imageLayer->getUID() ) ) ); 00742 00743 //If we already have a request for this layer, remove it from the list and use the new one 00744 for( TaskRequestList::iterator i = _requests.begin(); i != _requests.end(); ) 00745 { 00746 TileColorLayerRequest* r2 = static_cast<TileColorLayerRequest*>( i->get() ); 00747 if ( r2->_layerUID == imageLayer->getUID() ) 00748 i = _requests.erase( i ); 00749 else 00750 ++i; 00751 } 00752 00753 //Add the new imagery request 00754 _requests.push_back( r ); 00755 } 00756 00757 // This method is called from the CULL TRAVERSAL, from CustomTerrain. //from TileImageBackfillCallback in OSGTileFactory.cpp. 00758 void 00759 CustomTile::servicePendingImageRequests( const MapFrame& mapf, int stamp ) 00760 { 00761 //Don't do anything until we have been added to the scene graph 00762 if (!_hasBeenTraversed) return; 00763 00764 // install our requests if they are not already installed: 00765 if ( !_requestsInstalled ) 00766 { 00767 // since we're in the CULL thread, use the cull thread map frame: 00768 installRequests( mapf, stamp ); 00769 } 00770 00771 for( TaskRequestList::iterator i = _requests.begin(); i != _requests.end(); ++i ) 00772 { 00773 TileColorLayerRequest* r = static_cast<TileColorLayerRequest*>( i->get() ); 00774 00775 //If a request has been marked as IDLE, the TaskService has tried to service it 00776 //and it was either deemed out of date or was cancelled, so we need to add it again. 00777 if ( r->isIdle() ) 00778 { 00779 //OE_NOTICE << "Queuing IR (" << _key.str() << ")" << std::endl; 00780 r->setStamp( stamp ); 00781 getCustomTerrain()->getImageryTaskService( r->_layerUID )->add( r ); 00782 } 00783 else if ( !r->isCompleted() ) 00784 { 00785 r->setStamp( stamp ); 00786 } 00787 } 00788 } 00789 00790 // This method is called from the UPDATE TRAVERSAL, from CustomTerrain::traverse. 00791 void 00792 CustomTile::servicePendingElevationRequests( const MapFrame& mapf, int stamp, bool tileTableLocked ) 00793 { 00794 //Don't do anything until we have been added to the scene graph 00795 if (!_hasBeenTraversed) return; 00796 00797 00798 // install our requests if they are not already installed: 00799 if ( !_requestsInstalled ) 00800 { 00801 installRequests( mapf, stamp ); 00802 } 00803 00804 if ( _hasElevation && !_elevationLayerUpToDate && _elevRequest.valid() && _elevPlaceholderRequest.valid() ) 00805 { 00806 CustomTerrain* terrain = getCustomTerrain(); 00807 00808 // update the main elevation request if it's running: 00809 if ( !_elevRequest->isIdle() ) 00810 { 00811 #ifdef PREEMPTIVE_DEBUG 00812 OE_NOTICE << "Tile (" << _key.str() << ") .. ER not idle" << std::endl; 00813 #endif 00814 00815 if ( !_elevRequest->isCompleted() ) 00816 { 00817 _elevRequest->setStamp( stamp ); 00818 } 00819 } 00820 00821 // update the placeholder request if it's running: 00822 else if ( !_elevPlaceholderRequest->isIdle() ) 00823 { 00824 #ifdef PREEMPTIVE_DEBUG 00825 OE_NOTICE << "Tile (" << _key.str() << ") .. PR not idle" << std::endl; 00826 #endif 00827 if ( !_elevPlaceholderRequest->isCompleted() ) 00828 { 00829 _elevPlaceholderRequest->setStamp( stamp ); 00830 } 00831 } 00832 00833 // otherwise, see if it is legal yet to start a new request: 00834 else if ( readyForNewElevation() ) 00835 { 00836 if ( _elevationLOD + 1 == _key.getLevelOfDetail() ) 00837 { 00838 _elevRequest->setStamp( stamp ); 00839 _elevRequest->setProgressCallback( new ProgressCallback() ); 00840 terrain->getElevationTaskService()->add( _elevRequest.get() ); 00841 #ifdef PREEMPTIVE_DEBUG 00842 OE_NOTICE << "..queued FE req for (" << _key.str() << ")" << std::endl; 00843 #endif 00844 } 00845 00846 else if ( _family[Relative::PARENT].elevLOD > _elevationLOD ) 00847 { 00848 osg::ref_ptr<CustomTile> parentTile; 00849 terrain->getCustomTile( _family[Relative::PARENT].tileID, parentTile, !tileTableLocked ); 00850 00851 if ( _elevationLOD < _family[Relative::PARENT].elevLOD && parentTile.valid() ) 00852 { 00853 TileElevationPlaceholderLayerRequest* er = static_cast<TileElevationPlaceholderLayerRequest*>(_elevPlaceholderRequest.get()); 00854 00855 er->setStamp( stamp ); 00856 er->setProgressCallback( new ProgressCallback() ); 00857 float priority = (float)_key.getLevelOfDetail(); 00858 er->setPriority( priority ); 00859 //TODO: should there be a read lock here when accessing the parent tile's elevation layer? GW 00860 osgTerrain::HeightFieldLayer* hfLayer = static_cast<osgTerrain::HeightFieldLayer*>(parentTile->getElevationLayer()); 00861 er->setParentHF( hfLayer->getHeightField() ); 00862 er->setNextLOD( _family[Relative::PARENT].elevLOD ); 00863 terrain->getElevationTaskService()->add( er ); 00864 #ifdef PREEMPTIVE_DEBUG 00865 OE_NOTICE << "..queued PH req for (" << _key.str() << ")" << std::endl; 00866 #endif 00867 } 00868 00869 else 00870 { 00871 #ifdef PREEMPTIVE_DEBUG 00872 OE_NOTICE << "...tile (" << _key.str() << ") ready, but nothing to do." << std::endl; 00873 #endif 00874 } 00875 } 00876 } 00877 } 00878 } 00879 00880 void 00881 CustomTile::queueTileUpdate( TileUpdate::Action action, int value ) 00882 { 00883 if ( _useTileGenRequest ) 00884 { 00885 _tileUpdates.push( TileUpdate(action, value) ); 00886 } 00887 else 00888 { 00889 this->setDirty( true ); 00890 } 00891 } 00892 00893 void 00894 CustomTile::applyImmediateTileUpdate( TileUpdate::Action action, int value ) 00895 { 00896 CustomTerrainTechnique* tech = dynamic_cast<CustomTerrainTechnique*>( getTerrainTechnique() ); 00897 if ( tech ) 00898 { 00899 tech->compile( TileUpdate(action, value), 0L ); 00900 tech->applyTileUpdates(); 00901 } 00902 else 00903 { 00904 queueTileUpdate( action, value ); 00905 } 00906 } 00907 00908 // called from the UPDATE TRAVERSAL, because this method can potentially alter 00909 // the scene graph. 00910 bool 00911 CustomTile::serviceCompletedRequests( const MapFrame& mapf, bool tileTableLocked ) 00912 { 00913 //Don't do anything until we have been added to the scene graph 00914 if (!_hasBeenTraversed) return false; 00915 00916 bool tileModified = false; 00917 00918 if ( !_requestsInstalled ) 00919 return false; 00920 00921 // First service the tile generator: 00922 if ( _tileGenRequest.valid() && _tileGenRequest->isCompleted() ) 00923 { 00924 CustomTerrainTechnique* tech = dynamic_cast<CustomTerrainTechnique*>( getTerrainTechnique() ); 00925 if ( tech ) 00926 { 00927 //TODO: consider waiting to apply if there are still more tile updates in the queue. 00928 if ( _tileUpdates.size() == 0 ) 00929 tileModified = tech->applyTileUpdates(); 00930 } 00931 _tileGenRequest = 0L; 00932 } 00933 00934 00935 // now deal with imagery. 00936 const LoadingPolicy& lp = getCustomTerrain()->getLoadingPolicy(); 00937 00938 //Check each layer independently. 00939 for( ImageLayerVector::const_iterator i = mapf.imageLayers().begin(); i != mapf.imageLayers().end(); ++i ) 00940 { 00941 ImageLayer* imageLayer = i->get(); 00942 00943 bool checkForFinalImagery = false; 00944 00945 CustomColorLayer colorLayer; 00946 if ( getCustomColorLayer( imageLayer->getUID(), colorLayer ) ) 00947 { 00948 if ( lp.mode() == LoadingPolicy::MODE_PREEMPTIVE ) 00949 { 00950 // in preemptive mode, always check for the final imagery - there are no intermediate 00951 // placeholders. 00952 checkForFinalImagery = true; 00953 } 00954 else if (lp.mode() == LoadingPolicy::MODE_SEQUENTIAL && 00955 readyForNewImagery(imageLayer, colorLayer.getLevelOfDetail()) ) 00956 { 00957 // in sequential mode, we have to incrementally increase imagery resolution by 00958 // creating placeholders based of parent tiles, one LOD at a time. 00959 if ( colorLayer.getLevelOfDetail() + 1 < (int)_key.getLevelOfDetail() ) 00960 { 00961 // if the parent's image LOD is higher than ours, replace ours with the parent's 00962 // since it is a higher-resolution placeholder: 00963 if ( _family[Relative::PARENT].getImageLOD(colorLayer.getUID()) > colorLayer.getLevelOfDetail() ) 00964 { 00965 osg::ref_ptr<CustomTile> parentTile; 00966 getCustomTerrain()->getCustomTile( _family[Relative::PARENT].tileID, parentTile, !tileTableLocked ); 00967 00968 // Set the color layer to the parent color layer as a placeholder. 00969 CustomColorLayer parentColorLayer; 00970 if ( parentTile->getCustomColorLayer( colorLayer.getUID(), parentColorLayer ) ) 00971 { 00972 this->setCustomColorLayer( parentColorLayer ); 00973 } 00974 00975 // ... and queue up an update request. 00976 queueTileUpdate( TileUpdate::UPDATE_IMAGE_LAYER, colorLayer.getUID() ); 00977 } 00978 } 00979 else 00980 { 00981 // we've gone as far as we can with placeholders; time to check for the 00982 // final imagery tile. 00983 checkForFinalImagery = true; 00984 } 00985 } 00986 } 00987 00988 if ( checkForFinalImagery ) 00989 { 00990 // Then the image requests: 00991 for( TaskRequestList::iterator itr = _requests.begin(); itr != _requests.end(); ) 00992 { 00993 bool increment = true; 00994 TileColorLayerRequest* r = static_cast<TileColorLayerRequest*>( itr->get() ); 00995 //We only care about the current layer we are checking 00996 if ( r->_layerUID == imageLayer->getUID() ) 00997 { 00998 if ( itr->get()->isCompleted() ) 00999 { 01000 if ( r->wasCanceled() ) 01001 { 01002 //Reset the cancelled task to IDLE and give it a new progress callback. 01003 r->setState( TaskRequest::STATE_IDLE ); 01004 r->setProgressCallback( new StampedProgressCallback( 01005 r, getCustomTerrain()->getImageryTaskService( r->_layerUID ))); 01006 r->reset(); 01007 } 01008 else // success.. 01009 { 01010 //See if we even care about the request 01011 if ( !mapf.getImageLayerByUID( r->_layerUID ) ) 01012 { 01013 //The maplayer was probably deleted 01014 OE_DEBUG << "Layer uid=" << r->_layerUID << " no longer exists, ignoring TileColorLayerRequest " << std::endl; 01015 itr = _requests.erase(itr); 01016 increment = false; 01017 } 01018 else 01019 { 01020 CustomColorLayerRef* result = static_cast<CustomColorLayerRef*>( r->getResult() ); 01021 if ( result ) 01022 { 01023 this->setCustomColorLayer( result->_layer ); 01024 01025 queueTileUpdate( TileUpdate::UPDATE_IMAGE_LAYER, r->_layerUID ); 01026 01027 //OE_NOTICE << "Complete IR (" << _key.str() << ") layer=" << r->_layerId << std::endl; 01028 01029 // remove from the list (don't reference "r" after this!) 01030 itr = _requests.erase( itr ); 01031 increment = false; 01032 } 01033 else 01034 { 01035 if (r->_numTries > r->_maxTries) 01036 { 01037 CustomColorLayer oldLayer; 01038 if ( this->getCustomColorLayer( r->_layerUID, oldLayer ) ) 01039 { 01040 // apply the old color layer but with a new LOD. 01041 this->setCustomColorLayer( CustomColorLayer( 01042 oldLayer.getMapLayer(), 01043 oldLayer.getImage(), 01044 oldLayer.getLocator(), 01045 _key.getLevelOfDetail(), 01046 _key )); 01047 01048 itr = _requests.erase( itr ); 01049 increment = false; 01050 OE_DEBUG << "Tried (" << _key.str() << ") (layer uid=" << r->_layerUID << "), too many times, moving on...." << std::endl; 01051 } 01052 } 01053 else 01054 { 01055 OE_DEBUG << "IReq error (" << _key.str() << ") (layer uid=" << r->_layerUID << "), retrying" << std::endl; 01056 01057 //The color layer request failed, probably due to a server error. Reset it. 01058 r->setState( TaskRequest::STATE_IDLE ); 01059 r->reset(); 01060 } 01061 } 01062 } 01063 } 01064 } 01065 } 01066 01067 if ( increment ) 01068 ++itr; 01069 } 01070 } 01071 } 01072 01073 // Finally, the elevation requests: 01074 if ( _hasElevation && !_elevationLayerUpToDate && _elevRequest.valid() && _elevPlaceholderRequest.valid() ) 01075 { 01076 // First, check is the Main elevation request is done. If so, we will now have the final HF data 01077 // and can shut down the elevation requests for this tile. 01078 if ( _elevRequest->isCompleted() ) 01079 { 01080 if ( _elevRequest->wasCanceled() ) 01081 { 01082 // If the request was canceled, reset it to IDLE and reset the callback. On the next 01083 _elevRequest->setState( TaskRequest::STATE_IDLE ); 01084 _elevRequest->setProgressCallback( new ProgressCallback() ); 01085 _elevRequest->reset(); 01086 } 01087 else // success: 01088 { 01089 // if the elevation request succeeded, install the new elevation layer! 01090 TileElevationLayerRequest* r = static_cast<TileElevationLayerRequest*>( _elevRequest.get() ); 01091 osg::ref_ptr<osgTerrain::HeightFieldLayer> newHFLayer = static_cast<osgTerrain::HeightFieldLayer*>( r->getResult() ); 01092 if ( newHFLayer.valid() && newHFLayer->getHeightField() != NULL ) 01093 { 01094 newHFLayer->getHeightField()->setSkirtHeight( 01095 getCustomTerrain()->getTileFactory()->getTerrainOptions().heightFieldSkirtRatio().get() 01096 * this->getBound().radius() ); 01097 01098 // need to write-lock the layer data since we'll be changing it: 01099 { 01100 Threading::ScopedWriteLock lock( _tileLayersMutex ); 01101 this->setElevationLayer( newHFLayer.get() ); 01102 this->dirtyBound(); 01103 } 01104 01105 // the tile needs rebuilding. This will kick off a TileGenRequest. 01106 queueTileUpdate( TileUpdate::UPDATE_ELEVATION ); 01107 01108 // finalize the LOD marker for this tile, so other tiles can see where we are. 01109 //setElevationLOD( _key.getLevelOfDetail() ); 01110 _elevationLOD = _key.getLevelOfDetail(); 01111 01112 #ifdef PREEMPTIVE_DEBUG 01113 OE_NOTICE << "Tile (" << _key.str() << ") final HF, LOD (" << _elevationLOD << ")" << std::endl; 01114 #endif 01115 // this was the final elev request, so mark elevation as DONE. 01116 _elevationLayerUpToDate = true; 01117 01118 // GW- just reset these and leave them alone and let cancelRequests() take care of cleanup later. 01119 // done with our Elevation requests! 01120 //_elevRequest = 0L; 01121 //_elevPlaceholderRequest = 0L; 01122 } 01123 else 01124 { 01125 _elevRequest->setState( TaskRequest::STATE_IDLE ); 01126 _elevRequest->reset(); 01127 } 01128 } 01129 } 01130 01131 else if ( _elevPlaceholderRequest->isCompleted() ) 01132 { 01133 TileElevationPlaceholderLayerRequest* r = 01134 static_cast<TileElevationPlaceholderLayerRequest*>(_elevPlaceholderRequest.get()); 01135 01136 if ( r->wasCanceled() ) 01137 { 01138 r->setState( TaskRequest::STATE_IDLE ); 01139 r->setProgressCallback( new ProgressCallback() ); 01140 r->reset(); 01141 } 01142 else // success: 01143 { 01144 osg::ref_ptr<osgTerrain::HeightFieldLayer> newPhLayer = static_cast<osgTerrain::HeightFieldLayer*>( r->getResult() ); 01145 if ( newPhLayer.valid() && newPhLayer->getHeightField() != NULL ) 01146 { 01147 // install the new elevation layer. 01148 { 01149 Threading::ScopedWriteLock lock( _tileLayersMutex ); 01150 this->setElevationLayer( newPhLayer.get() ); 01151 this->dirtyBound(); 01152 } 01153 01154 // tile needs to be recompiled. 01155 queueTileUpdate( TileUpdate::UPDATE_ELEVATION ); 01156 //markTileForRegeneration(); 01157 01158 // update the elevation LOD for this tile, now that the new HF data is installed. This will 01159 // allow other tiles to see where this tile's HF data is. 01160 _elevationLOD = r->_nextLOD; 01161 //setElevationLOD( r->_nextLOD ); 01162 01163 #ifdef PREEMPTIVE_DEBUG 01164 OE_NOTICE << "..tile (" << _key.str() << ") is now at (" << _elevationLOD << ")" << std::endl; 01165 #endif 01166 } 01167 _elevPlaceholderRequest->setState( TaskRequest::STATE_IDLE ); 01168 _elevPlaceholderRequest->reset(); 01169 } 01170 } 01171 } 01172 01173 // if we have a new TileGenRequest, queue it up now. 01174 if ( _tileUpdates.size() > 0 && !_tileGenRequest.valid() ) // _tileGenNeeded && !_tileGenRequest.valid()) 01175 { 01176 _tileGenRequest = new TileGenRequest( this, _tileUpdates.front() ); 01177 _tileUpdates.pop(); 01178 //OE_NOTICE << "tile (" << _key.str() << ") queuing new tile gen" << std::endl; 01179 getCustomTerrain()->getTileGenerationTaskSerivce()->add( _tileGenRequest.get() ); 01180 } 01181 01182 return tileModified; 01183 } 01184 01185 void 01186 CustomTile::traverse( osg::NodeVisitor& nv ) 01187 { 01188 if ( !_hasBeenTraversed && nv.getVisitorType() == osg::NodeVisitor::UPDATE_VISITOR ) 01189 { 01190 Threading::ScopedWriteLock lock( this->_tileLayersMutex ); 01191 { 01192 if ( !_hasBeenTraversed && getCustomTerrain() ) 01193 { 01194 _hasBeenTraversed = true; 01195 01196 // we constructed this tile with an update traversal count of 1 so it would get 01197 // here and we could register the tile. Now we can decrement it back to normal. 01198 // this MUST be called from the UPDATE traversal. 01199 ADJUST_UPDATE_TRAV_COUNT( this, -1 ); 01200 //adjustUpdateTraversalCount( -1 ); 01201 } 01202 } 01203 } 01204 01205 osgTerrain::TerrainTile::traverse( nv ); 01206 } 01207 01208 void 01209 CustomTile::releaseGLObjects(osg::State* state) const 01210 { 01211 Group::releaseGLObjects(state); 01212 01213 if ( _quickReleaseGLObjects && _terrainTechnique.valid() ) 01214 { 01215 //NOTE: crashes sometimes if OSG_RELEASE_DELAY is set -gw 01216 _terrainTechnique->releaseGLObjects( state ); 01217 } 01218 } 01219 #endif