]> git.mxchange.org Git - flightgear.git/blobdiff - src/Viewer/renderer.cxx
commradio: improvements for atis speech
[flightgear.git] / src / Viewer / renderer.cxx
index 599e2d9c76cb5dd105b1d8bcbbd94452d438deaa..9728f0f72ac0757c255a8d6ac75e5d3b2efea667 100644 (file)
@@ -35,6 +35,8 @@
 #include <vector>
 #include <typeinfo>
 
+#include <boost/foreach.hpp>
+
 #include <osg/ref_ptr>
 #include <osg/AlphaFunc>
 #include <osg/BlendFunc>
 #include <simgear/scene/material/EffectCullVisitor.hxx>
 #include <simgear/scene/material/Effect.hxx>
 #include <simgear/scene/material/EffectGeode.hxx>
+#include <simgear/scene/material/EffectBuilder.hxx>
 #include <simgear/scene/model/animation.hxx>
 #include <simgear/scene/model/placement.hxx>
 #include <simgear/scene/sky/sky.hxx>
+#include <simgear/scene/util/DeletionManager.hxx>
 #include <simgear/scene/util/SGUpdateVisitor.hxx>
 #include <simgear/scene/util/RenderConstants.hxx>
 #include <simgear/scene/util/SGSceneUserData.hxx>
 #include <simgear/scene/tgdb/GroundLightManager.hxx>
 #include <simgear/scene/tgdb/pt_lights.hxx>
+#include <simgear/scene/tgdb/userdata.hxx>
 #include <simgear/structure/OSGUtils.hxx>
 #include <simgear/props/props.hxx>
 #include <simgear/timing/sg_time.hxx>
 #include <simgear/ephemeris/ephemeris.hxx>
 #include <simgear/math/sg_random.h>
-#ifdef FG_JPEG_SERVER
-#include <simgear/screen/jpgfactory.hxx>
-#endif
 
 #include <Time/light.hxx>
 #include <Time/light.hxx>
 #include "CameraGroup.hxx"
 #include "FGEventHandler.hxx"
 
+#include <plib/pu.h>
+
 using namespace osg;
 using namespace simgear;
 using namespace flightgear;
@@ -214,9 +218,12 @@ public:
     glPushAttrib(GL_ALL_ATTRIB_BITS);
     glPushClientAttrib(~0u);
       
-    HUD *hud = static_cast<HUD*>(globals->get_subsystem("hud"));
-    hud->draw(state);
-
+    // HUD can be NULL
+      HUD *hud = static_cast<HUD*>(globals->get_subsystem("hud"));
+      if (hud) {
+          hud->draw(state);
+      }
+      
     glPopClientAttrib();
     glPopAttrib();
   }
@@ -248,6 +255,11 @@ public:
     osg::Light* light = lightSource->getLight();
     
     FGLight *l = static_cast<FGLight*>(globals->get_subsystem("lighting"));
