void MapNode::init() { // Take a reference to this object so that it doesn't get inadvertently // deleting during startup. It is possible that during startup, a driver // will load that will take a reference to the MapNode (like in a // ModelSource node operation) and we don't want that deleting the MapNode // out from under us. // This is paired by an unref_nodelete() at the end of this method. this->ref(); // Protect the MapNode from the Optimizer setDataVariance(osg::Object::DYNAMIC); // initialize 0Ls _terrainEngine = 0L; _terrainEngineContainer = 0L; _overlayDecorator = 0L; setName( "osgEarth::MapNode" ); // Since we have global uniforms in the stateset, mark it dynamic so it is immune to // multi-threaded overlap // TODO: do we need this anymore? there are no more global uniforms in here.. gw getOrCreateStateSet()->setDataVariance(osg::Object::DYNAMIC); _modelLayerCallback = new MapModelLayerCallback(this); _maskLayerNode = 0L; _lastNumBlacklistedFilenames = 0; // Set the global proxy settings // TODO: this should probably happen elsewhere, like in the registry? if ( _mapNodeOptions.proxySettings().isSet() ) { HTTPClient::setProxySettings( _mapNodeOptions.proxySettings().get() ); } // establish global driver options. These are OSG reader-writer options that // will make their way to any read* calls down the pipe const osgDB::Options* global_options = _map->getGlobalOptions(); osg::ref_ptr<osgDB::Options> local_options = global_options ? Registry::instance()->cloneOrCreateOptions( global_options ) : NULL; if ( local_options.valid() ) { OE_INFO << LC << "Options string = " << (local_options.valid()? local_options->getOptionString() : "<empty>") << std::endl; } // TODO: not sure why we call this here _map->setGlobalOptions( local_options.get() ); // load and attach the terrain engine, but don't initialize it until we need it const TerrainOptions& terrainOptions = _mapNodeOptions.getTerrainOptions(); _terrainEngine = TerrainEngineNodeFactory::create( _map.get(), terrainOptions ); _terrainEngineInitialized = false; // the engine needs a container so we can set lighting state on the container and // not on the terrain engine itself. Setting the dynamic variance will prevent // an optimizer from collapsing the empty group node. _terrainEngineContainer = new osg::Group(); _terrainEngineContainer->setDataVariance( osg::Object::DYNAMIC ); this->addChild( _terrainEngineContainer ); // initialize terrain-level lighting: if ( terrainOptions.enableLighting().isSet() ) { _terrainEngineContainer->getOrCreateStateSet()->setMode( GL_LIGHTING, terrainOptions.enableLighting().value() ? 1 : 0 ); } if ( _terrainEngine ) { // inform the terrain engine of the map information now so that it can properly // initialize it's CoordinateSystemNode. This is necessary in order to support // manipulators and to set up the texture compositor prior to frame-loop // initialization. _terrainEngine->preInitialize( _map.get(), terrainOptions ); _terrainEngineContainer->addChild( _terrainEngine ); } else { OE_WARN << "FAILED to create a terrain engine for this map" << std::endl; } // make a group for the model layers. // NOTE: for now, we are going to nullify any shader programs that occur above the model // group, since it does not YET support shader composition. Programs defined INSIDE a // model layer will still work OK though. _models = new osg::Group(); _models->setName( "osgEarth::MapNode.modelsGroup" ); addChild( _models.get() ); // a decorator for overlay models: _overlayDecorator = new OverlayDecorator(); _overlayDecorator->setOverlayGraphTraversalMask( terrainOptions.secondaryTraversalMask().value() ); // install the Draping technique for overlays: { DrapingTechnique* draping = new DrapingTechnique(); if ( _mapNodeOptions.overlayBlending().isSet() ) draping->setOverlayBlending( *_mapNodeOptions.overlayBlending() ); if ( _mapNodeOptions.overlayTextureSize().isSet() ) draping->setTextureSize( *_mapNodeOptions.overlayTextureSize() ); if ( _mapNodeOptions.overlayMipMapping().isSet() ) draping->setMipMapping( *_mapNodeOptions.overlayMipMapping() ); if ( _mapNodeOptions.overlayAttachStencil().isSet() ) draping->setAttachStencil( *_mapNodeOptions.overlayAttachStencil() ); _overlayDecorator->addTechnique( draping ); } // install the Clamping technique for overlays: { _overlayDecorator->addTechnique( new ClampingTechnique() ); //_overlayDecorator->addTechnique( new ClampingBinTechnique() ); //...why not combine the 2 clamping techniques? use a group AND a bin? } addTerrainDecorator( _overlayDecorator ); // install any pre-existing model layers: ModelLayerVector modelLayers; _map->getModelLayers( modelLayers ); int modelLayerIndex = 0; for( ModelLayerVector::const_iterator k = modelLayers.begin(); k != modelLayers.end(); k++, modelLayerIndex++ ) { onModelLayerAdded( k->get(), modelLayerIndex ); } _mapCallback = new MapNodeMapCallbackProxy(this); // install a layer callback for processing further map actions: _map->addMapCallback( _mapCallback.get() ); osg::StateSet* ss = getOrCreateStateSet(); if ( _mapNodeOptions.enableLighting().isSet() ) { ss->setMode( GL_LIGHTING, _mapNodeOptions.enableLighting().value() ? 1 : 0 ); } dirtyBound(); // Install top-level shader programs: if ( Registry::capabilities().supportsGLSL() ) { // Note. We use OVERRIDE here so that child object that use the ShaderGenerator // don't have to worry about installing default shaders. The usage pattern is // to use PROTECTED mode if you want to override the defaults in (say) a ModelLayer // or in a TextureCompositor. VirtualProgram* vp = new VirtualProgram(); vp->setName( "MapNode" ); vp->installDefaultColoringAndLightingShaders( 0, osg::StateAttribute::ON | osg::StateAttribute::OVERRIDE ); ss->setAttributeAndModes( vp, osg::StateAttribute::ON ); } // register for event traversals so we can deal with blacklisted filenames ADJUST_EVENT_TRAV_COUNT( this, 1 ); // remove the temporary reference. this->unref_nodelete(); }
void MapNode::init() { // Take a reference to this object so that it doesn't get inadvertently // deleting during startup. It is possible that during startup, a driver // will load that will take a reference to the MapNode (like in a // ModelSource node operation) and we don't want that deleting the MapNode // out from under us. // This is paired by an unref_nodelete() at the end of this method. this->ref(); // Protect the MapNode from the Optimizer setDataVariance(osg::Object::DYNAMIC); // Protect the MapNode from the ShaderGenerator ShaderGenerator::setIgnoreHint(this, true); // initialize 0Ls _terrainEngine = 0L; _terrainEngineContainer = 0L; _overlayDecorator = 0L; setName( "osgEarth::MapNode" ); _maskLayerNode = 0L; _lastNumBlacklistedFilenames = 0; // Set the global proxy settings // TODO: this should probably happen elsewhere, like in the registry? if ( _mapNodeOptions.proxySettings().isSet() ) { HTTPClient::setProxySettings( _mapNodeOptions.proxySettings().get() ); } // establish global driver options. These are OSG reader-writer options that // will make their way to any read* calls down the pipe const osgDB::Options* global_options = _map->getGlobalOptions(); osg::ref_ptr<osgDB::Options> local_options = global_options ? Registry::instance()->cloneOrCreateOptions( global_options ) : NULL; if ( local_options.valid() ) { OE_INFO << LC << "Options string = " << (local_options.valid()? local_options->getOptionString() : "<empty>") << std::endl; } // TODO: not sure why we call this here _map->setGlobalOptions( local_options.get() ); // load and attach the terrain engine, but don't initialize it until we need it const TerrainOptions& terrainOptions = _mapNodeOptions.getTerrainOptions(); _terrainEngine = TerrainEngineNodeFactory::create( _map.get(), terrainOptions ); _terrainEngineInitialized = false; // the engine needs a container so we can set lighting state on the container and // not on the terrain engine itself. Setting the dynamic variance will prevent // an optimizer from collapsing the empty group node. _terrainEngineContainer = new osg::Group(); _terrainEngineContainer->setDataVariance( osg::Object::DYNAMIC ); this->addChild( _terrainEngineContainer ); // initialize terrain-level lighting: if ( terrainOptions.enableLighting().isSet() ) { _terrainEngineContainer->getOrCreateStateSet()->addUniform( Registry::shaderFactory()->createUniformForGLMode(GL_LIGHTING, *terrainOptions.enableLighting()) ); _terrainEngineContainer->getOrCreateStateSet()->setMode( GL_LIGHTING, terrainOptions.enableLighting().value() ? 1 : 0 ); } if ( _terrainEngine ) { // inform the terrain engine of the map information now so that it can properly // initialize it's CoordinateSystemNode. This is necessary in order to support // manipulators and to set up the texture compositor prior to frame-loop // initialization. _terrainEngine->preInitialize( _map.get(), terrainOptions ); _terrainEngineContainer->addChild( _terrainEngine ); } else { OE_WARN << "FAILED to create a terrain engine for this map" << std::endl; } // make a group for the model layers. // NOTE: for now, we are going to nullify any shader programs that occur above the model // group, since it does not YET support shader composition. Programs defined INSIDE a // model layer will still work OK though. _models = new osg::Group(); _models->setName( "osgEarth::MapNode.modelsGroup" ); _models->getOrCreateStateSet()->setRenderBinDetails(2, "RenderBin"); addChild( _models.get() ); // a decorator for overlay models: _overlayDecorator = new OverlayDecorator(); // install the Draping technique for overlays: { DrapingTechnique* draping = new DrapingTechnique(); const char* envOverlayTextureSize = ::getenv("OSGEARTH_OVERLAY_TEXTURE_SIZE"); if ( _mapNodeOptions.overlayBlending().isSet() ) draping->setOverlayBlending( *_mapNodeOptions.overlayBlending() ); if ( envOverlayTextureSize ) draping->setTextureSize( as<int>(envOverlayTextureSize, 1024) ); else if ( _mapNodeOptions.overlayTextureSize().isSet() ) draping->setTextureSize( *_mapNodeOptions.overlayTextureSize() ); if ( _mapNodeOptions.overlayMipMapping().isSet() ) draping->setMipMapping( *_mapNodeOptions.overlayMipMapping() ); if ( _mapNodeOptions.overlayAttachStencil().isSet() ) draping->setAttachStencil( *_mapNodeOptions.overlayAttachStencil() ); if ( _mapNodeOptions.overlayResolutionRatio().isSet() ) draping->setResolutionRatio( *_mapNodeOptions.overlayResolutionRatio() ); _overlayDecorator->addTechnique( draping ); } // install the Clamping technique for overlays: { _overlayDecorator->addTechnique( new ClampingTechnique() ); } addTerrainDecorator( _overlayDecorator ); // install any pre-existing model layers: ModelLayerVector modelLayers; _map->getModelLayers( modelLayers ); int modelLayerIndex = 0; for( ModelLayerVector::const_iterator k = modelLayers.begin(); k != modelLayers.end(); k++, modelLayerIndex++ ) { onModelLayerAdded( k->get(), modelLayerIndex ); } _mapCallback = new MapNodeMapCallbackProxy(this); // install a layer callback for processing further map actions: _map->addMapCallback( _mapCallback.get() ); osg::StateSet* stateset = getOrCreateStateSet(); if ( _mapNodeOptions.enableLighting().isSet() ) { stateset->addUniform(Registry::shaderFactory()->createUniformForGLMode( GL_LIGHTING, _mapNodeOptions.enableLighting().value() ? 1 : 0)); stateset->setMode( GL_LIGHTING, _mapNodeOptions.enableLighting().value() ? 1 : 0); } // Add in some global uniforms stateset->addUniform( new osg::Uniform("oe_isGeocentric", _map->isGeocentric()) ); if ( _map->isGeocentric() ) { OE_INFO << LC << "Adding ellipsoid uniforms.\n"; // for a geocentric map, use an ellipsoid unit-frame transform and its inverse: osg::Vec3d ellipFrameInverse( _map->getSRS()->getEllipsoid()->getRadiusEquator(), _map->getSRS()->getEllipsoid()->getRadiusEquator(), _map->getSRS()->getEllipsoid()->getRadiusPolar()); stateset->addUniform( new osg::Uniform("oe_ellipsoidFrameInverse", osg::Vec3f(ellipFrameInverse)) ); osg::Vec3d ellipFrame = osg::componentDivide(osg::Vec3d(1.0,1.0,1.0), ellipFrameInverse); stateset->addUniform( new osg::Uniform("oe_ellipsoidFrame", osg::Vec3f(ellipFrame)) ); } // install the default rendermode uniform: stateset->addUniform( new osg::Uniform("oe_isPickCamera", false) ); dirtyBound(); // register for event traversals so we can deal with blacklisted filenames ADJUST_EVENT_TRAV_COUNT( this, 1 ); // remove the temporary reference. this->unref_nodelete(); }