osgEarth 2.1.1

/home/cube/sources/osgearth/src/osgEarthDrivers/engine_osgterrain/CustomTile.cpp

Go to the documentation of this file.
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
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Defines