Пример #1
0
void
Map::clear()
{
    ImageLayerVector     imageLayersRemoved;
    ElevationLayerVector elevLayersRemoved;
    ModelLayerVector     modelLayersRemoved;
    MaskLayerVector      maskLayersRemoved;

    Revision newRevision;
    {
        Threading::ScopedWriteLock lock( _mapDataMutex );

        imageLayersRemoved.swap( _imageLayers );
        elevLayersRemoved.swap ( _elevationLayers );
        modelLayersRemoved.swap( _modelLayers );

        // calculate a new revision.
        newRevision = ++_dataModelRevision;
    }
    
    // a separate block b/c we don't need the mutex   
    for( MapCallbackList::iterator i = _mapCallbacks.begin(); i != _mapCallbacks.end(); i++ )
    {
        for( ImageLayerVector::iterator k = imageLayersRemoved.begin(); k != imageLayersRemoved.end(); ++k )
            i->get()->onMapModelChanged( MapModelChange(MapModelChange::REMOVE_IMAGE_LAYER, newRevision, k->get()) );
        for( ElevationLayerVector::iterator k = elevLayersRemoved.begin(); k != elevLayersRemoved.end(); ++k )
            i->get()->onMapModelChanged( MapModelChange(MapModelChange::REMOVE_ELEVATION_LAYER, newRevision, k->get()) );
        for( ModelLayerVector::iterator k = modelLayersRemoved.begin(); k != modelLayersRemoved.end(); ++k )
            i->get()->onMapModelChanged( MapModelChange(MapModelChange::REMOVE_MODEL_LAYER, newRevision, k->get()) );
    }
}
Пример #2
0
Revision
Map::getModelLayers( ModelLayerVector& out_list ) const
{
    out_list.reserve( _modelLayers.size() );

    Threading::ScopedReadLock lock( const_cast<Map*>(this)->_mapDataMutex );
    for( ModelLayerVector::const_iterator i = _modelLayers.begin(); i != _modelLayers.end(); ++i )
        out_list.push_back( i->get() );

    return _dataModelRevision;
}
Пример #3
0
MapNode::~MapNode()
{
    _map->removeMapCallback( _mapCallback.get() );

    ModelLayerVector modelLayers;
    _map->getModelLayers( modelLayers );
    //Remove our model callback from any of the model layers in the map    
    for (osgEarth::ModelLayerVector::iterator itr = modelLayers.begin(); itr != modelLayers.end(); ++itr)
    {
        this->onModelLayerRemoved( itr->get() );        
    }
}
Пример #4
0
void
ElevationQuery::gatherPatchLayers()
{
    // cache a vector of terrain patch models.
    _patchLayers.clear();
    ModelLayerVector modelLayers;
    _mapf.getLayers(modelLayers);
    for(ModelLayerVector::const_iterator i = modelLayers.begin();
        i != modelLayers.end();
        ++i)
    {
        if ( i->get()->isTerrainPatch() )
            _patchLayers.push_back( i->get() );
    }
}
Пример #5
0
    void dirtyModelLayers()
    {
        ModelLayerVector modelLayers;
        s_activeMap->getLayers(modelLayers);

        for(unsigned i=0; i<modelLayers.size(); ++i)
        {
            ModelSource* ms = modelLayers.at(i)->getModelSource();
            if ( ms )
            {
                ms->dirty();
            }
            else
            {
                OE_NOTICE << modelLayers.at(i)->getName()
                    << " has no model source.\n";
            }
        }
    }
