osgEarth 2.1.1

/home/cube/sources/osgearth/src/osgEarthDrivers/engine_droam/MeshManager.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 "MeshManager"
00020 #include <osg/CullFace>
00021 #include <osg/Texture2D>
00022 
00023 // --------------------------------------------------------------------------
00024 
00025 struct ImageRequest : public osgEarth::TaskRequest
00026 {
00027     ImageRequest( ImageLayer* layer, const TileKey& key ) : _layer(layer), _key(key) { }
00028 
00029     void operator()( ProgressCallback* progress )
00030     {
00031         _result = _layer->createImage( _key );
00032     }
00033 
00034     osg::ref_ptr<ImageLayer> _layer;
00035     TileKey _key;
00036     GeoImage _result;
00037 };
00038 
00039 // --------------------------------------------------------------------------
00040 
00041 MeshManager::MeshManager( Manifold* manifold, Map* map ) :
00042 _manifold( manifold ),
00043 _map( map ),
00044 _minGeomLevel( 1 ),
00045 _minActiveLevel( 0 ),
00046 _maxActiveLevel( MAX_ACTIVE_LEVEL ),
00047 _maxJobsPerFrame( MAX_JOBS_PER_FRAME )
00048 {
00049     // fire up a task service to load textures.
00050     _imageService = new TaskService( "Image Service", 16 );
00051 
00052     _amrGeom = new AMRGeometry();
00053     _amrGeom->setDataVariance( osg::Object::DYNAMIC );
00054 
00055     _amrGeode = new osg::Geode();
00056     _amrGeode->addDrawable( _amrGeom.get() );
00057     _amrGeode->getOrCreateStateSet()->setAttributeAndModes( new osg::CullFace( osg::CullFace::BACK ), 1 );
00058 
00059     // set up the manifold framework.
00060     manifold->initialize( this );
00061 }
00062 
00063 NodeIndex
00064 MeshManager::addNode( const MeshNode& node )
00065 {
00066     NodeIndex result;
00067 
00068     if ( _freeList.empty() )
00069     {
00070         _nodes.push_back( node );
00071         result = _nodes.size()-1;
00072     }
00073     else
00074     {
00075         NodeIndex ni = _freeList.front();
00076         _freeList.pop();
00077         _nodes[ni] = node;
00078         result = ni;
00079     }
00080 
00081     return result;
00082 }
00083 
00084 NodeIndex
00085 MeshManager::addNode( const osg::Vec3d& manifoldCoord )
00086 {
00087     return addNode( _manifold->createNode( manifoldCoord ) );
00088 }
00089 
00090 void
00091 MeshManager::removeNode( NodeIndex ni )
00092 {
00093     _freeList.push( ni );
00094 }
00095 
00096 void
00097 MeshManager::queueForRefresh( Diamond* d )
00098 {
00099     //OE_NOTICE << d->_name << ": queued for refresh." << std::endl;
00100     _dirtyQueue.push( d );
00101 }
00102 
00103 void
00104 MeshManager::queueForSplit( Diamond* d, float priority )
00105 {    
00106     if ( !d->_queuedForSplit )
00107     {
00108         //OE_NOTICE << "q split: " << d->_name << std::endl;        
00109         _splitQueue.push( DiamondJob( d, priority ) );
00110         d->_queuedForSplit = true;
00111     }
00112 }
00113 
00114 void
00115 MeshManager::queueForMerge( Diamond* d, float priority )
00116 {
00117     if ( !d->_queuedForMerge )
00118     {
00119         //OE_NOTICE << "q merge: " << d->_name << std::endl;
00120         _mergeQueue.push( DiamondJob( d, priority ) );
00121         d->_queuedForMerge = true;
00122     }
00123 }
00124 
00125 void
00126 MeshManager::queueForImage( Diamond* d, float priority )
00127 {
00128     if ( !d->_queuedForImage && !d->_imageRequest.valid() )
00129     {
00130         //OE_NOTICE << "REQ: " << d->_key->str() << " queueing request..." << std::endl;
00131         d->_imageRequest = new ImageRequest( _map->getImageLayerAt(0), d->_key );
00132         _imageService->add( d->_imageRequest.get() );
00133         _imageQueue.push_back( DiamondJob( d, priority ) ); //.insert( DiamondJob( d, priority ) );
00134         d->_queuedForImage = true;
00135     }
00136 }
00137 
00138 static void
00139 outlineTexture( osg::Image* image )
00140 {
00141     for( int s=1; s<image->s()-1; ++s )
00142     {
00143         *((unsigned int*)image->data( s, 1 )) = 0x00ff00ff;
00144         *((unsigned int*)image->data( s, image->t()-2 )) = 0x00ff00ff;
00145     }
00146 
00147     for( int t=1; t<image->t()-1; ++t )
00148     {
00149         *((unsigned int*)image->data( 1, t )) = 0x00ff00ff;
00150         *((unsigned int*)image->data( image->s()-2, t )) = 0x00ff00ff;
00151     }
00152 }
00153 
00154 void
00155 MeshManager::update()
00156 {
00157     int j;
00158 
00159     // process the split queue. these are diamonds that have requested to be split into
00160     // all four children.
00161     for( j=0; j<_maxJobsPerFrame && !_splitQueue.empty(); ++j )
00162     //if( !_splitQueue.empty() )
00163     {
00164         Diamond* d = _splitQueue.top()._d.get();
00165         if ( d->_status == ACTIVE && d->referenceCount() > 1 )
00166         {
00167             if ( d->_queuedForSplit )
00168             {
00169                 //OE_NOTICE << "split: " << d->_name << "\n";
00170                 d->split();
00171                 d->_queuedForSplit = false;
00172                 d->_queuedForMerge = false;
00173             }
00174             else
00175             {
00176                 //OE_WARN << d->_name << " was in the split Q, but NOT marked for splitting!" << std::endl;
00177             }
00178         }
00179         else
00180         {
00181             // the diamond was removed while in the queue. ignore it.
00182         }
00183         _splitQueue.pop();
00184     }
00185 
00186     // process the merge queue. these are diamonds that have requested that all their
00187     // children be removed.
00188     // FUTURE: process jobs until we reach some sort of time quota?
00189 
00190     for( j=0; j<_maxJobsPerFrame && !_mergeQueue.empty(); ++j )
00191     {
00192         Diamond* d = _mergeQueue.top()._d.get();
00193         if ( d->_status == ACTIVE && d->referenceCount() > 1 )
00194         {
00195             if ( d->_queuedForMerge )
00196             {
00197                 //OE_NOTICE << "merge: " << d->_name << "\n";
00198 
00199                 //TODO: when you merge, children are recursively merged..thus the merge
00200                 //may take some time. rather it might be better to traverse and schedule
00201                 //child merges first.?
00202                 d->merge();
00203                 d->_queuedForMerge = false;
00204                 d->_queuedForSplit = false;
00205             }
00206             else
00207             {
00208                 //this means that the diamond was once queued for a merge, but then
00209                 // passed cull again.
00210                 //OE_WARN << d->_name << " was in the merge Q, but NOT marked for merging!" << std::endl;
00211             }
00212         }
00213         _mergeQueue.pop();
00214     }
00215 
00216     // process the texture image request queue.
00217     j=0;
00218     for( DiamondJobList::iterator i = _imageQueue.begin(); i != _imageQueue.end() && j < _maxJobsPerFrame; ++j )
00219     //if( _imageQueue.size() > 0 )
00220     {
00221         bool increment = true;
00222         bool remove = true;
00223 
00224         Diamond* d = i->_d.get();
00225 
00226         if ( d->_status == ACTIVE && d->referenceCount() > 1 && d->_imageRequest.valid() )
00227         {
00228             if ( d->_imageRequest->isCompleted() )
00229             {
00230                 //OE_NOTICE << "REQ: " << d->_key->str() << " completed" << std::endl;
00231                 osg::Texture2D* tex = 0L;
00232                 
00233 #ifdef USE_DEBUG_TEXTURES
00234 
00235                 tex = new osg::Texture2D();
00236                 tex->setImage( createDebugImage() );
00237 
00238 #else
00239 
00240                 GeoImage* geoImage = dynamic_cast<GeoImage*>( d->_imageRequest->getResult() );
00241                 if ( geoImage )
00242                 {
00243                     tex = new osg::Texture2D();
00244                     tex->setImage( geoImage->getImage() );
00245                 }
00246 
00247 #endif // USE_DEBUG_TEXTURES
00248 
00249                 if ( tex )
00250                 {
00251                     tex->setWrap( osg::Texture::WRAP_S, osg::Texture::CLAMP_TO_EDGE );
00252                     tex->setWrap( osg::Texture::WRAP_T, osg::Texture::CLAMP_TO_EDGE );
00253                     tex->setFilter( osg::Texture::MIN_FILTER, osg::Texture::LINEAR_MIPMAP_LINEAR );
00254                     tex->setFilter( osg::Texture::MAG_FILTER, osg::Texture::LINEAR );
00255                     d->_stateSet->setTextureAttributeAndModes( 0, tex, osg::StateAttribute::ON );
00256                     d->_stateSet->dirty(); // bump revision number so that users of this stateset can detect the change
00257                     d->_hasFinalImage = true;
00258 
00259 #ifdef OUTLINE_TEXTURES
00260 
00261                     outlineTexture( tex->getImage() );
00262 #endif
00263                 }
00264 
00265                 remove = true;
00266             }
00267 
00268             else
00269             {
00270                 remove = false;
00271             }
00272         }
00273 
00274 
00275         if ( remove )
00276         {
00277             d->_imageRequest = 0L;
00278             d->_queuedForImage = false;
00279             i = _imageQueue.erase( i );
00280         }
00281         else
00282         {
00283             ++i;
00284         }
00285     }
00286 
00287 #ifdef USE_DIRTY_QUEUE
00288 
00289     // process the dirty diamond queue. these are diamonds that have been changed and
00290     // need a new primitive set.
00291     // NOTE: we need to process the entire dirty queue each frame.
00292     while( _dirtyQueue.size() > 0 )
00293     {
00294         Diamond* d = _dirtyQueue.front().get();
00295 
00296         if ( d->_status == ACTIVE && d->referenceCount() > 1 )
00297         {
00298             // first, check to see whether the diamond's target stateset is ready. if so,
00299             // install it and mark it up to date.
00300             if ( d->_targetStateSetOwner->_stateSet->outOfSyncWith( d->_targetStateSetRevision ) )
00301             {            
00302                 d->_amrDrawable->_stateSet = d->_targetStateSetOwner->_stateSet.get();
00303 
00304                 d->_currentStateSetOwner = d->_targetStateSetOwner;
00305                 d->_targetStateSetOwner->_stateSet->sync( d->_targetStateSetRevision );
00306             }
00307 
00308             // rebuild the primitives now.
00309             d->refreshDrawable();
00310         }
00311         _dirtyQueue.pop();
00312     }
00313 
00314 #endif
00315 
00316     //OE_NOTICE << "dq size = " << _dirtyQueue.size() << "; splits = " << _splitQueue.size() << "; merges = " << _mergeQueue.size() << std::endl;
00317 }
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Defines