void
LogarithmicDepthBuffer::uninstall(osg::Camera* camera)
{
    if ( camera && _supported )
    {
        SetFarPlaneUniformCallback* dc = dynamic_cast<SetFarPlaneUniformCallback*>(camera->getPreDrawCallback());
        if ( dc )
        {
            osg::ref_ptr<osg::Camera::DrawCallback> next = dc->_next.get();
            camera->setPreDrawCallback( next.get() );
        }

        osg::StateSet* stateset = camera->getStateSet();
        if ( stateset )
        {
            VirtualProgram* vp = VirtualProgram::get( camera->getStateSet() );
            if ( vp )
            {
                Shaders pkg;
                pkg.unloadFunction( vp, pkg.LogDepthBuffer_FragFile );
                pkg.unloadFunction( vp, pkg.LogDepthBuffer_VertFile );
                pkg.unloadFunction( vp, pkg.LogDepthBuffer_VertOnly_VertFile );
            }

            stateset->removeUniform( FC_UNIFORM );
            stateset->removeUniform( C_UNIFORM );
        }
    }
}
void
BumpMapTerrainEffect::onUninstall(TerrainEngineNode* engine)
{
    osg::StateSet* stateset = engine->getStateSet();
    if ( stateset )
    {
        if ( _bumpMapTex.valid() )
        {
            stateset->removeUniform("oe_bumpmap_maxRange");
            stateset->removeUniform("oe_bumpmap_octaves");
            stateset->removeUniform( _scaleUniform.get() );
            stateset->removeUniform( _intensityUniform.get() );
            stateset->removeUniform( _bumpMapTexUniform.get() );
            stateset->removeTextureAttribute( _bumpMapUnit, osg::StateAttribute::TEXTURE );
        }

        VirtualProgram* vp = VirtualProgram::get(stateset);
        if ( vp )
        {
            Shaders pkg;
            pkg.unloadFunction( vp, pkg.VertexModel );
            pkg.unloadFunction( vp, pkg.VertexView );
            pkg.unloadFunction( vp, pkg.FragmentSimple );
            pkg.unloadFunction( vp, pkg.FragmentProgressive );
        }
    }
    
    if ( _bumpMapUnit >= 0 )
    {
        engine->getResources()->releaseTextureImageUnit( _bumpMapUnit );
        _bumpMapUnit = -1;
    }
}
void
DepthOffsetAdapter::setGraph(osg::Node* graph)
{
    if ( !_supported ) return;

    bool graphChanging =
        _graph.get() != graph;

    bool uninstall =
        (_graph.valid() && _graph->getStateSet()) &&
        (graphChanging || (_options.enabled() == false));

    bool install =
        (graph && graphChanging ) || 
        (graph && (_options.enabled() == true));

    // shader package:
    Shaders shaders;

    if ( uninstall )
    {
        OE_TEST << LC << "Removing depth offset shaders" << std::endl;

        // uninstall uniforms and shaders.
        osg::StateSet* s = _graph->getStateSet();
        s->removeUniform( _minBiasUniform.get() );
        s->removeUniform( _maxBiasUniform.get() );
        s->removeUniform( _minRangeUniform.get() );
        s->removeUniform( _maxRangeUniform.get() );
        
        shaders.unloadFunction( VirtualProgram::get(s), shaders.DepthOffsetVertex );
    }

    if ( install )
    {
        OE_TEST << LC << "Installing depth offset shaders" << std::endl;

        // install uniforms and shaders.
        osg::StateSet* s = graph->getOrCreateStateSet();
        s->addUniform( _minBiasUniform.get() );
        s->addUniform( _maxBiasUniform.get() );
        s->addUniform( _minRangeUniform.get() );
        s->addUniform( _maxRangeUniform.get() );
        
        shaders.loadFunction(VirtualProgram::getOrCreate(s), shaders.DepthOffsetVertex);        
    }

    if ( graphChanging )
    {
        _graph = graph;
    }

    // always set Dirty when setGraph is called sine it may be called anytime
    // the subgraph changes (as can be detected by a computeBound)
    _dirty = (_options.automatic() == true);
}
void
GraticuleTerrainEffect::onUninstall(TerrainEngineNode* engine)
{
    osg::StateSet* stateset = engine->getTerrainStateSet();
    if ( stateset )
    {
        VirtualProgram* vp = VirtualProgram::get(stateset);
        if ( vp )
        {
            Shaders package;
            package.unloadFunction( vp, package.Graticule_Vertex );
            package.unloadFunction( vp, package.Graticule_Fragment );

            stateset->removeUniform( GraticuleOptions::resolutionUniformName() );
            stateset->removeUniform( GraticuleOptions::colorUniformName() );
            stateset->removeUniform( GraticuleOptions::lineWidthUniformName() );
        }
    }
}
void
NormalMapTerrainEffect::onUninstall(TerrainEngineNode* engine)
{
    osg::StateSet* stateset = engine->getStateSet();
    if ( stateset )
    {
        VirtualProgram* vp = VirtualProgram::get(stateset);
        if ( vp )
        {
            Shaders package;
            package.unloadFunction( vp, package.Vertex );
            package.unloadFunction( vp, package.Fragment );
        }
        stateset->removeUniform( NORMAL_SAMPLER );
    }

    if ( _normalMapUnit >= 0 )
    {
        engine->getResources()->releaseTextureImageUnit( _normalMapUnit );
        _normalMapUnit = -1;
    }
}