Пример #6
0
void
Map::setLayersFromMap( const Map* map )
{
    this->clear();

    if ( map )
    {
        ImageLayerVector newImages;
        map->getImageLayers( newImages );
        for( ImageLayerVector::iterator i = newImages.begin(); i != newImages.end(); ++i )
            addImageLayer( i->get() );

        ElevationLayerVector newElev;
        map->getElevationLayers( newElev );
        for( ElevationLayerVector::iterator i = newElev.begin(); i != newElev.end(); ++i )
            addElevationLayer( i->get() );

        ModelLayerVector newModels;
        map->getModelLayers( newModels );
        for( ModelLayerVector::iterator i = newModels.begin(); i != newModels.end(); ++i )
            addModelLayer( i->get() );
    }
}
Пример #7
0
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() );

    // make a group for overlay model layers:
    _overlayModels = new ObserverGroup(); //osg::Group();
    _overlayModels->setName( "osgEarth::MapNode.overlayModelsGroup" );

    // a decorator for overlay models:
    _overlayDecorator = new OverlayDecorator();
    _overlayDecorator->setOverlayGraphTraversalMask( terrainOptions.secondaryTraversalMask().value() );

    if ( _mapNodeOptions.overlayBlending().isSet() )
        _overlayDecorator->setOverlayBlending( *_mapNodeOptions.overlayBlending() );
    if ( _mapNodeOptions.overlayTextureSize().isSet() )
        _overlayDecorator->setTextureSize( *_mapNodeOptions.overlayTextureSize() );
    if ( _mapNodeOptions.overlayMipMapping().isSet() )
        _overlayDecorator->setMipMapping( *_mapNodeOptions.overlayMipMapping() );

    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() )
    {
        VirtualProgram* vp = new VirtualProgram();
        vp->setName( "MapNode" );
        vp->installDefaultColoringAndLightingShaders();
        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();
}
Пример #8
0
void
updateControlPanel()
{
    // erase all child controls and just rebuild them b/c we're lazy.

    //Rebuild all the image layers    
    s_imageBox->clearControls();

    int row = 0;

    LabelControl* activeLabel = new LabelControl( "Image Layers", 20, osg::Vec4f(1,1,0,1) );
    s_imageBox->setControl( 1, row++, activeLabel );

    // the active map layers:
    MapFrame mapf( s_activeMap.get() );
    ImageLayerVector imageLayers;
    mapf.getLayers(imageLayers);
    int layerNum = imageLayers.size()-1;
    for( ImageLayerVector::const_reverse_iterator i = imageLayers.rbegin(); i != imageLayers.rend(); ++i )
        createLayerItem( s_imageBox, row++, layerNum--, imageLayers.size(), i->get(), true );

    MapFrame mapf2( s_inactiveMap.get() );
    imageLayers.clear();
    mapf2.getLayers(imageLayers);
    if ( imageLayers.size() > 0 )
    {
        LabelControl* inactiveLabel = new LabelControl( "Removed:", 18, osg::Vec4f(1,1,0,1) );
        s_imageBox->setControl( 1, row++, inactiveLabel );

        for( unsigned int i=0; i<imageLayers.size(); ++i )
        {
            createLayerItem( s_imageBox, row++, -1, -1, imageLayers[i].get(), false );
        }
    }




    //Rebuild the elevation layers
    s_elevationBox->clearControls();

    row = 0;

    activeLabel = new LabelControl( "Elevation Layers", 20, osg::Vec4f(1,1,0,1) );
    s_elevationBox->setControl( 1, row++, activeLabel );

    // the active map layers:
    ElevationLayerVector elevationLayers;
    mapf.getLayers(elevationLayers);

    layerNum = elevationLayers.size()-1;
    for( ElevationLayerVector::const_reverse_iterator i = elevationLayers.rbegin(); i != elevationLayers.rend(); ++i )
        createLayerItem( s_elevationBox, row++, layerNum--, elevationLayers.size(), i->get(), true );

    if ( mapf2.elevationLayers().size() > 0 )
    {
        LabelControl* inactiveLabel = new LabelControl( "Removed:", 18, osg::Vec4f(1,1,0,1) );
        s_elevationBox->setControl( 1, row++, inactiveLabel );

        for( unsigned int i=0; i<mapf2.elevationLayers().size(); ++i )
        {
            createLayerItem( s_elevationBox, row++, -1, -1, mapf2.elevationLayers().at(i), false );
        }
    }



    //Rebuild the model layers
    s_modelBox->clearControls();

    row = 0;

    activeLabel = new LabelControl( "Model Layers", 20, osg::Vec4f(1,1,0,1) );
    s_modelBox->setControl( 1, row++, activeLabel );

    // the active map layers:
    ModelLayerVector modelLayers;
    mapf.getLayers(modelLayers);
    for( ModelLayerVector::const_reverse_iterator i = modelLayers.rbegin(); i != modelLayers.rend(); ++i )
        createModelLayerItem( s_modelBox, row++, i->get(), true );
}
Пример #9
0
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();
}
Пример #10
0
void
MapNode::init()
{
    // Protect the MapNode from the Optimizer
    setDataVariance(osg::Object::DYNAMIC);

    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::ReaderWriter::Options* global_options = _map->getGlobalOptions();
    osg::ref_ptr<osgDB::ReaderWriter::Options> local_options = global_options ?
            new osgDB::ReaderWriter::Options( *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() );

    // overlays:
    _pendingOverlayAutoSetTextureUnit = true;

    // 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.get() );

    // initialize terrain-level lighting:
    if ( terrainOptions.enableLighting().isSet() )
    {
        _terrainEngineContainer->getOrCreateStateSet()->setMode( GL_LIGHTING, terrainOptions.enableLighting().value() ?
                osg::StateAttribute::ON | osg::StateAttribute::PROTECTED :
                osg::StateAttribute::OFF | osg::StateAttribute::PROTECTED );
    }

    if ( _terrainEngine.valid() )
    {
        // 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.get() );
    }
    else
        OE_WARN << "FAILED to create a terrain engine for this map" << std::endl;

    // make a group for the model layers:
    _models = new osg::Group();
    _models->setName( "osgEarth::MapNode.modelsGroup" );
    addChild( _models.get() );

    // make a group for overlay model layers:
    _overlayModels = new osg::Group();
    _overlayModels->setName( "osgEarth::MapNode.overlayModelsGroup" );

    // a decorator for overlay models:
    _overlayDecorator = new OverlayDecorator();
    if ( _mapNodeOptions.overlayVertexWarping().isSet() )
        _overlayDecorator->setVertexWarping( *_mapNodeOptions.overlayVertexWarping() );
    if ( _mapNodeOptions.overlayBlending().isSet() )
        _overlayDecorator->setOverlayBlending( *_mapNodeOptions.overlayBlending() );
    if ( _mapNodeOptions.overlayTextureSize().isSet() )
        _overlayDecorator->setTextureSize( *_mapNodeOptions.overlayTextureSize() );
    if ( _mapNodeOptions.overlayMipMapping().isSet() )
        _overlayDecorator->setMipMapping( *_mapNodeOptions.overlayMipMapping() );
    addTerrainDecorator( _overlayDecorator.get() );

    // 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();
    //ss->setAttributeAndModes( new osg::CullFace() ); //, osg::StateAttribute::ON);
    //ss->setAttributeAndModes( new osg::PolygonOffset( -1, -1 ) );

    if ( _mapNodeOptions.enableLighting().isSet() )
    {
        ss->setMode( GL_LIGHTING, _mapNodeOptions.enableLighting().value() ?
                     osg::StateAttribute::ON | osg::StateAttribute::PROTECTED :
                     osg::StateAttribute::OFF | osg::StateAttribute::PROTECTED );
    }

    dirtyBound();

    // register for event traversals so we can deal with blacklisted filenames
    ADJUST_EVENT_TRAV_COUNT( this, 1 );
}