osgEarth 2.1.1

/home/cube/sources/osgearth/src/osgEarthDrivers/engine_osgterrain/Terrain.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 #include "Terrain"
00020 #include "Tile"
00021 #include "TransparentLayer"
00022 
00023 #include <osgEarth/Registry>
00024 #include <osgEarth/Map>
00025 #include <osgEarth/FindNode>
00026 #include <osgEarth/ThreadingUtils>
00027 
00028 #include <osg/NodeCallback>
00029 #include <osg/NodeVisitor>
00030 #include <osg/Node>
00031 #include <osgGA/EventVisitor>
00032 
00033 using namespace osgEarth;
00034 using namespace OpenThreads;
00035 
00036 #define LC "[Terrain] "
00037 
00038 //----------------------------------------------------------------------------
00039 
00040 namespace
00041 {
00045     struct NestingDrawCallback : public osg::Camera::DrawCallback
00046     {
00047         NestingDrawCallback( osg::Camera::DrawCallback* next ) : _next(next) { }
00048 
00049         virtual void operator()( osg::RenderInfo& renderInfo ) const
00050         {
00051             dispatch( renderInfo );
00052         }
00053 
00054         void dispatch( osg::RenderInfo& renderInfo ) const
00055         {
00056             if ( _next )
00057                 _next->operator ()( renderInfo );
00058         }
00059 
00060         osg::ref_ptr<osg::Camera::DrawCallback> _next;
00061     };
00062 
00063 
00064     // a simple draw callback, to be installed on a Camera, that tells all Terrains to
00065     // release GL memory on any expired tiles.
00066     struct QuickReleaseGLCallback : public NestingDrawCallback
00067     {
00068             typedef std::vector< osg::observer_ptr<Terrain> > ObserverTerrainList;
00069 
00070         QuickReleaseGLCallback( Terrain* terrain, osg::Camera::DrawCallback* next )
00071             : NestingDrawCallback(next), _terrain(terrain) { }
00072 
00073         virtual void operator()( osg::RenderInfo& renderInfo ) const
00074         {
00075             osg::ref_ptr<Terrain> terrainSafe = _terrain.get();
00076             if ( terrainSafe.valid() )
00077             {
00078                 terrainSafe->releaseGLObjectsForTiles( renderInfo.getState() );
00079             }
00080             dispatch( renderInfo );
00081         }
00082 
00083         osg::observer_ptr<Terrain> _terrain;
00084     };
00085 }
00086 
00087 //----------------------------------------------------------------------------
00088 
00089 Terrain::Terrain(const MapFrame& update_mapf, 
00090                  const MapFrame& cull_mapf, 
00091                  OSGTileFactory* tileFactory,
00092                  bool            quickReleaseGLObjects ) :
00093 
00094 _tileFactory( tileFactory ),
00095 _registeredWithReleaseGLCallback( false ),
00096 _update_mapf( update_mapf ),
00097 _cull_mapf( cull_mapf ),
00098 _onDemandDelay( 2 ),
00099 _quickReleaseGLObjects( quickReleaseGLObjects ),
00100 _quickReleaseCallbackInstalled( false ),
00101 _alwaysUpdate( false ),
00102 _sampleRatio( 1.0f ),
00103 _verticalScale( 1.0f )
00104 {
00105     this->setThreadSafeRefUnref( true );
00106 
00107     // the EVENT_VISITOR will reset this to 0 once the "delay" is expired.
00108     _alwaysUpdate = false;
00109     setNumChildrenRequiringUpdateTraversal( 1 );
00110 
00111     // register for events in order to support ON_DEMAND frame scheme
00112     setNumChildrenRequiringEventTraversal( 1 );
00113 
00114     getOrCreateStateSet()->setMode(GL_BLEND , osg::StateAttribute::ON);    
00115 }
00116 
00117 Terrain::~Terrain()
00118 {
00119     // detach all the tiles from the terrain first. Otherwise osgTerrain::Terrain
00120     // will crap out.
00121     for( TileTable::iterator i = _tiles.begin(); i != _tiles.end(); ++i )
00122     {
00123         i->second->attachToTerrain( 0L );
00124     }
00125     _tiles.clear();
00126 }
00127 
00128 void
00129 Terrain::setTechniquePrototype( TerrainTechnique* value )
00130 {
00131     _techPrototype = value;
00132 }
00133 
00134 TerrainTechnique*
00135 Terrain::cloneTechnique() const
00136 {
00137     return osg::clone( _techPrototype.get(), osg::CopyOp::DEEP_COPY_ALL );
00138 }
00139 
00140 Tile*
00141 Terrain::createTile(const TileKey& key, GeoLocator* keyLocator) const
00142 {
00143     return new Tile( key, keyLocator, this->getQuickReleaseGLObjects() );
00144 }
00145 
00146 void
00147 Terrain::setVerticalScale( float value )
00148 {
00149     if ( value != _verticalScale )
00150     {
00151         _verticalScale = value;
00152     }
00153 }
00154 
00155 void
00156 Terrain::setSampleRatio( float value )
00157 {
00158     if ( value != _sampleRatio )
00159     {
00160         _sampleRatio = value;
00161     }
00162 }
00163 
00164 void
00165 Terrain::getTiles( TileVector& out )
00166 {
00167     Threading::ScopedReadLock lock( _tilesMutex );
00168     out.clear();
00169     out.reserve( _tiles.size() );
00170     for( TileTable::const_iterator i = _tiles.begin(); i != _tiles.end(); ++i )
00171         out.push_back( i->second.get() );
00172 }
00173 
00174 void
00175 Terrain::registerTile( Tile* newTile )
00176 {
00177     Threading::ScopedWriteLock exclusiveTileTableLock( _tilesMutex );
00178     _tiles[ newTile->getTileId() ] = newTile;
00179 }
00180 
00181 // immediately release GL memory for any expired tiles.
00182 // called from the DRAW thread (QuickReleaseGLCallback). 
00183 void
00184 Terrain::releaseGLObjectsForTiles(osg::State* state)
00185 {
00186     OpenThreads::ScopedLock<Mutex> lock( _tilesToReleaseMutex );
00187 
00188     for( TileVector::iterator i = _tilesToRelease.begin(); i != _tilesToRelease.end(); ++i )
00189     {
00190         i->get()->releaseGLObjects( state );
00191     }
00192 
00193     _tilesToRelease.clear();
00194 
00195     //while( _tilesToRelease.size() > 0 )
00196     //{
00197     //    _tilesToRelease.front()->releaseGLObjects( state );
00198     //    _tilesToRelease.pop();
00199     //}
00200 }
00201 
00202 void
00203 Terrain::traverse( osg::NodeVisitor &nv )
00204 {
00205     // UPDATE runs whenever a Tile runs its update traversal on the first pass.
00206     // i.e., only runs then a new Tile is born.
00207     if ( nv.getVisitorType() == osg::NodeVisitor::UPDATE_VISITOR )
00208     {
00209         // if the terrain engine requested "quick release", install the quick release
00210         // draw callback now.
00211         if ( _quickReleaseGLObjects && !_quickReleaseCallbackInstalled )
00212         {
00213             osg::Camera* cam = findFirstParentOfType<osg::Camera>( this );
00214             if ( cam )
00215             {
00216                 cam->setPostDrawCallback( new QuickReleaseGLCallback( this, cam->getPostDrawCallback() ) );
00217                 _quickReleaseCallbackInstalled = true;
00218                 OE_INFO << LC << "Quick release enabled" << std::endl;
00219             }
00220         }
00221 
00222         // Collect any "dead" tiles and queue them for shutdown. Since UPDATE only runs
00223         // when new tiles arrive, this clears out old tiles from the queue at that time.
00224         // Another approach might be to use an observer_ptr instead...but then we may
00225         // not be able to use the quick-release.
00226         {
00227             Threading::ScopedWriteLock tileTableExclusiveLock( _tilesMutex );
00228 
00229             for( TileTable::iterator i = _tiles.begin(); i != _tiles.end(); )
00230             {
00231                 Tile* tile = i->second.get();
00232                 if ( tile->getNumParents() == 0 && tile->getHasBeenTraversed() )
00233                 {
00234                     _tilesToShutDown.push_back( tile );
00235                     
00236                     // i is incremented prior to calling erase, but i's previous value goes to erase,
00237                     // maintaining validity
00238                     _tiles.erase( i++ );
00239                 }
00240                 else
00241                     ++i;
00242             }
00243         }
00244 
00245         // Remove any dead tiles from the main tile table, while at the same time queuing 
00246         // any tiles that require quick-release. This criticial section requires an exclusive
00247         // lock on the main tile table.
00248         if ( _tilesToShutDown.size() > 0 ) // quick no-lock check..
00249         {
00250             Threading::ScopedMutexLock tilesToReleaseExclusiveLock( _tilesToReleaseMutex );
00251 
00252             // Shut down any dead tiles once there tasks are complete.
00253             for( TileList::iterator i = _tilesToShutDown.begin(); i != _tilesToShutDown.end(); )
00254             {
00255                 Tile* tile = i->get();
00256                 if ( tile && tile->cancelActiveTasks() )
00257                 {
00258                     if ( _quickReleaseGLObjects && _quickReleaseCallbackInstalled )
00259                     {
00260                         _tilesToRelease.push_back( tile );
00261                     }
00262 
00263                     i = _tilesToShutDown.erase( i );
00264                 }
00265                 else
00266                     ++i;
00267             }
00268         }
00269 
00270         // call subclass to continue update..
00271         updateTraversal( nv );
00272     }
00273     
00274     else if ( nv.getVisitorType() == osg::NodeVisitor::EVENT_VISITOR )
00275     {
00276         // in OSG's "ON_DEMAND" frame scheme, OSG runs the event visitor as part of the
00277         // test to see if a frame is needed. In sequential/preemptive mode, we need to 
00278         // check whether there are any pending tasks running. 
00279 
00280         // In addition, once the tasks run out, we continue to delay on-demand rendering
00281         // for another full frame so that the event dispatchers can catch up.
00282 
00283         if ( _tilesToShutDown.size() > 0 )
00284         {
00285             setDelay( 2 );
00286         }
00287 
00288         else if ( _onDemandDelay <= 0 )
00289         {
00290             unsigned numActiveTasks = getNumActiveTasks();
00291             if ( numActiveTasks > 0 )
00292             {
00293                 setDelay( 2 );
00294             }
00295         }
00296 
00297         //OE_INFO << "Tasks = " << numTasks << std::endl;
00298 
00299         if ( _onDemandDelay > 0 )
00300         {
00301             osgGA::EventVisitor* ev = dynamic_cast<osgGA::EventVisitor*>( &nv );
00302             ev->getActionAdapter()->requestRedraw();
00303             decDelay();
00304         }
00305     }
00306 
00307     osg::Group::traverse( nv );
00308 }
00309 
00310 void
00311 Terrain::setDelay( unsigned frames )
00312 {
00313     if ( _onDemandDelay == 0 && !_alwaysUpdate )
00314     {
00315         ADJUST_UPDATE_TRAV_COUNT( this, 1 );
00316     }
00317     _onDemandDelay = frames;
00318 }
00319 
00320 void
00321 Terrain::decDelay()
00322 {
00323     _onDemandDelay--;
00324     if ( _onDemandDelay == 0 && !_alwaysUpdate )
00325     {
00326         ADJUST_UPDATE_TRAV_COUNT(this, -1);
00327     }
00328 }
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Defines