+      if (!l) {
+          // lighting is down during re-init
+          return;
+      }
+      
     if (_isSun) {
       light->setAmbient(Vec4(0.0f, 0.0f, 0.0f, 0.0f));
       light->setDiffuse(Vec4(1.0f, 1.0f, 1.0f, 1.0f));
@@ -371,40 +383,6 @@ public:
 
 bool FGScenerySwitchCallback::scenery_enabled = false;
 
-static osg::ref_ptr<osg::FrameStamp> mFrameStamp = new osg::FrameStamp;
-static osg::ref_ptr<SGUpdateVisitor> mUpdateVisitor= new SGUpdateVisitor;
-
-static osg::ref_ptr<osg::Group> mRealRoot = new osg::Group;
-static osg::ref_ptr<osg::Group> mDeferredRealRoot = new osg::Group;
-
-static osg::ref_ptr<osg::Group> mRoot = new osg::Group;
-
-static osg::ref_ptr<osg::Switch> panelSwitch;
-                                    
-                                    
-// update callback for the switch node controlling the 2D panel
-class FGPanelSwitchCallback : public osg::NodeCallback {
-public:
-    virtual void operator()(osg::Node* node, osg::NodeVisitor* nv)
-    {
-        assert(dynamic_cast<osg::Switch*>(node));
-        osg::Switch* sw = static_cast<osg::Switch*>(node);
-        
-        bool enabled = fgPanelVisible();
-        sw->setValue(0, enabled);
-        if (!enabled)
-            return;
-        traverse(node, nv);
-    }
-};
-
-#ifdef FG_JPEG_SERVER
-static void updateRenderer()
-{
-    globals->get_renderer()->update();
-}
-#endif
-
 FGRenderer::FGRenderer() :
     _sky(NULL),
     _ambientFactor( new osg::Uniform( "fg_SunAmbientColor", osg::Vec4f() ) ),
@@ -418,11 +396,17 @@ FGRenderer::FGRenderer() :
     _shadowDistances( new osg::Uniform( "fg_ShadowDistances", osg::Vec4f(5.0, 50.0, 500.0, 5000.0 ) ) ),
     _depthInColor( new osg::Uniform( "fg_DepthInColor", false ) )
 {
-#ifdef FG_JPEG_SERVER
-   jpgRenderFrame = updateRenderer;
-#endif
-   eventHandler = new FGEventHandler;
+    // it's not the real root, whatever that means
+    _root = new osg::Group;
+    _root->setName("fakeRoot");
 
+    _updateVisitor = new SGUpdateVisitor;
+  
+  // when Rembrandt is enabled, we use this group to access the whole
+  // scene. Since the only child is the _viewerSceneRoot, we could
+  // simply copy the reference, we don't need the additional group.
+    _deferredRealRoot = new osg::Group;
+    
    _numCascades = 4;
    _cascadeFar[0] = 5.f;
    _cascadeFar[1] = 50.f;
@@ -432,9 +416,16 @@ FGRenderer::FGRenderer() :
 
 FGRenderer::~FGRenderer()
 {
-#ifdef FG_JPEG_SERVER
-   jpgRenderFrame = NULL;
-#endif
+    SGPropertyChangeListenerVec::iterator i = _listeners.begin();
+    for (; i != _listeners.end(); ++i) {
+        delete *i;
+    }
+    
+    // replace the viewer's scene completely
+    if (getViewer()) {
+        getViewer()->setSceneData(new osg::Group);
+    }
+    
     delete _sky;
 }
 
@@ -442,12 +433,20 @@ FGRenderer::~FGRenderer()
 // XXX This should be called "preinit" or something, as it initializes
 // critical parts of the scene graph in addition to the splash screen.
 void
-FGRenderer::splashinit( void ) {
+FGRenderer::splashinit( void )
+{
+    // important that we reset the viewer sceneData here, to ensure the reference
+    // time for everything is in sync; otherwise on reset the Viewer and
+    // GraphicsWindow clocks are out of sync.
     osgViewer::Viewer* viewer = getViewer();
-    mRealRoot = dynamic_cast<osg::Group*>(viewer->getSceneData());
+    viewer->setName("osgViewer");
+    _viewerSceneRoot = new osg::Group;
+    _viewerSceneRoot->setName("viewerSceneRoot");
+    viewer->setSceneData(_viewerSceneRoot);
+    
     ref_ptr<Node> splashNode = fgCreateSplashNode();
     if (_classicalRenderer) {
-        mRealRoot->addChild(splashNode.get());
+        _viewerSceneRoot->addChild(splashNode.get());
     } else {
         for (   CameraGroup::CameraIterator ii = CameraGroup::getDefault()->camerasBegin();
                 ii != CameraGroup::getDefault()->camerasEnd();
@@ -460,11 +459,13 @@ FGRenderer::splashinit( void ) {
             camera->addChild(splashNode.get());
         }
     }
-    mFrameStamp = viewer->getFrameStamp();
+    
+    _frameStamp = new osg::FrameStamp;
+    viewer->setFrameStamp(_frameStamp.get());
     // Scene doesn't seem to pass the frame stamp to the update
     // visitor automatically.
-    mUpdateVisitor->setFrameStamp(mFrameStamp.get());
-    viewer->setUpdateVisitor(mUpdateVisitor.get());
+    _updateVisitor->setFrameStamp(_frameStamp.get());
+    viewer->setUpdateVisitor(_updateVisitor.get());
     fgSetDouble("/sim/startup/splash-alpha", 1.0);
 }
 
@@ -496,19 +497,31 @@ public:
     }
 };
 
+void
+FGRenderer::addChangeListener(SGPropertyChangeListener* l, const char* path)
+{
+    _listeners.push_back(l);
+    fgAddChangeListener(l, path);
+}
+                                    
 void
 FGRenderer::init( void )
 {
-    _classicalRenderer = !fgGetBool("/sim/rendering/rembrandt", false);
+    if (!eventHandler)
+        eventHandler = new FGEventHandler();
+
+    sgUserDataInit( globals->get_props() );
+
+    _classicalRenderer = !fgGetBool("/sim/rendering/rembrandt/enabled", false);
     _shadowMapSize    = fgGetInt( "/sim/rendering/shadows/map-size", 4096 );
-    fgAddChangeListener( new ShadowMapSizeListener, "/sim/rendering/shadows/map-size" );
-    fgAddChangeListener( new ShadowEnabledListener, "/sim/rendering/shadows/enabled" );
+    addChangeListener( new ShadowMapSizeListener, "/sim/rendering/shadows/map-size" );
+    addChangeListener( new ShadowEnabledListener, "/sim/rendering/shadows/enabled" );
     ShadowRangeListener* srl = new ShadowRangeListener;
-    fgAddChangeListener(srl, "/sim/rendering/shadows/cascade-far-m[0]");
+    addChangeListener(srl, "/sim/rendering/shadows/cascade-far-m[0]");
     fgAddChangeListener(srl, "/sim/rendering/shadows/cascade-far-m[1]");
     fgAddChangeListener(srl, "/sim/rendering/shadows/cascade-far-m[2]");
     fgAddChangeListener(srl, "/sim/rendering/shadows/cascade-far-m[3]");
-    fgAddChangeListener(new ShadowNumListener, "/sim/rendering/shadows/num-cascades");
+    addChangeListener(new ShadowNumListener, "/sim/rendering/shadows/num-cascades");
     _numCascades = fgGetInt("/sim/rendering/shadows/num-cascades", 4);
     _cascadeFar[0] = fgGetFloat("/sim/rendering/shadows/cascade-far-m[0]", 5.0f);
     _cascadeFar[1] = fgGetFloat("/sim/rendering/shadows/cascade-far-m[1]", 50.0f);
@@ -519,11 +532,15 @@ FGRenderer::init( void )
     updateCascadeFar(1, _cascadeFar[1]);
     updateCascadeFar(2, _cascadeFar[2]);
     updateCascadeFar(3, _cascadeFar[3]);
-    _useColorForDepth = fgGetBool( "/sim/rendering/use-color-for-depth", false );
+    _useColorForDepth = fgGetBool( "/sim/rendering/rembrandt/use-color-for-depth", false );
     _depthInColor->set( _useColorForDepth );
 
+    _renderer         = fgGetString("/sim/rendering/rembrandt/renderer", "default-pipeline");
+    if (!_classicalRenderer)
+        _pipeline = makeRenderingPipeline(_renderer, 0);
     _scenery_loaded   = fgGetNode("/sim/sceneryloaded", true);
-    _scenery_override = fgGetNode("/sim/sceneryloaded-override", true);
+    _position_finalized = fgGetNode("/sim/position-finalized", true);
+    
     _panel_hotspots   = fgGetNode("/sim/panel-hotspots", true);
     _virtual_cockpit  = fgGetNode("/sim/virtual-cockpit", true);
 
@@ -533,12 +550,10 @@ FGRenderer::init( void )
     _ysize         = fgGetNode("/sim/startup/ysize", true);
     _splash_alpha  = fgGetNode("/sim/startup/splash-alpha", true);
 
-    _skyblend             = fgGetNode("/sim/rendering/skyblend", true);
     _point_sprites        = fgGetNode("/sim/rendering/point-sprites", true);
     _enhanced_lighting    = fgGetNode("/sim/rendering/enhanced-lighting", true);
     _distance_attenuation = fgGetNode("/sim/rendering/distance-attenuation", true);
     _horizon_effect       = fgGetNode("/sim/rendering/horizon-effect", true);
-    _textures             = fgGetNode("/sim/rendering/textures", true);
 
     _altitude_ft = fgGetNode("/position/altitude-ft", true);
 
@@ -595,9 +610,7 @@ void installCullVisitor(Camera* camera)
         = static_cast<osgViewer::Renderer*>(camera->getRenderer());
     for (int i = 0; i < 2; ++i) {
         osgUtil::SceneView* sceneView = renderer->getSceneView(i);
-#if SG_OSG_VERSION_LESS_THAN(3,0,0)
-        sceneView->setCullVisitor(new simgear::EffectCullVisitor);
-#else
+
         osg::ref_ptr<osgUtil::CullVisitor::Identifier> identifier;
         identifier = sceneView->getCullVisitor()->getIdentifier();
         sceneView->setCullVisitor(new simgear::EffectCullVisitor);
@@ -610,18 +623,18 @@ void installCullVisitor(Camera* camera)
         identifier = sceneView->getCullVisitorRight()->getIdentifier();
         sceneView->setCullVisitorRight(sceneView->getCullVisitor()->clone());
         sceneView->getCullVisitorRight()->setIdentifier(identifier.get());
-#endif
+
     }
 }
 
-flightgear::CameraInfo*
-FGRenderer::buildRenderingPipeline(flightgear::CameraGroup* cgroup, unsigned flags, Camera* camera,
+CameraInfo*
+FGRenderer::buildRenderingPipeline(CameraGroup* cgroup, unsigned flags, Camera* camera,
                                    const Matrix& view,
                                    const Matrix& projection,
                                                                   osg::GraphicsContext* gc,
                                    bool useMasterSceneData)
 {
-       flightgear::CameraInfo* info = 0;
+       CameraInfo* info = 0;
        if (!_classicalRenderer && (flags & (CameraGroup::GUI | CameraGroup::ORTHO)) == 0)
                info = buildDeferredPipeline( cgroup, flags, camera, view, projection, gc );
 
@@ -634,8 +647,8 @@ FGRenderer::buildRenderingPipeline(flightgear::CameraGroup* cgroup, unsigned fla
        }
 }
 
-flightgear::CameraInfo*
-FGRenderer::buildClassicalPipeline(flightgear::CameraGroup* cgroup, unsigned flags, osg::Camera* camera,
+CameraInfo*
+FGRenderer::buildClassicalPipeline(CameraGroup* cgroup, unsigned flags, osg::Camera* camera,
                                 const osg::Matrix& view,
                                 const osg::Matrix& projection,
                                 bool useMasterSceneData)
@@ -643,10 +656,12 @@ FGRenderer::buildClassicalPipeline(flightgear::CameraGroup* cgroup, unsigned fla
     CameraInfo* info = new CameraInfo(flags);
     // The camera group will always update the camera
     camera->setReferenceFrame(Transform::ABSOLUTE_RF);
-
+    info->name = "classic";
+    
     Camera* farCamera = 0;
     if ((flags & (CameraGroup::GUI | CameraGroup::ORTHO)) == 0) {
         farCamera = new Camera;
+        farCamera->setName("farCamera");
         farCamera->setAllowEventFocus(camera->getAllowEventFocus());
         farCamera->setGraphicsContext(camera->getGraphicsContext());
         farCamera->setCullingMode(camera->getCullingMode());
@@ -678,7 +693,7 @@ FGRenderer::buildClassicalPipeline(flightgear::CameraGroup* cgroup, unsigned fla
     cgroup->getViewer()->addSlave(camera, projection, view, useMasterSceneData);
     installCullVisitor(camera);
     int slaveIndex = cgroup->getViewer()->getNumSlaves() - 1;
-       info->addCamera( MAIN_CAMERA, camera, slaveIndex );
+    info->addCamera( MAIN_CAMERA, camera, slaveIndex );
     camera->setRenderOrder(Camera::POST_RENDER, slaveIndex);
     cgroup->addCamera(info);
     return info;
@@ -686,74 +701,69 @@ FGRenderer::buildClassicalPipeline(flightgear::CameraGroup* cgroup, unsigned fla
 
 class FGDeferredRenderingCameraCullCallback : public osg::NodeCallback {
 public:
-    FGDeferredRenderingCameraCullCallback( flightgear::CameraKind k, CameraInfo* i ) : kind( k ), info( i ) {}
+    FGDeferredRenderingCameraCullCallback( const std::string& k, CameraInfo* i, bool nd = false ) : kind( k ), info( i ), needsDuDv(nd) {}
     virtual void operator()( osg::Node *n, osg::NodeVisitor *nv) {
-    simgear::EffectCullVisitor* cv = dynamic_cast<simgear::EffectCullVisitor*>(nv);
-    osg::Camera* camera = static_cast<osg::Camera*>(n);
-
-    cv->clearBufferList();
-    cv->addBuffer(simgear::Effect::DEPTH_BUFFER, info->getBuffer( flightgear::RenderBufferInfo::DEPTH_BUFFER ) );
-    cv->addBuffer(simgear::Effect::NORMAL_BUFFER, info->getBuffer( flightgear::RenderBufferInfo::NORMAL_BUFFER ) );
-    cv->addBuffer(simgear::Effect::DIFFUSE_BUFFER, info->getBuffer( flightgear::RenderBufferInfo::DIFFUSE_BUFFER ) );
-    cv->addBuffer(simgear::Effect::SPEC_EMIS_BUFFER, info->getBuffer( flightgear::RenderBufferInfo::SPEC_EMIS_BUFFER ) );
-    cv->addBuffer(simgear::Effect::LIGHTING_BUFFER, info->getBuffer( flightgear::RenderBufferInfo::LIGHTING_BUFFER ) );
-    cv->addBuffer(simgear::Effect::SHADOW_BUFFER, info->getBuffer( flightgear::RenderBufferInfo::SHADOW_BUFFER ) );
-    // cv->addBuffer(simgear::Effect::AO_BUFFER, info->gBuffer->aoBuffer[2]);
-
-    if ( !info->getRenderStageInfo(kind).fullscreen )
-        info->setMatrices( camera );
-
-    cv->traverse( *camera );
-
-    if ( kind == flightgear::GEOMETRY_CAMERA ) {
-        // Save transparent bins to render later
-        osgUtil::RenderStage* renderStage = cv->getRenderStage();
-        osgUtil::RenderBin::RenderBinList& rbl = renderStage->getRenderBinList();
-        for (osgUtil::RenderBin::RenderBinList::iterator rbi = rbl.begin(); rbi != rbl.end(); ) {
-            if (rbi->second->getSortMode() == osgUtil::RenderBin::SORT_BACK_TO_FRONT) {
-                info->savedTransparentBins.insert( std::make_pair( rbi->first, rbi->second ) );
-                rbl.erase( rbi++ );
-            } else {
-                ++rbi;
-            }
+        simgear::EffectCullVisitor* cv = dynamic_cast<simgear::EffectCullVisitor*>(nv);
+        osg::Camera* camera = static_cast<osg::Camera*>(n);
+
+        cv->clearBufferList();
+        for (RenderBufferMap::iterator ii = info->buffers.begin(); ii != info->buffers.end(); ++ii) {
+            cv->addBuffer(ii->first, ii->second.texture);
+        }
+
+        if ( !info->getRenderStageInfo(kind).fullscreen )
+            info->setMatrices( camera );
+
+        if (needsDuDv) {
+            osg::Matrix projInverse;
+            info->projInverse->get( projInverse );
+
+            osg::Vec4 p0 = osg::Vec4( -1.0, -1.0, 0.0, 1.0 ) * projInverse;
+            info->du->set( osg::Vec4(  1.0, -1.0, 0.0, 1.0 ) * projInverse - p0 );
+            info->dv->set( osg::Vec4( -1.0,  1.0, 0.0, 1.0 ) * projInverse - p0 );
         }
-    } else if ( kind == flightgear::LIGHTING_CAMERA ) {
-        osg::ref_ptr<osg::Camera> mainShadowCamera = info->getCamera( SHADOW_CAMERA );
+
+        cv->traverse( *camera );
+
+        if ( kind == GEOMETRY_CAMERA ) {
+            // Remove transparent bins. They will be renderer in the additional light stage (side effect)
+            osgUtil::RenderStage* renderStage = cv->getRenderStage();
+            osgUtil::RenderBin::RenderBinList& rbl = renderStage->getRenderBinList();
+            for (osgUtil::RenderBin::RenderBinList::iterator rbi = rbl.begin(); rbi != rbl.end(); ) {
+                if (rbi->second->getSortMode() == osgUtil::RenderBin::SORT_BACK_TO_FRONT) {
+                    rbl.erase( rbi++ );
+                } else {
+                    ++rbi;
+                }
+            }
+        } else if ( kind == LIGHTING_CAMERA ) {
+            osg::ref_ptr<osg::Camera> mainShadowCamera = info->getCamera( SHADOW_CAMERA );
             if (mainShadowCamera.valid()) {
                 osg::Switch* grp = mainShadowCamera->getChild(0)->asSwitch();
                 for (int i = 0; i < 4; ++i ) {
                     if (!grp->getValue(i))
                         continue;
-                    osg::TexGen* shadowTexGen = info->shadowTexGen[i];
-                    shadowTexGen->setMode(osg::TexGen::EYE_LINEAR);
 
                     osg::Camera* cascadeCam = static_cast<osg::Camera*>( grp->getChild(i) );
-                    // compute the matrix which takes a vertex from view coords into tex coords
-                    shadowTexGen->setPlanesFromMatrix(  cascadeCam->getProjectionMatrix() *
-                                                        osg::Matrix::translate(1.0,1.0,1.0) *
-                                                        osg::Matrix::scale(0.5f,0.5f,0.5f) );
+                    osg::Matrixf shadowMatrix = camera->getInverseViewMatrix() *
+                                                cascadeCam->getViewMatrix() *
+                                                cascadeCam->getProjectionMatrix() *
+                                                osg::Matrix::translate(1.0, 1.0, 1.0) *
+                                                osg::Matrix::scale(0.5f, 0.5f, 0.5f);
 
-                    osg::RefMatrix * refMatrix = new osg::RefMatrix( cascadeCam->getInverseViewMatrix() * *cv->getModelViewMatrix() );
-
-                    cv->getRenderStage()->getPositionalStateContainer()->addPositionedTextureAttribute( i+1, refMatrix, shadowTexGen );
+                    info->shadowMatrix[i]->set( shadowMatrix );
                 }
             }
-            // Render saved transparent render bins
-            osgUtil::RenderStage* renderStage = cv->getRenderStage();
-            osgUtil::RenderBin::RenderBinList& rbl = renderStage->getRenderBinList();
-            for (osgUtil::RenderBin::RenderBinList::iterator rbi = info->savedTransparentBins.begin(); rbi != info->savedTransparentBins.end(); ++rbi ){
-                rbl.insert( std::make_pair( rbi->first + 10000, rbi->second ) );
-            }
-            info->savedTransparentBins.clear();
         }
     }
 
 private:
-    flightgear::CameraKind kind;
+    std::string kind;
     CameraInfo* info;
+    bool needsDuDv;
 };
 
-osg::Texture2D* buildDeferredBuffer(GLint internalFormat, GLenum sourceFormat, GLenum sourceType, osg::Texture::WrapMode wrapMode, bool shadowComparison = false)
+osg::Texture2D* buildDeferredBuffer(GLint internalFormat, GLenum sourceFormat, GLenum sourceType, GLenum wrapMode, bool shadowComparison = false)
 {
     osg::Texture2D* tex = new osg::Texture2D;
     tex->setResizeNonPowerOfTwoHint( false );
@@ -767,64 +777,49 @@ osg::Texture2D* buildDeferredBuffer(GLint internalFormat, GLenum sourceFormat, G
     tex->setSourceType(sourceType);
     tex->setFilter( osg::Texture2D::MIN_FILTER, osg::Texture2D::LINEAR );
     tex->setFilter( osg::Texture2D::MAG_FILTER, osg::Texture2D::LINEAR );
-    tex->setWrap( osg::Texture::WRAP_S, wrapMode );
-    tex->setWrap( osg::Texture::WRAP_T, wrapMode );
+    tex->setWrap( osg::Texture::WRAP_S, (osg::Texture::WrapMode)wrapMode );
+    tex->setWrap( osg::Texture::WRAP_T, (osg::Texture::WrapMode)wrapMode );
        return tex;
 }
 
-void buildDeferredBuffers( flightgear::CameraInfo* info, int shadowMapSize, bool useColorForDepth )
-{
-    if (useColorForDepth) {
-        info->addBuffer(flightgear::RenderBufferInfo::REAL_DEPTH_BUFFER, buildDeferredBuffer( GL_DEPTH_COMPONENT32, GL_DEPTH_COMPONENT, GL_FLOAT, osg::Texture::CLAMP_TO_BORDER) );
-        info->addBuffer(flightgear::RenderBufferInfo::DEPTH_BUFFER, buildDeferredBuffer( GL_RGBA8, GL_RGBA, GL_UNSIGNED_BYTE, osg::Texture::CLAMP_TO_BORDER) );
-    }
-    else {
-        info->addBuffer(flightgear::RenderBufferInfo::DEPTH_BUFFER, buildDeferredBuffer( GL_DEPTH_COMPONENT32, GL_DEPTH_COMPONENT, GL_FLOAT, osg::Texture::CLAMP_TO_BORDER) );
-    }
-    info->addBuffer(flightgear::RenderBufferInfo::NORMAL_BUFFER, buildDeferredBuffer( GL_RGBA8, GL_RGBA, GL_UNSIGNED_BYTE, osg::Texture::CLAMP_TO_BORDER) );
-    info->addBuffer(flightgear::RenderBufferInfo::DIFFUSE_BUFFER, buildDeferredBuffer( GL_RGBA8, GL_RGBA, GL_UNSIGNED_BYTE, osg::Texture::CLAMP_TO_BORDER) );
-    info->addBuffer(flightgear::RenderBufferInfo::SPEC_EMIS_BUFFER, buildDeferredBuffer( GL_RGBA8, GL_RGBA, GL_UNSIGNED_BYTE, osg::Texture::CLAMP_TO_BORDER) );
-    info->addBuffer(flightgear::RenderBufferInfo::LIGHTING_BUFFER, buildDeferredBuffer( GL_RGBA8, GL_RGBA, GL_UNSIGNED_BYTE, osg::Texture::CLAMP_TO_BORDER) );
-    info->addBuffer(flightgear::RenderBufferInfo::SHADOW_BUFFER, buildDeferredBuffer( GL_DEPTH_COMPONENT32, GL_DEPTH_COMPONENT, GL_FLOAT, osg::Texture::CLAMP_TO_BORDER, true), 0.0f );
-    info->getBuffer(RenderBufferInfo::SHADOW_BUFFER)->setTextureSize(shadowMapSize,shadowMapSize);
-}
-
-void attachBufferToCamera( flightgear::CameraInfo* info, osg::Camera* camera, osg::Camera::BufferComponent c, flightgear::CameraKind ck, flightgear::RenderBufferInfo::Kind bk )
+void attachBufferToCamera( CameraInfo* info, osg::Camera* camera, osg::Camera::BufferComponent c, const std::string& ck, const std::string& bk )
 {
     camera->attach( c, info->getBuffer(bk) );
     info->getRenderStageInfo(ck).buffers.insert( std::make_pair( c, bk ) );
 }
 
-osg::Camera* FGRenderer::buildDeferredGeometryCamera( flightgear::CameraInfo* info, osg::GraphicsContext* gc )
+void buildAttachments(CameraInfo* info, osg::Camera* camera, const std::string& name, const std::vector<ref_ptr<FGRenderingPipeline::Attachment> > &attachments) {
+    BOOST_FOREACH(ref_ptr<FGRenderingPipeline::Attachment> attachment, attachments) {
+        if (attachment->valid())
+            attachBufferToCamera( info, camera, attachment->component, name, attachment->buffer );
+    }
+}
+
+osg::Camera* FGRenderer::buildDeferredGeometryCamera( CameraInfo* info, osg::GraphicsContext* gc, const std::string& name, const std::vector<ref_ptr<FGRenderingPipeline::Attachment> > &attachments )
 {
     osg::Camera* camera = new osg::Camera;
-    info->addCamera(flightgear::GEOMETRY_CAMERA, camera );
+    info->addCamera(name, camera );
 
     camera->setCullMask( ~simgear::MODELLIGHT_BIT );
     camera->setName( "GeometryC" );
+    camera->setReferenceFrame(osg::Transform::ABSOLUTE_RF);
     camera->setGraphicsContext( gc );
-    camera->setCullCallback( new FGDeferredRenderingCameraCullCallback( flightgear::GEOMETRY_CAMERA, info ) );
+    camera->setCullCallback( new FGDeferredRenderingCameraCullCallback( name, info ) );
     camera->setClearMask( GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT );
     camera->setClearColor( osg::Vec4( 0., 0., 0., 0. ) );
     camera->setClearDepth( 1.0 );
+    camera->setColorMask(true, true, true, true);
     camera->setRenderTargetImplementation( osg::Camera::FRAME_BUFFER_OBJECT );
+    camera->setRenderOrder(osg::Camera::NESTED_RENDER, 0);
     camera->setViewport( new osg::Viewport );
-    attachBufferToCamera( info, camera, osg::Camera::COLOR_BUFFER0, flightgear::GEOMETRY_CAMERA, flightgear::RenderBufferInfo::NORMAL_BUFFER );
-    attachBufferToCamera( info, camera, osg::Camera::COLOR_BUFFER1, flightgear::GEOMETRY_CAMERA, flightgear::RenderBufferInfo::DIFFUSE_BUFFER );
-    attachBufferToCamera( info, camera, osg::Camera::COLOR_BUFFER2, flightgear::GEOMETRY_CAMERA, flightgear::RenderBufferInfo::SPEC_EMIS_BUFFER );
-    if (_useColorForDepth) {
-        attachBufferToCamera( info, camera, osg::Camera::DEPTH_BUFFER, flightgear::GEOMETRY_CAMERA, flightgear::RenderBufferInfo::REAL_DEPTH_BUFFER );
-        attachBufferToCamera( info, camera, osg::Camera::COLOR_BUFFER3, flightgear::GEOMETRY_CAMERA, flightgear::RenderBufferInfo::DEPTH_BUFFER );
-    } else {
-        attachBufferToCamera( info, camera, osg::Camera::DEPTH_BUFFER, flightgear::GEOMETRY_CAMERA, flightgear::RenderBufferInfo::DEPTH_BUFFER );
-    }
+    buildAttachments(info, camera, name, attachments);
     camera->setDrawBuffer(GL_FRONT);
     camera->setReadBuffer(GL_FRONT);
 
     osg::StateSet* ss = camera->getOrCreateStateSet();
     ss->addUniform( _depthInColor );
 
-    camera->addChild( mDeferredRealRoot.get() );
+    camera->addChild( _deferredRealRoot.get() );
 
     return camera;
 }
@@ -857,8 +852,8 @@ static osg::Camera* createShadowCascadeCamera( int no, int cascadeSize ) {
     oss << "CascadeCamera" << (no + 1);
     cascadeCam->setName( oss.str() );
     cascadeCam->setClearMask(0);
-    cascadeCam->setCullMask(~( simgear::MODELLIGHT_BIT /* | simgear::NO_SHADOW_BIT */ ) );
-    cascadeCam->setCullingMode( cascadeCam->getCullingMode() & ~osg::CullSettings::SMALL_FEATURE_CULLING );
+    cascadeCam->setCullMask( simgear::CASTSHADOW_BIT );
+    cascadeCam->setCullingMode( cascadeCam->getCullingMode() osg::CullSettings::SMALL_FEATURE_CULLING );
     cascadeCam->setAllowEventFocus(false);
     cascadeCam->setReferenceFrame(osg::Transform::ABSOLUTE_RF_INHERIT_VIEWPOINT);
     cascadeCam->setRenderOrder(osg::Camera::NESTED_RENDER);
@@ -867,10 +862,10 @@ static osg::Camera* createShadowCascadeCamera( int no, int cascadeSize ) {
     return cascadeCam;
 }
 
-osg::Camera* FGRenderer::buildDeferredShadowCamera( flightgear::CameraInfo* info, osg::GraphicsContext* gc )
+osg::Camera* FGRenderer::buildDeferredShadowCamera( CameraInfo* info, osg::GraphicsContext* gc, const std::string& name, const std::vector<ref_ptr<FGRenderingPipeline::Attachment> > &attachments )
 {
     osg::Camera* mainShadowCamera = new osg::Camera;
-    info->addCamera(flightgear::SHADOW_CAMERA, mainShadowCamera, 0.0f );
+    info->addCamera(name, mainShadowCamera, 0.0f );
 
     mainShadowCamera->setName( "ShadowC" );
     mainShadowCamera->setClearMask( GL_DEPTH_BUFFER_BIT );
@@ -878,7 +873,7 @@ osg::Camera* FGRenderer::buildDeferredShadowCamera( flightgear::CameraInfo* info
     mainShadowCamera->setAllowEventFocus(false);
     mainShadowCamera->setGraphicsContext(gc);
     mainShadowCamera->setRenderTargetImplementation( osg::Camera::FRAME_BUFFER_OBJECT );
-    attachBufferToCamera( info, mainShadowCamera, osg::Camera::DEPTH_BUFFER, flightgear::SHADOW_CAMERA, flightgear::RenderBufferInfo::SHADOW_BUFFER );
+    buildAttachments(info, mainShadowCamera, name, attachments);
     mainShadowCamera->setComputeNearFarMode(osg::Camera::DO_NOT_COMPUTE_NEAR_FAR);
     mainShadowCamera->setReferenceFrame(osg::Transform::ABSOLUTE_RF);
     mainShadowCamera->setProjectionMatrix(osg::Matrix::identity());
@@ -886,15 +881,15 @@ osg::Camera* FGRenderer::buildDeferredShadowCamera( flightgear::CameraInfo* info
     mainShadowCamera->setViewport( 0, 0, _shadowMapSize, _shadowMapSize );
     mainShadowCamera->setDrawBuffer(GL_FRONT);
     mainShadowCamera->setReadBuffer(GL_FRONT);
+    mainShadowCamera->setRenderOrder(Camera::NESTED_RENDER, 1);
 
     osg::Switch* shadowSwitch = new osg::Switch;
     mainShadowCamera->addChild( shadowSwitch );
 
     for (int i = 0; i < 4; ++i ) {
         osg::Camera* cascadeCam = createShadowCascadeCamera( i, _shadowMapSize/2 );
-        cascadeCam->addChild( mDeferredRealRoot.get() );
+        cascadeCam->addChild( _deferredRealRoot.get() );
         shadowSwitch->addChild( cascadeCam );
-        info->shadowTexGen[i] = new osg::TexGen;
     }
     if (fgGetBool("/sim/rendering/shadows/enabled", true))
         shadowSwitch->setAllChildrenOn();
@@ -930,7 +925,7 @@ osg::Vec3 FGRenderer::getSunDirection() const
     return val;
 }
 
-void FGRenderer::updateShadowCamera(const flightgear::CameraInfo* info, const osg::Vec3d& position)
+void FGRenderer::updateShadowCamera(const CameraInfo* info, const osg::Vec3d& position)
 {
     ref_ptr<Camera> mainShadowCamera = info->getCamera( SHADOW_CAMERA );
     if (mainShadowCamera.valid()) {
@@ -1002,7 +997,7 @@ void FGRenderer::updateShadowMapSize(int mapSize)
         Camera* camera = info->getCamera(SHADOW_CAMERA);
         if (camera == 0) continue;
 
-        Texture2D* tex = info->getBuffer(RenderBufferInfo::SHADOW_BUFFER);
+        Texture2D* tex = info->getBuffer("shadow");
         if (tex == 0) continue;
 
         tex->setTextureSize( mapSize, mapSize );
@@ -1073,421 +1068,167 @@ void FGRenderer::updateCascadeNumber(size_t num)
     _shadowNumber->set( (int)_numCascades );
 }
 
+class DebugPassListener : public SGPropertyChangeListener {
+public:
+    DebugPassListener(osg::Switch* sw, int i) : _switch(sw), _index(i) {}
+    virtual void valueChanged(SGPropertyNode* node) {
+        _switch->setValue(_index, node->getBoolValue());
+    }
 
-#define STRINGIFY(x) #x
-#define TOSTRING(x) STRINGIFY(x)
-
-const char *ambient_vert_src = ""
-    "#line " TOSTRING(__LINE__) " 1\n"
-    "void main() {\n"
-    "    gl_Position = gl_Vertex;\n"
-    "    gl_TexCoord[0] = gl_MultiTexCoord0;\n"
-    "}\n";
-
-const char *ambient_frag_src = ""
-    "#line " TOSTRING(__LINE__) " 1\n"
-    "uniform sampler2D color_tex;\n"
-//    "uniform sampler2D ao_tex;\n"
-    "uniform sampler2D normal_tex;\n"
-    "uniform sampler2D spec_emis_tex;\n"
-    "uniform vec4 fg_SunAmbientColor;\n"
-    "void main() {\n"
-    "    vec2 coords = gl_TexCoord[0].xy;\n"
-    "    float initialized = texture2D( spec_emis_tex, coords ).a;\n"
-    "    if ( initialized < 0.1 )\n"
-    "        discard;\n"
-    "    vec3 tcolor = texture2D( color_tex, coords ).rgb;\n"
-//    "    float ao = texture2D( ao_tex, coords ).r;\n"
-//    "    gl_FragColor = vec4(tcolor*fg_SunAmbientColor.rgb*ao, 1.0);\n"
-    "    gl_FragColor = vec4(tcolor*fg_SunAmbientColor.rgb, 1.0);\n"
-    "}\n";
-
-const char *sunlight_vert_src = ""
-    "#line " TOSTRING(__LINE__) " 1\n"
-//  "uniform mat4 fg_ViewMatrixInverse;\n"
-    "uniform mat4 fg_ProjectionMatrixInverse;\n"
-    "varying vec3 ray;\n"
-    "void main() {\n"
-    "    gl_Position = gl_Vertex;\n"
-    "    gl_TexCoord[0] = gl_MultiTexCoord0;\n"
-//  "    ray = (fg_ViewMatrixInverse * vec4((fg_ProjectionMatrixInverse * gl_Vertex).xyz, 0.0)).xyz;\n"
-    "    ray = (fg_ProjectionMatrixInverse * gl_Vertex).xyz;\n"
-    "}\n";
-
-const char *sunlight_frag_src = ""
-#if 0
-    "#version 130\n"
-#endif
-    "#line " TOSTRING(__LINE__) " 1\n"
-    "uniform mat4 fg_ViewMatrix;\n"
-    "uniform sampler2D depth_tex;\n"
-    "uniform sampler2D normal_tex;\n"
-    "uniform sampler2D color_tex;\n"
-    "uniform sampler2D spec_emis_tex;\n"
-    "uniform sampler2DShadow shadow_tex;\n"
-    "uniform vec4 fg_SunDiffuseColor;\n"
-    "uniform vec4 fg_SunSpecularColor;\n"
-    "uniform vec3 fg_SunDirection;\n"
-    "uniform vec3 fg_Planes;\n"
-    "varying vec3 ray;\n"
-    "vec4 DynamicShadow( in vec4 ecPosition, out vec4 tint )\n"
-    "{\n"
-    "    vec4 coords;\n"
-    "    vec2 shift = vec2( 0.0 );\n"
-    "    int index = 4;\n"
-    "    if (ecPosition.z > -5.0) {\n"
-    "        index = 1;\n"
-    "        tint = vec4(0.0,1.0,0.0,1.0);\n"
-    "    } else if (ecPosition.z > -50.0) {\n"
-    "        index = 2;\n"
-    "        shift = vec2( 0.0, 0.5 );\n"
-    "        tint = vec4(0.0,0.0,1.0,1.0);\n"
-    "    } else if (ecPosition.z > -512.0) {\n"
-    "        index = 3;\n"
-    "        shift = vec2( 0.5, 0.0 );\n"
-    "        tint = vec4(1.0,1.0,0.0,1.0);\n"
-    "    } else if (ecPosition.z > -10000.0) {\n"
-    "        shift = vec2( 0.5, 0.5 );\n"
-    "        tint = vec4(1.0,0.0,0.0,1.0);\n"
-    "    } else {\n"
-    "        return vec4(1.1,1.1,0.0,1.0);\n" // outside, clamp to border
-    "    }\n"
-    "    coords.s = dot( ecPosition, gl_EyePlaneS[index] );\n"
-    "    coords.t = dot( ecPosition, gl_EyePlaneT[index] );\n"
-    "    coords.p = dot( ecPosition, gl_EyePlaneR[index] );\n"
-    "    coords.q = dot( ecPosition, gl_EyePlaneQ[index] );\n"
-    "    coords.st *= .5;\n"
-    "    coords.st += shift;\n"
-    "    return coords;\n"
-    "}\n"
-    "void main() {\n"
-    "    vec2 coords = gl_TexCoord[0].xy;\n"
-    "    vec4 spec_emis = texture2D( spec_emis_tex, coords );\n"
-    "    if ( spec_emis.a < 0.1 )\n"
-    "        discard;\n"
-    "    vec3 normal;\n"
-    "    normal.xy = texture2D( normal_tex, coords ).rg * 2.0 - vec2(1.0,1.0);\n"
-    "    normal.z = sqrt( 1.0 - dot( normal.xy, normal.xy ) );\n"
-    "    float len = length(normal);\n"
-    "    normal /= len;\n"
-    "    vec3 viewDir = normalize(ray);\n"
-    "    float depth = texture2D( depth_tex, coords ).r;\n"
-    "    vec3 pos;\n"
-    "    pos.z = - fg_Planes.y / (fg_Planes.x + depth * fg_Planes.z);\n"
-    "    pos.xy = viewDir.xy / viewDir.z * pos.z;\n"
-
-    "    vec4 tint;\n"
-#if 0
-    "    float shadow = 1.0;\n"
-#elif 1
-    "    float shadow = shadow2DProj( shadow_tex, DynamicShadow( vec4( pos, 1.0 ), tint ) ).r;\n"
-#else
-    "    float kernel[9] = float[]( 36/256.0, 24/256.0, 6/256.0,\n"
-    "                           24/256.0, 16/256.0, 4/256.0,\n"
-    "                           6/256.0,  4/256.0, 1/256.0 );\n"
-    "    float shadow = 0;\n"
-    "    for( int x = -2; x <= 2; ++x )\n"
-    "      for( int y = -2; y <= 2; ++y )\n"
-    "        shadow += kernel[abs(x)*3 + abs(y)] * shadow2DProj( shadow_tex, DynamicShadow( vec4(pos + vec3(0.05 * x, 0.05 * y, 0), 1.0), tint ) ).r;\n"
-#endif
-    "    vec3 lightDir = (fg_ViewMatrix * vec4( fg_SunDirection, 0.0 )).xyz;\n"
-    "    lightDir = normalize( lightDir );\n"
-    "    vec3 color = texture2D( color_tex, coords ).rgb;\n"
-    "    vec3 Idiff = clamp( dot( lightDir, normal ), 0.0, 1.0 ) * color * fg_SunDiffuseColor.rgb;\n"
-    "    vec3 halfDir = lightDir - viewDir;\n"
-    "    len = length( halfDir );\n"
-    "    vec3 Ispec = vec3(0.0);\n"
-    "    vec3 Iemis = spec_emis.z * color;\n"
-    "    if (len > 0.0001) {\n"
-    "        halfDir /= len;\n"
-    "        Ispec = pow( clamp( dot( halfDir, normal ), 0.0, 1.0 ), spec_emis.y * 255.0 ) * spec_emis.x * fg_SunSpecularColor.rgb;\n"
-    "    }\n"
-    "    gl_FragColor = vec4(mix(vec3(0.0), Idiff + Ispec, shadow) + Iemis, 1.0);\n"
-//    "    gl_FragColor = mix(tint, vec4(mix(vec3(0.0), Idiff + Ispec, shadow) + Iemis, 1.0), 0.92);\n"
-    "}\n";
-
-const char *fog_vert_src = ""
-    "#line " TOSTRING(__LINE__) " 1\n"
-    "uniform mat4 fg_ProjectionMatrixInverse;\n"
-    "varying vec3 ray;\n"
-    "void main() {\n"
-    "    gl_Position = gl_Vertex;\n"
-    "    gl_TexCoord[0] = gl_MultiTexCoord0;\n"
-    "    ray = (fg_ProjectionMatrixInverse * gl_Vertex).xyz;\n"
-    "}\n";
-
-const char *fog_frag_src = ""
-    "#line " TOSTRING(__LINE__) " 1\n"
-    "uniform sampler2D depth_tex;\n"
-    "uniform sampler2D normal_tex;\n"
-    "uniform sampler2D color_tex;\n"
-    "uniform sampler2D spec_emis_tex;\n"
-    "uniform vec4 fg_FogColor;\n"
-    "uniform float fg_FogDensity;\n"
-    "uniform vec3 fg_Planes;\n"
-    "varying vec3 ray;\n"
-    "void main() {\n"
-    "    vec2 coords = gl_TexCoord[0].xy;\n"
-    "    float initialized = texture2D( spec_emis_tex, coords ).a;\n"
-    "    if ( initialized < 0.1 )\n"
-    "        discard;\n"
-    "    vec3 normal;\n"
-    "    normal.xy = texture2D( normal_tex, coords ).rg * 2.0 - vec2(1.0,1.0);\n"
-    "    normal.z = sqrt( 1.0 - dot( normal.xy, normal.xy ) );\n"
-    "    float len = length(normal);\n"
-    "    normal /= len;\n"
-    "    vec3 viewDir = normalize(ray);\n"
-    "    float depth = texture2D( depth_tex, coords ).r;\n"
-    "    vec3 pos;\n"
-    "    pos.z = - fg_Planes.y / (fg_Planes.x + depth * fg_Planes.z);\n"
-    "    pos.xy = viewDir.xy / viewDir.z * pos.z;\n"
-
-    "    float fogFactor = 0.0;\n"
-    "    const float LOG2 = 1.442695;\n"
-    "    fogFactor = exp2(-fg_FogDensity * fg_FogDensity * pos.z * pos.z * LOG2);\n"
-    "    fogFactor = clamp(fogFactor, 0.0, 1.0);\n"
-
-    "    gl_FragColor = vec4(fg_FogColor.rgb, 1.0 - fogFactor);\n"
-    "}\n";
-
-osg::Camera* FGRenderer::buildDeferredLightingCamera( flightgear::CameraInfo* info, osg::GraphicsContext* gc )
+private:
+    osg::ref_ptr<osg::Switch> _switch;
+    int _index;
+};
+
+osg::Camera*
+FGRenderer::buildDeferredLightingCamera( flightgear::CameraInfo* info, osg::GraphicsContext* gc, const FGRenderingPipeline::Stage* stage )
 {
     osg::Camera* camera = new osg::Camera;
-    info->addCamera(flightgear::LIGHTING_CAMERA, camera );
+    info->addCamera(stage->name, camera );
 
-    camera->setCullCallback( new FGDeferredRenderingCameraCullCallback( flightgear::LIGHTING_CAMERA, info ) );
+    camera->setCullCallback( new FGDeferredRenderingCameraCullCallback( stage->name, info ) );
     camera->setAllowEventFocus(false);
     camera->setGraphicsContext(gc);
     camera->setViewport(new Viewport);
-    camera->setName("LightingC");
+    camera->setName(stage->name+"C");
     camera->setReferenceFrame(osg::Transform::ABSOLUTE_RF);
-    camera->setRenderOrder(osg::Camera::POST_RENDER, 50);
+    camera->setRenderOrder(osg::Camera::NESTED_RENDER, stage->orderNum);
     camera->setRenderTargetImplementation( osg::Camera::FRAME_BUFFER_OBJECT );
     camera->setViewport( new osg::Viewport );
-    attachBufferToCamera( info, camera, osg::Camera::COLOR_BUFFER, flightgear::LIGHTING_CAMERA, flightgear::RenderBufferInfo::LIGHTING_BUFFER );
-    if (_useColorForDepth) {
-        attachBufferToCamera( info, camera, osg::Camera::DEPTH_BUFFER, flightgear::GEOMETRY_CAMERA, flightgear::RenderBufferInfo::REAL_DEPTH_BUFFER );
-    } else {
-        attachBufferToCamera( info, camera, osg::Camera::DEPTH_BUFFER, flightgear::GEOMETRY_CAMERA, flightgear::RenderBufferInfo::DEPTH_BUFFER );
-    }
+    buildAttachments(info, camera, stage->name, stage->attachments);
     camera->setDrawBuffer(GL_FRONT);
     camera->setReadBuffer(GL_FRONT);
-    camera->setClearColor( osg::Vec4( 0., 0., 0., 1. ) );
     camera->setClearMask( GL_COLOR_BUFFER_BIT );
     osg::StateSet* ss = camera->getOrCreateStateSet();
     ss->setAttribute( new osg::Depth(osg::Depth::LESS, 0.0, 1.0, false) );
     ss->addUniform( _depthInColor );
 
-    osg::Group* lightingGroup = new osg::Group;
-
-    osg::Camera* quadCam1 = new osg::Camera;
-    quadCam1->setName( "QuadCamera1" );
-    quadCam1->setClearMask(0);
-    quadCam1->setAllowEventFocus(false);
-    quadCam1->setReferenceFrame(osg::Transform::ABSOLUTE_RF);
-    quadCam1->setRenderOrder(osg::Camera::NESTED_RENDER);
-    quadCam1->setViewMatrix(osg::Matrix::identity());
-    quadCam1->setProjectionMatrixAsOrtho2D(-1,1,-1,1);
-    quadCam1->setComputeNearFarMode(osg::CullSettings::DO_NOT_COMPUTE_NEAR_FAR);
-    ss = quadCam1->getOrCreateStateSet();
-    ss->addUniform( _ambientFactor );
+    osg::Switch* lightingGroup = new osg::Switch;
+
+    BOOST_FOREACH( osg::ref_ptr<FGRenderingPipeline::Pass> pass, stage->passes ) {
+        ref_ptr<Node> node = buildPass(info, pass);
+        if (node.valid()) {
+            lightingGroup->addChild(node);
+            if (!pass->debugProperty.empty()) {
+                lightingGroup->setValue(lightingGroup->getNumChildren()-1, fgGetBool(pass->debugProperty));
+                fgAddChangeListener(new DebugPassListener(lightingGroup, lightingGroup->getNumChildren()-1), pass->debugProperty);
+            }
+        }
+    }
+
+    camera->addChild( lightingGroup );
+
+    return camera;
+}
+
+CameraInfo*
+FGRenderer::buildDeferredPipeline(CameraGroup* cgroup, unsigned flags, osg::Camera* camera,
+                                    const osg::Matrix& view,
+                                    const osg::Matrix& projection,
+                                    osg::GraphicsContext* gc)
+{
+    return buildCameraFromRenderingPipeline(_pipeline, cgroup, flags, camera, view, projection, gc);
+}
+
+osg::Camera* 
+FGRenderer::buildDeferredFullscreenCamera( flightgear::CameraInfo* info, const FGRenderingPipeline::Pass* pass )
+{
+    osg::Camera* camera = new osg::Camera;
+
+    camera->setClearMask( 0 );
+    camera->setAllowEventFocus(false);
+    camera->setName(pass->name+"C");
+    camera->setReferenceFrame(osg::Transform::ABSOLUTE_RF);
+    camera->setRenderOrder(osg::Camera::NESTED_RENDER, pass->orderNum);
+    camera->setComputeNearFarMode(osg::CullSettings::DO_NOT_COMPUTE_NEAR_FAR);
+    camera->setViewMatrix(osg::Matrix::identity());
+    camera->setProjectionMatrixAsOrtho2D(-1,1,-1,1);
+
+    osg::StateSet* ss = camera->getOrCreateStateSet();
+    ss->setMode(GL_DEPTH_TEST, osg::StateAttribute::OFF);
     ss->addUniform( info->projInverse );
     ss->addUniform( info->viewInverse );
     ss->addUniform( info->view );
+    ss->addUniform( info->bufferSize );
+    ss->addUniform( info->worldPosCart );
+    ss->addUniform( info->worldPosGeod );
+    ss->addUniform( info->shadowMatrix[0] );
+    ss->addUniform( info->shadowMatrix[1] );
+    ss->addUniform( info->shadowMatrix[2] );
+    ss->addUniform( info->shadowMatrix[3] );
+    ss->addUniform( _ambientFactor );
     ss->addUniform( _sunDiffuse );
     ss->addUniform( _sunSpecular );
     ss->addUniform( _sunDirection );
     ss->addUniform( _planes );
     ss->addUniform( _shadowNumber );
     ss->addUniform( _shadowDistances );
+    ss->addUniform( _fogColor );
+    ss->addUniform( _fogDensity );
 
     osg::Geometry* g = osg::createTexturedQuadGeometry( osg::Vec3(-1.,-1.,0.), osg::Vec3(2.,0.,0.), osg::Vec3(0.,2.,0.) );
     g->setUseDisplayList(false);
     simgear::EffectGeode* eg = new simgear::EffectGeode;
-    simgear::Effect* effect = simgear::makeEffect("Effects/ambient", true);
+    osg::ref_ptr<SGReaderWriterOptions> opt;
+    opt = SGReaderWriterOptions::fromPath(globals->get_fg_root());
+    opt->setPropertyNode(globals->get_props());
+    simgear::Effect* effect = simgear::makeEffect(pass->effect, true, opt.get());
     if (effect) {
         eg->setEffect( effect );
-    } else {
-        SG_LOG( SG_VIEW, SG_ALERT, "=> Using default, builtin, Effects/ambient" );
-        ss = eg->getOrCreateStateSet();
-        ss->setMode( GL_LIGHTING, osg::StateAttribute::OFF );
-        ss->setMode( GL_DEPTH_TEST, osg::StateAttribute::OFF );
-        ss->setTextureAttributeAndModes( 0, info->getBuffer( flightgear::RenderBufferInfo::DEPTH_BUFFER ) );
-        ss->setTextureAttributeAndModes( 1, info->getBuffer( flightgear::RenderBufferInfo::NORMAL_BUFFER ) );
-        ss->setTextureAttributeAndModes( 2, info->getBuffer( flightgear::RenderBufferInfo::DIFFUSE_BUFFER ) );
-        ss->setTextureAttributeAndModes( 3, info->getBuffer( flightgear::RenderBufferInfo::SPEC_EMIS_BUFFER ) );
-        //ss->setTextureAttributeAndModes( 4, info->gBuffer->aoBuffer[2] );
-        ss->addUniform( new osg::Uniform( "depth_tex", 0 ) );
-        ss->addUniform( new osg::Uniform( "normal_tex", 1 ) );
-        ss->addUniform( new osg::Uniform( "color_tex", 2 ) );
-        ss->addUniform( new osg::Uniform( "spec_emis_tex", 3 ) );
-        //ss->addUniform( new osg::Uniform( "ao_tex", 4 ) );
-        ss->setRenderBinDetails( 0, "RenderBin" );
-        osg::Program* program = new osg::Program;
-        program->addShader( new osg::Shader( osg::Shader::VERTEX, ambient_vert_src ) );
-        program->addShader( new osg::Shader( osg::Shader::FRAGMENT, ambient_frag_src ) );
-        ss->setAttributeAndModes( program );
     }
 
-    g->setName( "AmbientQuad" );
-    eg->setName("AmbientQuad");
+    eg->setName(pass->name+"Quad");
     eg->setCullingActive(false);
     eg->addDrawable(g);
-    quadCam1->addChild( eg );
-
-    g = osg::createTexturedQuadGeometry( osg::Vec3(-1.,-1.,0.), osg::Vec3(2.,0.,0.), osg::Vec3(0.,2.,0.) );
-    g->setUseDisplayList(false);
-    g->setName( "SunlightQuad" );
-    eg = new simgear::EffectGeode;
-    effect = simgear::makeEffect("Effects/sunlight", true);
-    if (effect) {
-        eg->setEffect( effect );
-    } else {
-        SG_LOG( SG_VIEW, SG_ALERT, "=> Using default, builtin, Effects/sunlight" );
-        ss = eg->getOrCreateStateSet();
-        ss->setMode( GL_LIGHTING, osg::StateAttribute::OFF );
-        ss->setMode( GL_DEPTH_TEST, osg::StateAttribute::OFF );
-        ss->setAttributeAndModes( new osg::BlendFunc( osg::BlendFunc::ONE, osg::BlendFunc::ONE ) );
-        ss->setTextureAttribute( 0, info->getBuffer( flightgear::RenderBufferInfo::DEPTH_BUFFER ) );
-        ss->setTextureAttribute( 1, info->getBuffer( flightgear::RenderBufferInfo::NORMAL_BUFFER ) );
-        ss->setTextureAttribute( 2, info->getBuffer( flightgear::RenderBufferInfo::DIFFUSE_BUFFER ) );
-        ss->setTextureAttribute( 3, info->getBuffer( flightgear::RenderBufferInfo::SPEC_EMIS_BUFFER ) );
-        ss->setTextureAttribute( 4, info->getBuffer( flightgear::RenderBufferInfo::SHADOW_BUFFER ) );
-        ss->addUniform( new osg::Uniform( "depth_tex", 0 ) );
-        ss->addUniform( new osg::Uniform( "normal_tex", 1 ) );
-        ss->addUniform( new osg::Uniform( "color_tex", 2 ) );
-        ss->addUniform( new osg::Uniform( "spec_emis_tex", 3 ) );
-        ss->addUniform( new osg::Uniform( "shadow_tex", 4 ) );
-        ss->setRenderBinDetails( 1, "RenderBin" );
-        osg::Program* program = new osg::Program;
-        program->addShader( new osg::Shader( osg::Shader::VERTEX, sunlight_vert_src ) );
-        program->addShader( new osg::Shader( osg::Shader::FRAGMENT, sunlight_frag_src ) );
-        ss->setAttributeAndModes( program );
-    }
-    eg->setName("SunlightQuad");
-    eg->setCullingActive(false);
-    eg->addDrawable(g);
-    quadCam1->addChild( eg );
+    camera->addChild(eg);
 
-    osg::Camera* lightCam = new osg::Camera;
-    ss = lightCam->getOrCreateStateSet();
-    ss->addUniform( _planes );
-    ss->addUniform( info->bufferSize );
-    lightCam->setName( "LightCamera" );
-    lightCam->setClearMask(0);
-    lightCam->setAllowEventFocus(false);
-    lightCam->setReferenceFrame(osg::Transform::RELATIVE_RF);
-    lightCam->setRenderOrder(osg::Camera::NESTED_RENDER,1);
-    lightCam->setViewMatrix(osg::Matrix::identity());
-    lightCam->setProjectionMatrix(osg::Matrix::identity());
-    lightCam->setComputeNearFarMode(osg::CullSettings::DO_NOT_COMPUTE_NEAR_FAR);
-    lightCam->setCullMask( simgear::MODELLIGHT_BIT );
-    lightCam->setInheritanceMask( osg::CullSettings::ALL_VARIABLES & ~osg::CullSettings::CULL_MASK );
-    lightCam->addChild( mDeferredRealRoot.get() );
-
-
-    osg::Camera* quadCam2 = new osg::Camera;
-    quadCam2->setName( "QuadCamera1" );
-    quadCam2->setClearMask(0);
-    quadCam2->setAllowEventFocus(false);
-    quadCam2->setReferenceFrame(osg::Transform::ABSOLUTE_RF);
-    quadCam2->setRenderOrder(osg::Camera::NESTED_RENDER,2);
-    quadCam2->setViewMatrix(osg::Matrix::identity());
-    quadCam2->setProjectionMatrixAsOrtho2D(-1,1,-1,1);
-    quadCam2->setComputeNearFarMode(osg::CullSettings::DO_NOT_COMPUTE_NEAR_FAR);
-    ss = quadCam2->getOrCreateStateSet();
-    ss->addUniform( _ambientFactor );
-    ss->addUniform( info->projInverse );
-    ss->addUniform( info->viewInverse );
-    ss->addUniform( info->view );
-    ss->addUniform( _sunDiffuse );
-    ss->addUniform( _sunSpecular );
-    ss->addUniform( _sunDirection );
-    ss->addUniform( _fogColor );
-    ss->addUniform( _fogDensity );
-    ss->addUniform( _planes );
+    return camera;
+}
 
-    g = osg::createTexturedQuadGeometry( osg::Vec3(-1.,-1.,0.), osg::Vec3(2.,0.,0.), osg::Vec3(0.,2.,0.) );
-    g->setUseDisplayList(false);
-    g->setName( "FogQuad" );
-    eg = new simgear::EffectGeode;
-    effect = simgear::makeEffect("Effects/fog", true);
-    if (effect) {
-        eg->setEffect( effect );
-    } else {
-        SG_LOG( SG_VIEW, SG_ALERT, "=> Using default, builtin, Effects/fog" );
-        ss = eg->getOrCreateStateSet();
-        ss->setMode( GL_LIGHTING, osg::StateAttribute::OFF );
-        ss->setMode( GL_DEPTH_TEST, osg::StateAttribute::OFF );
-        ss->setAttributeAndModes( new osg::BlendFunc( osg::BlendFunc::SRC_ALPHA, osg::BlendFunc::ONE_MINUS_SRC_ALPHA ) );
-        ss->setTextureAttributeAndModes( 0, info->getBuffer( flightgear::RenderBufferInfo::DEPTH_BUFFER ) );
-        ss->setTextureAttributeAndModes( 1, info->getBuffer( flightgear::RenderBufferInfo::NORMAL_BUFFER ) );
-        ss->setTextureAttributeAndModes( 2, info->getBuffer( flightgear::RenderBufferInfo::DIFFUSE_BUFFER ) );
-        ss->setTextureAttributeAndModes( 3, info->getBuffer( flightgear::RenderBufferInfo::SPEC_EMIS_BUFFER ) );
-        ss->addUniform( new osg::Uniform( "depth_tex", 0 ) );
-        ss->addUniform( new osg::Uniform( "normal_tex", 1 ) );
-        ss->addUniform( new osg::Uniform( "color_tex", 2 ) );
-        ss->addUniform( new osg::Uniform( "spec_emis_tex", 3 ) );
-        ss->setRenderBinDetails( 10000, "RenderBin" );
-        osg::Program* program = new osg::Program;
-        program->addShader( new osg::Shader( osg::Shader::VERTEX, fog_vert_src ) );
-        program->addShader( new osg::Shader( osg::Shader::FRAGMENT, fog_frag_src ) );
-        ss->setAttributeAndModes( program );
-    }
-    eg->setName("FogQuad");
-    eg->setCullingActive(false);
-    eg->addDrawable(g);
-    quadCam2->addChild( eg );
+osg::Camera* 
+FGRenderer::buildDeferredFullscreenCamera( flightgear::CameraInfo* info, osg::GraphicsContext* gc, const FGRenderingPipeline::Stage* stage )
+{
+    osg::Camera* camera = buildDeferredFullscreenCamera(info, static_cast<const FGRenderingPipeline::Pass*>(stage));
+    info->addCamera(stage->name, camera, stage->scaleFactor, true);
 
-    lightingGroup->addChild( _sky->getPreRoot() );
-    lightingGroup->addChild( _sky->getCloudRoot() );
-    lightingGroup->addChild( quadCam1 );
-    lightingGroup->addChild( lightCam );
-    lightingGroup->addChild( quadCam2 );
+    camera->setCullCallback( new FGDeferredRenderingCameraCullCallback(stage->name, info, stage->needsDuDv) );
+    camera->setGraphicsContext(gc);
+    camera->setViewport(new Viewport);
+    camera->setRenderTargetImplementation( osg::Camera::FRAME_BUFFER_OBJECT );
+    buildAttachments(info, camera, stage->name, stage->attachments);
+    camera->setDrawBuffer(GL_FRONT);
+    camera->setReadBuffer(GL_FRONT);
+    camera->setClearColor( osg::Vec4( 1., 1., 1., 1. ) );
+    camera->setClearMask( GL_COLOR_BUFFER_BIT );
+    camera->setViewMatrix(osg::Matrix::identity());
+    camera->setProjectionMatrixAsOrtho2D(-1,1,-1,1);
 
-    camera->addChild( lightingGroup );
+    osg::StateSet* ss = camera->getOrCreateStateSet();
+    if (stage->needsDuDv) {
+        ss->addUniform( info->du );
+        ss->addUniform( info->dv );
+    }
 
     return camera;
 }
 
-flightgear::CameraInfo*
-FGRenderer::buildDeferredPipeline(flightgear::CameraGroup* cgroup, unsigned flags, osg::Camera* camera,
-                                    const osg::Matrix& view,
-                                    const osg::Matrix& projection,
-                                    osg::GraphicsContext* gc)
+void
+FGRenderer::buildDeferredDisplayCamera( osg::Camera* camera, flightgear::CameraInfo* info, const FGRenderingPipeline::Stage* stage, osg::GraphicsContext* gc )
 {
-    CameraInfo* info = new CameraInfo(flags);
-    buildDeferredBuffers(info, _shadowMapSize, _useColorForDepth);
-
-    osg::Camera* geometryCamera = buildDeferredGeometryCamera( info, gc );
-    cgroup->getViewer()->addSlave(geometryCamera, false);
-    installCullVisitor(geometryCamera);
-    int slaveIndex = cgroup->getViewer()->getNumSlaves() - 1;
-    info->getRenderStageInfo(GEOMETRY_CAMERA).slaveIndex = slaveIndex;
-    
-    Camera* shadowCamera = buildDeferredShadowCamera( info, gc );
-    cgroup->getViewer()->addSlave(shadowCamera, false);
-    installCullVisitor(shadowCamera);
-    slaveIndex = cgroup->getViewer()->getNumSlaves() - 1;
-    info->getRenderStageInfo(SHADOW_CAMERA).slaveIndex = slaveIndex;
-
-    osg::Camera* lightingCamera = buildDeferredLightingCamera( info, gc );
-    cgroup->getViewer()->addSlave(lightingCamera, false);
-    installCullVisitor(lightingCamera);
-    slaveIndex = cgroup->getViewer()->getNumSlaves() - 1;
-    info->getRenderStageInfo(LIGHTING_CAMERA).slaveIndex = slaveIndex;
-
     camera->setName( "DisplayC" );
-    camera->setCullCallback( new FGDeferredRenderingCameraCullCallback( flightgear::DISPLAY_CAMERA, info ) );
+    camera->setCullCallback( new FGDeferredRenderingCameraCullCallback( stage->name, info ) );
     camera->setReferenceFrame(Transform::ABSOLUTE_RF);
     camera->setAllowEventFocus(false);
     osg::Geometry* g = osg::createTexturedQuadGeometry( osg::Vec3(-1.,-1.,0.), osg::Vec3(2.,0.,0.), osg::Vec3(0.,2.,0.) );
     g->setUseDisplayList(false); //DEBUG
     simgear::EffectGeode* eg = new simgear::EffectGeode;
-    simgear::Effect* effect = simgear::makeEffect("Effects/display", true);
+    osg::ref_ptr<SGReaderWriterOptions> opt;
+    opt = SGReaderWriterOptions::fromPath(globals->get_fg_root());
+    opt->setPropertyNode(globals->get_props());
+    simgear::Effect* effect = simgear::makeEffect(stage->effect, true, opt.get());
     if (!effect) {
-        SG_LOG(SG_VIEW, SG_ALERT, "Effects/display not found");
-        return 0;
+        SG_LOG(SG_VIEW, SG_ALERT, stage->effect + " not found");
+        return;
     }
     eg->setEffect(effect);
     eg->setCullingActive(false);
@@ -1498,70 +1239,182 @@ FGRenderer::buildDeferredPipeline(flightgear::CameraGroup* cgroup, unsigned flag
 
     osg::StateSet* ss = camera->getOrCreateStateSet();
     ss->addUniform( _depthInColor );
+    ss->addUniform( info->projInverse );
+    ss->addUniform( info->viewInverse );
+    ss->addUniform( info->view );
+    ss->addUniform( info->bufferSize );
+    ss->addUniform( info->worldPosCart );
+    ss->addUniform( info->worldPosGeod );
+    ss->addUniform( info->shadowMatrix[0] );
+    ss->addUniform( info->shadowMatrix[1] );
+    ss->addUniform( info->shadowMatrix[2] );
+    ss->addUniform( info->shadowMatrix[3] );
+    ss->addUniform( _ambientFactor );
+    ss->addUniform( _sunDiffuse );
+    ss->addUniform( _sunSpecular );
+    ss->addUniform( _sunDirection );
+    ss->addUniform( _planes );
+    ss->addUniform( _shadowNumber );
+    ss->addUniform( _shadowDistances );
+    ss->addUniform( _fogColor );
+    ss->addUniform( _fogDensity );
+}
 
-    cgroup->getViewer()->addSlave(camera, false);
+void
+FGRenderer::buildStage(CameraInfo* info,
+                        FGRenderingPipeline::Stage* stage,
+                        CameraGroup* cgroup,
+                        osg::Camera* mainCamera,
+                        const osg::Matrix& view, const osg::Matrix& projection, osg::GraphicsContext* gc)
+{
+    if (!stage->valid())
+        return;
+
+    ref_ptr<Camera> camera;
+    bool needOffsets = false;
+    if (stage->type == "geometry") {
+        camera = buildDeferredGeometryCamera(info, gc, stage->name, stage->attachments);
+        needOffsets = true;
+    } else if (stage->type == "lighting") {
+        camera = buildDeferredLightingCamera(info, gc, stage);
+        needOffsets = true;
+    } else if (stage->type == "shadow")
+        camera = buildDeferredShadowCamera(info, gc, stage->name, stage->attachments);
+    else if (stage->type == "fullscreen")
+        camera = buildDeferredFullscreenCamera(info, gc, stage);
+    else if (stage->type == "display") {
+        camera = mainCamera;
+        buildDeferredDisplayCamera(camera, info, stage, gc);
+    } else
+        throw sg_exception("Stage type is not supported");
+
+    if (needOffsets)
+        cgroup->getViewer()->addSlave(camera, projection, view, false);
+    else
+        cgroup->getViewer()->addSlave(camera, false);
     installCullVisitor(camera);
-    slaveIndex = cgroup->getViewer()->getNumSlaves() - 1;
-    info->addCamera( DISPLAY_CAMERA, camera, slaveIndex, true );
-    camera->setRenderOrder(Camera::POST_RENDER, 99+slaveIndex); //FIXME
-    cgroup->addCamera(info);
-    return info;
+    int slaveIndex = cgroup->getViewer()->getNumSlaves() - 1;
+    if (stage->type == "display")
+        info->addCamera( stage->type, camera, slaveIndex, true );
+    info->getRenderStageInfo(stage->name).slaveIndex = slaveIndex;
 }
 
+osg::Node*
+FGRenderer::buildLightingSkyCloudsPass(FGRenderingPipeline::Pass* pass)
+{
+    Group* group = new Group;
+    group->setName("skyCloudsGroup");
+    group->setNodeMask(simgear::BACKGROUND_BIT);
+    
+    StateSet* ss = group->getOrCreateStateSet();
+    ss->setAttributeAndModes( new osg::ColorMask( true, true, true, false ), osg::StateAttribute::ON );
+    group->addChild( _sky->getPreRoot() );
+    group->addChild( _sky->getCloudRoot() );
+    return group;
+}
 
-void
-FGRenderer::setupView( void )
+osg::Node*
+FGRenderer::buildLightingLightsPass(CameraInfo* info, FGRenderingPipeline::Pass* pass)
 {
-    osgViewer::Viewer* viewer = globals->get_renderer()->getViewer();
-    osg::initNotifyLevel();
+    osg::Camera* lightCam = new osg::Camera;
+    StateSet* ss = lightCam->getOrCreateStateSet();
+    ss->addUniform( _planes );
+    ss->addUniform( info->bufferSize );
+    ss->addUniform( _fogColor );
+    ss->addUniform( _fogDensity );
+    lightCam->setName( "LightCamera" );
+    lightCam->setClearMask(0);
+    lightCam->setAllowEventFocus(false);
+    lightCam->setReferenceFrame(osg::Transform::RELATIVE_RF);
+    lightCam->setRenderOrder(osg::Camera::NESTED_RENDER,pass->orderNum);
+    lightCam->setViewMatrix(osg::Matrix::identity());
+    lightCam->setProjectionMatrix(osg::Matrix::identity());
+    lightCam->setComputeNearFarMode(osg::CullSettings::DO_NOT_COMPUTE_NEAR_FAR);
+    lightCam->setCullMask( simgear::MODELLIGHT_BIT | simgear::PANEL2D_BIT | simgear::PERMANENTLIGHT_BIT);
+    lightCam->setInheritanceMask( osg::CullSettings::ALL_VARIABLES & ~osg::CullSettings::CULL_MASK );
+    lightCam->addChild( _deferredRealRoot.get() );
 
-    // The number of polygon-offset "units" to place between layers.  In
-    // principle, one is supposed to be enough.  In practice, I find that
-    // my hardware/driver requires many more.
-    osg::PolygonOffset::setUnitsMultiplier(1);
-    osg::PolygonOffset::setFactorMultiplier(1);
+    return lightCam;
+}
 
-    // Go full screen if requested ...
-    if ( fgGetBool("/sim/startup/fullscreen") )
-        fgOSFullScreen();
+osg::Node*
+FGRenderer::buildPass(CameraInfo* info, FGRenderingPipeline::Pass* pass)
+{
+    if (!pass->valid())
+        return 0;
 
-// build the sky    
-    // The sun and moon diameters are scaled down numbers of the
-    // actual diameters. This was needed to fit both the sun and the
-    // moon within the distance to the far clip plane.
-    // Moon diameter:    3,476 kilometers
-    // Sun diameter: 1,390,000 kilometers
-    _sky->build( 80000.0, 80000.0,
-                  463.3, 361.8,
-                  *globals->get_ephem(),
-                  fgGetNode("/environment", true));
-    
-    viewer->getCamera()
-        ->setComputeNearFarMode(osg::CullSettings::DO_NOT_COMPUTE_NEAR_FAR);
+    ref_ptr<Node> node;
+    if (pass->type == "sky-clouds")
+        node = buildLightingSkyCloudsPass(pass);
+    else if (pass->type == "fullscreen")
+        node = buildDeferredFullscreenCamera(info, pass);
+    else if (pass->type == "lights")
+        node = buildLightingLightsPass(info, pass);
+    else
+        throw sg_exception("Pass type is not supported");
+
+    return node.release();
+}
+
+void
+FGRenderer::buildBuffers(FGRenderingPipeline* rpipe, CameraInfo* info)
+{
+    for (size_t i = 0; i < rpipe->buffers.size(); ++i) {
+        osg::ref_ptr<FGRenderingPipeline::Buffer> buffer = rpipe->buffers[i];
+        if (buffer->valid()) {
+            bool fullscreen = buffer->width == -1 && buffer->height == -1;
+            info->addBuffer(buffer->name, buildDeferredBuffer( buffer->internalFormat,
+                                                                buffer->sourceFormat,
+                                                                buffer->sourceType,
+                                                                buffer->wrapMode,
+                                                                buffer->shadowComparison),
+                            fullscreen ? buffer->scaleFactor : 0.0f);
+            if (!fullscreen) {
+                info->getBuffer(buffer->name)->setTextureSize(buffer->width, buffer->height);
+            }
+        }
+    }
+}
+
+CameraInfo* FGRenderer::buildCameraFromRenderingPipeline(FGRenderingPipeline* rpipe, CameraGroup* cgroup, unsigned flags, osg::Camera* camera,
+                                    const osg::Matrix& view, const osg::Matrix& projection, osg::GraphicsContext* gc)
+{
+    CameraInfo* info = new CameraInfo(flags);
+    buildBuffers(rpipe, info);
     
-    osg::StateSet* stateSet = mRoot->getOrCreateStateSet();
+    for (size_t i = 0; i < rpipe->stages.size(); ++i) {
+        osg::ref_ptr<FGRenderingPipeline::Stage> stage = rpipe->stages[i];
+        buildStage(info, stage, cgroup, camera, view, projection, gc);
+    }
+
+    cgroup->addCamera(info);
+
+    return info;
+}
 
+void FGRenderer::setupRoot()
+{
+    osg::StateSet* stateSet = _root->getOrCreateStateSet();
+    
     stateSet->setMode(GL_LIGHTING, osg::StateAttribute::OFF);
     
     stateSet->setAttribute(new osg::Depth(osg::Depth::LESS));
     stateSet->setMode(GL_DEPTH_TEST, osg::StateAttribute::OFF);
-
-    stateSet->setAttribute(new osg::AlphaFunc(osg::AlphaFunc::GREATER, 0.01));
-    stateSet->setMode(GL_ALPHA_TEST, osg::StateAttribute::OFF);
+    
     stateSet->setAttribute(new osg::BlendFunc);
     stateSet->setMode(GL_BLEND, osg::StateAttribute::OFF);
-
+    
     stateSet->setMode(GL_FOG, osg::StateAttribute::OFF);
     
     // this will be set below
     stateSet->setMode(GL_NORMALIZE, osg::StateAttribute::OFF);
-
+    
     osg::Material* material = new osg::Material;
     stateSet->setAttribute(material);
     
     stateSet->setTextureAttribute(0, new osg::TexEnv);
     stateSet->setTextureMode(0, GL_TEXTURE_2D, osg::StateAttribute::OFF);
-
+    
     osg::Hint* hint = new osg::Hint(GL_FOG_HINT, GL_DONT_CARE);
     hint->setUpdateCallback(new FGHintUpdateCallback("/sim/rendering/fog"));
     stateSet->setAttribute(hint);
@@ -1577,16 +1430,41 @@ FGRenderer::setupView( void )
     hint = new osg::Hint(GL_PERSPECTIVE_CORRECTION_HINT, GL_DONT_CARE);
     hint->setUpdateCallback(new FGHintUpdateCallback("/sim/rendering/perspective-correction"));
     stateSet->setAttribute(hint);
+}
+                                    
+void
+FGRenderer::setupView( void )
+{
+    osgViewer::Viewer* viewer = globals->get_renderer()->getViewer();
+    osg::initNotifyLevel();
 
-    osg::Group* sceneGroup = new osg::Group;
-    sceneGroup->addChild(globals->get_scenery()->get_scene_graph());
-    sceneGroup->setNodeMask(~simgear::BACKGROUND_BIT);
-
-    //sceneGroup->addChild(thesky->getCloudRoot());
-
-    stateSet = sceneGroup->getOrCreateStateSet();
-    stateSet->setMode(GL_DEPTH_TEST, osg::StateAttribute::ON);
+    // The number of polygon-offset "units" to place between layers.  In
+    // principle, one is supposed to be enough.  In practice, I find that
+    // my hardware/driver requires many more.
+    osg::PolygonOffset::setUnitsMultiplier(1);
+    osg::PolygonOffset::setFactorMultiplier(1);
 
+    setupRoot();
+  
+// build the sky    
+    // The sun and moon diameters are scaled down numbers of the
+    // actual diameters. This was needed to fit both the sun and the
+    // moon within the distance to the far clip plane.
+    // Moon diameter:    3,476 kilometers
+    // Sun diameter: 1,390,000 kilometers
+    osg::ref_ptr<SGReaderWriterOptions> opt;
+    opt = SGReaderWriterOptions::fromPath(globals->get_fg_root());
+    opt->setPropertyNode(globals->get_props());
+    _sky->build( 80000.0, 80000.0,
+                  463.3, 361.8,
+                  *globals->get_ephem(),
+                  fgGetNode("/environment", true),
+                  opt.get());
+    
+    viewer->getCamera()
+        ->setComputeNearFarMode(osg::CullSettings::DO_NOT_COMPUTE_NEAR_FAR);
+    
+  
     // need to update the light on every frame
     // OSG LightSource objects are rather confusing. OSG only supports
     // the 10 lights specified by OpenGL itself; if more than one
@@ -1597,15 +1475,18 @@ FGRenderer::setupView( void )
     // has the corresponding OpenGL light enabled: a LightSource will
     // affect geometry anywhere in the scene graph that has its light
     // number enabled in a state set. 
-    LightSource* lightSource = new LightSource;
+    osg::ref_ptr<LightSource> lightSource = new LightSource;
+    lightSource->setName("FGLightSource");
     lightSource->getLight()->setDataVariance(Object::DYNAMIC);
     // relative because of CameraView being just a clever transform node
     lightSource->setReferenceFrame(osg::LightSource::RELATIVE_RF);
     lightSource->setLocalStateSetModes(osg::StateAttribute::ON);
     lightSource->setUpdateCallback(new FGLightSourceUpdateCallback);
-    mRealRoot->addChild(lightSource);
+    _viewerSceneRoot->addChild(lightSource);
+    
     // we need a white diffuse light for the phase of the moon
-    osg::LightSource* sunLight = new osg::LightSource;
+    osg::ref_ptr<LightSource> sunLight = new osg::LightSource;
+    sunLight->setName("sunLightSource");
     sunLight->getLight()->setDataVariance(Object::DYNAMIC);
     sunLight->getLight()->setLightNum(1);
     sunLight->setUpdateCallback(new FGLightSourceUpdateCallback(true));
@@ -1614,18 +1495,22 @@ FGRenderer::setupView( void )
     
     // Hang a StateSet above the sky subgraph in order to turn off
     // light 0
-    Group* skyGroup = new Group;
+    Group* skyGroup = _sky->getPreRoot();
     StateSet* skySS = skyGroup->getOrCreateStateSet();
     skySS->setMode(GL_LIGHT0, StateAttribute::OFF);
-    skyGroup->addChild(_sky->getPreRoot());
     sunLight->addChild(skyGroup);
-    mRoot->addChild(sceneGroup);
-    if ( _classicalRenderer )
-        mRoot->addChild(sunLight);
     
-    // Clouds are added to the scene graph later
-    stateSet = globals->get_scenery()->get_scene_graph()->getOrCreateStateSet();
-    stateSet->setMode(GL_ALPHA_TEST, osg::StateAttribute::ON);
+    if ( _classicalRenderer ) {
+        _root->addChild(sunLight);
+    }
+  
+    osg::Group* sceneGroup = globals->get_scenery()->get_scene_graph();
+    sceneGroup->setName("rendererScene");
+    sceneGroup->setNodeMask(~simgear::BACKGROUND_BIT);
+    _root->addChild(sceneGroup);
+  
+    // setup state-set for main scenery (including models and aircraft)
+    osg::StateSet* stateSet = sceneGroup->getOrCreateStateSet();
     stateSet->setMode(GL_LIGHTING, osg::StateAttribute::ON);
     stateSet->setMode(GL_DEPTH_TEST, osg::StateAttribute::ON);
 
@@ -1655,62 +1540,37 @@ FGRenderer::setupView( void )
         geode->addDrawable(new SGHUDDrawable);
         guiCamera->addChild(geode);
       
-        panelSwitch = new osg::Switch;
-        osg::StateSet* stateSet = panelSwitch->getOrCreateStateSet();
-        stateSet->setRenderBinDetails(1000, "RenderBin");
-        
-        // speed optimization?
-        stateSet->setMode(GL_CULL_FACE, osg::StateAttribute::OFF);
-        stateSet->setAttribute(new osg::BlendFunc(osg::BlendFunc::SRC_ALPHA, osg::BlendFunc::ONE_MINUS_SRC_ALPHA));
-        stateSet->setMode(GL_BLEND, osg::StateAttribute::ON);
-        stateSet->setMode(GL_FOG, osg::StateAttribute::OFF);
-        stateSet->setMode(GL_DEPTH_TEST, osg::StateAttribute::OFF);
-        
-        
-        panelSwitch->setUpdateCallback(new FGPanelSwitchCallback);
-        panelChanged();
         
-        guiCamera->addChild(panelSwitch.get());
+      guiCamera->addChild(FGPanelNode::create2DPanelNode());
     }
     
     osg::Switch* sw = new osg::Switch;
+    sw->setName("scenerySwitch");
     sw->setUpdateCallback(new FGScenerySwitchCallback);
-    sw->addChild(mRoot.get());
-    mRealRoot->addChild(sw);
+    sw->addChild(_root.get());
+    _viewerSceneRoot->addChild(sw);
     // The clouds are attached directly to the scene graph root
     // because, in theory, they don't want the same default state set
     // as the rest of the scene. This may not be true in practice.
-       if ( _classicalRenderer ) {
-               mRealRoot->addChild(_sky->getCloudRoot());
-               mRealRoot->addChild(FGCreateRedoutNode());
-       }
+    if ( _classicalRenderer ) {
+      _viewerSceneRoot->addChild(_sky->getCloudRoot());
+      _viewerSceneRoot->addChild(FGCreateRedoutNode());
+    }
+  
     // Attach empty program to the scene root so that shader programs
     // don't leak into state sets (effects) that shouldn't have one.
-    stateSet = mRealRoot->getOrCreateStateSet();
+    stateSet = _viewerSceneRoot->getOrCreateStateSet();
     stateSet->setAttributeAndModes(new osg::Program, osg::StateAttribute::ON);
 
-       mDeferredRealRoot->addChild( mRealRoot.get() );
-}
-
-void FGRenderer::panelChanged()
-{
-    if (!panelSwitch) {
-        return;
-    }
-    
-    osg::Node* n = FGPanelNode::createNode(globals->get_current_panel());
-    if (panelSwitch->getNumChildren()) {
-        panelSwitch->setChild(0, n);
-    } else {
-        panelSwitch->addChild(n);
+    if ( !_classicalRenderer ) {
+        _deferredRealRoot->addChild( _viewerSceneRoot.get() );
     }
 }
-                                    
+
 // Update all Visuals (redraws anything graphics related)
 void
 FGRenderer::update( ) {
-    if (!(_scenery_loaded->getBoolValue() || 
-           _scenery_override->getBoolValue()))
+    if (!_position_finalized || !_scenery_loaded->getBoolValue())
     {
         _splash_alpha->setDoubleValue(1.0);
         return;
@@ -1757,124 +1617,89 @@ FGRenderer::update( ) {
   
     osg::Camera *camera = viewer->getCamera();
 
-    bool skyblend = _skyblend->getBoolValue();
-    if ( skyblend ) {
-       
-        if ( _textures->getBoolValue() ) {
-            SGVec4f clearColor(l->adj_fog_color());
-            camera->setClearColor(toOsg(clearColor));
-        }
-    } else {
-        SGVec4f clearColor(l->sky_color());
-        camera->setClearColor(toOsg(clearColor));
-    }
-
-    // update fog params if visibility has changed
-    double visibility_meters = _visibility_m->getDoubleValue();
-    _sky->set_visibility(visibility_meters);
-
-    double altitude_m = _altitude_ft->getDoubleValue() * SG_FEET_TO_METER;
-    _sky->modify_vis( altitude_m, 0.0 /* time factor, now unused */);
-
-    // update the sky dome
-    if ( skyblend ) {
-
-        // The sun and moon distances are scaled down versions
-        // of the actual distance to get both the moon and the sun
-        // within the range of the far clip plane.
-        // Moon distance:    384,467 kilometers
-        // Sun distance: 150,000,000 kilometers
-
-        double sun_horiz_eff, moon_horiz_eff;
-        if (_horizon_effect->getBoolValue()) {
-            sun_horiz_eff
-                = 0.67 + pow(osg::clampAbove(0.5 + cos(l->get_sun_angle()),
-                                             0.0),
-                             0.33) / 3.0;
-            moon_horiz_eff
-                = 0.67 + pow(osg::clampAbove(0.5 + cos(l->get_moon_angle()),
-                                             0.0),
-                             0.33)/3.0;
-        } else {
-           sun_horiz_eff = moon_horiz_eff = 1.0;
-        }
-
-        SGSkyState sstate;
-        sstate.pos       = current__view->getViewPosition();
-        sstate.pos_geod  = current__view->getPosition();
-        sstate.ori       = current__view->getViewOrientation();
-        sstate.spin      = l->get_sun_rotation();
-        sstate.gst       = globals->get_time_params()->getGst();
-        sstate.sun_dist  = 50000.0 * sun_horiz_eff;
-        sstate.moon_dist = 40000.0 * moon_horiz_eff;
-        sstate.sun_angle = l->get_sun_angle();
-
-        SGSkyColor scolor;
-        scolor.sky_color   = SGVec3f(l->sky_color().data());
-        scolor.adj_sky_color = SGVec3f(l->adj_sky_color().data());
-        scolor.fog_color   = SGVec3f(l->adj_fog_color().data());
-        scolor.cloud_color = SGVec3f(l->cloud_color().data());
-        scolor.sun_angle   = l->get_sun_angle();
-        scolor.moon_angle  = l->get_moon_angle();
-  
-        double delta_time_sec = _sim_delta_sec->getDoubleValue();
-        _sky->reposition( sstate, *globals->get_ephem(), delta_time_sec );
-        _sky->repaint( scolor, *globals->get_ephem() );
-
-            //OSGFIXME
-//         shadows->setupShadows(
-//           current__view->getLongitude_deg(),
-//           current__view->getLatitude_deg(),
-//           globals->get_time_params()->getGst(),
-//           globals->get_ephem()->getSunRightAscension(),
-//           globals->get_ephem()->getSunDeclination(),
-//           l->get_sun_angle());
-
-    }
-
-//     sgEnviro.setLight(l->adj_fog_color());
-//     sgEnviro.startOfFrame(current__view->get_view_pos(), 
-//         current__view->get_world_up(),
-//         current__view->getLongitude_deg(),
-//         current__view->getLatitude_deg(),
-//         current__view->getAltitudeASL_ft() * SG_FEET_TO_METER,
-//         delta_time_sec);
-
-    // OSGFIXME
-//     sgEnviro.drawLightning();
-
-//        double current_view_origin_airspeed_horiz_kt =
-//         fgGetDouble("/velocities/airspeed-kt", 0.0)
-//                        * cos( fgGetDouble("/orientation/pitch-deg", 0.0)
-//                                * SGD_DEGREES_TO_RADIANS);
-
-    // OSGFIXME
-//     if( is_internal )
-//         shadows->endOfFrame();
+    SGVec4f clearColor(l->adj_fog_color());
+    camera->setClearColor(toOsg(clearColor));
 
+    updateSky();
+    
     // need to call the update visitor once
-    mFrameStamp->setCalendarTime(*globals->get_time_params()->getGmt());
-    mUpdateVisitor->setViewData(current__view->getViewPosition(),
+    _frameStamp->setCalendarTime(*globals->get_time_params()->getGmt());
+    _updateVisitor->setViewData(current__view->getViewPosition(),
                                 current__view->getViewOrientation());
     SGVec3f direction(l->sun_vec()[0], l->sun_vec()[1], l->sun_vec()[2]);
-    mUpdateVisitor->setLight(direction, l->scene_ambient(),
+    _updateVisitor->setLight(direction, l->scene_ambient(),
                              l->scene_diffuse(), l->scene_specular(),
                              l->adj_fog_color(),
                              l->get_sun_angle()*SGD_RADIANS_TO_DEGREES);
-    mUpdateVisitor->setVisibility(actual_visibility);
-    simgear::GroundLightManager::instance()->update(mUpdateVisitor.get());
+    _updateVisitor->setVisibility(actual_visibility);
+    simgear::GroundLightManager::instance()->update(_updateVisitor.get());
     osg::Node::NodeMask cullMask = ~simgear::LIGHTS_BITS & ~simgear::PICK_BIT;
     cullMask |= simgear::GroundLightManager::instance()
-        ->getLightNodeMask(mUpdateVisitor.get());
+        ->getLightNodeMask(_updateVisitor.get());
     if (_panel_hotspots->getBoolValue())
         cullMask |= simgear::PICK_BIT;
     CameraGroup::getDefault()->setCameraCullMasks(cullMask);
        if ( !_classicalRenderer ) {
                _fogColor->set( toOsg( l->adj_fog_color() ) );
-               _fogDensity->set( float( mUpdateVisitor->getFogExp2Density() ) );
+               _fogDensity->set( float( _updateVisitor->getFogExp2Density() ) );
        }
 }
 
+void
+FGRenderer::updateSky()
+{
+    // update fog params if visibility has changed
+    double visibility_meters = _visibility_m->getDoubleValue();
+    _sky->set_visibility(visibility_meters);
+    
+    double altitude_m = _altitude_ft->getDoubleValue() * SG_FEET_TO_METER;
+    _sky->modify_vis( altitude_m, 0.0 /* time factor, now unused */);
+
+    FGLight *l = static_cast<FGLight*>(globals->get_subsystem("lighting"));
+    
+    // The sun and moon distances are scaled down versions
+    // of the actual distance to get both the moon and the sun
+    // within the range of the far clip plane.
+    // Moon distance:    384,467 kilometers
+    // Sun distance: 150,000,000 kilometers
+    
+    double sun_horiz_eff, moon_horiz_eff;
+    if (_horizon_effect->getBoolValue()) {
+        sun_horiz_eff
+        = 0.67 + pow(osg::clampAbove(0.5 + cos(l->get_sun_angle()),
+                                     0.0),
+                     0.33) / 3.0;
+        moon_horiz_eff
+        = 0.67 + pow(osg::clampAbove(0.5 + cos(l->get_moon_angle()),
+                                     0.0),
+                     0.33)/3.0;
+    } else {
+        sun_horiz_eff = moon_horiz_eff = 1.0;
+    }
+    
+    SGSkyState sstate;
+    sstate.pos       = globals->get_current_view()->getViewPosition();
+    sstate.pos_geod  = globals->get_current_view()->getPosition();
+    sstate.ori       = globals->get_current_view()->getViewOrientation();
+    sstate.spin      = l->get_sun_rotation();
+    sstate.gst       = globals->get_time_params()->getGst();
+    sstate.sun_dist  = 50000.0 * sun_horiz_eff;
+    sstate.moon_dist = 40000.0 * moon_horiz_eff;
+    sstate.sun_angle = l->get_sun_angle();
+    
+    SGSkyColor scolor;
+    scolor.sky_color   = SGVec3f(l->sky_color().data());
+    scolor.adj_sky_color = SGVec3f(l->adj_sky_color().data());
+    scolor.fog_color   = SGVec3f(l->adj_fog_color().data());
+    scolor.cloud_color = SGVec3f(l->cloud_color().data());
+    scolor.sun_angle   = l->get_sun_angle();
+    scolor.moon_angle  = l->get_moon_angle();
+    
+    double delta_time_sec = _sim_delta_sec->getDoubleValue();
+    _sky->reposition( sstate, *globals->get_ephem(), delta_time_sec );
+    _sky->repaint( scolor, *globals->get_ephem() );
+}
+                                    
 void
 FGRenderer::resize( int width, int height )
 {
@@ -1888,16 +1713,71 @@ FGRenderer::resize( int width, int height )
     }
 }
 
+typedef osgUtil::LineSegmentIntersector::Intersection Intersection;
+SGVec2d uvFromIntersection(const Intersection& hit)
+{
+  // Taken from http://trac.openscenegraph.org/projects/osg/browser/OpenSceneGraph/trunk/examples/osgmovie/osgmovie.cpp
+
+  osg::Drawable* drawable = hit.drawable.get();
+  osg::Geometry* geometry = drawable ? drawable->asGeometry() : 0;
+  osg::Vec3Array* vertices =
+    geometry ? dynamic_cast<osg::Vec3Array*>(geometry->getVertexArray()) : 0;
+
+  if( !vertices )
+  {
+    SG_LOG(SG_INPUT, SG_WARN, "Unable to get vertices for intersection.");
+    return SGVec2d(-9999,-9999);
+  }
+
+  // get the vertex indices.
+  const Intersection::IndexList& indices = hit.indexList;
+  const Intersection::RatioList& ratios = hit.ratioList;
+
+  if( indices.size() != 3 || ratios.size() != 3 )
+  {
+    SG_LOG( SG_INPUT,
+            SG_WARN,
+            "Intersection has insufficient indices to work with." );
+    return SGVec2d(-9999,-9999);
+  }
+
+  unsigned int i1 = indices[0];
+  unsigned int i2 = indices[1];
+  unsigned int i3 = indices[2];
+
+  float r1 = ratios[0];
+  float r2 = ratios[1];
+  float r3 = ratios[2];
+
+  osg::Array* texcoords =
+    (geometry->getNumTexCoordArrays() > 0) ? geometry->getTexCoordArray(0) : 0;
+  osg::Vec2Array* texcoords_Vec2Array =
+    dynamic_cast<osg::Vec2Array*>(texcoords);
+
+  if( !texcoords_Vec2Array )
+  {
+    SG_LOG(SG_INPUT, SG_WARN, "Unable to get texcoords for intersection.");
+    return SGVec2d(-9999,-9999);
+  }
+
+  // we have tex coord array so now we can compute the final tex coord at the
+  // point of intersection.
+  osg::Vec2 tc1 = (*texcoords_Vec2Array)[i1];
+  osg::Vec2 tc2 = (*texcoords_Vec2Array)[i2];
+  osg::Vec2 tc3 = (*texcoords_Vec2Array)[i3];
+
+  return toSG( osg::Vec2d(tc1 * r1 + tc2 * r2 + tc3 * r3) );
+}
+
 bool
-FGRenderer::pick(std::vector<SGSceneryPick>& pickList,
-                 const osgGA::GUIEventAdapter* ea)
+FGRenderer::pick(std::vector<SGSceneryPick>& pickList, const osg::Vec2& windowPos)
 {
     // wipe out the return ...
     pickList.clear();
     typedef osgUtil::LineSegmentIntersector::Intersections Intersections;
     Intersections intersections;
 
-    if (!computeIntersections(CameraGroup::getDefault(), ea, intersections))
+    if (!computeIntersections(CameraGroup::getDefault(), windowPos, intersections))
         return false;
     for (Intersections::iterator hit = intersections.begin(),
              e = intersections.end();
@@ -1905,10 +1785,12 @@ FGRenderer::pick(std::vector<SGSceneryPick>& pickList,
          ++hit) {
         const osg::NodePath& np = hit->nodePath;
         osg::NodePath::const_reverse_iterator npi;
+        
         for (npi = np.rbegin(); npi != np.rend(); ++npi) {
             SGSceneUserData* ud = SGSceneUserData::getSceneUserData(*npi);
-            if (!ud)
+            if (!ud || (ud->getNumPickCallbacks() == 0))
                 continue;
+            
             for (unsigned i = 0; i < ud->getNumPickCallbacks(); ++i) {
                 SGPickCallback* pickCallback = ud->getPickCallback(i);
                 if (!pickCallback)
@@ -1916,11 +1798,16 @@ FGRenderer::pick(std::vector<SGSceneryPick>& pickList,
                 SGSceneryPick sceneryPick;
                 sceneryPick.info.local = toSG(hit->getLocalIntersectPoint());
                 sceneryPick.info.wgs84 = toSG(hit->getWorldIntersectPoint());
+
+                if( pickCallback->needsUV() )
+                  sceneryPick.info.uv = uvFromIntersection(*hit);
+
                 sceneryPick.callback = pickCallback;
                 pickList.push_back(sceneryPick);
-            }
-        }
+            } // of installed pick callbacks iteration
+        } // of reverse node path walk
     }
+    
     return !pickList.empty();
 }
 
@@ -1939,13 +1826,13 @@ FGRenderer::setEventHandler(FGEventHandler* eventHandler_)
 void
 FGRenderer::addCamera(osg::Camera* camera, bool useSceneData)
 {
-    mRealRoot->addChild(camera);
+    _viewerSceneRoot->addChild(camera);
 }
 
 void
 FGRenderer::removeCamera(osg::Camera* camera)
 {
-    mRealRoot->removeChild(camera);
+    _viewerSceneRoot->removeChild(camera);
 }
                                     
 void
@@ -1957,7 +1844,8 @@ FGRenderer::setPlanes( double zNear, double zFar )
 bool
 fgDumpSceneGraphToFile(const char* filename)
 {
-    return osgDB::writeNodeFile(*mRealRoot.get(), filename);
+    osgViewer::Viewer* viewer = globals->get_renderer()->getViewer();
+    return osgDB::writeNodeFile(*viewer->getSceneData(), filename);
 }
 
 bool