osgEarth 2.1.1
|
00001 /* -*-c++-*- */ 00002 /* osgEarth - Dynamic map generation toolkit for OpenSceneGraph 00003 * Copyright 2008-2010 Pelican Mapping 00004 * http://osgearth.org 00005 * 00006 * osgEarth is free software; you can redistribute it and/or modify 00007 * it under the terms of the GNU Lesser General Public License as published by 00008 * the Free Software Foundation; either version 2 of the License, or 00009 * (at your option) any later version. 00010 * 00011 * This program is distributed in the hope that it will be useful, 00012 * but WITHOUT ANY WARRANTY; without even the implied warranty of 00013 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 00014 * GNU Lesser General Public License for more details. 00015 * 00016 * You should have received a copy of the GNU Lesser General Public License 00017 * along with this program. If not, see <http://www.gnu.org/licenses/> 00018 */ 00019 #include <osgEarth/MapNode> 00020 #include <osgEarth/MaskNode> 00021 #include <osgEarth/FindNode> 00022 #include <osgEarth/Registry> 00023 #include <osgEarth/ShaderComposition> 00024 #include <osgEarth/OverlayDecorator> 00025 #include <osg/ArgumentParser> 00026 #include <osg/PagedLOD> 00027 00028 using namespace osgEarth; 00029 00030 #define LC "[MapNode] " 00031 00032 //--------------------------------------------------------------------------- 00033 00034 namespace 00035 { 00036 // adapter that lets MapNode listen to Map events 00037 struct MapNodeMapCallbackProxy : public MapCallback 00038 { 00039 MapNodeMapCallbackProxy(MapNode* node) : _node(node) { } 00040 00041 void onModelLayerAdded( ModelLayer* layer, unsigned int index ) { 00042 _node->onModelLayerAdded( layer, index ); 00043 } 00044 void onModelLayerRemoved( ModelLayer* layer ) { 00045 _node->onModelLayerRemoved( layer ); 00046 } 00047 void onModelLayerMoved( ModelLayer* layer, unsigned int oldIndex, unsigned int newIndex ) { 00048 _node->onModelLayerMoved( layer, oldIndex, newIndex); 00049 } 00050 #if 0 00051 void onMaskLayerAdded( MaskLayer* layer ) { 00052 _node->onMaskLayerAdded( layer ); 00053 } 00054 void onMaskLayerRemoved( MaskLayer* layer ) { 00055 _node->onMaskLayerRemoved( layer ); 00056 } 00057 #endif 00058 00059 osg::observer_ptr<MapNode> _node; 00060 }; 00061 00062 // converys overlay property changes to the OverlayDecorator in MapNode. 00063 class MapModelLayerCallback : public ModelLayerCallback 00064 { 00065 public: 00066 MapModelLayerCallback(MapNode* mapNode) : _node(mapNode) { } 00067 00068 virtual void onOverlayChanged(ModelLayer* layer) 00069 { 00070 _node->onModelLayerOverlayChanged( layer ); 00071 } 00072 00073 osg::observer_ptr<MapNode> _node; 00074 }; 00075 } 00076 00077 //--------------------------------------------------------------------------- 00078 00079 class RemoveBlacklistedFilenamesVisitor : public osg::NodeVisitor 00080 { 00081 public: 00082 RemoveBlacklistedFilenamesVisitor(): 00083 osg::NodeVisitor(osg::NodeVisitor::TRAVERSE_ALL_CHILDREN), 00084 _numRemoved(0) 00085 { 00086 } 00087 00088 virtual void apply(osg::PagedLOD& node) 00089 { 00090 //The PagedLOD node will contain two filenames, the first is empty and is the actual geometry of the 00091 //tile and the second is the filename of the next tile. 00092 if (node.getNumFileNames() > 1) 00093 { 00094 //Get the child filename 00095 const std::string &filename = node.getFileName(1); 00096 if (osgEarth::Registry::instance()->isBlacklisted(filename)) 00097 { 00098 //If the tile is blacklisted, we set the actual geometry, child 0, to always display 00099 //and the second child to never display 00100 node.setRange(0, 0, FLT_MAX); 00101 node.setRange(1, FLT_MAX, FLT_MAX); 00102 } 00103 else 00104 { 00105 //If the child is not blacklisted, it is possible that it could have been blacklisted previously so reset the 00106 //ranges of both the first and second children. This gives the second child another 00107 //chance to be traversed in case a layer was added that might have data. 00108 osg::ref_ptr< MapNode::TileRangeData > ranges = static_cast< MapNode::TileRangeData* >(node.getUserData()); 00109 if (ranges) 00110 { 00111 node.setRange(0, ranges->_minRange, ranges->_maxRange); 00112 node.setRange(1, 0, ranges->_minRange); 00113 } 00114 } 00115 00116 } 00117 traverse(node); 00118 } 00119 00120 unsigned int _numRemoved; 00121 }; 00122 00123 //--------------------------------------------------------------------------- 00124 00125 MapNode* 00126 MapNode::load(osg::ArgumentParser& args) 00127 { 00128 for( unsigned i=1; i<args.argc(); ++i ) 00129 { 00130 if ( args[i] && endsWith(args[i], ".earth") ) 00131 { 00132 osg::ref_ptr<osg::Node> output; 00133 if ( HTTPClient::readNodeFile( args[i], output ) == HTTPClient::RESULT_OK ) 00134 { 00135 return dynamic_cast<MapNode*>( output.release() ); 00136 } 00137 } 00138 } 00139 return 0L; 00140 } 00141 00142 //--------------------------------------------------------------------------- 00143 00144 MapNode::MapNode() : 00145 _map( new Map() ) 00146 { 00147 init(); 00148 } 00149 00150 MapNode::MapNode( Map* map ) : 00151 _map( map ) 00152 { 00153 init(); 00154 } 00155 00156 MapNode::MapNode( const MapNodeOptions& options ) : 00157 _map( new Map() ), 00158 _mapNodeOptions( options ) 00159 { 00160 init(); 00161 } 00162 00163 MapNode::MapNode( Map* map, const MapNodeOptions& options ) : 00164 _map( map? map : new Map() ), 00165 _mapNodeOptions( options ) 00166 { 00167 init(); 00168 } 00169 00170 void 00171 MapNode::init() 00172 { 00173 // Protect the MapNode from the Optimizer 00174 setDataVariance(osg::Object::DYNAMIC); 00175 00176 setName( "osgEarth::MapNode" ); 00177 00178 // Since we have global uniforms in the stateset, mark it dynamic so it is immune to 00179 // multi-threaded overlap 00180 // TODO: do we need this anymore? there are no more global uniforms in here.. gw 00181 getOrCreateStateSet()->setDataVariance(osg::Object::DYNAMIC); 00182 00183 _modelLayerCallback = new MapModelLayerCallback(this); 00184 00185 _maskLayerNode = 0L; 00186 _lastNumBlacklistedFilenames = 0; 00187 00188 // Set the global proxy settings 00189 // TODO: this should probably happen elsewhere, like in the registry? 00190 if ( _mapNodeOptions.proxySettings().isSet() ) 00191 { 00192 HTTPClient::setProxySettings( _mapNodeOptions.proxySettings().get() ); 00193 } 00194 00195 // establish global driver options. These are OSG reader-writer options that 00196 // will make their way to any read* calls down the pipe 00197 const osgDB::ReaderWriter::Options* global_options = _map->getGlobalOptions(); 00198 osg::ref_ptr<osgDB::ReaderWriter::Options> local_options = global_options ? 00199 new osgDB::ReaderWriter::Options( *global_options ) : 00200 NULL; 00201 00202 if ( local_options.valid() ) 00203 { 00204 OE_INFO << LC 00205 << "Options string = " 00206 << (local_options.valid()? local_options->getOptionString() : "<empty>") 00207 << std::endl; 00208 } 00209 00210 // TODO: not sure why we call this here 00211 _map->setGlobalOptions( local_options.get() ); 00212 00213 // overlays: 00214 _pendingOverlayAutoSetTextureUnit = true; 00215 00216 // load and attach the terrain engine, but don't initialize it until we need it 00217 const TerrainOptions& terrainOptions = _mapNodeOptions.getTerrainOptions(); 00218 00219 _terrainEngine = TerrainEngineNodeFactory::create( _map.get(), terrainOptions ); 00220 _terrainEngineInitialized = false; 00221 00222 // the engine needs a container so we can set lighting state on the container and 00223 // not on the terrain engine itself. Setting the dynamic variance will prevent 00224 // an optimizer from collapsing the empty group node. 00225 _terrainEngineContainer = new osg::Group(); 00226 _terrainEngineContainer->setDataVariance( osg::Object::DYNAMIC ); 00227 this->addChild( _terrainEngineContainer.get() ); 00228 00229 // initialize terrain-level lighting: 00230 if ( terrainOptions.enableLighting().isSet() ) 00231 { 00232 _terrainEngineContainer->getOrCreateStateSet()->setMode( GL_LIGHTING, terrainOptions.enableLighting().value() ? 00233 osg::StateAttribute::ON | osg::StateAttribute::PROTECTED : 00234 osg::StateAttribute::OFF | osg::StateAttribute::PROTECTED ); 00235 } 00236 00237 if ( _terrainEngine.valid() ) 00238 { 00239 // inform the terrain engine of the map information now so that it can properly 00240 // initialize it's CoordinateSystemNode. This is necessary in order to support 00241 // manipulators and to set up the texture compositor prior to frame-loop 00242 // initialization. 00243 _terrainEngine->preInitialize( _map.get(), terrainOptions ); 00244 00245 _terrainEngineContainer->addChild( _terrainEngine.get() ); 00246 } 00247 else 00248 OE_WARN << "FAILED to create a terrain engine for this map" << std::endl; 00249 00250 // make a group for the model layers: 00251 _models = new osg::Group(); 00252 _models->setName( "osgEarth::MapNode.modelsGroup" ); 00253 addChild( _models.get() ); 00254 00255 // make a group for overlay model layers: 00256 _overlayModels = new osg::Group(); 00257 _overlayModels->setName( "osgEarth::MapNode.overlayModelsGroup" ); 00258 00259 // a decorator for overlay models: 00260 _overlayDecorator = new OverlayDecorator(); 00261 if ( _mapNodeOptions.overlayVertexWarping().isSet() ) 00262 _overlayDecorator->setVertexWarping( *_mapNodeOptions.overlayVertexWarping() ); 00263 if ( _mapNodeOptions.overlayBlending().isSet() ) 00264 _overlayDecorator->setOverlayBlending( *_mapNodeOptions.overlayBlending() ); 00265 if ( _mapNodeOptions.overlayTextureSize().isSet() ) 00266 _overlayDecorator->setTextureSize( *_mapNodeOptions.overlayTextureSize() ); 00267 addTerrainDecorator( _overlayDecorator.get() ); 00268 00269 // install any pre-existing model layers: 00270 ModelLayerVector modelLayers; 00271 _map->getModelLayers( modelLayers ); 00272 int modelLayerIndex = 0; 00273 for( ModelLayerVector::const_iterator k = modelLayers.begin(); k != modelLayers.end(); k++, modelLayerIndex++ ) 00274 { 00275 onModelLayerAdded( k->get(), modelLayerIndex ); 00276 } 00277 00278 #if 0 00279 // install any pre-existing mask layer: 00280 if ( _map->getTerrainMaskLayer() ) 00281 { 00282 onMaskLayerAdded( _map->getTerrainMaskLayer() ); 00283 } 00284 #endif 00285 00286 _mapCallback = new MapNodeMapCallbackProxy(this); 00287 // install a layer callback for processing further map actions: 00288 _map->addMapCallback( _mapCallback.get() ); 00289 00290 osg::StateSet* ss = getOrCreateStateSet(); 00291 //ss->setAttributeAndModes( new osg::CullFace() ); //, osg::StateAttribute::ON); 00292 //ss->setAttributeAndModes( new osg::PolygonOffset( -1, -1 ) ); 00293 00294 if ( _mapNodeOptions.enableLighting().isSet() ) 00295 { 00296 ss->setMode( GL_LIGHTING, _mapNodeOptions.enableLighting().value() ? 00297 osg::StateAttribute::ON | osg::StateAttribute::PROTECTED : 00298 osg::StateAttribute::OFF | osg::StateAttribute::PROTECTED ); 00299 } 00300 00301 dirtyBound(); 00302 00303 // register for event traversals so we can deal with blacklisted filenames 00304 adjustEventTraversalCount( 1 ); 00305 } 00306 00307 MapNode::~MapNode() 00308 { 00309 _map->removeMapCallback( _mapCallback.get() ); 00310 00311 ModelLayerVector modelLayers; 00312 _map->getModelLayers( modelLayers ); 00313 //Remove our model callback from any of the model layers in the map 00314 for (osgEarth::ModelLayerVector::iterator itr = modelLayers.begin(); itr != modelLayers.end(); ++itr) 00315 { 00316 this->onModelLayerRemoved( itr->get() ); 00317 } 00318 } 00319 00320 osg::BoundingSphere 00321 MapNode::computeBound() const 00322 { 00323 osg::BoundingSphere bs; 00324 if ( getTerrainEngine() ) 00325 { 00326 bs.expandBy( getTerrainEngine()->getBound() ); 00327 } 00328 if ( _models.valid() ) 00329 bs.expandBy( _models->getBound() ); 00330 return bs; 00331 } 00332 00333 Map* 00334 MapNode::getMap() 00335 { 00336 return _map.get(); 00337 } 00338 00339 TerrainEngineNode* 00340 MapNode::getTerrainEngine() const 00341 { 00342 if ( !_terrainEngineInitialized && _terrainEngine.valid() ) 00343 { 00344 _terrainEngine->postInitialize( _map.get(), getMapNodeOptions().getTerrainOptions() ); 00345 MapNode* me = const_cast< MapNode* >(this); 00346 me->_terrainEngineInitialized = true; 00347 me->dirtyBound(); 00348 } 00349 return _terrainEngine.get(); 00350 } 00351 00352 osg::Group* 00353 MapNode::getModelLayerGroup() const 00354 { 00355 return _models.get(); 00356 } 00357 00358 const MapNodeOptions& 00359 MapNode::getMapNodeOptions() const 00360 { 00361 return _mapNodeOptions; 00362 } 00363 00364 MapNode* 00365 MapNode::findMapNode( osg::Node* graph ) 00366 { 00367 return findTopMostNodeOfType<MapNode>( graph ); 00368 } 00369 00370 bool 00371 MapNode::isGeocentric() const 00372 { 00373 return _map->isGeocentric(); 00374 } 00375 00376 void 00377 MapNode::onModelLayerAdded( ModelLayer* layer, unsigned int index ) 00378 { 00379 osg::Node* node = layer->getOrCreateNode(); 00380 00381 layer->addCallback(_modelLayerCallback.get() ); 00382 00383 if ( node ) 00384 { 00385 if ( _modelLayerNodes.find( layer ) != _modelLayerNodes.end() ) 00386 { 00387 OE_WARN 00388 << "Illegal: tried to add the name model layer more than once: " 00389 << layer->getName() 00390 << std::endl; 00391 } 00392 else 00393 { 00394 if ( dynamic_cast<TerrainDecorator*>(node) || dynamic_cast<osgSim::OverlayNode*>(node) ) 00395 { 00396 OE_INFO << LC << "Installing overlay node" << std::endl; 00397 addTerrainDecorator( node->asGroup() ); 00398 } 00399 else 00400 { 00401 if ( layer->getOverlay() ) 00402 { 00403 _overlayModels->addChild( node ); // todo: index? 00404 updateOverlayGraph(); 00405 } 00406 else 00407 { 00408 _models->insertChild( index, node ); 00409 } 00410 } 00411 00412 ModelSource* ms = layer->getModelSource(); 00413 if ( ms && ms->getOptions().renderOrder().isSet() ) 00414 { 00415 node->getOrCreateStateSet()->setRenderBinDetails( 00416 ms->getOptions().renderOrder().value(), "RenderBin" ); 00417 } 00418 00419 _modelLayerNodes[ layer ] = node; 00420 } 00421 00422 dirtyBound(); 00423 } 00424 } 00425 00426 void 00427 MapNode::onModelLayerRemoved( ModelLayer* layer ) 00428 { 00429 if ( layer ) 00430 { 00431 layer->removeCallback( _modelLayerCallback.get() ); 00432 00433 // look up the node associated with this model layer. 00434 ModelLayerNodeMap::iterator i = _modelLayerNodes.find( layer ); 00435 if ( i != _modelLayerNodes.end() ) 00436 { 00437 osg::Node* node = i->second; 00438 00439 if ( dynamic_cast<TerrainDecorator*>( node ) || dynamic_cast<osgSim::OverlayNode*>( node ) ) 00440 { 00441 removeTerrainDecorator( node->asGroup() ); 00442 } 00443 else 00444 { 00445 if ( layer->getModelLayerOptions().overlay() == true ) 00446 { 00447 _overlayModels->removeChild( node ); 00448 updateOverlayGraph(); 00449 } 00450 else 00451 { 00452 _models->removeChild( node ); 00453 } 00454 } 00455 00456 _modelLayerNodes.erase( i ); 00457 } 00458 00459 dirtyBound(); 00460 } 00461 } 00462 00463 void 00464 MapNode::onModelLayerMoved( ModelLayer* layer, unsigned int oldIndex, unsigned int newIndex ) 00465 { 00466 if ( layer ) 00467 { 00468 // look up the node associated with this model layer. 00469 ModelLayerNodeMap::iterator i = _modelLayerNodes.find( layer ); 00470 if ( i != _modelLayerNodes.end() ) 00471 { 00472 osg::Node* node = i->second; 00473 00474 if ( dynamic_cast<osgSim::OverlayNode*>( node ) ) 00475 { 00476 // treat overlay node as a special case 00477 } 00478 else 00479 { 00480 _models->removeChild( node ); 00481 _models->insertChild( newIndex, node ); 00482 } 00483 } 00484 00485 dirtyBound(); 00486 } 00487 } 00488 00489 struct MaskNodeFinder : public osg::NodeVisitor { 00490 MaskNodeFinder() : osg::NodeVisitor( osg::NodeVisitor::TRAVERSE_ALL_CHILDREN ) { } 00491 void apply( osg::Group& group ) { 00492 if ( dynamic_cast<MaskNode*>( &group ) ) { 00493 _groups.push_back( &group ); 00494 } 00495 traverse(group); 00496 } 00497 std::list< osg::Group* > _groups; 00498 }; 00499 00500 void 00501 MapNode::addTerrainDecorator(osg::Group* decorator) 00502 { 00503 if ( _terrainEngine.valid() ) 00504 { 00505 decorator->addChild( _terrainEngine.get() ); 00506 _terrainEngine->getParent(0)->replaceChild( _terrainEngine.get(), decorator ); 00507 dirtyBound(); 00508 00509 TerrainDecorator* td = dynamic_cast<TerrainDecorator*>( decorator ); 00510 if ( td ) 00511 td->onInstall( _terrainEngine.get() ); 00512 } 00513 } 00514 00515 void 00516 MapNode::removeTerrainDecorator(osg::Group* decorator) 00517 { 00518 if ( _terrainEngine.valid() ) 00519 { 00520 TerrainDecorator* td = dynamic_cast<TerrainDecorator*>( decorator ); 00521 if ( td ) 00522 td->onUninstall( _terrainEngine.get() ); 00523 00524 osg::Node* child = _terrainEngine.get(); 00525 for( osg::Group* g = child->getParent(0); g != _terrainEngineContainer.get(); ) 00526 { 00527 if ( g == decorator ) 00528 { 00529 g->getParent(0)->replaceChild( g, child ); 00530 g->removeChild( child ); 00531 break; 00532 } 00533 child = g; 00534 g = g->getParent(0); 00535 } 00536 dirtyBound(); 00537 } 00538 } 00539 00540 void 00541 MapNode::adjustEventTraversalCount( int delta ) 00542 { 00543 int oldCount = this->getNumChildrenRequiringEventTraversal(); 00544 if ( oldCount + delta >= 0 ) 00545 this->setNumChildrenRequiringEventTraversal( (unsigned int)(oldCount + delta) ); 00546 } 00547 00548 void 00549 MapNode::traverse( osg::NodeVisitor& nv ) 00550 { 00551 if ( nv.getVisitorType() == osg::NodeVisitor::EVENT_VISITOR ) 00552 { 00553 unsigned int numBlacklist = Registry::instance()->getNumBlacklistedFilenames(); 00554 if (numBlacklist != _lastNumBlacklistedFilenames) 00555 { 00556 //Only remove the blacklisted filenames if new filenames have been added since last time. 00557 _lastNumBlacklistedFilenames = numBlacklist; 00558 RemoveBlacklistedFilenamesVisitor v; 00559 //accept( v ); 00560 _terrainEngine->accept( v ); 00561 } 00562 } 00563 00564 osg::Group::traverse( nv ); 00565 } 00566 00567 void 00568 MapNode::onModelLayerOverlayChanged( ModelLayer* layer ) 00569 { 00570 OE_NOTICE << "Overlay changed to " << layer->getOverlay() << std::endl; 00571 osg::ref_ptr< osg::Group > origParent = layer->getOverlay() ? _models.get() : _overlayModels.get(); 00572 osg::ref_ptr< osg::Group > newParent = layer->getOverlay() ? _overlayModels.get() : _models.get(); 00573 00574 osg::ref_ptr< osg::Node > node = layer->getOrCreateNode(); 00575 if (node.valid()) 00576 { 00577 //Remove it from the original parent and add it to the new parent 00578 origParent->removeChild( node.get() ); 00579 newParent->addChild( node.get() ); 00580 } 00581 00582 updateOverlayGraph(); 00583 } 00584 00585 void 00586 MapNode::updateOverlayGraph() 00587 { 00588 if ( _overlayModels->getNumChildren() > 0 && _overlayDecorator->getOverlayGraph() != _overlayModels.get() ) 00589 { 00590 _overlayDecorator->setOverlayGraph( _overlayModels.get() ); 00591 } 00592 else if ( _overlayModels->getNumChildren() == 0 && _overlayDecorator->getOverlayGraph() == _overlayModels.get() ) 00593 { 00594 _overlayDecorator->setOverlayGraph( 0L ); 00595 } 00596 }