]> git.mxchange.org Git - flightgear.git/commitdiff
Move viewer-related sources to separate folder.
authorThorstenB <brehmt@gmail.com>
Wed, 25 Apr 2012 21:28:00 +0000 (23:28 +0200)
committerThorstenB <brehmt@gmail.com>
Wed, 25 Apr 2012 21:28:00 +0000 (23:28 +0200)
Simple source directory clean-up, so "Main" folder contains fewer stuff
and the list of files in the editors a lot shorter.

70 files changed:
src/AIModel/AIAircraft.cxx
src/AIModel/AICarrier.cxx
src/AIModel/AIEscort.cxx
src/AIModel/AIGroundVehicle.cxx
src/CMakeLists.txt
src/Cockpit/panel.cxx
src/Environment/environment_mgr.cxx
src/Environment/fgclouds.cxx
src/Environment/precipitation_mgr.cxx
src/GUI/gui.cxx
src/GUI/gui_funcs.cxx
src/Input/FGMouseInput.hxx
src/Instrumentation/HUD/HUD.cxx
src/Instrumentation/HUD/HUD_ladder.cxx
src/Instrumentation/HUD/HUD_runway.cxx
src/Instrumentation/groundradar.cxx
src/Instrumentation/od_gauge.cxx
src/Main/CMakeLists.txt
src/Main/CameraGroup.cxx [deleted file]
src/Main/CameraGroup.hxx [deleted file]
src/Main/FGEventHandler.cxx [deleted file]
src/Main/FGEventHandler.hxx [deleted file]
src/Main/WindowBuilder.cxx [deleted file]
src/Main/WindowBuilder.hxx [deleted file]
src/Main/WindowSystemAdapter.cxx [deleted file]
src/Main/WindowSystemAdapter.hxx [deleted file]
src/Main/bootstrap.cxx
src/Main/fg_commands.cxx
src/Main/fg_init.cxx
src/Main/fg_os_common.cxx
src/Main/fg_os_osgviewer.cxx [deleted file]
src/Main/fgviewer.cxx [deleted file]
src/Main/fgviewer.hxx [deleted file]
src/Main/globals.cxx
src/Main/main.cxx
src/Main/options.cxx
src/Main/renderer.cxx [deleted file]
src/Main/renderer.hxx [deleted file]
src/Main/splash.cxx [deleted file]
src/Main/splash.hxx [deleted file]
src/Main/viewer.cxx [deleted file]
src/Main/viewer.hxx [deleted file]
src/Main/viewmgr.cxx [deleted file]
src/Main/viewmgr.hxx [deleted file]
src/Model/acmodel.cxx
src/Network/jpg-httpd.cxx
src/Network/props.cxx
src/Scenery/scenery.cxx
src/Scenery/tilemgr.cxx
src/Time/light.cxx
src/Viewer/CMakeLists.txt [new file with mode: 0644]
src/Viewer/CameraGroup.cxx [new file with mode: 0644]
src/Viewer/CameraGroup.hxx [new file with mode: 0644]
src/Viewer/FGEventHandler.cxx [new file with mode: 0644]
src/Viewer/FGEventHandler.hxx [new file with mode: 0644]
src/Viewer/WindowBuilder.cxx [new file with mode: 0644]
src/Viewer/WindowBuilder.hxx [new file with mode: 0644]
src/Viewer/WindowSystemAdapter.cxx [new file with mode: 0644]
src/Viewer/WindowSystemAdapter.hxx [new file with mode: 0644]
src/Viewer/fg_os_osgviewer.cxx [new file with mode: 0644]
src/Viewer/fgviewer.cxx [new file with mode: 0644]
src/Viewer/fgviewer.hxx [new file with mode: 0644]
src/Viewer/renderer.cxx [new file with mode: 0644]
src/Viewer/renderer.hxx [new file with mode: 0644]
src/Viewer/splash.cxx [new file with mode: 0644]
src/Viewer/splash.hxx [new file with mode: 0644]
src/Viewer/viewer.cxx [new file with mode: 0644]
src/Viewer/viewer.hxx [new file with mode: 0644]
src/Viewer/viewmgr.cxx [new file with mode: 0644]
src/Viewer/viewmgr.hxx [new file with mode: 0644]

index 408dfb4a17c710e730f91f8faefeddebb001bd82..0a1050863d88b5359939be8687629209ab73a1ac 100644 (file)
@@ -25,7 +25,7 @@
 #include <simgear/route/waypoint.hxx>
 #include <Main/fg_props.hxx>
 #include <Main/globals.hxx>
-#include <Main/viewer.hxx>
+#include <Viewer/viewer.hxx>
 #include <Scenery/scenery.hxx>
 #include <Scenery/tilemgr.hxx>
 #include <Airports/dynamics.hxx>
index dc8cde561419f19aca2f0306b2b0f8bea8ce3438..8a39b1467759412a1854a3d06258363a4b8481b8 100644 (file)
@@ -31,7 +31,7 @@
 
 #include <math.h>
 #include <Main/util.hxx>
-#include <Main/viewer.hxx>
+#include <Viewer/viewer.hxx>
 
 #include "AICarrier.hxx"
 
index 9d19ce4b407180b586427843aca2169dcf918497..b3218ecee9879056a4aacd4a84c04dd14eb5192c 100644 (file)
@@ -32,7 +32,7 @@
 
 #include <math.h>
 #include <Main/util.hxx>
-#include <Main/viewer.hxx>
+#include <Viewer/viewer.hxx>
 
 #include <Scenery/scenery.hxx>
 
index e6df8d3025f291e7eae8c8c90c2d726a567e0f1b..f5f2b8832dcee3994902195deef2ebfd0ac4d15c 100644 (file)
@@ -24,7 +24,7 @@
 
 #include <simgear/sg_inlines.h>
 
-#include <Main/viewer.hxx>
+#include <Viewer/viewer.hxx>
 #include <Scenery/scenery.hxx>
 #include <Airports/dynamics.hxx>
 
index e558433a8257b2d304afb18cb5386fda86aba328..ab32ec186e170b4626bda96f2792d63e5c7d1ceb 100644 (file)
@@ -27,9 +27,11 @@ foreach( mylibfolder
                Time
                Traffic
                FDM
+               Viewer
                Main
-    )
+       )
+
+       add_subdirectory(${mylibfolder})
 
-    add_subdirectory(${mylibfolder})
 endforeach( mylibfolder )
 
index 0eb1f96f2013cd4d295221b193aaae063dd6c866..bc8f220bad528bbc1ab0a40c422436190d86bc98 100644 (file)
 
 #include <Main/globals.hxx>
 #include <Main/fg_props.hxx>
-#include <Main/viewmgr.hxx>
+#include <Viewer/viewmgr.hxx>
+#include <Viewer/viewer.hxx>
 #include <Time/light.hxx>
 #include <GUI/FGFontCache.hxx> 
-#include <Main/viewer.hxx>
 #include <Instrumentation/dclgps.hxx>
 
 #define WIN_X 0
index cc74f99553495fd4b587e36f0e5d72e0d3a831f6..f13d9e88f87e61444d85eb4cd6fe5581c2264870 100644 (file)
@@ -31,8 +31,8 @@
 #include <simgear/structure/event_mgr.hxx>
 
 #include <Main/main.hxx>
-#include <Main/renderer.hxx>
 #include <Main/fg_props.hxx>
+#include <Viewer/renderer.hxx>
 #include <FDM/flight.hxx>
 
 #include "environment.hxx"
index 6090851333d2845e9efac2116af74c281e813da4..d5db1ed204b7c3a78e37ca1e8bba0426f200dac4 100644 (file)
@@ -38,9 +38,9 @@
 #include <simgear/props/props_io.hxx>
 
 #include <Main/globals.hxx>
-#include <Main/renderer.hxx>
-#include <Airports/simple.hxx>
 #include <Main/util.hxx>
+#include <Viewer/renderer.hxx>
+#include <Airports/simple.hxx>
 
 #include "fgclouds.hxx"
 
index b3dd6e48012fe750b6e6a5c2853544fb75699883..e4ca0c0f638723d3bb367cd1b0d532d6fcdda3b5 100644 (file)
@@ -39,7 +39,7 @@
 
 #include <Main/fg_props.hxx>
 #include <Main/globals.hxx>
-#include <Main/renderer.hxx>
+#include <Viewer/renderer.hxx>
 #include <Scenery/scenery.hxx>
 
 #include "precipitation_mgr.hxx"
index 851f5dbb3a2e7cc5fde27e29515d91b565b367de..f9a16925973c0dc504ba5ceb11aebe5e3e378000 100644 (file)
@@ -43,7 +43,7 @@
 #include <Main/globals.hxx>
 #include <Main/locale.hxx>
 #include <Main/fg_props.hxx>
-#include <Main/WindowSystemAdapter.hxx>
+#include <Viewer/WindowSystemAdapter.hxx>
 #include <GUI/new_gui.hxx>
 #include <GUI/FGFontCache.hxx>
 
index 6cd2a95bf4d15953e3bb5439f50a047f42dfce2a..22e3e6a8caa071caef55d6dd25360b2743e8805a 100644 (file)
 #include <Main/globals.hxx>
 #include <Main/fg_props.hxx>
 #include <Main/fg_os.hxx>
-#include <Main/renderer.hxx>
-#include <Main/viewmgr.hxx>
-#include <Main/WindowSystemAdapter.hxx>
-#include <Main/CameraGroup.hxx>
+#include <Viewer/renderer.hxx>
+#include <Viewer/viewmgr.hxx>
+#include <Viewer/WindowSystemAdapter.hxx>
+#include <Viewer/CameraGroup.hxx>
 #include <GUI/new_gui.hxx>
 
 
index 7b9705713da6737323f45423112daa4840fec7a4..ba0054ca0c38f46e58ab0a41d359115a71a10ad2 100644 (file)
@@ -37,7 +37,8 @@
 #include <list>
 #include <simgear/structure/subsystem_mgr.hxx>
 #include <simgear/scene/util/SGPickCallback.hxx>
-#include <Main/renderer.hxx>
+#include <Viewer/renderer.hxx>
+
 /**
   * List of currently pressed mouse button events
   */
index 762b206fc248c97d4abd1c55047488909b183ca2..8c112aef6c1ee785ec2b45a17c424404ba6874cc 100644 (file)
@@ -37,8 +37,8 @@
 #include <plib/fnt.h>
 
 #include <Main/globals.hxx>
-#include <Main/viewmgr.hxx>
-#include <Main/viewer.hxx>
+#include <Viewer/viewmgr.hxx>
+#include <Viewer/viewer.hxx>
 #include <GUI/FGFontCache.hxx>
 
 #include "HUD.hxx"
index 9b4ba108461dbec5cd959cce462020e94b0fffbb..37a9f292cafaa3c132b4327ea71b33613ef8d926 100644 (file)
@@ -25,7 +25,7 @@
 
 #include <sstream>
 #include <simgear/math/SGGeometry.hxx>
-#include <Main/viewer.hxx>
+#include <Viewer/viewer.hxx>
 #include "HUD.hxx"
 
 // FIXME
index b115b3ae741c4756697bbdaeaf6da2f013d62cc1..f44a6d3a588e8eaaef82da263cade86f73f2401a 100644 (file)
@@ -33,8 +33,8 @@
 #include <FDM/flight.hxx>
 #include <Environment/environment.hxx>
 #include <Environment/environment_mgr.hxx>
-#include <Main/viewer.hxx>
-#include <Main/viewmgr.hxx>
+#include <Viewer/viewer.hxx>
+#include <Viewer/viewmgr.hxx>
 #include <ATCDCL/ATCutils.hxx>
 
 #include "HUD.hxx"
index 2669d2ab1b151b3cf42c22dff4a4b208570b10b0..b7d2834136d5f8b370b75ce8d11388aa2457426c 100644 (file)
@@ -36,7 +36,7 @@
 
 #include <Main/fg_props.hxx>
 #include <Main/globals.hxx>
-#include <Main/renderer.hxx>
+#include <Viewer/renderer.hxx>
 #include <Cockpit/panel.hxx>
 #include <Airports/simple.hxx>
 #include <Airports/runways.hxx>
index ad79f021ac5bbc8dfdf53d63d77a9c32bf2a7d44..6760bcd2244e17562d3aea218f89c3afda3a32ed 100644 (file)
@@ -42,7 +42,7 @@
 #include <simgear/debug/logstream.hxx>
 
 #include <Main/globals.hxx>
-#include <Main/renderer.hxx>
+#include <Viewer/renderer.hxx>
 #include <Scenery/scenery.hxx>
 #include "od_gauge.hxx"
 
index d136da9cbca8ec599e50d25833a6ecc6c785654a..017a29c8a409f95b7d55f3f46549e2c4046c0a40 100644 (file)
@@ -8,51 +8,32 @@ if (MSVC)
 endif (MSVC)
 
 set(SOURCES
-       CameraGroup.cxx
-       FGEventHandler.cxx
-       WindowBuilder.cxx
-       WindowSystemAdapter.cxx
        bootstrap.cxx
        fg_commands.cxx
        fg_init.cxx
        fg_io.cxx
        fg_os_common.cxx
-       fg_os_osgviewer.cxx
        fg_props.cxx
-       fgviewer.cxx
        globals.cxx
        locale.cxx
        logger.cxx
        main.cxx
        options.cxx
-       renderer.cxx
-       splash.cxx
        util.cxx
-       viewer.cxx
-       viewmgr.cxx
        ${RESOURCE_FILE}
        )
 
 set(HEADERS
-       CameraGroup.hxx
-       FGEventHandler.hxx
-       WindowBuilder.hxx
-       WindowSystemAdapter.hxx
        fg_commands.hxx
        fg_init.hxx
        fg_io.hxx
        fg_props.hxx
-       fgviewer.hxx
        globals.hxx
        locale.hxx
        logger.hxx
        main.hxx
        options.hxx
-       renderer.hxx
-       splash.hxx
        util.hxx
-       viewer.hxx
-       viewmgr.hxx
        )
 
 get_property(FG_SOURCES GLOBAL PROPERTY FG_SOURCES)
diff --git a/src/Main/CameraGroup.cxx b/src/Main/CameraGroup.cxx
deleted file mode 100644 (file)
index 495da49..0000000
+++ /dev/null
@@ -1,1241 +0,0 @@
-// Copyright (C) 2008  Tim Moore
-// Copyright (C) 2011  Mathias Froehlich
-//
-// This program is free software; you can redistribute it and/or
-// modify it under the terms of the GNU General Public License as
-// published by the Free Software Foundation; either version 2 of the
-// License, or (at your option) any later version.
-//
-// This program is distributed in the hope that it will be useful, but
-// WITHOUT ANY WARRANTY; without even the implied warranty of
-// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
-// General Public License for more details.
-//
-// You should have received a copy of the GNU General Public License
-// along with this program; if not, write to the Free Software
-// Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
-
-#ifdef HAVE_CONFIG_H
-#  include <config.h>
-#endif
-
-#include "CameraGroup.hxx"
-
-#include "fg_props.hxx"
-#include "globals.hxx"
-#include "renderer.hxx"
-#include "FGEventHandler.hxx"
-#include "WindowBuilder.hxx"
-#include "WindowSystemAdapter.hxx"
-#include <simgear/props/props.hxx>
-#include <simgear/structure/OSGUtils.hxx>
-#include <simgear/structure/OSGVersion.hxx>
-#include <simgear/scene/material/EffectCullVisitor.hxx>
-#include <simgear/scene/util/RenderConstants.hxx>
-#include <simgear/scene/tgdb/userdata.hxx>
-
-#include <algorithm>
-#include <cstring>
-#include <string>
-
-#include <osg/Camera>
-#include <osg/Geometry>
-#include <osg/GraphicsContext>
-#include <osg/io_utils>
-#include <osg/Math>
-#include <osg/Matrix>
-#include <osg/Notify>
-#include <osg/Program>
-#include <osg/Quat>
-#include <osg/TexMat>
-#include <osg/Vec3d>
-#include <osg/Viewport>
-
-#include <osgUtil/IntersectionVisitor>
-
-#include <osgViewer/GraphicsWindow>
-#include <osgViewer/Renderer>
-
-static osg::Matrix
-invert(const osg::Matrix& matrix)
-{
-    return osg::Matrix::inverse(matrix);
-}
-
-/// Returns the zoom factor of the master camera.
-/// The reference fov is the historic 55 deg
-static double
-zoomFactor()
-{
-    double fov = fgGetDouble("/sim/current-view/field-of-view", 55);
-    if (fov < 1)
-        fov = 1;
-    return tan(55*0.5*SG_DEGREES_TO_RADIANS)/tan(fov*0.5*SG_DEGREES_TO_RADIANS);
-}
-
-static osg::Vec2d
-preMult(const osg::Vec2d& v, const osg::Matrix& m)
-{
-  osg::Vec3d tmp = m.preMult(osg::Vec3(v, 0));
-  return osg::Vec2d(tmp[0], tmp[1]);
-}
-
-static osg::Matrix
-relativeProjection(const osg::Matrix& P0, const osg::Matrix& R, const osg::Vec2d ref[2],
-                   const osg::Matrix& pP, const osg::Matrix& pR, const osg::Vec2d pRef[2])
-{
-  // Track the way from one projection space to the other:
-  // We want
-  //  P = T*S*P0
-  // where P0 is the projection template sensible for the given window size,
-  // T is a translation matrix and S a scale matrix.
-  // We need to determine T and S so that the reference points in the parents
-  // projection space match the two reference points in this cameras projection space.
-
-  // Starting from the parents camera projection space, we get into this cameras
-  // projection space by the transform matrix:
-  //  P*R*inv(pP*pR) = T*S*P0*R*inv(pP*pR)
-  // So, at first compute that matrix without T*S and determine S and T from that
-
-  // Ok, now osg uses the inverse matrix multiplication order, thus:
-  osg::Matrix PtoPwithoutTS = invert(pR*pP)*R*P0;
-  // Compute the parents reference points in the current projection space
-  // without the yet unknown T and S
-  osg::Vec2d pRefInThis[2] = {
-    preMult(pRef[0], PtoPwithoutTS),
-    preMult(pRef[1], PtoPwithoutTS)
-  };
-
-  // To get the same zoom, rescale to match the parents size
-  double s = (ref[0] - ref[1]).length()/(pRefInThis[0] - pRefInThis[1]).length();
-  osg::Matrix S = osg::Matrix::scale(s, s, 1);
-
-  // For the translation offset, incorporate the now known scale
-  // and recompute the position ot the first reference point in the
-  // currents projection space without the yet unknown T.
-  pRefInThis[0] = preMult(pRef[0], PtoPwithoutTS*S);
-  // The translation is then the difference of the reference points
-  osg::Matrix T = osg::Matrix::translate(osg::Vec3d(ref[0] - pRefInThis[0], 0));
-
-  // Compose and return the desired final projection matrix
-  return P0*S*T;
-}
-
-namespace flightgear
-{
-using namespace osg;
-
-using std::strcmp;
-using std::string;
-
-ref_ptr<CameraGroup> CameraGroup::_defaultGroup;
-
-CameraGroup::CameraGroup(osgViewer::Viewer* viewer) :
-    _viewer(viewer)
-{
-}
-
-}
-
-namespace
-{
-using namespace osg;
-
-// Given a projection matrix, return a new one with the same frustum
-// sides and new near / far values.
-
-void makeNewProjMat(Matrixd& oldProj, double znear,
-                                       double zfar, Matrixd& projection)
-{
-    projection = oldProj;
-    // Slightly inflate the near & far planes to avoid objects at the
-    // extremes being clipped out.
-    znear *= 0.999;
-    zfar *= 1.001;
-
-    // Clamp the projection matrix z values to the range (near, far)
-    double epsilon = 1.0e-6;
-    if (fabs(projection(0,3)) < epsilon &&
-        fabs(projection(1,3)) < epsilon &&
-        fabs(projection(2,3)) < epsilon) {
-        // Projection is Orthographic
-        epsilon = -1.0/(zfar - znear); // Used as a temp variable
-        projection(2,2) = 2.0*epsilon;
-        projection(3,2) = (zfar + znear)*epsilon;
-    } else {
-        // Projection is Perspective
-        double trans_near = (-znear*projection(2,2) + projection(3,2)) /
-            (-znear*projection(2,3) + projection(3,3));
-        double trans_far = (-zfar*projection(2,2) + projection(3,2)) /
-            (-zfar*projection(2,3) + projection(3,3));
-        double ratio = fabs(2.0/(trans_near - trans_far));
-        double center = -0.5*(trans_near + trans_far);
-
-        projection.postMult(osg::Matrixd(1.0, 0.0, 0.0, 0.0,
-                                         0.0, 1.0, 0.0, 0.0,
-                                         0.0, 0.0, ratio, 0.0,
-                                         0.0, 0.0, center*ratio, 1.0));
-    }
-}
-}
-
-namespace flightgear
-{
-void CameraInfo::updateCameras()
-{
-    bufferSize->set( osg::Vec2f( width, height ) );
-
-    for (CameraMap::iterator ii = cameras.begin(); ii != cameras.end(); ++ii ) {
-        float f = ii->second.scaleFactor;
-        if ( f == 0.0f ) continue;
-        ii->second.camera->getViewport()->setViewport(x*f, y*f, width*f, height*f);
-    }
-
-    for (RenderBufferMap::iterator ii = buffers.begin(); ii != buffers.end(); ++ii ) {
-        float f = ii->second.scaleFactor;
-        if ( f == 0.0f ) continue;
-        osg::Texture2D* texture = ii->second.texture.get();
-        if ( texture->getTextureHeight() != height*f || texture->getTextureWidth() != width*f ) {
-            texture->setTextureSize( width*f, height*f );
-            texture->dirtyTextureObject();
-        }
-    }
-}
-
-void CameraInfo::resized(double w, double h)
-{
-    bufferSize->set( osg::Vec2f( w, h ) );
-
-    for (RenderBufferMap::iterator ii = buffers.begin(); ii != buffers.end(); ++ii) {
-        float s = ii->second.scaleFactor;
-        if ( s == 0.0f ) continue;
-        ii->second.texture->setTextureSize( w * s, h * s );
-        ii->second.texture->dirtyTextureObject();
-    }
-
-    for (CameraMap::iterator ii = cameras.begin(); ii != cameras.end(); ++ii) {
-        RenderStageInfo& rsi = ii->second;
-        if (!rsi.resizable ||
-                rsi.camera->getRenderTargetImplementation() != osg::Camera::FRAME_BUFFER_OBJECT ||
-                rsi.scaleFactor == 0.0f )
-            continue;
-
-        Viewport* vp = rsi.camera->getViewport();
-        vp->width() = w * rsi.scaleFactor;
-        vp->height() = h * rsi.scaleFactor;
-
-        osgViewer::Renderer* renderer
-            = static_cast<osgViewer::Renderer*>(rsi.camera->getRenderer());
-        for (int i = 0; i < 2; ++i) {
-            osgUtil::SceneView* sceneView = renderer->getSceneView(i);
-            sceneView->getRenderStage()->setFrameBufferObject(0);
-            sceneView->getRenderStage()->setCameraRequiresSetUp(true);
-            if (sceneView->getRenderStageLeft()) {
-                sceneView->getRenderStageLeft()->setFrameBufferObject(0);
-                sceneView->getRenderStageLeft()->setCameraRequiresSetUp(true);
-            }
-            if (sceneView->getRenderStageRight()) {
-                sceneView->getRenderStageRight()->setFrameBufferObject(0);
-                sceneView->getRenderStageRight()->setCameraRequiresSetUp(true);
-            }
-        }
-    }
-}
-
-osg::Camera* CameraInfo::getCamera(CameraKind k) const
-{
-    CameraMap::const_iterator ii = cameras.find( k );
-    if (ii == cameras.end())
-        return 0;
-    return ii->second.camera.get();
-}
-
-osg::Texture2D* CameraInfo::getBuffer(RenderBufferInfo::Kind k) const
-{
-    RenderBufferMap::const_iterator ii = buffers.find(k);
-    if (ii == buffers.end())
-        return 0;
-    return ii->second.texture.get();
-}
-
-int CameraInfo::getMainSlaveIndex() const
-{
-    return cameras.find( MAIN_CAMERA )->second.slaveIndex;
-}
-
-void CameraInfo::setMatrices(osg::Camera* c)
-{
-    view->set( c->getViewMatrix() );
-    viewInverse->set( osg::Matrix::inverse( c->getViewMatrix() ) );
-    projInverse->set( osg::Matrix::inverse( c->getProjectionMatrix() ) );
-}
-
-void CameraGroup::update(const osg::Vec3d& position,
-                         const osg::Quat& orientation)
-{
-    const Matrix masterView(osg::Matrix::translate(-position)
-                            * osg::Matrix::rotate(orientation.inverse()));
-    _viewer->getCamera()->setViewMatrix(masterView);
-    const Matrix& masterProj = _viewer->getCamera()->getProjectionMatrix();
-    double masterZoomFactor = zoomFactor();
-    for (CameraList::iterator i = _cameras.begin(); i != _cameras.end(); ++i) {
-        const CameraInfo* info = i->get();
-
-        Camera* camera = info->getCamera(MAIN_CAMERA);
-        if ( camera ) {
-            const View::Slave& slave = _viewer->getSlave(info->getMainSlaveIndex());
-#if SG_OSG_VERSION_LESS_THAN(3,0,0)
-            // refreshes camera viewports (for now)
-            info->updateCameras();
-#endif
-            Matrix viewMatrix;
-            if (info->flags & GUI) {
-                viewMatrix = osg::Matrix(); // identifty transform on the GUI camera
-            } else if ((info->flags & VIEW_ABSOLUTE) != 0)
-                viewMatrix = slave._viewOffset;
-            else
-                viewMatrix = masterView * slave._viewOffset;
-            camera->setViewMatrix(viewMatrix);
-            Matrix projectionMatrix;
-            if (info->flags & GUI) {
-                projectionMatrix = osg::Matrix::ortho2D(0, info->width, 0, info->height);
-            } else if ((info->flags & PROJECTION_ABSOLUTE) != 0) {
-                if (info->flags & ENABLE_MASTER_ZOOM) {
-                    if (info->relativeCameraParent < _cameras.size()) {
-                        // template projection matrix and view matrix of the current camera
-                        osg::Matrix P0 = slave._projectionOffset;
-                        osg::Matrix R = viewMatrix;
-
-                        // The already known projection and view matrix of the parent camera
-                        const CameraInfo* parentInfo = _cameras[info->relativeCameraParent].get();
-                        RenderStageInfo prsi = parentInfo->cameras.find(MAIN_CAMERA)->second;
-                        osg::Matrix pP = prsi.camera->getProjectionMatrix();
-                        osg::Matrix pR = prsi.camera->getViewMatrix();
-                    
-                        // And the projection matrix derived from P0 so that the reference points match
-                        projectionMatrix = relativeProjection(P0, R, info->thisReference,
-                                                              pP, pR, info->parentReference);
-                    
-                    } else {
-                        // We want to zoom, so take the original matrix and apply the zoom to it.
-                        projectionMatrix = slave._projectionOffset;
-                        projectionMatrix.postMultScale(osg::Vec3d(masterZoomFactor, masterZoomFactor, 1));
-                    }
-                } else {
-                    projectionMatrix = slave._projectionOffset;
-                }
-            } else {
-                projectionMatrix = masterProj * slave._projectionOffset;
-            }
-
-            CameraMap::const_iterator ii = info->cameras.find(FAR_CAMERA);
-            if (ii == info->cameras.end() || !ii->second.camera.valid()) {
-                camera->setProjectionMatrix(projectionMatrix);
-            } else {
-                Camera* farCamera = ii->second.camera;
-                farCamera->setViewMatrix(viewMatrix);
-                double left, right, bottom, top, parentNear, parentFar;
-                projectionMatrix.getFrustum(left, right, bottom, top,
-                                            parentNear, parentFar);
-                if ((info->flags & FIXED_NEAR_FAR) == 0) {
-                    parentNear = _zNear;
-                    parentFar = _zFar;
-                }
-                if (parentFar < _nearField || _nearField == 0.0f) {
-                    camera->setProjectionMatrix(projectionMatrix);
-                    camera->setCullMask(camera->getCullMask()
-                                        | simgear::BACKGROUND_BIT);
-                    camera->setClearMask(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT | GL_STENCIL_BUFFER_BIT);
-                    farCamera->setNodeMask(0);
-                } else {
-                    Matrix nearProj, farProj;
-                    makeNewProjMat(projectionMatrix, parentNear, _nearField,
-                                   nearProj);
-                    makeNewProjMat(projectionMatrix, _nearField, parentFar,
-                                   farProj);
-                    camera->setProjectionMatrix(nearProj);
-                    camera->setCullMask(camera->getCullMask()
-                                        & ~simgear::BACKGROUND_BIT);
-                    camera->setClearMask(GL_DEPTH_BUFFER_BIT);
-                    farCamera->setProjectionMatrix(farProj);
-                    farCamera->setNodeMask(camera->getNodeMask());
-                }
-            }
-        } else {
-            bool viewDone = false;
-            Matrix viewMatrix;
-            bool projectionDone = false;
-            Matrix projectionMatrix;
-            for ( CameraMap::const_iterator ii = info->cameras.begin(); ii != info->cameras.end(); ++ii ) {
-                if ( ii->first == SHADOW_CAMERA ) {
-                    globals->get_renderer()->updateShadowCamera(info, position);
-                    continue;
-                }
-                if ( ii->second.fullscreen )
-                    continue;
-
-                Camera* camera = ii->second.camera.get();
-                int slaveIndex = ii->second.slaveIndex;
-                const View::Slave& slave = _viewer->getSlave(slaveIndex);
-
-                if ( !viewDone ) {
-                    if ((info->flags & VIEW_ABSOLUTE) != 0)
-                        viewMatrix = slave._viewOffset;
-                    else
-                        viewMatrix = masterView * slave._viewOffset;
-                    viewDone = true;
-                }
-
-                camera->setViewMatrix( viewMatrix );
-
-                if ( !projectionDone ) {
-                    if ((info->flags & PROJECTION_ABSOLUTE) != 0) {
-                        if (info->flags & ENABLE_MASTER_ZOOM) {
-                            if (info->relativeCameraParent < _cameras.size()) {
-                                // template projection matrix and view matrix of the current camera
-                                osg::Matrix P0 = slave._projectionOffset;
-                                osg::Matrix R = viewMatrix;
-
-                                // The already known projection and view matrix of the parent camera
-                                const CameraInfo* parentInfo = _cameras[info->relativeCameraParent].get();
-                                RenderStageInfo prsi = parentInfo->cameras.find(MAIN_CAMERA)->second;
-                                osg::Matrix pP = prsi.camera->getProjectionMatrix();
-                                osg::Matrix pR = prsi.camera->getViewMatrix();
-                    
-                                // And the projection matrix derived from P0 so that the reference points match
-                                projectionMatrix = relativeProjection(P0, R, info->thisReference,
-                                                                      pP, pR, info->parentReference);
-                    
-                            } else {
-                                // We want to zoom, so take the original matrix and apply the zoom to it.
-                                projectionMatrix = slave._projectionOffset;
-                                projectionMatrix.postMultScale(osg::Vec3d(masterZoomFactor, masterZoomFactor, 1));
-                            }
-                        } else {
-                            projectionMatrix = slave._projectionOffset;
-                        }
-                    } else {
-                        projectionMatrix = masterProj * slave._projectionOffset;
-                    }
-                    projectionDone = true;
-                }
-
-                camera->setProjectionMatrix(projectionMatrix);
-            }
-        }
-    }
-
-    globals->get_renderer()->setPlanes( _zNear, _zFar );
-}
-
-void CameraGroup::setCameraParameters(float vfov, float aspectRatio)
-{
-    if (vfov != 0.0f && aspectRatio != 0.0f)
-        _viewer->getCamera()
-            ->setProjectionMatrixAsPerspective(vfov,
-                                               1.0f / aspectRatio,
-                                               _zNear, _zFar);
-}
-    
-double CameraGroup::getMasterAspectRatio() const
-{
-    if (_cameras.empty())
-        return 0.0;
-    
-    const CameraInfo* info = _cameras.front();
-    
-    osg::Camera* camera = info->getCamera(MAIN_CAMERA);
-    if ( !camera )
-        camera = info->getCamera( GEOMETRY_CAMERA );
-    const osg::Viewport* viewport = camera->getViewport();
-    if (!viewport) {
-        return 0.0;
-    }
-    
-    return static_cast<double>(viewport->height()) / viewport->width();
-}
-    
-}
-
-namespace
-{
-// A raw value for property nodes that references a class member via
-// an osg::ref_ptr.
-template<class C, class T>
-class RefMember : public SGRawValue<T>
-{
-public:
-    RefMember (C *obj, T C::*ptr)
-        : _obj(obj), _ptr(ptr) {}
-    virtual ~RefMember () {}
-    virtual T getValue () const
-    {
-        return _obj.get()->*_ptr;
-    }
-    virtual bool setValue (T value)
-    {
-        _obj.get()->*_ptr = value;
-        return true;
-    }
-    virtual SGRawValue<T> * clone () const
-    {
-        return new RefMember(_obj.get(), _ptr);
-    }
-private:
-    ref_ptr<C> _obj;
-    T C::* const _ptr;
-};
-
-template<typename C, typename T>
-RefMember<C, T> makeRefMember(C *obj, T C::*ptr)
-{
-    return RefMember<C, T>(obj, ptr);
-}
-
-template<typename C, typename T>
-void bindMemberToNode(SGPropertyNode* parent, const char* childName,
-                      C* obj, T C::*ptr, T value)
-{
-    SGPropertyNode* valNode = parent->getNode(childName);
-    RefMember<C, T> refMember = makeRefMember(obj, ptr);
-    if (!valNode) {
-        valNode = parent->getNode(childName, true);
-        valNode->tie(refMember, false);
-        setValue(valNode, value);
-    } else {
-        valNode->tie(refMember, true);
-    }
-}
-
-void buildViewport(flightgear::CameraInfo* info, SGPropertyNode* viewportNode,
-                   const osg::GraphicsContext::Traits *traits)
-{
-    using namespace flightgear;
-    bindMemberToNode(viewportNode, "x", info, &CameraInfo::x, 0.0);
-    bindMemberToNode(viewportNode, "y", info, &CameraInfo::y, 0.0);
-    bindMemberToNode(viewportNode, "width", info, &CameraInfo::width,
-                     static_cast<double>(traits->width));
-    bindMemberToNode(viewportNode, "height", info, &CameraInfo::height,
-                     static_cast<double>(traits->height));
-}
-}
-
-namespace flightgear
-{
-
-// Mostly copied from osg's osgViewer/View.cpp
-
-static osg::Geometry* createPanoramicSphericalDisplayDistortionMesh(
-    const Vec3& origin, const Vec3& widthVector, const Vec3& heightVector,
-    double sphere_radius, double collar_radius,
-    Image* intensityMap = 0, const Matrix& projectorMatrix = Matrix())
-{
-    osg::Vec3d center(0.0,0.0,0.0);
-    osg::Vec3d eye(0.0,0.0,0.0);
-
-    double distance = sqrt(sphere_radius*sphere_radius - collar_radius*collar_radius);
-    bool flip = false;
-    bool texcoord_flip = false;
-
-#if 0
-    osg::Vec3d projector = eye - osg::Vec3d(0.0,0.0, distance);
-
-    OSG_INFO<<"createPanoramicSphericalDisplayDistortionMesh : Projector position = "<<projector<<std::endl;
-    OSG_INFO<<"createPanoramicSphericalDisplayDistortionMesh : distance = "<<distance<<std::endl;
-#endif
-    // create the quad to visualize.
-    osg::Geometry* geometry = new osg::Geometry();
-
-    geometry->setSupportsDisplayList(false);
-
-    osg::Vec3 xAxis(widthVector);
-    float width = widthVector.length();
-    xAxis /= width;
-
-    osg::Vec3 yAxis(heightVector);
-    float height = heightVector.length();
-    yAxis /= height;
-
-    int noSteps = 160;
-
-    osg::Vec3Array* vertices = new osg::Vec3Array;
-    osg::Vec2Array* texcoords0 = new osg::Vec2Array;
-    osg::Vec2Array* texcoords1 = intensityMap==0 ? new osg::Vec2Array : 0;
-    osg::Vec4Array* colors = new osg::Vec4Array;
-
-#if 0
-    osg::Vec3 bottom = origin;
-    osg::Vec3 dx = xAxis*(width/((float)(noSteps-2)));
-    osg::Vec3 dy = yAxis*(height/((float)(noSteps-1)));
-#endif
-    osg::Vec3 top = origin + yAxis*height;
-
-    osg::Vec3 screenCenter = origin + widthVector*0.5f + heightVector*0.5f;
-    float screenRadius = heightVector.length() * 0.5f;
-
-    geometry->getOrCreateStateSet()->setMode(GL_CULL_FACE, osg::StateAttribute::OFF | osg::StateAttribute::PROTECTED);
-
-    for(int i=0;i<noSteps;++i)
-    {
-        //osg::Vec3 cursor = bottom+dy*(float)i;
-        for(int j=0;j<noSteps;++j)
-        {
-            osg::Vec2 texcoord(double(i)/double(noSteps-1), double(j)/double(noSteps-1));
-            double theta = texcoord.x() * 2.0 * osg::PI;
-            double phi = (1.0-texcoord.y()) * osg::PI;
-
-            if (texcoord_flip) texcoord.y() = 1.0f - texcoord.y();
-
-            osg::Vec3 pos(sin(phi)*sin(theta), sin(phi)*cos(theta), cos(phi));
-            pos = pos*projectorMatrix;
-
-            double alpha = atan2(pos.x(), pos.y());
-            if (alpha<0.0) alpha += 2.0*osg::PI;
-
-            double beta = atan2(sqrt(pos.x()*pos.x() + pos.y()*pos.y()), pos.z());
-            if (beta<0.0) beta += 2.0*osg::PI;
-
-            double gamma = atan2(sqrt(double(pos.x()*pos.x() + pos.y()*pos.y())), double(pos.z()+distance));
-            if (gamma<0.0) gamma += 2.0*osg::PI;
-
-
-            osg::Vec3 v = screenCenter + osg::Vec3(sin(alpha)*gamma*2.0/osg::PI, -cos(alpha)*gamma*2.0/osg::PI, 0.0f)*screenRadius;
-
-            if (flip)
-                vertices->push_back(osg::Vec3(v.x(), top.y()-(v.y()-origin.y()),v.z()));
-            else
-                vertices->push_back(v);
-
-            texcoords0->push_back( texcoord );
-
-            osg::Vec2 texcoord1(alpha/(2.0*osg::PI), 1.0f - beta/osg::PI);
-            if (intensityMap)
-            {
-                colors->push_back(intensityMap->getColor(texcoord1));
-            }
-            else
-            {
-                colors->push_back(osg::Vec4(1.0f,1.0f,1.0f,1.0f));
-                if (texcoords1) texcoords1->push_back( texcoord1 );
-            }
-
-
-        }
-    }
-
-
-    // pass the created vertex array to the points geometry object.
-    geometry->setVertexArray(vertices);
-
-    geometry->setColorArray(colors);
-    geometry->setColorBinding(osg::Geometry::BIND_PER_VERTEX);
-
-    geometry->setTexCoordArray(0,texcoords0);
-    if (texcoords1) geometry->setTexCoordArray(1,texcoords1);
-
-    osg::DrawElementsUShort* elements = new osg::DrawElementsUShort(osg::PrimitiveSet::TRIANGLES);
-    geometry->addPrimitiveSet(elements);
-
-    for(int i=0;i<noSteps-1;++i)
-    {
-        for(int j=0;j<noSteps-1;++j)
-        {
-            int i1 = j+(i+1)*noSteps;
-            int i2 = j+(i)*noSteps;
-            int i3 = j+1+(i)*noSteps;
-            int i4 = j+1+(i+1)*noSteps;
-
-            osg::Vec3& v1 = (*vertices)[i1];
-            osg::Vec3& v2 = (*vertices)[i2];
-            osg::Vec3& v3 = (*vertices)[i3];
-            osg::Vec3& v4 = (*vertices)[i4];
-
-            if ((v1-screenCenter).length()>screenRadius) continue;
-            if ((v2-screenCenter).length()>screenRadius) continue;
-            if ((v3-screenCenter).length()>screenRadius) continue;
-            if ((v4-screenCenter).length()>screenRadius) continue;
-
-            elements->push_back(i1);
-            elements->push_back(i2);
-            elements->push_back(i3);
-
-            elements->push_back(i1);
-            elements->push_back(i3);
-            elements->push_back(i4);
-        }
-    }
-
-    return geometry;
-}
-
-void CameraGroup::buildDistortionCamera(const SGPropertyNode* psNode,
-                                        Camera* camera)
-{
-    const SGPropertyNode* texNode = psNode->getNode("texture");
-    if (!texNode) {
-        // error
-        return;
-    }
-    string texName = texNode->getStringValue();
-    TextureMap::iterator itr = _textureTargets.find(texName);
-    if (itr == _textureTargets.end()) {
-        // error
-        return;
-    }
-    Viewport* viewport = camera->getViewport();
-    float width = viewport->width();
-    float height = viewport->height();
-    TextureRectangle* texRect = itr->second.get();
-    double radius = psNode->getDoubleValue("radius", 1.0);
-    double collar = psNode->getDoubleValue("collar", 0.45);
-    Geode* geode = new Geode();
-    geode->addDrawable(createPanoramicSphericalDisplayDistortionMesh(
-                           Vec3(0.0f,0.0f,0.0f), Vec3(width,0.0f,0.0f),
-                           Vec3(0.0f,height,0.0f), radius, collar));
-
-    // new we need to add the texture to the mesh, we do so by creating a
-    // StateSet to contain the Texture StateAttribute.
-    StateSet* stateset = geode->getOrCreateStateSet();
-    stateset->setTextureAttributeAndModes(0, texRect, StateAttribute::ON);
-    stateset->setMode(GL_LIGHTING, StateAttribute::OFF);
-
-    TexMat* texmat = new TexMat;
-    texmat->setScaleByTextureRectangleSize(true);
-    stateset->setTextureAttributeAndModes(0, texmat, osg::StateAttribute::ON);
-#if 0
-    if (!applyIntensityMapAsColours && intensityMap)
-    {
-        stateset->setTextureAttributeAndModes(1, new osg::Texture2D(intensityMap), osg::StateAttribute::ON);
-    }
-#endif
-    // add subgraph to render
-    camera->addChild(geode);
-    camera->setClearMask(GL_DEPTH_BUFFER_BIT | GL_COLOR_BUFFER_BIT);
-    camera->setClearColor(osg::Vec4(0.0, 0.0, 0.0, 1.0));
-    camera->setComputeNearFarMode(osg::CullSettings::DO_NOT_COMPUTE_NEAR_FAR);
-    camera->setCullingMode(osg::CullSettings::NO_CULLING);
-    camera->setName("DistortionCorrectionCamera");
-}
-
-CameraInfo* CameraGroup::buildCamera(SGPropertyNode* cameraNode)
-{
-    WindowBuilder *wBuild = WindowBuilder::getWindowBuilder();
-    const SGPropertyNode* windowNode = cameraNode->getNode("window");
-    GraphicsWindow* window = 0;
-    int cameraFlags = DO_INTERSECTION_TEST;
-    if (windowNode) {
-        // New style window declaration / definition
-        window = wBuild->buildWindow(windowNode);
-    } else {
-        // Old style: suck window params out of camera block
-        window = wBuild->buildWindow(cameraNode);
-    }
-    if (!window) {
-        return 0;
-    }
-    Camera* camera = new Camera;
-    camera->setAllowEventFocus(false);
-    camera->setGraphicsContext(window->gc.get());
-    camera->setViewport(new Viewport);
-    camera->setCullingMode(CullSettings::SMALL_FEATURE_CULLING
-                           | CullSettings::VIEW_FRUSTUM_CULLING);
-    camera->setInheritanceMask(CullSettings::ALL_VARIABLES
-                               & ~(CullSettings::CULL_MASK
-                                   | CullSettings::CULLING_MODE
-#if defined(HAVE_CULLSETTINGS_CLEAR_MASK)
-                                   | CullSettings::CLEAR_MASK
-#endif
-                                   ));
-
-    osg::Matrix vOff;
-    const SGPropertyNode* viewNode = cameraNode->getNode("view");
-    if (viewNode) {
-        double heading = viewNode->getDoubleValue("heading-deg", 0.0);
-        double pitch = viewNode->getDoubleValue("pitch-deg", 0.0);
-        double roll = viewNode->getDoubleValue("roll-deg", 0.0);
-        double x = viewNode->getDoubleValue("x", 0.0);
-        double y = viewNode->getDoubleValue("y", 0.0);
-        double z = viewNode->getDoubleValue("z", 0.0);
-        // Build a view matrix, which is the inverse of a model
-        // orientation matrix.
-        vOff = (Matrix::translate(-x, -y, -z)
-                * Matrix::rotate(-DegreesToRadians(heading),
-                                 Vec3d(0.0, 1.0, 0.0),
-                                 -DegreesToRadians(pitch),
-                                 Vec3d(1.0, 0.0, 0.0),
-                                 -DegreesToRadians(roll),
-                                 Vec3d(0.0, 0.0, 1.0)));
-        if (viewNode->getBoolValue("absolute", false))
-            cameraFlags |= VIEW_ABSOLUTE;
-    } else {
-        // Old heading parameter, works in the opposite direction
-        double heading = cameraNode->getDoubleValue("heading-deg", 0.0);
-        vOff.makeRotate(DegreesToRadians(heading), osg::Vec3(0, 1, 0));
-    }
-    // Configuring the physical dimensions of a monitor
-    SGPropertyNode* viewportNode = cameraNode->getNode("viewport", true);
-    double physicalWidth = viewportNode->getDoubleValue("width", 1024);
-    double physicalHeight = viewportNode->getDoubleValue("height", 768);
-    double bezelHeightTop = 0;
-    double bezelHeightBottom = 0;
-    double bezelWidthLeft = 0;
-    double bezelWidthRight = 0;
-    const SGPropertyNode* physicalDimensionsNode = 0;
-    if ((physicalDimensionsNode = cameraNode->getNode("physical-dimensions")) != 0) {
-        physicalWidth = physicalDimensionsNode->getDoubleValue("width", physicalWidth);
-        physicalHeight = physicalDimensionsNode->getDoubleValue("height", physicalHeight);
-        const SGPropertyNode* bezelNode = 0;
-        if ((bezelNode = physicalDimensionsNode->getNode("bezel")) != 0) {
-            bezelHeightTop = bezelNode->getDoubleValue("top", bezelHeightTop);
-            bezelHeightBottom = bezelNode->getDoubleValue("bottom", bezelHeightBottom);
-            bezelWidthLeft = bezelNode->getDoubleValue("left", bezelWidthLeft);
-            bezelWidthRight = bezelNode->getDoubleValue("right", bezelWidthRight);
-        }
-    }
-    osg::Matrix pOff;
-    unsigned parentCameraIndex = ~0u;
-    osg::Vec2d parentReference[2];
-    osg::Vec2d thisReference[2];
-    SGPropertyNode* projectionNode = 0;
-    if ((projectionNode = cameraNode->getNode("perspective")) != 0) {
-        double fovy = projectionNode->getDoubleValue("fovy-deg", 55.0);
-        double aspectRatio = projectionNode->getDoubleValue("aspect-ratio",
-                                                            1.0);
-        double zNear = projectionNode->getDoubleValue("near", 0.0);
-        double zFar = projectionNode->getDoubleValue("far", zNear + 20000);
-        double offsetX = projectionNode->getDoubleValue("offset-x", 0.0);
-        double offsetY = projectionNode->getDoubleValue("offset-y", 0.0);
-        double tan_fovy = tan(DegreesToRadians(fovy*0.5));
-        double right = tan_fovy * aspectRatio * zNear + offsetX;
-        double left = -tan_fovy * aspectRatio * zNear + offsetX;
-        double top = tan_fovy * zNear + offsetY;
-        double bottom = -tan_fovy * zNear + offsetY;
-        pOff.makeFrustum(left, right, bottom, top, zNear, zFar);
-        cameraFlags |= PROJECTION_ABSOLUTE;
-        if (projectionNode->getBoolValue("fixed-near-far", true))
-            cameraFlags |= FIXED_NEAR_FAR;
-    } else if ((projectionNode = cameraNode->getNode("frustum")) != 0
-               || (projectionNode = cameraNode->getNode("ortho")) != 0) {
-        double top = projectionNode->getDoubleValue("top", 0.0);
-        double bottom = projectionNode->getDoubleValue("bottom", 0.0);
-        double left = projectionNode->getDoubleValue("left", 0.0);
-        double right = projectionNode->getDoubleValue("right", 0.0);
-        double zNear = projectionNode->getDoubleValue("near", 0.0);
-        double zFar = projectionNode->getDoubleValue("far", zNear + 20000);
-        if (cameraNode->getNode("frustum")) {
-            pOff.makeFrustum(left, right, bottom, top, zNear, zFar);
-            cameraFlags |= PROJECTION_ABSOLUTE;
-        } else {
-            pOff.makeOrtho(left, right, bottom, top, zNear, zFar);
-            cameraFlags |= (PROJECTION_ABSOLUTE | ORTHO);
-        }
-        if (projectionNode->getBoolValue("fixed-near-far", true))
-            cameraFlags |= FIXED_NEAR_FAR;
-    } else if ((projectionNode = cameraNode->getNode("master-perspective")) != 0) {
-        double zNear = projectionNode->getDoubleValue("eye-distance", 0.4*physicalWidth);
-        double xoff = projectionNode->getDoubleValue("x-offset", 0);
-        double yoff = projectionNode->getDoubleValue("y-offset", 0);
-        double left = -0.5*physicalWidth - xoff;
-        double right = 0.5*physicalWidth - xoff;
-        double bottom = -0.5*physicalHeight - yoff;
-        double top = 0.5*physicalHeight - yoff;
-        pOff.makeFrustum(left, right, bottom, top, zNear, zNear*1000);
-        cameraFlags |= PROJECTION_ABSOLUTE | ENABLE_MASTER_ZOOM;
-    } else if ((projectionNode = cameraNode->getNode("right-of-perspective"))
-               || (projectionNode = cameraNode->getNode("left-of-perspective"))
-               || (projectionNode = cameraNode->getNode("above-perspective"))
-               || (projectionNode = cameraNode->getNode("below-perspective"))
-               || (projectionNode = cameraNode->getNode("reference-points-perspective"))) {
-        std::string name = projectionNode->getStringValue("parent-camera");
-        for (unsigned i = 0; i < _cameras.size(); ++i) {
-            if (_cameras[i]->name != name)
-                continue;
-            parentCameraIndex = i;
-        }
-        if (_cameras.size() <= parentCameraIndex) {
-            SG_LOG(SG_VIEW, SG_ALERT, "CameraGroup::buildCamera: "
-                   "failed to find parent camera for relative camera!");
-            return 0;
-        }
-        const CameraInfo* parentInfo = _cameras[parentCameraIndex].get();
-        if (projectionNode->getNameString() == "right-of-perspective") {
-            double tmp = (parentInfo->physicalWidth + 2*parentInfo->bezelWidthRight)/parentInfo->physicalWidth;
-            parentReference[0] = osg::Vec2d(tmp, -1);
-            parentReference[1] = osg::Vec2d(tmp, 1);
-            tmp = (physicalWidth + 2*bezelWidthLeft)/physicalWidth;
-            thisReference[0] = osg::Vec2d(-tmp, -1);
-            thisReference[1] = osg::Vec2d(-tmp, 1);
-        } else if (projectionNode->getNameString() == "left-of-perspective") {
-            double tmp = (parentInfo->physicalWidth + 2*parentInfo->bezelWidthLeft)/parentInfo->physicalWidth;
-            parentReference[0] = osg::Vec2d(-tmp, -1);
-            parentReference[1] = osg::Vec2d(-tmp, 1);
-            tmp = (physicalWidth + 2*bezelWidthRight)/physicalWidth;
-            thisReference[0] = osg::Vec2d(tmp, -1);
-            thisReference[1] = osg::Vec2d(tmp, 1);
-        } else if (projectionNode->getNameString() == "above-perspective") {
-            double tmp = (parentInfo->physicalHeight + 2*parentInfo->bezelHeightTop)/parentInfo->physicalHeight;
-            parentReference[0] = osg::Vec2d(-1, tmp);
-            parentReference[1] = osg::Vec2d(1, tmp);
-            tmp = (physicalHeight + 2*bezelHeightBottom)/physicalHeight;
-            thisReference[0] = osg::Vec2d(-1, -tmp);
-            thisReference[1] = osg::Vec2d(1, -tmp);
-        } else if (projectionNode->getNameString() == "below-perspective") {
-            double tmp = (parentInfo->physicalHeight + 2*parentInfo->bezelHeightBottom)/parentInfo->physicalHeight;
-            parentReference[0] = osg::Vec2d(-1, -tmp);
-            parentReference[1] = osg::Vec2d(1, -tmp);
-            tmp = (physicalHeight + 2*bezelHeightTop)/physicalHeight;
-            thisReference[0] = osg::Vec2d(-1, tmp);
-            thisReference[1] = osg::Vec2d(1, tmp);
-        } else if (projectionNode->getNameString() == "reference-points-perspective") {
-            SGPropertyNode* parentNode = projectionNode->getNode("parent", true);
-            SGPropertyNode* thisNode = projectionNode->getNode("this", true);
-            SGPropertyNode* pointNode;
-
-            pointNode = parentNode->getNode("point", 0, true);
-            parentReference[0][0] = pointNode->getDoubleValue("x", 0)*2/parentInfo->physicalWidth;
-            parentReference[0][1] = pointNode->getDoubleValue("y", 0)*2/parentInfo->physicalHeight;
-            pointNode = parentNode->getNode("point", 1, true);
-            parentReference[1][0] = pointNode->getDoubleValue("x", 0)*2/parentInfo->physicalWidth;
-            parentReference[1][1] = pointNode->getDoubleValue("y", 0)*2/parentInfo->physicalHeight;
-
-            pointNode = thisNode->getNode("point", 0, true);
-            thisReference[0][0] = pointNode->getDoubleValue("x", 0)*2/physicalWidth;
-            thisReference[0][1] = pointNode->getDoubleValue("y", 0)*2/physicalHeight;
-            pointNode = thisNode->getNode("point", 1, true);
-            thisReference[1][0] = pointNode->getDoubleValue("x", 0)*2/physicalWidth;
-            thisReference[1][1] = pointNode->getDoubleValue("y", 0)*2/physicalHeight;
-        }
-
-        pOff = osg::Matrix::perspective(45, physicalWidth/physicalHeight, 1, 20000);
-        cameraFlags |= PROJECTION_ABSOLUTE | ENABLE_MASTER_ZOOM;
-    } else {
-        // old style shear parameters
-        double shearx = cameraNode->getDoubleValue("shear-x", 0);
-        double sheary = cameraNode->getDoubleValue("shear-y", 0);
-        pOff.makeTranslate(-shearx, -sheary, 0);
-    }
-    const SGPropertyNode* textureNode = cameraNode->getNode("texture");
-    if (textureNode) {
-        string texName = textureNode->getStringValue("name");
-        int tex_width = textureNode->getIntValue("width");
-        int tex_height = textureNode->getIntValue("height");
-        TextureRectangle* texture = new TextureRectangle;
-
-        texture->setTextureSize(tex_width, tex_height);
-        texture->setInternalFormat(GL_RGB);
-        texture->setFilter(Texture::MIN_FILTER, Texture::LINEAR);
-        texture->setFilter(Texture::MAG_FILTER, Texture::LINEAR);
-        texture->setWrap(Texture::WRAP_S, Texture::CLAMP_TO_EDGE);
-        texture->setWrap(Texture::WRAP_T, Texture::CLAMP_TO_EDGE);
-        camera->setDrawBuffer(GL_FRONT);
-        camera->setReadBuffer(GL_FRONT);
-        camera->setRenderTargetImplementation(Camera::FRAME_BUFFER_OBJECT);
-        camera->attach(Camera::COLOR_BUFFER, texture);
-        _textureTargets[texName] = texture;
-    } else {
-        camera->setDrawBuffer(GL_BACK);
-        camera->setReadBuffer(GL_BACK);
-    }
-    const SGPropertyNode* psNode = cameraNode->getNode("panoramic-spherical");
-    bool useMasterSceneGraph = !psNode;
-    CameraInfo* info = globals->get_renderer()->buildRenderingPipeline(this, cameraFlags, camera, vOff, pOff,
-                                                                        window->gc.get(), useMasterSceneGraph);
-    info->name = cameraNode->getStringValue("name");
-    info->physicalWidth = physicalWidth;
-    info->physicalHeight = physicalHeight;
-    info->bezelHeightTop = bezelHeightTop;
-    info->bezelHeightBottom = bezelHeightBottom;
-    info->bezelWidthLeft = bezelWidthLeft;
-    info->bezelWidthRight = bezelWidthRight;
-    info->relativeCameraParent = parentCameraIndex;
-    info->parentReference[0] = parentReference[0];
-    info->parentReference[1] = parentReference[1];
-    info->thisReference[0] = thisReference[0];
-    info->thisReference[1] = thisReference[1];
-    // If a viewport isn't set on the camera, then it's hard to dig it
-    // out of the SceneView objects in the viewer, and the coordinates
-    // of mouse events are somewhat bizzare.
-    buildViewport(info, viewportNode, window->gc->getTraits());
-    info->updateCameras();
-    // Distortion camera needs the viewport which is created by addCamera().
-    if (psNode) {
-        info->flags = info->flags | VIEW_ABSOLUTE;
-        buildDistortionCamera(psNode, camera);
-    }
-    return info;
-}
-
-CameraInfo* CameraGroup::buildGUICamera(SGPropertyNode* cameraNode,
-                                        GraphicsWindow* window)
-{
-    WindowBuilder *wBuild = WindowBuilder::getWindowBuilder();
-    const SGPropertyNode* windowNode = (cameraNode
-                                        ? cameraNode->getNode("window")
-                                        : 0);
-    if (!window && windowNode) {
-      // New style window declaration / definition
-      window = wBuild->buildWindow(windowNode);
-    }
-
-    if (!window) { // buildWindow can fail
-      SG_LOG(SG_VIEW, SG_WARN, "CameraGroup::buildGUICamera: failed to build a window");
-      return NULL;
-    }
-
-    Camera* camera = new Camera;
-    camera->setName( "GUICamera" );
-    camera->setAllowEventFocus(false);
-    camera->setGraphicsContext(window->gc.get());
-    camera->setViewport(new Viewport);
-    camera->setClearMask(0);
-    camera->setInheritanceMask(CullSettings::ALL_VARIABLES
-                               & ~(CullSettings::COMPUTE_NEAR_FAR_MODE
-                                   | CullSettings::CULLING_MODE
-#if defined(HAVE_CULLSETTINGS_CLEAR_MASK)
-                                   | CullSettings::CLEAR_MASK
-#endif
-                                   ));
-    camera->setComputeNearFarMode(osg::CullSettings::DO_NOT_COMPUTE_NEAR_FAR);
-    camera->setCullingMode(osg::CullSettings::NO_CULLING);
-    camera->setProjectionResizePolicy(Camera::FIXED);
-    camera->setReferenceFrame(Transform::ABSOLUTE_RF);
-    const int cameraFlags = GUI | DO_INTERSECTION_TEST;
-
-    CameraInfo* result = new CameraInfo(cameraFlags);
-    // The camera group will always update the camera
-    camera->setReferenceFrame(Transform::ABSOLUTE_RF);
-
-    getViewer()->addSlave(camera, Matrixd::identity(), Matrixd::identity(), false);
-    //installCullVisitor(camera);
-    int slaveIndex = getViewer()->getNumSlaves() - 1;
-    result->addCamera( MAIN_CAMERA, camera, slaveIndex );
-    camera->setRenderOrder(Camera::POST_RENDER, slaveIndex);
-    addCamera(result);
-
-    // XXX Camera needs to be drawn last; eventually the render order
-    // should be assigned by a camera manager.
-    camera->setRenderOrder(osg::Camera::POST_RENDER, 10000);
-    SGPropertyNode* viewportNode = cameraNode->getNode("viewport", true);
-    buildViewport(result, viewportNode, window->gc->getTraits());
-
-    // Disable statistics for the GUI camera.
-    camera->setStats(0);
-    result->updateCameras();
-    return result;
-}
-
-CameraGroup* CameraGroup::buildCameraGroup(osgViewer::Viewer* viewer,
-                                           SGPropertyNode* gnode)
-{
-    sgUserDataInit( globals->get_props() );
-
-    CameraGroup* cgroup = new CameraGroup(viewer);
-    for (int i = 0; i < gnode->nChildren(); ++i) {
-        SGPropertyNode* pNode = gnode->getChild(i);
-        const char* name = pNode->getName();
-        if (!strcmp(name, "camera")) {
-            cgroup->buildCamera(pNode);
-        } else if (!strcmp(name, "window")) {
-            WindowBuilder::getWindowBuilder()->buildWindow(pNode);
-        } else if (!strcmp(name, "gui")) {
-            cgroup->buildGUICamera(pNode);
-        }
-    }
-    bindMemberToNode(gnode, "znear", cgroup, &CameraGroup::_zNear, .1f);
-    bindMemberToNode(gnode, "zfar", cgroup, &CameraGroup::_zFar, 120000.0f);
-    bindMemberToNode(gnode, "near-field", cgroup, &CameraGroup::_nearField,
-                     100.0f);
-    return cgroup;
-}
-
-void CameraGroup::setCameraCullMasks(Node::NodeMask nm)
-{
-    for (CameraIterator i = camerasBegin(), e = camerasEnd(); i != e; ++i) {
-        CameraInfo* info = i->get();
-        if (info->flags & GUI)
-            continue;
-        osg::ref_ptr<osg::Camera> farCamera = info->getCamera(FAR_CAMERA);
-        osg::Camera* camera = info->getCamera( MAIN_CAMERA );
-        if (camera) {
-            if (farCamera.valid() && farCamera->getNodeMask() != 0) {
-                camera->setCullMask(nm & ~simgear::BACKGROUND_BIT);
-                camera->setCullMaskLeft(nm & ~simgear::BACKGROUND_BIT);
-                camera->setCullMaskRight(nm & ~simgear::BACKGROUND_BIT);
-                farCamera->setCullMask(nm);
-                farCamera->setCullMaskLeft(nm);
-                farCamera->setCullMaskRight(nm);
-            } else {
-                camera->setCullMask(nm);
-                camera->setCullMaskLeft(nm);
-                camera->setCullMaskRight(nm);
-            }
-        } else {
-            camera = info->getCamera( GEOMETRY_CAMERA );
-            if (camera == 0) continue;
-            camera->setCullMask( nm & ~simgear::MODELLIGHT_BIT );
-        }
-    }
-}
-
-void CameraGroup::resized()
-{
-    for (CameraIterator i = camerasBegin(), e = camerasEnd(); i != e; ++i) {
-        CameraInfo *info = i->get();
-        Camera* camera = info->getCamera( MAIN_CAMERA );
-        if ( camera == 0 )
-            camera = info->getCamera( DISPLAY_CAMERA );
-        const Viewport* viewport = camera->getViewport();
-        info->x = viewport->x();
-        info->y = viewport->y();
-        info->width = viewport->width();
-        info->height = viewport->height();
-
-        info->resized( info->width, info->height );
-    }
-}
-
-const CameraInfo* CameraGroup::getGUICamera() const
-{
-    ConstCameraIterator result
-        = std::find_if(camerasBegin(), camerasEnd(),
-                   FlagTester<CameraInfo>(GUI));
-    if (result == camerasEnd()) {
-        return NULL;
-    }
-
-    return *result;
-}
-  
-Camera* getGUICamera(CameraGroup* cgroup)
-{
-    const CameraInfo* info = cgroup->getGUICamera();
-    if (!info) {
-        return NULL;
-    }
-    
-    return info->getCamera(MAIN_CAMERA);
-}
-
-static bool computeCameraIntersection(const CameraInfo* cinfo,
-                                      const osgGA::GUIEventAdapter* ea,
-                                      osgUtil::LineSegmentIntersector::Intersections& intersections)
-{
-  using osgUtil::Intersector;
-  using osgUtil::LineSegmentIntersector;
-  double x, y;
-  eventToWindowCoords(ea, x, y);
-  
-  if (!(cinfo->flags & CameraGroup::DO_INTERSECTION_TEST))
-    return false;
-  
-  const Camera* camera = cinfo->getCamera(MAIN_CAMERA);
-  if ( !camera )
-    camera = cinfo->getCamera( GEOMETRY_CAMERA );
-  if (camera->getGraphicsContext() != ea->getGraphicsContext())
-    return false;
-  
-  const Viewport* viewport = camera->getViewport();
-  double epsilon = 0.5;
-  if (!(x >= viewport->x() - epsilon
-        && x < viewport->x() + viewport->width() -1.0 + epsilon
-        && y >= viewport->y() - epsilon
-        && y < viewport->y() + viewport->height() -1.0 + epsilon))
-    return false;
-  
-  Vec4d start(x, y, 0.0, 1.0);
-  Vec4d end(x, y, 1.0, 1.0);
-  Matrix windowMat = viewport->computeWindowMatrix();
-  Matrix startPtMat = Matrix::inverse(camera->getProjectionMatrix()
-                                      * windowMat);
-  Matrix endPtMat;
-  const Camera* farCamera = cinfo->getCamera( FAR_CAMERA );
-  if (!farCamera || farCamera->getNodeMask() == 0)
-    endPtMat = startPtMat;
-  else
-    endPtMat = Matrix::inverse(farCamera->getProjectionMatrix()
-                               * windowMat);
-  start = start * startPtMat;
-  start /= start.w();
-  end = end * endPtMat;
-  end /= end.w();
-  ref_ptr<LineSegmentIntersector> picker
-  = new LineSegmentIntersector(Intersector::VIEW,
-                               Vec3d(start.x(), start.y(), start.z()),
-                               Vec3d(end.x(), end.y(), end.z()));
-  osgUtil::IntersectionVisitor iv(picker.get());
-  iv.setTraversalMask( ~simgear::MODELLIGHT_BIT );
-  const_cast<Camera*>(camera)->accept(iv);
-  if (picker->containsIntersections()) {
-    intersections = picker->getIntersections();
-    return true;
-  }
-  
-  return false;
-}
-  
-bool computeIntersections(const CameraGroup* cgroup,
-                          const osgGA::GUIEventAdapter* ea,
-                          osgUtil::LineSegmentIntersector::Intersections& intersections)
-{
-    // test the GUI first
-    const CameraInfo* guiCamera = cgroup->getGUICamera();
-    if (guiCamera && computeCameraIntersection(guiCamera, ea, intersections))
-        return true;
-    
-    // Find camera that contains event
-    for (CameraGroup::ConstCameraIterator iter = cgroup->camerasBegin(),
-             e = cgroup->camerasEnd();
-         iter != e;
-         ++iter) {
-        const CameraInfo* cinfo = iter->get();
-        if (cinfo == guiCamera)
-            continue;
-        
-        if (computeCameraIntersection(cinfo, ea, intersections))
-            return true;
-    }
-  
-    intersections.clear();
-    return false;
-}
-
-void warpGUIPointer(CameraGroup* cgroup, int x, int y)
-{
-    using osgViewer::GraphicsWindow;
-    Camera* guiCamera = getGUICamera(cgroup);
-    if (!guiCamera)
-        return;
-    Viewport* vport = guiCamera->getViewport();
-    GraphicsWindow* gw
-        = dynamic_cast<GraphicsWindow*>(guiCamera->getGraphicsContext());
-    if (!gw)
-        return;
-    globals->get_renderer()->getEventHandler()->setMouseWarped();
-    // Translate the warp request into the viewport of the GUI camera,
-    // send the request to the window, then transform the coordinates
-    // for the Viewer's event queue.
-    double wx = x + vport->x();
-    double wyUp = vport->height() + vport->y() - y;
-    double wy;
-    const GraphicsContext::Traits* traits = gw->getTraits();
-    if (gw->getEventQueue()->getCurrentEventState()->getMouseYOrientation()
-        == osgGA::GUIEventAdapter::Y_INCREASING_DOWNWARDS) {
-        wy = traits->height - wyUp;
-    } else {
-        wy = wyUp;
-    }
-    gw->getEventQueue()->mouseWarped(wx, wy);
-    gw->requestWarpPointer(wx, wy);
-    osgGA::GUIEventAdapter* eventState
-        = cgroup->getViewer()->getEventQueue()->getCurrentEventState();
-    double viewerX
-        = (eventState->getXmin()
-           + ((wx / double(traits->width))
-              * (eventState->getXmax() - eventState->getXmin())));
-    double viewerY
-        = (eventState->getYmin()
-           + ((wyUp / double(traits->height))
-              * (eventState->getYmax() - eventState->getYmin())));
-    cgroup->getViewer()->getEventQueue()->mouseWarped(viewerX, viewerY);
-}
-}
diff --git a/src/Main/CameraGroup.hxx b/src/Main/CameraGroup.hxx
deleted file mode 100644 (file)
index 606bfc3..0000000
+++ /dev/null
@@ -1,337 +0,0 @@
-// Copyright (C) 2008  Tim Moore
-//
-// This program is free software; you can redistribute it and/or
-// modify it under the terms of the GNU General Public License as
-// published by the Free Software Foundation; either version 2 of the
-// License, or (at your option) any later version.
-//
-// This program is distributed in the hope that it will be useful, but
-// WITHOUT ANY WARRANTY; without even the implied warranty of
-// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
-// General Public License for more details.
-//
-// You should have received a copy of the GNU General Public License
-// along with this program; if not, write to the Free Software
-// Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
-
-#ifndef CAMERAGROUP_HXX
-#define CAMERAGROUP_HXX 1
-
-#include <map>
-#include <string>
-#include <vector>
-
-#include <osg/Matrix>
-#include <osg/ref_ptr>
-#include <osg/Referenced>
-#include <osg/Node>
-#include <osg/TextureRectangle>
-#include <osg/Texture2D>
-#include <osg/TexGen>
-#include <osgUtil/RenderBin>
-
-// For osgUtil::LineSegmentIntersector::Intersections, which is a typedef.
-#include <osgUtil/LineSegmentIntersector>
-namespace osg
-{
-class Camera;
-}
-
-namespace osgViewer
-{
-class Viewer;
-}
-
-class SGPropertyNode;
-
-namespace flightgear
-{
-
-class GraphicsWindow;
-
-struct RenderBufferInfo {
-       enum Kind {
-               DEPTH_BUFFER,
-               NORMAL_BUFFER,
-               DIFFUSE_BUFFER,
-               SPEC_EMIS_BUFFER,
-               LIGHTING_BUFFER,
-        SHADOW_BUFFER
-       };
-
-       RenderBufferInfo(osg::Texture2D* t = 0, float s = 1.0 ) : texture(t), scaleFactor(s) {}
-       osg::ref_ptr<osg::Texture2D> texture;
-       float scaleFactor;
-};
-typedef std::map<RenderBufferInfo::Kind,RenderBufferInfo> RenderBufferMap;
-typedef std::map<osg::Camera::BufferComponent,size_t> AttachmentMap;
-
-struct RenderStageInfo {
-       RenderStageInfo(osg::Camera* camera_ = 0, int si = -1, bool fs = false)
-               : camera(camera_), slaveIndex(si), scaleFactor(1.0f), fullscreen(fs)
-               , resizable(true)
-       {
-       }
-
-       osg::ref_ptr<osg::Camera> camera;
-       AttachmentMap buffers;
-       int slaveIndex;
-       float scaleFactor;
-       bool fullscreen;
-       bool resizable;
-};
-
-enum CameraKind {
-       MAIN_CAMERA,
-       FAR_CAMERA,
-       GEOMETRY_CAMERA,
-       SHADOW_CAMERA,
-       BLOOM_CAMERA_1,
-       BLOOM_CAMERA_2,
-       AO_CAMERA_1,
-       AO_CAMERA_2,
-       AO_CAMERA_3,
-       LIGHTING_CAMERA,
-       DISPLAY_CAMERA
-};
-typedef std::map<CameraKind,RenderStageInfo> CameraMap;
-
-/** A wrapper around osg::Camera that contains some extra information.
- */
-struct CameraInfo : public osg::Referenced
-{
-    CameraInfo(unsigned flags_)
-        : flags(flags_),
-          x(0.0), y(0.0), width(0.0), height(0.0),
-          physicalWidth(0), physicalHeight(0), bezelHeightTop(0),
-          bezelHeightBottom(0), bezelWidthLeft(0), bezelWidthRight(0),
-          relativeCameraParent(~0u),
-          bufferSize( new osg::Uniform("fg_BufferSize", osg::Vec2f() ) ),
-          projInverse( new osg::Uniform( "fg_ProjectionMatrixInverse", osg::Matrixf() ) ),
-          viewInverse( new osg::Uniform( "fg_ViewMatrixInverse",osg::Matrixf() ) ),
-          view( new osg::Uniform( "fg_ViewMatrix",osg::Matrixf() ) ),
-          du( new osg::Uniform( "fg_du",osg::Vec4() ) ),
-          dv( new osg::Uniform( "fg_dv",osg::Vec4() ) )
-    {
-    }
-
-       /** Update and resize cameras
-        */
-       void updateCameras();
-       void resized(double w, double h);
-    /** The name as given in the config file.
-     */
-    std::string name;
-    /** Properties of the camera. @see CameraGroup::Flags.
-     */
-    unsigned flags;
-
-    /** Viewport parameters.
-     */
-    double x;
-    double y;
-    double width;
-    double height;
-    /** Physical size parameters.
-     */
-    double physicalWidth;
-    double physicalHeight;
-    double bezelHeightTop;
-    double bezelHeightBottom;
-    double bezelWidthLeft;
-    double bezelWidthRight;
-    /** The parent camera for relative camera configurations.
-     */
-    unsigned relativeCameraParent;
-
-    /** the camera objects
-     */
-       CameraMap cameras;
-       void addCamera( CameraKind k, osg::Camera* c, int si = -1, bool fs = false ) { cameras[k].camera = c; cameras[k].slaveIndex = si; cameras[k].fullscreen = fs; }
-       void addCamera( CameraKind k, osg::Camera* c, bool fs ) { cameras[k].camera = c; cameras[k].fullscreen = fs; }
-       void addCamera( CameraKind k, osg::Camera* c, float s ) { cameras[k].camera = c; cameras[k].scaleFactor = s; }
-       osg::Camera* getCamera(CameraKind k) const;
-       int getMainSlaveIndex() const;
-       RenderStageInfo& getRenderStageInfo( CameraKind k ) { return cameras[k]; }
-
-       /** the buffer objects
-        */
-       RenderBufferMap buffers;
-       void addBuffer(RenderBufferInfo::Kind k, osg::Texture2D* tex, float scale = 1.0 ) { buffers[k] = RenderBufferInfo(tex,scale); }
-       osg::Texture2D* getBuffer(RenderBufferInfo::Kind k) const;
-
-    osg::ref_ptr<osg::TexGen> shadowTexGen[4];
-
-    osg::ref_ptr<osg::Uniform> bufferSize;
-    //osg::ref_ptr<osg::Uniform> bloomOffset[2];
-    osg::ref_ptr<osg::Uniform> projInverse;
-    osg::ref_ptr<osg::Uniform> viewInverse;
-    osg::ref_ptr<osg::Uniform> view;
-    osg::ref_ptr<osg::Uniform> du;
-    osg::ref_ptr<osg::Uniform> dv;
-
-       void setMatrices( osg::Camera* c );
-
-       osgUtil::RenderBin::RenderBinList savedTransparentBins;
-    /** The reference points in the parents projection space.
-     */
-    osg::Vec2d parentReference[2];
-    /** The reference points in the current projection space.
-     */
-    osg::Vec2d thisReference[2];
-};
-
-/** Update the OSG cameras from the camera info.
- */
-void updateCameras(const CameraInfo* info);
-
-class CameraGroup : public osg::Referenced
-{
-public:
-    /** properties of a camera.
-     */
-    enum Flags
-    {
-        VIEW_ABSOLUTE = 0x1, /**< The camera view is absolute, not
-                                relative to the master camera. */
-        PROJECTION_ABSOLUTE = 0x2, /**< The projection is absolute. */
-        ORTHO = 0x4,               /**< The projection is orthographic */
-        GUI = 0x8,                 /**< Camera draws the GUI. */
-        DO_INTERSECTION_TEST = 0x10,/**< scene intersection tests this
-                                       camera. */
-        FIXED_NEAR_FAR = 0x20,     /**< take the near far values in the
-                                      projection for real. */
-        ENABLE_MASTER_ZOOM = 0x40  /**< Can apply the zoom algorithm. */
-    };
-    /** Create a camera group associated with an osgViewer::Viewer.
-     * @param viewer the viewer
-     */
-    CameraGroup(osgViewer::Viewer* viewer);
-    /** Get the camera group's Viewer.
-     * @return the viewer
-     */
-    osgViewer::Viewer* getViewer() { return _viewer.get(); }
-    /** Create an osg::Camera from a property node and add it to the
-     * camera group.
-     * @param cameraNode the property node.
-     * @return a CameraInfo object for the camera.
-     */
-    CameraInfo* buildCamera(SGPropertyNode* cameraNode);
-    /** Create a camera from properties that will draw the GUI and add
-     * it to the camera group.
-     * @param cameraNode the property node. This can be 0, in which
-     * case a default GUI camera is created.
-     * @param window the GraphicsWindow to use for the GUI camera. If
-     * this is 0, the window is determined from the property node.
-     * @return a CameraInfo object for the GUI camera.
-     */
-    CameraInfo* buildGUICamera(SGPropertyNode* cameraNode,
-                               GraphicsWindow* window = 0);
-    /** Update the view for the camera group.
-     * @param position the world position of the view
-     * @param orientation the world orientation of the view.
-     */
-    void update(const osg::Vec3d& position, const osg::Quat& orientation);
-    /** Set the parameters of the viewer's master camera. This won't
-     * affect cameras that have CameraFlags::PROJECTION_ABSOLUTE set.
-     * XXX Should znear and zfar be settable?
-     * @param vfov the vertical field of view angle
-     * @param aspectRatio the master camera's aspect ratio. This
-     * doesn't actually change the viewport, but should reflect the
-     * current viewport.
-     */
-    void setCameraParameters(float vfov, float aspectRatio);
-    /** Set the default CameraGroup, which is the only one that
-     * matters at this time.
-     * @param group the group to set.
-     */
-    static void setDefault(CameraGroup* group) { _defaultGroup = group; }
-    /** Get the default CameraGroup.
-     * @return the default camera group.
-     */
-    static CameraGroup* getDefault() { return _defaultGroup.get(); }
-    typedef std::vector<osg::ref_ptr<CameraInfo> > CameraList;
-    typedef CameraList::iterator CameraIterator;
-    typedef CameraList::const_iterator ConstCameraIterator;
-    /** Get iterator for camera vector. The iterator's value is a ref_ptr.
-     */
-    CameraIterator camerasBegin() { return _cameras.begin(); }
-    /** Get iteator pointing to the end of the camera list.
-     */
-    CameraIterator camerasEnd() { return _cameras.end(); }
-    ConstCameraIterator camerasBegin() const { return _cameras.begin(); }
-    ConstCameraIterator camerasEnd() const { return _cameras.end(); }
-    void addCamera(CameraInfo* info) { _cameras.push_back(info); }
-    /** Build a complete CameraGroup from a property node.
-     * @param viewer the viewer associated with this camera group.
-     * @param the camera group property node.
-     */
-    static CameraGroup* buildCameraGroup(osgViewer::Viewer* viewer,
-                                         SGPropertyNode* node);
-    /** Set the cull mask on all non-GUI cameras
-     */
-    void setCameraCullMasks(osg::Node::NodeMask nm);
-    /** Update camera properties after a resize event.
-     */
-    void resized();
-
-    void buildDistortionCamera(const SGPropertyNode* psNode,
-                               osg::Camera* camera);
-  
-    /**
-     * get aspect ratio of master camera's viewport
-     */
-    double getMasterAspectRatio() const;
-  
-    /**
-     * find the GUI camera if one is defined 
-     */
-    const CameraInfo* getGUICamera() const;
-protected:
-    CameraList _cameras;
-    osg::ref_ptr<osgViewer::Viewer> _viewer;
-    static osg::ref_ptr<CameraGroup> _defaultGroup;
-    // Near, far for the master camera if used.
-    float _zNear;
-    float _zFar;
-    float _nearField;
-    typedef std::map<std::string, osg::ref_ptr<osg::TextureRectangle> > TextureMap;
-    TextureMap _textureTargets;
-};
-
-}
-
-namespace osgGA
-{
-class GUIEventAdapter;
-}
-
-namespace flightgear
-{
-/** Get the osg::Camera that draws the GUI, if any, from a camera
- * group.
- * @param cgroup the camera group
- * @return the GUI camera or 0
- */
-osg::Camera* getGUICamera(CameraGroup* cgroup);
-/** Choose a camera using an event and do intersection testing on its
- * view of the scene. Only cameras with the DO_INTERSECTION_TEST flag
- * set are considered.
- * @param cgroup the CameraGroup
- * @param ea the event containing a window and mouse coordinates
- * @param intersections container for the result of intersection
- * testing.
- * @return true if any intersections are found
- */
-bool computeIntersections(const CameraGroup* cgroup,
-                          const osgGA::GUIEventAdapter* ea,
-                          osgUtil::LineSegmentIntersector::Intersections&
-                          intersections);
-/** Warp the pointer to coordinates in the GUI camera of a camera group.
- * @param cgroup the camera group
- * @param x x window coordinate of pointer
- * @param y y window coordinate of pointer, in "y down" coordinates.
- */
-void warpGUIPointer(CameraGroup* cgroup, int x, int y);
-}
-#endif
diff --git a/src/Main/FGEventHandler.cxx b/src/Main/FGEventHandler.cxx
deleted file mode 100644 (file)
index 9951c00..0000000
+++ /dev/null
@@ -1,413 +0,0 @@
-#ifdef HAVE_CONFIG_H
-#  include <config.h>
-#endif
-#include <osg/Camera>
-#include <osg/GraphicsContext>
-#include <osg/Math>
-#include <osg/Viewport>
-#include <osgViewer/Viewer>
-
-#include <plib/pu.h>
-#include <Main/fg_props.hxx>
-#include "CameraGroup.hxx"
-#include "FGEventHandler.hxx"
-#include "WindowSystemAdapter.hxx"
-#include "renderer.hxx"
-
-#if !defined(X_DISPLAY_MISSING)
-#define X_DOUBLE_SCROLL_BUG 1
-#endif
-
-#ifdef SG_MAC
-// hack - during interactive resize on Mac, OSG queues and then flushes
-// a large number of resize events, without doing any drawing.
-extern void puCleanUpJunk ( void ) ;
-#endif
-
-namespace flightgear
-{
-const int displayStatsKey = 1;
-const int printStatsKey = 2;
-
-
-// The manipulator is responsible for updating a Viewer's camera. Its
-// event handling method is also a convenient place to run the FG idle
-// and draw handlers.
-
-FGEventHandler::FGEventHandler() :
-    idleHandler(0),
-    keyHandler(0),
-    mouseClickHandler(0),
-    mouseMotionHandler(0),
-    statsHandler(new FGStatsHandler),
-    statsEvent(new osgGA::GUIEventAdapter),
-    statsType(osgViewer::StatsHandler::NO_STATS),
-    currentModifiers(0),
-    resizable(true),
-    mouseWarped(false),
-    scrollButtonPressed(false),
-    changeStatsCameraRenderOrder(false)
-{
-    using namespace osgGA;
-    statsHandler->setKeyEventTogglesOnScreenStats(displayStatsKey);
-    statsHandler->setKeyEventPrintsOutStats(printStatsKey);
-    statsEvent->setEventType(GUIEventAdapter::KEYDOWN);
-
-    // OSG reports NumPad keycodes independent of the NumLock modifier.
-    // Both KP-4 and KP-Left are reported as KEY_KP_Left (0xff96), so we
-    // have to generate the locked keys ourselves.
-    numlockKeyMap[GUIEventAdapter::KEY_KP_Insert]  = '0';
-    numlockKeyMap[GUIEventAdapter::KEY_KP_End] = '1';
-    numlockKeyMap[GUIEventAdapter::KEY_KP_Down] = '2';
-    numlockKeyMap[GUIEventAdapter::KEY_KP_Page_Down] = '3';
-    numlockKeyMap[GUIEventAdapter::KEY_KP_Left] = '4';
-    numlockKeyMap[GUIEventAdapter::KEY_KP_Begin] = '5';
-    numlockKeyMap[GUIEventAdapter::KEY_KP_Right] = '6';
-    numlockKeyMap[GUIEventAdapter::KEY_KP_Home] = '7';
-    numlockKeyMap[GUIEventAdapter::KEY_KP_Up] = '8';
-    numlockKeyMap[GUIEventAdapter::KEY_KP_Page_Up] = '9';
-    numlockKeyMap[GUIEventAdapter::KEY_KP_Delete] = '.';
-
-    // mapping when NumLock is off
-    noNumlockKeyMap[GUIEventAdapter::KEY_KP_Insert]     = PU_KEY_INSERT;
-    noNumlockKeyMap[GUIEventAdapter::KEY_KP_End]        = PU_KEY_END;
-    noNumlockKeyMap[GUIEventAdapter::KEY_KP_Down]       = PU_KEY_DOWN;
-    noNumlockKeyMap[GUIEventAdapter::KEY_KP_Page_Down]  = PU_KEY_PAGE_DOWN;
-    noNumlockKeyMap[GUIEventAdapter::KEY_KP_Left]       = PU_KEY_LEFT;
-    noNumlockKeyMap[GUIEventAdapter::KEY_KP_Begin]      = '5';
-    noNumlockKeyMap[GUIEventAdapter::KEY_KP_Right]      = PU_KEY_RIGHT;
-    noNumlockKeyMap[GUIEventAdapter::KEY_KP_Home]       = PU_KEY_HOME;
-    noNumlockKeyMap[GUIEventAdapter::KEY_KP_Up]         = PU_KEY_UP;
-    noNumlockKeyMap[GUIEventAdapter::KEY_KP_Page_Up]    = PU_KEY_PAGE_UP;
-    noNumlockKeyMap[GUIEventAdapter::KEY_KP_Delete]     = 127;
-
-    for (int i = 0; i < 128; i++)
-        release_keys[i] = i;
-}
-
-namespace
-{
-// Translate OSG modifier mask to FG modifier mask.
-int osgToFGModifiers(int modifiers)
-{
-    int result = 0;
-    if (modifiers & osgGA::GUIEventAdapter::MODKEY_SHIFT)
-        result |= KEYMOD_SHIFT;
-
-    if (modifiers & osgGA::GUIEventAdapter::MODKEY_CTRL)
-        result |= KEYMOD_CTRL;
-
-    if (modifiers & osgGA::GUIEventAdapter::MODKEY_ALT)
-        result |= KEYMOD_ALT;
-
-    if (modifiers & osgGA::GUIEventAdapter::MODKEY_META)
-        result |= KEYMOD_META;
-
-    if (modifiers & osgGA::GUIEventAdapter::MODKEY_SUPER)
-        result |= KEYMOD_SUPER;
-
-    if (modifiers & osgGA::GUIEventAdapter::MODKEY_HYPER)
-        result |= KEYMOD_HYPER;
-    return result;
-}
-}
-
-#if 0
-void FGEventHandler::init(const osgGA::GUIEventAdapter& ea,
-                          osgGA::GUIActionAdapter& us)
-{
-    currentModifiers = osgToFGModifiers(ea.getModKeyMask());
-    (void)handle(ea, us);
-}
-#endif
-
-// Calculate event coordinates in the viewport of the GUI camera, if
-// possible. Otherwise return false and (-1, -1).
-namespace
-{
-bool
-eventToViewport(const osgGA::GUIEventAdapter& ea, osgGA::GUIActionAdapter& us,
-                int& x, int& y)
-{
-    x = -1;
-    y = -1;
-
-    const osg::GraphicsContext* eventGC = ea.getGraphicsContext();
-    const osg::GraphicsContext::Traits* traits = eventGC->getTraits();
-    osg::Camera* guiCamera = getGUICamera(CameraGroup::getDefault());
-    if (!guiCamera)
-        return false;
-    osg::Viewport* vport = guiCamera->getViewport();
-    if (!vport)
-        return false;
-    
-    // Scale x, y to the dimensions of the window
-    double wx = (((ea.getX() - ea.getXmin()) / (ea.getXmax() - ea.getXmin()))
-                 * (float)traits->width);
-    double wy = (((ea.getY() - ea.getYmin()) / (ea.getYmax() - ea.getYmin()))
-                 * (float)traits->height);
-    if (vport->x() <= wx && wx <= vport->x() + vport->width()
-        && vport->y() <= wy && wy <= vport->y() + vport->height()) {
-        // Finally, into viewport coordinates. Change y to "increasing
-        // downwards".
-        x = wx - vport->x();
-        y = vport->height() - (wy - vport->y());
-        return true;
-    } else {
-        return false;
-    }
-}
-}
-
-bool FGEventHandler::handle(const osgGA::GUIEventAdapter& ea,
-                            osgGA::GUIActionAdapter& us)
-{
-    int x = 0;
-    int y = 0;
-
-    switch (ea.getEventType()) {
-    case osgGA::GUIEventAdapter::FRAME:
-        mouseWarped = false;
-        handleStats(us);
-        return true;
-    case osgGA::GUIEventAdapter::KEYDOWN:
-    case osgGA::GUIEventAdapter::KEYUP:
-    {
-        int key, modmask;
-        handleKey(ea, key, modmask);
-        eventToViewport(ea, us, x, y);
-        if (keyHandler)
-            (*keyHandler)(key, modmask, x, y);
-        return true;
-    }
-    case osgGA::GUIEventAdapter::PUSH:
-    case osgGA::GUIEventAdapter::RELEASE:
-    {
-        bool mainWindow = eventToViewport(ea, us, x, y);
-        int button = 0;
-        switch (ea.getButton()) {
-        case osgGA::GUIEventAdapter::LEFT_MOUSE_BUTTON:
-            button = 0;
-            break;
-        case osgGA::GUIEventAdapter::MIDDLE_MOUSE_BUTTON:
-            button = 1;
-            break;
-        case osgGA::GUIEventAdapter::RIGHT_MOUSE_BUTTON:
-            button = 2;
-            break;
-        }
-        if (mouseClickHandler)
-            (*mouseClickHandler)(button,
-                                 (ea.getEventType()
-                                  == osgGA::GUIEventAdapter::RELEASE), x, y, mainWindow, &ea);
-        return true;
-    }
-    case osgGA::GUIEventAdapter::SCROLL:
-    {
-        bool mainWindow = eventToViewport(ea, us, x, y);
-#ifdef X_DOUBLE_SCROLL_BUG
-        scrollButtonPressed = !scrollButtonPressed;
-        if (!scrollButtonPressed) // Drop the button release event
-            return true;
-#endif
-        int button;
-        if (ea.getScrollingMotion() == osgGA::GUIEventAdapter::SCROLL_2D) {
-            if (ea.getScrollingDeltaY() > 0)
-                button = 3;
-            else if (ea.getScrollingDeltaY() < 0)
-                button = 4;
-            else
-                button = -1;
-        } else if (ea.getScrollingMotion() == osgGA::GUIEventAdapter::SCROLL_UP)
-            button = 3;
-        else
-            button = 4;
-        if (mouseClickHandler && button != -1) {
-            (*mouseClickHandler)(button, 0, x, y, mainWindow, &ea);
-            (*mouseClickHandler)(button, 1, x, y, mainWindow, &ea);
-        }
-        return true;
-    }
-    case osgGA::GUIEventAdapter::MOVE:
-    case osgGA::GUIEventAdapter::DRAG:
-        // If we warped the mouse, then disregard all pointer motion
-        // events for this frame. We really want to flush the event
-        // queue of mouse events, but don't have the ability to do
-        // that with osgViewer.
-        if (mouseWarped)
-            return true;
-        if (eventToViewport(ea, us, x, y) && mouseMotionHandler)
-            (*mouseMotionHandler)(x, y);
-        return true;
-    case osgGA::GUIEventAdapter::RESIZE:
-        SG_LOG(SG_VIEW, SG_DEBUG, "FGEventHandler::handle: RESIZE event " << ea.getWindowHeight() << " x " << ea.getWindowWidth() << ", resizable: " << resizable);
-        CameraGroup::getDefault()->resized();
-        if (resizable)
-          globals->get_renderer()->resize(ea.getWindowWidth(), ea.getWindowHeight());
-        statsHandler->handle(ea, us);
-      #ifdef SG_MAC
-        // work around OSG Cocoa-Viewer issue with resize event handling,
-        // where resize events are queued up, then dispatched in a batch, with
-        // no interveningd drawing calls.
-        puCleanUpJunk();
-      #endif
-        return true;
-     case osgGA::GUIEventAdapter::CLOSE_WINDOW:
-    case osgGA::GUIEventAdapter::QUIT_APPLICATION:
-        fgOSExit(0);
-        return true;
-    default:
-        return false;
-    }
-}
-
-void FGEventHandler::handleKey(const osgGA::GUIEventAdapter& ea, int& key,
-                               int& modifiers)
-{
-    using namespace osgGA;
-    key = ea.getKey();
-    // XXX Probably other translations are needed too.
-    switch (key) {
-    case GUIEventAdapter::KEY_Escape:      key = 0x1b; break;
-    case GUIEventAdapter::KEY_Return:      key = '\n'; break;
-    case GUIEventAdapter::KEY_BackSpace:   key = '\b'; break;
-    case GUIEventAdapter::KEY_Delete:      key = 0x7f; break;
-    case GUIEventAdapter::KEY_Tab:         key = '\t'; break;
-    case GUIEventAdapter::KEY_Left:        key = PU_KEY_LEFT;      break;
-    case GUIEventAdapter::KEY_Up:          key = PU_KEY_UP;        break;
-    case GUIEventAdapter::KEY_Right:       key = PU_KEY_RIGHT;     break;
-    case GUIEventAdapter::KEY_Down:        key = PU_KEY_DOWN;      break;
-    case GUIEventAdapter::KEY_Page_Up:     key = PU_KEY_PAGE_UP;   break;
-    case GUIEventAdapter::KEY_Page_Down:   key = PU_KEY_PAGE_DOWN; break;
-    case GUIEventAdapter::KEY_Home:        key = PU_KEY_HOME;      break;
-    case GUIEventAdapter::KEY_End:         key = PU_KEY_END;       break;
-    case GUIEventAdapter::KEY_Insert:      key = PU_KEY_INSERT;    break;
-    case GUIEventAdapter::KEY_F1:          key = PU_KEY_F1;        break;
-    case GUIEventAdapter::KEY_F2:          key = PU_KEY_F2;        break;
-    case GUIEventAdapter::KEY_F3:          key = PU_KEY_F3;        break;
-    case GUIEventAdapter::KEY_F4:          key = PU_KEY_F4;        break;
-    case GUIEventAdapter::KEY_F5:          key = PU_KEY_F5;        break;
-    case GUIEventAdapter::KEY_F6:          key = PU_KEY_F6;        break;
-    case GUIEventAdapter::KEY_F7:          key = PU_KEY_F7;        break;
-    case GUIEventAdapter::KEY_F8:          key = PU_KEY_F8;        break;
-    case GUIEventAdapter::KEY_F9:          key = PU_KEY_F9;        break;
-    case GUIEventAdapter::KEY_F10:         key = PU_KEY_F10;       break;
-    case GUIEventAdapter::KEY_F11:         key = PU_KEY_F11;       break;
-    case GUIEventAdapter::KEY_F12:         key = PU_KEY_F12;       break;
-    case GUIEventAdapter::KEY_KP_Enter:    key = '\r'; break;
-    case GUIEventAdapter::KEY_KP_Add:      key = '+';  break;
-    case GUIEventAdapter::KEY_KP_Divide:   key = '/';  break;
-    case GUIEventAdapter::KEY_KP_Multiply: key = '*';  break;
-    case GUIEventAdapter::KEY_KP_Subtract: key = '-';  break;
-    }
-    osgGA::GUIEventAdapter::EventType eventType = ea.getEventType();
-
-#ifdef __APPLE__
-    // Num Lock is always true on Mac
-    std::map<int, int>::iterator numPadIter = numlockKeyMap.find(key);
-    if (numPadIter != numlockKeyMap.end()) {
-        key = numPadIter->second;
-    }
-#else
-    if (ea.getModKeyMask() & osgGA::GUIEventAdapter::MODKEY_NUM_LOCK)
-    {
-        // NumLock on: map to numeric keys
-        std::map<int, int>::iterator numPadIter = numlockKeyMap.find(key);
-        if (numPadIter != numlockKeyMap.end()) {
-            key = numPadIter->second;
-        }
-    }
-    else
-    {
-        // NumLock off: map to PU arrow keys
-        std::map<int, int>::iterator numPadIter = noNumlockKeyMap.find(key);
-        if (numPadIter != noNumlockKeyMap.end()) {
-            key = numPadIter->second;
-        }
-    }
-#endif
-
-    modifiers = osgToFGModifiers(ea.getModKeyMask());
-    currentModifiers = modifiers;
-    if (eventType == osgGA::GUIEventAdapter::KEYUP)
-        modifiers |= KEYMOD_RELEASED;
-
-    // Release the letter key, for which the key press was reported. This
-    // is to deal with Ctrl-press -> a-press -> Ctrl-release -> a-release
-    // correctly.
-    if (key >= 0 && key < 128) {
-        if (modifiers & KEYMOD_RELEASED) {
-            key = release_keys[key];
-        } else {
-            release_keys[key] = key;
-            if (key >= 1 && key <= 26) {
-                release_keys[key + '@'] = key;
-                release_keys[key + '`'] = key;
-            } else if (key >= 'A' && key <= 'Z') {
-                release_keys[key - '@'] = key;
-                release_keys[tolower(key)] = key;
-            } else if (key >= 'a' && key <= 'z') {
-                release_keys[key - '`'] = key;
-                release_keys[toupper(key)] = key;
-            }
-        }
-    }
-}
-
-void FGEventHandler::handleStats(osgGA::GUIActionAdapter& us)
-{
-    static SGPropertyNode_ptr display = fgGetNode("/sim/rendering/on-screen-statistics", true);
-    static SGPropertyNode_ptr print = fgGetNode("/sim/rendering/print-statistics", true);
-
-    int type = display->getIntValue() % osgViewer::StatsHandler::LAST;
-    if (type != statsType) {
-        statsEvent->setKey(displayStatsKey);
-        do {
-            statsType = (statsType + 1) % osgViewer::StatsHandler::LAST;
-            statsHandler->handle(*statsEvent, us);
-            if (changeStatsCameraRenderOrder) {
-                statsHandler->getCamera()->setRenderOrder(osg::Camera::POST_RENDER, 99999);
-                changeStatsCameraRenderOrder = false;
-            }
-        } while (statsType != type);
-
-        display->setIntValue(statsType);
-    }
-
-    if (print->getBoolValue()) {
-        statsEvent->setKey(printStatsKey);
-        statsHandler->handle(*statsEvent, us);
-        print->setBoolValue(false);
-    }
-}
-
-void eventToWindowCoords(const osgGA::GUIEventAdapter* ea,
-                         double& x, double& y)
-{
-    using namespace osg;
-    const GraphicsContext* gc = ea->getGraphicsContext();
-    const GraphicsContext::Traits* traits = gc->getTraits() ;
-    // Scale x, y to the dimensions of the window
-    x = (((ea->getX() - ea->getXmin()) / (ea->getXmax() - ea->getXmin()))
-         * (double)traits->width);
-    y = (((ea->getY() - ea->getYmin()) / (ea->getYmax() - ea->getYmin()))
-         * (double)traits->height);
-    if (ea->getMouseYOrientation() == osgGA::GUIEventAdapter::Y_INCREASING_DOWNWARDS)
-        y = (double)traits->height - y;
-}
-
-void eventToWindowCoordsYDown(const osgGA::GUIEventAdapter* ea,
-                              double& x, double& y)
-{
-    using namespace osg;
-    const GraphicsContext* gc = ea->getGraphicsContext();
-    const GraphicsContext::Traits* traits = gc->getTraits() ;
-    // Scale x, y to the dimensions of the window
-    x = (((ea->getX() - ea->getXmin()) / (ea->getXmax() - ea->getXmin()))
-         * (double)traits->width);
-    y = (((ea->getY() - ea->getYmin()) / (ea->getYmax() - ea->getYmin()))
-         * (double)traits->height);
-    if (ea->getMouseYOrientation() == osgGA::GUIEventAdapter::Y_INCREASING_UPWARDS)
-        y = (double)traits->height - y;
-}
-}
diff --git a/src/Main/FGEventHandler.hxx b/src/Main/FGEventHandler.hxx
deleted file mode 100644 (file)
index 9eed484..0000000
+++ /dev/null
@@ -1,129 +0,0 @@
-#ifndef FGEVENTHANDLER_H
-#define FGEVENTHANDLER_H 1
-
-#include <map>
-#include <osg/Quat>
-#include <osgGA/GUIEventHandler>
-#include <osgViewer/ViewerEventHandlers>
-#include <simgear/structure/OSGVersion.hxx>
-
-#include "fg_os.hxx"
-
-namespace flightgear
-{
-    class FGStatsHandler : public osgViewer::StatsHandler
-    {
-        public:
-            FGStatsHandler()
-            {
-#if (SG_OSG_VERSION >= 30000)
-                // Adjust font type/size for >=OSG3.
-                // OSG defaults aren't working/available for FG.
-                _font = "Fonts/helvetica_medium.txf";
-                _characterSize = 12.0f;
-#endif
-            }
-    };
-
-class FGEventHandler : public osgGA::GUIEventHandler {
-public:
-    FGEventHandler();
-    
-    virtual ~FGEventHandler() {}
-    
-    virtual const char* className() const {return "FGEventHandler"; }
-#if 0
-    virtual void init(const osgGA::GUIEventAdapter& ea,
-                     osgGA::GUIActionAdapter& us);
-#endif
-    virtual bool handle(const osgGA::GUIEventAdapter& ea,
-                       osgGA::GUIActionAdapter& us);
-
-    void setIdleHandler(fgIdleHandler idleHandler)
-       {
-           this->idleHandler = idleHandler;
-       }
-
-    fgIdleHandler getIdleHandler() const
-       {
-           return idleHandler;
-       }
-
-    void setKeyHandler(fgKeyHandler keyHandler)
-       {
-           this->keyHandler = keyHandler;
-       }
-
-    fgKeyHandler getKeyHandler() const
-       {
-           return keyHandler;
-       }
-
-    void setMouseClickHandler(fgMouseClickHandler mouseClickHandler)
-       {
-           this->mouseClickHandler = mouseClickHandler;
-       }
-    
-    fgMouseClickHandler getMouseClickHandler()
-       {
-           return mouseClickHandler;
-       }
-
-    void setMouseMotionHandler(fgMouseMotionHandler mouseMotionHandler)
-       {
-           this->mouseMotionHandler = mouseMotionHandler;
-       }
-    
-    fgMouseMotionHandler getMouseMotionHandler()
-       {
-           return mouseMotionHandler;
-       }
-
-    void setChangeStatsCameraRenderOrder(bool c)
-    {
-        changeStatsCameraRenderOrder = c;
-    }
-
-    int getCurrentModifiers() const
-       {
-           return currentModifiers;
-       }
-
-    void setMouseWarped()
-       {
-           mouseWarped = true;
-       }
-
-    /** Whether or not resizing is supported. It might not be when
-     * using multiple displays.
-     */
-    bool getResizable() { return resizable; }
-    void setResizable(bool _resizable) { resizable = _resizable; }
-
-protected:
-    osg::ref_ptr<osg::Node> _node;
-    fgIdleHandler idleHandler;
-    fgKeyHandler keyHandler;
-    fgMouseClickHandler mouseClickHandler;
-    fgMouseMotionHandler mouseMotionHandler;
-    osg::ref_ptr<FGStatsHandler> statsHandler;
-    osg::ref_ptr<osgGA::GUIEventAdapter> statsEvent;
-    int statsType;
-    int currentModifiers;
-    std::map<int, int> numlockKeyMap;
-    std::map<int, int> noNumlockKeyMap;
-    void handleKey(const osgGA::GUIEventAdapter& ea, int& key, int& modifiers);
-    bool resizable;
-    bool mouseWarped;
-    // workaround for osgViewer double scroll events
-    bool scrollButtonPressed;
-    int release_keys[128];
-    void handleStats(osgGA::GUIActionAdapter& us);
-    bool changeStatsCameraRenderOrder;
-};
-
-void eventToWindowCoords(const osgGA::GUIEventAdapter* ea, double& x, double& y);
-void eventToWindowCoordsYDown(const osgGA::GUIEventAdapter* ea,
-                              double& x, double& y);
-}
-#endif
diff --git a/src/Main/WindowBuilder.cxx b/src/Main/WindowBuilder.cxx
deleted file mode 100644 (file)
index 239a5e6..0000000
+++ /dev/null
@@ -1,258 +0,0 @@
-// Copyright (C) 2008  Tim Moore
-//
-// This program is free software; you can redistribute it and/or
-// modify it under the terms of the GNU General Public License as
-// published by the Free Software Foundation; either version 2 of the
-// License, or (at your option) any later version.
-//
-// This program is distributed in the hope that it will be useful, but
-// WITHOUT ANY WARRANTY; without even the implied warranty of
-// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
-// General Public License for more details.
-//
-// You should have received a copy of the GNU General Public License
-// along with this program; if not, write to the Free Software
-// Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
-
-#ifdef HAVE_CONFIG_H
-#  include "config.h"
-#endif
-
-#include "WindowBuilder.hxx"
-
-#include "WindowSystemAdapter.hxx"
-#include "fg_props.hxx"
-
-#include <sstream>
-
-using namespace std;
-using namespace osg;
-
-namespace flightgear
-{
-string makeName(const string& prefix, int num)
-{
-    stringstream stream;
-    stream << prefix << num;
-    return stream.str();
-}
-
-ref_ptr<WindowBuilder> WindowBuilder::windowBuilder;
-
-const string WindowBuilder::defaultWindowName("FlightGear");
-
-void WindowBuilder::initWindowBuilder(bool stencil)
-{
-    windowBuilder = new WindowBuilder(stencil);
-}
-
-WindowBuilder::WindowBuilder(bool stencil) : defaultCounter(0)
-{
-    defaultTraits = makeDefaultTraits(stencil);
-}
-
-GraphicsContext::Traits*
-WindowBuilder::makeDefaultTraits(bool stencil)
-{
-    GraphicsContext::WindowingSystemInterface* wsi
-        = osg::GraphicsContext::getWindowingSystemInterface();
-    GraphicsContext::Traits* traits = new osg::GraphicsContext::Traits;
-
-    traits->readDISPLAY();
-    if (traits->displayNum < 0)
-        traits->displayNum = 0;
-    if (traits->screenNum < 0)
-        traits->screenNum = 0;
-
-    int bpp = fgGetInt("/sim/rendering/bits-per-pixel");
-    bool alpha = fgGetBool("/sim/rendering/clouds3d-enable");
-    int cbits = (bpp <= 16) ?  5 :  8;
-    int zbits = (bpp <= 16) ? 16 : 24;
-    traits->red = traits->green = traits->blue = cbits;
-    traits->depth = zbits;
-    if (alpha)
-        traits->alpha = 8;
-
-    if (stencil)
-        traits->stencil = 8;
-
-    unsigned screenwidth = 0;
-    unsigned screenheight = 0;
-    wsi->getScreenResolution(*traits, screenwidth, screenheight);
-
-    traits->doubleBuffer = true;
-    traits->mipMapGeneration = true;
-    traits->windowName = "FlightGear";
-    // XXX should check per window too.
-    traits->sampleBuffers = fgGetInt("/sim/rendering/multi-sample-buffers", traits->sampleBuffers);
-    traits->samples = fgGetInt("/sim/rendering/multi-samples", traits->samples);
-    traits->vsync = fgGetBool("/sim/rendering/vsync-enable", traits->vsync);
-    traits->windowDecoration = !fgGetBool("/sim/startup/fullscreen");
-
-    if (!traits->windowDecoration) {
-        // fullscreen
-        traits->supportsResize = false;
-        traits->width = screenwidth;
-        traits->height = screenheight;
-        SG_LOG(SG_VIEW,SG_DEBUG,"Using full screen size for window: " << screenwidth << " x " << screenheight);
-    } else {
-        // window
-        int w = fgGetInt("/sim/startup/xsize");
-        int h = fgGetInt("/sim/startup/ysize");
-        traits->supportsResize = true;
-        traits->width = w;
-        traits->height = h;
-        if ((w>0)&&(h>0))
-        {
-            traits->x = ((unsigned)w>screenwidth) ? 0 : (screenwidth-w)/3;
-            traits->y = ((unsigned)h>screenheight) ? 0 : (screenheight-h)/3;
-        }
-        SG_LOG(SG_VIEW,SG_DEBUG,"Using initial window size: " << w << " x " << h);
-    }
-    return traits;
-}
-}
-
-namespace
-{
-// Helper functions that set a value based on a property if it exists,
-// returning 1 if the value was set.
-
-inline int setFromProperty(string& place, const SGPropertyNode* node,
-                            const char* name)
-{
-    const SGPropertyNode* valNode = node->getNode(name);
-    if (valNode) {
-        place = valNode->getStringValue();
-        return 1;
-    }
-    return 0;
-}
-
-inline int setFromProperty(int& place, const SGPropertyNode* node,
-                            const char* name)
-{
-    const SGPropertyNode* valNode = node->getNode(name);
-    if (valNode) {
-        place = valNode->getIntValue();
-        return 1;
-    }
-    return 0;
-}
-
-inline int setFromProperty(bool& place, const SGPropertyNode* node,
-                            const char* name)
-{
-    const SGPropertyNode* valNode = node->getNode(name);
-    if (valNode) {
-        place = valNode->getBoolValue();
-        return 1;
-    }
-    return 0;
-}
-}
-
-namespace flightgear
-{
-GraphicsWindow* WindowBuilder::buildWindow(const SGPropertyNode* winNode)
-{
-    GraphicsContext::WindowingSystemInterface* wsi
-        = osg::GraphicsContext::getWindowingSystemInterface();
-    WindowSystemAdapter* wsa = WindowSystemAdapter::getWSA();
-    string windowName;
-    if (winNode->hasChild("window-name"))
-        windowName = winNode->getStringValue("window-name");
-    else if (winNode->hasChild("name"))
-        windowName = winNode->getStringValue("name");
-    GraphicsWindow* result = 0;
-    if (!windowName.empty()) {
-        result = wsa->findWindow(windowName);
-        if (result)
-            return result;
-    }
-    GraphicsContext::Traits* traits
-        = new GraphicsContext::Traits(*defaultTraits);
-    int traitsSet = setFromProperty(traits->hostName, winNode, "host-name");
-    traitsSet |= setFromProperty(traits->displayNum, winNode, "display");
-    traitsSet |= setFromProperty(traits->screenNum, winNode, "screen");
-
-    const SGPropertyNode* fullscreenNode = winNode->getNode("fullscreen");
-
-    if (fullscreenNode && fullscreenNode->getBoolValue()) {
-        // fullscreen mode
-        unsigned width = 0;
-        unsigned height = 0;
-        wsi->getScreenResolution(*traits, width, height);
-        traits->windowDecoration = false;
-        traits->width = width;
-        traits->height = height;
-        traits->supportsResize = false;
-        traits->x = 0;
-        traits->y = 0;
-        traitsSet = 1;
-    } else {
-        int resizable = 0;
-        if (fullscreenNode && !fullscreenNode->getBoolValue())
-        {
-            traits->windowDecoration = true;
-            resizable = 1;
-        }
-        resizable |= setFromProperty(traits->windowDecoration, winNode,
-                                     "decoration");
-        resizable |= setFromProperty(traits->width, winNode, "width");
-        resizable |= setFromProperty(traits->height, winNode, "height");
-        if (resizable) {
-            traits->supportsResize = true;
-            traitsSet = 1;
-        }
-        // Otherwise use default values.
-    }
-    traitsSet |= setFromProperty(traits->x, winNode, "x");
-    traitsSet |= setFromProperty(traits->y, winNode, "y");
-    if (!windowName.empty() && windowName != traits->windowName) {
-        traits->windowName = windowName;
-        traitsSet = 1;
-    } else if (traitsSet) {
-        traits->windowName = makeName("FlightGear", defaultCounter++);
-    }
-    bool drawGUI = false;
-    traitsSet |= setFromProperty(drawGUI, winNode, "gui");
-    if (traitsSet) {
-        GraphicsContext* gc = GraphicsContext::createGraphicsContext(traits);
-        if (gc) {
-            GraphicsWindow* window = WindowSystemAdapter::getWSA()
-                ->registerWindow(gc, traits->windowName);
-            if (drawGUI)
-                window->flags |= GraphicsWindow::GUI;
-            return window;
-        } else {
-            return 0;
-        }
-    } else {
-        // XXX What if the window has no traits, but does have a name?
-        // We should create a "default window" registered with that name.
-        return getDefaultWindow();
-    }
-}
-
-GraphicsWindow* WindowBuilder::getDefaultWindow()
-{
-    GraphicsWindow* defaultWindow
-        = WindowSystemAdapter::getWSA()->findWindow(defaultWindowName);
-    if (defaultWindow)
-        return defaultWindow;
-    GraphicsContext::Traits* traits
-        = new GraphicsContext::Traits(*defaultTraits);
-    traits->windowName = "FlightGear";
-    
-    GraphicsContext* gc = GraphicsContext::createGraphicsContext(traits);
-    if (gc) {
-        defaultWindow = WindowSystemAdapter::getWSA()
-            ->registerWindow(gc, defaultWindowName);
-        return defaultWindow;
-    } else {
-        SG_LOG(SG_VIEW, SG_ALERT, "getDefaultWindow: failed to create GraphicsContext");
-        return 0;
-    }
-}
-}
diff --git a/src/Main/WindowBuilder.hxx b/src/Main/WindowBuilder.hxx
deleted file mode 100644 (file)
index 92e158b..0000000
+++ /dev/null
@@ -1,75 +0,0 @@
-// Copyright (C) 2008  Tim Moore
-//
-// This program is free software; you can redistribute it and/or
-// modify it under the terms of the GNU General Public License as
-// published by the Free Software Foundation; either version 2 of the
-// License, or (at your option) any later version.
-//
-// This program is distributed in the hope that it will be useful, but
-// WITHOUT ANY WARRANTY; without even the implied warranty of
-// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
-// General Public License for more details.
-//
-// You should have received a copy of the GNU General Public License
-// along with this program; if not, write to the Free Software
-// Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
-
-#ifndef FLIGHTGEAR_WINDOWBUILDER_HXX
-#define FLIGHTGEAR_WINDOWBUILDER_HXX 1
-
-#include <osg/ref_ptr>
-#include <osg/Referenced>
-#include <osg/GraphicsContext>
-
-#include <string>
-
-class SGPropertyNode;
-
-namespace flightgear
-{
-class GraphicsWindow;
-/** Singleton Builder class for creating a GraphicsWindow from property
- * nodes. This involves initializing an osg::GraphicsContext::Traits
- * structure from the property node values and creating an
- * osgViewer::GraphicsWindow.
- */
-class WindowBuilder : public osg::Referenced
-{
-public:
-    /** Initialize the singleton window builder.
-     * @param stencil whether windows should allocate stencil planes
-     */
-    static void initWindowBuilder(bool stencil);
-    /** Get the singleton window builder
-     */
-    static WindowBuilder* getWindowBuilder() { return windowBuilder.get(); }
-    /** Create a window from its property node description.
-     * @param winNode The window's root property node
-     * @return a graphics window.
-     */
-    GraphicsWindow* buildWindow(const SGPropertyNode* winNode);
-    /** Get a window whose properties come from FlightGear's
-     * command line arguments and their defaults. The window is opened
-     * if it has not been already.
-     * @return the default graphics window
-     */
-    GraphicsWindow* getDefaultWindow();
-    /** Get the name used to look up the default window.
-     */
-    const std::string& getDefaultWindowName() { return defaultWindowName; }
-protected:
-    WindowBuilder(bool stencil);
-    static osg::GraphicsContext::Traits* makeDefaultTraits(bool stencil);
-    osg::ref_ptr<osg::GraphicsContext::Traits> defaultTraits;
-    int defaultCounter;
-    static osg::ref_ptr<WindowBuilder> windowBuilder;
-    static const std::string defaultWindowName;
-};
-
-/** Silly function for making the default window and camera
- * names. This concatenates a string with in integer.
- */
-std::string makeName(const std::string& prefix, int num);
-
-}
-#endif
diff --git a/src/Main/WindowSystemAdapter.cxx b/src/Main/WindowSystemAdapter.cxx
deleted file mode 100644 (file)
index 9da3400..0000000
+++ /dev/null
@@ -1,97 +0,0 @@
-// Copyright (C) 2008 Tim Moore
-//
-// This program is free software; you can redistribute it and/or
-// modify it under the terms of the GNU General Public License as
-// published by the Free Software Foundation; either version 2 of the
-// License, or (at your option) any later version.
-//
-// This program is distributed in the hope that it will be useful, but
-// WITHOUT ANY WARRANTY; without even the implied warranty of
-// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
-// General Public License for more details.
-//
-// You should have received a copy of the GNU General Public License
-// along with this program; if not, write to the Free Software
-// Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
-#ifdef HAVE_CONFIG_H
-#  include <config.h>
-#endif
-
-#include <plib/pu.h>
-
-#include<algorithm>
-#include <functional>
-
-#include "CameraGroup.hxx"
-#include "WindowSystemAdapter.hxx"
-
-#include <osg/Camera>
-#include <osg/GraphicsContext>
-#include <osg/Viewport>
-
-using namespace osg;
-using namespace std;
-
-namespace flightgear
-{
-ref_ptr<WindowSystemAdapter> WindowSystemAdapter::_wsa;
-
-void GraphicsContextOperation::operator()(GraphicsContext* gc)
-{
-    run(gc);
-    ++done;
-}
-
-WindowSystemAdapter::WindowSystemAdapter() :
-    _nextWindowID(0), _isPuInitialized(false)
-{
-}
-
-GraphicsWindow*
-WindowSystemAdapter::registerWindow(GraphicsContext* gc,
-                                    const string& windowName)
-{
-    GraphicsWindow* window = new GraphicsWindow(gc, windowName,
-                                                _nextWindowID++);
-    windows.push_back(window);
-    return window;
-}
-
-// The pu getWindow callback is supposed to return a window ID that
-// would allow drawing a GUI on different windows. All that stuff is
-// broken in multi-threaded OSG, and we only have one GUI "window"
-// anyway, so just return a constant. 
-int WindowSystemAdapter::puGetWindow()
-{
-    return 1;
-}
-
-void WindowSystemAdapter::puGetWindowSize(int* width, int* height)
-{
-    *width = 0;
-    *height = 0;
-    Camera* camera = getGUICamera(CameraGroup::getDefault());
-    if (!camera)
-        return;
-    Viewport* vport = camera->getViewport();
-    *width = (int)vport->width();
-    *height = (int)vport->height();
-}
-
-void WindowSystemAdapter::puInitialize()
-{
-    puSetWindowFuncs(puGetWindow, 0, puGetWindowSize, 0);
-    puRealInit();
-}
-
-GraphicsWindow* WindowSystemAdapter::findWindow(const string& name)
-{
-    for (WindowVector::iterator iter = windows.begin(), e = windows.end();
-         iter != e;
-         ++iter) {
-        if ((*iter)->name == name)
-            return iter->get();
-    }
-    return 0;
-}
-}
diff --git a/src/Main/WindowSystemAdapter.hxx b/src/Main/WindowSystemAdapter.hxx
deleted file mode 100644 (file)
index b359f8e..0000000
+++ /dev/null
@@ -1,165 +0,0 @@
-// Copyright (C) 2008 Tim Moore
-//
-// This program is free software; you can redistribute it and/or
-// modify it under the terms of the GNU General Public License as
-// published by the Free Software Foundation; either version 2 of the
-// License, or (at your option) any later version.
-//
-// This program is distributed in the hope that it will be useful, but
-// WITHOUT ANY WARRANTY; without even the implied warranty of
-// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
-// General Public License for more details.
-//
-// You should have received a copy of the GNU General Public License
-// along with this program; if not, write to the Free Software
-// Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
-
-#ifndef FLIGHTGEAR_WINDOWSYSTEMADAPTER_HXX
-#define FLIGHTGEAR_WINDOWSYSTEMADAPTER_HXX 1
-
-#include <functional>
-#include <string>
-
-#include <osg/Referenced>
-#include <osg/Camera>
-#include <osg/GraphicsThread>
-#include <osg/ref_ptr>
-
-#include <simgear/structure/SGAtomic.hxx>
-
-namespace osg
-{
-class GraphicsContext;
-}
-
-// Flexible window support
-namespace flightgear
-{
-/** A window with a graphics context and an integer ID
- */
-class GraphicsWindow : public osg::Referenced
-{
-public:
-    GraphicsWindow(osg::GraphicsContext* gc_, const std::string& name_,
-                   int id_, unsigned flags_ = 0) :
-        gc(gc_), name(name_), id(id_), flags(flags_)
-    {
-    }
-    /** The OSG graphics context for this window.
-     */
-    osg::ref_ptr<osg::GraphicsContext> gc;
-    /** The window's internal name.
-     */
-    std::string name;
-    /** A unique ID for the window.
-     */
-    int id;
-    enum Flags {
-        GUI = 1 /**< The GUI (and 2D cockpit) will be drawn on this window. */
-    };
-    /** Flags for the window.
-     */
-    unsigned flags;
-};
-
-typedef std::vector<osg::ref_ptr<GraphicsWindow> >  WindowVector;
-
-/**
- * An operation that is run once with a particular GraphicsContext
- * current. It will probably be deferred and may run in a different
- * thread.
- */
-class GraphicsContextOperation : public osg::GraphicsOperation
-{
-public:
-    GraphicsContextOperation(const std::string& name) :
-        osg::GraphicsOperation(name, false)
-    {
-    }
-    /** Don't override this!
-     */
-    virtual void operator()(osg::GraphicsContext* gc);
-    /** The body of the operation.
-     */
-    virtual void run(osg::GraphicsContext* gc) = 0;
-    /** Test if the operation has completed.
-     * @return true if the run() method has finished.
-     */
-    bool isFinished() const { return done != 0; }
-private:
-    SGAtomic done;
-};
-
-/** Adapter from windows system / graphics context management API to
- * functions used by flightgear. This papers over the difference
- * between osgViewer::Viewer, which handles multiple windows, graphics
- * threads, etc., and the embedded viewer used with GLUT and SDL.
- */
-class WindowSystemAdapter : public osg::Referenced
-{
-public:
-    WindowSystemAdapter();
-    virtual ~WindowSystemAdapter() {}
-    /** Vector of all the registered windows.
-     */
-    WindowVector windows;
-    /** Register a window, assigning  it an ID.
-     * @param gc graphics context
-     * @param windowName internal name (not displayed)
-     * @return a graphics window
-     */
-    GraphicsWindow* registerWindow(osg::GraphicsContext* gc,
-                                   const std::string& windowName);
-    /** Initialize the plib pui interface library. This might happen
-     *in another thread and may be deferred.
-     */
-    virtual void puInitialize();
-    /** Find a window by name.
-     * @param name the window name
-     * @return the window or 0
-     */
-    GraphicsWindow* findWindow(const std::string& name);
-    /** Get the global WindowSystemAdapter
-     * @return the adapter
-     */
-    static WindowSystemAdapter* getWSA() { return _wsa.get(); }
-    /** Set the global adapter
-     * @param wsa the adapter
-     */
-    static void setWSA(WindowSystemAdapter* wsa) { _wsa = wsa; }
-protected:
-    int _nextWindowID;
-    osg::ref_ptr<GraphicsContextOperation> _puInitOp;
-    bool _isPuInitialized;
-    static osg::ref_ptr<WindowSystemAdapter> _wsa;
-    // Default callbacks for plib
-    static int puGetWindow();
-    static void puGetWindowSize(int* width, int* height);
-
-};
-
-/**
- * Class for testing if flags are set in an object with a flags member.
- */
-template<typename T>
-class FlagTester : public std::unary_function<osg::ref_ptr<T>, bool>
-{
-public:
-    /** Initialize with flags to test for.
-     * @param flags logical or of flags to test.
-     */
-    FlagTester(unsigned flags_) : flags(flags_) {}
-    /** test operator
-     * @param obj An object with a flags member
-     * @return true if flags member of obj contains any of the flags
-     * (bitwise and with flags is nonzero).
-     */
-    bool operator() (const osg::ref_ptr<T>& obj)
-    {
-        return (obj->flags & flags) != 0;
-    }
-    unsigned flags;
-};
-
-}
-#endif
index a5d5c2a47f8640f027144da4f139336316132397..0f43f766a465fe70a05956194a1f737fc4b4e802 100644 (file)
 using std::cerr;
 using std::endl;
 
+#include <Viewer/fgviewer.hxx>
 #include "main.hxx"
 #include "globals.hxx"
 #include "fg_props.hxx"
-#include "fgviewer.hxx"
 
 
 #include "fg_os.hxx"
index 60822e2d9f3f12205d8f445d08a520cd43e0775d..4c7e0ffaf3583941792b49ea021c9e9d32bc1321 100644 (file)
@@ -38,6 +38,9 @@
 #include <Sound/sample_queue.hxx>
 #include <Airports/xmlloader.hxx>
 #include <Network/HTTPClient.hxx>
+#include <Viewer/viewmgr.hxx>
+#include <Viewer/viewer.hxx>
+#include <Environment/presets.hxx>
 
 #include "fg_init.hxx"
 #include "fg_io.hxx"
 #include "globals.hxx"
 #include "logger.hxx"
 #include "util.hxx"
-#include "viewmgr.hxx"
 #include "main.hxx"
-#include <Main/viewer.hxx>
-#include <Environment/presets.hxx>
 
 #include <boost/scoped_array.hpp>
 
index 134a34416c5164691d20879d7054c47d860c8b0c..e1bcc06210a47092f17ba2b40e420fcfc4955823 100644 (file)
 #include <FDM/fdm_shell.hxx>
 #include <Environment/ephemeris.hxx>
 #include <Environment/environment_mgr.hxx>
+#include <Viewer/renderer.hxx>
+#include <Viewer/viewmgr.hxx>
 
 #include "fg_init.hxx"
 #include "fg_io.hxx"
 #include "options.hxx"
 #include "globals.hxx"
 #include "logger.hxx"
-#include "renderer.hxx"
-#include "viewmgr.hxx"
 #include "main.hxx"
 
 
index cba760bb91e02ffc698406c8a3a797c55146bb39..3dd07c610a81bf6e12043d5a5791211cb51d45ab 100644 (file)
 #include <plib/pu.h>
 #include <osg/GraphicsContext>
 
+#include <Viewer/renderer.hxx>
+#include <Viewer/FGEventHandler.hxx>
 #include "fg_os.hxx"
 #include "globals.hxx"
-#include "renderer.hxx"
-#include "FGEventHandler.hxx"
 
 // fg_os callback registration APIs
 //
diff --git a/src/Main/fg_os_osgviewer.cxx b/src/Main/fg_os_osgviewer.cxx
deleted file mode 100644 (file)
index e8ba901..0000000
+++ /dev/null
@@ -1,376 +0,0 @@
-// fg_os_osgviewer.cxx -- common functions for fg_os interface
-// implemented as an osgViewer
-//
-// Copyright (C) 2007  Tim Moore timoore@redhat.com
-// Copyright (C) 2007 Mathias Froehlich 
-//
-// This program is free software; you can redistribute it and/or
-// modify it under the terms of the GNU General Public License as
-// published by the Free Software Foundation; either version 2 of the
-// License, or (at your option) any later version.
-//
-// This program is distributed in the hope that it will be useful, but
-// WITHOUT ANY WARRANTY; without even the implied warranty of
-// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
-// General Public License for more details.
-//
-// You should have received a copy of the GNU General Public License
-// along with this program; if not, write to the Free Software
-// Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
-
-#ifdef HAVE_CONFIG_H
-#include <config.h>
-#endif
-
-#include <algorithm>
-#include <iostream>
-#include <sstream>
-#include <string>
-
-#include <stdlib.h>
-
-#include <boost/foreach.hpp>
-
-#include <simgear/compiler.h>
-#include <simgear/structure/exception.hxx>
-#include <simgear/debug/logstream.hxx>
-#include <simgear/props/props_io.hxx>
-
-#include <osg/Camera>
-#include <osg/GraphicsContext>
-#include <osg/Group>
-#include <osg/Matrixd>
-#include <osg/Viewport>
-#include <osg/Version>
-#include <osg/View>
-#include <osgViewer/ViewerEventHandlers>
-#include <osgViewer/Viewer>
-#include <osgViewer/GraphicsWindow>
-
-#include <Scenery/scenery.hxx>
-#include "fg_os.hxx"
-#include "fg_props.hxx"
-#include "util.hxx"
-#include "globals.hxx"
-#include "renderer.hxx"
-#include "CameraGroup.hxx"
-#include "FGEventHandler.hxx"
-#include "WindowBuilder.hxx"
-#include "WindowSystemAdapter.hxx"
-
-// Static linking of OSG needs special macros
-#ifdef OSG_LIBRARY_STATIC
-#include <osgDB/Registry>
-USE_GRAPHICSWINDOW();
-// Image formats
-USE_OSGPLUGIN(bmp);
-USE_OSGPLUGIN(dds);
-USE_OSGPLUGIN(hdr);
-USE_OSGPLUGIN(pic);
-USE_OSGPLUGIN(pnm);
-USE_OSGPLUGIN(rgb);
-USE_OSGPLUGIN(tga);
-#ifdef OSG_JPEG_ENABLED
-  USE_OSGPLUGIN(jpeg);
-#endif
-#ifdef OSG_PNG_ENABLED
-  USE_OSGPLUGIN(png);
-#endif
-#ifdef OSG_TIFF_ENABLED
-  USE_OSGPLUGIN(tiff);
-#endif
-// Model formats
-USE_OSGPLUGIN(3ds);
-USE_OSGPLUGIN(ac);
-USE_OSGPLUGIN(ive);
-USE_OSGPLUGIN(osg);
-USE_OSGPLUGIN(txf);
-#endif
-
-// fg_os implementation using OpenSceneGraph's osgViewer::Viewer class
-// to create the graphics window and run the event/update/render loop.
-
-//
-// fg_os implementation
-//
-
-using namespace std;    
-using namespace flightgear;
-using namespace osg;
-
-static osg::ref_ptr<osgViewer::Viewer> viewer;
-static osg::ref_ptr<osg::Camera> mainCamera;
-
-static void setStereoMode( const char * mode )
-{
-    DisplaySettings::StereoMode stereoMode = DisplaySettings::QUAD_BUFFER;
-    bool stereoOn = true;
-
-    if (strcmp(mode,"QUAD_BUFFER")==0)
-    {
-        stereoMode = DisplaySettings::QUAD_BUFFER;
-    }
-    else if (strcmp(mode,"ANAGLYPHIC")==0)
-    {
-        stereoMode = DisplaySettings::ANAGLYPHIC;
-    }
-    else if (strcmp(mode,"HORIZONTAL_SPLIT")==0)
-    {
-        stereoMode = DisplaySettings::HORIZONTAL_SPLIT;
-    }
-    else if (strcmp(mode,"VERTICAL_SPLIT")==0)
-    {
-        stereoMode = DisplaySettings::VERTICAL_SPLIT;
-    }
-    else if (strcmp(mode,"LEFT_EYE")==0)
-    {
-        stereoMode = DisplaySettings::LEFT_EYE;
-    }
-    else if (strcmp(mode,"RIGHT_EYE")==0)
-    {
-        stereoMode = DisplaySettings::RIGHT_EYE;
-    }
-    else if (strcmp(mode,"HORIZONTAL_INTERLACE")==0)
-    {
-        stereoMode = DisplaySettings::HORIZONTAL_INTERLACE;
-    }
-    else if (strcmp(mode,"VERTICAL_INTERLACE")==0)
-    {
-        stereoMode = DisplaySettings::VERTICAL_INTERLACE;
-    }
-    else if (strcmp(mode,"CHECKERBOARD")==0)
-    {
-        stereoMode = DisplaySettings::CHECKERBOARD;
-    } else {
-        stereoOn = false; 
-    }
-    DisplaySettings::instance()->setStereo( stereoOn );
-    DisplaySettings::instance()->setStereoMode( stereoMode );
-}
-
-static const char * getStereoMode()
-{
-    DisplaySettings::StereoMode stereoMode = DisplaySettings::instance()->getStereoMode();
-    bool stereoOn = DisplaySettings::instance()->getStereo();
-    if( !stereoOn ) return "OFF";
-    if( stereoMode == DisplaySettings::QUAD_BUFFER ) {
-        return "QUAD_BUFFER";
-    } else if( stereoMode == DisplaySettings::ANAGLYPHIC ) {
-        return "ANAGLYPHIC";
-    } else if( stereoMode == DisplaySettings::HORIZONTAL_SPLIT ) {
-        return "HORIZONTAL_SPLIT";
-    } else if( stereoMode == DisplaySettings::VERTICAL_SPLIT ) {
-        return "VERTICAL_SPLIT";
-    } else if( stereoMode == DisplaySettings::LEFT_EYE ) {
-        return "LEFT_EYE";
-    } else if( stereoMode == DisplaySettings::RIGHT_EYE ) {
-        return "RIGHT_EYE";
-    } else if( stereoMode == DisplaySettings::HORIZONTAL_INTERLACE ) {
-        return "HORIZONTAL_INTERLACE";
-    } else if( stereoMode == DisplaySettings::VERTICAL_INTERLACE ) {
-        return "VERTICAL_INTERLACE";
-    } else if( stereoMode == DisplaySettings::CHECKERBOARD ) {
-        return "CHECKERBOARD";
-    } 
-    return "OFF";
-}
-
-void fgOSOpenWindow(bool stencil)
-{
-    viewer = new osgViewer::Viewer;
-    viewer->setDatabasePager(FGScenery::getPagerSingleton());
-    CameraGroup* cameraGroup = 0;
-    std::string mode;
-    mode = fgGetString("/sim/rendering/multithreading-mode", "SingleThreaded");
-    if (mode == "AutomaticSelection")
-      viewer->setThreadingModel(osgViewer::Viewer::AutomaticSelection);
-    else if (mode == "CullDrawThreadPerContext")
-      viewer->setThreadingModel(osgViewer::Viewer::CullDrawThreadPerContext);
-    else if (mode == "DrawThreadPerContext")
-      viewer->setThreadingModel(osgViewer::Viewer::DrawThreadPerContext);
-    else if (mode == "CullThreadPerCameraDrawThreadPerContext")
-      viewer->setThreadingModel(osgViewer::Viewer::CullThreadPerCameraDrawThreadPerContext);
-    else
-      viewer->setThreadingModel(osgViewer::Viewer::SingleThreaded);
-    WindowBuilder::initWindowBuilder(stencil);
-    WindowBuilder *windowBuilder = WindowBuilder::getWindowBuilder();
-
-    // Look for windows, camera groups, and the old syntax of
-    // top-level cameras
-    SGPropertyNode* renderingNode = fgGetNode("/sim/rendering");
-    SGPropertyNode* cgroupNode = renderingNode->getNode("camera-group", true);
-    bool oldSyntax = !cgroupNode->hasChild("camera");
-    if (oldSyntax) {
-        for (int i = 0; i < renderingNode->nChildren(); ++i) {
-            SGPropertyNode* propNode = renderingNode->getChild(i);
-            const char* propName = propNode->getName();
-            if (!strcmp(propName, "window") || !strcmp(propName, "camera")) {
-                SGPropertyNode* copiedNode
-                    = cgroupNode->getNode(propName, propNode->getIndex(), true);
-                copyProperties(propNode, copiedNode);
-            }
-        }
-        vector<SGPropertyNode_ptr> cameras = cgroupNode->getChildren("camera");
-        SGPropertyNode* masterCamera = 0;
-        BOOST_FOREACH(SGPropertyNode_ptr& camera, cameras) {
-            if (camera->getDoubleValue("shear-x", 0.0) == 0.0
-                && camera->getDoubleValue("shear-y", 0.0) == 0.0) {
-                masterCamera = camera.ptr();
-                break;
-            }
-        }
-        if (!masterCamera) {
-            masterCamera = cgroupNode->getChild("camera", cameras.size(), true);
-            setValue(masterCamera->getNode("window/name", true),
-                     windowBuilder->getDefaultWindowName());
-        }
-        SGPropertyNode* nameNode = masterCamera->getNode("window/name");
-        if (nameNode)
-            setValue(cgroupNode->getNode("gui/window/name", true),
-                     nameNode->getStringValue());
-    }
-    cameraGroup = CameraGroup::buildCameraGroup(viewer.get(), cgroupNode);
-    Camera* guiCamera = getGUICamera(cameraGroup);
-    if (guiCamera) {
-        Viewport* guiViewport = guiCamera->getViewport();
-        fgSetInt("/sim/startup/xsize", guiViewport->width());
-        fgSetInt("/sim/startup/ysize", guiViewport->height());
-    }
-    FGEventHandler* manipulator = globals->get_renderer()->getEventHandler();
-    WindowSystemAdapter* wsa = WindowSystemAdapter::getWSA();
-    if (wsa->windows.size() != 1) {
-        manipulator->setResizable(false);
-    }
-    viewer->getCamera()->setProjectionResizePolicy(osg::Camera::FIXED);
-    viewer->addEventHandler(manipulator);
-    // Let FG handle the escape key with a confirmation
-    viewer->setKeyEventSetsDone(0);
-    // The viewer won't start without some root.
-    viewer->setSceneData(new osg::Group);
-    globals->get_renderer()->setViewer(viewer.get());
-    CameraGroup::setDefault(cameraGroup);
-
-    DisplaySettings * displaySettings = DisplaySettings::instance();
-    fgTie("/sim/rendering/osg-displaysettings/eye-separation", displaySettings, &DisplaySettings::getEyeSeparation, &DisplaySettings::setEyeSeparation );
-    fgTie("/sim/rendering/osg-displaysettings/screen-distance", displaySettings, &DisplaySettings::getScreenDistance, &DisplaySettings::setScreenDistance );
-    fgTie("/sim/rendering/osg-displaysettings/screen-width", displaySettings, &DisplaySettings::getScreenWidth, &DisplaySettings::setScreenWidth );
-    fgTie("/sim/rendering/osg-displaysettings/screen-height", displaySettings, &DisplaySettings::getScreenHeight, &DisplaySettings::setScreenHeight );
-    fgTie("/sim/rendering/osg-displaysettings/stereo-mode", getStereoMode, setStereoMode );
-    fgTie("/sim/rendering/osg-displaysettings/double-buffer", displaySettings, &DisplaySettings::getDoubleBuffer, &DisplaySettings::setDoubleBuffer );
-    fgTie("/sim/rendering/osg-displaysettings/depth-buffer", displaySettings, &DisplaySettings::getDepthBuffer, &DisplaySettings::setDepthBuffer );
-    fgTie("/sim/rendering/osg-displaysettings/rgb", displaySettings, &DisplaySettings::getRGB, &DisplaySettings::setRGB );
-}
-
-
-static int status = 0;
-
-void fgOSExit(int code)
-{
-    viewer->setDone(true);
-    viewer->getDatabasePager()->cancel();
-    status = code;
-}
-
-int fgOSMainLoop()
-{
-    ref_ptr<FGEventHandler> manipulator
-        = globals->get_renderer()->getEventHandler();
-    viewer->setReleaseContextAtEndOfFrameHint(false);
-    if (!viewer->isRealized())
-        viewer->realize();
-    while (!viewer->done()) {
-        fgIdleHandler idleFunc = manipulator->getIdleHandler();
-        if (idleFunc)
-            (*idleFunc)();
-        globals->get_renderer()->update();
-        viewer->frame();
-    }
-    
-    return status;
-}
-
-int fgGetKeyModifiers()
-{
-    if (!globals->get_renderer()) { // happens during shutdown
-      return 0;
-    }
-    
-    return globals->get_renderer()->getEventHandler()->getCurrentModifiers();
-}
-
-void fgWarpMouse(int x, int y)
-{
-    warpGUIPointer(CameraGroup::getDefault(), x, y);
-}
-
-void fgOSInit(int* argc, char** argv)
-{
-    globals->get_renderer()->init();
-    WindowSystemAdapter::setWSA(new WindowSystemAdapter);
-}
-
-// Noop
-void fgOSFullScreen()
-{
-}
-
-static void setMouseCursor(osgViewer::GraphicsWindow* gw, int cursor)
-{
-    if (!gw) {
-        return;
-    }
-  
-    osgViewer::GraphicsWindow::MouseCursor mouseCursor;
-    mouseCursor = osgViewer::GraphicsWindow::InheritCursor;
-    if (cursor == MOUSE_CURSOR_NONE)
-        mouseCursor = osgViewer::GraphicsWindow::NoCursor;
-    else if(cursor == MOUSE_CURSOR_POINTER)
-#ifdef SG_MAC
-        // osgViewer-Cocoa lacks RightArrowCursor, use Left
-        mouseCursor = osgViewer::GraphicsWindow::LeftArrowCursor;
-#else
-        mouseCursor = osgViewer::GraphicsWindow::RightArrowCursor;
-#endif
-    else if(cursor == MOUSE_CURSOR_WAIT)
-        mouseCursor = osgViewer::GraphicsWindow::WaitCursor;
-    else if(cursor == MOUSE_CURSOR_CROSSHAIR)
-        mouseCursor = osgViewer::GraphicsWindow::CrosshairCursor;
-    else if(cursor == MOUSE_CURSOR_LEFTRIGHT)
-        mouseCursor = osgViewer::GraphicsWindow::LeftRightCursor;
-    else if(cursor == MOUSE_CURSOR_TOPSIDE)
-        mouseCursor = osgViewer::GraphicsWindow::TopSideCursor;
-    else if(cursor == MOUSE_CURSOR_BOTTOMSIDE)
-        mouseCursor = osgViewer::GraphicsWindow::BottomSideCursor;
-    else if(cursor == MOUSE_CURSOR_LEFTSIDE)
-        mouseCursor = osgViewer::GraphicsWindow::LeftSideCursor;
-    else if(cursor == MOUSE_CURSOR_RIGHTSIDE)
-        mouseCursor = osgViewer::GraphicsWindow::RightSideCursor;
-    else if(cursor == MOUSE_CURSOR_TOPLEFT)
-        mouseCursor = osgViewer::GraphicsWindow::TopLeftCorner;
-    else if(cursor == MOUSE_CURSOR_TOPRIGHT)
-        mouseCursor = osgViewer::GraphicsWindow::TopRightCorner;
-    else if(cursor == MOUSE_CURSOR_BOTTOMLEFT)
-        mouseCursor = osgViewer::GraphicsWindow::BottomLeftCorner;
-    else if(cursor == MOUSE_CURSOR_BOTTOMRIGHT)
-        mouseCursor = osgViewer::GraphicsWindow::BottomRightCorner;
-
-    gw->setCursor(mouseCursor);
-}
-
-static int _cursor = -1;
-
-void fgSetMouseCursor(int cursor)
-{
-    _cursor = cursor;
-  
-    std::vector<osgViewer::GraphicsWindow*> windows;
-    viewer->getWindows(windows);
-    BOOST_FOREACH(osgViewer::GraphicsWindow* gw, windows) {
-        setMouseCursor(gw, cursor);
-    }
-}
-
-int fgGetMouseCursor()
-{
-    return _cursor;
-}
diff --git a/src/Main/fgviewer.cxx b/src/Main/fgviewer.cxx
deleted file mode 100644 (file)
index 73c3cb2..0000000
+++ /dev/null
@@ -1,228 +0,0 @@
-#ifdef HAVE_CONFIG_H
-#  include "config.h"
-#endif
-
-#include <iostream>
-#include <cstdlib>
-
-#include <osg/ArgumentParser>
-#include <osg/Fog>
-#include <osgDB/ReadFile>
-#include <osgDB/Registry>
-#include <osgDB/WriteFile>
-#include <osgViewer/Renderer>
-#include <osgViewer/Viewer>
-#include <osgViewer/ViewerEventHandlers>
-#include <osgGA/KeySwitchMatrixManipulator>
-#include <osgGA/TrackballManipulator>
-#include <osgGA/FlightManipulator>
-#include <osgGA/DriveManipulator>
-#include <osgGA/TerrainManipulator>
-#include <osgGA/StateSetManipulator>
-
-#include <simgear/props/props.hxx>
-#include <simgear/props/props_io.hxx>
-#include <simgear/misc/sg_path.hxx>
-#include <simgear/scene/material/EffectCullVisitor.hxx>
-#include <simgear/scene/material/matlib.hxx>
-#include <simgear/scene/util/SGReaderWriterOptions.hxx>
-#include <simgear/scene/tgdb/userdata.hxx>
-#include <simgear/scene/model/ModelRegistry.hxx>
-#include <simgear/scene/model/modellib.hxx>
-
-#include <Scenery/scenery.hxx>
-
-#include "fg_init.hxx"
-#include "fg_props.hxx"
-#include "globals.hxx"
-#include "options.hxx"
-
-class GraphDumpHandler : public  osgGA::GUIEventHandler
-{
-public:
-    GraphDumpHandler() : _keyDump('d') {}
-    void setKeyDump(int key) { _keyDump = key; }
-    int getKeyDump() const { return _keyDump; }
-    bool handle(const osgGA::GUIEventAdapter& ea, osgGA::GUIActionAdapter& aa);
-
-    /** Get the keyboard and mouse usage of this manipulator.*/
-    virtual void getUsage(osg::ApplicationUsage& usage) const;
-protected:
-    int _keyDump;
-};
-
-static void dumpOut(osg::Node* node)
-{
-    char filename[24];
-    static int count = 1;
-
-    while (count < 1000) {
-        FILE *fp;
-        snprintf(filename, 24, "fgviewer-%03d.osg", count++);
-        if ( (fp = fopen(filename, "r")) == NULL )
-            break;
-        fclose(fp);
-    }
-
-    if (osgDB::writeNodeFile(*node, filename))
-        std::cerr << "Entire scene graph saved to \"" << filename << "\".\n";
-    else
-        std::cerr << "Failed to save to \"" << filename << "\".\n";
-}
-
-bool GraphDumpHandler::handle(const osgGA::GUIEventAdapter& ea,
-                              osgGA::GUIActionAdapter& aa)
-{
-    osgViewer::View* view = dynamic_cast<osgViewer::View*>(&aa);
-    if (!view)
-        return false;
-    if (ea.getHandled())
-        return false;
-    switch(ea.getEventType()) {
-    case osgGA::GUIEventAdapter::KEYUP:
-        if (ea.getKey() == _keyDump) {
-            dumpOut(view->getScene()->getSceneData());
-            return true;
-        }
-        break;
-    default:
-        return false;
-    }
-    return false;
-}
-
-void GraphDumpHandler::getUsage(osg::ApplicationUsage& usage) const
-{
-    std::ostringstream ostr;
-    ostr << char(_keyDump);
-            usage.addKeyboardMouseBinding(ostr.str(),
-                                          "Dump scene graph to file");
-}
-
-int
-fgviewerMain(int argc, char** argv)
-{
-
-    sgUserDataInit(0);
-
-    // use an ArgumentParser object to manage the program arguments.
-    osg::ArgumentParser arguments(&argc, argv);
-
-    // construct the viewer.
-    osgViewer::Viewer viewer(arguments);
-    osg::Camera* camera = viewer.getCamera();
-    osgViewer::Renderer* renderer
-        = static_cast<osgViewer::Renderer*>(camera->getRenderer());
-    for (int i = 0; i < 2; ++i) {
-        osgUtil::SceneView* sceneView = renderer->getSceneView(i);
-        sceneView->setCullVisitor(new simgear::EffectCullVisitor);
-    }
-    // Shaders expect valid fog
-    osg::StateSet* cameraSS = camera->getOrCreateStateSet();
-    osg::Fog* fog = new osg::Fog;
-    fog->setMode(osg::Fog::EXP2);
-    fog->setColor(osg::Vec4(1.0, 1.0, 1.0, 1.0));
-    fog->setDensity(.0000001);
-    cameraSS->setAttributeAndModes(fog);
-    // ... for some reason, get rid of that FIXME!
-    viewer.setThreadingModel(osgViewer::Viewer::SingleThreaded);
-
-    // set up the camera manipulators.
-    osgGA::KeySwitchMatrixManipulator* keyswitchManipulator;
-    keyswitchManipulator = new osgGA::KeySwitchMatrixManipulator;
-
-    keyswitchManipulator->addMatrixManipulator('1', "Trackball",
-                                               new osgGA::TrackballManipulator);
-    keyswitchManipulator->addMatrixManipulator('2', "Flight",
-                                               new osgGA::FlightManipulator);
-    keyswitchManipulator->addMatrixManipulator('3', "Drive",
-                                               new osgGA::DriveManipulator);
-    keyswitchManipulator->addMatrixManipulator('4', "Terrain",
-                                               new osgGA::TerrainManipulator);
-    viewer.setCameraManipulator(keyswitchManipulator);
-
-    // Usefull stats
-    viewer.addEventHandler(new osgViewer::HelpHandler);
-    viewer.addEventHandler(new osgViewer::StatsHandler);
-    viewer.addEventHandler( new osgGA::StateSetManipulator(viewer.getCamera()->getOrCreateStateSet()) );
-    // Same FIXME ...
-    // viewer.addEventHandler(new osgViewer::ThreadingHandler);
-    viewer.addEventHandler(new osgViewer::LODScaleHandler);
-    viewer.addEventHandler(new osgViewer::ScreenCaptureHandler);
-
-    viewer.addEventHandler(new GraphDumpHandler);
-
-    // Extract files to load from arguments now; this way fgInitConfig
-    // won't choke on them.
-    string_list dataFiles;
-    for (int i = arguments.argc() - 1; i >= 0; --i) {
-        if (arguments.isOption(i)) {
-            break;
-        } else {
-            dataFiles.insert(dataFiles.begin(), arguments[i]);
-            arguments.remove(i);
-        }
-    }
-
-    // A subset of full flightgear initialization.
-    // Allocate global data structures.  This needs to happen before
-    // we parse command line options
-
-    globals = new FGGlobals;
-
-    if ( !fgInitConfig(arguments.argc(), arguments.argv()) ) {
-        SG_LOG( SG_GENERAL, SG_ALERT, "Config option parsing failed ..." );
-        exit(-1);
-    }
-
-    osgDB::FilePathList filePathList
-        = osgDB::Registry::instance()->getDataFilePathList();
-    filePathList.push_back(globals->get_fg_root());
-
-    string_list path_list = globals->get_fg_scenery();
-    for (unsigned i = 0; i < path_list.size(); ++i) {
-        filePathList.push_back(path_list[i]);
-    }
-
-    globals->set_matlib( new SGMaterialLib );
-    simgear::SGModelLib::init(globals->get_fg_root(), globals->get_props());
-
-    // Initialize the material property subsystem.
-
-    SGPath mpath( globals->get_fg_root() );
-    mpath.append( fgGetString("/sim/rendering/materials-file") );
-    if ( ! globals->get_matlib()->load(globals->get_fg_root(), mpath.str(),
-            globals->get_props()) ) {
-        SG_LOG( SG_GENERAL, SG_ALERT,
-                "Error loading materials file " << mpath.str() );
-        exit(-1);
-    }
-
-    globals->set_scenery( new FGScenery );
-    globals->get_scenery()->init();
-    globals->get_scenery()->bind();
-
-    // The file path list must be set in the registry.
-    osgDB::Registry::instance()->getDataFilePathList() = filePathList;
-
-    simgear::SGReaderWriterOptions* options = new simgear::SGReaderWriterOptions;
-    options->getDatabasePathList() = filePathList;
-    options->setMaterialLib(globals->get_matlib());
-    options->setPropertyNode(globals->get_props());
-
-    // read the scene from the list of file specified command line args.
-    osg::ref_ptr<osg::Node> loadedModel;
-    loadedModel = osgDB::readNodeFiles(dataFiles, options);
-
-    // if no model has been successfully loaded report failure.
-    if (!loadedModel.valid()) {
-        std::cerr << arguments.getApplicationName()
-                  << ": No data loaded" << std::endl;
-        return EXIT_FAILURE;
-    }
-
-    // pass the loaded scene graph to the viewer.
-    viewer.setSceneData(loadedModel.get());
-
-    return viewer.run();
-}
diff --git a/src/Main/fgviewer.hxx b/src/Main/fgviewer.hxx
deleted file mode 100644 (file)
index 82cdf5e..0000000
+++ /dev/null
@@ -1,5 +0,0 @@
-#ifndef __FG_FGVIEWER_HXX
-#define __FG_FGVIEWER_HXX 1
-
-int fgviewerMain(int argc, char** argv);
-#endif
index 8adcd57ca5e201bd55c9d575209a81eb83d29796..2dd696ba9e12ceb81e913c135d932a4e41a335e1 100644 (file)
 #include <Scenery/scenery.hxx>
 #include <Scenery/tilemgr.hxx>
 #include <Navaids/navlist.hxx>
+#include <Viewer/renderer.hxx>
+#include <Viewer/viewmgr.hxx>
 
 #include "globals.hxx"
-#include "renderer.hxx"
-#include "viewmgr.hxx"
 #include "locale.hxx"
 
 #include "fg_props.hxx"
index dc6043af8f30c1039882bea1031dc79c9fd3eae9..ac3880f292ee41b8433f178f2739ca0688fadcdd 100644 (file)
 #include <GUI/gui.h>
 #include <GUI/new_gui.hxx>
 #include <MultiPlayer/multiplaymgr.hxx>
+#include <Viewer/CameraGroup.hxx>
+#include <Viewer/viewer.hxx>
+#include <Viewer/WindowSystemAdapter.hxx>
+#include <Viewer/splash.hxx>
+#include <Viewer/renderer.hxx>
 
-#include "CameraGroup.hxx"
 #include "fg_commands.hxx"
 #include "fg_io.hxx"
-#include "renderer.hxx"
-#include "splash.hxx"
 #include "main.hxx"
 #include "util.hxx"
 #include "fg_init.hxx"
 #include "fg_os.hxx"
-#include "WindowSystemAdapter.hxx"
-#include <Main/viewer.hxx>
-#include <Main/fg_props.hxx>
+#include "fg_props.hxx"
 
 using namespace flightgear;
 
index aba0650fe994eafa87db03f49c8ea324615c9785..52df477ac6767d5d93b18e6b18020c39287b9cfa 100644 (file)
 #include "fg_props.hxx"
 #include "options.hxx"
 #include "util.hxx"
-#include "viewmgr.hxx"
 #include "main.hxx"
-#include <Main/viewer.hxx>
-#include <Main/locale.hxx>
+#include "locale.hxx"
+#include <Viewer/viewer.hxx>
+#include <Viewer/viewmgr.hxx>
 #include <Environment/presets.hxx>
 
 #include <osg/Version>
diff --git a/src/Main/renderer.cxx b/src/Main/renderer.cxx
deleted file mode 100644 (file)
index c1e2b32..0000000
+++ /dev/null
@@ -1,2152 +0,0 @@
-// renderer.cxx -- top level sim routines
-//
-// Written by Curtis Olson, started May 1997.
-// This file contains parts of main.cxx prior to october 2004
-//
-// Copyright (C) 1997 - 2002  Curtis L. Olson  - http://www.flightgear.org/~curt
-//
-// This program is free software; you can redistribute it and/or
-// modify it under the terms of the GNU General Public License as
-// published by the Free Software Foundation; either version 2 of the
-// License, or (at your option) any later version.
-//
-// This program is distributed in the hope that it will be useful, but
-// WITHOUT ANY WARRANTY; without even the implied warranty of
-// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
-// General Public License for more details.
-//
-// You should have received a copy of the GNU General Public License
-// along with this program; if not, write to the Free Software
-// Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
-
-#ifdef HAVE_CONFIG_H
-#  include <config.h>
-#endif
-
-#ifdef HAVE_WINDOWS_H
-#  include <windows.h>
-#endif
-
-#include <simgear/compiler.h>
-
-#include <algorithm>
-#include <iostream>
-#include <map>
-#include <vector>
-#include <typeinfo>
-
-#include <osg/ref_ptr>
-#include <osg/AlphaFunc>
-#include <osg/BlendFunc>
-#include <osg/Camera>
-#include <osg/CullFace>
-#include <osg/CullStack>
-#include <osg/Depth>
-#include <osg/Fog>
-#include <osg/Group>
-#include <osg/Hint>
-#include <osg/Light>
-#include <osg/LightModel>
-#include <osg/LightSource>
-#include <osg/Material>
-#include <osg/Math>
-#include <osg/NodeCallback>
-#include <osg/Notify>
-#include <osg/PolygonMode>
-#include <osg/PolygonOffset>
-#include <osg/Program>
-#include <osg/Version>
-#include <osg/TexEnv>
-
-#include <osgUtil/LineSegmentIntersector>
-
-#include <osg/io_utils>
-#include <osgDB/WriteFile>
-#include <osgViewer/Renderer>
-
-#include <simgear/math/SGMath.hxx>
-#include <simgear/scene/material/matlib.hxx>
-#include <simgear/scene/material/EffectCullVisitor.hxx>
-#include <simgear/scene/material/Effect.hxx>
-#include <simgear/scene/material/EffectGeode.hxx>
-#include <simgear/scene/model/animation.hxx>
-#include <simgear/scene/model/placement.hxx>
-#include <simgear/scene/sky/sky.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/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 <Cockpit/panel.hxx>
-
-#include <Model/panelnode.hxx>
-#include <Model/modelmgr.hxx>
-#include <Model/acmodel.hxx>
-#include <Scenery/scenery.hxx>
-#include <Scenery/redout.hxx>
-#include <GUI/new_gui.hxx>
-#include <Instrumentation/HUD/HUD.hxx>
-#include <Environment/precipitation_mgr.hxx>
-#include <Environment/environment_mgr.hxx>
-
-#include "splash.hxx"
-#include "renderer.hxx"
-#include "main.hxx"
-#include "CameraGroup.hxx"
-#include "FGEventHandler.hxx"
-#include <Main/viewer.hxx>
-#include <Main/viewmgr.hxx>
-
-using namespace osg;
-using namespace simgear;
-using namespace flightgear;
-
-class FGHintUpdateCallback : public osg::StateAttribute::Callback {
-public:
-  FGHintUpdateCallback(const char* configNode) :
-    mConfigNode(fgGetNode(configNode, true))
-  { }
-  virtual void operator()(osg::StateAttribute* stateAttribute,
-                          osg::NodeVisitor*)
-  {
-    assert(dynamic_cast<osg::Hint*>(stateAttribute));
-    osg::Hint* hint = static_cast<osg::Hint*>(stateAttribute);
-
-    const char* value = mConfigNode->getStringValue();
-    if (!value)
-      hint->setMode(GL_DONT_CARE);
-    else if (0 == strcmp(value, "nicest"))
-      hint->setMode(GL_NICEST);
-    else if (0 == strcmp(value, "fastest"))
-      hint->setMode(GL_FASTEST);
-    else
-      hint->setMode(GL_DONT_CARE);
-  }
-private:
-  SGPropertyNode_ptr mConfigNode;
-};
-
-
-class SGPuDrawable : public osg::Drawable {
-public:
-  SGPuDrawable()
-  {
-    // Dynamic stuff, do not store geometry
-    setUseDisplayList(false);
-    setDataVariance(Object::DYNAMIC);
-
-    osg::StateSet* stateSet = getOrCreateStateSet();
-    stateSet->setRenderBinDetails(1001, "RenderBin");
-    // speed optimization?
-    stateSet->setMode(GL_CULL_FACE, osg::StateAttribute::OFF);
-    // We can do translucent menus, so why not. :-)
-    stateSet->setAttribute(new osg::BlendFunc(osg::BlendFunc::SRC_ALPHA, osg::BlendFunc::ONE_MINUS_SRC_ALPHA));
-    stateSet->setMode(GL_BLEND, osg::StateAttribute::ON);
-    stateSet->setTextureMode(0, GL_TEXTURE_2D, osg::StateAttribute::OFF);
-
-    stateSet->setTextureAttribute(0, new osg::TexEnv(osg::TexEnv::MODULATE));
-
-    stateSet->setMode(GL_FOG, osg::StateAttribute::OFF);
-    stateSet->setMode(GL_DEPTH_TEST, osg::StateAttribute::OFF);
-  }
-  virtual void drawImplementation(osg::RenderInfo& renderInfo) const
-  { drawImplementation(*renderInfo.getState()); }
-  void drawImplementation(osg::State& state) const
-  {
-    state.setActiveTextureUnit(0);
-    state.setClientActiveTextureUnit(0);
-
-    state.disableAllVertexArrays();
-
-    glPushAttrib(GL_ALL_ATTRIB_BITS);
-    glPushClientAttrib(~0u);
-
-    puDisplay();
-
-    glPopClientAttrib();
-    glPopAttrib();
-  }
-
-  virtual osg::Object* cloneType() const { return new SGPuDrawable; }
-  virtual osg::Object* clone(const osg::CopyOp&) const { return new SGPuDrawable; }
-  
-private:
-};
-
-class SGHUDDrawable : public osg::Drawable {
-public:
-  SGHUDDrawable()
-  {
-    // Dynamic stuff, do not store geometry
-    setUseDisplayList(false);
-    setDataVariance(Object::DYNAMIC);
-
-    osg::StateSet* stateSet = 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);
-
-    stateSet->setTextureAttribute(0, new osg::TexEnv(osg::TexEnv::MODULATE));
-  }
-  virtual void drawImplementation(osg::RenderInfo& renderInfo) const
-  { drawImplementation(*renderInfo.getState()); }
-  void drawImplementation(osg::State& state) const
-  {
-    state.setActiveTextureUnit(0);
-    state.setClientActiveTextureUnit(0);
-    state.disableAllVertexArrays();
-
-    glPushAttrib(GL_ALL_ATTRIB_BITS);
-    glPushClientAttrib(~0u);
-      
-    HUD *hud = static_cast<HUD*>(globals->get_subsystem("hud"));
-    hud->draw(state);
-
-    glPopClientAttrib();
-    glPopAttrib();
-  }
-
-  virtual osg::Object* cloneType() const { return new SGHUDDrawable; }
-  virtual osg::Object* clone(const osg::CopyOp&) const { return new SGHUDDrawable; }
-  
-private:
-};
-
-class FGLightSourceUpdateCallback : public osg::NodeCallback {
-public:
-  
-  /**
-   * @param isSun true if the light is the actual sun i.e., for
-   * illuminating the moon.
-   */
-  FGLightSourceUpdateCallback(bool isSun = false) : _isSun(isSun) {}
-  FGLightSourceUpdateCallback(const FGLightSourceUpdateCallback& nc,
-                              const CopyOp& op)
-    : NodeCallback(nc, op), _isSun(nc._isSun)
-  {}
-  META_Object(flightgear,FGLightSourceUpdateCallback);
-  
-  virtual void operator()(osg::Node* node, osg::NodeVisitor* nv)
-  {
-    assert(dynamic_cast<osg::LightSource*>(node));
-    osg::LightSource* lightSource = static_cast<osg::LightSource*>(node);
-    osg::Light* light = lightSource->getLight();
-    
-    FGLight *l = static_cast<FGLight*>(globals->get_subsystem("lighting"));
-    if (_isSun) {
-      light->setAmbient(Vec4(0.0f, 0.0f, 0.0f, 0.0f));
-      light->setDiffuse(Vec4(1.0f, 1.0f, 1.0f, 1.0f));
-      light->setSpecular(Vec4(0.0f, 0.0f, 0.0f, 0.0f));
-    } else {
-      light->setAmbient(toOsg(l->scene_ambient()));
-      light->setDiffuse(toOsg(l->scene_diffuse()));
-      light->setSpecular(toOsg(l->scene_specular()));
-    }
-    osg::Vec4f position(l->sun_vec()[0], l->sun_vec()[1], l->sun_vec()[2], 0);
-    light->setPosition(position);
-
-    traverse(node, nv);
-  }
-private:
-  const bool _isSun;
-};
-
-class FGWireFrameModeUpdateCallback : public osg::StateAttribute::Callback {
-public:
-  FGWireFrameModeUpdateCallback() :
-    mWireframe(fgGetNode("/sim/rendering/wireframe", true))
-  { }
-  virtual void operator()(osg::StateAttribute* stateAttribute,
-                          osg::NodeVisitor*)
-  {
-    assert(dynamic_cast<osg::PolygonMode*>(stateAttribute));
-    osg::PolygonMode* polygonMode;
-    polygonMode = static_cast<osg::PolygonMode*>(stateAttribute);
-
-    if (mWireframe->getBoolValue())
-      polygonMode->setMode(osg::PolygonMode::FRONT_AND_BACK,
-                           osg::PolygonMode::LINE);
-    else
-      polygonMode->setMode(osg::PolygonMode::FRONT_AND_BACK,
-                           osg::PolygonMode::FILL);
-  }
-private:
-  SGPropertyNode_ptr mWireframe;
-};
-
-class FGLightModelUpdateCallback : public osg::StateAttribute::Callback {
-public:
-  FGLightModelUpdateCallback() :
-    mHighlights(fgGetNode("/sim/rendering/specular-highlight", true))
-  { }
-  virtual void operator()(osg::StateAttribute* stateAttribute,
-                          osg::NodeVisitor*)
-  {
-    assert(dynamic_cast<osg::LightModel*>(stateAttribute));
-    osg::LightModel* lightModel;
-    lightModel = static_cast<osg::LightModel*>(stateAttribute);
-
-#if 0
-    FGLight *l = static_cast<FGLight*>(globals->get_subsystem("lighting"));
-    lightModel->setAmbientIntensity(toOsg(l->scene_ambient());
-#else
-    lightModel->setAmbientIntensity(osg::Vec4(0, 0, 0, 1));
-#endif
-    lightModel->setTwoSided(true);
-    lightModel->setLocalViewer(false);
-
-    if (mHighlights->getBoolValue()) {
-      lightModel->setColorControl(osg::LightModel::SEPARATE_SPECULAR_COLOR);
-    } else {
-      lightModel->setColorControl(osg::LightModel::SINGLE_COLOR);
-    }
-  }
-private:
-  SGPropertyNode_ptr mHighlights;
-};
-
-class FGFogEnableUpdateCallback : public osg::StateSet::Callback {
-public:
-  FGFogEnableUpdateCallback() :
-    mFogEnabled(fgGetNode("/sim/rendering/fog", true))
-  { }
-  virtual void operator()(osg::StateSet* stateSet, osg::NodeVisitor*)
-  {
-    if (strcmp(mFogEnabled->getStringValue(), "disabled") == 0) {
-      stateSet->setMode(GL_FOG, osg::StateAttribute::OFF);
-    } else {
-      stateSet->setMode(GL_FOG, osg::StateAttribute::ON);
-    }
-  }
-private:
-  SGPropertyNode_ptr mFogEnabled;
-};
-
-class FGFogUpdateCallback : public osg::StateAttribute::Callback {
-public:
-  virtual void operator () (osg::StateAttribute* sa, osg::NodeVisitor* nv)
-  {
-    assert(dynamic_cast<SGUpdateVisitor*>(nv));
-    assert(dynamic_cast<osg::Fog*>(sa));
-    SGUpdateVisitor* updateVisitor = static_cast<SGUpdateVisitor*>(nv);
-    osg::Fog* fog = static_cast<osg::Fog*>(sa);
-    fog->setMode(osg::Fog::EXP2);
-    fog->setColor(toOsg(updateVisitor->getFogColor()));
-    fog->setDensity(updateVisitor->getFogExp2Density());
-  }
-};
-
-// update callback for the switch node guarding that splash
-class FGScenerySwitchCallback : 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 = scenery_enabled;
-    sw->setValue(0, enabled);
-    if (!enabled)
-      return;
-    traverse(node, nv);
-  }
-
-  static bool scenery_enabled;
-};
-
-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() ) ),
-    _sunDiffuse( new osg::Uniform( "fg_SunDiffuseColor", osg::Vec4f() ) ),
-    _sunSpecular( new osg::Uniform( "fg_SunSpecularColor", osg::Vec4f() ) ),
-    _sunDirection( new osg::Uniform( "fg_SunDirection", osg::Vec3f() ) ),
-    _planes( new osg::Uniform( "fg_Planes", osg::Vec3f() ) ),
-    _fogColor( new osg::Uniform( "fg_FogColor", osg::Vec4f(1.0, 1.0, 1.0, 1.0) ) ),
-    _fogDensity( new osg::Uniform( "fg_FogDensity", 0.0001f ) ),
-    _shadowNumber( new osg::Uniform( "fg_ShadowNumber", (int)4 ) ),
-    _shadowDistances( new osg::Uniform( "fg_ShadowDistances", osg::Vec4f(5.0, 50.0, 500.0, 5000.0 ) ) )
-{
-#ifdef FG_JPEG_SERVER
-   jpgRenderFrame = updateRenderer;
-#endif
-   eventHandler = new FGEventHandler;
-
-   _numCascades = 4;
-   _cascadeFar[0] = 5.f;
-   _cascadeFar[1] = 50.f;
-   _cascadeFar[2] = 500.f;
-   _cascadeFar[3] = 5000.f;
-}
-
-FGRenderer::~FGRenderer()
-{
-#ifdef FG_JPEG_SERVER
-   jpgRenderFrame = NULL;
-#endif
-    delete _sky;
-}
-
-// Initialize various GL/view parameters
-// 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 ) {
-    osgViewer::Viewer* viewer = getViewer();
-    mRealRoot = dynamic_cast<osg::Group*>(viewer->getSceneData());
-    ref_ptr<Node> splashNode = fgCreateSplashNode();
-    if (_classicalRenderer) {
-        mRealRoot->addChild(splashNode.get());
-    } else {
-        for (   CameraGroup::CameraIterator ii = CameraGroup::getDefault()->camerasBegin();
-                ii != CameraGroup::getDefault()->camerasEnd();
-                ++ii )
-        {
-            CameraInfo* info = ii->get();
-            Camera* camera = info->getCamera(DISPLAY_CAMERA);
-            if (camera == 0) continue;
-
-            camera->addChild(splashNode.get());
-        }
-    }
-    mFrameStamp = viewer->getFrameStamp();
-    // Scene doesn't seem to pass the frame stamp to the update
-    // visitor automatically.
-    mUpdateVisitor->setFrameStamp(mFrameStamp.get());
-    viewer->setUpdateVisitor(mUpdateVisitor.get());
-    fgSetDouble("/sim/startup/splash-alpha", 1.0);
-}
-
-class ShadowMapSizeListener : public SGPropertyChangeListener {
-public:
-    virtual void valueChanged(SGPropertyNode* node) {
-        globals->get_renderer()->updateShadowMapSize(node->getIntValue());
-    }
-};
-
-class ShadowEnabledListener : public SGPropertyChangeListener {
-public:
-    virtual void valueChanged(SGPropertyNode* node) {
-        globals->get_renderer()->enableShadows(node->getBoolValue());
-    }
-};
-
-class ShadowNumListener : public SGPropertyChangeListener {
-public:
-    virtual void valueChanged(SGPropertyNode* node) {
-        globals->get_renderer()->updateCascadeNumber(node->getIntValue());
-    }
-};
-
-class ShadowRangeListener : public SGPropertyChangeListener {
-public:
-    virtual void valueChanged(SGPropertyNode* node) {
-        globals->get_renderer()->updateCascadeFar(node->getIndex(), node->getFloatValue());
-    }
-};
-
-void
-FGRenderer::init( void )
-{
-    _classicalRenderer = !fgGetBool("/sim/rendering/rembrandt", false);
-    _shadowMapSize    = fgGetInt( "/sim/rendering/shadows/map-size", 4096 );
-    fgAddChangeListener( new ShadowMapSizeListener, "/sim/rendering/shadows/map-size" );
-    fgAddChangeListener( new ShadowEnabledListener, "/sim/rendering/shadows/enabled" );
-    ShadowRangeListener* srl = new ShadowRangeListener;
-    fgAddChangeListener(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");
-    _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);
-    _cascadeFar[2] = fgGetFloat("/sim/rendering/shadows/cascade-far-m[2]", 500.0f);
-    _cascadeFar[3] = fgGetFloat("/sim/rendering/shadows/cascade-far-m[3]", 5000.0f);
-    _scenery_loaded   = fgGetNode("/sim/sceneryloaded", true);
-    _scenery_override = fgGetNode("/sim/sceneryloaded-override", true);
-    _panel_hotspots   = fgGetNode("/sim/panel-hotspots", true);
-    _virtual_cockpit  = fgGetNode("/sim/virtual-cockpit", true);
-
-    _sim_delta_sec = fgGetNode("/sim/time/delta-sec", true);
-
-    _xsize         = fgGetNode("/sim/startup/xsize", true);
-    _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);
-
-    _cloud_status = fgGetNode("/environment/clouds/status", true);
-    _visibility_m = fgGetNode("/environment/visibility-m", true);
-    
-    bool use_point_sprites = _point_sprites->getBoolValue();
-    bool enhanced_lighting = _enhanced_lighting->getBoolValue();
-    bool distance_attenuation = _distance_attenuation->getBoolValue();
-
-    SGConfigureDirectionalLights( use_point_sprites, enhanced_lighting,
-                                  distance_attenuation );
-
-    if (const char* tc = fgGetString("/sim/rendering/texture-compression", NULL)) {
-      if (strcmp(tc, "false") == 0 || strcmp(tc, "off") == 0 ||
-          strcmp(tc, "0") == 0 || strcmp(tc, "no") == 0 ||
-          strcmp(tc, "none") == 0) {
-        SGSceneFeatures::instance()->setTextureCompression(SGSceneFeatures::DoNotUseCompression);
-      } else if (strcmp(tc, "arb") == 0) {
-        SGSceneFeatures::instance()->setTextureCompression(SGSceneFeatures::UseARBCompression);
-      } else if (strcmp(tc, "dxt1") == 0) {
-        SGSceneFeatures::instance()->setTextureCompression(SGSceneFeatures::UseDXT1Compression);
-      } else if (strcmp(tc, "dxt3") == 0) {
-        SGSceneFeatures::instance()->setTextureCompression(SGSceneFeatures::UseDXT3Compression);
-      } else if (strcmp(tc, "dxt5") == 0) {
-        SGSceneFeatures::instance()->setTextureCompression(SGSceneFeatures::UseDXT5Compression);
-      } else {
-        SG_LOG(SG_VIEW, SG_WARN, "Unknown texture compression setting!");
-      }
-    }
-    
-// create sky, but can't build until setupView, since we depend
-// on other subsystems to be inited, eg Ephemeris    
-    _sky = new SGSky;
-    
-    SGPath texture_path(globals->get_fg_root());
-    texture_path.append("Textures");
-    texture_path.append("Sky");
-    for (int i = 0; i < FGEnvironmentMgr::MAX_CLOUD_LAYERS; i++) {
-        SGCloudLayer * layer = new SGCloudLayer(texture_path.str());
-        _sky->add_cloud_layer(layer);
-    }
-    
-    _sky->texture_path( texture_path.str() );
-
-    if (!_classicalRenderer) {
-        eventHandler->setChangeStatsCameraRenderOrder( true );
-    }
-}
-
-void installCullVisitor(Camera* camera)
-{
-    osgViewer::Renderer* renderer
-        = 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);
-        sceneView->getCullVisitor()->setIdentifier(identifier.get());
-
-        identifier = sceneView->getCullVisitorLeft()->getIdentifier();
-        sceneView->setCullVisitorLeft(sceneView->getCullVisitor()->clone());
-        sceneView->getCullVisitorLeft()->setIdentifier(identifier.get());
-
-        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,
-                                   const Matrix& view,
-                                   const Matrix& projection,
-                                                                  osg::GraphicsContext* gc,
-                                   bool useMasterSceneData)
-{
-       flightgear::CameraInfo* info = 0;
-       if (!_classicalRenderer && (flags & (CameraGroup::GUI | CameraGroup::ORTHO)) == 0)
-               info = buildDeferredPipeline( cgroup, flags, camera, view, projection, gc );
-
-       if (info) {
-               return info;
-       } else {
-               if ((flags & (CameraGroup::GUI | CameraGroup::ORTHO)) == 0)
-                       _classicalRenderer = true;
-               return buildClassicalPipeline( cgroup, flags, camera, view, projection, useMasterSceneData );
-       }
-}
-
-flightgear::CameraInfo*
-FGRenderer::buildClassicalPipeline(flightgear::CameraGroup* cgroup, unsigned flags, osg::Camera* camera,
-                                const osg::Matrix& view,
-                                const osg::Matrix& projection,
-                                bool useMasterSceneData)
-{
-    CameraInfo* info = new CameraInfo(flags);
-    // The camera group will always update the camera
-    camera->setReferenceFrame(Transform::ABSOLUTE_RF);
-
-    Camera* farCamera = 0;
-    if ((flags & (CameraGroup::GUI | CameraGroup::ORTHO)) == 0) {
-        farCamera = new Camera;
-        farCamera->setAllowEventFocus(camera->getAllowEventFocus());
-        farCamera->setGraphicsContext(camera->getGraphicsContext());
-        farCamera->setCullingMode(camera->getCullingMode());
-        farCamera->setInheritanceMask(camera->getInheritanceMask());
-        farCamera->setReferenceFrame(Transform::ABSOLUTE_RF);
-        // Each camera's viewport is written when the window is
-        // resized; if the the viewport isn't copied here, it gets updated
-        // twice and ends up with the wrong value.
-        farCamera->setViewport(simgear::clone(camera->getViewport()));
-        farCamera->setDrawBuffer(camera->getDrawBuffer());
-        farCamera->setReadBuffer(camera->getReadBuffer());
-        farCamera->setRenderTargetImplementation(
-            camera->getRenderTargetImplementation());
-        const Camera::BufferAttachmentMap& bufferMap
-            = camera->getBufferAttachmentMap();
-        if (bufferMap.count(Camera::COLOR_BUFFER) != 0) {
-            farCamera->attach(
-                Camera::COLOR_BUFFER,
-                bufferMap.find(Camera::COLOR_BUFFER)->second._texture.get());
-        }
-        cgroup->getViewer()->addSlave(farCamera, projection, view, useMasterSceneData);
-        installCullVisitor(farCamera);
-               int farSlaveIndex = cgroup->getViewer()->getNumSlaves() - 1;
-               info->addCamera( FAR_CAMERA, farCamera, farSlaveIndex );
-        farCamera->setRenderOrder(Camera::POST_RENDER, farSlaveIndex);
-        camera->setCullMask(camera->getCullMask() & ~simgear::BACKGROUND_BIT);
-        camera->setClearMask(GL_DEPTH_BUFFER_BIT);
-    }
-    cgroup->getViewer()->addSlave(camera, projection, view, useMasterSceneData);
-    installCullVisitor(camera);
-    int slaveIndex = cgroup->getViewer()->getNumSlaves() - 1;
-       info->addCamera( MAIN_CAMERA, camera, slaveIndex );
-    camera->setRenderOrder(Camera::POST_RENDER, slaveIndex);
-    cgroup->addCamera(info);
-    return info;
-}
-
-class FGDeferredRenderingCameraCullCallback : public osg::NodeCallback {
-public:
-       FGDeferredRenderingCameraCullCallback( flightgear::CameraKind k, CameraInfo* i ) : kind( k ), info( i ) {}
-       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;
-                               }
-                       }
-               } else if ( kind == flightgear::LIGHTING_CAMERA ) {
-            osg::ref_ptr<osg::Camera> mainShadowCamera = info->getCamera( SHADOW_CAMERA );
-                       if (mainShadowCamera.valid()) {
-                               osg::Group* grp = mainShadowCamera->getChild(0)->asGroup();
-                               for (int i = 0; i < 4; ++i ) {
-                                       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::RefMatrix * refMatrix = new osg::RefMatrix( cascadeCam->getInverseViewMatrix() * *cv->getModelViewMatrix() );
-
-                                       cv->getRenderStage()->getPositionalStateContainer()->addPositionedTextureAttribute( i+1, refMatrix, shadowTexGen );
-                               }
-                       }
-                       // 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;
-    CameraInfo* info;
-};
-
-osg::Texture2D* buildDeferredBuffer(GLint internalFormat, GLenum sourceFormat, GLenum sourceType, osg::Texture::WrapMode wrapMode, bool shadowComparison = false)
-{
-    osg::Texture2D* tex = new osg::Texture2D;
-    tex->setResizeNonPowerOfTwoHint( false );
-    tex->setInternalFormat( internalFormat );
-    tex->setShadowComparison(shadowComparison);
-    if (shadowComparison) {
-        tex->setShadowTextureMode(osg::Texture2D::LUMINANCE);
-        tex->setBorderColor(osg::Vec4(1.0f,1.0f,1.0f,1.0f));
-    }
-    tex->setSourceFormat(sourceFormat);
-    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 );
-       return tex;
-}
-
-void buildDeferredBuffers( flightgear::CameraInfo* info, int shadowMapSize, bool normal16 )
-{
-    info->addBuffer(flightgear::RenderBufferInfo::DEPTH_BUFFER, buildDeferredBuffer( GL_DEPTH_COMPONENT32, GL_DEPTH_COMPONENT, GL_FLOAT, osg::Texture::CLAMP_TO_BORDER) );
-    if (false)
-        info->addBuffer(flightgear::RenderBufferInfo::NORMAL_BUFFER, buildDeferredBuffer( 0x822C /*GL_RG16*/, 0x8227 /*GL_RG*/, GL_UNSIGNED_SHORT, osg::Texture::CLAMP_TO_BORDER) );
-    else
-        info->addBuffer(flightgear::RenderBufferInfo::NORMAL_BUFFER, buildDeferredBuffer( GL_RGBA8, GL_RGBA, GL_UNSIGNED_SHORT, 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 )
-{
-    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 )
-{
-    osg::Camera* camera = new osg::Camera;
-    info->addCamera(flightgear::GEOMETRY_CAMERA, camera );
-
-    camera->setCullMask( ~simgear::MODELLIGHT_BIT );
-    camera->setName( "GeometryC" );
-    camera->setGraphicsContext( gc );
-    camera->setCullCallback( new FGDeferredRenderingCameraCullCallback( flightgear::GEOMETRY_CAMERA, info ) );
-    camera->setClearMask( GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT );
-    camera->setClearColor( osg::Vec4( 0., 0., 0., 0. ) );
-    camera->setClearDepth( 1.0 );
-    camera->setRenderTargetImplementation( osg::Camera::FRAME_BUFFER_OBJECT );
-    camera->setViewport( new osg::Viewport );
-    attachBufferToCamera( info, camera, osg::Camera::DEPTH_BUFFER, flightgear::GEOMETRY_CAMERA, flightgear::RenderBufferInfo::DEPTH_BUFFER );
-    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 );
-    camera->setDrawBuffer(GL_FRONT);
-    camera->setReadBuffer(GL_FRONT);
-
-    camera->addChild( mDeferredRealRoot.get() );
-
-    return camera;
-}
-
-static void setShadowCascadeStateSet( osg::Camera* cam ) {
-    osg::StateSet* ss = cam->getOrCreateStateSet();
-    ss->setAttribute( new osg::PolygonOffset( 1.1f, 5.0f ), osg::StateAttribute::ON | osg::StateAttribute::OVERRIDE );
-    ss->setMode( GL_POLYGON_OFFSET_FILL, osg::StateAttribute::ON | osg::StateAttribute::OVERRIDE );
-    ss->setRenderBinDetails( 0, "RenderBin", osg::StateSet::OVERRIDE_RENDERBIN_DETAILS );
-    ss->setAttributeAndModes( new osg::AlphaFunc( osg::AlphaFunc::GREATER, 0.05 ), osg::StateAttribute::ON | osg::StateAttribute::OVERRIDE );
-    ss->setAttributeAndModes( new osg::ColorMask( false, false, false, false ), osg::StateAttribute::ON | osg::StateAttribute::OVERRIDE );
-    ss->setAttributeAndModes( new osg::CullFace( osg::CullFace::FRONT ), osg::StateAttribute::ON | osg::StateAttribute::OVERRIDE );
-    osg::Program* program = new osg::Program;
-    ss->setAttribute( program, osg::StateAttribute::OVERRIDE | osg::StateAttribute::ON );
-    ss->setMode( GL_LIGHTING, osg::StateAttribute::OVERRIDE | osg::StateAttribute::OFF );
-    ss->setMode( GL_BLEND, osg::StateAttribute::OVERRIDE | osg::StateAttribute::OFF );
-    //ss->setTextureMode( 0, GL_TEXTURE_2D, osg::StateAttribute::OVERRIDE | osg::StateAttribute::ON );
-    ss->setTextureMode( 0, GL_TEXTURE_3D, osg::StateAttribute::OVERRIDE | osg::StateAttribute::OFF );
-    ss->setTextureMode( 1, GL_TEXTURE_2D, osg::StateAttribute::OVERRIDE | osg::StateAttribute::OFF );
-    ss->setTextureMode( 1, GL_TEXTURE_3D, osg::StateAttribute::OVERRIDE | osg::StateAttribute::OFF );
-    ss->setTextureMode( 2, GL_TEXTURE_2D, osg::StateAttribute::OVERRIDE | osg::StateAttribute::OFF );
-    ss->setTextureMode( 2, GL_TEXTURE_3D, osg::StateAttribute::OVERRIDE | osg::StateAttribute::OFF );
-}
-
-static osg::Camera* createShadowCascadeCamera( int no, int cascadeSize ) {
-    osg::Camera* cascadeCam = new osg::Camera;
-    setShadowCascadeStateSet( cascadeCam );
-
-    std::ostringstream oss;
-    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->setAllowEventFocus(false);
-    cascadeCam->setReferenceFrame(osg::Transform::ABSOLUTE_RF_INHERIT_VIEWPOINT);
-    cascadeCam->setRenderOrder(osg::Camera::NESTED_RENDER);
-    cascadeCam->setComputeNearFarMode(osg::CullSettings::DO_NOT_COMPUTE_NEAR_FAR);
-    cascadeCam->setViewport( int( no / 2 ) * cascadeSize, (no & 1) * cascadeSize, cascadeSize, cascadeSize );
-    return cascadeCam;
-}
-
-osg::Camera* FGRenderer::buildDeferredShadowCamera( flightgear::CameraInfo* info, osg::GraphicsContext* gc )
-{
-    osg::Camera* mainShadowCamera = new osg::Camera;
-    info->addCamera(flightgear::SHADOW_CAMERA, mainShadowCamera, 0.0f );
-
-    mainShadowCamera->setName( "ShadowC" );
-    mainShadowCamera->setClearMask( GL_DEPTH_BUFFER_BIT );
-    mainShadowCamera->setClearDepth( 1.0 );
-    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 );
-    mainShadowCamera->setComputeNearFarMode(osg::Camera::DO_NOT_COMPUTE_NEAR_FAR);
-    mainShadowCamera->setReferenceFrame(osg::Transform::ABSOLUTE_RF);
-    mainShadowCamera->setProjectionMatrix(osg::Matrix::identity());
-    mainShadowCamera->setCullingMode( osg::CullSettings::NO_CULLING );
-    mainShadowCamera->setViewport( 0, 0, _shadowMapSize, _shadowMapSize );
-    mainShadowCamera->setDrawBuffer(GL_FRONT);
-    mainShadowCamera->setReadBuffer(GL_FRONT);
-
-    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() );
-        shadowSwitch->addChild( cascadeCam );
-        info->shadowTexGen[i] = new osg::TexGen;
-    }
-    if (fgGetBool("/sim/rendering/shadows/enabled", true))
-        shadowSwitch->setAllChildrenOn();
-    else
-        shadowSwitch->setAllChildrenOff();
-
-    return mainShadowCamera;
-}
-
-void FGRenderer::updateShadowCascade(const CameraInfo* info, osg::Camera* camera, osg::Group* grp, int idx, double left, double right, double bottom, double top, double zNear, double f1, double f2)
-{
-    osg::Camera* cascade = static_cast<osg::Camera*>( grp->getChild(idx) );
-    osg::Matrixd &viewMatrix = cascade->getViewMatrix();
-    osg::Matrixd &projectionMatrix = cascade->getProjectionMatrix();
-
-    osg::BoundingSphere bs;
-    bs.expandBy(osg::Vec3(left,bottom,-zNear) * f1);
-    bs.expandBy(osg::Vec3(right,top,-zNear) * f2);
-    bs.expandBy(osg::Vec3(left,bottom,-zNear) * f2);
-    bs.expandBy(osg::Vec3(right,top,-zNear) * f1);
-
-    osg::Vec4 aim = osg::Vec4(bs.center(), 1.0) * camera->getInverseViewMatrix();
-
-    projectionMatrix.makeOrtho( -bs.radius(), bs.radius(), -bs.radius(), bs.radius(), 1., 15000.0 );
-    osg::Vec3 position( aim.x(), aim.y(), aim.z() );
-    viewMatrix.makeLookAt( position + (getSunDirection() * 10000.0), position, position );
-}
-
-osg::Vec3 FGRenderer::getSunDirection() const
-{
-    osg::Vec3 val;
-    _sunDirection->get( val );
-    return val;
-}
-
-void FGRenderer::updateShadowCamera(const flightgear::CameraInfo* info, const osg::Vec3d& position)
-{
-    ref_ptr<Camera> mainShadowCamera = info->getCamera( SHADOW_CAMERA );
-    if (mainShadowCamera.valid()) {
-        ref_ptr<Switch> shadowSwitch = mainShadowCamera->getChild( 0 )->asSwitch();
-        osg::Vec3d up = position,
-            dir = getSunDirection();
-        up.normalize();
-        dir.normalize();
-        // cos(100 deg) == -0.17
-        if (up * dir < -0.17 || !fgGetBool("/sim/rendering/shadows/enabled", true)) {
-            shadowSwitch->setAllChildrenOff();
-        } else {
-            double left,right,bottom,top,zNear,zFar;
-            ref_ptr<Camera> camera = info->getCamera(GEOMETRY_CAMERA);
-            camera->getProjectionMatrix().getFrustum(left,right,bottom,top,zNear,zFar);
-
-            shadowSwitch->setAllChildrenOn();
-            if (_numCascades == 1) {
-                osg::Camera* cascadeCam = static_cast<osg::Camera*>( shadowSwitch->getChild(0) );
-                cascadeCam->setViewport( 0, 0, _shadowMapSize, _shadowMapSize );
-            } else {
-                for (int no = 0; no < 4; ++no) {
-                    osg::Camera* cascadeCam = static_cast<osg::Camera*>( shadowSwitch->getChild(no) );
-                    cascadeCam->setViewport( int( no / 2 ) * (_shadowMapSize/2), (no & 1) * (_shadowMapSize/2), (_shadowMapSize/2), (_shadowMapSize/2) );
-                }
-            }
-            updateShadowCascade(info, camera, shadowSwitch, 0, left, right, bottom, top, zNear, 1.0, _cascadeFar[0]/zNear);
-            if (_numCascades > 1) {
-                shadowSwitch->setValue(1, true);
-                updateShadowCascade(info, camera, shadowSwitch, 1, left, right, bottom, top, zNear, _cascadeFar[0]/zNear, _cascadeFar[1]/zNear);
-            } else {
-                shadowSwitch->setValue(1, false);
-            }
-            if (_numCascades > 2) {
-                shadowSwitch->setValue(2, true);
-                updateShadowCascade(info, camera, shadowSwitch, 2, left, right, bottom, top, zNear, _cascadeFar[1]/zNear, _cascadeFar[2]/zNear);
-            } else {
-                shadowSwitch->setValue(2, false);
-            }
-            if (_numCascades > 3) {
-                shadowSwitch->setValue(3, true);
-                updateShadowCascade(info, camera, shadowSwitch, 3, left, right, bottom, top, zNear, _cascadeFar[2]/zNear, _cascadeFar[3]/zNear);
-            } else {
-                shadowSwitch->setValue(3, false);
-            }
-            {
-            osg::Matrixd &viewMatrix = mainShadowCamera->getViewMatrix();
-
-            osg::Vec4 aim = osg::Vec4( 0.0, 0.0, 0.0, 1.0 ) * camera->getInverseViewMatrix();
-
-            osg::Vec3 position( aim.x(), aim.y(), aim.z() );
-            viewMatrix.makeLookAt( position, position + (getSunDirection() * 10000.0), position );
-            }
-        }
-    }
-}
-
-void FGRenderer::updateShadowMapSize(int mapSize)
-{
-    if ( ((~( mapSize-1 )) & mapSize) != mapSize ) {
-        SG_LOG( SG_VIEW, SG_ALERT, "Map size is not a power of two" );
-        return;
-    }
-    for (   CameraGroup::CameraIterator ii = CameraGroup::getDefault()->camerasBegin();
-            ii != CameraGroup::getDefault()->camerasEnd();
-            ++ii )
-    {
-        CameraInfo* info = ii->get();
-        Camera* camera = info->getCamera(SHADOW_CAMERA);
-        if (camera == 0) continue;
-
-        Texture2D* tex = info->getBuffer(RenderBufferInfo::SHADOW_BUFFER);
-        if (tex == 0) continue;
-
-        tex->setTextureSize( mapSize, mapSize );
-        tex->dirtyTextureObject();
-
-        Viewport* vp = camera->getViewport();
-        vp->width() = mapSize;
-        vp->height() = mapSize;
-
-        osgViewer::Renderer* renderer
-            = static_cast<osgViewer::Renderer*>(camera->getRenderer());
-        for (int i = 0; i < 2; ++i) {
-            osgUtil::SceneView* sceneView = renderer->getSceneView(i);
-            sceneView->getRenderStage()->setFrameBufferObject(0);
-            sceneView->getRenderStage()->setCameraRequiresSetUp(true);
-            if (sceneView->getRenderStageLeft()) {
-                sceneView->getRenderStageLeft()->setFrameBufferObject(0);
-                sceneView->getRenderStageLeft()->setCameraRequiresSetUp(true);
-            }
-            if (sceneView->getRenderStageRight()) {
-                sceneView->getRenderStageRight()->setFrameBufferObject(0);
-                sceneView->getRenderStageRight()->setCameraRequiresSetUp(true);
-            }
-        }
-
-        int cascadeSize = mapSize / 2;
-        Group* grp = camera->getChild(0)->asGroup();
-        for (int i = 0; i < 4; ++i ) {
-            Camera* cascadeCam = static_cast<Camera*>( grp->getChild(i) );
-            cascadeCam->setViewport( int( i / 2 ) * cascadeSize, (i & 1) * cascadeSize, cascadeSize, cascadeSize );
-        }
-
-        _shadowMapSize = mapSize;
-    }
-}
-
-void FGRenderer::enableShadows(bool enabled)
-{
-    for (   CameraGroup::CameraIterator ii = CameraGroup::getDefault()->camerasBegin();
-            ii != CameraGroup::getDefault()->camerasEnd();
-            ++ii )
-    {
-        CameraInfo* info = ii->get();
-        Camera* camera = info->getCamera(SHADOW_CAMERA);
-        if (camera == 0) continue;
-
-        osg::Switch* shadowSwitch = camera->getChild(0)->asSwitch();
-        if (enabled)
-            shadowSwitch->setAllChildrenOn();
-        else
-            shadowSwitch->setAllChildrenOff();
-    }
-}
-
-void FGRenderer::updateCascadeFar(int index, float far_m)
-{
-    if (index < 0 || index > 3)
-        return;
-    _cascadeFar[index] = far_m;
-    _shadowDistances->set( osg::Vec4f(_cascadeFar[0], _cascadeFar[1], _cascadeFar[2], _cascadeFar[3]) );
-}
-
-void FGRenderer::updateCascadeNumber(size_t num)
-{
-    if (num < 1 || num > 4)
-        return;
-    _numCascades = num;
-    _shadowNumber->set( (int)_numCascades );
-}
-
-
-#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 )
-{
-    osg::Camera* camera = new osg::Camera;
-    info->addCamera(flightgear::LIGHTING_CAMERA, camera );
-
-    camera->setCullCallback( new FGDeferredRenderingCameraCullCallback( flightgear::LIGHTING_CAMERA, info ) );
-    camera->setAllowEventFocus(false);
-    camera->setGraphicsContext(gc);
-    camera->setViewport(new Viewport);
-    camera->setName("LightingC");
-    camera->setReferenceFrame(osg::Transform::ABSOLUTE_RF);
-    camera->setRenderOrder(osg::Camera::POST_RENDER, 50);
-    camera->setRenderTargetImplementation( osg::Camera::FRAME_BUFFER_OBJECT );
-    camera->setViewport( new osg::Viewport );
-    attachBufferToCamera( info, camera, osg::Camera::DEPTH_BUFFER, flightgear::LIGHTING_CAMERA, flightgear::RenderBufferInfo::DEPTH_BUFFER );
-    attachBufferToCamera( info, camera, osg::Camera::COLOR_BUFFER, flightgear::LIGHTING_CAMERA, flightgear::RenderBufferInfo::LIGHTING_BUFFER );
-    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) );
-
-    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 );
-    ss->addUniform( info->projInverse );
-    ss->addUniform( info->viewInverse );
-    ss->addUniform( info->view );
-    ss->addUniform( _sunDiffuse );
-    ss->addUniform( _sunSpecular );
-    ss->addUniform( _sunDirection );
-    ss->addUniform( _planes );
-    ss->addUniform( _shadowNumber );
-    ss->addUniform( _shadowDistances );
-
-    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);
-    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->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 );
-
-    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 );
-
-    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 );
-
-    lightingGroup->addChild( _sky->getPreRoot() );
-    lightingGroup->addChild( _sky->getCloudRoot() );
-    lightingGroup->addChild( quadCam1 );
-    lightingGroup->addChild( lightCam );
-    lightingGroup->addChild( quadCam2 );
-
-    camera->addChild( lightingGroup );
-
-    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)
-{
-    CameraInfo* info = new CameraInfo(flags);
-       buildDeferredBuffers( info, _shadowMapSize, !fgGetBool("/sim/rendering/no-16bit-buffer", false ) );
-
-    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->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);
-    if (!effect) {
-        SG_LOG(SG_VIEW, SG_ALERT, "Effects/display not found");
-        return 0;
-    }
-    eg->setEffect(effect);
-    eg->setCullingActive(false);
-    eg->addDrawable(g);
-    camera->setViewMatrix(osg::Matrix::identity());
-    camera->setProjectionMatrixAsOrtho2D(-1,1,-1,1);
-    camera->addChild(eg);
-
-    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;
-}
-
-
-void
-FGRenderer::setupView( void )
-{
-    osgViewer::Viewer* viewer = globals->get_renderer()->getViewer();
-    osg::initNotifyLevel();
-
-    // 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);
-
-    // Go full screen if requested ...
-    if ( fgGetBool("/sim/startup/fullscreen") )
-        fgOSFullScreen();
-
-// 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);
-    
-    osg::StateSet* stateSet = mRoot->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);
-    hint = new osg::Hint(GL_POLYGON_SMOOTH_HINT, GL_DONT_CARE);
-    hint->setUpdateCallback(new FGHintUpdateCallback("/sim/rendering/polygon-smooth"));
-    stateSet->setAttribute(hint);
-    hint = new osg::Hint(GL_LINE_SMOOTH_HINT, GL_DONT_CARE);
-    hint->setUpdateCallback(new FGHintUpdateCallback("/sim/rendering/line-smooth"));
-    stateSet->setAttribute(hint);
-    hint = new osg::Hint(GL_POINT_SMOOTH_HINT, GL_DONT_CARE);
-    hint->setUpdateCallback(new FGHintUpdateCallback("/sim/rendering/point-smooth"));
-    stateSet->setAttribute(hint);
-    hint = new osg::Hint(GL_PERSPECTIVE_CORRECTION_HINT, GL_DONT_CARE);
-    hint->setUpdateCallback(new FGHintUpdateCallback("/sim/rendering/perspective-correction"));
-    stateSet->setAttribute(hint);
-
-    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);
-
-    // 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
-    // LightSource in the scene graph have the same light number, it's
-    // indeterminate which values will be used to render geometry that
-    // has that light number enabled. Also, adding children to a
-    // LightSource is just a shortcut for setting up a state set that
-    // 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;
-    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);
-    // we need a white diffuse light for the phase of the moon
-    osg::LightSource* sunLight = new osg::LightSource;
-    sunLight->getLight()->setDataVariance(Object::DYNAMIC);
-    sunLight->getLight()->setLightNum(1);
-    sunLight->setUpdateCallback(new FGLightSourceUpdateCallback(true));
-    sunLight->setReferenceFrame(osg::LightSource::RELATIVE_RF);
-    sunLight->setLocalStateSetModes(osg::StateAttribute::ON);
-    
-    // Hang a StateSet above the sky subgraph in order to turn off
-    // light 0
-    Group* skyGroup = new Group;
-    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);
-    stateSet->setMode(GL_LIGHTING, osg::StateAttribute::ON);
-    stateSet->setMode(GL_DEPTH_TEST, osg::StateAttribute::ON);
-
-    // enable disable specular highlights.
-    // is the place where we might plug in an other fragment shader ...
-    osg::LightModel* lightModel = new osg::LightModel;
-    lightModel->setUpdateCallback(new FGLightModelUpdateCallback);
-    stateSet->setAttribute(lightModel);
-
-    // switch to enable wireframe
-    osg::PolygonMode* polygonMode = new osg::PolygonMode;
-    polygonMode->setUpdateCallback(new FGWireFrameModeUpdateCallback);
-    stateSet->setAttributeAndModes(polygonMode);
-
-    // scene fog handling
-    osg::Fog* fog = new osg::Fog;
-    fog->setUpdateCallback(new FGFogUpdateCallback);
-    stateSet->setAttributeAndModes(fog);
-    stateSet->setUpdateCallback(new FGFogEnableUpdateCallback);
-
-    // plug in the GUI
-    osg::Camera* guiCamera = getGUICamera(CameraGroup::getDefault());
-    if (guiCamera) {
-        
-        osg::Geode* geode = new osg::Geode;
-        geode->addDrawable(new SGPuDrawable);
-        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());
-    }
-    
-    osg::Switch* sw = new osg::Switch;
-    sw->setUpdateCallback(new FGScenerySwitchCallback);
-    sw->addChild(mRoot.get());
-    mRealRoot->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());
-       }
-    // 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->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);
-    }
-}
-                                    
-// Update all Visuals (redraws anything graphics related)
-void
-FGRenderer::update( ) {
-    if (!(_scenery_loaded->getBoolValue() || 
-           _scenery_override->getBoolValue()))
-    {
-        _splash_alpha->setDoubleValue(1.0);
-        return;
-    }
-    osgViewer::Viewer* viewer = globals->get_renderer()->getViewer();
-
-    if (_splash_alpha->getDoubleValue()>0.0)
-    {
-        // Fade out the splash screen
-        const double fade_time = 0.5;
-        const double fade_steps_per_sec = 10;
-        double delay_time = SGMiscd::min(fade_time/fade_steps_per_sec,
-                                         (SGTimeStamp::now() - _splash_time).toSecs());
-        _splash_time = SGTimeStamp::now();
-        double sAlpha = _splash_alpha->getDoubleValue();
-        sAlpha -= SGMiscd::max(0.0,delay_time/fade_time);
-        FGScenerySwitchCallback::scenery_enabled = (sAlpha<1.0);
-        _splash_alpha->setDoubleValue((sAlpha < 0) ? 0.0 : sAlpha);
-    }
-
-    FGLight *l = static_cast<FGLight*>(globals->get_subsystem("lighting"));
-       if (!_classicalRenderer ) {
-               _ambientFactor->set( toOsg(l->scene_ambient()) );
-               _sunDiffuse->set( toOsg(l->scene_diffuse()) );
-               _sunSpecular->set( toOsg(l->scene_specular()) );
-               _sunDirection->set( osg::Vec3f(l->sun_vec()[0], l->sun_vec()[1], l->sun_vec()[2]) );
-       }
-
-    // update fog params
-    double actual_visibility;
-    if (_cloud_status->getBoolValue()) {
-        actual_visibility = _sky->get_visibility();
-    } else {
-        actual_visibility = _visibility_m->getDoubleValue();
-    }
-
-    // idle_state is now 1000 meaning we've finished all our
-    // initializations and are running the main loop, so this will
-    // now work without seg faulting the system.
-
-    FGViewer *current__view = globals->get_current_view();
-    // Force update of center dependent values ...
-    current__view->set_dirty();
-  
-    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();
-
-    // need to call the update visitor once
-    mFrameStamp->setCalendarTime(*globals->get_time_params()->getGmt());
-    mUpdateVisitor->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(),
-                             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());
-    osg::Node::NodeMask cullMask = ~simgear::LIGHTS_BITS & ~simgear::PICK_BIT;
-    cullMask |= simgear::GroundLightManager::instance()
-        ->getLightNodeMask(mUpdateVisitor.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() ) );
-       }
-}
-
-void
-FGRenderer::resize( int width, int height )
-{
-    int curWidth = _xsize->getIntValue(),
-        curHeight = _ysize->getIntValue();
-    SG_LOG(SG_VIEW, SG_DEBUG, "FGRenderer::resize: new size " << width << " x " << height);
-    if ((curHeight != height) || (curWidth != width)) {
-    // must guard setting these, or PLIB-PUI fails with too many live interfaces
-        _xsize->setIntValue(width);
-        _ysize->setIntValue(height);
-    }
-}
-
-bool
-FGRenderer::pick(std::vector<SGSceneryPick>& pickList,
-                 const osgGA::GUIEventAdapter* ea)
-{
-    // wipe out the return ...
-    pickList.clear();
-    typedef osgUtil::LineSegmentIntersector::Intersections Intersections;
-    Intersections intersections;
-
-    if (!computeIntersections(CameraGroup::getDefault(), ea, intersections))
-        return false;
-    for (Intersections::iterator hit = intersections.begin(),
-             e = intersections.end();
-         hit != e;
-         ++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)
-                continue;
-            for (unsigned i = 0; i < ud->getNumPickCallbacks(); ++i) {
-                SGPickCallback* pickCallback = ud->getPickCallback(i);
-                if (!pickCallback)
-                    continue;
-                SGSceneryPick sceneryPick;
-                sceneryPick.info.local = toSG(hit->getLocalIntersectPoint());
-                sceneryPick.info.wgs84 = toSG(hit->getWorldIntersectPoint());
-                sceneryPick.callback = pickCallback;
-                pickList.push_back(sceneryPick);
-            }
-        }
-    }
-    return !pickList.empty();
-}
-
-void
-FGRenderer::setViewer(osgViewer::Viewer* viewer_)
-{
-    viewer = viewer_;
-}
-
-void
-FGRenderer::setEventHandler(FGEventHandler* eventHandler_)
-{
-    eventHandler = eventHandler_;
-}
-
-void
-FGRenderer::addCamera(osg::Camera* camera, bool useSceneData)
-{
-    mRealRoot->addChild(camera);
-}
-
-void
-FGRenderer::removeCamera(osg::Camera* camera)
-{
-    mRealRoot->removeChild(camera);
-}
-                                    
-void
-FGRenderer::setPlanes( double zNear, double zFar )
-{
-       _planes->set( osg::Vec3f( - zFar, - zFar * zNear, zFar - zNear ) );
-}
-
-bool
-fgDumpSceneGraphToFile(const char* filename)
-{
-    return osgDB::writeNodeFile(*mRealRoot.get(), filename);
-}
-
-bool
-fgDumpTerrainBranchToFile(const char* filename)
-{
-    return osgDB::writeNodeFile( *globals->get_scenery()->get_terrain_branch(),
-                                 filename );
-}
-
-// For debugging
-bool
-fgDumpNodeToFile(osg::Node* node, const char* filename)
-{
-    return osgDB::writeNodeFile(*node, filename);
-}
-
-namespace flightgear
-{
-using namespace osg;
-
-class VisibleSceneInfoVistor : public NodeVisitor, CullStack
-{
-public:
-    VisibleSceneInfoVistor()
-        : NodeVisitor(CULL_VISITOR, TRAVERSE_ACTIVE_CHILDREN)
-    {
-        setCullingMode(CullSettings::SMALL_FEATURE_CULLING
-                       | CullSettings::VIEW_FRUSTUM_CULLING);
-        setComputeNearFarMode(CullSettings::DO_NOT_COMPUTE_NEAR_FAR);
-    }
-
-    VisibleSceneInfoVistor(const VisibleSceneInfoVistor& rhs)
-    {
-    }
-
-    META_NodeVisitor("flightgear","VisibleSceneInfoVistor")
-
-    typedef std::map<const std::string,int> InfoMap;
-
-    void getNodeInfo(Node* node)
-    {
-        const char* typeName = typeid(*node).name();
-        classInfo[typeName]++;
-        const std::string& nodeName = node->getName();
-        if (!nodeName.empty())
-            nodeInfo[nodeName]++;
-    }
-
-    void dumpInfo()
-    {
-        using namespace std;
-        typedef vector<InfoMap::iterator> FreqVector;
-        cout << "class info:\n";
-        FreqVector classes;
-        for (InfoMap::iterator itr = classInfo.begin(), end = classInfo.end();
-             itr != end;
-             ++itr)
-            classes.push_back(itr);
-        sort(classes.begin(), classes.end(), freqComp);
-        for (FreqVector::iterator itr = classes.begin(), end = classes.end();
-             itr != end;
-             ++itr) {
-            cout << (*itr)->first << " " << (*itr)->second << "\n";
-        }
-        cout << "\nnode info:\n";
-        FreqVector nodes;
-        for (InfoMap::iterator itr = nodeInfo.begin(), end = nodeInfo.end();
-             itr != end;
-             ++itr)
-            nodes.push_back(itr);
-
-        sort (nodes.begin(), nodes.end(), freqComp);
-        for (FreqVector::iterator itr = nodes.begin(), end = nodes.end();
-             itr != end;
-             ++itr) {
-            cout << (*itr)->first << " " << (*itr)->second << "\n";
-        }
-        cout << endl;
-    }
-    
-    void doTraversal(Camera* camera, Node* root, Viewport* viewport)
-    {
-        ref_ptr<RefMatrix> projection
-            = createOrReuseMatrix(camera->getProjectionMatrix());
-        ref_ptr<RefMatrix> mv = createOrReuseMatrix(camera->getViewMatrix());
-        if (!viewport)
-            viewport = camera->getViewport();
-        if (viewport)
-            pushViewport(viewport);
-        pushProjectionMatrix(projection.get());
-        pushModelViewMatrix(mv.get(), Transform::ABSOLUTE_RF);
-        root->accept(*this);
-        popModelViewMatrix();
-        popProjectionMatrix();
-        if (viewport)
-            popViewport();
-        dumpInfo();
-    }
-
-    void apply(Node& node)
-    {
-        if (isCulled(node))
-            return;
-        pushCurrentMask();
-        getNodeInfo(&node);
-        traverse(node);
-        popCurrentMask();
-    }
-    void apply(Group& node)
-    {
-        if (isCulled(node))
-            return;
-        pushCurrentMask();
-        getNodeInfo(&node);
-        traverse(node);
-        popCurrentMask();
-    }
-
-    void apply(Transform& node)
-    {
-        if (isCulled(node))
-            return;
-        pushCurrentMask();
-        ref_ptr<RefMatrix> matrix = createOrReuseMatrix(*getModelViewMatrix());
-        node.computeLocalToWorldMatrix(*matrix,this);
-        pushModelViewMatrix(matrix.get(), node.getReferenceFrame());
-        getNodeInfo(&node);
-        traverse(node);
-        popModelViewMatrix();
-        popCurrentMask();
-    }
-
-    void apply(Camera& camera)
-    {
-        // Save current cull settings
-        CullSettings saved_cull_settings(*this);
-
-        // set cull settings from this Camera
-        setCullSettings(camera);
-        // inherit the settings from above
-        inheritCullSettings(saved_cull_settings, camera.getInheritanceMask());
-
-        // set the cull mask.
-        unsigned int savedTraversalMask = getTraversalMask();
-        bool mustSetCullMask = (camera.getInheritanceMask()
-                                & osg::CullSettings::CULL_MASK) == 0;
-        if (mustSetCullMask)
-            setTraversalMask(camera.getCullMask());
-
-        osg::RefMatrix* projection = 0;
-        osg::RefMatrix* modelview = 0;
-
-        if (camera.getReferenceFrame()==osg::Transform::RELATIVE_RF) {
-            if (camera.getTransformOrder()==osg::Camera::POST_MULTIPLY) {
-                projection = createOrReuseMatrix(*getProjectionMatrix()
-                                                 *camera.getProjectionMatrix());
-                modelview = createOrReuseMatrix(*getModelViewMatrix()
-                                                * camera.getViewMatrix());
-            }
-            else {              // pre multiply 
-                projection = createOrReuseMatrix(camera.getProjectionMatrix()
-                                                 * (*getProjectionMatrix()));
-                modelview = createOrReuseMatrix(camera.getViewMatrix()
-                                                * (*getModelViewMatrix()));
-            }
-        } else {
-            // an absolute reference frame
-            projection = createOrReuseMatrix(camera.getProjectionMatrix());
-            modelview = createOrReuseMatrix(camera.getViewMatrix());
-        }
-        if (camera.getViewport())
-            pushViewport(camera.getViewport());
-
-        pushProjectionMatrix(projection);
-        pushModelViewMatrix(modelview, camera.getReferenceFrame());    
-
-        traverse(camera);
-    
-        // restore the previous model view matrix.
-        popModelViewMatrix();
-
-        // restore the previous model view matrix.
-        popProjectionMatrix();
-
-        if (camera.getViewport()) popViewport();
-
-        // restore the previous traversal mask settings
-        if (mustSetCullMask)
-            setTraversalMask(savedTraversalMask);
-
-        // restore the previous cull settings
-        setCullSettings(saved_cull_settings);
-    }
-
-protected:
-    // sort in reverse
-    static bool freqComp(const InfoMap::iterator& lhs, const InfoMap::iterator& rhs)
-    {
-        return lhs->second > rhs->second;
-    }
-    InfoMap classInfo;
-    InfoMap nodeInfo;
-};
-
-bool printVisibleSceneInfo(FGRenderer* renderer)
-{
-    osgViewer::Viewer* viewer = renderer->getViewer();
-    VisibleSceneInfoVistor vsv;
-    Viewport* vp = 0;
-    if (!viewer->getCamera()->getViewport() && viewer->getNumSlaves() > 0) {
-        const View::Slave& slave = viewer->getSlave(0);
-        vp = slave._camera->getViewport();
-    }
-    vsv.doTraversal(viewer->getCamera(), viewer->getSceneData(), vp);
-    return true;
-}
-
-}
-// end of renderer.cxx
-    
diff --git a/src/Main/renderer.hxx b/src/Main/renderer.hxx
deleted file mode 100644 (file)
index fa089bc..0000000
+++ /dev/null
@@ -1,165 +0,0 @@
-
-#ifndef __FG_RENDERER_HXX
-#define __FG_RENDERER_HXX 1
-
-#include <simgear/scene/util/SGPickCallback.hxx>
-#include <simgear/props/props.hxx>
-#include <simgear/timing/timestamp.hxx>
-
-#include <osg/ref_ptr>
-#include <osg/Matrix>
-#include <osg/Vec3>
-
-namespace osg
-{
-class Camera;
-class Group;
-class GraphicsContext;
-}
-
-namespace osgGA
-{
-class GUIEventAdapter;
-}
-
-namespace osgShadow
-{
-class ShadowedScene;
-}
-
-namespace osgViewer
-{
-class Viewer;
-}
-
-namespace flightgear
-{
-class FGEventHandler;
-struct CameraInfo;
-class CameraGroup;
-}
-
-class SGSky;
-
-class FGRenderer {
-
-public:
-
-    FGRenderer();
-    ~FGRenderer();
-
-    void splashinit();
-    void init();
-
-    void setupView();
-
-    void resize(int width, int height );
-
-    void update();
-  
-    /** Just pick into the scene and return the pick callbacks on the way ...
-     */
-    bool pick( std::vector<SGSceneryPick>& pickList,
-               const osgGA::GUIEventAdapter* ea );
-
-    /** Get and set the OSG Viewer object, if any.
-     */
-    osgViewer::Viewer* getViewer() { return viewer.get(); }
-    const osgViewer::Viewer* getViewer() const { return viewer.get(); }
-    void setViewer(osgViewer::Viewer* viewer);
-    /** Get and set the manipulator object, if any.
-     */
-    flightgear::FGEventHandler* getEventHandler() { return eventHandler.get(); }
-    const flightgear::FGEventHandler* getEventHandler() const { return eventHandler.get(); }
-    void setEventHandler(flightgear::FGEventHandler* manipulator);
-
-    /** Add a top level camera.
-     */
-    void addCamera(osg::Camera* camera, bool useSceneData);
-
-    void removeCamera(osg::Camera* camera);
-  
-    /** Add a camera to the group. The camera is added to the viewer
-     * as a slave. See osgViewer::Viewer::addSlave.
-     * @param flags properties of the camera; see CameraGroup::Flags
-     * @param projection slave projection matrix
-     * @param view slave view matrix
-     * @param useMasterSceneData whether the camera displays the
-     * viewer's scene data.
-     * @return a CameraInfo object for the camera.
-     */
-       flightgear::CameraInfo* buildRenderingPipeline(flightgear::CameraGroup* cgroup, unsigned flags, osg::Camera* camera,
-                                   const osg::Matrix& view,
-                                   const osg::Matrix& projection,
-                                                                  osg::GraphicsContext* gc,
-                                   bool useMasterSceneData);
-
-       /**
-        */
-       flightgear::CameraInfo* buildClassicalPipeline(flightgear::CameraGroup* cgroup, unsigned flags, osg::Camera* camera,
-                                   const osg::Matrix& view,
-                                   const osg::Matrix& projection,
-                                   bool useMasterSceneData);
-
-       /**
-        */
-       flightgear::CameraInfo* buildDeferredPipeline(flightgear::CameraGroup* cgroup, unsigned flags, osg::Camera* camera,
-                                   const osg::Matrix& view, const osg::Matrix& projection, osg::GraphicsContext* gc);
-
-    void updateShadowCamera(const flightgear::CameraInfo* info, const osg::Vec3d& position);
-    void updateShadowMapSize(int mapSize);
-    void enableShadows(bool enabled);
-    void updateCascadeFar(int index, float far_m);
-    void updateCascadeNumber(size_t num);
-
-    SGSky* getSky() const { return _sky; }
-
-       void setPlanes( double zNear, double zFar );
-    
-    /**
-     * inform the renderer when the global (2D) panel is changed
-     */
-    void panelChanged();
-protected:
-    osg::ref_ptr<osgViewer::Viewer> viewer;
-    osg::ref_ptr<flightgear::FGEventHandler> eventHandler;
-    SGPropertyNode_ptr _scenery_loaded,_scenery_override;
-    SGPropertyNode_ptr _skyblend, _splash_alpha;
-    SGPropertyNode_ptr _point_sprites, _enhanced_lighting, _distance_attenuation;
-    SGPropertyNode_ptr _textures;
-    SGPropertyNode_ptr _cloud_status, _visibility_m; 
-    SGPropertyNode_ptr _xsize, _ysize;
-    SGPropertyNode_ptr _panel_hotspots, _sim_delta_sec, _horizon_effect, _altitude_ft;
-    SGPropertyNode_ptr _virtual_cockpit;
-    SGTimeStamp _splash_time;
-    SGSky* _sky;
-    bool _classicalRenderer;
-    int _shadowMapSize;
-    size_t _numCascades;
-    float _cascadeFar[4];
-
-    osg::Camera* buildDeferredGeometryCamera( flightgear::CameraInfo* info, osg::GraphicsContext* gc );
-    osg::Camera* buildDeferredShadowCamera( flightgear::CameraInfo* info, osg::GraphicsContext* gc );
-    osg::Camera* buildDeferredLightingCamera( flightgear::CameraInfo* info, osg::GraphicsContext* gc );
-    void updateShadowCascade(const flightgear::CameraInfo* info, osg::Camera* camera, osg::Group* grp, int idx, double left, double right, double bottom, double top, double zNear, double f1, double f2);
-    osg::Vec3 getSunDirection() const;
-    osg::ref_ptr<osg::Uniform> _ambientFactor;
-    osg::ref_ptr<osg::Uniform> _sunDiffuse;
-    osg::ref_ptr<osg::Uniform> _sunSpecular;
-    osg::ref_ptr<osg::Uniform> _sunDirection;
-    osg::ref_ptr<osg::Uniform> _planes;
-    osg::ref_ptr<osg::Uniform> _fogColor;
-    osg::ref_ptr<osg::Uniform> _fogDensity;
-    osg::ref_ptr<osg::Uniform> _shadowNumber;
-    osg::ref_ptr<osg::Uniform> _shadowDistances;
-};
-
-bool fgDumpSceneGraphToFile(const char* filename);
-bool fgDumpTerrainBranchToFile(const char* filename);
-
-namespace flightgear
-{
-bool printVisibleSceneInfo(FGRenderer* renderer);
-}
-
-#endif
diff --git a/src/Main/splash.cxx b/src/Main/splash.cxx
deleted file mode 100644 (file)
index a170a31..0000000
+++ /dev/null
@@ -1,376 +0,0 @@
-// splash.cxx -- draws the initial splash screen
-//
-// Written by Curtis Olson, started July 1998.  (With a little looking
-// at Freidemann's panel code.) :-)
-//
-// Copyright (C) 1997  Michele F. America  - nomimarketing@mail.telepac.pt
-//
-// This program is free software; you can redistribute it and/or
-// modify it under the terms of the GNU General Public License as
-// published by the Free Software Foundation; either version 2 of the
-// License, or (at your option) any later version.
-//
-// This program is distributed in the hope that it will be useful, but
-// WITHOUT ANY WARRANTY; without even the implied warranty of
-// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
-// General Public License for more details.
-//
-// You should have received a copy of the GNU General Public License
-// along with this program; if not, write to the Free Software
-// Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
-//
-// $Id$
-
-
-#ifdef HAVE_CONFIG_H
-#  include <config.h>
-#endif
-
-#include <osg/BlendFunc>
-#include <osg/Camera>
-#include <osg/Depth>
-#include <osg/Geometry>
-#include <osg/Node>
-#include <osg/NodeCallback>
-#include <osg/NodeVisitor>
-#include <osg/StateSet>
-#include <osg/Switch>
-#include <osg/Texture2D>
-#include <osgUtil/CullVisitor>
-#include <osgText/Text>
-#include <osgDB/ReadFile>
-
-#include <simgear/compiler.h>
-
-#include <simgear/debug/logstream.hxx>
-#include <simgear/math/sg_random.h>
-#include <simgear/misc/sg_path.hxx>
-
-#include <plib/fnt.h>
-
-#include "GUI/FGFontCache.hxx"
-#include "GUI/FGColor.hxx"
-
-#include "globals.hxx"
-#include "fg_props.hxx"
-#include "splash.hxx"
-#include "renderer.hxx"
-#include "fg_os.hxx"
-
-class FGSplashUpdateCallback : public osg::Drawable::UpdateCallback {
-public:
-  FGSplashUpdateCallback(osg::Vec4Array* colorArray, SGPropertyNode* prop) :
-    _colorArray(colorArray),
-    _colorProperty(prop),
-    _alphaProperty(fgGetNode("/sim/startup/splash-alpha", true))
-  { }
-  virtual void update(osg::NodeVisitor*, osg::Drawable*)
-  {
-    FGColor c(0, 0, 0);
-    if (_colorProperty) {
-      c.merge(_colorProperty);
-      (*_colorArray)[0][0] = c.red();
-      (*_colorArray)[0][1] = c.green();
-      (*_colorArray)[0][2] = c.blue();
-    }
-    (*_colorArray)[0][3] = _alphaProperty->getFloatValue();
-    _colorArray->dirty();
-  }
-private:
-  osg::ref_ptr<osg::Vec4Array> _colorArray;
-  SGSharedPtr<const SGPropertyNode> _colorProperty;
-  SGSharedPtr<const SGPropertyNode> _alphaProperty;
-};
-
-class FGSplashTextUpdateCallback : public osg::Drawable::UpdateCallback {
-public:
-  FGSplashTextUpdateCallback(const SGPropertyNode* prop) :
-    _textProperty(prop),
-    _alphaProperty(fgGetNode("/sim/startup/splash-alpha", true)),
-    _styleProperty(fgGetNode("/sim/gui/style[0]", true))
-  {}
-  virtual void update(osg::NodeVisitor*, osg::Drawable* drawable)
-  {
-    assert(dynamic_cast<osgText::Text*>(drawable));
-    osgText::Text* text = static_cast<osgText::Text*>(drawable);
-
-    FGColor c(1.0, 0.9, 0.0);
-    c.merge(_styleProperty->getNode("colors/splash-font"));
-    float alpha = _alphaProperty->getFloatValue();
-    text->setColor(osg::Vec4(c.red(), c.green(), c.blue(), alpha));
-
-    const char* s = _textProperty->getStringValue();
-    if (s && fgGetBool("/sim/startup/splash-progress", true))
-      text->setText(s);
-    else
-      text->setText("");
-  }
-private:
-  SGSharedPtr<const SGPropertyNode> _textProperty;
-  SGSharedPtr<const SGPropertyNode> _alphaProperty;
-  SGSharedPtr<const SGPropertyNode> _styleProperty;
-};
-
-
-
-class FGSplashContentProjectionCalback : public osg::NodeCallback {
-public:
-  virtual void operator()(osg::Node* node, osg::NodeVisitor* nv)
-  { 
-    assert(dynamic_cast<osgUtil::CullVisitor*>(nv));
-    osgUtil::CullVisitor* cullVisitor = static_cast<osgUtil::CullVisitor*>(nv);
-
-    // adjust the projection matrix in a way that preserves the aspect ratio
-    // of the content ...
-    const osg::Viewport* viewport = cullVisitor->getViewport();
-    float viewportAspect = float(viewport->height())/float(viewport->width());
-
-    float height, width;
-    if (viewportAspect < 1) {
-      height = 1;
-      width = 1/viewportAspect;
-    } else {
-      height = viewportAspect;
-      width = 1;
-    }
-
-    osg::RefMatrix* matrix = new osg::RefMatrix;
-    matrix->makeOrtho2D(-width, width, -height, height);
-
-    // The trick is to have the projection matrix adapted independent
-    // of the scenegraph but dependent on the viewport of this current
-    // camera we cull for. Therefore we do not put that projection matrix into
-    // an additional camera rather than from within that cull callback.
-    cullVisitor->pushProjectionMatrix(matrix);
-    traverse(node, nv);
-    cullVisitor->popProjectionMatrix();
-  }
-};
-
-char *genNameString()
-{
-    std::string website = "http://www.flightgear.org";
-    std::string programName = "FlightGear";
-    char *name = new char[26];
-    name[20] = 114;
-    name[8] = 119;
-    name[5] = 47;
-    name[12] = 108;
-    name[2] = 116;
-    name[1] = 116;
-    name[16] = 116;
-    name[13] = 105;
-    name[17] = 103;
-    name[19] = 97;
-    name[25] = 0;
-    name[0] = 104;
-    name[24] = 103;
-    name[21] = 46;
-    name[15] = 104;
-    name[3] = 112;
-    name[22] = 111;
-    name[18] = 101;
-    name[7] = 119;
-    name[14] = 103;
-    name[23] = 114;
-    name[4] = 58;
-    name[11] = 102;
-    name[9] = 119;
-    name[10] = 46;
-    name[6] = 47;
-    return name;
-}
-
-static osg::Node* fgCreateSplashCamera()
-{
-  const char* splash_texture = fgGetString("/sim/startup/splash-texture");
-  SGSharedPtr<SGPropertyNode> style = fgGetNode("/sim/gui/style[0]", true);
-
-  char *namestring = genNameString();
-  fgSetString("/sim/startup/program-name", namestring);
-  delete[] namestring;
-
-  SGPath tpath;
-  if (splash_texture  && strcmp(splash_texture, "")) {
-      tpath = globals->resolve_maybe_aircraft_path(splash_texture);
-      if (tpath.isNull())
-      {
-          SG_LOG( SG_VIEW, SG_ALERT, "Cannot find splash screen file '" << splash_texture
-                  << "'. Using default." );
-      }
-  }
-
-  if (tpath.isNull()) {
-    // no splash screen specified - select random image
-    tpath = globals->get_fg_root();
-    // load in the texture data
-    int num = (int)(sg_random() * 5.0 + 1.0);
-    char num_str[5];
-    snprintf(num_str, 4, "%d", num);
-
-    tpath.append( "Textures/Splash" );
-    tpath.concat( num_str );
-    tpath.concat( ".png" );
-  }
-
-  osg::Texture2D* splashTexture = new osg::Texture2D;
-  splashTexture->setImage(osgDB::readImageFile(tpath.c_str()));
-
-  osg::Camera* camera = new osg::Camera;
-  camera->setReferenceFrame(osg::Transform::ABSOLUTE_RF);
-  camera->setProjectionMatrix(osg::Matrix::ortho2D(-1, 1, -1, 1));
-  camera->setViewMatrix(osg::Matrix::identity());
-  camera->setRenderOrder(osg::Camera::POST_RENDER, 10000);
-  camera->setClearMask(0);
-  camera->setAllowEventFocus(false);
-  camera->setCullingActive(false);
-
-  osg::StateSet* stateSet = camera->getOrCreateStateSet();
-  stateSet->setMode(GL_ALPHA_TEST, osg::StateAttribute::OFF);
-  stateSet->setMode(GL_BLEND, osg::StateAttribute::ON);
-  stateSet->setAttribute(new osg::BlendFunc);
-  stateSet->setMode(GL_CULL_FACE, osg::StateAttribute::OFF);
-  stateSet->setMode(GL_DEPTH_TEST, osg::StateAttribute::OFF);
-  stateSet->setAttribute(new osg::Depth(osg::Depth::ALWAYS, 0, 1, false));
-  stateSet->setMode(GL_LIGHTING, osg::StateAttribute::OFF);
-
-
-  osg::Geometry* geometry = new osg::Geometry;
-  geometry->setSupportsDisplayList(false);
-
-  osg::Vec3Array* vertexArray = new osg::Vec3Array;
-  vertexArray->push_back(osg::Vec3(-1, -1, 0));
-  vertexArray->push_back(osg::Vec3( 1, -1, 0));
-  vertexArray->push_back(osg::Vec3( 1,  1, 0));
-  vertexArray->push_back(osg::Vec3(-1,  1, 0));
-  geometry->setVertexArray(vertexArray);
-  osg::Vec4Array* colorArray = new osg::Vec4Array;
-  colorArray->push_back(osg::Vec4(0, 0, 0, 1));
-  geometry->setColorArray(colorArray);
-  geometry->setColorBinding(osg::Geometry::BIND_OVERALL);
-  geometry->addPrimitiveSet(new osg::DrawArrays(GL_POLYGON, 0, 4));
-  geometry->setUpdateCallback(new FGSplashUpdateCallback(colorArray,
-                              style->getNode("colors/splash-screen")));
-
-  osg::Geode* geode = new osg::Geode;
-  geode->addDrawable(geometry);
-
-  stateSet = geode->getOrCreateStateSet();
-  stateSet->setRenderBinDetails(1, "RenderBin");
-  camera->addChild(geode);
-
-
-  // The group is needed because of osg is handling the cull callbacks in a
-  // different way for groups than for a geode. It does not hurt here ...
-  osg::Group* group = new osg::Group;
-  group->setCullCallback(new FGSplashContentProjectionCalback);
-  camera->addChild(group);
-
-  geode = new osg::Geode;
-  stateSet = geode->getOrCreateStateSet();
-  stateSet->setRenderBinDetails(2, "RenderBin");
-  group->addChild(geode);
-
-
-  geometry = new osg::Geometry;
-  geometry->setSupportsDisplayList(false);
-
-  vertexArray = new osg::Vec3Array;
-  vertexArray->push_back(osg::Vec3(-0.84, -0.84, 0));
-  vertexArray->push_back(osg::Vec3( 0.84, -0.84, 0));
-  vertexArray->push_back(osg::Vec3( 0.84,  0.84, 0));
-  vertexArray->push_back(osg::Vec3(-0.84,  0.84, 0));
-  geometry->setVertexArray(vertexArray);
-  osg::Vec2Array* texCoordArray = new osg::Vec2Array;
-  texCoordArray->push_back(osg::Vec2(0, 0));
-  texCoordArray->push_back(osg::Vec2(1, 0));
-  texCoordArray->push_back(osg::Vec2(1, 1));
-  texCoordArray->push_back(osg::Vec2(0, 1));
-  geometry->setTexCoordArray(0, texCoordArray);
-  colorArray = new osg::Vec4Array;
-  colorArray->push_back(osg::Vec4(1, 1, 1, 1));
-  geometry->setColorArray(colorArray);
-  geometry->setColorBinding(osg::Geometry::BIND_OVERALL);
-  geometry->addPrimitiveSet(new osg::DrawArrays(GL_POLYGON, 0, 4));
-  geometry->setUpdateCallback(new FGSplashUpdateCallback(colorArray, 0));
-  stateSet = geometry->getOrCreateStateSet();
-  stateSet->setTextureMode(0, GL_TEXTURE_2D, osg::StateAttribute::ON);
-  stateSet->setTextureAttribute(0, splashTexture);
-  geode->addDrawable(geometry);
-
-
-  osgText::Text* text = new osgText::Text;
-  std::string fn = style->getStringValue("fonts/splash", "");
-  text->setFont(globals->get_fontcache()->getfntpath(fn.c_str()).str());
-  text->setCharacterSize(0.06);
-  text->setColor(osg::Vec4(1, 1, 1, 1));
-  text->setPosition(osg::Vec3(0, -0.92, 0));
-  text->setAlignment(osgText::Text::CENTER_CENTER);
-  SGPropertyNode* prop = fgGetNode("/sim/startup/splash-progress-text", true);
-  prop->setStringValue("initializing");
-  text->setUpdateCallback(new FGSplashTextUpdateCallback(prop));
-  geode->addDrawable(text);
-
-  text = new osgText::Text;
-  text->setFont(globals->get_fontcache()->getfntpath(fn.c_str()).str());
-  text->setCharacterSize(0.08);
-  text->setColor(osg::Vec4(1, 1, 1, 1));
-  text->setPosition(osg::Vec3(0, 0.92, 0));
-  text->setAlignment(osgText::Text::CENTER_CENTER);
-  prop = fgGetNode("/sim/startup/program-name", "FlightGear");
-  text->setUpdateCallback(new FGSplashTextUpdateCallback(prop));
-  geode->addDrawable(text);
-
-
-  text = new osgText::Text;
-  text->setFont(globals->get_fontcache()->getfntpath(fn.c_str()).str());
-  text->setCharacterSize(0.06);
-  text->setColor(osg::Vec4(1, 1, 1, 1));
-  text->setPosition(osg::Vec3(0, 0.82, 0));
-  text->setAlignment(osgText::Text::CENTER_CENTER);
-  prop = fgGetNode("/sim/startup/splash-title", true);
-  text->setUpdateCallback(new FGSplashTextUpdateCallback(prop));
-  geode->addDrawable(text);
-
-  return camera;
-}
-
-// update callback for the switch node guarding that splash
-class FGSplashGroupUpdateCallback : public osg::NodeCallback {
-public:
-  FGSplashGroupUpdateCallback() :
-    _splashAlphaNode(fgGetNode("/sim/startup/splash-alpha", true))
-  { }
-  virtual void operator()(osg::Node* node, osg::NodeVisitor* nv)
-  {
-    assert(dynamic_cast<osg::Group*>(node));
-    osg::Group* group = static_cast<osg::Group*>(node);
-
-    double alpha = _splashAlphaNode->getDoubleValue();
-    if (alpha <= 0 || !fgGetBool("/sim/startup/splash-screen"))
-      group->removeChild(0, group->getNumChildren());
-    else if (group->getNumChildren() == 0)
-      group->addChild(fgCreateSplashCamera());
-
-    traverse(node, nv);
-  }
-private:
-  SGSharedPtr<const SGPropertyNode> _splashAlphaNode;
-};
-
-osg::Node* fgCreateSplashNode() {
-  osg::Group* group = new osg::Group;
-  group->setUpdateCallback(new FGSplashGroupUpdateCallback);
-  return group;
-}
-
-// Initialize the splash screen
-void fgSplashInit () {
-  SG_LOG( SG_VIEW, SG_INFO, "Initializing splash screen" );
-  globals->get_renderer()->splashinit();
-}
-
-void fgSplashProgress ( const char *text ) {
-  SG_LOG( SG_VIEW, SG_INFO, "Splash screen progress " << text );
-  fgSetString("/sim/startup/splash-progress-text", text);
-}
diff --git a/src/Main/splash.hxx b/src/Main/splash.hxx
deleted file mode 100644 (file)
index 30643c2..0000000
+++ /dev/null
@@ -1,45 +0,0 @@
-// splash.hxx -- draws the initial splash screen
-//
-// Written by Curtis Olson, started July 1998.  (With a little looking
-// at Freidemann's panel code.) :-)
-//
-// Copyright (C) 1997  Michele F. America  - nomimarketing@mail.telepac.pt
-//
-// This program is free software; you can redistribute it and/or
-// modify it under the terms of the GNU General Public License as
-// published by the Free Software Foundation; either version 2 of the
-// License, or (at your option) any later version.
-//
-// This program is distributed in the hope that it will be useful, but
-// WITHOUT ANY WARRANTY; without even the implied warranty of
-// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
-// General Public License for more details.
-//
-// You should have received a copy of the GNU General Public License
-// along with this program; if not, write to the Free Software
-// Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
-//
-// $Id$
-
-
-#ifndef _SPLASH_HXX
-#define _SPLASH_HXX
-
-#include <osg/Node>
-
-#ifndef __cplusplus
-# error This library requires C++
-#endif
-
-// Initialize the splash screen
-void fgSplashInit ();
-
-// Set progress information
-void fgSplashProgress ( const char *text );
-
-// Retrieve the splash screen node ...
-osg::Node* fgCreateSplashNode();
-
-#endif // _SPLASH_HXX
-
-
diff --git a/src/Main/viewer.cxx b/src/Main/viewer.cxx
deleted file mode 100644 (file)
index 97ae345..0000000
+++ /dev/null
@@ -1,680 +0,0 @@
-// viewer.cxx -- class for managing a viewer in the flightgear world.
-//
-// Written by Curtis Olson, started August 1997.
-//                          overhaul started October 2000.
-//   partially rewritten by Jim Wilson jim@kelcomaine.com using interface
-//                          by David Megginson March 2002
-//
-// Copyright (C) 1997 - 2000  Curtis L. Olson  - http://www.flightgear.org/~curt
-//
-// This program is free software; you can redistribute it and/or
-// modify it under the terms of the GNU General Public License as
-// published by the Free Software Foundation; either version 2 of the
-// License, or (at your option) any later version.
-//
-// This program is distributed in the hope that it will be useful, but
-// WITHOUT ANY WARRANTY; without even the implied warranty of
-// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
-// General Public License for more details.
-//
-// You should have received a copy of the GNU General Public License
-// along with this program; if not, write to the Free Software
-// Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
-//
-// $Id$
-
-#ifdef HAVE_CONFIG_H
-#  include "config.h"
-#endif
-
-#include <simgear/compiler.h>
-#include <cassert>
-
-#include "fg_props.hxx"
-
-#include <simgear/debug/logstream.hxx>
-#include <simgear/constants.h>
-#include <simgear/scene/model/placement.hxx>
-#include <simgear/scene/util/OsgMath.hxx>
-
-#include <Main/globals.hxx>
-#include <Scenery/scenery.hxx>
-#include <Model/acmodel.hxx>
-
-#include "viewer.hxx"
-
-#include "CameraGroup.hxx"
-
-using namespace flightgear;
-\f
-////////////////////////////////////////////////////////////////////////
-// Implementation of FGViewer.
-////////////////////////////////////////////////////////////////////////
-
-// Constructor...
-FGViewer::FGViewer( fgViewType Type, bool from_model, int from_model_index,
-                    bool at_model, int at_model_index,
-                    double damp_roll, double damp_pitch, double damp_heading,
-                    double x_offset_m, double y_offset_m, double z_offset_m,
-                    double heading_offset_deg, double pitch_offset_deg,
-                    double roll_offset_deg,
-                    double fov_deg, double aspect_ratio_multiplier,
-                    double target_x_offset_m, double target_y_offset_m,
-                    double target_z_offset_m, double near_m, bool internal ):
-    _dirty(true),
-    _roll_deg(0),
-    _pitch_deg(0),
-    _heading_deg(0),
-    _scaling_type(FG_SCALING_MAX),
-    _cameraGroup(CameraGroup::getDefault())
-{
-    _absolute_view_pos = SGVec3d(0, 0, 0);
-    _type = Type;
-    _from_model = from_model;
-    _from_model_index = from_model_index;
-    _at_model = at_model;
-    _at_model_index = at_model_index;
-
-    _internal = internal;
-
-    _dampFactor = SGVec3d::zeros();
-    _dampOutput = SGVec3d::zeros();
-    _dampTarget = SGVec3d::zeros();
-    
-    if (damp_roll > 0.0)
-      _dampFactor[0] = 1.0 / pow(10.0, fabs(damp_roll));
-    if (damp_pitch > 0.0)
-      _dampFactor[1] = 1.0 / pow(10.0, fabs(damp_pitch));
-    if (damp_heading > 0.0)
-      _dampFactor[2] = 1.0 / pow(10.0, fabs(damp_heading));
-
-    _offset_m.x() = x_offset_m;
-    _offset_m.y() = y_offset_m;
-    _offset_m.z() = z_offset_m;
-    _heading_offset_deg = heading_offset_deg;
-    _pitch_offset_deg = pitch_offset_deg;
-    _roll_offset_deg = roll_offset_deg;
-    _goal_heading_offset_deg = heading_offset_deg;
-    _goal_pitch_offset_deg = pitch_offset_deg;
-    _goal_roll_offset_deg = roll_offset_deg;
-    if (fov_deg > 0) {
-      _fov_deg = fov_deg;
-    } else {
-      _fov_deg = 55;
-    }
-
-    _aspect_ratio_multiplier = aspect_ratio_multiplier;
-    _target_offset_m.x() = target_x_offset_m;
-    _target_offset_m.y() = target_y_offset_m;
-    _target_offset_m.z() = target_z_offset_m;
-    _ground_level_nearplane_m = near_m;
-    // a reasonable guess for init, so that the math doesn't blow up
-}
-
-
-// Destructor
-FGViewer::~FGViewer( void ) {
-}
-
-void
-FGViewer::init ()
-{
-}
-
-void
-FGViewer::bind ()
-{
-}
-
-void
-FGViewer::unbind ()
-{
-}
-
-void
-FGViewer::setType ( int type )
-{
-  if (type == 0)
-    _type = FG_LOOKFROM;
-  if (type == 1)
-    _type = FG_LOOKAT;
-}
-
-void
-FGViewer::setInternal ( bool internal )
-{
-  _internal = internal;
-}
-
-void
-FGViewer::setPosition (double lon_deg, double lat_deg, double alt_ft)
-{
-  _dirty = true;
-  _position = SGGeod::fromDegFt(lon_deg, lat_deg, alt_ft);
-}
-
-void
-FGViewer::setTargetPosition (double lon_deg, double lat_deg, double alt_ft)
-{
-  _dirty = true;
-  _target = SGGeod::fromDegFt(lon_deg, lat_deg, alt_ft);
-}
-
-void
-FGViewer::setRoll_deg (double roll_deg)
-{
-  _dirty = true;
-  _roll_deg = roll_deg;
-}
-
-void
-FGViewer::setPitch_deg (double pitch_deg)
-{
-  _dirty = true;
-  _pitch_deg = pitch_deg;
-}
-
-void
-FGViewer::setHeading_deg (double heading_deg)
-{
-  _dirty = true;
-  _heading_deg = heading_deg;
-}
-
-void
-FGViewer::setOrientation (double roll_deg, double pitch_deg, double heading_deg)
-{
-  _dirty = true;
-  _roll_deg = roll_deg;
-  _pitch_deg = pitch_deg;
-  _heading_deg = heading_deg;
-}
-
-void
-FGViewer::setTargetRoll_deg (double target_roll_deg)
-{
-  _dirty = true;
-  _target_roll_deg = target_roll_deg;
-}
-
-void
-FGViewer::setTargetPitch_deg (double target_pitch_deg)
-{
-  _dirty = true;
-  _target_pitch_deg = target_pitch_deg;
-}
-
-void
-FGViewer::setTargetHeading_deg (double target_heading_deg)
-{
-  _dirty = true;
-  _target_heading_deg = target_heading_deg;
-}
-
-void
-FGViewer::setTargetOrientation (double target_roll_deg, double target_pitch_deg, double target_heading_deg)
-{
-  _dirty = true;
-  _target_roll_deg = target_roll_deg;
-  _target_pitch_deg = target_pitch_deg;
-  _target_heading_deg = target_heading_deg;
-}
-
-void
-FGViewer::setXOffset_m (double x_offset_m)
-{
-  _dirty = true;
-  _offset_m.x() = x_offset_m;
-}
-
-void
-FGViewer::setYOffset_m (double y_offset_m)
-{
-  _dirty = true;
-  _offset_m.y() = y_offset_m;
-}
-
-void
-FGViewer::setZOffset_m (double z_offset_m)
-{
-  _dirty = true;
-  _offset_m.z() = z_offset_m;
-}
-
-void
-FGViewer::setTargetXOffset_m (double target_x_offset_m)
-{
-  _dirty = true;
-  _target_offset_m.x() = target_x_offset_m;
-}
-
-void
-FGViewer::setTargetYOffset_m (double target_y_offset_m)
-{
-  _dirty = true;
-  _target_offset_m.y() = target_y_offset_m;
-}
-
-void
-FGViewer::setTargetZOffset_m (double target_z_offset_m)
-{
-  _dirty = true;
-  _target_offset_m.z() = target_z_offset_m;
-}
-
-void
-FGViewer::setPositionOffsets (double x_offset_m, double y_offset_m, double z_offset_m)
-{
-  _dirty = true;
-  _offset_m.x() = x_offset_m;
-  _offset_m.y() = y_offset_m;
-  _offset_m.z() = z_offset_m;
-}
-
-void
-FGViewer::setRollOffset_deg (double roll_offset_deg)
-{
-  _dirty = true;
-  _roll_offset_deg = roll_offset_deg;
-}
-
-void
-FGViewer::setPitchOffset_deg (double pitch_offset_deg)
-{
-  _dirty = true;
-  _pitch_offset_deg = pitch_offset_deg;
-}
-
-void
-FGViewer::setHeadingOffset_deg (double heading_offset_deg)
-{
-  _dirty = true;
-  if (_at_model && (_offset_m.x() == 0.0)&&(_offset_m.z() == 0.0))
-  {
-      /* avoid optical effects (e.g. rotating sky) when "looking at" with
-       * heading offsets x==z==0 (view heading cannot change). */
-      _heading_offset_deg = 0.0;
-  }
-  else
-      _heading_offset_deg = heading_offset_deg;
-}
-
-void
-FGViewer::setGoalRollOffset_deg (double goal_roll_offset_deg)
-{
-  _dirty = true;
-  _goal_roll_offset_deg = goal_roll_offset_deg;
-}
-
-void
-FGViewer::setGoalPitchOffset_deg (double goal_pitch_offset_deg)
-{
-  _dirty = true;
-  _goal_pitch_offset_deg = goal_pitch_offset_deg;
-  if ( _goal_pitch_offset_deg < -90 ) {
-    _goal_pitch_offset_deg = -90.0;
-  }
-  if ( _goal_pitch_offset_deg > 90.0 ) {
-    _goal_pitch_offset_deg = 90.0;
-  }
-
-}
-
-void
-FGViewer::setGoalHeadingOffset_deg (double goal_heading_offset_deg)
-{
-  _dirty = true;
-  if (_at_model && (_offset_m.x() == 0.0)&&(_offset_m.z() == 0.0))
-  {
-      /* avoid optical effects (e.g. rotating sky) when "looking at" with
-       * heading offsets x==z==0 (view heading cannot change). */
-      _goal_heading_offset_deg = 0.0;
-      return;
-  }
-  
-  _goal_heading_offset_deg = goal_heading_offset_deg;
-  while ( _goal_heading_offset_deg < 0.0 ) {
-    _goal_heading_offset_deg += 360;
-  }
-  while ( _goal_heading_offset_deg > 360 ) {
-    _goal_heading_offset_deg -= 360;
-  }
-}
-
-void
-FGViewer::setOrientationOffsets (double roll_offset_deg, double pitch_offset_deg, double heading_offset_deg)
-{
-  _dirty = true;
-  _roll_offset_deg = roll_offset_deg;
-  _pitch_offset_deg = pitch_offset_deg;
-  _heading_offset_deg = heading_offset_deg;
-}
-
-// recalc() is done every time one of the setters is called (making the 
-// cached data "dirty") on the next "get".  It calculates all the outputs 
-// for viewer.
-void
-FGViewer::recalc ()
-{
-  if (_type == FG_LOOKFROM) {
-    recalcLookFrom();
-  } else {
-    recalcLookAt();
-  }
-
-  set_clean();
-}
-
-// recalculate for LookFrom view type...
-void
-FGViewer::recalcLookFrom ()
-{
-  // Update location data ...
-  if ( _from_model ) {
-    SGModelPlacement* placement = globals->get_aircraft_model()->get3DModel();
-    _position = placement->getPosition();
-  
-    _heading_deg = placement->getHeadingDeg();
-    _pitch_deg = placement->getPitchDeg();
-    _roll_deg = placement->getRollDeg();
-  }
-
-  double head = _heading_deg;
-  double pitch = _pitch_deg;
-  double roll = _roll_deg;
-  if ( !_from_model ) {
-    // update from our own data...
-    setDampTarget(roll, pitch, head);
-    getDampOutput(roll, pitch, head);
-  }
-
-  // The rotation rotating from the earth centerd frame to
-  // the horizontal local frame
-  SGQuatd hlOr = SGQuatd::fromLonLat(_position);
-
-  // The rotation from the horizontal local frame to the basic view orientation
-  SGQuatd hlToBody = SGQuatd::fromYawPitchRollDeg(head, pitch, roll);
-
-  // The rotation offset, don't know why heading is negative here ...
-  mViewOffsetOr
-      = SGQuatd::fromYawPitchRollDeg(-_heading_offset_deg, _pitch_offset_deg,
-                                     _roll_offset_deg);
-
-  // Compute the eyepoints orientation and position
-  // wrt the earth centered frame - that is global coorinates
-  SGQuatd ec2body = hlOr*hlToBody;
-
-  // The cartesian position of the basic view coordinate
-  SGVec3d position = SGVec3d::fromGeod(_position);
-
-  // This is rotates the x-forward, y-right, z-down coordinate system the where
-  // simulation runs into the OpenGL camera system with x-right, y-up, z-back.
-  SGQuatd q(-0.5, -0.5, 0.5, 0.5);
-
-  _absolute_view_pos = position + (ec2body*q).backTransform(_offset_m);
-  mViewOrientation = ec2body*mViewOffsetOr*q;
-}
-
-void
-FGViewer::recalcLookAt ()
-{
-  // The geodetic position of our target to look at
-  if ( _at_model ) {
-    SGModelPlacement* placement = globals->get_aircraft_model()->get3DModel();
-    _target = placement->getPosition();
-    _target_heading_deg = placement->getHeadingDeg();
-    _target_pitch_deg = placement->getPitchDeg();
-    _target_roll_deg = placement->getRollDeg();
-  } else {
-    // if not model then calculate our own target position...
-    setDampTarget(_target_roll_deg, _target_pitch_deg, _target_heading_deg);
-    getDampOutput(_target_roll_deg, _target_pitch_deg, _target_heading_deg);
-  }
-
-  SGQuatd geodTargetOr = SGQuatd::fromYawPitchRollDeg(_target_heading_deg,
-                                                   _target_pitch_deg,
-                                                   _target_roll_deg);
-  SGQuatd geodTargetHlOr = SGQuatd::fromLonLat(_target);
-
-
-  if ( _from_model ) {
-    SGModelPlacement* placement = globals->get_aircraft_model()->get3DModel();
-    _position = placement->getPosition();
-    _heading_deg = placement->getHeadingDeg();
-    _pitch_deg = placement->getPitchDeg();
-    _roll_deg = placement->getRollDeg();
-  } else {
-    // update from our own data, just the rotation here...
-    setDampTarget(_roll_deg, _pitch_deg, _heading_deg);
-    getDampOutput(_roll_deg, _pitch_deg, _heading_deg);
-  }
-  SGQuatd geodEyeOr = SGQuatd::fromYawPitchRollDeg(_heading_deg, _pitch_deg, _roll_deg);
-  SGQuatd geodEyeHlOr = SGQuatd::fromLonLat(_position);
-
-  // the rotation offset, don't know why heading is negative here ...
-  mViewOffsetOr =
-    SGQuatd::fromYawPitchRollDeg(-_heading_offset_deg + 180, _pitch_offset_deg,
-                                 _roll_offset_deg);
-
-  // Offsets to the eye position
-  SGVec3d eyeOff(-_offset_m.z(), _offset_m.x(), -_offset_m.y());
-  SGQuatd ec2eye = geodEyeHlOr*geodEyeOr;
-  SGVec3d eyeCart = SGVec3d::fromGeod(_position);
-  eyeCart += (ec2eye*mViewOffsetOr).backTransform(eyeOff);
-
-  SGVec3d atCart = SGVec3d::fromGeod(_target);
-
-  // add target offsets to at_position...
-  SGVec3d target_pos_off(-_target_offset_m.z(), _target_offset_m.x(),
-                         -_target_offset_m.y());
-  target_pos_off = (geodTargetHlOr*geodTargetOr).backTransform(target_pos_off);
-  atCart += target_pos_off;
-  eyeCart += target_pos_off;
-
-  // Compute the eyepoints orientation and position
-  // wrt the earth centered frame - that is global coorinates
-  _absolute_view_pos = eyeCart;
-
-  // the view direction
-  SGVec3d dir = normalize(atCart - eyeCart);
-  // the up directon
-  SGVec3d up = ec2eye.backTransform(SGVec3d(0, 0, -1));
-  // rotate -dir to the 2-th unit vector
-  // rotate up to 1-th unit vector
-  // Note that this matches the OpenGL camera coordinate system
-  // with x-right, y-up, z-back.
-  mViewOrientation = SGQuatd::fromRotateTo(-dir, 2, up, 1);
-}
-
-void
-FGViewer::setDampTarget(double roll, double pitch, double heading)
-{
-  _dampTarget = SGVec3d(roll, pitch, heading);
-}
-
-void
-FGViewer::getDampOutput(double& roll, double& pitch, double& heading)
-{
-  roll = _dampOutput[0];
-  pitch = _dampOutput[1];
-  heading = _dampOutput[2];
-}
-
-
-void
-FGViewer::updateDampOutput(double dt)
-{
-  static FGViewer *last_view = 0;
-  if ((last_view != this) || (dt > 1.0)) {
-    _dampOutput = _dampTarget;
-    last_view = this;
-    return;
-  }
-  
-  const double interval = 0.01;
-  while (dt > interval) {
-    
-    for (unsigned int i=0; i<3; ++i) {
-      if (_dampFactor[i] <= 0.0) {
-        // axis is un-damped, set output to target directly
-        _dampOutput[i] = _dampTarget[i];
-        continue;
-      }
-      
-      double d = _dampOutput[i] - _dampTarget[i];
-      if (d > 180.0) {
-        _dampOutput[i] -= 360.0;
-      } else if (d < -180.0) {
-        _dampOutput[i] += 360.0;
-      }
-      
-      _dampOutput[i] = (_dampTarget[i] * _dampFactor[i]) + 
-        (_dampOutput[i] * (1.0 - _dampFactor[i]));
-    } // of axis iteration
-    
-    dt -= interval;
-  } // of dt subdivision by interval
-}
-
-double
-FGViewer::get_h_fov()
-{
-    double aspectRatio = _cameraGroup->getMasterAspectRatio();
-    switch (_scaling_type) {
-    case FG_SCALING_WIDTH:  // h_fov == fov
-       return _fov_deg;
-    case FG_SCALING_MAX:
-       if (aspectRatio < 1.0) {
-           // h_fov == fov
-           return _fov_deg;
-       } else {
-           // v_fov == fov
-           return
-                atan(tan(_fov_deg/2 * SG_DEGREES_TO_RADIANS)
-                     / (aspectRatio*_aspect_ratio_multiplier))
-                * SG_RADIANS_TO_DEGREES * 2;
-       }
-    default:
-       assert(false);
-    }
-    return 0.0;
-}
-
-
-
-double
-FGViewer::get_v_fov()
-{
-    double aspectRatio = _cameraGroup->getMasterAspectRatio();
-    switch (_scaling_type) {
-    case FG_SCALING_WIDTH:  // h_fov == fov
-       return 
-            atan(tan(_fov_deg/2 * SG_DEGREES_TO_RADIANS)
-                 * (aspectRatio*_aspect_ratio_multiplier))
-            * SG_RADIANS_TO_DEGREES * 2;
-    case FG_SCALING_MAX:
-       if (aspectRatio < 1.0) {
-           // h_fov == fov
-           return
-                atan(tan(_fov_deg/2 * SG_DEGREES_TO_RADIANS)
-                     * (aspectRatio*_aspect_ratio_multiplier))
-                * SG_RADIANS_TO_DEGREES * 2;
-       } else {
-           // v_fov == fov
-           return _fov_deg;
-       }
-    default:
-       assert(false);
-    }
-    return 0.0;
-}
-
-void
-FGViewer::update (double dt)
-{
-  updateDampOutput(dt);
-  
-  int i;
-  int dt_ms = int(dt * 1000);
-  for ( i = 0; i < dt_ms; i++ ) {
-    if ( fabs( _goal_heading_offset_deg - _heading_offset_deg) < 1 ) {
-      setHeadingOffset_deg( _goal_heading_offset_deg );
-      break;
-    } else {
-      // move current_view.headingoffset towards
-      // current_view.goal_view_offset
-      if ( _goal_heading_offset_deg > _heading_offset_deg )
-       {
-         if ( _goal_heading_offset_deg - _heading_offset_deg < 180 ){
-           incHeadingOffset_deg( 0.5 );
-         } else {
-           incHeadingOffset_deg( -0.5 );
-         }
-       } else {
-         if ( _heading_offset_deg - _goal_heading_offset_deg < 180 ){
-           incHeadingOffset_deg( -0.5 );
-         } else {
-           incHeadingOffset_deg( 0.5 );
-         }
-       }
-      if ( _heading_offset_deg > 360 ) {
-       incHeadingOffset_deg( -360 );
-      } else if ( _heading_offset_deg < 0 ) {
-       incHeadingOffset_deg( 360 );
-      }
-    }
-  }
-
-  for ( i = 0; i < dt_ms; i++ ) {
-    if ( fabs( _goal_pitch_offset_deg - _pitch_offset_deg ) < 1 ) {
-      setPitchOffset_deg( _goal_pitch_offset_deg );
-      break;
-    } else {
-      // move current_view.pitch_offset_deg towards
-      // current_view.goal_pitch_offset
-      if ( _goal_pitch_offset_deg > _pitch_offset_deg )
-       {
-         incPitchOffset_deg( 1.0 );
-       } else {
-           incPitchOffset_deg( -1.0 );
-       }
-      if ( _pitch_offset_deg > 90 ) {
-       setPitchOffset_deg(90);
-      } else if ( _pitch_offset_deg < -90 ) {
-       setPitchOffset_deg( -90 );
-      }
-    }
-  }
-
-
-  for ( i = 0; i < dt_ms; i++ ) {
-    if ( fabs( _goal_roll_offset_deg - _roll_offset_deg ) < 1 ) {
-      setRollOffset_deg( _goal_roll_offset_deg );
-      break;
-    } else {
-      // move current_view.roll_offset_deg towards
-      // current_view.goal_roll_offset
-      if ( _goal_roll_offset_deg > _roll_offset_deg )
-       {
-         incRollOffset_deg( 1.0 );
-       } else {
-           incRollOffset_deg( -1.0 );
-       }
-      if ( _roll_offset_deg > 90 ) {
-       setRollOffset_deg(90);
-      } else if ( _roll_offset_deg < -90 ) {
-       setRollOffset_deg( -90 );
-      }
-    }
-  }
-  recalc();
-  if( fgGetBool( "/sim/rendering/draw-otw", true ) ) {
-    _cameraGroup->update(toOsg(_absolute_view_pos), toOsg(mViewOrientation));
-    _cameraGroup->setCameraParameters(get_v_fov(), get_aspect_ratio());
-  }
-}
-
-double FGViewer::get_aspect_ratio() const
-{
-    return _cameraGroup->getMasterAspectRatio();
-}
diff --git a/src/Main/viewer.hxx b/src/Main/viewer.hxx
deleted file mode 100644 (file)
index ef5df50..0000000
+++ /dev/null
@@ -1,345 +0,0 @@
-// viewer.hxx -- class for managing a viewer in the flightgear world.
-//
-// Written by Curtis Olson, started August 1997.
-//                          overhaul started October 2000.
-//   partially rewritten by Jim Wilson jim@kelcomaine.com using interface
-//                          by David Megginson March 2002
-//
-// Copyright (C) 1997 - 2000  Curtis L. Olson  - http://www.flightgear.org/~curt
-//
-// This program is free software; you can redistribute it and/or
-// modify it under the terms of the GNU General Public License as
-// published by the Free Software Foundation; either version 2 of the
-// License, or (at your option) any later version.
-//
-// This program is distributed in the hope that it will be useful, but
-// WITHOUT ANY WARRANTY; without even the implied warranty of
-// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
-// General Public License for more details.
-//
-// You should have received a copy of the GNU General Public License
-// along with this program; if not, write to the Free Software
-// Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
-//
-// $Id$
-
-
-#ifndef _VIEWER_HXX
-#define _VIEWER_HXX                                
-
-namespace flightgear
-{
-class CameraGroup;
-}
-
-#include <osg/ref_ptr>
-
-#include <simgear/compiler.h>
-#include <simgear/constants.h>
-#include <simgear/structure/subsystem_mgr.hxx>
-#include <simgear/math/SGMath.hxx>
-
-#define FG_FOV_MIN 0.1
-#define FG_FOV_MAX 179.9
-
-enum fgViewType {
- FG_LOOKFROM = 0,
- FG_LOOKAT = 1
-};
-
-// Define a structure containing view information
-class FGViewer : public SGSubsystem {
-
-public:
-
-    enum fgScalingType {  // nominal Field Of View actually applies to ...
-       FG_SCALING_WIDTH,       // window width
-       FG_SCALING_MAX          // max(width, height)
-       // FG_SCALING_G_MEAN,      // geometric_mean(width, height)
-       // FG_SCALING_INDEPENDENT  // whole screen
-    };
-
-    // Constructor
-    FGViewer( fgViewType Type, bool from_model, int from_model_index,
-              bool at_model, int at_model_index,
-              double damp_roll, double damp_pitch, double damp_heading,
-              double x_offset_m, double y_offset_m, double z_offset_m,
-              double heading_offset_deg, double pitch_offset_deg,
-              double roll_offset_deg,
-              double fov_deg, double aspect_ratio_multiplier,
-              double target_x_offset_m, double target_y_offset_m,
-              double target_z_offset_m, double near_m, bool internal );
-
-    // Destructor
-    virtual ~FGViewer( void );
-
-    //////////////////////////////////////////////////////////////////////
-    // Part 1: standard SGSubsystem implementation.
-    //////////////////////////////////////////////////////////////////////
-
-    virtual void init ();
-    virtual void bind ();
-    virtual void unbind ();
-    void update (double dt);
-
-
-    //////////////////////////////////////////////////////////////////////
-    // Part 2: user settings.
-    //////////////////////////////////////////////////////////////////////
-
-    virtual fgViewType getType() const { return _type; }
-    virtual void setType( int type );
-
-    virtual bool getInternal() const { return _internal; }
-    virtual void setInternal( bool internal );
-
-    // Reference geodetic position of view from position...
-    //   These are the actual aircraft position (pilot in
-    //   pilot view, model in model view).
-    //   FIXME: the model view position (ie target positions) 
-    //   should be in the model class.
-    virtual void setPosition (double lon_deg, double lat_deg, double alt_ft);
-    const SGGeod& getPosition() const { return _position; }
-
-    // Reference geodetic target position...
-    virtual void setTargetPosition (double lon_deg, double lat_deg, double alt_ft);
-    const SGGeod& getTargetPosition() const { return _target; }
-
-
-
-    // Position offsets from reference
-    //   These offsets position they "eye" in the scene according to a given
-    //   location.  For example in pilot view they are used to position the 
-    //   head inside the aircraft.
-    //   Note that in pilot view these are applied "before" the orientation 
-    //   rotations (see below) so that the orientation rotations have the 
-    //   effect of the pilot staying in his seat and "looking out" in 
-    //   different directions.
-    //   In chase view these are applied "after" the application of the 
-    //   orientation rotations listed below.  This has the effect of the 
-    //   eye moving around and "looking at" the object (model) from 
-    //   different angles.
-    virtual SGVec3d getOffset_m () const { return _offset_m; }
-    virtual double getXOffset_m () const { return _offset_m.x(); }
-    virtual double getYOffset_m () const { return _offset_m.y(); }
-    virtual double getZOffset_m () const { return _offset_m.z(); }
-    virtual double getTargetXOffset_m () const { return _target_offset_m.x(); }
-    virtual double getTargetYOffset_m () const { return _target_offset_m.y(); }
-    virtual double getTargetZOffset_m () const { return _target_offset_m.z(); }
-    virtual void setXOffset_m (double x_offset_m);
-    virtual void setYOffset_m (double y_offset_m);
-    virtual void setZOffset_m (double z_offset_m);
-    virtual void setTargetXOffset_m (double x_offset_m);
-    virtual void setTargetYOffset_m (double y_offset_m);
-    virtual void setTargetZOffset_m (double z_offset_m);
-    virtual void setPositionOffsets (double x_offset_m,
-                                    double y_offset_m,
-                                    double z_offset_m);
-
-
-
-
-    // Reference orientation rotations...
-    //   These are rotations that represent the plane attitude effect on
-    //   the view (in Pilot view).  IE The view frustrum rotates as the plane
-    //   turns, pitches, and rolls.
-    //   In model view (lookat/chaseview) these end up changing the angle that
-    //   the eye is looking at the ojbect (ie the model).
-    //   FIXME: the FGModel class should have its own version of these so that
-    //   it can generate it's own model rotations.
-    virtual double getRoll_deg () const { return _roll_deg; }
-    virtual double getPitch_deg () const {return _pitch_deg; }
-    virtual double getHeading_deg () const {return _heading_deg; }
-    virtual void setRoll_deg (double roll_deg);
-    virtual void setPitch_deg (double pitch_deg);
-    virtual void setHeading_deg (double heading_deg);
-    virtual void setOrientation (double roll_deg, double pitch_deg, double heading_deg);
-    virtual double getTargetRoll_deg () const { return _target_roll_deg; }
-    virtual double getTargetPitch_deg () const {return _target_pitch_deg; }
-    virtual double getTargetHeading_deg () const {return _target_heading_deg; }
-    virtual void setTargetRoll_deg (double roll_deg);
-    virtual void setTargetPitch_deg (double pitch_deg);
-    virtual void setTargetHeading_deg (double heading_deg);
-    virtual void setTargetOrientation (double roll_deg, double pitch_deg, double heading_deg);
-
-
-
-
-    // Orientation offsets rotations from reference orientation.
-    // Goal settings are for smooth transition from prior 
-    // offset when changing view direction.
-    //   These offsets are in ADDITION to the orientation rotations listed 
-    //   above.
-    //   In pilot view they are applied after the position offsets in order to
-    //   give the effect of the pilot looking around.
-    //   In lookat view they are applied before the position offsets so that
-    //   the effect is the eye moving around looking at the object (ie the model)
-    //   from different angles.
-    virtual double getRollOffset_deg () const { return _roll_offset_deg; }
-    virtual double getPitchOffset_deg () const { return _pitch_offset_deg; }
-    virtual double getHeadingOffset_deg () const { return _heading_offset_deg; }
-    virtual double getGoalRollOffset_deg () const { return _goal_roll_offset_deg; }
-    virtual double getGoalPitchOffset_deg () const { return _goal_pitch_offset_deg; }
-    virtual double getGoalHeadingOffset_deg () const {return _goal_heading_offset_deg; }
-    virtual void setRollOffset_deg (double roll_offset_deg);
-    virtual void setPitchOffset_deg (double pitch_offset_deg);
-    virtual void setHeadingOffset_deg (double heading_offset_deg);
-    virtual void setGoalRollOffset_deg (double goal_roll_offset_deg);
-    virtual void setGoalPitchOffset_deg (double goal_pitch_offset_deg);
-    virtual void setGoalHeadingOffset_deg (double goal_heading_offset_deg);
-    virtual void setOrientationOffsets (double roll_offset_deg,
-                                    double heading_offset_deg,
-                                    double pitch_offset_deg);
-
-
-
-    //////////////////////////////////////////////////////////////////////
-    // Part 3: output vectors and matrices in FlightGear coordinates.
-    //////////////////////////////////////////////////////////////////////
-
-    // Vectors and positions...
-
-    const SGVec3d& get_view_pos() { if ( _dirty ) { recalc(); } return _absolute_view_pos; }
-    const SGVec3d& getViewPosition() { if ( _dirty ) { recalc(); } return _absolute_view_pos; }
-    const SGQuatd& getViewOrientation() { if ( _dirty ) { recalc(); } return mViewOrientation; }
-    const SGQuatd& getViewOrientationOffset() { if ( _dirty ) { recalc(); } return mViewOffsetOr; }
-
-    //////////////////////////////////////////////////////////////////////
-    // Part 4: View and frustrum data setters and getters
-    //////////////////////////////////////////////////////////////////////
-
-    virtual void set_fov( double fov_deg ) {
-       _fov_deg = fov_deg;
-    }
-    virtual double get_fov() const { return _fov_deg; }
-    virtual double get_h_fov();    // Get horizontal fov, in degrees.
-    virtual double get_v_fov();    // Get vertical fov, in degrees.
-
-    virtual double get_aspect_ratio() const;
-
-    virtual void set_aspect_ratio_multiplier( double m ) {
-       _aspect_ratio_multiplier = m;
-    }
-    virtual double get_aspect_ratio_multiplier() const {
-        return _aspect_ratio_multiplier;
-    }
-
-    virtual double getNear_m () const { return _ground_level_nearplane_m; }
-    inline void setNear_m (double near_m) {
-        _ground_level_nearplane_m = near_m;
-    }
-
-    //////////////////////////////////////////////////////////////////////
-    // Part 5: misc setters and getters
-    //////////////////////////////////////////////////////////////////////
-
-    inline void set_dirty() { _dirty = true; }
-    inline void set_clean() { _dirty = false; }
-    
-private:
-
-    //////////////////////////////////////////////////////////////////
-    // private data                                                 //
-    //////////////////////////////////////////////////////////////////
-
-    // flag forcing a recalc of derived view parameters
-    bool _dirty;
-
-    SGQuatd mViewOrientation;
-    SGQuatd mViewOffsetOr;
-    SGVec3d _absolute_view_pos;
-
-    SGGeod _position;
-    SGGeod _target;
-
-    double _roll_deg;
-    double _pitch_deg;
-    double _heading_deg;
-    double _target_roll_deg;
-    double _target_pitch_deg;
-    double _target_heading_deg;
-
-    SGVec3d _dampTarget; ///< current target value we are damping towards
-    SGVec3d _dampOutput; ///< current output of damping filter
-    SGVec3d _dampFactor; ///< weighting of the damping filter
-    
-    // Position offsets from FDM origin.  The X axis is positive
-    // out the tail, Y is out the right wing, and Z is positive up.
-    // distance in meters
-    SGVec3d _offset_m;
-
-    // Target offsets from FDM origin (for "lookat" targets) The X
-    // axis is positive out the tail, Y is out the right wing, and Z
-    // is positive up.  distance in meters
-    SGVec3d _target_offset_m;
-
-
-    // orientation offsets from reference (_goal* are for smoothed transitions)
-    double _roll_offset_deg;
-    double _pitch_offset_deg;
-    double _heading_offset_deg;
-    double _goal_roll_offset_deg;
-    double _goal_pitch_offset_deg;
-    double _goal_heading_offset_deg;
-
-    // used to set nearplane when at ground level for this view
-    double _ground_level_nearplane_m;
-
-    fgViewType _type;
-    fgScalingType _scaling_type;
-
-    // internal view (e.g. cockpit) flag
-    bool _internal;
-
-    // view is looking from a model
-    bool _from_model;
-    int _from_model_index;  // number of model (for multi model)
-
-    // view is looking at a model
-    bool _at_model;
-    int _at_model_index;  // number of model (for multi model)
-
-    // the nominal field of view (angle, in degrees)
-    double _fov_deg;
-
-    // default = 1.0, this value is user configurable and is
-    // multiplied into the aspect_ratio to get the actual vertical fov
-    double _aspect_ratio_multiplier;
-
-    // camera group controled by this view
-    osg::ref_ptr<flightgear::CameraGroup> _cameraGroup;
-    //////////////////////////////////////////////////////////////////
-    // private functions                                            //
-    //////////////////////////////////////////////////////////////////
-
-    void recalc ();
-    void recalcLookFrom();
-    void recalcLookAt();
-
-    void setDampTarget(double h, double p, double r);
-    void getDampOutput(double& roll, double& pitch, double& heading);
-    
-    void updateDampOutput(double dt);
-    
-    // add to _heading_offset_deg
-    inline void incHeadingOffset_deg( double amt ) {
-       set_dirty();
-       _heading_offset_deg += amt;
-    }
-
-    // add to _pitch_offset_deg
-    inline void incPitchOffset_deg( double amt ) {
-       set_dirty();
-       _pitch_offset_deg += amt;
-    }
-
-    // add to _roll_offset_deg
-    inline void incRollOffset_deg( double amt ) {
-       set_dirty();
-       _roll_offset_deg += amt;
-    }
-
-};
-
-
-#endif // _VIEWER_HXX
diff --git a/src/Main/viewmgr.cxx b/src/Main/viewmgr.cxx
deleted file mode 100644 (file)
index 32e7390..0000000
+++ /dev/null
@@ -1,920 +0,0 @@
-// viewmgr.cxx -- class for managing all the views in the flightgear world.
-//
-// Written by Curtis Olson, started October 2000.
-//   partially rewritten by Jim Wilson March 2002
-//
-// Copyright (C) 2000  Curtis L. Olson  - http://www.flightgear.org/~curt
-//
-// This program is free software; you can redistribute it and/or
-// modify it under the terms of the GNU General Public License as
-// published by the Free Software Foundation; either version 2 of the
-// License, or (at your option) any later version.
-//
-// This program is distributed in the hope that it will be useful, but
-// WITHOUT ANY WARRANTY; without even the implied warranty of
-// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
-// General Public License for more details.
-//
-// You should have received a copy of the GNU General Public License
-// along with this program; if not, write to the Free Software
-// Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
-//
-// $Id$
-
-#ifdef HAVE_CONFIG_H
-#  include "config.h"
-#endif
-
-#include "viewmgr.hxx"
-
-#include <string.h>            // strcmp
-
-#include <simgear/compiler.h>
-#include <simgear/sound/soundmgr_openal.hxx>
-#include <Model/acmodel.hxx>
-#include <Main/viewer.hxx>
-#include <Main/fg_props.hxx>
-
-// Constructor
-FGViewMgr::FGViewMgr( void ) :
-  axis_long(0),
-  axis_lat(0),
-  inited(false),
-  view_number(fgGetNode("/sim/current-view/view-number", true)),
-  config_list(fgGetNode("/sim", true)->getChildren("view")),
-  abs_viewer_position(SGVec3d::zeros()),
-  current(0),
-  current_view_orientation(SGQuatd::zeros()),
-  current_view_or_offset(SGQuatd::zeros()),
-  smgr(globals->get_soundmgr())
-{
-}
-
-// Destructor
-FGViewMgr::~FGViewMgr( void ) {
-}
-
-void
-FGViewMgr::init ()
-{
-  if (inited) {
-    SG_LOG(SG_VIEW, SG_WARN, "duplicate init of view manager");
-    return;
-  }
-  
-  inited = true;
-  
-  double aspect_ratio_multiplier
-      = fgGetDouble("/sim/current-view/aspect-ratio-multiplier");
-
-  for (unsigned int i = 0; i < config_list.size(); i++) {
-    SGPropertyNode *n = config_list[i];
-
-    // find out if this is an internal view (e.g. in cockpit, low near plane)
-    bool internal = n->getBoolValue("internal", false);
-
-    // FIXME:
-    // this is assumed to be an aircraft model...we will need to read
-    // model-from-type as well.
-
-    // find out if this is a model we are looking from...
-    bool from_model = n->getBoolValue("config/from-model");
-    int from_model_index = n->getIntValue("config/from-model-idx");
-
-    double x_offset_m = n->getDoubleValue("config/x-offset-m");
-    double y_offset_m = n->getDoubleValue("config/y-offset-m");
-    double z_offset_m = n->getDoubleValue("config/z-offset-m");
-
-    double heading_offset_deg = n->getDoubleValue("config/heading-offset-deg");
-    n->setDoubleValue("config/heading-offset-deg", heading_offset_deg);
-    double pitch_offset_deg = n->getDoubleValue("config/pitch-offset-deg");
-    n->setDoubleValue("config/pitch-offset-deg", pitch_offset_deg);
-    double roll_offset_deg = n->getDoubleValue("config/roll-offset-deg");
-    n->setDoubleValue("config/roll-offset-deg", roll_offset_deg);
-
-    double fov_deg = n->getDoubleValue("config/default-field-of-view-deg");
-    double near_m = n->getDoubleValue("config/ground-level-nearplane-m");
-
-    // supporting two types "lookat" = 1 and "lookfrom" = 0
-    const char *type = n->getStringValue("type");
-    if (!strcmp(type, "lookat")) {
-
-      bool at_model = n->getBoolValue("config/at-model");
-      int at_model_index = n->getIntValue("config/at-model-idx");
-
-      double damp_roll = n->getDoubleValue("config/at-model-roll-damping");
-      double damp_pitch = n->getDoubleValue("config/at-model-pitch-damping");
-      double damp_heading = n->getDoubleValue("config/at-model-heading-damping");
-
-      double target_x_offset_m = n->getDoubleValue("config/target-x-offset-m");
-      double target_y_offset_m = n->getDoubleValue("config/target-y-offset-m");
-      double target_z_offset_m = n->getDoubleValue("config/target-z-offset-m");
-
-      add_view(new FGViewer ( FG_LOOKAT, from_model, from_model_index,
-                              at_model, at_model_index,
-                              damp_roll, damp_pitch, damp_heading,
-                              x_offset_m, y_offset_m,z_offset_m,
-                              heading_offset_deg, pitch_offset_deg,
-                              roll_offset_deg, fov_deg, aspect_ratio_multiplier,
-                              target_x_offset_m, target_y_offset_m,
-                              target_z_offset_m, near_m, internal ));
-    } else {
-      add_view(new FGViewer ( FG_LOOKFROM, from_model, from_model_index,
-                              false, 0, 0.0, 0.0, 0.0,
-                              x_offset_m, y_offset_m, z_offset_m,
-                              heading_offset_deg, pitch_offset_deg,
-                              roll_offset_deg, fov_deg, aspect_ratio_multiplier,
-                              0, 0, 0, near_m, internal ));
-    }
-  }
-
-  copyToCurrent();
-  do_bind();
-}
-
-void
-FGViewMgr::reinit ()
-{
-  // reset offsets and fov to configuration defaults
-  for (unsigned int i = 0; i < config_list.size(); i++) {
-    SGPropertyNode *n = config_list[i];
-    setView(i);
-
-    fgSetDouble("/sim/current-view/x-offset-m",
-        n->getDoubleValue("config/x-offset-m"));
-    fgSetDouble("/sim/current-view/y-offset-m",
-        n->getDoubleValue("config/y-offset-m"));
-    fgSetDouble("/sim/current-view/z-offset-m",
-        n->getDoubleValue("config/z-offset-m"));
-    fgSetDouble("/sim/current-view/pitch-offset-deg",
-        n->getDoubleValue("config/pitch-offset-deg"));
-    fgSetDouble("/sim/current-view/heading-offset-deg",
-        n->getDoubleValue("config/heading-offset-deg"));
-    fgSetDouble("/sim/current-view/roll-offset-deg",
-        n->getDoubleValue("config/roll-offset-deg"));
-
-    double fov_deg = n->getDoubleValue("config/default-field-of-view-deg");
-    if (fov_deg < 10.0)
-      fov_deg = 55.0;
-    fgSetDouble("/sim/current-view/field-of-view", fov_deg);
-
-    // target offsets for lookat mode only...
-    fgSetDouble("/sim/current-view/target-x-offset-m",
-        n->getDoubleValue("config/target-x-offset-m"));
-    fgSetDouble("/sim/current-view/target-y-offset-m",
-        n->getDoubleValue("config/target-y-offset-m"));
-    fgSetDouble("/sim/current-view/target-z-offset-m",
-        n->getDoubleValue("config/target-z-offset-m"));
-  }
-  setView(0);
-}
-
-typedef double (FGViewMgr::*double_getter)() const;
-
-void
-FGViewMgr::bind()
-{
-  // view-manager code was designed to init before bind, so
-  // this is a no-op; init() calls the real bind() impl below
-}
-
-void
-FGViewMgr::do_bind()
-{
-  // these are bound to the current view properties
-  _tiedProperties.setRoot(fgGetNode("/sim/current-view", true));
-  _tiedProperties.Tie("heading-offset-deg", this,
-                      &FGViewMgr::getViewHeadingOffset_deg,
-                      &FGViewMgr::setViewHeadingOffset_deg);
-  fgSetArchivable("/sim/current-view/heading-offset-deg");
-  _tiedProperties.Tie("goal-heading-offset-deg", this,
-                      &FGViewMgr::getViewGoalHeadingOffset_deg,
-                      &FGViewMgr::setViewGoalHeadingOffset_deg);
-  fgSetArchivable("/sim/current-view/goal-heading-offset-deg");
-  _tiedProperties.Tie("pitch-offset-deg", this,
-                      &FGViewMgr::getViewPitchOffset_deg,
-                      &FGViewMgr::setViewPitchOffset_deg);
-  fgSetArchivable("/sim/current-view/pitch-offset-deg");
-  _tiedProperties.Tie("goal-pitch-offset-deg", this,
-                      &FGViewMgr::getGoalViewPitchOffset_deg,
-                      &FGViewMgr::setGoalViewPitchOffset_deg);
-  fgSetArchivable("/sim/current-view/goal-pitch-offset-deg");
-  _tiedProperties.Tie("roll-offset-deg", this,
-                      &FGViewMgr::getViewRollOffset_deg,
-                      &FGViewMgr::setViewRollOffset_deg);
-  fgSetArchivable("/sim/current-view/roll-offset-deg");
-  _tiedProperties.Tie("goal-roll-offset-deg", this,
-                      &FGViewMgr::getGoalViewRollOffset_deg,
-                      &FGViewMgr::setGoalViewRollOffset_deg);
-  fgSetArchivable("/sim/current-view/goal-roll-offset-deg");
-
-  _tiedProperties.Tie("view-number", this,
-                      &FGViewMgr::getView, &FGViewMgr::setView);
-  fgSetArchivable("/sim/current-view/view-number", false);
-
-  _tiedProperties.Tie("axes/long", this,
-                      (double_getter)0, &FGViewMgr::setViewAxisLong);
-  fgSetArchivable("/sim/current-view/axes/long");
-
-  _tiedProperties.Tie("axes/lat", this,
-                      (double_getter)0, &FGViewMgr::setViewAxisLat);
-  fgSetArchivable("/sim/current-view/axes/lat");
-
-  _tiedProperties.Tie("field-of-view", this,
-                      &FGViewMgr::getFOV_deg, &FGViewMgr::setFOV_deg);
-  fgSetArchivable("/sim/current-view/field-of-view");
-
-  _tiedProperties.Tie("aspect-ratio-multiplier", this,
-                      &FGViewMgr::getARM_deg, &FGViewMgr::setARM_deg);
-  fgSetArchivable("/sim/current-view/field-of-view");
-
-  _tiedProperties.Tie("ground-level-nearplane-m", this,
-                      &FGViewMgr::getNear_m, &FGViewMgr::setNear_m);
-  fgSetArchivable("/sim/current-view/ground-level-nearplane-m");
-
-  SGPropertyNode *n = fgGetNode("/sim/current-view", true);
-  _tiedProperties.Tie(n->getNode("viewer-x-m", true),SGRawValuePointer<double>(&abs_viewer_position[0]));
-  _tiedProperties.Tie(n->getNode("viewer-y-m", true),SGRawValuePointer<double>(&abs_viewer_position[1]));
-  _tiedProperties.Tie(n->getNode("viewer-z-m", true),SGRawValuePointer<double>(&abs_viewer_position[2]));
-
-  _tiedProperties.Tie("debug/orientation-w", this,
-                      &FGViewMgr::getCurrentViewOrientation_w);
-  _tiedProperties.Tie("debug/orientation-x", this,
-                      &FGViewMgr::getCurrentViewOrientation_x);
-  _tiedProperties.Tie("debug/orientation-y", this,
-                      &FGViewMgr::getCurrentViewOrientation_y);
-  _tiedProperties.Tie("debug/orientation-z", this,
-                      &FGViewMgr::getCurrentViewOrientation_z);
-
-  _tiedProperties.Tie("debug/orientation_offset-w", this,
-                      &FGViewMgr::getCurrentViewOrOffset_w);
-  _tiedProperties.Tie("debug/orientation_offset-x", this,
-                      &FGViewMgr::getCurrentViewOrOffset_x);
-  _tiedProperties.Tie("debug/orientation_offset-y", this,
-                      &FGViewMgr::getCurrentViewOrOffset_y);
-  _tiedProperties.Tie("debug/orientation_offset-z", this,
-                      &FGViewMgr::getCurrentViewOrOffset_z);
-
-  _tiedProperties.Tie("debug/frame-w", this,
-                      &FGViewMgr::getCurrentViewFrame_w);
-  _tiedProperties.Tie("debug/frame-x", this,
-                      &FGViewMgr::getCurrentViewFrame_x);
-  _tiedProperties.Tie("debug/frame-y", this,
-                      &FGViewMgr::getCurrentViewFrame_y);
-  _tiedProperties.Tie("debug/frame-z", this,
-                      &FGViewMgr::getCurrentViewFrame_z);
-}
-
-void
-FGViewMgr::unbind ()
-{
-  _tiedProperties.Untie();
-}
-
-void
-FGViewMgr::update (double dt)
-{
-  FGViewer *loop_view = (FGViewer *)get_current_view();
-  if (loop_view == 0) return;
-
-  SGPropertyNode *n = config_list[current];
-  double lon_deg, lat_deg, alt_ft, roll_deg, pitch_deg, heading_deg;
-
-  // Set up view location and orientation
-
-  if (!n->getBoolValue("config/from-model")) {
-    lon_deg = fgGetDouble(n->getStringValue("config/eye-lon-deg-path"));
-    lat_deg = fgGetDouble(n->getStringValue("config/eye-lat-deg-path"));
-    alt_ft = fgGetDouble(n->getStringValue("config/eye-alt-ft-path"));
-    roll_deg = fgGetDouble(n->getStringValue("config/eye-roll-deg-path"));
-    pitch_deg = fgGetDouble(n->getStringValue("config/eye-pitch-deg-path"));
-    heading_deg = fgGetDouble(n->getStringValue("config/eye-heading-deg-path"));
-
-    loop_view->setPosition(lon_deg, lat_deg, alt_ft);
-    loop_view->setOrientation(roll_deg, pitch_deg, heading_deg);
-  } else {
-    // force recalc in viewer
-    loop_view->set_dirty();
-  }
-
-  // if lookat (type 1) then get target data...
-  if (loop_view->getType() == FG_LOOKAT) {
-    if (!n->getBoolValue("config/from-model")) {
-      lon_deg = fgGetDouble(n->getStringValue("config/target-lon-deg-path"));
-      lat_deg = fgGetDouble(n->getStringValue("config/target-lat-deg-path"));
-      alt_ft = fgGetDouble(n->getStringValue("config/target-alt-ft-path"));
-      roll_deg = fgGetDouble(n->getStringValue("config/target-roll-deg-path"));
-      pitch_deg = fgGetDouble(n->getStringValue("config/target-pitch-deg-path"));
-      heading_deg = fgGetDouble(n->getStringValue("config/target-heading-deg-path"));
-
-      loop_view->setTargetPosition(lon_deg, lat_deg, alt_ft);
-      loop_view->setTargetOrientation(roll_deg, pitch_deg, heading_deg);
-    } else {
-      loop_view->set_dirty();
-    }
-  }
-
-  setViewXOffset_m(fgGetDouble("/sim/current-view/x-offset-m"));
-  setViewYOffset_m(fgGetDouble("/sim/current-view/y-offset-m"));
-  setViewZOffset_m(fgGetDouble("/sim/current-view/z-offset-m"));
-
-  setViewTargetXOffset_m(fgGetDouble("/sim/current-view/target-x-offset-m"));
-  setViewTargetYOffset_m(fgGetDouble("/sim/current-view/target-y-offset-m"));
-  setViewTargetZOffset_m(fgGetDouble("/sim/current-view/target-z-offset-m"));
-
-  current_view_orientation = loop_view->getViewOrientation();
-  current_view_or_offset = loop_view->getViewOrientationOffset();
-
-  // Update the current view
-  do_axes();
-  loop_view->update(dt);
-  abs_viewer_position = loop_view->getViewPosition();
-
-  // update audio listener values
-  // set the viewer position in Cartesian coordinates in meters
-  smgr->set_position( abs_viewer_position, loop_view->getPosition() );
-  smgr->set_orientation( current_view_orientation );
-
-  // get the model velocity
-  SGVec3d velocity = SGVec3d::zeros();
-  if ( !stationary() ) {
-    velocity = globals->get_aircraft_model()->getVelocity();
-  }
-  smgr->set_velocity( velocity );
-}
-
-void
-FGViewMgr::copyToCurrent()
-{
-  if (!inited) {
-    return;
-  }
-  
-    SGPropertyNode *n = config_list[current];
-    fgSetString("/sim/current-view/name", n->getStringValue("name"));
-    fgSetString("/sim/current-view/type", n->getStringValue("type"));
-
-    // copy certain view config data for default values
-    fgSetDouble("/sim/current-view/config/heading-offset-deg",
-                n->getDoubleValue("config/default-heading-offset-deg"));
-    fgSetDouble("/sim/current-view/config/pitch-offset-deg",
-                n->getDoubleValue("config/pitch-offset-deg"));
-    fgSetDouble("/sim/current-view/config/roll-offset-deg",
-                n->getDoubleValue("config/roll-offset-deg"));
-    fgSetDouble("/sim/current-view/config/default-field-of-view-deg",
-                n->getDoubleValue("config/default-field-of-view-deg"));
-    fgSetBool("/sim/current-view/config/from-model",
-                n->getBoolValue("config/from-model"));
-
-    // copy view data
-    fgSetDouble("/sim/current-view/x-offset-m", getViewXOffset_m());
-    fgSetDouble("/sim/current-view/y-offset-m", getViewYOffset_m());
-    fgSetDouble("/sim/current-view/z-offset-m", getViewZOffset_m());
-
-    fgSetDouble("/sim/current-view/goal-heading-offset-deg",
-                get_current_view()->getGoalHeadingOffset_deg());
-    fgSetDouble("/sim/current-view/goal-pitch-offset-deg",
-                get_current_view()->getGoalPitchOffset_deg());
-    fgSetDouble("/sim/current-view/goal-roll-offset-deg",
-                get_current_view()->getRollOffset_deg());
-    fgSetDouble("/sim/current-view/heading-offset-deg",
-                get_current_view()->getHeadingOffset_deg());
-    fgSetDouble("/sim/current-view/pitch-offset-deg",
-                get_current_view()->getPitchOffset_deg());
-    fgSetDouble("/sim/current-view/roll-offset-deg",
-                get_current_view()->getRollOffset_deg());
-    fgSetDouble("/sim/current-view/target-x-offset-m",
-                get_current_view()->getTargetXOffset_m());
-    fgSetDouble("/sim/current-view/target-y-offset-m",
-                get_current_view()->getTargetYOffset_m());
-    fgSetDouble("/sim/current-view/target-z-offset-m",
-                get_current_view()->getTargetZOffset_m());
-    fgSetBool("/sim/current-view/internal",
-                get_current_view()->getInternal());
-}
-
-void FGViewMgr::clear()
-{
-  views.clear();
-}
-
-FGViewer*
-FGViewMgr::get_current_view()
-{
-       if ( current < (int)views.size() ) {
-           return views[current];
-       } else {
-           return NULL;
-       }
-}
-
-const FGViewer*
-FGViewMgr::get_current_view() const
-{
-       if ( current < (int)views.size() ) {
-           return views[current];
-       } else {
-           return NULL;
-       }
-}
-
-
-FGViewer*
-FGViewMgr::get_view( int i )
-{
-       if ( i < 0 ) { i = 0; }
-       if ( i >= (int)views.size() ) { i = views.size() - 1; }
-       return views[i];
-}
-
-const FGViewer*
-FGViewMgr::get_view( int i ) const
-{
-       if ( i < 0 ) { i = 0; }
-       if ( i >= (int)views.size() ) { i = views.size() - 1; }
-       return views[i];
-}
-
-FGViewer*
-FGViewMgr::next_view()
-{
-       setView((current+1 < (int)views.size()) ? (current + 1) : 0);
-       view_number->fireValueChanged();
-       return views[current];
-}
-
-FGViewer*
-FGViewMgr::prev_view()
-{
-       setView((0 < current) ? (current - 1) : (views.size() - 1));
-       view_number->fireValueChanged();
-       return views[current];
-}
-
-void
-FGViewMgr::add_view( FGViewer * v )
-{
-  views.push_back(v);
-  v->init();
-}
-    
-double
-FGViewMgr::getViewHeadingOffset_deg () const
-{
-  const FGViewer * view = get_current_view();
-  return (view == 0 ? 0 : view->getHeadingOffset_deg());
-}
-
-void
-FGViewMgr::setViewHeadingOffset_deg (double offset)
-{
-  FGViewer * view = get_current_view();
-  if (view != 0) {
-    view->setGoalHeadingOffset_deg(offset);
-    view->setHeadingOffset_deg(offset);
-  }
-}
-
-double
-FGViewMgr::getViewGoalHeadingOffset_deg () const
-{
-  const FGViewer * view = get_current_view();
-  return (view == 0 ? 0 : view->getGoalHeadingOffset_deg());
-}
-
-void
-FGViewMgr::setViewGoalHeadingOffset_deg (double offset)
-{
-  FGViewer * view = get_current_view();
-  if (view != 0)
-    view->setGoalHeadingOffset_deg(offset);
-}
-
-double
-FGViewMgr::getViewPitchOffset_deg () const
-{
-  const FGViewer * view = get_current_view();
-  return (view == 0 ? 0 : view->getPitchOffset_deg());
-}
-
-void
-FGViewMgr::setViewPitchOffset_deg (double tilt)
-{
-  FGViewer * view = get_current_view();
-  if (view != 0) {
-    view->setGoalPitchOffset_deg(tilt);
-    view->setPitchOffset_deg(tilt);
-  }
-}
-
-double
-FGViewMgr::getGoalViewPitchOffset_deg () const
-{
-  const FGViewer * view = get_current_view();
-  return (view == 0 ? 0 : view->getGoalPitchOffset_deg());
-}
-
-void
-FGViewMgr::setGoalViewPitchOffset_deg (double tilt)
-{
-  FGViewer * view = get_current_view();
-  if (view != 0)
-    view->setGoalPitchOffset_deg(tilt);
-}
-
-double
-FGViewMgr::getViewRollOffset_deg () const
-{
-  const FGViewer * view = get_current_view();
-  return (view == 0 ? 0 : view->getRollOffset_deg());
-}
-
-void
-FGViewMgr::setViewRollOffset_deg (double tilt)
-{
-  FGViewer * view = get_current_view();
-  if (view != 0) {
-    view->setGoalRollOffset_deg(tilt);
-    view->setRollOffset_deg(tilt);
-  }
-}
-
-double
-FGViewMgr::getGoalViewRollOffset_deg () const
-{
-  const FGViewer * view = get_current_view();
-  return (view == 0 ? 0 : view->getGoalRollOffset_deg());
-}
-
-void
-FGViewMgr::setGoalViewRollOffset_deg (double tilt)
-{
-  FGViewer * view = get_current_view();
-  if (view != 0)
-    view->setGoalRollOffset_deg(tilt);
-}
-
-double
-FGViewMgr::getViewXOffset_m () const
-{
-  const FGViewer * view = get_current_view();
-  if (view != 0) {
-    return ((FGViewer *)view)->getXOffset_m();
-  } else {
-    return 0;
-  }
-}
-
-void
-FGViewMgr::setViewXOffset_m (double x)
-{
-  FGViewer * view = get_current_view();
-  if (view != 0) {
-    view->setXOffset_m(x);
-  }
-}
-
-double
-FGViewMgr::getViewYOffset_m () const
-{
-  const FGViewer * view = get_current_view();
-  if (view != 0) {
-    return ((FGViewer *)view)->getYOffset_m();
-  } else {
-    return 0;
-  }
-}
-
-void
-FGViewMgr::setViewYOffset_m (double y)
-{
-  FGViewer * view = get_current_view();
-  if (view != 0) {
-    view->setYOffset_m(y);
-  }
-}
-
-double
-FGViewMgr::getViewZOffset_m () const
-{
-  const FGViewer * view = get_current_view();
-  if (view != 0) {
-    return ((FGViewer *)view)->getZOffset_m();
-  } else {
-    return 0;
-  }
-}
-
-void
-FGViewMgr::setViewZOffset_m (double z)
-{
-  FGViewer * view = get_current_view();
-  if (view != 0) {
-    view->setZOffset_m(z);
-  }
-}
-
-bool
-FGViewMgr::stationary () const
-{
-  const FGViewer * view = get_current_view();
-  if (view != 0) {
-    if (((FGViewer *)view)->getXOffset_m() == 0.0 &&
-        ((FGViewer *)view)->getYOffset_m() == 0.0 &&
-        ((FGViewer *)view)->getZOffset_m() == 0.0)
-      return true;
-  }
-
-  return false;
-}
-
-double
-FGViewMgr::getViewTargetXOffset_m () const
-{
-  const FGViewer * view = get_current_view();
-  if (view != 0) {
-    return ((FGViewer *)view)->getTargetXOffset_m();
-  } else {
-    return 0;
-  }
-}
-
-void
-FGViewMgr::setViewTargetXOffset_m (double x)
-{
-  FGViewer * view = get_current_view();
-  if (view != 0) {
-    view->setTargetXOffset_m(x);
-  }
-}
-
-double
-FGViewMgr::getViewTargetYOffset_m () const
-{
-  const FGViewer * view = get_current_view();
-  if (view != 0) {
-    return ((FGViewer *)view)->getTargetYOffset_m();
-  } else {
-    return 0;
-  }
-}
-
-void
-FGViewMgr::setViewTargetYOffset_m (double y)
-{
-  FGViewer * view = get_current_view();
-  if (view != 0) {
-    view->setTargetYOffset_m(y);
-  }
-}
-
-double
-FGViewMgr::getViewTargetZOffset_m () const
-{
-  const FGViewer * view = get_current_view();
-  if (view != 0) {
-    return ((FGViewer *)view)->getTargetZOffset_m();
-  } else {
-    return 0;
-  }
-}
-
-void
-FGViewMgr::setViewTargetZOffset_m (double z)
-{
-  FGViewer * view = get_current_view();
-  if (view != 0) {
-    view->setTargetZOffset_m(z);
-  }
-}
-
-int
-FGViewMgr::getView () const
-{
-  return ( current );
-}
-
-void
-FGViewMgr::setView (int newview)
-{
-  // negative numbers -> set view with node index -newview
-  if (newview < 0) {
-    for (int i = 0; i < (int)config_list.size(); i++) {
-      int index = -config_list[i]->getIndex();
-      if (index == newview)
-        newview = i;
-    }
-    if (newview < 0)
-      return;
-  }
-
-  // if newview number too low wrap to last view...
-  if (newview < 0)
-    newview = (int)views.size() - 1;
-
-  // if newview number to high wrap to zero...
-  if (newview >= (int)views.size())
-    newview = 0;
-
-  // set new view
-  current = newview;
-  // copy in view data
-  copyToCurrent();
-}
-
-
-double
-FGViewMgr::getFOV_deg () const
-{
-  const FGViewer * view = get_current_view();
-  return (view == 0 ? 0 : view->get_fov());
-}
-
-void
-FGViewMgr::setFOV_deg (double fov)
-{
-  FGViewer * view = get_current_view();
-  if (view != 0)
-    view->set_fov(fov);
-}
-
-double
-FGViewMgr::getARM_deg () const
-{
-  const FGViewer * view = get_current_view();
-  return (view == 0 ? 0 : view->get_aspect_ratio_multiplier());
-}
-
-void
-FGViewMgr::setARM_deg (double aspect_ratio_multiplier)
-{  
-  FGViewer * view = get_current_view();
-  if (view != 0)
-    view->set_aspect_ratio_multiplier(aspect_ratio_multiplier);
-}
-
-double
-FGViewMgr::getNear_m () const
-{
-  const FGViewer * view = get_current_view();
-  return (view == 0 ? 0.5f : view->getNear_m());
-}
-
-void
-FGViewMgr::setNear_m (double near_m)
-{
-  FGViewer * view = get_current_view();
-  if (view != 0)
-    view->setNear_m(near_m);
-}
-
-void
-FGViewMgr::setViewAxisLong (double axis)
-{
-  axis_long = axis;
-}
-
-void
-FGViewMgr::setViewAxisLat (double axis)
-{
-  axis_lat = axis;
-}
-
-// reference frame orientation.
-// This is the view orientation you get when you have no
-// view offset, i.e. the offset operator is the identity.
-// 
-// For example, in the familiar "cockpit lookfrom" view,
-// the reference frame is equal to the aircraft attitude,
-// i.e. it is the view looking towards 12:00 straight ahead.
-//
-// FIXME:  Somebody needs to figure out what is the reference
-// frame view for the other view modes.
-// 
-// Conceptually, this quat represents a rotation relative
-// to the ECEF reference orientation, as described at
-//    http://www.av8n.com/physics/coords.htm#sec-orientation
-//
-// See the NOTE concerning reference orientations, below.
-//
-// The components of this quat are expressed in 
-// the conventional aviation basis set,
-// i.e.  x=forward, y=starboard, z=bottom
-double FGViewMgr::getCurrentViewFrame_w() const{
-  return ((current_view_orientation*conj(fsb2sta())*conj(current_view_or_offset))).w();
-}
-double FGViewMgr::getCurrentViewFrame_x() const{
-  return ((current_view_orientation*conj(fsb2sta())*conj(current_view_or_offset))).x();
-}
-double FGViewMgr::getCurrentViewFrame_y() const{
-  return ((current_view_orientation*conj(fsb2sta())*conj(current_view_or_offset))).y();
-}
-double FGViewMgr::getCurrentViewFrame_z() const{
-  return ((current_view_orientation*conj(fsb2sta())*conj(current_view_or_offset))).z();
-}
-
-
-// view offset.
-// This rotation takes you from the aforementioned
-// reference frame view orientation to whatever
-// actual current view orientation is.
-//
-// The components of this quaternion are expressed in 
-// the conventional aviation basis set,
-// i.e.  x=forward, y=starboard, z=bottom
-double FGViewMgr::getCurrentViewOrOffset_w() const{
-   return current_view_or_offset.w();
-}
-double FGViewMgr::getCurrentViewOrOffset_x() const{
-   return current_view_or_offset.x();
-}
-double FGViewMgr::getCurrentViewOrOffset_y() const{
-   return current_view_or_offset.y();
-}
-double FGViewMgr::getCurrentViewOrOffset_z() const{
-   return current_view_or_offset.z();
-}
-
-
-// current view orientation.
-// This is a rotation relative to the earth-centered (ec)
-// reference frame.
-// 
-// NOTE: Here we remove a factor of fsb2sta so that 
-// the components of this quat are displayed using the 
-// conventional ECEF basis set.  This is *not* the way
-// the view orientation is stored in the views[] array,
-// but is easier for non-graphics hackers to understand.
-// If we did not remove this factor of fsb2sta here and
-// in getCurrentViewFrame, that would be equivalent to
-// the following peculiar reference orientation:
-// Suppose you are over the Gulf of Guinea, at (lat,lon) = (0,0).
-// Then the reference frame orientation can be achieved via:
-//    -- The aircraft X-axis (nose) headed south.
-//    -- The aircraft Y-axis (starboard wingtip) pointing up.
-//    -- The aircraft Z-axis (belly) pointing west.
-// To say the same thing in other words, and perhaps more to the
-// point:  If we use the OpenGL camera orientation conventions, 
-// i.e. Xprime=starboard, Yprime=top, Zprime=aft, then the
-// aforementioned peculiar reference orientation at (lat,lon)
-//  = (0,0) can be described as:
-//    -- aircraft Xprime axis (starboard) pointed up
-//    -- aircraft Yprime axis (top) pointed east
-//    -- aircraft Zprime axis (aft) pointed north
-// meaning the OpenGL axes are aligned with the ECEF axes.
-double FGViewMgr::getCurrentViewOrientation_w() const{
-  return (current_view_orientation * conj(fsb2sta())).w();
-}
-double FGViewMgr::getCurrentViewOrientation_x() const{
-  return (current_view_orientation * conj(fsb2sta())).x();
-}
-double FGViewMgr::getCurrentViewOrientation_y() const{
-  return (current_view_orientation * conj(fsb2sta())).y();
-}
-double FGViewMgr::getCurrentViewOrientation_z() const{
-  return (current_view_orientation * conj(fsb2sta())).z();
-}
-
-void
-FGViewMgr::do_axes ()
-{
-                               // Take no action when hat is centered
-  if ( ( axis_long <  0.01 ) &&
-       ( axis_long > -0.01 ) &&
-       ( axis_lat  <  0.01 ) &&
-       ( axis_lat  > -0.01 )
-     )
-    return;
-
-  double viewDir = 999;
-
-  /* Do all the quick and easy cases */
-  if (axis_long < 0) {         // Longitudinal axis forward
-    if (axis_lat == axis_long)
-      viewDir = fgGetDouble("/sim/view/config/front-left-direction-deg");
-    else if (axis_lat == - axis_long)
-      viewDir = fgGetDouble("/sim/view/config/front-right-direction-deg");
-    else if (axis_lat == 0)
-      viewDir = fgGetDouble("/sim/view/config/front-direction-deg");
-  } else if (axis_long > 0) {  // Longitudinal axis backward
-    if (axis_lat == - axis_long)
-      viewDir = fgGetDouble("/sim/view/config/back-left-direction-deg");
-    else if (axis_lat == axis_long)
-      viewDir = fgGetDouble("/sim/view/config/back-right-direction-deg");
-    else if (axis_lat == 0)
-      viewDir = fgGetDouble("/sim/view/config/back-direction-deg");
-  } else if (axis_long == 0) { // Longitudinal axis neutral
-    if (axis_lat < 0)
-      viewDir = fgGetDouble("/sim/view/config/left-direction-deg");
-    else if (axis_lat > 0)
-      viewDir = fgGetDouble("/sim/view/config/right-direction-deg");
-    else return; /* And assertion failure maybe? */
-  }
-
-                               // Do all the difficult cases
-  if ( viewDir > 900 )
-    viewDir = SGD_RADIANS_TO_DEGREES * atan2 ( -axis_lat, -axis_long );
-  if ( viewDir < -1 ) viewDir += 360;
-
-  get_current_view()->setGoalHeadingOffset_deg(viewDir);
-}
diff --git a/src/Main/viewmgr.hxx b/src/Main/viewmgr.hxx
deleted file mode 100644 (file)
index d094a3d..0000000
+++ /dev/null
@@ -1,165 +0,0 @@
-// viewmgr.hxx -- class for managing all the views in the flightgear world.
-//
-// Written by Curtis Olson, started October 2000.
-//
-// Copyright (C) 2000  Curtis L. Olson  - http://www.flightgear.org/~curt
-//
-// This program is free software; you can redistribute it and/or
-// modify it under the terms of the GNU General Public License as
-// published by the Free Software Foundation; either version 2 of the
-// License, or (at your option) any later version.
-//
-// This program is distributed in the hope that it will be useful, but
-// WITHOUT ANY WARRANTY; without even the implied warranty of
-// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
-// General Public License for more details.
-//
-// You should have received a copy of the GNU General Public License
-// along with this program; if not, write to the Free Software
-// Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
-//
-// $Id$
-
-
-#ifndef _VIEWMGR_HXX
-#define _VIEWMGR_HXX
-
-#include <vector>
-
-#include <simgear/compiler.h>
-#include <simgear/structure/subsystem_mgr.hxx>
-#include <simgear/props/props.hxx>
-#include <simgear/props/tiedpropertylist.hxx>
-#include <simgear/math/SGMath.hxx>
-
-// forward decls
-class FGViewer;
-class SGSoundMgr;
-typedef SGSharedPtr<FGViewer> FGViewerPtr;
-
-// Define a structure containing view information
-class FGViewMgr : public SGSubsystem
-{
-
-public:
-
-    // Constructor
-    FGViewMgr( void );
-
-    // Destructor
-    ~FGViewMgr( void );
-
-    virtual void init ();
-    virtual void bind ();
-    virtual void unbind ();
-    virtual void update (double dt);
-    virtual void reinit ();
-
-    // getters
-    inline int size() const { return views.size(); }
-    inline int get_current() const { return current; }
-    
-    FGViewer *get_current_view();
-    const FGViewer *get_current_view() const;
-    
-    FGViewer *get_view( int i ); 
-    const FGViewer *get_view( int i ) const;
-      
-    FGViewer *next_view();
-    FGViewer *prev_view();
-      
-    // setters
-    void clear();
-
-    void add_view( FGViewer * v );
-    
-private:
-    void do_bind();
-
-    simgear::TiedPropertyList _tiedProperties;
-
-    double axis_long;
-    double axis_lat;
-
-    void do_axes ();
-
-    //  callbacks in manager to access viewer methods
-    double getViewHeadingOffset_deg () const;
-    void setViewHeadingOffset_deg (double offset);
-    double getViewGoalHeadingOffset_deg () const;
-    void setViewGoalHeadingOffset_deg (double offset);
-    double getViewPitchOffset_deg () const;
-    void setViewPitchOffset_deg (double tilt);
-    double getGoalViewPitchOffset_deg () const;
-    void setGoalViewRollOffset_deg (double tilt);
-    double getViewRollOffset_deg () const;
-    void setViewRollOffset_deg (double tilt);
-    double getGoalViewRollOffset_deg () const;
-    void setGoalViewPitchOffset_deg (double tilt);
-    double getViewXOffset_m () const;
-    void setViewXOffset_m (double x);
-    double getViewYOffset_m () const;
-    void setViewYOffset_m (double y);
-    double getViewZOffset_m () const;
-    void setViewZOffset_m (double z);
-    double getViewTargetXOffset_m () const;
-    void setViewTargetXOffset_m (double x);
-    double getViewTargetYOffset_m () const;
-    void setViewTargetYOffset_m (double y);
-    double getViewTargetZOffset_m () const;
-    void setViewTargetZOffset_m (double z);
-    double getFOV_deg () const;
-    void setFOV_deg (double fov);
-    double getARM_deg () const; // Aspect Ratio Multiplier
-    void setARM_deg (double fov);
-    double getNear_m () const;
-    void setNear_m (double near_m);
-    void setViewAxisLong (double axis);
-    void setViewAxisLat (double axis);
-    int getView () const;
-    void setView (int newview);
-
-// quaternion accessors, for debugging:
-    double getCurrentViewOrientation_w() const;
-    double getCurrentViewOrientation_x() const;
-    double getCurrentViewOrientation_y() const;
-    double getCurrentViewOrientation_z() const;
-    double getCurrentViewOrOffset_w() const;
-    double getCurrentViewOrOffset_x() const;
-    double getCurrentViewOrOffset_y() const;
-    double getCurrentViewOrOffset_z() const;
-    double getCurrentViewFrame_w() const;
-    double getCurrentViewFrame_x() const;
-    double getCurrentViewFrame_y() const;
-    double getCurrentViewFrame_z() const;
-
-    bool stationary () const;
-
-    // copies current offset settings to current-view path...
-    void copyToCurrent ();
-    
-    bool inited;
-    SGPropertyNode_ptr view_number;
-    std::vector<SGPropertyNode_ptr> config_list;
-    typedef std::vector<FGViewerPtr> viewer_list;
-    viewer_list views;
-    SGVec3d abs_viewer_position;
-
-    int current;
-    SGQuatd current_view_orientation, current_view_or_offset;
-
-    SGSoundMgr *smgr;
-
-};
-
-// This takes the conventional aviation XYZ body system 
-// i.e.  x=forward, y=starboard, z=bottom
-// which is widely used in FGFS
-// and rotates it into the OpenGL camera system 
-// i.e. Xprime=starboard, Yprime=top, Zprime=aft.
-inline const SGQuatd fsb2sta()
-{
-    return SGQuatd(-0.5, -0.5, 0.5, 0.5);
-}
-
-#endif // _VIEWMGR_HXX
index d4e8c0f48ac1a9dc444c121f760aa5ade5724cab..51f4082f316471c095257cf776d04e895914f750 100644 (file)
@@ -18,9 +18,9 @@
 
 #include <Main/globals.hxx>
 #include <Main/fg_props.hxx>
-#include <Main/renderer.hxx>
-#include <Main/viewmgr.hxx>
-#include <Main/viewer.hxx>
+#include <Viewer/renderer.hxx>
+#include <Viewer/viewmgr.hxx>
+#include <Viewer/viewer.hxx>
 #include <Scenery/scenery.hxx>
 #include <Sound/fg_fx.hxx>
 
index 55e5e79c02c44619fddf7c50dfcebda0f9abfe50..b1ba76dc1f7a4589242369caa5ca53e639ad1540 100644 (file)
@@ -42,7 +42,7 @@
 
 #include <Main/fg_props.hxx>
 #include <Main/globals.hxx>
-#include <Main/renderer.hxx>
+#include <Viewer/renderer.hxx>
 
 #include "jpg-httpd.hxx"
 
index 7240d5cb236bcd360f1371ce348e909479bc0df2..1fd2971eb3fafb44cf04eddfeec45292212c5b21 100644 (file)
@@ -39,7 +39,7 @@
 #include <errno.h>
 
 #include <Main/globals.hxx>
-#include <Main/viewmgr.hxx>
+#include <Viewer/viewmgr.hxx>
 
 #include <simgear/io/sg_netChat.hxx>
 
index 908f4da22870e9bc226cd02f1364fa950637198d..eeec77bb48fd53ec6966004e02b82caa65627e21 100644 (file)
@@ -45,7 +45,7 @@
 #include <simgear/scene/bvh/BVHNode.hxx>
 #include <simgear/scene/bvh/BVHLineSegmentVisitor.hxx>
 
-#include <Main/renderer.hxx>
+#include <Viewer/renderer.hxx>
 #include <Main/fg_props.hxx>
 
 #include "tilemgr.hxx"
index 3471316556189dcf2caba00900698977dc2d9258..5a9679221073de0f22c186e25b43cbe03ffab776 100644 (file)
@@ -40,8 +40,8 @@
 
 #include <Main/globals.hxx>
 #include <Main/fg_props.hxx>
-#include <Main/renderer.hxx>
-#include <Main/viewer.hxx>
+#include <Viewer/renderer.hxx>
+#include <Viewer/viewer.hxx>
 #include <Scripting/NasalSys.hxx>
 
 #include "scenery.hxx"
index bcd6ebf69e0e85e83598ac522c7636a4e7f8b9e9..0c3face551d5d821674c82880a50cf4f156273ee 100644 (file)
@@ -42,8 +42,8 @@
 #include <Main/main.hxx>
 #include <Main/globals.hxx>
 #include <Main/fg_props.hxx>
-#include <Main/renderer.hxx>
-#include <Main/viewer.hxx>
+#include <Viewer/renderer.hxx>
+#include <Viewer/viewer.hxx>
 
 #include "light.hxx"
 #include "sunsolver.hxx"
diff --git a/src/Viewer/CMakeLists.txt b/src/Viewer/CMakeLists.txt
new file mode 100644 (file)
index 0000000..7b7bd0a
--- /dev/null
@@ -0,0 +1,28 @@
+include(FlightGearComponent)
+
+set(SOURCES
+       CameraGroup.cxx
+       FGEventHandler.cxx
+       WindowBuilder.cxx
+       WindowSystemAdapter.cxx
+       fg_os_osgviewer.cxx
+       fgviewer.cxx
+       renderer.cxx
+       splash.cxx
+       viewer.cxx
+       viewmgr.cxx
+       )
+
+set(HEADERS
+       CameraGroup.hxx
+       FGEventHandler.hxx
+       WindowBuilder.hxx
+       WindowSystemAdapter.hxx
+       fgviewer.hxx
+       renderer.hxx
+       splash.hxx
+       viewer.hxx
+       viewmgr.hxx
+       )
+
+flightgear_component(Viewer "${SOURCES}" "${HEADERS}")
diff --git a/src/Viewer/CameraGroup.cxx b/src/Viewer/CameraGroup.cxx
new file mode 100644 (file)
index 0000000..4adbbfa
--- /dev/null
@@ -0,0 +1,1241 @@
+// Copyright (C) 2008  Tim Moore
+// Copyright (C) 2011  Mathias Froehlich
+//
+// This program is free software; you can redistribute it and/or
+// modify it under the terms of the GNU General Public License as
+// published by the Free Software Foundation; either version 2 of the
+// License, or (at your option) any later version.
+//
+// This program is distributed in the hope that it will be useful, but
+// WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+// General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License
+// along with this program; if not, write to the Free Software
+// Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
+
+#ifdef HAVE_CONFIG_H
+#  include <config.h>
+#endif
+
+#include "CameraGroup.hxx"
+
+#include <Main/fg_props.hxx>
+#include <Main/globals.hxx>
+#include "renderer.hxx"
+#include "FGEventHandler.hxx"
+#include "WindowBuilder.hxx"
+#include "WindowSystemAdapter.hxx"
+#include <simgear/props/props.hxx>
+#include <simgear/structure/OSGUtils.hxx>
+#include <simgear/structure/OSGVersion.hxx>
+#include <simgear/scene/material/EffectCullVisitor.hxx>
+#include <simgear/scene/util/RenderConstants.hxx>
+#include <simgear/scene/tgdb/userdata.hxx>
+
+#include <algorithm>
+#include <cstring>
+#include <string>
+
+#include <osg/Camera>
+#include <osg/Geometry>
+#include <osg/GraphicsContext>
+#include <osg/io_utils>
+#include <osg/Math>
+#include <osg/Matrix>
+#include <osg/Notify>
+#include <osg/Program>
+#include <osg/Quat>
+#include <osg/TexMat>
+#include <osg/Vec3d>
+#include <osg/Viewport>
+
+#include <osgUtil/IntersectionVisitor>
+
+#include <osgViewer/GraphicsWindow>
+#include <osgViewer/Renderer>
+
+static osg::Matrix
+invert(const osg::Matrix& matrix)
+{
+    return osg::Matrix::inverse(matrix);
+}
+
+/// Returns the zoom factor of the master camera.
+/// The reference fov is the historic 55 deg
+static double
+zoomFactor()
+{
+    double fov = fgGetDouble("/sim/current-view/field-of-view", 55);
+    if (fov < 1)
+        fov = 1;
+    return tan(55*0.5*SG_DEGREES_TO_RADIANS)/tan(fov*0.5*SG_DEGREES_TO_RADIANS);
+}
+
+static osg::Vec2d
+preMult(const osg::Vec2d& v, const osg::Matrix& m)
+{
+  osg::Vec3d tmp = m.preMult(osg::Vec3(v, 0));
+  return osg::Vec2d(tmp[0], tmp[1]);
+}
+
+static osg::Matrix
+relativeProjection(const osg::Matrix& P0, const osg::Matrix& R, const osg::Vec2d ref[2],
+                   const osg::Matrix& pP, const osg::Matrix& pR, const osg::Vec2d pRef[2])
+{
+  // Track the way from one projection space to the other:
+  // We want
+  //  P = T*S*P0
+  // where P0 is the projection template sensible for the given window size,
+  // T is a translation matrix and S a scale matrix.
+  // We need to determine T and S so that the reference points in the parents
+  // projection space match the two reference points in this cameras projection space.
+
+  // Starting from the parents camera projection space, we get into this cameras
+  // projection space by the transform matrix:
+  //  P*R*inv(pP*pR) = T*S*P0*R*inv(pP*pR)
+  // So, at first compute that matrix without T*S and determine S and T from that
+
+  // Ok, now osg uses the inverse matrix multiplication order, thus:
+  osg::Matrix PtoPwithoutTS = invert(pR*pP)*R*P0;
+  // Compute the parents reference points in the current projection space
+  // without the yet unknown T and S
+  osg::Vec2d pRefInThis[2] = {
+    preMult(pRef[0], PtoPwithoutTS),
+    preMult(pRef[1], PtoPwithoutTS)
+  };
+
+  // To get the same zoom, rescale to match the parents size
+  double s = (ref[0] - ref[1]).length()/(pRefInThis[0] - pRefInThis[1]).length();
+  osg::Matrix S = osg::Matrix::scale(s, s, 1);
+
+  // For the translation offset, incorporate the now known scale
+  // and recompute the position ot the first reference point in the
+  // currents projection space without the yet unknown T.
+  pRefInThis[0] = preMult(pRef[0], PtoPwithoutTS*S);
+  // The translation is then the difference of the reference points
+  osg::Matrix T = osg::Matrix::translate(osg::Vec3d(ref[0] - pRefInThis[0], 0));
+
+  // Compose and return the desired final projection matrix
+  return P0*S*T;
+}
+
+namespace flightgear
+{
+using namespace osg;
+
+using std::strcmp;
+using std::string;
+
+ref_ptr<CameraGroup> CameraGroup::_defaultGroup;
+
+CameraGroup::CameraGroup(osgViewer::Viewer* viewer) :
+    _viewer(viewer)
+{
+}
+
+}
+
+namespace
+{
+using namespace osg;
+
+// Given a projection matrix, return a new one with the same frustum
+// sides and new near / far values.
+
+void makeNewProjMat(Matrixd& oldProj, double znear,
+                                       double zfar, Matrixd& projection)
+{
+    projection = oldProj;
+    // Slightly inflate the near & far planes to avoid objects at the
+    // extremes being clipped out.
+    znear *= 0.999;
+    zfar *= 1.001;
+
+    // Clamp the projection matrix z values to the range (near, far)
+    double epsilon = 1.0e-6;
+    if (fabs(projection(0,3)) < epsilon &&
+        fabs(projection(1,3)) < epsilon &&
+        fabs(projection(2,3)) < epsilon) {
+        // Projection is Orthographic
+        epsilon = -1.0/(zfar - znear); // Used as a temp variable
+        projection(2,2) = 2.0*epsilon;
+        projection(3,2) = (zfar + znear)*epsilon;
+    } else {
+        // Projection is Perspective
+        double trans_near = (-znear*projection(2,2) + projection(3,2)) /
+            (-znear*projection(2,3) + projection(3,3));
+        double trans_far = (-zfar*projection(2,2) + projection(3,2)) /
+            (-zfar*projection(2,3) + projection(3,3));
+        double ratio = fabs(2.0/(trans_near - trans_far));
+        double center = -0.5*(trans_near + trans_far);
+
+        projection.postMult(osg::Matrixd(1.0, 0.0, 0.0, 0.0,
+                                         0.0, 1.0, 0.0, 0.0,
+                                         0.0, 0.0, ratio, 0.0,
+                                         0.0, 0.0, center*ratio, 1.0));
+    }
+}
+}
+
+namespace flightgear
+{
+void CameraInfo::updateCameras()
+{
+    bufferSize->set( osg::Vec2f( width, height ) );
+
+    for (CameraMap::iterator ii = cameras.begin(); ii != cameras.end(); ++ii ) {
+        float f = ii->second.scaleFactor;
+        if ( f == 0.0f ) continue;
+        ii->second.camera->getViewport()->setViewport(x*f, y*f, width*f, height*f);
+    }
+
+    for (RenderBufferMap::iterator ii = buffers.begin(); ii != buffers.end(); ++ii ) {
+        float f = ii->second.scaleFactor;
+        if ( f == 0.0f ) continue;
+        osg::Texture2D* texture = ii->second.texture.get();
+        if ( texture->getTextureHeight() != height*f || texture->getTextureWidth() != width*f ) {
+            texture->setTextureSize( width*f, height*f );
+            texture->dirtyTextureObject();
+        }
+    }
+}
+
+void CameraInfo::resized(double w, double h)
+{
+    bufferSize->set( osg::Vec2f( w, h ) );
+
+    for (RenderBufferMap::iterator ii = buffers.begin(); ii != buffers.end(); ++ii) {
+        float s = ii->second.scaleFactor;
+        if ( s == 0.0f ) continue;
+        ii->second.texture->setTextureSize( w * s, h * s );
+        ii->second.texture->dirtyTextureObject();
+    }
+
+    for (CameraMap::iterator ii = cameras.begin(); ii != cameras.end(); ++ii) {
+        RenderStageInfo& rsi = ii->second;
+        if (!rsi.resizable ||
+                rsi.camera->getRenderTargetImplementation() != osg::Camera::FRAME_BUFFER_OBJECT ||
+                rsi.scaleFactor == 0.0f )
+            continue;
+
+        Viewport* vp = rsi.camera->getViewport();
+        vp->width() = w * rsi.scaleFactor;
+        vp->height() = h * rsi.scaleFactor;
+
+        osgViewer::Renderer* renderer
+            = static_cast<osgViewer::Renderer*>(rsi.camera->getRenderer());
+        for (int i = 0; i < 2; ++i) {
+            osgUtil::SceneView* sceneView = renderer->getSceneView(i);
+            sceneView->getRenderStage()->setFrameBufferObject(0);
+            sceneView->getRenderStage()->setCameraRequiresSetUp(true);
+            if (sceneView->getRenderStageLeft()) {
+                sceneView->getRenderStageLeft()->setFrameBufferObject(0);
+                sceneView->getRenderStageLeft()->setCameraRequiresSetUp(true);
+            }
+            if (sceneView->getRenderStageRight()) {
+                sceneView->getRenderStageRight()->setFrameBufferObject(0);
+                sceneView->getRenderStageRight()->setCameraRequiresSetUp(true);
+            }
+        }
+    }
+}
+
+osg::Camera* CameraInfo::getCamera(CameraKind k) const
+{
+    CameraMap::const_iterator ii = cameras.find( k );
+    if (ii == cameras.end())
+        return 0;
+    return ii->second.camera.get();
+}
+
+osg::Texture2D* CameraInfo::getBuffer(RenderBufferInfo::Kind k) const
+{
+    RenderBufferMap::const_iterator ii = buffers.find(k);
+    if (ii == buffers.end())
+        return 0;
+    return ii->second.texture.get();
+}
+
+int CameraInfo::getMainSlaveIndex() const
+{
+    return cameras.find( MAIN_CAMERA )->second.slaveIndex;
+}
+
+void CameraInfo::setMatrices(osg::Camera* c)
+{
+    view->set( c->getViewMatrix() );
+    viewInverse->set( osg::Matrix::inverse( c->getViewMatrix() ) );
+    projInverse->set( osg::Matrix::inverse( c->getProjectionMatrix() ) );
+}
+
+void CameraGroup::update(const osg::Vec3d& position,
+                         const osg::Quat& orientation)
+{
+    const Matrix masterView(osg::Matrix::translate(-position)
+                            * osg::Matrix::rotate(orientation.inverse()));
+    _viewer->getCamera()->setViewMatrix(masterView);
+    const Matrix& masterProj = _viewer->getCamera()->getProjectionMatrix();
+    double masterZoomFactor = zoomFactor();
+    for (CameraList::iterator i = _cameras.begin(); i != _cameras.end(); ++i) {
+        const CameraInfo* info = i->get();
+
+        Camera* camera = info->getCamera(MAIN_CAMERA);
+        if ( camera ) {
+            const View::Slave& slave = _viewer->getSlave(info->getMainSlaveIndex());
+#if SG_OSG_VERSION_LESS_THAN(3,0,0)
+            // refreshes camera viewports (for now)
+            info->updateCameras();
+#endif
+            Matrix viewMatrix;
+            if (info->flags & GUI) {
+                viewMatrix = osg::Matrix(); // identifty transform on the GUI camera
+            } else if ((info->flags & VIEW_ABSOLUTE) != 0)
+                viewMatrix = slave._viewOffset;
+            else
+                viewMatrix = masterView * slave._viewOffset;
+            camera->setViewMatrix(viewMatrix);
+            Matrix projectionMatrix;
+            if (info->flags & GUI) {
+                projectionMatrix = osg::Matrix::ortho2D(0, info->width, 0, info->height);
+            } else if ((info->flags & PROJECTION_ABSOLUTE) != 0) {
+                if (info->flags & ENABLE_MASTER_ZOOM) {
+                    if (info->relativeCameraParent < _cameras.size()) {
+                        // template projection matrix and view matrix of the current camera
+                        osg::Matrix P0 = slave._projectionOffset;
+                        osg::Matrix R = viewMatrix;
+
+                        // The already known projection and view matrix of the parent camera
+                        const CameraInfo* parentInfo = _cameras[info->relativeCameraParent].get();
+                        RenderStageInfo prsi = parentInfo->cameras.find(MAIN_CAMERA)->second;
+                        osg::Matrix pP = prsi.camera->getProjectionMatrix();
+                        osg::Matrix pR = prsi.camera->getViewMatrix();
+                    
+                        // And the projection matrix derived from P0 so that the reference points match
+                        projectionMatrix = relativeProjection(P0, R, info->thisReference,
+                                                              pP, pR, info->parentReference);
+                    
+                    } else {
+                        // We want to zoom, so take the original matrix and apply the zoom to it.
+                        projectionMatrix = slave._projectionOffset;
+                        projectionMatrix.postMultScale(osg::Vec3d(masterZoomFactor, masterZoomFactor, 1));
+                    }
+                } else {
+                    projectionMatrix = slave._projectionOffset;
+                }
+            } else {
+                projectionMatrix = masterProj * slave._projectionOffset;
+            }
+
+            CameraMap::const_iterator ii = info->cameras.find(FAR_CAMERA);
+            if (ii == info->cameras.end() || !ii->second.camera.valid()) {
+                camera->setProjectionMatrix(projectionMatrix);
+            } else {
+                Camera* farCamera = ii->second.camera;
+                farCamera->setViewMatrix(viewMatrix);
+                double left, right, bottom, top, parentNear, parentFar;
+                projectionMatrix.getFrustum(left, right, bottom, top,
+                                            parentNear, parentFar);
+                if ((info->flags & FIXED_NEAR_FAR) == 0) {
+                    parentNear = _zNear;
+                    parentFar = _zFar;
+                }
+                if (parentFar < _nearField || _nearField == 0.0f) {
+                    camera->setProjectionMatrix(projectionMatrix);
+                    camera->setCullMask(camera->getCullMask()
+                                        | simgear::BACKGROUND_BIT);
+                    camera->setClearMask(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT | GL_STENCIL_BUFFER_BIT);
+                    farCamera->setNodeMask(0);
+                } else {
+                    Matrix nearProj, farProj;
+                    makeNewProjMat(projectionMatrix, parentNear, _nearField,
+                                   nearProj);
+                    makeNewProjMat(projectionMatrix, _nearField, parentFar,
+                                   farProj);
+                    camera->setProjectionMatrix(nearProj);
+                    camera->setCullMask(camera->getCullMask()
+                                        & ~simgear::BACKGROUND_BIT);
+                    camera->setClearMask(GL_DEPTH_BUFFER_BIT);
+                    farCamera->setProjectionMatrix(farProj);
+                    farCamera->setNodeMask(camera->getNodeMask());
+                }
+            }
+        } else {
+            bool viewDone = false;
+            Matrix viewMatrix;
+            bool projectionDone = false;
+            Matrix projectionMatrix;
+            for ( CameraMap::const_iterator ii = info->cameras.begin(); ii != info->cameras.end(); ++ii ) {
+                if ( ii->first == SHADOW_CAMERA ) {
+                    globals->get_renderer()->updateShadowCamera(info, position);
+                    continue;
+                }
+                if ( ii->second.fullscreen )
+                    continue;
+
+                Camera* camera = ii->second.camera.get();
+                int slaveIndex = ii->second.slaveIndex;
+                const View::Slave& slave = _viewer->getSlave(slaveIndex);
+
+                if ( !viewDone ) {
+                    if ((info->flags & VIEW_ABSOLUTE) != 0)
+                        viewMatrix = slave._viewOffset;
+                    else
+                        viewMatrix = masterView * slave._viewOffset;
+                    viewDone = true;
+                }
+
+                camera->setViewMatrix( viewMatrix );
+
+                if ( !projectionDone ) {
+                    if ((info->flags & PROJECTION_ABSOLUTE) != 0) {
+                        if (info->flags & ENABLE_MASTER_ZOOM) {
+                            if (info->relativeCameraParent < _cameras.size()) {
+                                // template projection matrix and view matrix of the current camera
+                                osg::Matrix P0 = slave._projectionOffset;
+                                osg::Matrix R = viewMatrix;
+
+                                // The already known projection and view matrix of the parent camera
+                                const CameraInfo* parentInfo = _cameras[info->relativeCameraParent].get();
+                                RenderStageInfo prsi = parentInfo->cameras.find(MAIN_CAMERA)->second;
+                                osg::Matrix pP = prsi.camera->getProjectionMatrix();
+                                osg::Matrix pR = prsi.camera->getViewMatrix();
+                    
+                                // And the projection matrix derived from P0 so that the reference points match
+                                projectionMatrix = relativeProjection(P0, R, info->thisReference,
+                                                                      pP, pR, info->parentReference);
+                    
+                            } else {
+                                // We want to zoom, so take the original matrix and apply the zoom to it.
+                                projectionMatrix = slave._projectionOffset;
+                                projectionMatrix.postMultScale(osg::Vec3d(masterZoomFactor, masterZoomFactor, 1));
+                            }
+                        } else {
+                            projectionMatrix = slave._projectionOffset;
+                        }
+                    } else {
+                        projectionMatrix = masterProj * slave._projectionOffset;
+                    }
+                    projectionDone = true;
+                }
+
+                camera->setProjectionMatrix(projectionMatrix);
+            }
+        }
+    }
+
+    globals->get_renderer()->setPlanes( _zNear, _zFar );
+}
+
+void CameraGroup::setCameraParameters(float vfov, float aspectRatio)
+{
+    if (vfov != 0.0f && aspectRatio != 0.0f)
+        _viewer->getCamera()
+            ->setProjectionMatrixAsPerspective(vfov,
+                                               1.0f / aspectRatio,
+                                               _zNear, _zFar);
+}
+    
+double CameraGroup::getMasterAspectRatio() const
+{
+    if (_cameras.empty())
+        return 0.0;
+    
+    const CameraInfo* info = _cameras.front();
+    
+    osg::Camera* camera = info->getCamera(MAIN_CAMERA);
+    if ( !camera )
+        camera = info->getCamera( GEOMETRY_CAMERA );
+    const osg::Viewport* viewport = camera->getViewport();
+    if (!viewport) {
+        return 0.0;
+    }
+    
+    return static_cast<double>(viewport->height()) / viewport->width();
+}
+    
+}
+
+namespace
+{
+// A raw value for property nodes that references a class member via
+// an osg::ref_ptr.
+template<class C, class T>
+class RefMember : public SGRawValue<T>
+{
+public:
+    RefMember (C *obj, T C::*ptr)
+        : _obj(obj), _ptr(ptr) {}
+    virtual ~RefMember () {}
+    virtual T getValue () const
+    {
+        return _obj.get()->*_ptr;
+    }
+    virtual bool setValue (T value)
+    {
+        _obj.get()->*_ptr = value;
+        return true;
+    }
+    virtual SGRawValue<T> * clone () const
+    {
+        return new RefMember(_obj.get(), _ptr);
+    }
+private:
+    ref_ptr<C> _obj;
+    T C::* const _ptr;
+};
+
+template<typename C, typename T>
+RefMember<C, T> makeRefMember(C *obj, T C::*ptr)
+{
+    return RefMember<C, T>(obj, ptr);
+}
+
+template<typename C, typename T>
+void bindMemberToNode(SGPropertyNode* parent, const char* childName,
+                      C* obj, T C::*ptr, T value)
+{
+    SGPropertyNode* valNode = parent->getNode(childName);
+    RefMember<C, T> refMember = makeRefMember(obj, ptr);
+    if (!valNode) {
+        valNode = parent->getNode(childName, true);
+        valNode->tie(refMember, false);
+        setValue(valNode, value);
+    } else {
+        valNode->tie(refMember, true);
+    }
+}
+
+void buildViewport(flightgear::CameraInfo* info, SGPropertyNode* viewportNode,
+                   const osg::GraphicsContext::Traits *traits)
+{
+    using namespace flightgear;
+    bindMemberToNode(viewportNode, "x", info, &CameraInfo::x, 0.0);
+    bindMemberToNode(viewportNode, "y", info, &CameraInfo::y, 0.0);
+    bindMemberToNode(viewportNode, "width", info, &CameraInfo::width,
+                     static_cast<double>(traits->width));
+    bindMemberToNode(viewportNode, "height", info, &CameraInfo::height,
+                     static_cast<double>(traits->height));
+}
+}
+
+namespace flightgear
+{
+
+// Mostly copied from osg's osgViewer/View.cpp
+
+static osg::Geometry* createPanoramicSphericalDisplayDistortionMesh(
+    const Vec3& origin, const Vec3& widthVector, const Vec3& heightVector,
+    double sphere_radius, double collar_radius,
+    Image* intensityMap = 0, const Matrix& projectorMatrix = Matrix())
+{
+    osg::Vec3d center(0.0,0.0,0.0);
+    osg::Vec3d eye(0.0,0.0,0.0);
+
+    double distance = sqrt(sphere_radius*sphere_radius - collar_radius*collar_radius);
+    bool flip = false;
+    bool texcoord_flip = false;
+
+#if 0
+    osg::Vec3d projector = eye - osg::Vec3d(0.0,0.0, distance);
+
+    OSG_INFO<<"createPanoramicSphericalDisplayDistortionMesh : Projector position = "<<projector<<std::endl;
+    OSG_INFO<<"createPanoramicSphericalDisplayDistortionMesh : distance = "<<distance<<std::endl;
+#endif
+    // create the quad to visualize.
+    osg::Geometry* geometry = new osg::Geometry();
+
+    geometry->setSupportsDisplayList(false);
+
+    osg::Vec3 xAxis(widthVector);
+    float width = widthVector.length();
+    xAxis /= width;
+
+    osg::Vec3 yAxis(heightVector);
+    float height = heightVector.length();
+    yAxis /= height;
+
+    int noSteps = 160;
+
+    osg::Vec3Array* vertices = new osg::Vec3Array;
+    osg::Vec2Array* texcoords0 = new osg::Vec2Array;
+    osg::Vec2Array* texcoords1 = intensityMap==0 ? new osg::Vec2Array : 0;
+    osg::Vec4Array* colors = new osg::Vec4Array;
+
+#if 0
+    osg::Vec3 bottom = origin;
+    osg::Vec3 dx = xAxis*(width/((float)(noSteps-2)));
+    osg::Vec3 dy = yAxis*(height/((float)(noSteps-1)));
+#endif
+    osg::Vec3 top = origin + yAxis*height;
+
+    osg::Vec3 screenCenter = origin + widthVector*0.5f + heightVector*0.5f;
+    float screenRadius = heightVector.length() * 0.5f;
+
+    geometry->getOrCreateStateSet()->setMode(GL_CULL_FACE, osg::StateAttribute::OFF | osg::StateAttribute::PROTECTED);
+
+    for(int i=0;i<noSteps;++i)
+    {
+        //osg::Vec3 cursor = bottom+dy*(float)i;
+        for(int j=0;j<noSteps;++j)
+        {
+            osg::Vec2 texcoord(double(i)/double(noSteps-1), double(j)/double(noSteps-1));
+            double theta = texcoord.x() * 2.0 * osg::PI;
+            double phi = (1.0-texcoord.y()) * osg::PI;
+
+            if (texcoord_flip) texcoord.y() = 1.0f - texcoord.y();
+
+            osg::Vec3 pos(sin(phi)*sin(theta), sin(phi)*cos(theta), cos(phi));
+            pos = pos*projectorMatrix;
+
+            double alpha = atan2(pos.x(), pos.y());
+            if (alpha<0.0) alpha += 2.0*osg::PI;
+
+            double beta = atan2(sqrt(pos.x()*pos.x() + pos.y()*pos.y()), pos.z());
+            if (beta<0.0) beta += 2.0*osg::PI;
+
+            double gamma = atan2(sqrt(double(pos.x()*pos.x() + pos.y()*pos.y())), double(pos.z()+distance));
+            if (gamma<0.0) gamma += 2.0*osg::PI;
+
+
+            osg::Vec3 v = screenCenter + osg::Vec3(sin(alpha)*gamma*2.0/osg::PI, -cos(alpha)*gamma*2.0/osg::PI, 0.0f)*screenRadius;
+
+            if (flip)
+                vertices->push_back(osg::Vec3(v.x(), top.y()-(v.y()-origin.y()),v.z()));
+            else
+                vertices->push_back(v);
+
+            texcoords0->push_back( texcoord );
+
+            osg::Vec2 texcoord1(alpha/(2.0*osg::PI), 1.0f - beta/osg::PI);
+            if (intensityMap)
+            {
+                colors->push_back(intensityMap->getColor(texcoord1));
+            }
+            else
+            {
+                colors->push_back(osg::Vec4(1.0f,1.0f,1.0f,1.0f));
+                if (texcoords1) texcoords1->push_back( texcoord1 );
+            }
+
+
+        }
+    }
+
+
+    // pass the created vertex array to the points geometry object.
+    geometry->setVertexArray(vertices);
+
+    geometry->setColorArray(colors);
+    geometry->setColorBinding(osg::Geometry::BIND_PER_VERTEX);
+
+    geometry->setTexCoordArray(0,texcoords0);
+    if (texcoords1) geometry->setTexCoordArray(1,texcoords1);
+
+    osg::DrawElementsUShort* elements = new osg::DrawElementsUShort(osg::PrimitiveSet::TRIANGLES);
+    geometry->addPrimitiveSet(elements);
+
+    for(int i=0;i<noSteps-1;++i)
+    {
+        for(int j=0;j<noSteps-1;++j)
+        {
+            int i1 = j+(i+1)*noSteps;
+            int i2 = j+(i)*noSteps;
+            int i3 = j+1+(i)*noSteps;
+            int i4 = j+1+(i+1)*noSteps;
+
+            osg::Vec3& v1 = (*vertices)[i1];
+            osg::Vec3& v2 = (*vertices)[i2];
+            osg::Vec3& v3 = (*vertices)[i3];
+            osg::Vec3& v4 = (*vertices)[i4];
+
+            if ((v1-screenCenter).length()>screenRadius) continue;
+            if ((v2-screenCenter).length()>screenRadius) continue;
+            if ((v3-screenCenter).length()>screenRadius) continue;
+            if ((v4-screenCenter).length()>screenRadius) continue;
+
+            elements->push_back(i1);
+            elements->push_back(i2);
+            elements->push_back(i3);
+
+            elements->push_back(i1);
+            elements->push_back(i3);
+            elements->push_back(i4);
+        }
+    }
+
+    return geometry;
+}
+
+void CameraGroup::buildDistortionCamera(const SGPropertyNode* psNode,
+                                        Camera* camera)
+{
+    const SGPropertyNode* texNode = psNode->getNode("texture");
+    if (!texNode) {
+        // error
+        return;
+    }
+    string texName = texNode->getStringValue();
+    TextureMap::iterator itr = _textureTargets.find(texName);
+    if (itr == _textureTargets.end()) {
+        // error
+        return;
+    }
+    Viewport* viewport = camera->getViewport();
+    float width = viewport->width();
+    float height = viewport->height();
+    TextureRectangle* texRect = itr->second.get();
+    double radius = psNode->getDoubleValue("radius", 1.0);
+    double collar = psNode->getDoubleValue("collar", 0.45);
+    Geode* geode = new Geode();
+    geode->addDrawable(createPanoramicSphericalDisplayDistortionMesh(
+                           Vec3(0.0f,0.0f,0.0f), Vec3(width,0.0f,0.0f),
+                           Vec3(0.0f,height,0.0f), radius, collar));
+
+    // new we need to add the texture to the mesh, we do so by creating a
+    // StateSet to contain the Texture StateAttribute.
+    StateSet* stateset = geode->getOrCreateStateSet();
+    stateset->setTextureAttributeAndModes(0, texRect, StateAttribute::ON);
+    stateset->setMode(GL_LIGHTING, StateAttribute::OFF);
+
+    TexMat* texmat = new TexMat;
+    texmat->setScaleByTextureRectangleSize(true);
+    stateset->setTextureAttributeAndModes(0, texmat, osg::StateAttribute::ON);
+#if 0
+    if (!applyIntensityMapAsColours && intensityMap)
+    {
+        stateset->setTextureAttributeAndModes(1, new osg::Texture2D(intensityMap), osg::StateAttribute::ON);
+    }
+#endif
+    // add subgraph to render
+    camera->addChild(geode);
+    camera->setClearMask(GL_DEPTH_BUFFER_BIT | GL_COLOR_BUFFER_BIT);
+    camera->setClearColor(osg::Vec4(0.0, 0.0, 0.0, 1.0));
+    camera->setComputeNearFarMode(osg::CullSettings::DO_NOT_COMPUTE_NEAR_FAR);
+    camera->setCullingMode(osg::CullSettings::NO_CULLING);
+    camera->setName("DistortionCorrectionCamera");
+}
+
+CameraInfo* CameraGroup::buildCamera(SGPropertyNode* cameraNode)
+{
+    WindowBuilder *wBuild = WindowBuilder::getWindowBuilder();
+    const SGPropertyNode* windowNode = cameraNode->getNode("window");
+    GraphicsWindow* window = 0;
+    int cameraFlags = DO_INTERSECTION_TEST;
+    if (windowNode) {
+        // New style window declaration / definition
+        window = wBuild->buildWindow(windowNode);
+    } else {
+        // Old style: suck window params out of camera block
+        window = wBuild->buildWindow(cameraNode);
+    }
+    if (!window) {
+        return 0;
+    }
+    Camera* camera = new Camera;
+    camera->setAllowEventFocus(false);
+    camera->setGraphicsContext(window->gc.get());
+    camera->setViewport(new Viewport);
+    camera->setCullingMode(CullSettings::SMALL_FEATURE_CULLING
+                           | CullSettings::VIEW_FRUSTUM_CULLING);
+    camera->setInheritanceMask(CullSettings::ALL_VARIABLES
+                               & ~(CullSettings::CULL_MASK
+                                   | CullSettings::CULLING_MODE
+#if defined(HAVE_CULLSETTINGS_CLEAR_MASK)
+                                   | CullSettings::CLEAR_MASK
+#endif
+                                   ));
+
+    osg::Matrix vOff;
+    const SGPropertyNode* viewNode = cameraNode->getNode("view");
+    if (viewNode) {
+        double heading = viewNode->getDoubleValue("heading-deg", 0.0);
+        double pitch = viewNode->getDoubleValue("pitch-deg", 0.0);
+        double roll = viewNode->getDoubleValue("roll-deg", 0.0);
+        double x = viewNode->getDoubleValue("x", 0.0);
+        double y = viewNode->getDoubleValue("y", 0.0);
+        double z = viewNode->getDoubleValue("z", 0.0);
+        // Build a view matrix, which is the inverse of a model
+        // orientation matrix.
+        vOff = (Matrix::translate(-x, -y, -z)
+                * Matrix::rotate(-DegreesToRadians(heading),
+                                 Vec3d(0.0, 1.0, 0.0),
+                                 -DegreesToRadians(pitch),
+                                 Vec3d(1.0, 0.0, 0.0),
+                                 -DegreesToRadians(roll),
+                                 Vec3d(0.0, 0.0, 1.0)));
+        if (viewNode->getBoolValue("absolute", false))
+            cameraFlags |= VIEW_ABSOLUTE;
+    } else {
+        // Old heading parameter, works in the opposite direction
+        double heading = cameraNode->getDoubleValue("heading-deg", 0.0);
+        vOff.makeRotate(DegreesToRadians(heading), osg::Vec3(0, 1, 0));
+    }
+    // Configuring the physical dimensions of a monitor
+    SGPropertyNode* viewportNode = cameraNode->getNode("viewport", true);
+    double physicalWidth = viewportNode->getDoubleValue("width", 1024);
+    double physicalHeight = viewportNode->getDoubleValue("height", 768);
+    double bezelHeightTop = 0;
+    double bezelHeightBottom = 0;
+    double bezelWidthLeft = 0;
+    double bezelWidthRight = 0;
+    const SGPropertyNode* physicalDimensionsNode = 0;
+    if ((physicalDimensionsNode = cameraNode->getNode("physical-dimensions")) != 0) {
+        physicalWidth = physicalDimensionsNode->getDoubleValue("width", physicalWidth);
+        physicalHeight = physicalDimensionsNode->getDoubleValue("height", physicalHeight);
+        const SGPropertyNode* bezelNode = 0;
+        if ((bezelNode = physicalDimensionsNode->getNode("bezel")) != 0) {
+            bezelHeightTop = bezelNode->getDoubleValue("top", bezelHeightTop);
+            bezelHeightBottom = bezelNode->getDoubleValue("bottom", bezelHeightBottom);
+            bezelWidthLeft = bezelNode->getDoubleValue("left", bezelWidthLeft);
+            bezelWidthRight = bezelNode->getDoubleValue("right", bezelWidthRight);
+        }
+    }
+    osg::Matrix pOff;
+    unsigned parentCameraIndex = ~0u;
+    osg::Vec2d parentReference[2];
+    osg::Vec2d thisReference[2];
+    SGPropertyNode* projectionNode = 0;
+    if ((projectionNode = cameraNode->getNode("perspective")) != 0) {
+        double fovy = projectionNode->getDoubleValue("fovy-deg", 55.0);
+        double aspectRatio = projectionNode->getDoubleValue("aspect-ratio",
+                                                            1.0);
+        double zNear = projectionNode->getDoubleValue("near", 0.0);
+        double zFar = projectionNode->getDoubleValue("far", zNear + 20000);
+        double offsetX = projectionNode->getDoubleValue("offset-x", 0.0);
+        double offsetY = projectionNode->getDoubleValue("offset-y", 0.0);
+        double tan_fovy = tan(DegreesToRadians(fovy*0.5));
+        double right = tan_fovy * aspectRatio * zNear + offsetX;
+        double left = -tan_fovy * aspectRatio * zNear + offsetX;
+        double top = tan_fovy * zNear + offsetY;
+        double bottom = -tan_fovy * zNear + offsetY;
+        pOff.makeFrustum(left, right, bottom, top, zNear, zFar);
+        cameraFlags |= PROJECTION_ABSOLUTE;
+        if (projectionNode->getBoolValue("fixed-near-far", true))
+            cameraFlags |= FIXED_NEAR_FAR;
+    } else if ((projectionNode = cameraNode->getNode("frustum")) != 0
+               || (projectionNode = cameraNode->getNode("ortho")) != 0) {
+        double top = projectionNode->getDoubleValue("top", 0.0);
+        double bottom = projectionNode->getDoubleValue("bottom", 0.0);
+        double left = projectionNode->getDoubleValue("left", 0.0);
+        double right = projectionNode->getDoubleValue("right", 0.0);
+        double zNear = projectionNode->getDoubleValue("near", 0.0);
+        double zFar = projectionNode->getDoubleValue("far", zNear + 20000);
+        if (cameraNode->getNode("frustum")) {
+            pOff.makeFrustum(left, right, bottom, top, zNear, zFar);
+            cameraFlags |= PROJECTION_ABSOLUTE;
+        } else {
+            pOff.makeOrtho(left, right, bottom, top, zNear, zFar);
+            cameraFlags |= (PROJECTION_ABSOLUTE | ORTHO);
+        }
+        if (projectionNode->getBoolValue("fixed-near-far", true))
+            cameraFlags |= FIXED_NEAR_FAR;
+    } else if ((projectionNode = cameraNode->getNode("master-perspective")) != 0) {
+        double zNear = projectionNode->getDoubleValue("eye-distance", 0.4*physicalWidth);
+        double xoff = projectionNode->getDoubleValue("x-offset", 0);
+        double yoff = projectionNode->getDoubleValue("y-offset", 0);
+        double left = -0.5*physicalWidth - xoff;
+        double right = 0.5*physicalWidth - xoff;
+        double bottom = -0.5*physicalHeight - yoff;
+        double top = 0.5*physicalHeight - yoff;
+        pOff.makeFrustum(left, right, bottom, top, zNear, zNear*1000);
+        cameraFlags |= PROJECTION_ABSOLUTE | ENABLE_MASTER_ZOOM;
+    } else if ((projectionNode = cameraNode->getNode("right-of-perspective"))
+               || (projectionNode = cameraNode->getNode("left-of-perspective"))
+               || (projectionNode = cameraNode->getNode("above-perspective"))
+               || (projectionNode = cameraNode->getNode("below-perspective"))
+               || (projectionNode = cameraNode->getNode("reference-points-perspective"))) {
+        std::string name = projectionNode->getStringValue("parent-camera");
+        for (unsigned i = 0; i < _cameras.size(); ++i) {
+            if (_cameras[i]->name != name)
+                continue;
+            parentCameraIndex = i;
+        }
+        if (_cameras.size() <= parentCameraIndex) {
+            SG_LOG(SG_VIEW, SG_ALERT, "CameraGroup::buildCamera: "
+                   "failed to find parent camera for relative camera!");
+            return 0;
+        }
+        const CameraInfo* parentInfo = _cameras[parentCameraIndex].get();
+        if (projectionNode->getNameString() == "right-of-perspective") {
+            double tmp = (parentInfo->physicalWidth + 2*parentInfo->bezelWidthRight)/parentInfo->physicalWidth;
+            parentReference[0] = osg::Vec2d(tmp, -1);
+            parentReference[1] = osg::Vec2d(tmp, 1);
+            tmp = (physicalWidth + 2*bezelWidthLeft)/physicalWidth;
+            thisReference[0] = osg::Vec2d(-tmp, -1);
+            thisReference[1] = osg::Vec2d(-tmp, 1);
+        } else if (projectionNode->getNameString() == "left-of-perspective") {
+            double tmp = (parentInfo->physicalWidth + 2*parentInfo->bezelWidthLeft)/parentInfo->physicalWidth;
+            parentReference[0] = osg::Vec2d(-tmp, -1);
+            parentReference[1] = osg::Vec2d(-tmp, 1);
+            tmp = (physicalWidth + 2*bezelWidthRight)/physicalWidth;
+            thisReference[0] = osg::Vec2d(tmp, -1);
+            thisReference[1] = osg::Vec2d(tmp, 1);
+        } else if (projectionNode->getNameString() == "above-perspective") {
+            double tmp = (parentInfo->physicalHeight + 2*parentInfo->bezelHeightTop)/parentInfo->physicalHeight;
+            parentReference[0] = osg::Vec2d(-1, tmp);
+            parentReference[1] = osg::Vec2d(1, tmp);
+            tmp = (physicalHeight + 2*bezelHeightBottom)/physicalHeight;
+            thisReference[0] = osg::Vec2d(-1, -tmp);
+            thisReference[1] = osg::Vec2d(1, -tmp);
+        } else if (projectionNode->getNameString() == "below-perspective") {
+            double tmp = (parentInfo->physicalHeight + 2*parentInfo->bezelHeightBottom)/parentInfo->physicalHeight;
+            parentReference[0] = osg::Vec2d(-1, -tmp);
+            parentReference[1] = osg::Vec2d(1, -tmp);
+            tmp = (physicalHeight + 2*bezelHeightTop)/physicalHeight;
+            thisReference[0] = osg::Vec2d(-1, tmp);
+            thisReference[1] = osg::Vec2d(1, tmp);
+        } else if (projectionNode->getNameString() == "reference-points-perspective") {
+            SGPropertyNode* parentNode = projectionNode->getNode("parent", true);
+            SGPropertyNode* thisNode = projectionNode->getNode("this", true);
+            SGPropertyNode* pointNode;
+
+            pointNode = parentNode->getNode("point", 0, true);
+            parentReference[0][0] = pointNode->getDoubleValue("x", 0)*2/parentInfo->physicalWidth;
+            parentReference[0][1] = pointNode->getDoubleValue("y", 0)*2/parentInfo->physicalHeight;
+            pointNode = parentNode->getNode("point", 1, true);
+            parentReference[1][0] = pointNode->getDoubleValue("x", 0)*2/parentInfo->physicalWidth;
+            parentReference[1][1] = pointNode->getDoubleValue("y", 0)*2/parentInfo->physicalHeight;
+
+            pointNode = thisNode->getNode("point", 0, true);
+            thisReference[0][0] = pointNode->getDoubleValue("x", 0)*2/physicalWidth;
+            thisReference[0][1] = pointNode->getDoubleValue("y", 0)*2/physicalHeight;
+            pointNode = thisNode->getNode("point", 1, true);
+            thisReference[1][0] = pointNode->getDoubleValue("x", 0)*2/physicalWidth;
+            thisReference[1][1] = pointNode->getDoubleValue("y", 0)*2/physicalHeight;
+        }
+
+        pOff = osg::Matrix::perspective(45, physicalWidth/physicalHeight, 1, 20000);
+        cameraFlags |= PROJECTION_ABSOLUTE | ENABLE_MASTER_ZOOM;
+    } else {
+        // old style shear parameters
+        double shearx = cameraNode->getDoubleValue("shear-x", 0);
+        double sheary = cameraNode->getDoubleValue("shear-y", 0);
+        pOff.makeTranslate(-shearx, -sheary, 0);
+    }
+    const SGPropertyNode* textureNode = cameraNode->getNode("texture");
+    if (textureNode) {
+        string texName = textureNode->getStringValue("name");
+        int tex_width = textureNode->getIntValue("width");
+        int tex_height = textureNode->getIntValue("height");
+        TextureRectangle* texture = new TextureRectangle;
+
+        texture->setTextureSize(tex_width, tex_height);
+        texture->setInternalFormat(GL_RGB);
+        texture->setFilter(Texture::MIN_FILTER, Texture::LINEAR);
+        texture->setFilter(Texture::MAG_FILTER, Texture::LINEAR);
+        texture->setWrap(Texture::WRAP_S, Texture::CLAMP_TO_EDGE);
+        texture->setWrap(Texture::WRAP_T, Texture::CLAMP_TO_EDGE);
+        camera->setDrawBuffer(GL_FRONT);
+        camera->setReadBuffer(GL_FRONT);
+        camera->setRenderTargetImplementation(Camera::FRAME_BUFFER_OBJECT);
+        camera->attach(Camera::COLOR_BUFFER, texture);
+        _textureTargets[texName] = texture;
+    } else {
+        camera->setDrawBuffer(GL_BACK);
+        camera->setReadBuffer(GL_BACK);
+    }
+    const SGPropertyNode* psNode = cameraNode->getNode("panoramic-spherical");
+    bool useMasterSceneGraph = !psNode;
+    CameraInfo* info = globals->get_renderer()->buildRenderingPipeline(this, cameraFlags, camera, vOff, pOff,
+                                                                        window->gc.get(), useMasterSceneGraph);
+    info->name = cameraNode->getStringValue("name");
+    info->physicalWidth = physicalWidth;
+    info->physicalHeight = physicalHeight;
+    info->bezelHeightTop = bezelHeightTop;
+    info->bezelHeightBottom = bezelHeightBottom;
+    info->bezelWidthLeft = bezelWidthLeft;
+    info->bezelWidthRight = bezelWidthRight;
+    info->relativeCameraParent = parentCameraIndex;
+    info->parentReference[0] = parentReference[0];
+    info->parentReference[1] = parentReference[1];
+    info->thisReference[0] = thisReference[0];
+    info->thisReference[1] = thisReference[1];
+    // If a viewport isn't set on the camera, then it's hard to dig it
+    // out of the SceneView objects in the viewer, and the coordinates
+    // of mouse events are somewhat bizzare.
+    buildViewport(info, viewportNode, window->gc->getTraits());
+    info->updateCameras();
+    // Distortion camera needs the viewport which is created by addCamera().
+    if (psNode) {
+        info->flags = info->flags | VIEW_ABSOLUTE;
+        buildDistortionCamera(psNode, camera);
+    }
+    return info;
+}
+
+CameraInfo* CameraGroup::buildGUICamera(SGPropertyNode* cameraNode,
+                                        GraphicsWindow* window)
+{
+    WindowBuilder *wBuild = WindowBuilder::getWindowBuilder();
+    const SGPropertyNode* windowNode = (cameraNode
+                                        ? cameraNode->getNode("window")
+                                        : 0);
+    if (!window && windowNode) {
+      // New style window declaration / definition
+      window = wBuild->buildWindow(windowNode);
+    }
+
+    if (!window) { // buildWindow can fail
+      SG_LOG(SG_VIEW, SG_WARN, "CameraGroup::buildGUICamera: failed to build a window");
+      return NULL;
+    }
+
+    Camera* camera = new Camera;
+    camera->setName( "GUICamera" );
+    camera->setAllowEventFocus(false);
+    camera->setGraphicsContext(window->gc.get());
+    camera->setViewport(new Viewport);
+    camera->setClearMask(0);
+    camera->setInheritanceMask(CullSettings::ALL_VARIABLES
+                               & ~(CullSettings::COMPUTE_NEAR_FAR_MODE
+                                   | CullSettings::CULLING_MODE
+#if defined(HAVE_CULLSETTINGS_CLEAR_MASK)
+                                   | CullSettings::CLEAR_MASK
+#endif
+                                   ));
+    camera->setComputeNearFarMode(osg::CullSettings::DO_NOT_COMPUTE_NEAR_FAR);
+    camera->setCullingMode(osg::CullSettings::NO_CULLING);
+    camera->setProjectionResizePolicy(Camera::FIXED);
+    camera->setReferenceFrame(Transform::ABSOLUTE_RF);
+    const int cameraFlags = GUI | DO_INTERSECTION_TEST;
+
+    CameraInfo* result = new CameraInfo(cameraFlags);
+    // The camera group will always update the camera
+    camera->setReferenceFrame(Transform::ABSOLUTE_RF);
+
+    getViewer()->addSlave(camera, Matrixd::identity(), Matrixd::identity(), false);
+    //installCullVisitor(camera);
+    int slaveIndex = getViewer()->getNumSlaves() - 1;
+    result->addCamera( MAIN_CAMERA, camera, slaveIndex );
+    camera->setRenderOrder(Camera::POST_RENDER, slaveIndex);
+    addCamera(result);
+
+    // XXX Camera needs to be drawn last; eventually the render order
+    // should be assigned by a camera manager.
+    camera->setRenderOrder(osg::Camera::POST_RENDER, 10000);
+    SGPropertyNode* viewportNode = cameraNode->getNode("viewport", true);
+    buildViewport(result, viewportNode, window->gc->getTraits());
+
+    // Disable statistics for the GUI camera.
+    camera->setStats(0);
+    result->updateCameras();
+    return result;
+}
+
+CameraGroup* CameraGroup::buildCameraGroup(osgViewer::Viewer* viewer,
+                                           SGPropertyNode* gnode)
+{
+    sgUserDataInit( globals->get_props() );
+
+    CameraGroup* cgroup = new CameraGroup(viewer);
+    for (int i = 0; i < gnode->nChildren(); ++i) {
+        SGPropertyNode* pNode = gnode->getChild(i);
+        const char* name = pNode->getName();
+        if (!strcmp(name, "camera")) {
+            cgroup->buildCamera(pNode);
+        } else if (!strcmp(name, "window")) {
+            WindowBuilder::getWindowBuilder()->buildWindow(pNode);
+        } else if (!strcmp(name, "gui")) {
+            cgroup->buildGUICamera(pNode);
+        }
+    }
+    bindMemberToNode(gnode, "znear", cgroup, &CameraGroup::_zNear, .1f);
+    bindMemberToNode(gnode, "zfar", cgroup, &CameraGroup::_zFar, 120000.0f);
+    bindMemberToNode(gnode, "near-field", cgroup, &CameraGroup::_nearField,
+                     100.0f);
+    return cgroup;
+}
+
+void CameraGroup::setCameraCullMasks(Node::NodeMask nm)
+{
+    for (CameraIterator i = camerasBegin(), e = camerasEnd(); i != e; ++i) {
+        CameraInfo* info = i->get();
+        if (info->flags & GUI)
+            continue;
+        osg::ref_ptr<osg::Camera> farCamera = info->getCamera(FAR_CAMERA);
+        osg::Camera* camera = info->getCamera( MAIN_CAMERA );
+        if (camera) {
+            if (farCamera.valid() && farCamera->getNodeMask() != 0) {
+                camera->setCullMask(nm & ~simgear::BACKGROUND_BIT);
+                camera->setCullMaskLeft(nm & ~simgear::BACKGROUND_BIT);
+                camera->setCullMaskRight(nm & ~simgear::BACKGROUND_BIT);
+                farCamera->setCullMask(nm);
+                farCamera->setCullMaskLeft(nm);
+                farCamera->setCullMaskRight(nm);
+            } else {
+                camera->setCullMask(nm);
+                camera->setCullMaskLeft(nm);
+                camera->setCullMaskRight(nm);
+            }
+        } else {
+            camera = info->getCamera( GEOMETRY_CAMERA );
+            if (camera == 0) continue;
+            camera->setCullMask( nm & ~simgear::MODELLIGHT_BIT );
+        }
+    }
+}
+
+void CameraGroup::resized()
+{
+    for (CameraIterator i = camerasBegin(), e = camerasEnd(); i != e; ++i) {
+        CameraInfo *info = i->get();
+        Camera* camera = info->getCamera( MAIN_CAMERA );
+        if ( camera == 0 )
+            camera = info->getCamera( DISPLAY_CAMERA );
+        const Viewport* viewport = camera->getViewport();
+        info->x = viewport->x();
+        info->y = viewport->y();
+        info->width = viewport->width();
+        info->height = viewport->height();
+
+        info->resized( info->width, info->height );
+    }
+}
+
+const CameraInfo* CameraGroup::getGUICamera() const
+{
+    ConstCameraIterator result
+        = std::find_if(camerasBegin(), camerasEnd(),
+                   FlagTester<CameraInfo>(GUI));
+    if (result == camerasEnd()) {
+        return NULL;
+    }
+
+    return *result;
+}
+  
+Camera* getGUICamera(CameraGroup* cgroup)
+{
+    const CameraInfo* info = cgroup->getGUICamera();
+    if (!info) {
+        return NULL;
+    }
+    
+    return info->getCamera(MAIN_CAMERA);
+}
+
+static bool computeCameraIntersection(const CameraInfo* cinfo,
+                                      const osgGA::GUIEventAdapter* ea,
+                                      osgUtil::LineSegmentIntersector::Intersections& intersections)
+{
+  using osgUtil::Intersector;
+  using osgUtil::LineSegmentIntersector;
+  double x, y;
+  eventToWindowCoords(ea, x, y);
+  
+  if (!(cinfo->flags & CameraGroup::DO_INTERSECTION_TEST))
+    return false;
+  
+  const Camera* camera = cinfo->getCamera(MAIN_CAMERA);
+  if ( !camera )
+    camera = cinfo->getCamera( GEOMETRY_CAMERA );
+  if (camera->getGraphicsContext() != ea->getGraphicsContext())
+    return false;
+  
+  const Viewport* viewport = camera->getViewport();
+  double epsilon = 0.5;
+  if (!(x >= viewport->x() - epsilon
+        && x < viewport->x() + viewport->width() -1.0 + epsilon
+        && y >= viewport->y() - epsilon
+        && y < viewport->y() + viewport->height() -1.0 + epsilon))
+    return false;
+  
+  Vec4d start(x, y, 0.0, 1.0);
+  Vec4d end(x, y, 1.0, 1.0);
+  Matrix windowMat = viewport->computeWindowMatrix();
+  Matrix startPtMat = Matrix::inverse(camera->getProjectionMatrix()
+                                      * windowMat);
+  Matrix endPtMat;
+  const Camera* farCamera = cinfo->getCamera( FAR_CAMERA );
+  if (!farCamera || farCamera->getNodeMask() == 0)
+    endPtMat = startPtMat;
+  else
+    endPtMat = Matrix::inverse(farCamera->getProjectionMatrix()
+                               * windowMat);
+  start = start * startPtMat;
+  start /= start.w();
+  end = end * endPtMat;
+  end /= end.w();
+  ref_ptr<LineSegmentIntersector> picker
+  = new LineSegmentIntersector(Intersector::VIEW,
+                               Vec3d(start.x(), start.y(), start.z()),
+                               Vec3d(end.x(), end.y(), end.z()));
+  osgUtil::IntersectionVisitor iv(picker.get());
+  iv.setTraversalMask( ~simgear::MODELLIGHT_BIT );
+  const_cast<Camera*>(camera)->accept(iv);
+  if (picker->containsIntersections()) {
+    intersections = picker->getIntersections();
+    return true;
+  }
+  
+  return false;
+}
+  
+bool computeIntersections(const CameraGroup* cgroup,
+                          const osgGA::GUIEventAdapter* ea,
+                          osgUtil::LineSegmentIntersector::Intersections& intersections)
+{
+    // test the GUI first
+    const CameraInfo* guiCamera = cgroup->getGUICamera();
+    if (guiCamera && computeCameraIntersection(guiCamera, ea, intersections))
+        return true;
+    
+    // Find camera that contains event
+    for (CameraGroup::ConstCameraIterator iter = cgroup->camerasBegin(),
+             e = cgroup->camerasEnd();
+         iter != e;
+         ++iter) {
+        const CameraInfo* cinfo = iter->get();
+        if (cinfo == guiCamera)
+            continue;
+        
+        if (computeCameraIntersection(cinfo, ea, intersections))
+            return true;
+    }
+  
+    intersections.clear();
+    return false;
+}
+
+void warpGUIPointer(CameraGroup* cgroup, int x, int y)
+{
+    using osgViewer::GraphicsWindow;
+    Camera* guiCamera = getGUICamera(cgroup);
+    if (!guiCamera)
+        return;
+    Viewport* vport = guiCamera->getViewport();
+    GraphicsWindow* gw
+        = dynamic_cast<GraphicsWindow*>(guiCamera->getGraphicsContext());
+    if (!gw)
+        return;
+    globals->get_renderer()->getEventHandler()->setMouseWarped();
+    // Translate the warp request into the viewport of the GUI camera,
+    // send the request to the window, then transform the coordinates
+    // for the Viewer's event queue.
+    double wx = x + vport->x();
+    double wyUp = vport->height() + vport->y() - y;
+    double wy;
+    const GraphicsContext::Traits* traits = gw->getTraits();
+    if (gw->getEventQueue()->getCurrentEventState()->getMouseYOrientation()
+        == osgGA::GUIEventAdapter::Y_INCREASING_DOWNWARDS) {
+        wy = traits->height - wyUp;
+    } else {
+        wy = wyUp;
+    }
+    gw->getEventQueue()->mouseWarped(wx, wy);
+    gw->requestWarpPointer(wx, wy);
+    osgGA::GUIEventAdapter* eventState
+        = cgroup->getViewer()->getEventQueue()->getCurrentEventState();
+    double viewerX
+        = (eventState->getXmin()
+           + ((wx / double(traits->width))
+              * (eventState->getXmax() - eventState->getXmin())));
+    double viewerY
+        = (eventState->getYmin()
+           + ((wyUp / double(traits->height))
+              * (eventState->getYmax() - eventState->getYmin())));
+    cgroup->getViewer()->getEventQueue()->mouseWarped(viewerX, viewerY);
+}
+}
diff --git a/src/Viewer/CameraGroup.hxx b/src/Viewer/CameraGroup.hxx
new file mode 100644 (file)
index 0000000..606bfc3
--- /dev/null
@@ -0,0 +1,337 @@
+// Copyright (C) 2008  Tim Moore
+//
+// This program is free software; you can redistribute it and/or
+// modify it under the terms of the GNU General Public License as
+// published by the Free Software Foundation; either version 2 of the
+// License, or (at your option) any later version.
+//
+// This program is distributed in the hope that it will be useful, but
+// WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+// General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License
+// along with this program; if not, write to the Free Software
+// Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
+
+#ifndef CAMERAGROUP_HXX
+#define CAMERAGROUP_HXX 1
+
+#include <map>
+#include <string>
+#include <vector>
+
+#include <osg/Matrix>
+#include <osg/ref_ptr>
+#include <osg/Referenced>
+#include <osg/Node>
+#include <osg/TextureRectangle>
+#include <osg/Texture2D>
+#include <osg/TexGen>
+#include <osgUtil/RenderBin>
+
+// For osgUtil::LineSegmentIntersector::Intersections, which is a typedef.
+#include <osgUtil/LineSegmentIntersector>
+namespace osg
+{
+class Camera;
+}
+
+namespace osgViewer
+{
+class Viewer;
+}
+
+class SGPropertyNode;
+
+namespace flightgear
+{
+
+class GraphicsWindow;
+
+struct RenderBufferInfo {
+       enum Kind {
+               DEPTH_BUFFER,
+               NORMAL_BUFFER,
+               DIFFUSE_BUFFER,
+               SPEC_EMIS_BUFFER,
+               LIGHTING_BUFFER,
+        SHADOW_BUFFER
+       };
+
+       RenderBufferInfo(osg::Texture2D* t = 0, float s = 1.0 ) : texture(t), scaleFactor(s) {}
+       osg::ref_ptr<osg::Texture2D> texture;
+       float scaleFactor;
+};
+typedef std::map<RenderBufferInfo::Kind,RenderBufferInfo> RenderBufferMap;
+typedef std::map<osg::Camera::BufferComponent,size_t> AttachmentMap;
+
+struct RenderStageInfo {
+       RenderStageInfo(osg::Camera* camera_ = 0, int si = -1, bool fs = false)
+               : camera(camera_), slaveIndex(si), scaleFactor(1.0f), fullscreen(fs)
+               , resizable(true)
+       {
+       }
+
+       osg::ref_ptr<osg::Camera> camera;
+       AttachmentMap buffers;
+       int slaveIndex;
+       float scaleFactor;
+       bool fullscreen;
+       bool resizable;
+};
+
+enum CameraKind {
+       MAIN_CAMERA,
+       FAR_CAMERA,
+       GEOMETRY_CAMERA,
+       SHADOW_CAMERA,
+       BLOOM_CAMERA_1,
+       BLOOM_CAMERA_2,
+       AO_CAMERA_1,
+       AO_CAMERA_2,
+       AO_CAMERA_3,
+       LIGHTING_CAMERA,
+       DISPLAY_CAMERA
+};
+typedef std::map<CameraKind,RenderStageInfo> CameraMap;
+
+/** A wrapper around osg::Camera that contains some extra information.
+ */
+struct CameraInfo : public osg::Referenced
+{
+    CameraInfo(unsigned flags_)
+        : flags(flags_),
+          x(0.0), y(0.0), width(0.0), height(0.0),
+          physicalWidth(0), physicalHeight(0), bezelHeightTop(0),
+          bezelHeightBottom(0), bezelWidthLeft(0), bezelWidthRight(0),
+          relativeCameraParent(~0u),
+          bufferSize( new osg::Uniform("fg_BufferSize", osg::Vec2f() ) ),
+          projInverse( new osg::Uniform( "fg_ProjectionMatrixInverse", osg::Matrixf() ) ),
+          viewInverse( new osg::Uniform( "fg_ViewMatrixInverse",osg::Matrixf() ) ),
+          view( new osg::Uniform( "fg_ViewMatrix",osg::Matrixf() ) ),
+          du( new osg::Uniform( "fg_du",osg::Vec4() ) ),
+          dv( new osg::Uniform( "fg_dv",osg::Vec4() ) )
+    {
+    }
+
+       /** Update and resize cameras
+        */
+       void updateCameras();
+       void resized(double w, double h);
+    /** The name as given in the config file.
+     */
+    std::string name;
+    /** Properties of the camera. @see CameraGroup::Flags.
+     */
+    unsigned flags;
+
+    /** Viewport parameters.
+     */
+    double x;
+    double y;
+    double width;
+    double height;
+    /** Physical size parameters.
+     */
+    double physicalWidth;
+    double physicalHeight;
+    double bezelHeightTop;
+    double bezelHeightBottom;
+    double bezelWidthLeft;
+    double bezelWidthRight;
+    /** The parent camera for relative camera configurations.
+     */
+    unsigned relativeCameraParent;
+
+    /** the camera objects
+     */
+       CameraMap cameras;
+       void addCamera( CameraKind k, osg::Camera* c, int si = -1, bool fs = false ) { cameras[k].camera = c; cameras[k].slaveIndex = si; cameras[k].fullscreen = fs; }
+       void addCamera( CameraKind k, osg::Camera* c, bool fs ) { cameras[k].camera = c; cameras[k].fullscreen = fs; }
+       void addCamera( CameraKind k, osg::Camera* c, float s ) { cameras[k].camera = c; cameras[k].scaleFactor = s; }
+       osg::Camera* getCamera(CameraKind k) const;
+       int getMainSlaveIndex() const;
+       RenderStageInfo& getRenderStageInfo( CameraKind k ) { return cameras[k]; }
+
+       /** the buffer objects
+        */
+       RenderBufferMap buffers;
+       void addBuffer(RenderBufferInfo::Kind k, osg::Texture2D* tex, float scale = 1.0 ) { buffers[k] = RenderBufferInfo(tex,scale); }
+       osg::Texture2D* getBuffer(RenderBufferInfo::Kind k) const;
+
+    osg::ref_ptr<osg::TexGen> shadowTexGen[4];
+
+    osg::ref_ptr<osg::Uniform> bufferSize;
+    //osg::ref_ptr<osg::Uniform> bloomOffset[2];
+    osg::ref_ptr<osg::Uniform> projInverse;
+    osg::ref_ptr<osg::Uniform> viewInverse;
+    osg::ref_ptr<osg::Uniform> view;
+    osg::ref_ptr<osg::Uniform> du;
+    osg::ref_ptr<osg::Uniform> dv;
+
+       void setMatrices( osg::Camera* c );
+
+       osgUtil::RenderBin::RenderBinList savedTransparentBins;
+    /** The reference points in the parents projection space.
+     */
+    osg::Vec2d parentReference[2];
+    /** The reference points in the current projection space.
+     */
+    osg::Vec2d thisReference[2];
+};
+
+/** Update the OSG cameras from the camera info.
+ */
+void updateCameras(const CameraInfo* info);
+
+class CameraGroup : public osg::Referenced
+{
+public:
+    /** properties of a camera.
+     */
+    enum Flags
+    {
+        VIEW_ABSOLUTE = 0x1, /**< The camera view is absolute, not
+                                relative to the master camera. */
+        PROJECTION_ABSOLUTE = 0x2, /**< The projection is absolute. */
+        ORTHO = 0x4,               /**< The projection is orthographic */
+        GUI = 0x8,                 /**< Camera draws the GUI. */
+        DO_INTERSECTION_TEST = 0x10,/**< scene intersection tests this
+                                       camera. */
+        FIXED_NEAR_FAR = 0x20,     /**< take the near far values in the
+                                      projection for real. */
+        ENABLE_MASTER_ZOOM = 0x40  /**< Can apply the zoom algorithm. */
+    };
+    /** Create a camera group associated with an osgViewer::Viewer.
+     * @param viewer the viewer
+     */
+    CameraGroup(osgViewer::Viewer* viewer);
+    /** Get the camera group's Viewer.
+     * @return the viewer
+     */
+    osgViewer::Viewer* getViewer() { return _viewer.get(); }
+    /** Create an osg::Camera from a property node and add it to the
+     * camera group.
+     * @param cameraNode the property node.
+     * @return a CameraInfo object for the camera.
+     */
+    CameraInfo* buildCamera(SGPropertyNode* cameraNode);
+    /** Create a camera from properties that will draw the GUI and add
+     * it to the camera group.
+     * @param cameraNode the property node. This can be 0, in which
+     * case a default GUI camera is created.
+     * @param window the GraphicsWindow to use for the GUI camera. If
+     * this is 0, the window is determined from the property node.
+     * @return a CameraInfo object for the GUI camera.
+     */
+    CameraInfo* buildGUICamera(SGPropertyNode* cameraNode,
+                               GraphicsWindow* window = 0);
+    /** Update the view for the camera group.
+     * @param position the world position of the view
+     * @param orientation the world orientation of the view.
+     */
+    void update(const osg::Vec3d& position, const osg::Quat& orientation);
+    /** Set the parameters of the viewer's master camera. This won't
+     * affect cameras that have CameraFlags::PROJECTION_ABSOLUTE set.
+     * XXX Should znear and zfar be settable?
+     * @param vfov the vertical field of view angle
+     * @param aspectRatio the master camera's aspect ratio. This
+     * doesn't actually change the viewport, but should reflect the
+     * current viewport.
+     */
+    void setCameraParameters(float vfov, float aspectRatio);
+    /** Set the default CameraGroup, which is the only one that
+     * matters at this time.
+     * @param group the group to set.
+     */
+    static void setDefault(CameraGroup* group) { _defaultGroup = group; }
+    /** Get the default CameraGroup.
+     * @return the default camera group.
+     */
+    static CameraGroup* getDefault() { return _defaultGroup.get(); }
+    typedef std::vector<osg::ref_ptr<CameraInfo> > CameraList;
+    typedef CameraList::iterator CameraIterator;
+    typedef CameraList::const_iterator ConstCameraIterator;
+    /** Get iterator for camera vector. The iterator's value is a ref_ptr.
+     */
+    CameraIterator camerasBegin() { return _cameras.begin(); }
+    /** Get iteator pointing to the end of the camera list.
+     */
+    CameraIterator camerasEnd() { return _cameras.end(); }
+    ConstCameraIterator camerasBegin() const { return _cameras.begin(); }
+    ConstCameraIterator camerasEnd() const { return _cameras.end(); }
+    void addCamera(CameraInfo* info) { _cameras.push_back(info); }
+    /** Build a complete CameraGroup from a property node.
+     * @param viewer the viewer associated with this camera group.
+     * @param the camera group property node.
+     */
+    static CameraGroup* buildCameraGroup(osgViewer::Viewer* viewer,
+                                         SGPropertyNode* node);
+    /** Set the cull mask on all non-GUI cameras
+     */
+    void setCameraCullMasks(osg::Node::NodeMask nm);
+    /** Update camera properties after a resize event.
+     */
+    void resized();
+
+    void buildDistortionCamera(const SGPropertyNode* psNode,
+                               osg::Camera* camera);
+  
+    /**
+     * get aspect ratio of master camera's viewport
+     */
+    double getMasterAspectRatio() const;
+  
+    /**
+     * find the GUI camera if one is defined 
+     */
+    const CameraInfo* getGUICamera() const;
+protected:
+    CameraList _cameras;
+    osg::ref_ptr<osgViewer::Viewer> _viewer;
+    static osg::ref_ptr<CameraGroup> _defaultGroup;
+    // Near, far for the master camera if used.
+    float _zNear;
+    float _zFar;
+    float _nearField;
+    typedef std::map<std::string, osg::ref_ptr<osg::TextureRectangle> > TextureMap;
+    TextureMap _textureTargets;
+};
+
+}
+
+namespace osgGA
+{
+class GUIEventAdapter;
+}
+
+namespace flightgear
+{
+/** Get the osg::Camera that draws the GUI, if any, from a camera
+ * group.
+ * @param cgroup the camera group
+ * @return the GUI camera or 0
+ */
+osg::Camera* getGUICamera(CameraGroup* cgroup);
+/** Choose a camera using an event and do intersection testing on its
+ * view of the scene. Only cameras with the DO_INTERSECTION_TEST flag
+ * set are considered.
+ * @param cgroup the CameraGroup
+ * @param ea the event containing a window and mouse coordinates
+ * @param intersections container for the result of intersection
+ * testing.
+ * @return true if any intersections are found
+ */
+bool computeIntersections(const CameraGroup* cgroup,
+                          const osgGA::GUIEventAdapter* ea,
+                          osgUtil::LineSegmentIntersector::Intersections&
+                          intersections);
+/** Warp the pointer to coordinates in the GUI camera of a camera group.
+ * @param cgroup the camera group
+ * @param x x window coordinate of pointer
+ * @param y y window coordinate of pointer, in "y down" coordinates.
+ */
+void warpGUIPointer(CameraGroup* cgroup, int x, int y);
+}
+#endif
diff --git a/src/Viewer/FGEventHandler.cxx b/src/Viewer/FGEventHandler.cxx
new file mode 100644 (file)
index 0000000..9951c00
--- /dev/null
@@ -0,0 +1,413 @@
+#ifdef HAVE_CONFIG_H
+#  include <config.h>
+#endif
+#include <osg/Camera>
+#include <osg/GraphicsContext>
+#include <osg/Math>
+#include <osg/Viewport>
+#include <osgViewer/Viewer>
+
+#include <plib/pu.h>
+#include <Main/fg_props.hxx>
+#include "CameraGroup.hxx"
+#include "FGEventHandler.hxx"
+#include "WindowSystemAdapter.hxx"
+#include "renderer.hxx"
+
+#if !defined(X_DISPLAY_MISSING)
+#define X_DOUBLE_SCROLL_BUG 1
+#endif
+
+#ifdef SG_MAC
+// hack - during interactive resize on Mac, OSG queues and then flushes
+// a large number of resize events, without doing any drawing.
+extern void puCleanUpJunk ( void ) ;
+#endif
+
+namespace flightgear
+{
+const int displayStatsKey = 1;
+const int printStatsKey = 2;
+
+
+// The manipulator is responsible for updating a Viewer's camera. Its
+// event handling method is also a convenient place to run the FG idle
+// and draw handlers.
+
+FGEventHandler::FGEventHandler() :
+    idleHandler(0),
+    keyHandler(0),
+    mouseClickHandler(0),
+    mouseMotionHandler(0),
+    statsHandler(new FGStatsHandler),
+    statsEvent(new osgGA::GUIEventAdapter),
+    statsType(osgViewer::StatsHandler::NO_STATS),
+    currentModifiers(0),
+    resizable(true),
+    mouseWarped(false),
+    scrollButtonPressed(false),
+    changeStatsCameraRenderOrder(false)
+{
+    using namespace osgGA;
+    statsHandler->setKeyEventTogglesOnScreenStats(displayStatsKey);
+    statsHandler->setKeyEventPrintsOutStats(printStatsKey);
+    statsEvent->setEventType(GUIEventAdapter::KEYDOWN);
+
+    // OSG reports NumPad keycodes independent of the NumLock modifier.
+    // Both KP-4 and KP-Left are reported as KEY_KP_Left (0xff96), so we
+    // have to generate the locked keys ourselves.
+    numlockKeyMap[GUIEventAdapter::KEY_KP_Insert]  = '0';
+    numlockKeyMap[GUIEventAdapter::KEY_KP_End] = '1';
+    numlockKeyMap[GUIEventAdapter::KEY_KP_Down] = '2';
+    numlockKeyMap[GUIEventAdapter::KEY_KP_Page_Down] = '3';
+    numlockKeyMap[GUIEventAdapter::KEY_KP_Left] = '4';
+    numlockKeyMap[GUIEventAdapter::KEY_KP_Begin] = '5';
+    numlockKeyMap[GUIEventAdapter::KEY_KP_Right] = '6';
+    numlockKeyMap[GUIEventAdapter::KEY_KP_Home] = '7';
+    numlockKeyMap[GUIEventAdapter::KEY_KP_Up] = '8';
+    numlockKeyMap[GUIEventAdapter::KEY_KP_Page_Up] = '9';
+    numlockKeyMap[GUIEventAdapter::KEY_KP_Delete] = '.';
+
+    // mapping when NumLock is off
+    noNumlockKeyMap[GUIEventAdapter::KEY_KP_Insert]     = PU_KEY_INSERT;
+    noNumlockKeyMap[GUIEventAdapter::KEY_KP_End]        = PU_KEY_END;
+    noNumlockKeyMap[GUIEventAdapter::KEY_KP_Down]       = PU_KEY_DOWN;
+    noNumlockKeyMap[GUIEventAdapter::KEY_KP_Page_Down]  = PU_KEY_PAGE_DOWN;
+    noNumlockKeyMap[GUIEventAdapter::KEY_KP_Left]       = PU_KEY_LEFT;
+    noNumlockKeyMap[GUIEventAdapter::KEY_KP_Begin]      = '5';
+    noNumlockKeyMap[GUIEventAdapter::KEY_KP_Right]      = PU_KEY_RIGHT;
+    noNumlockKeyMap[GUIEventAdapter::KEY_KP_Home]       = PU_KEY_HOME;
+    noNumlockKeyMap[GUIEventAdapter::KEY_KP_Up]         = PU_KEY_UP;
+    noNumlockKeyMap[GUIEventAdapter::KEY_KP_Page_Up]    = PU_KEY_PAGE_UP;
+    noNumlockKeyMap[GUIEventAdapter::KEY_KP_Delete]     = 127;
+
+    for (int i = 0; i < 128; i++)
+        release_keys[i] = i;
+}
+
+namespace
+{
+// Translate OSG modifier mask to FG modifier mask.
+int osgToFGModifiers(int modifiers)
+{
+    int result = 0;
+    if (modifiers & osgGA::GUIEventAdapter::MODKEY_SHIFT)
+        result |= KEYMOD_SHIFT;
+
+    if (modifiers & osgGA::GUIEventAdapter::MODKEY_CTRL)
+        result |= KEYMOD_CTRL;
+
+    if (modifiers & osgGA::GUIEventAdapter::MODKEY_ALT)
+        result |= KEYMOD_ALT;
+
+    if (modifiers & osgGA::GUIEventAdapter::MODKEY_META)
+        result |= KEYMOD_META;
+
+    if (modifiers & osgGA::GUIEventAdapter::MODKEY_SUPER)
+        result |= KEYMOD_SUPER;
+
+    if (modifiers & osgGA::GUIEventAdapter::MODKEY_HYPER)
+        result |= KEYMOD_HYPER;
+    return result;
+}
+}
+
+#if 0
+void FGEventHandler::init(const osgGA::GUIEventAdapter& ea,
+                          osgGA::GUIActionAdapter& us)
+{
+    currentModifiers = osgToFGModifiers(ea.getModKeyMask());
+    (void)handle(ea, us);
+}
+#endif
+
+// Calculate event coordinates in the viewport of the GUI camera, if
+// possible. Otherwise return false and (-1, -1).
+namespace
+{
+bool
+eventToViewport(const osgGA::GUIEventAdapter& ea, osgGA::GUIActionAdapter& us,
+                int& x, int& y)
+{
+    x = -1;
+    y = -1;
+
+    const osg::GraphicsContext* eventGC = ea.getGraphicsContext();
+    const osg::GraphicsContext::Traits* traits = eventGC->getTraits();
+    osg::Camera* guiCamera = getGUICamera(CameraGroup::getDefault());
+    if (!guiCamera)
+        return false;
+    osg::Viewport* vport = guiCamera->getViewport();
+    if (!vport)
+        return false;
+    
+    // Scale x, y to the dimensions of the window
+    double wx = (((ea.getX() - ea.getXmin()) / (ea.getXmax() - ea.getXmin()))
+                 * (float)traits->width);
+    double wy = (((ea.getY() - ea.getYmin()) / (ea.getYmax() - ea.getYmin()))
+                 * (float)traits->height);
+    if (vport->x() <= wx && wx <= vport->x() + vport->width()
+        && vport->y() <= wy && wy <= vport->y() + vport->height()) {
+        // Finally, into viewport coordinates. Change y to "increasing
+        // downwards".
+        x = wx - vport->x();
+        y = vport->height() - (wy - vport->y());
+        return true;
+    } else {
+        return false;
+    }
+}
+}
+
+bool FGEventHandler::handle(const osgGA::GUIEventAdapter& ea,
+                            osgGA::GUIActionAdapter& us)
+{
+    int x = 0;
+    int y = 0;
+
+    switch (ea.getEventType()) {
+    case osgGA::GUIEventAdapter::FRAME:
+        mouseWarped = false;
+        handleStats(us);
+        return true;
+    case osgGA::GUIEventAdapter::KEYDOWN:
+    case osgGA::GUIEventAdapter::KEYUP:
+    {
+        int key, modmask;
+        handleKey(ea, key, modmask);
+        eventToViewport(ea, us, x, y);
+        if (keyHandler)
+            (*keyHandler)(key, modmask, x, y);
+        return true;
+    }
+    case osgGA::GUIEventAdapter::PUSH:
+    case osgGA::GUIEventAdapter::RELEASE:
+    {
+        bool mainWindow = eventToViewport(ea, us, x, y);
+        int button = 0;
+        switch (ea.getButton()) {
+        case osgGA::GUIEventAdapter::LEFT_MOUSE_BUTTON:
+            button = 0;
+            break;
+        case osgGA::GUIEventAdapter::MIDDLE_MOUSE_BUTTON:
+            button = 1;
+            break;
+        case osgGA::GUIEventAdapter::RIGHT_MOUSE_BUTTON:
+            button = 2;
+            break;
+        }
+        if (mouseClickHandler)
+            (*mouseClickHandler)(button,
+                                 (ea.getEventType()
+                                  == osgGA::GUIEventAdapter::RELEASE), x, y, mainWindow, &ea);
+        return true;
+    }
+    case osgGA::GUIEventAdapter::SCROLL:
+    {
+        bool mainWindow = eventToViewport(ea, us, x, y);
+#ifdef X_DOUBLE_SCROLL_BUG
+        scrollButtonPressed = !scrollButtonPressed;
+        if (!scrollButtonPressed) // Drop the button release event
+            return true;
+#endif
+        int button;
+        if (ea.getScrollingMotion() == osgGA::GUIEventAdapter::SCROLL_2D) {
+            if (ea.getScrollingDeltaY() > 0)
+                button = 3;
+            else if (ea.getScrollingDeltaY() < 0)
+                button = 4;
+            else
+                button = -1;
+        } else if (ea.getScrollingMotion() == osgGA::GUIEventAdapter::SCROLL_UP)
+            button = 3;
+        else
+            button = 4;
+        if (mouseClickHandler && button != -1) {
+            (*mouseClickHandler)(button, 0, x, y, mainWindow, &ea);
+            (*mouseClickHandler)(button, 1, x, y, mainWindow, &ea);
+        }
+        return true;
+    }
+    case osgGA::GUIEventAdapter::MOVE:
+    case osgGA::GUIEventAdapter::DRAG:
+        // If we warped the mouse, then disregard all pointer motion
+        // events for this frame. We really want to flush the event
+        // queue of mouse events, but don't have the ability to do
+        // that with osgViewer.
+        if (mouseWarped)
+            return true;
+        if (eventToViewport(ea, us, x, y) && mouseMotionHandler)
+            (*mouseMotionHandler)(x, y);
+        return true;
+    case osgGA::GUIEventAdapter::RESIZE:
+        SG_LOG(SG_VIEW, SG_DEBUG, "FGEventHandler::handle: RESIZE event " << ea.getWindowHeight() << " x " << ea.getWindowWidth() << ", resizable: " << resizable);
+        CameraGroup::getDefault()->resized();
+        if (resizable)
+          globals->get_renderer()->resize(ea.getWindowWidth(), ea.getWindowHeight());
+        statsHandler->handle(ea, us);
+      #ifdef SG_MAC
+        // work around OSG Cocoa-Viewer issue with resize event handling,
+        // where resize events are queued up, then dispatched in a batch, with
+        // no interveningd drawing calls.
+        puCleanUpJunk();
+      #endif
+        return true;
+     case osgGA::GUIEventAdapter::CLOSE_WINDOW:
+    case osgGA::GUIEventAdapter::QUIT_APPLICATION:
+        fgOSExit(0);
+        return true;
+    default:
+        return false;
+    }
+}
+
+void FGEventHandler::handleKey(const osgGA::GUIEventAdapter& ea, int& key,
+                               int& modifiers)
+{
+    using namespace osgGA;
+    key = ea.getKey();
+    // XXX Probably other translations are needed too.
+    switch (key) {
+    case GUIEventAdapter::KEY_Escape:      key = 0x1b; break;
+    case GUIEventAdapter::KEY_Return:      key = '\n'; break;
+    case GUIEventAdapter::KEY_BackSpace:   key = '\b'; break;
+    case GUIEventAdapter::KEY_Delete:      key = 0x7f; break;
+    case GUIEventAdapter::KEY_Tab:         key = '\t'; break;
+    case GUIEventAdapter::KEY_Left:        key = PU_KEY_LEFT;      break;
+    case GUIEventAdapter::KEY_Up:          key = PU_KEY_UP;        break;
+    case GUIEventAdapter::KEY_Right:       key = PU_KEY_RIGHT;     break;
+    case GUIEventAdapter::KEY_Down:        key = PU_KEY_DOWN;      break;
+    case GUIEventAdapter::KEY_Page_Up:     key = PU_KEY_PAGE_UP;   break;
+    case GUIEventAdapter::KEY_Page_Down:   key = PU_KEY_PAGE_DOWN; break;
+    case GUIEventAdapter::KEY_Home:        key = PU_KEY_HOME;      break;
+    case GUIEventAdapter::KEY_End:         key = PU_KEY_END;       break;
+    case GUIEventAdapter::KEY_Insert:      key = PU_KEY_INSERT;    break;
+    case GUIEventAdapter::KEY_F1:          key = PU_KEY_F1;        break;
+    case GUIEventAdapter::KEY_F2:          key = PU_KEY_F2;        break;
+    case GUIEventAdapter::KEY_F3:          key = PU_KEY_F3;        break;
+    case GUIEventAdapter::KEY_F4:          key = PU_KEY_F4;        break;
+    case GUIEventAdapter::KEY_F5:          key = PU_KEY_F5;        break;
+    case GUIEventAdapter::KEY_F6:          key = PU_KEY_F6;        break;
+    case GUIEventAdapter::KEY_F7:          key = PU_KEY_F7;        break;
+    case GUIEventAdapter::KEY_F8:          key = PU_KEY_F8;        break;
+    case GUIEventAdapter::KEY_F9:          key = PU_KEY_F9;        break;
+    case GUIEventAdapter::KEY_F10:         key = PU_KEY_F10;       break;
+    case GUIEventAdapter::KEY_F11:         key = PU_KEY_F11;       break;
+    case GUIEventAdapter::KEY_F12:         key = PU_KEY_F12;       break;
+    case GUIEventAdapter::KEY_KP_Enter:    key = '\r'; break;
+    case GUIEventAdapter::KEY_KP_Add:      key = '+';  break;
+    case GUIEventAdapter::KEY_KP_Divide:   key = '/';  break;
+    case GUIEventAdapter::KEY_KP_Multiply: key = '*';  break;
+    case GUIEventAdapter::KEY_KP_Subtract: key = '-';  break;
+    }
+    osgGA::GUIEventAdapter::EventType eventType = ea.getEventType();
+
+#ifdef __APPLE__
+    // Num Lock is always true on Mac
+    std::map<int, int>::iterator numPadIter = numlockKeyMap.find(key);
+    if (numPadIter != numlockKeyMap.end()) {
+        key = numPadIter->second;
+    }
+#else
+    if (ea.getModKeyMask() & osgGA::GUIEventAdapter::MODKEY_NUM_LOCK)
+    {
+        // NumLock on: map to numeric keys
+        std::map<int, int>::iterator numPadIter = numlockKeyMap.find(key);
+        if (numPadIter != numlockKeyMap.end()) {
+            key = numPadIter->second;
+        }
+    }
+    else
+    {
+        // NumLock off: map to PU arrow keys
+        std::map<int, int>::iterator numPadIter = noNumlockKeyMap.find(key);
+        if (numPadIter != noNumlockKeyMap.end()) {
+            key = numPadIter->second;
+        }
+    }
+#endif
+
+    modifiers = osgToFGModifiers(ea.getModKeyMask());
+    currentModifiers = modifiers;
+    if (eventType == osgGA::GUIEventAdapter::KEYUP)
+        modifiers |= KEYMOD_RELEASED;
+
+    // Release the letter key, for which the key press was reported. This
+    // is to deal with Ctrl-press -> a-press -> Ctrl-release -> a-release
+    // correctly.
+    if (key >= 0 && key < 128) {
+        if (modifiers & KEYMOD_RELEASED) {
+            key = release_keys[key];
+        } else {
+            release_keys[key] = key;
+            if (key >= 1 && key <= 26) {
+                release_keys[key + '@'] = key;
+                release_keys[key + '`'] = key;
+            } else if (key >= 'A' && key <= 'Z') {
+                release_keys[key - '@'] = key;
+                release_keys[tolower(key)] = key;
+            } else if (key >= 'a' && key <= 'z') {
+                release_keys[key - '`'] = key;
+                release_keys[toupper(key)] = key;
+            }
+        }
+    }
+}
+
+void FGEventHandler::handleStats(osgGA::GUIActionAdapter& us)
+{
+    static SGPropertyNode_ptr display = fgGetNode("/sim/rendering/on-screen-statistics", true);
+    static SGPropertyNode_ptr print = fgGetNode("/sim/rendering/print-statistics", true);
+
+    int type = display->getIntValue() % osgViewer::StatsHandler::LAST;
+    if (type != statsType) {
+        statsEvent->setKey(displayStatsKey);
+        do {
+            statsType = (statsType + 1) % osgViewer::StatsHandler::LAST;
+            statsHandler->handle(*statsEvent, us);
+            if (changeStatsCameraRenderOrder) {
+                statsHandler->getCamera()->setRenderOrder(osg::Camera::POST_RENDER, 99999);
+                changeStatsCameraRenderOrder = false;
+            }
+        } while (statsType != type);
+
+        display->setIntValue(statsType);
+    }
+
+    if (print->getBoolValue()) {
+        statsEvent->setKey(printStatsKey);
+        statsHandler->handle(*statsEvent, us);
+        print->setBoolValue(false);
+    }
+}
+
+void eventToWindowCoords(const osgGA::GUIEventAdapter* ea,
+                         double& x, double& y)
+{
+    using namespace osg;
+    const GraphicsContext* gc = ea->getGraphicsContext();
+    const GraphicsContext::Traits* traits = gc->getTraits() ;
+    // Scale x, y to the dimensions of the window
+    x = (((ea->getX() - ea->getXmin()) / (ea->getXmax() - ea->getXmin()))
+         * (double)traits->width);
+    y = (((ea->getY() - ea->getYmin()) / (ea->getYmax() - ea->getYmin()))
+         * (double)traits->height);
+    if (ea->getMouseYOrientation() == osgGA::GUIEventAdapter::Y_INCREASING_DOWNWARDS)
+        y = (double)traits->height - y;
+}
+
+void eventToWindowCoordsYDown(const osgGA::GUIEventAdapter* ea,
+                              double& x, double& y)
+{
+    using namespace osg;
+    const GraphicsContext* gc = ea->getGraphicsContext();
+    const GraphicsContext::Traits* traits = gc->getTraits() ;
+    // Scale x, y to the dimensions of the window
+    x = (((ea->getX() - ea->getXmin()) / (ea->getXmax() - ea->getXmin()))
+         * (double)traits->width);
+    y = (((ea->getY() - ea->getYmin()) / (ea->getYmax() - ea->getYmin()))
+         * (double)traits->height);
+    if (ea->getMouseYOrientation() == osgGA::GUIEventAdapter::Y_INCREASING_UPWARDS)
+        y = (double)traits->height - y;
+}
+}
diff --git a/src/Viewer/FGEventHandler.hxx b/src/Viewer/FGEventHandler.hxx
new file mode 100644 (file)
index 0000000..2e38c41
--- /dev/null
@@ -0,0 +1,129 @@
+#ifndef FGEVENTHANDLER_H
+#define FGEVENTHANDLER_H 1
+
+#include <map>
+#include <osg/Quat>
+#include <osgGA/GUIEventHandler>
+#include <osgViewer/ViewerEventHandlers>
+#include <simgear/structure/OSGVersion.hxx>
+
+#include <Main/fg_os.hxx>
+
+namespace flightgear
+{
+    class FGStatsHandler : public osgViewer::StatsHandler
+    {
+        public:
+            FGStatsHandler()
+            {
+#if (SG_OSG_VERSION >= 30000)
+                // Adjust font type/size for >=OSG3.
+                // OSG defaults aren't working/available for FG.
+                _font = "Fonts/helvetica_medium.txf";
+                _characterSize = 12.0f;
+#endif
+            }
+    };
+
+class FGEventHandler : public osgGA::GUIEventHandler {
+public:
+    FGEventHandler();
+    
+    virtual ~FGEventHandler() {}
+    
+    virtual const char* className() const {return "FGEventHandler"; }
+#if 0
+    virtual void init(const osgGA::GUIEventAdapter& ea,
+                     osgGA::GUIActionAdapter& us);
+#endif
+    virtual bool handle(const osgGA::GUIEventAdapter& ea,
+                       osgGA::GUIActionAdapter& us);
+
+    void setIdleHandler(fgIdleHandler idleHandler)
+       {
+           this->idleHandler = idleHandler;
+       }
+
+    fgIdleHandler getIdleHandler() const
+       {
+           return idleHandler;
+       }
+
+    void setKeyHandler(fgKeyHandler keyHandler)
+       {
+           this->keyHandler = keyHandler;
+       }
+
+    fgKeyHandler getKeyHandler() const
+       {
+           return keyHandler;
+       }
+
+    void setMouseClickHandler(fgMouseClickHandler mouseClickHandler)
+       {
+           this->mouseClickHandler = mouseClickHandler;
+       }
+    
+    fgMouseClickHandler getMouseClickHandler()
+       {
+           return mouseClickHandler;
+       }
+
+    void setMouseMotionHandler(fgMouseMotionHandler mouseMotionHandler)
+       {
+           this->mouseMotionHandler = mouseMotionHandler;
+       }
+    
+    fgMouseMotionHandler getMouseMotionHandler()
+       {
+           return mouseMotionHandler;
+       }
+
+    void setChangeStatsCameraRenderOrder(bool c)
+    {
+        changeStatsCameraRenderOrder = c;
+    }
+
+    int getCurrentModifiers() const
+       {
+           return currentModifiers;
+       }
+
+    void setMouseWarped()
+       {
+           mouseWarped = true;
+       }
+
+    /** Whether or not resizing is supported. It might not be when
+     * using multiple displays.
+     */
+    bool getResizable() { return resizable; }
+    void setResizable(bool _resizable) { resizable = _resizable; }
+
+protected:
+    osg::ref_ptr<osg::Node> _node;
+    fgIdleHandler idleHandler;
+    fgKeyHandler keyHandler;
+    fgMouseClickHandler mouseClickHandler;
+    fgMouseMotionHandler mouseMotionHandler;
+    osg::ref_ptr<FGStatsHandler> statsHandler;
+    osg::ref_ptr<osgGA::GUIEventAdapter> statsEvent;
+    int statsType;
+    int currentModifiers;
+    std::map<int, int> numlockKeyMap;
+    std::map<int, int> noNumlockKeyMap;
+    void handleKey(const osgGA::GUIEventAdapter& ea, int& key, int& modifiers);
+    bool resizable;
+    bool mouseWarped;
+    // workaround for osgViewer double scroll events
+    bool scrollButtonPressed;
+    int release_keys[128];
+    void handleStats(osgGA::GUIActionAdapter& us);
+    bool changeStatsCameraRenderOrder;
+};
+
+void eventToWindowCoords(const osgGA::GUIEventAdapter* ea, double& x, double& y);
+void eventToWindowCoordsYDown(const osgGA::GUIEventAdapter* ea,
+                              double& x, double& y);
+}
+#endif
diff --git a/src/Viewer/WindowBuilder.cxx b/src/Viewer/WindowBuilder.cxx
new file mode 100644 (file)
index 0000000..f48ea0e
--- /dev/null
@@ -0,0 +1,258 @@
+// Copyright (C) 2008  Tim Moore
+//
+// This program is free software; you can redistribute it and/or
+// modify it under the terms of the GNU General Public License as
+// published by the Free Software Foundation; either version 2 of the
+// License, or (at your option) any later version.
+//
+// This program is distributed in the hope that it will be useful, but
+// WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+// General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License
+// along with this program; if not, write to the Free Software
+// Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
+
+#ifdef HAVE_CONFIG_H
+#  include "config.h"
+#endif
+
+#include "WindowBuilder.hxx"
+
+#include "WindowSystemAdapter.hxx"
+#include <Main/fg_props.hxx>
+
+#include <sstream>
+
+using namespace std;
+using namespace osg;
+
+namespace flightgear
+{
+string makeName(const string& prefix, int num)
+{
+    stringstream stream;
+    stream << prefix << num;
+    return stream.str();
+}
+
+ref_ptr<WindowBuilder> WindowBuilder::windowBuilder;
+
+const string WindowBuilder::defaultWindowName("FlightGear");
+
+void WindowBuilder::initWindowBuilder(bool stencil)
+{
+    windowBuilder = new WindowBuilder(stencil);
+}
+
+WindowBuilder::WindowBuilder(bool stencil) : defaultCounter(0)
+{
+    defaultTraits = makeDefaultTraits(stencil);
+}
+
+GraphicsContext::Traits*
+WindowBuilder::makeDefaultTraits(bool stencil)
+{
+    GraphicsContext::WindowingSystemInterface* wsi
+        = osg::GraphicsContext::getWindowingSystemInterface();
+    GraphicsContext::Traits* traits = new osg::GraphicsContext::Traits;
+
+    traits->readDISPLAY();
+    if (traits->displayNum < 0)
+        traits->displayNum = 0;
+    if (traits->screenNum < 0)
+        traits->screenNum = 0;
+
+    int bpp = fgGetInt("/sim/rendering/bits-per-pixel");
+    bool alpha = fgGetBool("/sim/rendering/clouds3d-enable");
+    int cbits = (bpp <= 16) ?  5 :  8;
+    int zbits = (bpp <= 16) ? 16 : 24;
+    traits->red = traits->green = traits->blue = cbits;
+    traits->depth = zbits;
+    if (alpha)
+        traits->alpha = 8;
+
+    if (stencil)
+        traits->stencil = 8;
+
+    unsigned screenwidth = 0;
+    unsigned screenheight = 0;
+    wsi->getScreenResolution(*traits, screenwidth, screenheight);
+
+    traits->doubleBuffer = true;
+    traits->mipMapGeneration = true;
+    traits->windowName = "FlightGear";
+    // XXX should check per window too.
+    traits->sampleBuffers = fgGetInt("/sim/rendering/multi-sample-buffers", traits->sampleBuffers);
+    traits->samples = fgGetInt("/sim/rendering/multi-samples", traits->samples);
+    traits->vsync = fgGetBool("/sim/rendering/vsync-enable", traits->vsync);
+    traits->windowDecoration = !fgGetBool("/sim/startup/fullscreen");
+
+    if (!traits->windowDecoration) {
+        // fullscreen
+        traits->supportsResize = false;
+        traits->width = screenwidth;
+        traits->height = screenheight;
+        SG_LOG(SG_VIEW,SG_DEBUG,"Using full screen size for window: " << screenwidth << " x " << screenheight);
+    } else {
+        // window
+        int w = fgGetInt("/sim/startup/xsize");
+        int h = fgGetInt("/sim/startup/ysize");
+        traits->supportsResize = true;
+        traits->width = w;
+        traits->height = h;
+        if ((w>0)&&(h>0))
+        {
+            traits->x = ((unsigned)w>screenwidth) ? 0 : (screenwidth-w)/3;
+            traits->y = ((unsigned)h>screenheight) ? 0 : (screenheight-h)/3;
+        }
+        SG_LOG(SG_VIEW,SG_DEBUG,"Using initial window size: " << w << " x " << h);
+    }
+    return traits;
+}
+}
+
+namespace
+{
+// Helper functions that set a value based on a property if it exists,
+// returning 1 if the value was set.
+
+inline int setFromProperty(string& place, const SGPropertyNode* node,
+                            const char* name)
+{
+    const SGPropertyNode* valNode = node->getNode(name);
+    if (valNode) {
+        place = valNode->getStringValue();
+        return 1;
+    }
+    return 0;
+}
+
+inline int setFromProperty(int& place, const SGPropertyNode* node,
+                            const char* name)
+{
+    const SGPropertyNode* valNode = node->getNode(name);
+    if (valNode) {
+        place = valNode->getIntValue();
+        return 1;
+    }
+    return 0;
+}
+
+inline int setFromProperty(bool& place, const SGPropertyNode* node,
+                            const char* name)
+{
+    const SGPropertyNode* valNode = node->getNode(name);
+    if (valNode) {
+        place = valNode->getBoolValue();
+        return 1;
+    }
+    return 0;
+}
+}
+
+namespace flightgear
+{
+GraphicsWindow* WindowBuilder::buildWindow(const SGPropertyNode* winNode)
+{
+    GraphicsContext::WindowingSystemInterface* wsi
+        = osg::GraphicsContext::getWindowingSystemInterface();
+    WindowSystemAdapter* wsa = WindowSystemAdapter::getWSA();
+    string windowName;
+    if (winNode->hasChild("window-name"))
+        windowName = winNode->getStringValue("window-name");
+    else if (winNode->hasChild("name"))
+        windowName = winNode->getStringValue("name");
+    GraphicsWindow* result = 0;
+    if (!windowName.empty()) {
+        result = wsa->findWindow(windowName);
+        if (result)
+            return result;
+    }
+    GraphicsContext::Traits* traits
+        = new GraphicsContext::Traits(*defaultTraits);
+    int traitsSet = setFromProperty(traits->hostName, winNode, "host-name");
+    traitsSet |= setFromProperty(traits->displayNum, winNode, "display");
+    traitsSet |= setFromProperty(traits->screenNum, winNode, "screen");
+
+    const SGPropertyNode* fullscreenNode = winNode->getNode("fullscreen");
+
+    if (fullscreenNode && fullscreenNode->getBoolValue()) {
+        // fullscreen mode
+        unsigned width = 0;
+        unsigned height = 0;
+        wsi->getScreenResolution(*traits, width, height);
+        traits->windowDecoration = false;
+        traits->width = width;
+        traits->height = height;
+        traits->supportsResize = false;
+        traits->x = 0;
+        traits->y = 0;
+        traitsSet = 1;
+    } else {
+        int resizable = 0;
+        if (fullscreenNode && !fullscreenNode->getBoolValue())
+        {
+            traits->windowDecoration = true;
+            resizable = 1;
+        }
+        resizable |= setFromProperty(traits->windowDecoration, winNode,
+                                     "decoration");
+        resizable |= setFromProperty(traits->width, winNode, "width");
+        resizable |= setFromProperty(traits->height, winNode, "height");
+        if (resizable) {
+            traits->supportsResize = true;
+            traitsSet = 1;
+        }
+        // Otherwise use default values.
+    }
+    traitsSet |= setFromProperty(traits->x, winNode, "x");
+    traitsSet |= setFromProperty(traits->y, winNode, "y");
+    if (!windowName.empty() && windowName != traits->windowName) {
+        traits->windowName = windowName;
+        traitsSet = 1;
+    } else if (traitsSet) {
+        traits->windowName = makeName("FlightGear", defaultCounter++);
+    }
+    bool drawGUI = false;
+    traitsSet |= setFromProperty(drawGUI, winNode, "gui");
+    if (traitsSet) {
+        GraphicsContext* gc = GraphicsContext::createGraphicsContext(traits);
+        if (gc) {
+            GraphicsWindow* window = WindowSystemAdapter::getWSA()
+                ->registerWindow(gc, traits->windowName);
+            if (drawGUI)
+                window->flags |= GraphicsWindow::GUI;
+            return window;
+        } else {
+            return 0;
+        }
+    } else {
+        // XXX What if the window has no traits, but does have a name?
+        // We should create a "default window" registered with that name.
+        return getDefaultWindow();
+    }
+}
+
+GraphicsWindow* WindowBuilder::getDefaultWindow()
+{
+    GraphicsWindow* defaultWindow
+        = WindowSystemAdapter::getWSA()->findWindow(defaultWindowName);
+    if (defaultWindow)
+        return defaultWindow;
+    GraphicsContext::Traits* traits
+        = new GraphicsContext::Traits(*defaultTraits);
+    traits->windowName = "FlightGear";
+    
+    GraphicsContext* gc = GraphicsContext::createGraphicsContext(traits);
+    if (gc) {
+        defaultWindow = WindowSystemAdapter::getWSA()
+            ->registerWindow(gc, defaultWindowName);
+        return defaultWindow;
+    } else {
+        SG_LOG(SG_VIEW, SG_ALERT, "getDefaultWindow: failed to create GraphicsContext");
+        return 0;
+    }
+}
+}
diff --git a/src/Viewer/WindowBuilder.hxx b/src/Viewer/WindowBuilder.hxx
new file mode 100644 (file)
index 0000000..92e158b
--- /dev/null
@@ -0,0 +1,75 @@
+// Copyright (C) 2008  Tim Moore
+//
+// This program is free software; you can redistribute it and/or
+// modify it under the terms of the GNU General Public License as
+// published by the Free Software Foundation; either version 2 of the
+// License, or (at your option) any later version.
+//
+// This program is distributed in the hope that it will be useful, but
+// WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+// General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License
+// along with this program; if not, write to the Free Software
+// Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
+
+#ifndef FLIGHTGEAR_WINDOWBUILDER_HXX
+#define FLIGHTGEAR_WINDOWBUILDER_HXX 1
+
+#include <osg/ref_ptr>
+#include <osg/Referenced>
+#include <osg/GraphicsContext>
+
+#include <string>
+
+class SGPropertyNode;
+
+namespace flightgear
+{
+class GraphicsWindow;
+/** Singleton Builder class for creating a GraphicsWindow from property
+ * nodes. This involves initializing an osg::GraphicsContext::Traits
+ * structure from the property node values and creating an
+ * osgViewer::GraphicsWindow.
+ */
+class WindowBuilder : public osg::Referenced
+{
+public:
+    /** Initialize the singleton window builder.
+     * @param stencil whether windows should allocate stencil planes
+     */
+    static void initWindowBuilder(bool stencil);
+    /** Get the singleton window builder
+     */
+    static WindowBuilder* getWindowBuilder() { return windowBuilder.get(); }
+    /** Create a window from its property node description.
+     * @param winNode The window's root property node
+     * @return a graphics window.
+     */
+    GraphicsWindow* buildWindow(const SGPropertyNode* winNode);
+    /** Get a window whose properties come from FlightGear's
+     * command line arguments and their defaults. The window is opened
+     * if it has not been already.
+     * @return the default graphics window
+     */
+    GraphicsWindow* getDefaultWindow();
+    /** Get the name used to look up the default window.
+     */
+    const std::string& getDefaultWindowName() { return defaultWindowName; }
+protected:
+    WindowBuilder(bool stencil);
+    static osg::GraphicsContext::Traits* makeDefaultTraits(bool stencil);
+    osg::ref_ptr<osg::GraphicsContext::Traits> defaultTraits;
+    int defaultCounter;
+    static osg::ref_ptr<WindowBuilder> windowBuilder;
+    static const std::string defaultWindowName;
+};
+
+/** Silly function for making the default window and camera
+ * names. This concatenates a string with in integer.
+ */
+std::string makeName(const std::string& prefix, int num);
+
+}
+#endif
diff --git a/src/Viewer/WindowSystemAdapter.cxx b/src/Viewer/WindowSystemAdapter.cxx
new file mode 100644 (file)
index 0000000..9da3400
--- /dev/null
@@ -0,0 +1,97 @@
+// Copyright (C) 2008 Tim Moore
+//
+// This program is free software; you can redistribute it and/or
+// modify it under the terms of the GNU General Public License as
+// published by the Free Software Foundation; either version 2 of the
+// License, or (at your option) any later version.
+//
+// This program is distributed in the hope that it will be useful, but
+// WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+// General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License
+// along with this program; if not, write to the Free Software
+// Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
+#ifdef HAVE_CONFIG_H
+#  include <config.h>
+#endif
+
+#include <plib/pu.h>
+
+#include<algorithm>
+#include <functional>
+
+#include "CameraGroup.hxx"
+#include "WindowSystemAdapter.hxx"
+
+#include <osg/Camera>
+#include <osg/GraphicsContext>
+#include <osg/Viewport>
+
+using namespace osg;
+using namespace std;
+
+namespace flightgear
+{
+ref_ptr<WindowSystemAdapter> WindowSystemAdapter::_wsa;
+
+void GraphicsContextOperation::operator()(GraphicsContext* gc)
+{
+    run(gc);
+    ++done;
+}
+
+WindowSystemAdapter::WindowSystemAdapter() :
+    _nextWindowID(0), _isPuInitialized(false)
+{
+}
+
+GraphicsWindow*
+WindowSystemAdapter::registerWindow(GraphicsContext* gc,
+                                    const string& windowName)
+{
+    GraphicsWindow* window = new GraphicsWindow(gc, windowName,
+                                                _nextWindowID++);
+    windows.push_back(window);
+    return window;
+}
+
+// The pu getWindow callback is supposed to return a window ID that
+// would allow drawing a GUI on different windows. All that stuff is
+// broken in multi-threaded OSG, and we only have one GUI "window"
+// anyway, so just return a constant. 
+int WindowSystemAdapter::puGetWindow()
+{
+    return 1;
+}
+
+void WindowSystemAdapter::puGetWindowSize(int* width, int* height)
+{
+    *width = 0;
+    *height = 0;
+    Camera* camera = getGUICamera(CameraGroup::getDefault());
+    if (!camera)
+        return;
+    Viewport* vport = camera->getViewport();
+    *width = (int)vport->width();
+    *height = (int)vport->height();
+}
+
+void WindowSystemAdapter::puInitialize()
+{
+    puSetWindowFuncs(puGetWindow, 0, puGetWindowSize, 0);
+    puRealInit();
+}
+
+GraphicsWindow* WindowSystemAdapter::findWindow(const string& name)
+{
+    for (WindowVector::iterator iter = windows.begin(), e = windows.end();
+         iter != e;
+         ++iter) {
+        if ((*iter)->name == name)
+            return iter->get();
+    }
+    return 0;
+}
+}
diff --git a/src/Viewer/WindowSystemAdapter.hxx b/src/Viewer/WindowSystemAdapter.hxx
new file mode 100644 (file)
index 0000000..b359f8e
--- /dev/null
@@ -0,0 +1,165 @@
+// Copyright (C) 2008 Tim Moore
+//
+// This program is free software; you can redistribute it and/or
+// modify it under the terms of the GNU General Public License as
+// published by the Free Software Foundation; either version 2 of the
+// License, or (at your option) any later version.
+//
+// This program is distributed in the hope that it will be useful, but
+// WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+// General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License
+// along with this program; if not, write to the Free Software
+// Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
+
+#ifndef FLIGHTGEAR_WINDOWSYSTEMADAPTER_HXX
+#define FLIGHTGEAR_WINDOWSYSTEMADAPTER_HXX 1
+
+#include <functional>
+#include <string>
+
+#include <osg/Referenced>
+#include <osg/Camera>
+#include <osg/GraphicsThread>
+#include <osg/ref_ptr>
+
+#include <simgear/structure/SGAtomic.hxx>
+
+namespace osg
+{
+class GraphicsContext;
+}
+
+// Flexible window support
+namespace flightgear
+{
+/** A window with a graphics context and an integer ID
+ */
+class GraphicsWindow : public osg::Referenced
+{
+public:
+    GraphicsWindow(osg::GraphicsContext* gc_, const std::string& name_,
+                   int id_, unsigned flags_ = 0) :
+        gc(gc_), name(name_), id(id_), flags(flags_)
+    {
+    }
+    /** The OSG graphics context for this window.
+     */
+    osg::ref_ptr<osg::GraphicsContext> gc;
+    /** The window's internal name.
+     */
+    std::string name;
+    /** A unique ID for the window.
+     */
+    int id;
+    enum Flags {
+        GUI = 1 /**< The GUI (and 2D cockpit) will be drawn on this window. */
+    };
+    /** Flags for the window.
+     */
+    unsigned flags;
+};
+
+typedef std::vector<osg::ref_ptr<GraphicsWindow> >  WindowVector;
+
+/**
+ * An operation that is run once with a particular GraphicsContext
+ * current. It will probably be deferred and may run in a different
+ * thread.
+ */
+class GraphicsContextOperation : public osg::GraphicsOperation
+{
+public:
+    GraphicsContextOperation(const std::string& name) :
+        osg::GraphicsOperation(name, false)
+    {
+    }
+    /** Don't override this!
+     */
+    virtual void operator()(osg::GraphicsContext* gc);
+    /** The body of the operation.
+     */
+    virtual void run(osg::GraphicsContext* gc) = 0;
+    /** Test if the operation has completed.
+     * @return true if the run() method has finished.
+     */
+    bool isFinished() const { return done != 0; }
+private:
+    SGAtomic done;
+};
+
+/** Adapter from windows system / graphics context management API to
+ * functions used by flightgear. This papers over the difference
+ * between osgViewer::Viewer, which handles multiple windows, graphics
+ * threads, etc., and the embedded viewer used with GLUT and SDL.
+ */
+class WindowSystemAdapter : public osg::Referenced
+{
+public:
+    WindowSystemAdapter();
+    virtual ~WindowSystemAdapter() {}
+    /** Vector of all the registered windows.
+     */
+    WindowVector windows;
+    /** Register a window, assigning  it an ID.
+     * @param gc graphics context
+     * @param windowName internal name (not displayed)
+     * @return a graphics window
+     */
+    GraphicsWindow* registerWindow(osg::GraphicsContext* gc,
+                                   const std::string& windowName);
+    /** Initialize the plib pui interface library. This might happen
+     *in another thread and may be deferred.
+     */
+    virtual void puInitialize();
+    /** Find a window by name.
+     * @param name the window name
+     * @return the window or 0
+     */
+    GraphicsWindow* findWindow(const std::string& name);
+    /** Get the global WindowSystemAdapter
+     * @return the adapter
+     */
+    static WindowSystemAdapter* getWSA() { return _wsa.get(); }
+    /** Set the global adapter
+     * @param wsa the adapter
+     */
+    static void setWSA(WindowSystemAdapter* wsa) { _wsa = wsa; }
+protected:
+    int _nextWindowID;
+    osg::ref_ptr<GraphicsContextOperation> _puInitOp;
+    bool _isPuInitialized;
+    static osg::ref_ptr<WindowSystemAdapter> _wsa;
+    // Default callbacks for plib
+    static int puGetWindow();
+    static void puGetWindowSize(int* width, int* height);
+
+};
+
+/**
+ * Class for testing if flags are set in an object with a flags member.
+ */
+template<typename T>
+class FlagTester : public std::unary_function<osg::ref_ptr<T>, bool>
+{
+public:
+    /** Initialize with flags to test for.
+     * @param flags logical or of flags to test.
+     */
+    FlagTester(unsigned flags_) : flags(flags_) {}
+    /** test operator
+     * @param obj An object with a flags member
+     * @return true if flags member of obj contains any of the flags
+     * (bitwise and with flags is nonzero).
+     */
+    bool operator() (const osg::ref_ptr<T>& obj)
+    {
+        return (obj->flags & flags) != 0;
+    }
+    unsigned flags;
+};
+
+}
+#endif
diff --git a/src/Viewer/fg_os_osgviewer.cxx b/src/Viewer/fg_os_osgviewer.cxx
new file mode 100644 (file)
index 0000000..3600a65
--- /dev/null
@@ -0,0 +1,376 @@
+// fg_os_osgviewer.cxx -- common functions for fg_os interface
+// implemented as an osgViewer
+//
+// Copyright (C) 2007  Tim Moore timoore@redhat.com
+// Copyright (C) 2007 Mathias Froehlich 
+//
+// This program is free software; you can redistribute it and/or
+// modify it under the terms of the GNU General Public License as
+// published by the Free Software Foundation; either version 2 of the
+// License, or (at your option) any later version.
+//
+// This program is distributed in the hope that it will be useful, but
+// WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+// General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License
+// along with this program; if not, write to the Free Software
+// Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
+
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+
+#include <algorithm>
+#include <iostream>
+#include <sstream>
+#include <string>
+
+#include <stdlib.h>
+
+#include <boost/foreach.hpp>
+
+#include <simgear/compiler.h>
+#include <simgear/structure/exception.hxx>
+#include <simgear/debug/logstream.hxx>
+#include <simgear/props/props_io.hxx>
+
+#include <osg/Camera>
+#include <osg/GraphicsContext>
+#include <osg/Group>
+#include <osg/Matrixd>
+#include <osg/Viewport>
+#include <osg/Version>
+#include <osg/View>
+#include <osgViewer/ViewerEventHandlers>
+#include <osgViewer/Viewer>
+#include <osgViewer/GraphicsWindow>
+
+#include <Scenery/scenery.hxx>
+#include <Main/fg_os.hxx>
+#include <Main/fg_props.hxx>
+#include <Main/util.hxx>
+#include <Main/globals.hxx>
+#include "renderer.hxx"
+#include "CameraGroup.hxx"
+#include "FGEventHandler.hxx"
+#include "WindowBuilder.hxx"
+#include "WindowSystemAdapter.hxx"
+
+// Static linking of OSG needs special macros
+#ifdef OSG_LIBRARY_STATIC
+#include <osgDB/Registry>
+USE_GRAPHICSWINDOW();
+// Image formats
+USE_OSGPLUGIN(bmp);
+USE_OSGPLUGIN(dds);
+USE_OSGPLUGIN(hdr);
+USE_OSGPLUGIN(pic);
+USE_OSGPLUGIN(pnm);
+USE_OSGPLUGIN(rgb);
+USE_OSGPLUGIN(tga);
+#ifdef OSG_JPEG_ENABLED
+  USE_OSGPLUGIN(jpeg);
+#endif
+#ifdef OSG_PNG_ENABLED
+  USE_OSGPLUGIN(png);
+#endif
+#ifdef OSG_TIFF_ENABLED
+  USE_OSGPLUGIN(tiff);
+#endif
+// Model formats
+USE_OSGPLUGIN(3ds);
+USE_OSGPLUGIN(ac);
+USE_OSGPLUGIN(ive);
+USE_OSGPLUGIN(osg);
+USE_OSGPLUGIN(txf);
+#endif
+
+// fg_os implementation using OpenSceneGraph's osgViewer::Viewer class
+// to create the graphics window and run the event/update/render loop.
+
+//
+// fg_os implementation
+//
+
+using namespace std;    
+using namespace flightgear;
+using namespace osg;
+
+static osg::ref_ptr<osgViewer::Viewer> viewer;
+static osg::ref_ptr<osg::Camera> mainCamera;
+
+static void setStereoMode( const char * mode )
+{
+    DisplaySettings::StereoMode stereoMode = DisplaySettings::QUAD_BUFFER;
+    bool stereoOn = true;
+
+    if (strcmp(mode,"QUAD_BUFFER")==0)
+    {
+        stereoMode = DisplaySettings::QUAD_BUFFER;
+    }
+    else if (strcmp(mode,"ANAGLYPHIC")==0)
+    {
+        stereoMode = DisplaySettings::ANAGLYPHIC;
+    }
+    else if (strcmp(mode,"HORIZONTAL_SPLIT")==0)
+    {
+        stereoMode = DisplaySettings::HORIZONTAL_SPLIT;
+    }
+    else if (strcmp(mode,"VERTICAL_SPLIT")==0)
+    {
+        stereoMode = DisplaySettings::VERTICAL_SPLIT;
+    }
+    else if (strcmp(mode,"LEFT_EYE")==0)
+    {
+        stereoMode = DisplaySettings::LEFT_EYE;
+    }
+    else if (strcmp(mode,"RIGHT_EYE")==0)
+    {
+        stereoMode = DisplaySettings::RIGHT_EYE;
+    }
+    else if (strcmp(mode,"HORIZONTAL_INTERLACE")==0)
+    {
+        stereoMode = DisplaySettings::HORIZONTAL_INTERLACE;
+    }
+    else if (strcmp(mode,"VERTICAL_INTERLACE")==0)
+    {
+        stereoMode = DisplaySettings::VERTICAL_INTERLACE;
+    }
+    else if (strcmp(mode,"CHECKERBOARD")==0)
+    {
+        stereoMode = DisplaySettings::CHECKERBOARD;
+    } else {
+        stereoOn = false; 
+    }
+    DisplaySettings::instance()->setStereo( stereoOn );
+    DisplaySettings::instance()->setStereoMode( stereoMode );
+}
+
+static const char * getStereoMode()
+{
+    DisplaySettings::StereoMode stereoMode = DisplaySettings::instance()->getStereoMode();
+    bool stereoOn = DisplaySettings::instance()->getStereo();
+    if( !stereoOn ) return "OFF";
+    if( stereoMode == DisplaySettings::QUAD_BUFFER ) {
+        return "QUAD_BUFFER";
+    } else if( stereoMode == DisplaySettings::ANAGLYPHIC ) {
+        return "ANAGLYPHIC";
+    } else if( stereoMode == DisplaySettings::HORIZONTAL_SPLIT ) {
+        return "HORIZONTAL_SPLIT";
+    } else if( stereoMode == DisplaySettings::VERTICAL_SPLIT ) {
+        return "VERTICAL_SPLIT";
+    } else if( stereoMode == DisplaySettings::LEFT_EYE ) {
+        return "LEFT_EYE";
+    } else if( stereoMode == DisplaySettings::RIGHT_EYE ) {
+        return "RIGHT_EYE";
+    } else if( stereoMode == DisplaySettings::HORIZONTAL_INTERLACE ) {
+        return "HORIZONTAL_INTERLACE";
+    } else if( stereoMode == DisplaySettings::VERTICAL_INTERLACE ) {
+        return "VERTICAL_INTERLACE";
+    } else if( stereoMode == DisplaySettings::CHECKERBOARD ) {
+        return "CHECKERBOARD";
+    } 
+    return "OFF";
+}
+
+void fgOSOpenWindow(bool stencil)
+{
+    viewer = new osgViewer::Viewer;
+    viewer->setDatabasePager(FGScenery::getPagerSingleton());
+    CameraGroup* cameraGroup = 0;
+    std::string mode;
+    mode = fgGetString("/sim/rendering/multithreading-mode", "SingleThreaded");
+    if (mode == "AutomaticSelection")
+      viewer->setThreadingModel(osgViewer::Viewer::AutomaticSelection);
+    else if (mode == "CullDrawThreadPerContext")
+      viewer->setThreadingModel(osgViewer::Viewer::CullDrawThreadPerContext);
+    else if (mode == "DrawThreadPerContext")
+      viewer->setThreadingModel(osgViewer::Viewer::DrawThreadPerContext);
+    else if (mode == "CullThreadPerCameraDrawThreadPerContext")
+      viewer->setThreadingModel(osgViewer::Viewer::CullThreadPerCameraDrawThreadPerContext);
+    else
+      viewer->setThreadingModel(osgViewer::Viewer::SingleThreaded);
+    WindowBuilder::initWindowBuilder(stencil);
+    WindowBuilder *windowBuilder = WindowBuilder::getWindowBuilder();
+
+    // Look for windows, camera groups, and the old syntax of
+    // top-level cameras
+    SGPropertyNode* renderingNode = fgGetNode("/sim/rendering");
+    SGPropertyNode* cgroupNode = renderingNode->getNode("camera-group", true);
+    bool oldSyntax = !cgroupNode->hasChild("camera");
+    if (oldSyntax) {
+        for (int i = 0; i < renderingNode->nChildren(); ++i) {
+            SGPropertyNode* propNode = renderingNode->getChild(i);
+            const char* propName = propNode->getName();
+            if (!strcmp(propName, "window") || !strcmp(propName, "camera")) {
+                SGPropertyNode* copiedNode
+                    = cgroupNode->getNode(propName, propNode->getIndex(), true);
+                copyProperties(propNode, copiedNode);
+            }
+        }
+        vector<SGPropertyNode_ptr> cameras = cgroupNode->getChildren("camera");
+        SGPropertyNode* masterCamera = 0;
+        BOOST_FOREACH(SGPropertyNode_ptr& camera, cameras) {
+            if (camera->getDoubleValue("shear-x", 0.0) == 0.0
+                && camera->getDoubleValue("shear-y", 0.0) == 0.0) {
+                masterCamera = camera.ptr();
+                break;
+            }
+        }
+        if (!masterCamera) {
+            masterCamera = cgroupNode->getChild("camera", cameras.size(), true);
+            setValue(masterCamera->getNode("window/name", true),
+                     windowBuilder->getDefaultWindowName());
+        }
+        SGPropertyNode* nameNode = masterCamera->getNode("window/name");
+        if (nameNode)
+            setValue(cgroupNode->getNode("gui/window/name", true),
+                     nameNode->getStringValue());
+    }
+    cameraGroup = CameraGroup::buildCameraGroup(viewer.get(), cgroupNode);
+    Camera* guiCamera = getGUICamera(cameraGroup);
+    if (guiCamera) {
+        Viewport* guiViewport = guiCamera->getViewport();
+        fgSetInt("/sim/startup/xsize", guiViewport->width());
+        fgSetInt("/sim/startup/ysize", guiViewport->height());
+    }
+    FGEventHandler* manipulator = globals->get_renderer()->getEventHandler();
+    WindowSystemAdapter* wsa = WindowSystemAdapter::getWSA();
+    if (wsa->windows.size() != 1) {
+        manipulator->setResizable(false);
+    }
+    viewer->getCamera()->setProjectionResizePolicy(osg::Camera::FIXED);
+    viewer->addEventHandler(manipulator);
+    // Let FG handle the escape key with a confirmation
+    viewer->setKeyEventSetsDone(0);
+    // The viewer won't start without some root.
+    viewer->setSceneData(new osg::Group);
+    globals->get_renderer()->setViewer(viewer.get());
+    CameraGroup::setDefault(cameraGroup);
+
+    DisplaySettings * displaySettings = DisplaySettings::instance();
+    fgTie("/sim/rendering/osg-displaysettings/eye-separation", displaySettings, &DisplaySettings::getEyeSeparation, &DisplaySettings::setEyeSeparation );
+    fgTie("/sim/rendering/osg-displaysettings/screen-distance", displaySettings, &DisplaySettings::getScreenDistance, &DisplaySettings::setScreenDistance );
+    fgTie("/sim/rendering/osg-displaysettings/screen-width", displaySettings, &DisplaySettings::getScreenWidth, &DisplaySettings::setScreenWidth );
+    fgTie("/sim/rendering/osg-displaysettings/screen-height", displaySettings, &DisplaySettings::getScreenHeight, &DisplaySettings::setScreenHeight );
+    fgTie("/sim/rendering/osg-displaysettings/stereo-mode", getStereoMode, setStereoMode );
+    fgTie("/sim/rendering/osg-displaysettings/double-buffer", displaySettings, &DisplaySettings::getDoubleBuffer, &DisplaySettings::setDoubleBuffer );
+    fgTie("/sim/rendering/osg-displaysettings/depth-buffer", displaySettings, &DisplaySettings::getDepthBuffer, &DisplaySettings::setDepthBuffer );
+    fgTie("/sim/rendering/osg-displaysettings/rgb", displaySettings, &DisplaySettings::getRGB, &DisplaySettings::setRGB );
+}
+
+
+static int status = 0;
+
+void fgOSExit(int code)
+{
+    viewer->setDone(true);
+    viewer->getDatabasePager()->cancel();
+    status = code;
+}
+
+int fgOSMainLoop()
+{
+    ref_ptr<FGEventHandler> manipulator
+        = globals->get_renderer()->getEventHandler();
+    viewer->setReleaseContextAtEndOfFrameHint(false);
+    if (!viewer->isRealized())
+        viewer->realize();
+    while (!viewer->done()) {
+        fgIdleHandler idleFunc = manipulator->getIdleHandler();
+        if (idleFunc)
+            (*idleFunc)();
+        globals->get_renderer()->update();
+        viewer->frame();
+    }
+    
+    return status;
+}
+
+int fgGetKeyModifiers()
+{
+    if (!globals->get_renderer()) { // happens during shutdown
+      return 0;
+    }
+    
+    return globals->get_renderer()->getEventHandler()->getCurrentModifiers();
+}
+
+void fgWarpMouse(int x, int y)
+{
+    warpGUIPointer(CameraGroup::getDefault(), x, y);
+}
+
+void fgOSInit(int* argc, char** argv)
+{
+    globals->get_renderer()->init();
+    WindowSystemAdapter::setWSA(new WindowSystemAdapter);
+}
+
+// Noop
+void fgOSFullScreen()
+{
+}
+
+static void setMouseCursor(osgViewer::GraphicsWindow* gw, int cursor)
+{
+    if (!gw) {
+        return;
+    }
+  
+    osgViewer::GraphicsWindow::MouseCursor mouseCursor;
+    mouseCursor = osgViewer::GraphicsWindow::InheritCursor;
+    if (cursor == MOUSE_CURSOR_NONE)
+        mouseCursor = osgViewer::GraphicsWindow::NoCursor;
+    else if(cursor == MOUSE_CURSOR_POINTER)
+#ifdef SG_MAC
+        // osgViewer-Cocoa lacks RightArrowCursor, use Left
+        mouseCursor = osgViewer::GraphicsWindow::LeftArrowCursor;
+#else
+        mouseCursor = osgViewer::GraphicsWindow::RightArrowCursor;
+#endif
+    else if(cursor == MOUSE_CURSOR_WAIT)
+        mouseCursor = osgViewer::GraphicsWindow::WaitCursor;
+    else if(cursor == MOUSE_CURSOR_CROSSHAIR)
+        mouseCursor = osgViewer::GraphicsWindow::CrosshairCursor;
+    else if(cursor == MOUSE_CURSOR_LEFTRIGHT)
+        mouseCursor = osgViewer::GraphicsWindow::LeftRightCursor;
+    else if(cursor == MOUSE_CURSOR_TOPSIDE)
+        mouseCursor = osgViewer::GraphicsWindow::TopSideCursor;
+    else if(cursor == MOUSE_CURSOR_BOTTOMSIDE)
+        mouseCursor = osgViewer::GraphicsWindow::BottomSideCursor;
+    else if(cursor == MOUSE_CURSOR_LEFTSIDE)
+        mouseCursor = osgViewer::GraphicsWindow::LeftSideCursor;
+    else if(cursor == MOUSE_CURSOR_RIGHTSIDE)
+        mouseCursor = osgViewer::GraphicsWindow::RightSideCursor;
+    else if(cursor == MOUSE_CURSOR_TOPLEFT)
+        mouseCursor = osgViewer::GraphicsWindow::TopLeftCorner;
+    else if(cursor == MOUSE_CURSOR_TOPRIGHT)
+        mouseCursor = osgViewer::GraphicsWindow::TopRightCorner;
+    else if(cursor == MOUSE_CURSOR_BOTTOMLEFT)
+        mouseCursor = osgViewer::GraphicsWindow::BottomLeftCorner;
+    else if(cursor == MOUSE_CURSOR_BOTTOMRIGHT)
+        mouseCursor = osgViewer::GraphicsWindow::BottomRightCorner;
+
+    gw->setCursor(mouseCursor);
+}
+
+static int _cursor = -1;
+
+void fgSetMouseCursor(int cursor)
+{
+    _cursor = cursor;
+  
+    std::vector<osgViewer::GraphicsWindow*> windows;
+    viewer->getWindows(windows);
+    BOOST_FOREACH(osgViewer::GraphicsWindow* gw, windows) {
+        setMouseCursor(gw, cursor);
+    }
+}
+
+int fgGetMouseCursor()
+{
+    return _cursor;
+}
diff --git a/src/Viewer/fgviewer.cxx b/src/Viewer/fgviewer.cxx
new file mode 100644 (file)
index 0000000..7b4a830
--- /dev/null
@@ -0,0 +1,228 @@
+#ifdef HAVE_CONFIG_H
+#  include "config.h"
+#endif
+
+#include <iostream>
+#include <cstdlib>
+
+#include <osg/ArgumentParser>
+#include <osg/Fog>
+#include <osgDB/ReadFile>
+#include <osgDB/Registry>
+#include <osgDB/WriteFile>
+#include <osgViewer/Renderer>
+#include <osgViewer/Viewer>
+#include <osgViewer/ViewerEventHandlers>
+#include <osgGA/KeySwitchMatrixManipulator>
+#include <osgGA/TrackballManipulator>
+#include <osgGA/FlightManipulator>
+#include <osgGA/DriveManipulator>
+#include <osgGA/TerrainManipulator>
+#include <osgGA/StateSetManipulator>
+
+#include <simgear/props/props.hxx>
+#include <simgear/props/props_io.hxx>
+#include <simgear/misc/sg_path.hxx>
+#include <simgear/scene/material/EffectCullVisitor.hxx>
+#include <simgear/scene/material/matlib.hxx>
+#include <simgear/scene/util/SGReaderWriterOptions.hxx>
+#include <simgear/scene/tgdb/userdata.hxx>
+#include <simgear/scene/model/ModelRegistry.hxx>
+#include <simgear/scene/model/modellib.hxx>
+
+#include <Scenery/scenery.hxx>
+
+#include <Main/fg_props.hxx>
+#include <Main/globals.hxx>
+#include <Main/options.hxx>
+#include <Main/fg_init.hxx>
+
+class GraphDumpHandler : public  osgGA::GUIEventHandler
+{
+public:
+    GraphDumpHandler() : _keyDump('d') {}
+    void setKeyDump(int key) { _keyDump = key; }
+    int getKeyDump() const { return _keyDump; }
+    bool handle(const osgGA::GUIEventAdapter& ea, osgGA::GUIActionAdapter& aa);
+
+    /** Get the keyboard and mouse usage of this manipulator.*/
+    virtual void getUsage(osg::ApplicationUsage& usage) const;
+protected:
+    int _keyDump;
+};
+
+static void dumpOut(osg::Node* node)
+{
+    char filename[24];
+    static int count = 1;
+
+    while (count < 1000) {
+        FILE *fp;
+        snprintf(filename, 24, "fgviewer-%03d.osg", count++);
+        if ( (fp = fopen(filename, "r")) == NULL )
+            break;
+        fclose(fp);
+    }
+
+    if (osgDB::writeNodeFile(*node, filename))
+        std::cerr << "Entire scene graph saved to \"" << filename << "\".\n";
+    else
+        std::cerr << "Failed to save to \"" << filename << "\".\n";
+}
+
+bool GraphDumpHandler::handle(const osgGA::GUIEventAdapter& ea,
+                              osgGA::GUIActionAdapter& aa)
+{
+    osgViewer::View* view = dynamic_cast<osgViewer::View*>(&aa);
+    if (!view)
+        return false;
+    if (ea.getHandled())
+        return false;
+    switch(ea.getEventType()) {
+    case osgGA::GUIEventAdapter::KEYUP:
+        if (ea.getKey() == _keyDump) {
+            dumpOut(view->getScene()->getSceneData());
+            return true;
+        }
+        break;
+    default:
+        return false;
+    }
+    return false;
+}
+
+void GraphDumpHandler::getUsage(osg::ApplicationUsage& usage) const
+{
+    std::ostringstream ostr;
+    ostr << char(_keyDump);
+            usage.addKeyboardMouseBinding(ostr.str(),
+                                          "Dump scene graph to file");
+}
+
+int
+fgviewerMain(int argc, char** argv)
+{
+
+    sgUserDataInit(0);
+
+    // use an ArgumentParser object to manage the program arguments.
+    osg::ArgumentParser arguments(&argc, argv);
+
+    // construct the viewer.
+    osgViewer::Viewer viewer(arguments);
+    osg::Camera* camera = viewer.getCamera();
+    osgViewer::Renderer* renderer
+        = static_cast<osgViewer::Renderer*>(camera->getRenderer());
+    for (int i = 0; i < 2; ++i) {
+        osgUtil::SceneView* sceneView = renderer->getSceneView(i);
+        sceneView->setCullVisitor(new simgear::EffectCullVisitor);
+    }
+    // Shaders expect valid fog
+    osg::StateSet* cameraSS = camera->getOrCreateStateSet();
+    osg::Fog* fog = new osg::Fog;
+    fog->setMode(osg::Fog::EXP2);
+    fog->setColor(osg::Vec4(1.0, 1.0, 1.0, 1.0));
+    fog->setDensity(.0000001);
+    cameraSS->setAttributeAndModes(fog);
+    // ... for some reason, get rid of that FIXME!
+    viewer.setThreadingModel(osgViewer::Viewer::SingleThreaded);
+
+    // set up the camera manipulators.
+    osgGA::KeySwitchMatrixManipulator* keyswitchManipulator;
+    keyswitchManipulator = new osgGA::KeySwitchMatrixManipulator;
+
+    keyswitchManipulator->addMatrixManipulator('1', "Trackball",
+                                               new osgGA::TrackballManipulator);
+    keyswitchManipulator->addMatrixManipulator('2', "Flight",
+                                               new osgGA::FlightManipulator);
+    keyswitchManipulator->addMatrixManipulator('3', "Drive",
+                                               new osgGA::DriveManipulator);
+    keyswitchManipulator->addMatrixManipulator('4', "Terrain",
+                                               new osgGA::TerrainManipulator);
+    viewer.setCameraManipulator(keyswitchManipulator);
+
+    // Usefull stats
+    viewer.addEventHandler(new osgViewer::HelpHandler);
+    viewer.addEventHandler(new osgViewer::StatsHandler);
+    viewer.addEventHandler( new osgGA::StateSetManipulator(viewer.getCamera()->getOrCreateStateSet()) );
+    // Same FIXME ...
+    // viewer.addEventHandler(new osgViewer::ThreadingHandler);
+    viewer.addEventHandler(new osgViewer::LODScaleHandler);
+    viewer.addEventHandler(new osgViewer::ScreenCaptureHandler);
+
+    viewer.addEventHandler(new GraphDumpHandler);
+
+    // Extract files to load from arguments now; this way fgInitConfig
+    // won't choke on them.
+    string_list dataFiles;
+    for (int i = arguments.argc() - 1; i >= 0; --i) {
+        if (arguments.isOption(i)) {
+            break;
+        } else {
+            dataFiles.insert(dataFiles.begin(), arguments[i]);
+            arguments.remove(i);
+        }
+    }
+
+    // A subset of full flightgear initialization.
+    // Allocate global data structures.  This needs to happen before
+    // we parse command line options
+
+    globals = new FGGlobals;
+
+    if ( !fgInitConfig(arguments.argc(), arguments.argv()) ) {
+        SG_LOG( SG_GENERAL, SG_ALERT, "Config option parsing failed ..." );
+        exit(-1);
+    }
+
+    osgDB::FilePathList filePathList
+        = osgDB::Registry::instance()->getDataFilePathList();
+    filePathList.push_back(globals->get_fg_root());
+
+    string_list path_list = globals->get_fg_scenery();
+    for (unsigned i = 0; i < path_list.size(); ++i) {
+        filePathList.push_back(path_list[i]);
+    }
+
+    globals->set_matlib( new SGMaterialLib );
+    simgear::SGModelLib::init(globals->get_fg_root(), globals->get_props());
+
+    // Initialize the material property subsystem.
+
+    SGPath mpath( globals->get_fg_root() );
+    mpath.append( fgGetString("/sim/rendering/materials-file") );
+    if ( ! globals->get_matlib()->load(globals->get_fg_root(), mpath.str(),
+            globals->get_props()) ) {
+        SG_LOG( SG_GENERAL, SG_ALERT,
+                "Error loading materials file " << mpath.str() );
+        exit(-1);
+    }
+
+    globals->set_scenery( new FGScenery );
+    globals->get_scenery()->init();
+    globals->get_scenery()->bind();
+
+    // The file path list must be set in the registry.
+    osgDB::Registry::instance()->getDataFilePathList() = filePathList;
+
+    simgear::SGReaderWriterOptions* options = new simgear::SGReaderWriterOptions;
+    options->getDatabasePathList() = filePathList;
+    options->setMaterialLib(globals->get_matlib());
+    options->setPropertyNode(globals->get_props());
+
+    // read the scene from the list of file specified command line args.
+    osg::ref_ptr<osg::Node> loadedModel;
+    loadedModel = osgDB::readNodeFiles(dataFiles, options);
+
+    // if no model has been successfully loaded report failure.
+    if (!loadedModel.valid()) {
+        std::cerr << arguments.getApplicationName()
+                  << ": No data loaded" << std::endl;
+        return EXIT_FAILURE;
+    }
+
+    // pass the loaded scene graph to the viewer.
+    viewer.setSceneData(loadedModel.get());
+
+    return viewer.run();
+}
diff --git a/src/Viewer/fgviewer.hxx b/src/Viewer/fgviewer.hxx
new file mode 100644 (file)
index 0000000..82cdf5e
--- /dev/null
@@ -0,0 +1,5 @@
+#ifndef __FG_FGVIEWER_HXX
+#define __FG_FGVIEWER_HXX 1
+
+int fgviewerMain(int argc, char** argv);
+#endif
diff --git a/src/Viewer/renderer.cxx b/src/Viewer/renderer.cxx
new file mode 100644 (file)
index 0000000..3fa0755
--- /dev/null
@@ -0,0 +1,2152 @@
+// renderer.cxx -- top level sim routines
+//
+// Written by Curtis Olson, started May 1997.
+// This file contains parts of main.cxx prior to october 2004
+//
+// Copyright (C) 1997 - 2002  Curtis L. Olson  - http://www.flightgear.org/~curt
+//
+// This program is free software; you can redistribute it and/or
+// modify it under the terms of the GNU General Public License as
+// published by the Free Software Foundation; either version 2 of the
+// License, or (at your option) any later version.
+//
+// This program is distributed in the hope that it will be useful, but
+// WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+// General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License
+// along with this program; if not, write to the Free Software
+// Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
+
+#ifdef HAVE_CONFIG_H
+#  include <config.h>
+#endif
+
+#ifdef HAVE_WINDOWS_H
+#  include <windows.h>
+#endif
+
+#include <simgear/compiler.h>
+
+#include <algorithm>
+#include <iostream>
+#include <map>
+#include <vector>
+#include <typeinfo>
+
+#include <osg/ref_ptr>
+#include <osg/AlphaFunc>
+#include <osg/BlendFunc>
+#include <osg/Camera>
+#include <osg/CullFace>
+#include <osg/CullStack>
+#include <osg/Depth>
+#include <osg/Fog>
+#include <osg/Group>
+#include <osg/Hint>
+#include <osg/Light>
+#include <osg/LightModel>
+#include <osg/LightSource>
+#include <osg/Material>
+#include <osg/Math>
+#include <osg/NodeCallback>
+#include <osg/Notify>
+#include <osg/PolygonMode>
+#include <osg/PolygonOffset>
+#include <osg/Program>
+#include <osg/Version>
+#include <osg/TexEnv>
+
+#include <osgUtil/LineSegmentIntersector>
+
+#include <osg/io_utils>
+#include <osgDB/WriteFile>
+#include <osgViewer/Renderer>
+
+#include <simgear/math/SGMath.hxx>
+#include <simgear/scene/material/matlib.hxx>
+#include <simgear/scene/material/EffectCullVisitor.hxx>
+#include <simgear/scene/material/Effect.hxx>
+#include <simgear/scene/material/EffectGeode.hxx>
+#include <simgear/scene/model/animation.hxx>
+#include <simgear/scene/model/placement.hxx>
+#include <simgear/scene/sky/sky.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/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 <Cockpit/panel.hxx>
+
+#include <Model/panelnode.hxx>
+#include <Model/modelmgr.hxx>
+#include <Model/acmodel.hxx>
+#include <Scenery/scenery.hxx>
+#include <Scenery/redout.hxx>
+#include <GUI/new_gui.hxx>
+#include <Instrumentation/HUD/HUD.hxx>
+#include <Environment/precipitation_mgr.hxx>
+#include <Environment/environment_mgr.hxx>
+
+//#include <Main/main.hxx>
+#include "viewer.hxx"
+#include "viewmgr.hxx"
+#include "splash.hxx"
+#include "renderer.hxx"
+#include "CameraGroup.hxx"
+#include "FGEventHandler.hxx"
+
+using namespace osg;
+using namespace simgear;
+using namespace flightgear;
+
+class FGHintUpdateCallback : public osg::StateAttribute::Callback {
+public:
+  FGHintUpdateCallback(const char* configNode) :
+    mConfigNode(fgGetNode(configNode, true))
+  { }
+  virtual void operator()(osg::StateAttribute* stateAttribute,
+                          osg::NodeVisitor*)
+  {
+    assert(dynamic_cast<osg::Hint*>(stateAttribute));
+    osg::Hint* hint = static_cast<osg::Hint*>(stateAttribute);
+
+    const char* value = mConfigNode->getStringValue();
+    if (!value)
+      hint->setMode(GL_DONT_CARE);
+    else if (0 == strcmp(value, "nicest"))
+      hint->setMode(GL_NICEST);
+    else if (0 == strcmp(value, "fastest"))
+      hint->setMode(GL_FASTEST);
+    else
+      hint->setMode(GL_DONT_CARE);
+  }
+private:
+  SGPropertyNode_ptr mConfigNode;
+};
+
+
+class SGPuDrawable : public osg::Drawable {
+public:
+  SGPuDrawable()
+  {
+    // Dynamic stuff, do not store geometry
+    setUseDisplayList(false);
+    setDataVariance(Object::DYNAMIC);
+
+    osg::StateSet* stateSet = getOrCreateStateSet();
+    stateSet->setRenderBinDetails(1001, "RenderBin");
+    // speed optimization?
+    stateSet->setMode(GL_CULL_FACE, osg::StateAttribute::OFF);
+    // We can do translucent menus, so why not. :-)
+    stateSet->setAttribute(new osg::BlendFunc(osg::BlendFunc::SRC_ALPHA, osg::BlendFunc::ONE_MINUS_SRC_ALPHA));
+    stateSet->setMode(GL_BLEND, osg::StateAttribute::ON);
+    stateSet->setTextureMode(0, GL_TEXTURE_2D, osg::StateAttribute::OFF);
+
+    stateSet->setTextureAttribute(0, new osg::TexEnv(osg::TexEnv::MODULATE));
+
+    stateSet->setMode(GL_FOG, osg::StateAttribute::OFF);
+    stateSet->setMode(GL_DEPTH_TEST, osg::StateAttribute::OFF);
+  }
+  virtual void drawImplementation(osg::RenderInfo& renderInfo) const
+  { drawImplementation(*renderInfo.getState()); }
+  void drawImplementation(osg::State& state) const
+  {
+    state.setActiveTextureUnit(0);
+    state.setClientActiveTextureUnit(0);
+
+    state.disableAllVertexArrays();
+
+    glPushAttrib(GL_ALL_ATTRIB_BITS);
+    glPushClientAttrib(~0u);
+
+    puDisplay();
+
+    glPopClientAttrib();
+    glPopAttrib();
+  }
+
+  virtual osg::Object* cloneType() const { return new SGPuDrawable; }
+  virtual osg::Object* clone(const osg::CopyOp&) const { return new SGPuDrawable; }
+  
+private:
+};
+
+class SGHUDDrawable : public osg::Drawable {
+public:
+  SGHUDDrawable()
+  {
+    // Dynamic stuff, do not store geometry
+    setUseDisplayList(false);
+    setDataVariance(Object::DYNAMIC);
+
+    osg::StateSet* stateSet = 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);
+
+    stateSet->setTextureAttribute(0, new osg::TexEnv(osg::TexEnv::MODULATE));
+  }
+  virtual void drawImplementation(osg::RenderInfo& renderInfo) const
+  { drawImplementation(*renderInfo.getState()); }
+  void drawImplementation(osg::State& state) const
+  {
+    state.setActiveTextureUnit(0);
+    state.setClientActiveTextureUnit(0);
+    state.disableAllVertexArrays();
+
+    glPushAttrib(GL_ALL_ATTRIB_BITS);
+    glPushClientAttrib(~0u);
+      
+    HUD *hud = static_cast<HUD*>(globals->get_subsystem("hud"));
+    hud->draw(state);
+
+    glPopClientAttrib();
+    glPopAttrib();
+  }
+
+  virtual osg::Object* cloneType() const { return new SGHUDDrawable; }
+  virtual osg::Object* clone(const osg::CopyOp&) const { return new SGHUDDrawable; }
+  
+private:
+};
+
+class FGLightSourceUpdateCallback : public osg::NodeCallback {
+public:
+  
+  /**
+   * @param isSun true if the light is the actual sun i.e., for
+   * illuminating the moon.
+   */
+  FGLightSourceUpdateCallback(bool isSun = false) : _isSun(isSun) {}
+  FGLightSourceUpdateCallback(const FGLightSourceUpdateCallback& nc,
+                              const CopyOp& op)
+    : NodeCallback(nc, op), _isSun(nc._isSun)
+  {}
+  META_Object(flightgear,FGLightSourceUpdateCallback);
+  
+  virtual void operator()(osg::Node* node, osg::NodeVisitor* nv)
+  {
+    assert(dynamic_cast<osg::LightSource*>(node));
+    osg::LightSource* lightSource = static_cast<osg::LightSource*>(node);
+    osg::Light* light = lightSource->getLight();
+    
+    FGLight *l = static_cast<FGLight*>(globals->get_subsystem("lighting"));
+    if (_isSun) {
+      light->setAmbient(Vec4(0.0f, 0.0f, 0.0f, 0.0f));
+      light->setDiffuse(Vec4(1.0f, 1.0f, 1.0f, 1.0f));
+      light->setSpecular(Vec4(0.0f, 0.0f, 0.0f, 0.0f));
+    } else {
+      light->setAmbient(toOsg(l->scene_ambient()));
+      light->setDiffuse(toOsg(l->scene_diffuse()));
+      light->setSpecular(toOsg(l->scene_specular()));
+    }
+    osg::Vec4f position(l->sun_vec()[0], l->sun_vec()[1], l->sun_vec()[2], 0);
+    light->setPosition(position);
+
+    traverse(node, nv);
+  }
+private:
+  const bool _isSun;
+};
+
+class FGWireFrameModeUpdateCallback : public osg::StateAttribute::Callback {
+public:
+  FGWireFrameModeUpdateCallback() :
+    mWireframe(fgGetNode("/sim/rendering/wireframe", true))
+  { }
+  virtual void operator()(osg::StateAttribute* stateAttribute,
+                          osg::NodeVisitor*)
+  {
+    assert(dynamic_cast<osg::PolygonMode*>(stateAttribute));
+    osg::PolygonMode* polygonMode;
+    polygonMode = static_cast<osg::PolygonMode*>(stateAttribute);
+
+    if (mWireframe->getBoolValue())
+      polygonMode->setMode(osg::PolygonMode::FRONT_AND_BACK,
+                           osg::PolygonMode::LINE);
+    else
+      polygonMode->setMode(osg::PolygonMode::FRONT_AND_BACK,
+                           osg::PolygonMode::FILL);
+  }
+private:
+  SGPropertyNode_ptr mWireframe;
+};
+
+class FGLightModelUpdateCallback : public osg::StateAttribute::Callback {
+public:
+  FGLightModelUpdateCallback() :
+    mHighlights(fgGetNode("/sim/rendering/specular-highlight", true))
+  { }
+  virtual void operator()(osg::StateAttribute* stateAttribute,
+                          osg::NodeVisitor*)
+  {
+    assert(dynamic_cast<osg::LightModel*>(stateAttribute));
+    osg::LightModel* lightModel;
+    lightModel = static_cast<osg::LightModel*>(stateAttribute);
+
+#if 0
+    FGLight *l = static_cast<FGLight*>(globals->get_subsystem("lighting"));
+    lightModel->setAmbientIntensity(toOsg(l->scene_ambient());
+#else
+    lightModel->setAmbientIntensity(osg::Vec4(0, 0, 0, 1));
+#endif
+    lightModel->setTwoSided(true);
+    lightModel->setLocalViewer(false);
+
+    if (mHighlights->getBoolValue()) {
+      lightModel->setColorControl(osg::LightModel::SEPARATE_SPECULAR_COLOR);
+    } else {
+      lightModel->setColorControl(osg::LightModel::SINGLE_COLOR);
+    }
+  }
+private:
+  SGPropertyNode_ptr mHighlights;
+};
+
+class FGFogEnableUpdateCallback : public osg::StateSet::Callback {
+public:
+  FGFogEnableUpdateCallback() :
+    mFogEnabled(fgGetNode("/sim/rendering/fog", true))
+  { }
+  virtual void operator()(osg::StateSet* stateSet, osg::NodeVisitor*)
+  {
+    if (strcmp(mFogEnabled->getStringValue(), "disabled") == 0) {
+      stateSet->setMode(GL_FOG, osg::StateAttribute::OFF);
+    } else {
+      stateSet->setMode(GL_FOG, osg::StateAttribute::ON);
+    }
+  }
+private:
+  SGPropertyNode_ptr mFogEnabled;
+};
+
+class FGFogUpdateCallback : public osg::StateAttribute::Callback {
+public:
+  virtual void operator () (osg::StateAttribute* sa, osg::NodeVisitor* nv)
+  {
+    assert(dynamic_cast<SGUpdateVisitor*>(nv));
+    assert(dynamic_cast<osg::Fog*>(sa));
+    SGUpdateVisitor* updateVisitor = static_cast<SGUpdateVisitor*>(nv);
+    osg::Fog* fog = static_cast<osg::Fog*>(sa);
+    fog->setMode(osg::Fog::EXP2);
+    fog->setColor(toOsg(updateVisitor->getFogColor()));
+    fog->setDensity(updateVisitor->getFogExp2Density());
+  }
+};
+
+// update callback for the switch node guarding that splash
+class FGScenerySwitchCallback : 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 = scenery_enabled;
+    sw->setValue(0, enabled);
+    if (!enabled)
+      return;
+    traverse(node, nv);
+  }
+
+  static bool scenery_enabled;
+};
+
+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() ) ),
+    _sunDiffuse( new osg::Uniform( "fg_SunDiffuseColor", osg::Vec4f() ) ),
+    _sunSpecular( new osg::Uniform( "fg_SunSpecularColor", osg::Vec4f() ) ),
+    _sunDirection( new osg::Uniform( "fg_SunDirection", osg::Vec3f() ) ),
+    _planes( new osg::Uniform( "fg_Planes", osg::Vec3f() ) ),
+    _fogColor( new osg::Uniform( "fg_FogColor", osg::Vec4f(1.0, 1.0, 1.0, 1.0) ) ),
+    _fogDensity( new osg::Uniform( "fg_FogDensity", 0.0001f ) ),
+    _shadowNumber( new osg::Uniform( "fg_ShadowNumber", (int)4 ) ),
+    _shadowDistances( new osg::Uniform( "fg_ShadowDistances", osg::Vec4f(5.0, 50.0, 500.0, 5000.0 ) ) )
+{
+#ifdef FG_JPEG_SERVER
+   jpgRenderFrame = updateRenderer;
+#endif
+   eventHandler = new FGEventHandler;
+
+   _numCascades = 4;
+   _cascadeFar[0] = 5.f;
+   _cascadeFar[1] = 50.f;
+   _cascadeFar[2] = 500.f;
+   _cascadeFar[3] = 5000.f;
+}
+
+FGRenderer::~FGRenderer()
+{
+#ifdef FG_JPEG_SERVER
+   jpgRenderFrame = NULL;
+#endif
+    delete _sky;
+}
+
+// Initialize various GL/view parameters
+// 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 ) {
+    osgViewer::Viewer* viewer = getViewer();
+    mRealRoot = dynamic_cast<osg::Group*>(viewer->getSceneData());
+    ref_ptr<Node> splashNode = fgCreateSplashNode();
+    if (_classicalRenderer) {
+        mRealRoot->addChild(splashNode.get());
+    } else {
+        for (   CameraGroup::CameraIterator ii = CameraGroup::getDefault()->camerasBegin();
+                ii != CameraGroup::getDefault()->camerasEnd();
+                ++ii )
+        {
+            CameraInfo* info = ii->get();
+            Camera* camera = info->getCamera(DISPLAY_CAMERA);
+            if (camera == 0) continue;
+
+            camera->addChild(splashNode.get());
+        }
+    }
+    mFrameStamp = viewer->getFrameStamp();
+    // Scene doesn't seem to pass the frame stamp to the update
+    // visitor automatically.
+    mUpdateVisitor->setFrameStamp(mFrameStamp.get());
+    viewer->setUpdateVisitor(mUpdateVisitor.get());
+    fgSetDouble("/sim/startup/splash-alpha", 1.0);
+}
+
+class ShadowMapSizeListener : public SGPropertyChangeListener {
+public:
+    virtual void valueChanged(SGPropertyNode* node) {
+        globals->get_renderer()->updateShadowMapSize(node->getIntValue());
+    }
+};
+
+class ShadowEnabledListener : public SGPropertyChangeListener {
+public:
+    virtual void valueChanged(SGPropertyNode* node) {
+        globals->get_renderer()->enableShadows(node->getBoolValue());
+    }
+};
+
+class ShadowNumListener : public SGPropertyChangeListener {
+public:
+    virtual void valueChanged(SGPropertyNode* node) {
+        globals->get_renderer()->updateCascadeNumber(node->getIntValue());
+    }
+};
+
+class ShadowRangeListener : public SGPropertyChangeListener {
+public:
+    virtual void valueChanged(SGPropertyNode* node) {
+        globals->get_renderer()->updateCascadeFar(node->getIndex(), node->getFloatValue());
+    }
+};
+
+void
+FGRenderer::init( void )
+{
+    _classicalRenderer = !fgGetBool("/sim/rendering/rembrandt", false);
+    _shadowMapSize    = fgGetInt( "/sim/rendering/shadows/map-size", 4096 );
+    fgAddChangeListener( new ShadowMapSizeListener, "/sim/rendering/shadows/map-size" );
+    fgAddChangeListener( new ShadowEnabledListener, "/sim/rendering/shadows/enabled" );
+    ShadowRangeListener* srl = new ShadowRangeListener;
+    fgAddChangeListener(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");
+    _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);
+    _cascadeFar[2] = fgGetFloat("/sim/rendering/shadows/cascade-far-m[2]", 500.0f);
+    _cascadeFar[3] = fgGetFloat("/sim/rendering/shadows/cascade-far-m[3]", 5000.0f);
+    _scenery_loaded   = fgGetNode("/sim/sceneryloaded", true);
+    _scenery_override = fgGetNode("/sim/sceneryloaded-override", true);
+    _panel_hotspots   = fgGetNode("/sim/panel-hotspots", true);
+    _virtual_cockpit  = fgGetNode("/sim/virtual-cockpit", true);
+
+    _sim_delta_sec = fgGetNode("/sim/time/delta-sec", true);
+
+    _xsize         = fgGetNode("/sim/startup/xsize", true);
+    _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);
+
+    _cloud_status = fgGetNode("/environment/clouds/status", true);
+    _visibility_m = fgGetNode("/environment/visibility-m", true);
+    
+    bool use_point_sprites = _point_sprites->getBoolValue();
+    bool enhanced_lighting = _enhanced_lighting->getBoolValue();
+    bool distance_attenuation = _distance_attenuation->getBoolValue();
+
+    SGConfigureDirectionalLights( use_point_sprites, enhanced_lighting,
+                                  distance_attenuation );
+
+    if (const char* tc = fgGetString("/sim/rendering/texture-compression", NULL)) {
+      if (strcmp(tc, "false") == 0 || strcmp(tc, "off") == 0 ||
+          strcmp(tc, "0") == 0 || strcmp(tc, "no") == 0 ||
+          strcmp(tc, "none") == 0) {
+        SGSceneFeatures::instance()->setTextureCompression(SGSceneFeatures::DoNotUseCompression);
+      } else if (strcmp(tc, "arb") == 0) {
+        SGSceneFeatures::instance()->setTextureCompression(SGSceneFeatures::UseARBCompression);
+      } else if (strcmp(tc, "dxt1") == 0) {
+        SGSceneFeatures::instance()->setTextureCompression(SGSceneFeatures::UseDXT1Compression);
+      } else if (strcmp(tc, "dxt3") == 0) {
+        SGSceneFeatures::instance()->setTextureCompression(SGSceneFeatures::UseDXT3Compression);
+      } else if (strcmp(tc, "dxt5") == 0) {
+        SGSceneFeatures::instance()->setTextureCompression(SGSceneFeatures::UseDXT5Compression);
+      } else {
+        SG_LOG(SG_VIEW, SG_WARN, "Unknown texture compression setting!");
+      }
+    }
+    
+// create sky, but can't build until setupView, since we depend
+// on other subsystems to be inited, eg Ephemeris    
+    _sky = new SGSky;
+    
+    SGPath texture_path(globals->get_fg_root());
+    texture_path.append("Textures");
+    texture_path.append("Sky");
+    for (int i = 0; i < FGEnvironmentMgr::MAX_CLOUD_LAYERS; i++) {
+        SGCloudLayer * layer = new SGCloudLayer(texture_path.str());
+        _sky->add_cloud_layer(layer);
+    }
+    
+    _sky->texture_path( texture_path.str() );
+
+    if (!_classicalRenderer) {
+        eventHandler->setChangeStatsCameraRenderOrder( true );
+    }
+}
+
+void installCullVisitor(Camera* camera)
+{
+    osgViewer::Renderer* renderer
+        = 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);
+        sceneView->getCullVisitor()->setIdentifier(identifier.get());
+
+        identifier = sceneView->getCullVisitorLeft()->getIdentifier();
+        sceneView->setCullVisitorLeft(sceneView->getCullVisitor()->clone());
+        sceneView->getCullVisitorLeft()->setIdentifier(identifier.get());
+
+        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,
+                                   const Matrix& view,
+                                   const Matrix& projection,
+                                                                  osg::GraphicsContext* gc,
+                                   bool useMasterSceneData)
+{
+       flightgear::CameraInfo* info = 0;
+       if (!_classicalRenderer && (flags & (CameraGroup::GUI | CameraGroup::ORTHO)) == 0)
+               info = buildDeferredPipeline( cgroup, flags, camera, view, projection, gc );
+
+       if (info) {
+               return info;
+       } else {
+               if ((flags & (CameraGroup::GUI | CameraGroup::ORTHO)) == 0)
+                       _classicalRenderer = true;
+               return buildClassicalPipeline( cgroup, flags, camera, view, projection, useMasterSceneData );
+       }
+}
+
+flightgear::CameraInfo*
+FGRenderer::buildClassicalPipeline(flightgear::CameraGroup* cgroup, unsigned flags, osg::Camera* camera,
+                                const osg::Matrix& view,
+                                const osg::Matrix& projection,
+                                bool useMasterSceneData)
+{
+    CameraInfo* info = new CameraInfo(flags);
+    // The camera group will always update the camera
+    camera->setReferenceFrame(Transform::ABSOLUTE_RF);
+
+    Camera* farCamera = 0;
+    if ((flags & (CameraGroup::GUI | CameraGroup::ORTHO)) == 0) {
+        farCamera = new Camera;
+        farCamera->setAllowEventFocus(camera->getAllowEventFocus());
+        farCamera->setGraphicsContext(camera->getGraphicsContext());
+        farCamera->setCullingMode(camera->getCullingMode());
+        farCamera->setInheritanceMask(camera->getInheritanceMask());
+        farCamera->setReferenceFrame(Transform::ABSOLUTE_RF);
+        // Each camera's viewport is written when the window is
+        // resized; if the the viewport isn't copied here, it gets updated
+        // twice and ends up with the wrong value.
+        farCamera->setViewport(simgear::clone(camera->getViewport()));
+        farCamera->setDrawBuffer(camera->getDrawBuffer());
+        farCamera->setReadBuffer(camera->getReadBuffer());
+        farCamera->setRenderTargetImplementation(
+            camera->getRenderTargetImplementation());
+        const Camera::BufferAttachmentMap& bufferMap
+            = camera->getBufferAttachmentMap();
+        if (bufferMap.count(Camera::COLOR_BUFFER) != 0) {
+            farCamera->attach(
+                Camera::COLOR_BUFFER,
+                bufferMap.find(Camera::COLOR_BUFFER)->second._texture.get());
+        }
+        cgroup->getViewer()->addSlave(farCamera, projection, view, useMasterSceneData);
+        installCullVisitor(farCamera);
+               int farSlaveIndex = cgroup->getViewer()->getNumSlaves() - 1;
+               info->addCamera( FAR_CAMERA, farCamera, farSlaveIndex );
+        farCamera->setRenderOrder(Camera::POST_RENDER, farSlaveIndex);
+        camera->setCullMask(camera->getCullMask() & ~simgear::BACKGROUND_BIT);
+        camera->setClearMask(GL_DEPTH_BUFFER_BIT);
+    }
+    cgroup->getViewer()->addSlave(camera, projection, view, useMasterSceneData);
+    installCullVisitor(camera);
+    int slaveIndex = cgroup->getViewer()->getNumSlaves() - 1;
+       info->addCamera( MAIN_CAMERA, camera, slaveIndex );
+    camera->setRenderOrder(Camera::POST_RENDER, slaveIndex);
+    cgroup->addCamera(info);
+    return info;
+}
+
+class FGDeferredRenderingCameraCullCallback : public osg::NodeCallback {
+public:
+       FGDeferredRenderingCameraCullCallback( flightgear::CameraKind k, CameraInfo* i ) : kind( k ), info( i ) {}
+       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;
+                               }
+                       }
+               } else if ( kind == flightgear::LIGHTING_CAMERA ) {
+            osg::ref_ptr<osg::Camera> mainShadowCamera = info->getCamera( SHADOW_CAMERA );
+                       if (mainShadowCamera.valid()) {
+                               osg::Group* grp = mainShadowCamera->getChild(0)->asGroup();
+                               for (int i = 0; i < 4; ++i ) {
+                                       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::RefMatrix * refMatrix = new osg::RefMatrix( cascadeCam->getInverseViewMatrix() * *cv->getModelViewMatrix() );
+
+                                       cv->getRenderStage()->getPositionalStateContainer()->addPositionedTextureAttribute( i+1, refMatrix, shadowTexGen );
+                               }
+                       }
+                       // 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;
+    CameraInfo* info;
+};
+
+osg::Texture2D* buildDeferredBuffer(GLint internalFormat, GLenum sourceFormat, GLenum sourceType, osg::Texture::WrapMode wrapMode, bool shadowComparison = false)
+{
+    osg::Texture2D* tex = new osg::Texture2D;
+    tex->setResizeNonPowerOfTwoHint( false );
+    tex->setInternalFormat( internalFormat );
+    tex->setShadowComparison(shadowComparison);
+    if (shadowComparison) {
+        tex->setShadowTextureMode(osg::Texture2D::LUMINANCE);
+        tex->setBorderColor(osg::Vec4(1.0f,1.0f,1.0f,1.0f));
+    }
+    tex->setSourceFormat(sourceFormat);
+    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 );
+       return tex;
+}
+
+void buildDeferredBuffers( flightgear::CameraInfo* info, int shadowMapSize, bool normal16 )
+{
+    info->addBuffer(flightgear::RenderBufferInfo::DEPTH_BUFFER, buildDeferredBuffer( GL_DEPTH_COMPONENT32, GL_DEPTH_COMPONENT, GL_FLOAT, osg::Texture::CLAMP_TO_BORDER) );
+    if (false)
+        info->addBuffer(flightgear::RenderBufferInfo::NORMAL_BUFFER, buildDeferredBuffer( 0x822C /*GL_RG16*/, 0x8227 /*GL_RG*/, GL_UNSIGNED_SHORT, osg::Texture::CLAMP_TO_BORDER) );
+    else
+        info->addBuffer(flightgear::RenderBufferInfo::NORMAL_BUFFER, buildDeferredBuffer( GL_RGBA8, GL_RGBA, GL_UNSIGNED_SHORT, 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 )
+{
+    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 )
+{
+    osg::Camera* camera = new osg::Camera;
+    info->addCamera(flightgear::GEOMETRY_CAMERA, camera );
+
+    camera->setCullMask( ~simgear::MODELLIGHT_BIT );
+    camera->setName( "GeometryC" );
+    camera->setGraphicsContext( gc );
+    camera->setCullCallback( new FGDeferredRenderingCameraCullCallback( flightgear::GEOMETRY_CAMERA, info ) );
+    camera->setClearMask( GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT );
+    camera->setClearColor( osg::Vec4( 0., 0., 0., 0. ) );
+    camera->setClearDepth( 1.0 );
+    camera->setRenderTargetImplementation( osg::Camera::FRAME_BUFFER_OBJECT );
+    camera->setViewport( new osg::Viewport );
+    attachBufferToCamera( info, camera, osg::Camera::DEPTH_BUFFER, flightgear::GEOMETRY_CAMERA, flightgear::RenderBufferInfo::DEPTH_BUFFER );
+    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 );
+    camera->setDrawBuffer(GL_FRONT);
+    camera->setReadBuffer(GL_FRONT);
+
+    camera->addChild( mDeferredRealRoot.get() );
+
+    return camera;
+}
+
+static void setShadowCascadeStateSet( osg::Camera* cam ) {
+    osg::StateSet* ss = cam->getOrCreateStateSet();
+    ss->setAttribute( new osg::PolygonOffset( 1.1f, 5.0f ), osg::StateAttribute::ON | osg::StateAttribute::OVERRIDE );
+    ss->setMode( GL_POLYGON_OFFSET_FILL, osg::StateAttribute::ON | osg::StateAttribute::OVERRIDE );
+    ss->setRenderBinDetails( 0, "RenderBin", osg::StateSet::OVERRIDE_RENDERBIN_DETAILS );
+    ss->setAttributeAndModes( new osg::AlphaFunc( osg::AlphaFunc::GREATER, 0.05 ), osg::StateAttribute::ON | osg::StateAttribute::OVERRIDE );
+    ss->setAttributeAndModes( new osg::ColorMask( false, false, false, false ), osg::StateAttribute::ON | osg::StateAttribute::OVERRIDE );
+    ss->setAttributeAndModes( new osg::CullFace( osg::CullFace::FRONT ), osg::StateAttribute::ON | osg::StateAttribute::OVERRIDE );
+    osg::Program* program = new osg::Program;
+    ss->setAttribute( program, osg::StateAttribute::OVERRIDE | osg::StateAttribute::ON );
+    ss->setMode( GL_LIGHTING, osg::StateAttribute::OVERRIDE | osg::StateAttribute::OFF );
+    ss->setMode( GL_BLEND, osg::StateAttribute::OVERRIDE | osg::StateAttribute::OFF );
+    //ss->setTextureMode( 0, GL_TEXTURE_2D, osg::StateAttribute::OVERRIDE | osg::StateAttribute::ON );
+    ss->setTextureMode( 0, GL_TEXTURE_3D, osg::StateAttribute::OVERRIDE | osg::StateAttribute::OFF );
+    ss->setTextureMode( 1, GL_TEXTURE_2D, osg::StateAttribute::OVERRIDE | osg::StateAttribute::OFF );
+    ss->setTextureMode( 1, GL_TEXTURE_3D, osg::StateAttribute::OVERRIDE | osg::StateAttribute::OFF );
+    ss->setTextureMode( 2, GL_TEXTURE_2D, osg::StateAttribute::OVERRIDE | osg::StateAttribute::OFF );
+    ss->setTextureMode( 2, GL_TEXTURE_3D, osg::StateAttribute::OVERRIDE | osg::StateAttribute::OFF );
+}
+
+static osg::Camera* createShadowCascadeCamera( int no, int cascadeSize ) {
+    osg::Camera* cascadeCam = new osg::Camera;
+    setShadowCascadeStateSet( cascadeCam );
+
+    std::ostringstream oss;
+    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->setAllowEventFocus(false);
+    cascadeCam->setReferenceFrame(osg::Transform::ABSOLUTE_RF_INHERIT_VIEWPOINT);
+    cascadeCam->setRenderOrder(osg::Camera::NESTED_RENDER);
+    cascadeCam->setComputeNearFarMode(osg::CullSettings::DO_NOT_COMPUTE_NEAR_FAR);
+    cascadeCam->setViewport( int( no / 2 ) * cascadeSize, (no & 1) * cascadeSize, cascadeSize, cascadeSize );
+    return cascadeCam;
+}
+
+osg::Camera* FGRenderer::buildDeferredShadowCamera( flightgear::CameraInfo* info, osg::GraphicsContext* gc )
+{
+    osg::Camera* mainShadowCamera = new osg::Camera;
+    info->addCamera(flightgear::SHADOW_CAMERA, mainShadowCamera, 0.0f );
+
+    mainShadowCamera->setName( "ShadowC" );
+    mainShadowCamera->setClearMask( GL_DEPTH_BUFFER_BIT );
+    mainShadowCamera->setClearDepth( 1.0 );
+    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 );
+    mainShadowCamera->setComputeNearFarMode(osg::Camera::DO_NOT_COMPUTE_NEAR_FAR);
+    mainShadowCamera->setReferenceFrame(osg::Transform::ABSOLUTE_RF);
+    mainShadowCamera->setProjectionMatrix(osg::Matrix::identity());
+    mainShadowCamera->setCullingMode( osg::CullSettings::NO_CULLING );
+    mainShadowCamera->setViewport( 0, 0, _shadowMapSize, _shadowMapSize );
+    mainShadowCamera->setDrawBuffer(GL_FRONT);
+    mainShadowCamera->setReadBuffer(GL_FRONT);
+
+    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() );
+        shadowSwitch->addChild( cascadeCam );
+        info->shadowTexGen[i] = new osg::TexGen;
+    }
+    if (fgGetBool("/sim/rendering/shadows/enabled", true))
+        shadowSwitch->setAllChildrenOn();
+    else
+        shadowSwitch->setAllChildrenOff();
+
+    return mainShadowCamera;
+}
+
+void FGRenderer::updateShadowCascade(const CameraInfo* info, osg::Camera* camera, osg::Group* grp, int idx, double left, double right, double bottom, double top, double zNear, double f1, double f2)
+{
+    osg::Camera* cascade = static_cast<osg::Camera*>( grp->getChild(idx) );
+    osg::Matrixd &viewMatrix = cascade->getViewMatrix();
+    osg::Matrixd &projectionMatrix = cascade->getProjectionMatrix();
+
+    osg::BoundingSphere bs;
+    bs.expandBy(osg::Vec3(left,bottom,-zNear) * f1);
+    bs.expandBy(osg::Vec3(right,top,-zNear) * f2);
+    bs.expandBy(osg::Vec3(left,bottom,-zNear) * f2);
+    bs.expandBy(osg::Vec3(right,top,-zNear) * f1);
+
+    osg::Vec4 aim = osg::Vec4(bs.center(), 1.0) * camera->getInverseViewMatrix();
+
+    projectionMatrix.makeOrtho( -bs.radius(), bs.radius(), -bs.radius(), bs.radius(), 1., 15000.0 );
+    osg::Vec3 position( aim.x(), aim.y(), aim.z() );
+    viewMatrix.makeLookAt( position + (getSunDirection() * 10000.0), position, position );
+}
+
+osg::Vec3 FGRenderer::getSunDirection() const
+{
+    osg::Vec3 val;
+    _sunDirection->get( val );
+    return val;
+}
+
+void FGRenderer::updateShadowCamera(const flightgear::CameraInfo* info, const osg::Vec3d& position)
+{
+    ref_ptr<Camera> mainShadowCamera = info->getCamera( SHADOW_CAMERA );
+    if (mainShadowCamera.valid()) {
+        ref_ptr<Switch> shadowSwitch = mainShadowCamera->getChild( 0 )->asSwitch();
+        osg::Vec3d up = position,
+            dir = getSunDirection();
+        up.normalize();
+        dir.normalize();
+        // cos(100 deg) == -0.17
+        if (up * dir < -0.17 || !fgGetBool("/sim/rendering/shadows/enabled", true)) {
+            shadowSwitch->setAllChildrenOff();
+        } else {
+            double left,right,bottom,top,zNear,zFar;
+            ref_ptr<Camera> camera = info->getCamera(GEOMETRY_CAMERA);
+            camera->getProjectionMatrix().getFrustum(left,right,bottom,top,zNear,zFar);
+
+            shadowSwitch->setAllChildrenOn();
+            if (_numCascades == 1) {
+                osg::Camera* cascadeCam = static_cast<osg::Camera*>( shadowSwitch->getChild(0) );
+                cascadeCam->setViewport( 0, 0, _shadowMapSize, _shadowMapSize );
+            } else {
+                for (int no = 0; no < 4; ++no) {
+                    osg::Camera* cascadeCam = static_cast<osg::Camera*>( shadowSwitch->getChild(no) );
+                    cascadeCam->setViewport( int( no / 2 ) * (_shadowMapSize/2), (no & 1) * (_shadowMapSize/2), (_shadowMapSize/2), (_shadowMapSize/2) );
+                }
+            }
+            updateShadowCascade(info, camera, shadowSwitch, 0, left, right, bottom, top, zNear, 1.0, _cascadeFar[0]/zNear);
+            if (_numCascades > 1) {
+                shadowSwitch->setValue(1, true);
+                updateShadowCascade(info, camera, shadowSwitch, 1, left, right, bottom, top, zNear, _cascadeFar[0]/zNear, _cascadeFar[1]/zNear);
+            } else {
+                shadowSwitch->setValue(1, false);
+            }
+            if (_numCascades > 2) {
+                shadowSwitch->setValue(2, true);
+                updateShadowCascade(info, camera, shadowSwitch, 2, left, right, bottom, top, zNear, _cascadeFar[1]/zNear, _cascadeFar[2]/zNear);
+            } else {
+                shadowSwitch->setValue(2, false);
+            }
+            if (_numCascades > 3) {
+                shadowSwitch->setValue(3, true);
+                updateShadowCascade(info, camera, shadowSwitch, 3, left, right, bottom, top, zNear, _cascadeFar[2]/zNear, _cascadeFar[3]/zNear);
+            } else {
+                shadowSwitch->setValue(3, false);
+            }
+            {
+            osg::Matrixd &viewMatrix = mainShadowCamera->getViewMatrix();
+
+            osg::Vec4 aim = osg::Vec4( 0.0, 0.0, 0.0, 1.0 ) * camera->getInverseViewMatrix();
+
+            osg::Vec3 position( aim.x(), aim.y(), aim.z() );
+            viewMatrix.makeLookAt( position, position + (getSunDirection() * 10000.0), position );
+            }
+        }
+    }
+}
+
+void FGRenderer::updateShadowMapSize(int mapSize)
+{
+    if ( ((~( mapSize-1 )) & mapSize) != mapSize ) {
+        SG_LOG( SG_VIEW, SG_ALERT, "Map size is not a power of two" );
+        return;
+    }
+    for (   CameraGroup::CameraIterator ii = CameraGroup::getDefault()->camerasBegin();
+            ii != CameraGroup::getDefault()->camerasEnd();
+            ++ii )
+    {
+        CameraInfo* info = ii->get();
+        Camera* camera = info->getCamera(SHADOW_CAMERA);
+        if (camera == 0) continue;
+
+        Texture2D* tex = info->getBuffer(RenderBufferInfo::SHADOW_BUFFER);
+        if (tex == 0) continue;
+
+        tex->setTextureSize( mapSize, mapSize );
+        tex->dirtyTextureObject();
+
+        Viewport* vp = camera->getViewport();
+        vp->width() = mapSize;
+        vp->height() = mapSize;
+
+        osgViewer::Renderer* renderer
+            = static_cast<osgViewer::Renderer*>(camera->getRenderer());
+        for (int i = 0; i < 2; ++i) {
+            osgUtil::SceneView* sceneView = renderer->getSceneView(i);
+            sceneView->getRenderStage()->setFrameBufferObject(0);
+            sceneView->getRenderStage()->setCameraRequiresSetUp(true);
+            if (sceneView->getRenderStageLeft()) {
+                sceneView->getRenderStageLeft()->setFrameBufferObject(0);
+                sceneView->getRenderStageLeft()->setCameraRequiresSetUp(true);
+            }
+            if (sceneView->getRenderStageRight()) {
+                sceneView->getRenderStageRight()->setFrameBufferObject(0);
+                sceneView->getRenderStageRight()->setCameraRequiresSetUp(true);
+            }
+        }
+
+        int cascadeSize = mapSize / 2;
+        Group* grp = camera->getChild(0)->asGroup();
+        for (int i = 0; i < 4; ++i ) {
+            Camera* cascadeCam = static_cast<Camera*>( grp->getChild(i) );
+            cascadeCam->setViewport( int( i / 2 ) * cascadeSize, (i & 1) * cascadeSize, cascadeSize, cascadeSize );
+        }
+
+        _shadowMapSize = mapSize;
+    }
+}
+
+void FGRenderer::enableShadows(bool enabled)
+{
+    for (   CameraGroup::CameraIterator ii = CameraGroup::getDefault()->camerasBegin();
+            ii != CameraGroup::getDefault()->camerasEnd();
+            ++ii )
+    {
+        CameraInfo* info = ii->get();
+        Camera* camera = info->getCamera(SHADOW_CAMERA);
+        if (camera == 0) continue;
+
+        osg::Switch* shadowSwitch = camera->getChild(0)->asSwitch();
+        if (enabled)
+            shadowSwitch->setAllChildrenOn();
+        else
+            shadowSwitch->setAllChildrenOff();
+    }
+}
+
+void FGRenderer::updateCascadeFar(int index, float far_m)
+{
+    if (index < 0 || index > 3)
+        return;
+    _cascadeFar[index] = far_m;
+    _shadowDistances->set( osg::Vec4f(_cascadeFar[0], _cascadeFar[1], _cascadeFar[2], _cascadeFar[3]) );
+}
+
+void FGRenderer::updateCascadeNumber(size_t num)
+{
+    if (num < 1 || num > 4)
+        return;
+    _numCascades = num;
+    _shadowNumber->set( (int)_numCascades );
+}
+
+
+#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 )
+{
+    osg::Camera* camera = new osg::Camera;
+    info->addCamera(flightgear::LIGHTING_CAMERA, camera );
+
+    camera->setCullCallback( new FGDeferredRenderingCameraCullCallback( flightgear::LIGHTING_CAMERA, info ) );
+    camera->setAllowEventFocus(false);
+    camera->setGraphicsContext(gc);
+    camera->setViewport(new Viewport);
+    camera->setName("LightingC");
+    camera->setReferenceFrame(osg::Transform::ABSOLUTE_RF);
+    camera->setRenderOrder(osg::Camera::POST_RENDER, 50);
+    camera->setRenderTargetImplementation( osg::Camera::FRAME_BUFFER_OBJECT );
+    camera->setViewport( new osg::Viewport );
+    attachBufferToCamera( info, camera, osg::Camera::DEPTH_BUFFER, flightgear::LIGHTING_CAMERA, flightgear::RenderBufferInfo::DEPTH_BUFFER );
+    attachBufferToCamera( info, camera, osg::Camera::COLOR_BUFFER, flightgear::LIGHTING_CAMERA, flightgear::RenderBufferInfo::LIGHTING_BUFFER );
+    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) );
+
+    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 );
+    ss->addUniform( info->projInverse );
+    ss->addUniform( info->viewInverse );
+    ss->addUniform( info->view );
+    ss->addUniform( _sunDiffuse );
+    ss->addUniform( _sunSpecular );
+    ss->addUniform( _sunDirection );
+    ss->addUniform( _planes );
+    ss->addUniform( _shadowNumber );
+    ss->addUniform( _shadowDistances );
+
+    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);
+    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->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 );
+
+    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 );
+
+    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 );
+
+    lightingGroup->addChild( _sky->getPreRoot() );
+    lightingGroup->addChild( _sky->getCloudRoot() );
+    lightingGroup->addChild( quadCam1 );
+    lightingGroup->addChild( lightCam );
+    lightingGroup->addChild( quadCam2 );
+
+    camera->addChild( lightingGroup );
+
+    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)
+{
+    CameraInfo* info = new CameraInfo(flags);
+       buildDeferredBuffers( info, _shadowMapSize, !fgGetBool("/sim/rendering/no-16bit-buffer", false ) );
+
+    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->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);
+    if (!effect) {
+        SG_LOG(SG_VIEW, SG_ALERT, "Effects/display not found");
+        return 0;
+    }
+    eg->setEffect(effect);
+    eg->setCullingActive(false);
+    eg->addDrawable(g);
+    camera->setViewMatrix(osg::Matrix::identity());
+    camera->setProjectionMatrixAsOrtho2D(-1,1,-1,1);
+    camera->addChild(eg);
+
+    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;
+}
+
+
+void
+FGRenderer::setupView( void )
+{
+    osgViewer::Viewer* viewer = globals->get_renderer()->getViewer();
+    osg::initNotifyLevel();
+
+    // 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);
+
+    // Go full screen if requested ...
+    if ( fgGetBool("/sim/startup/fullscreen") )
+        fgOSFullScreen();
+
+// 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);
+    
+    osg::StateSet* stateSet = mRoot->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);
+    hint = new osg::Hint(GL_POLYGON_SMOOTH_HINT, GL_DONT_CARE);
+    hint->setUpdateCallback(new FGHintUpdateCallback("/sim/rendering/polygon-smooth"));
+    stateSet->setAttribute(hint);
+    hint = new osg::Hint(GL_LINE_SMOOTH_HINT, GL_DONT_CARE);
+    hint->setUpdateCallback(new FGHintUpdateCallback("/sim/rendering/line-smooth"));
+    stateSet->setAttribute(hint);
+    hint = new osg::Hint(GL_POINT_SMOOTH_HINT, GL_DONT_CARE);
+    hint->setUpdateCallback(new FGHintUpdateCallback("/sim/rendering/point-smooth"));
+    stateSet->setAttribute(hint);
+    hint = new osg::Hint(GL_PERSPECTIVE_CORRECTION_HINT, GL_DONT_CARE);
+    hint->setUpdateCallback(new FGHintUpdateCallback("/sim/rendering/perspective-correction"));
+    stateSet->setAttribute(hint);
+
+    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);
+
+    // 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
+    // LightSource in the scene graph have the same light number, it's
+    // indeterminate which values will be used to render geometry that
+    // has that light number enabled. Also, adding children to a
+    // LightSource is just a shortcut for setting up a state set that
+    // 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;
+    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);
+    // we need a white diffuse light for the phase of the moon
+    osg::LightSource* sunLight = new osg::LightSource;
+    sunLight->getLight()->setDataVariance(Object::DYNAMIC);
+    sunLight->getLight()->setLightNum(1);
+    sunLight->setUpdateCallback(new FGLightSourceUpdateCallback(true));
+    sunLight->setReferenceFrame(osg::LightSource::RELATIVE_RF);
+    sunLight->setLocalStateSetModes(osg::StateAttribute::ON);
+    
+    // Hang a StateSet above the sky subgraph in order to turn off
+    // light 0
+    Group* skyGroup = new Group;
+    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);
+    stateSet->setMode(GL_LIGHTING, osg::StateAttribute::ON);
+    stateSet->setMode(GL_DEPTH_TEST, osg::StateAttribute::ON);
+
+    // enable disable specular highlights.
+    // is the place where we might plug in an other fragment shader ...
+    osg::LightModel* lightModel = new osg::LightModel;
+    lightModel->setUpdateCallback(new FGLightModelUpdateCallback);
+    stateSet->setAttribute(lightModel);
+
+    // switch to enable wireframe
+    osg::PolygonMode* polygonMode = new osg::PolygonMode;
+    polygonMode->setUpdateCallback(new FGWireFrameModeUpdateCallback);
+    stateSet->setAttributeAndModes(polygonMode);
+
+    // scene fog handling
+    osg::Fog* fog = new osg::Fog;
+    fog->setUpdateCallback(new FGFogUpdateCallback);
+    stateSet->setAttributeAndModes(fog);
+    stateSet->setUpdateCallback(new FGFogEnableUpdateCallback);
+
+    // plug in the GUI
+    osg::Camera* guiCamera = getGUICamera(CameraGroup::getDefault());
+    if (guiCamera) {
+        
+        osg::Geode* geode = new osg::Geode;
+        geode->addDrawable(new SGPuDrawable);
+        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());
+    }
+    
+    osg::Switch* sw = new osg::Switch;
+    sw->setUpdateCallback(new FGScenerySwitchCallback);
+    sw->addChild(mRoot.get());
+    mRealRoot->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());
+       }
+    // 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->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);
+    }
+}
+                                    
+// Update all Visuals (redraws anything graphics related)
+void
+FGRenderer::update( ) {
+    if (!(_scenery_loaded->getBoolValue() || 
+           _scenery_override->getBoolValue()))
+    {
+        _splash_alpha->setDoubleValue(1.0);
+        return;
+    }
+    osgViewer::Viewer* viewer = globals->get_renderer()->getViewer();
+
+    if (_splash_alpha->getDoubleValue()>0.0)
+    {
+        // Fade out the splash screen
+        const double fade_time = 0.5;
+        const double fade_steps_per_sec = 10;
+        double delay_time = SGMiscd::min(fade_time/fade_steps_per_sec,
+                                         (SGTimeStamp::now() - _splash_time).toSecs());
+        _splash_time = SGTimeStamp::now();
+        double sAlpha = _splash_alpha->getDoubleValue();
+        sAlpha -= SGMiscd::max(0.0,delay_time/fade_time);
+        FGScenerySwitchCallback::scenery_enabled = (sAlpha<1.0);
+        _splash_alpha->setDoubleValue((sAlpha < 0) ? 0.0 : sAlpha);
+    }
+
+    FGLight *l = static_cast<FGLight*>(globals->get_subsystem("lighting"));
+       if (!_classicalRenderer ) {
+               _ambientFactor->set( toOsg(l->scene_ambient()) );
+               _sunDiffuse->set( toOsg(l->scene_diffuse()) );
+               _sunSpecular->set( toOsg(l->scene_specular()) );
+               _sunDirection->set( osg::Vec3f(l->sun_vec()[0], l->sun_vec()[1], l->sun_vec()[2]) );
+       }
+
+    // update fog params
+    double actual_visibility;
+    if (_cloud_status->getBoolValue()) {
+        actual_visibility = _sky->get_visibility();
+    } else {
+        actual_visibility = _visibility_m->getDoubleValue();
+    }
+
+    // idle_state is now 1000 meaning we've finished all our
+    // initializations and are running the main loop, so this will
+    // now work without seg faulting the system.
+
+    FGViewer *current__view = globals->get_current_view();
+    // Force update of center dependent values ...
+    current__view->set_dirty();
+  
+    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();
+
+    // need to call the update visitor once
+    mFrameStamp->setCalendarTime(*globals->get_time_params()->getGmt());
+    mUpdateVisitor->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(),
+                             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());
+    osg::Node::NodeMask cullMask = ~simgear::LIGHTS_BITS & ~simgear::PICK_BIT;
+    cullMask |= simgear::GroundLightManager::instance()
+        ->getLightNodeMask(mUpdateVisitor.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() ) );
+       }
+}
+
+void
+FGRenderer::resize( int width, int height )
+{
+    int curWidth = _xsize->getIntValue(),
+        curHeight = _ysize->getIntValue();
+    SG_LOG(SG_VIEW, SG_DEBUG, "FGRenderer::resize: new size " << width << " x " << height);
+    if ((curHeight != height) || (curWidth != width)) {
+    // must guard setting these, or PLIB-PUI fails with too many live interfaces
+        _xsize->setIntValue(width);
+        _ysize->setIntValue(height);
+    }
+}
+
+bool
+FGRenderer::pick(std::vector<SGSceneryPick>& pickList,
+                 const osgGA::GUIEventAdapter* ea)
+{
+    // wipe out the return ...
+    pickList.clear();
+    typedef osgUtil::LineSegmentIntersector::Intersections Intersections;
+    Intersections intersections;
+
+    if (!computeIntersections(CameraGroup::getDefault(), ea, intersections))
+        return false;
+    for (Intersections::iterator hit = intersections.begin(),
+             e = intersections.end();
+         hit != e;
+         ++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)
+                continue;
+            for (unsigned i = 0; i < ud->getNumPickCallbacks(); ++i) {
+                SGPickCallback* pickCallback = ud->getPickCallback(i);
+                if (!pickCallback)
+                    continue;
+                SGSceneryPick sceneryPick;
+                sceneryPick.info.local = toSG(hit->getLocalIntersectPoint());
+                sceneryPick.info.wgs84 = toSG(hit->getWorldIntersectPoint());
+                sceneryPick.callback = pickCallback;
+                pickList.push_back(sceneryPick);
+            }
+        }
+    }
+    return !pickList.empty();
+}
+
+void
+FGRenderer::setViewer(osgViewer::Viewer* viewer_)
+{
+    viewer = viewer_;
+}
+
+void
+FGRenderer::setEventHandler(FGEventHandler* eventHandler_)
+{
+    eventHandler = eventHandler_;
+}
+
+void
+FGRenderer::addCamera(osg::Camera* camera, bool useSceneData)
+{
+    mRealRoot->addChild(camera);
+}
+
+void
+FGRenderer::removeCamera(osg::Camera* camera)
+{
+    mRealRoot->removeChild(camera);
+}
+                                    
+void
+FGRenderer::setPlanes( double zNear, double zFar )
+{
+       _planes->set( osg::Vec3f( - zFar, - zFar * zNear, zFar - zNear ) );
+}
+
+bool
+fgDumpSceneGraphToFile(const char* filename)
+{
+    return osgDB::writeNodeFile(*mRealRoot.get(), filename);
+}
+
+bool
+fgDumpTerrainBranchToFile(const char* filename)
+{
+    return osgDB::writeNodeFile( *globals->get_scenery()->get_terrain_branch(),
+                                 filename );
+}
+
+// For debugging
+bool
+fgDumpNodeToFile(osg::Node* node, const char* filename)
+{
+    return osgDB::writeNodeFile(*node, filename);
+}
+
+namespace flightgear
+{
+using namespace osg;
+
+class VisibleSceneInfoVistor : public NodeVisitor, CullStack
+{
+public:
+    VisibleSceneInfoVistor()
+        : NodeVisitor(CULL_VISITOR, TRAVERSE_ACTIVE_CHILDREN)
+    {
+        setCullingMode(CullSettings::SMALL_FEATURE_CULLING
+                       | CullSettings::VIEW_FRUSTUM_CULLING);
+        setComputeNearFarMode(CullSettings::DO_NOT_COMPUTE_NEAR_FAR);
+    }
+
+    VisibleSceneInfoVistor(const VisibleSceneInfoVistor& rhs)
+    {
+    }
+
+    META_NodeVisitor("flightgear","VisibleSceneInfoVistor")
+
+    typedef std::map<const std::string,int> InfoMap;
+
+    void getNodeInfo(Node* node)
+    {
+        const char* typeName = typeid(*node).name();
+        classInfo[typeName]++;
+        const std::string& nodeName = node->getName();
+        if (!nodeName.empty())
+            nodeInfo[nodeName]++;
+    }
+
+    void dumpInfo()
+    {
+        using namespace std;
+        typedef vector<InfoMap::iterator> FreqVector;
+        cout << "class info:\n";
+        FreqVector classes;
+        for (InfoMap::iterator itr = classInfo.begin(), end = classInfo.end();
+             itr != end;
+             ++itr)
+            classes.push_back(itr);
+        sort(classes.begin(), classes.end(), freqComp);
+        for (FreqVector::iterator itr = classes.begin(), end = classes.end();
+             itr != end;
+             ++itr) {
+            cout << (*itr)->first << " " << (*itr)->second << "\n";
+        }
+        cout << "\nnode info:\n";
+        FreqVector nodes;
+        for (InfoMap::iterator itr = nodeInfo.begin(), end = nodeInfo.end();
+             itr != end;
+             ++itr)
+            nodes.push_back(itr);
+
+        sort (nodes.begin(), nodes.end(), freqComp);
+        for (FreqVector::iterator itr = nodes.begin(), end = nodes.end();
+             itr != end;
+             ++itr) {
+            cout << (*itr)->first << " " << (*itr)->second << "\n";
+        }
+        cout << endl;
+    }
+    
+    void doTraversal(Camera* camera, Node* root, Viewport* viewport)
+    {
+        ref_ptr<RefMatrix> projection
+            = createOrReuseMatrix(camera->getProjectionMatrix());
+        ref_ptr<RefMatrix> mv = createOrReuseMatrix(camera->getViewMatrix());
+        if (!viewport)
+            viewport = camera->getViewport();
+        if (viewport)
+            pushViewport(viewport);
+        pushProjectionMatrix(projection.get());
+        pushModelViewMatrix(mv.get(), Transform::ABSOLUTE_RF);
+        root->accept(*this);
+        popModelViewMatrix();
+        popProjectionMatrix();
+        if (viewport)
+            popViewport();
+        dumpInfo();
+    }
+
+    void apply(Node& node)
+    {
+        if (isCulled(node))
+            return;
+        pushCurrentMask();
+        getNodeInfo(&node);
+        traverse(node);
+        popCurrentMask();
+    }
+    void apply(Group& node)
+    {
+        if (isCulled(node))
+            return;
+        pushCurrentMask();
+        getNodeInfo(&node);
+        traverse(node);
+        popCurrentMask();
+    }
+
+    void apply(Transform& node)
+    {
+        if (isCulled(node))
+            return;
+        pushCurrentMask();
+        ref_ptr<RefMatrix> matrix = createOrReuseMatrix(*getModelViewMatrix());
+        node.computeLocalToWorldMatrix(*matrix,this);
+        pushModelViewMatrix(matrix.get(), node.getReferenceFrame());
+        getNodeInfo(&node);
+        traverse(node);
+        popModelViewMatrix();
+        popCurrentMask();
+    }
+
+    void apply(Camera& camera)
+    {
+        // Save current cull settings
+        CullSettings saved_cull_settings(*this);
+
+        // set cull settings from this Camera
+        setCullSettings(camera);
+        // inherit the settings from above
+        inheritCullSettings(saved_cull_settings, camera.getInheritanceMask());
+
+        // set the cull mask.
+        unsigned int savedTraversalMask = getTraversalMask();
+        bool mustSetCullMask = (camera.getInheritanceMask()
+                                & osg::CullSettings::CULL_MASK) == 0;
+        if (mustSetCullMask)
+            setTraversalMask(camera.getCullMask());
+
+        osg::RefMatrix* projection = 0;
+        osg::RefMatrix* modelview = 0;
+
+        if (camera.getReferenceFrame()==osg::Transform::RELATIVE_RF) {
+            if (camera.getTransformOrder()==osg::Camera::POST_MULTIPLY) {
+                projection = createOrReuseMatrix(*getProjectionMatrix()
+                                                 *camera.getProjectionMatrix());
+                modelview = createOrReuseMatrix(*getModelViewMatrix()
+                                                * camera.getViewMatrix());
+            }
+            else {              // pre multiply 
+                projection = createOrReuseMatrix(camera.getProjectionMatrix()
+                                                 * (*getProjectionMatrix()));
+                modelview = createOrReuseMatrix(camera.getViewMatrix()
+                                                * (*getModelViewMatrix()));
+            }
+        } else {
+            // an absolute reference frame
+            projection = createOrReuseMatrix(camera.getProjectionMatrix());
+            modelview = createOrReuseMatrix(camera.getViewMatrix());
+        }
+        if (camera.getViewport())
+            pushViewport(camera.getViewport());
+
+        pushProjectionMatrix(projection);
+        pushModelViewMatrix(modelview, camera.getReferenceFrame());    
+
+        traverse(camera);
+    
+        // restore the previous model view matrix.
+        popModelViewMatrix();
+
+        // restore the previous model view matrix.
+        popProjectionMatrix();
+
+        if (camera.getViewport()) popViewport();
+
+        // restore the previous traversal mask settings
+        if (mustSetCullMask)
+            setTraversalMask(savedTraversalMask);
+
+        // restore the previous cull settings
+        setCullSettings(saved_cull_settings);
+    }
+
+protected:
+    // sort in reverse
+    static bool freqComp(const InfoMap::iterator& lhs, const InfoMap::iterator& rhs)
+    {
+        return lhs->second > rhs->second;
+    }
+    InfoMap classInfo;
+    InfoMap nodeInfo;
+};
+
+bool printVisibleSceneInfo(FGRenderer* renderer)
+{
+    osgViewer::Viewer* viewer = renderer->getViewer();
+    VisibleSceneInfoVistor vsv;
+    Viewport* vp = 0;
+    if (!viewer->getCamera()->getViewport() && viewer->getNumSlaves() > 0) {
+        const View::Slave& slave = viewer->getSlave(0);
+        vp = slave._camera->getViewport();
+    }
+    vsv.doTraversal(viewer->getCamera(), viewer->getSceneData(), vp);
+    return true;
+}
+
+}
+// end of renderer.cxx
+    
diff --git a/src/Viewer/renderer.hxx b/src/Viewer/renderer.hxx
new file mode 100644 (file)
index 0000000..fa089bc
--- /dev/null
@@ -0,0 +1,165 @@
+
+#ifndef __FG_RENDERER_HXX
+#define __FG_RENDERER_HXX 1
+
+#include <simgear/scene/util/SGPickCallback.hxx>
+#include <simgear/props/props.hxx>
+#include <simgear/timing/timestamp.hxx>
+
+#include <osg/ref_ptr>
+#include <osg/Matrix>
+#include <osg/Vec3>
+
+namespace osg
+{
+class Camera;
+class Group;
+class GraphicsContext;
+}
+
+namespace osgGA
+{
+class GUIEventAdapter;
+}
+
+namespace osgShadow
+{
+class ShadowedScene;
+}
+
+namespace osgViewer
+{
+class Viewer;
+}
+
+namespace flightgear
+{
+class FGEventHandler;
+struct CameraInfo;
+class CameraGroup;
+}
+
+class SGSky;
+
+class FGRenderer {
+
+public:
+
+    FGRenderer();
+    ~FGRenderer();
+
+    void splashinit();
+    void init();
+
+    void setupView();
+
+    void resize(int width, int height );
+
+    void update();
+  
+    /** Just pick into the scene and return the pick callbacks on the way ...
+     */
+    bool pick( std::vector<SGSceneryPick>& pickList,
+               const osgGA::GUIEventAdapter* ea );
+
+    /** Get and set the OSG Viewer object, if any.
+     */
+    osgViewer::Viewer* getViewer() { return viewer.get(); }
+    const osgViewer::Viewer* getViewer() const { return viewer.get(); }
+    void setViewer(osgViewer::Viewer* viewer);
+    /** Get and set the manipulator object, if any.
+     */
+    flightgear::FGEventHandler* getEventHandler() { return eventHandler.get(); }
+    const flightgear::FGEventHandler* getEventHandler() const { return eventHandler.get(); }
+    void setEventHandler(flightgear::FGEventHandler* manipulator);
+
+    /** Add a top level camera.
+     */
+    void addCamera(osg::Camera* camera, bool useSceneData);
+
+    void removeCamera(osg::Camera* camera);
+  
+    /** Add a camera to the group. The camera is added to the viewer
+     * as a slave. See osgViewer::Viewer::addSlave.
+     * @param flags properties of the camera; see CameraGroup::Flags
+     * @param projection slave projection matrix
+     * @param view slave view matrix
+     * @param useMasterSceneData whether the camera displays the
+     * viewer's scene data.
+     * @return a CameraInfo object for the camera.
+     */
+       flightgear::CameraInfo* buildRenderingPipeline(flightgear::CameraGroup* cgroup, unsigned flags, osg::Camera* camera,
+                                   const osg::Matrix& view,
+                                   const osg::Matrix& projection,
+                                                                  osg::GraphicsContext* gc,
+                                   bool useMasterSceneData);
+
+       /**
+        */
+       flightgear::CameraInfo* buildClassicalPipeline(flightgear::CameraGroup* cgroup, unsigned flags, osg::Camera* camera,
+                                   const osg::Matrix& view,
+                                   const osg::Matrix& projection,
+                                   bool useMasterSceneData);
+
+       /**
+        */
+       flightgear::CameraInfo* buildDeferredPipeline(flightgear::CameraGroup* cgroup, unsigned flags, osg::Camera* camera,
+                                   const osg::Matrix& view, const osg::Matrix& projection, osg::GraphicsContext* gc);
+
+    void updateShadowCamera(const flightgear::CameraInfo* info, const osg::Vec3d& position);
+    void updateShadowMapSize(int mapSize);
+    void enableShadows(bool enabled);
+    void updateCascadeFar(int index, float far_m);
+    void updateCascadeNumber(size_t num);
+
+    SGSky* getSky() const { return _sky; }
+
+       void setPlanes( double zNear, double zFar );
+    
+    /**
+     * inform the renderer when the global (2D) panel is changed
+     */
+    void panelChanged();
+protected:
+    osg::ref_ptr<osgViewer::Viewer> viewer;
+    osg::ref_ptr<flightgear::FGEventHandler> eventHandler;
+    SGPropertyNode_ptr _scenery_loaded,_scenery_override;
+    SGPropertyNode_ptr _skyblend, _splash_alpha;
+    SGPropertyNode_ptr _point_sprites, _enhanced_lighting, _distance_attenuation;
+    SGPropertyNode_ptr _textures;
+    SGPropertyNode_ptr _cloud_status, _visibility_m; 
+    SGPropertyNode_ptr _xsize, _ysize;
+    SGPropertyNode_ptr _panel_hotspots, _sim_delta_sec, _horizon_effect, _altitude_ft;
+    SGPropertyNode_ptr _virtual_cockpit;
+    SGTimeStamp _splash_time;
+    SGSky* _sky;
+    bool _classicalRenderer;
+    int _shadowMapSize;
+    size_t _numCascades;
+    float _cascadeFar[4];
+
+    osg::Camera* buildDeferredGeometryCamera( flightgear::CameraInfo* info, osg::GraphicsContext* gc );
+    osg::Camera* buildDeferredShadowCamera( flightgear::CameraInfo* info, osg::GraphicsContext* gc );
+    osg::Camera* buildDeferredLightingCamera( flightgear::CameraInfo* info, osg::GraphicsContext* gc );
+    void updateShadowCascade(const flightgear::CameraInfo* info, osg::Camera* camera, osg::Group* grp, int idx, double left, double right, double bottom, double top, double zNear, double f1, double f2);
+    osg::Vec3 getSunDirection() const;
+    osg::ref_ptr<osg::Uniform> _ambientFactor;
+    osg::ref_ptr<osg::Uniform> _sunDiffuse;
+    osg::ref_ptr<osg::Uniform> _sunSpecular;
+    osg::ref_ptr<osg::Uniform> _sunDirection;
+    osg::ref_ptr<osg::Uniform> _planes;
+    osg::ref_ptr<osg::Uniform> _fogColor;
+    osg::ref_ptr<osg::Uniform> _fogDensity;
+    osg::ref_ptr<osg::Uniform> _shadowNumber;
+    osg::ref_ptr<osg::Uniform> _shadowDistances;
+};
+
+bool fgDumpSceneGraphToFile(const char* filename);
+bool fgDumpTerrainBranchToFile(const char* filename);
+
+namespace flightgear
+{
+bool printVisibleSceneInfo(FGRenderer* renderer);
+}
+
+#endif
diff --git a/src/Viewer/splash.cxx b/src/Viewer/splash.cxx
new file mode 100644 (file)
index 0000000..78d79aa
--- /dev/null
@@ -0,0 +1,376 @@
+// splash.cxx -- draws the initial splash screen
+//
+// Written by Curtis Olson, started July 1998.  (With a little looking
+// at Freidemann's panel code.) :-)
+//
+// Copyright (C) 1997  Michele F. America  - nomimarketing@mail.telepac.pt
+//
+// This program is free software; you can redistribute it and/or
+// modify it under the terms of the GNU General Public License as
+// published by the Free Software Foundation; either version 2 of the
+// License, or (at your option) any later version.
+//
+// This program is distributed in the hope that it will be useful, but
+// WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+// General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License
+// along with this program; if not, write to the Free Software
+// Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
+//
+// $Id$
+
+
+#ifdef HAVE_CONFIG_H
+#  include <config.h>
+#endif
+
+#include <osg/BlendFunc>
+#include <osg/Camera>
+#include <osg/Depth>
+#include <osg/Geometry>
+#include <osg/Node>
+#include <osg/NodeCallback>
+#include <osg/NodeVisitor>
+#include <osg/StateSet>
+#include <osg/Switch>
+#include <osg/Texture2D>
+#include <osgUtil/CullVisitor>
+#include <osgText/Text>
+#include <osgDB/ReadFile>
+
+#include <simgear/compiler.h>
+
+#include <simgear/debug/logstream.hxx>
+#include <simgear/math/sg_random.h>
+#include <simgear/misc/sg_path.hxx>
+
+#include <plib/fnt.h>
+
+#include "GUI/FGFontCache.hxx"
+#include "GUI/FGColor.hxx"
+
+#include <Main/globals.hxx>
+#include <Main/fg_props.hxx>
+#include <Main/fg_os.hxx>
+#include "splash.hxx"
+#include "renderer.hxx"
+
+class FGSplashUpdateCallback : public osg::Drawable::UpdateCallback {
+public:
+  FGSplashUpdateCallback(osg::Vec4Array* colorArray, SGPropertyNode* prop) :
+    _colorArray(colorArray),
+    _colorProperty(prop),
+    _alphaProperty(fgGetNode("/sim/startup/splash-alpha", true))
+  { }
+  virtual void update(osg::NodeVisitor*, osg::Drawable*)
+  {
+    FGColor c(0, 0, 0);
+    if (_colorProperty) {
+      c.merge(_colorProperty);
+      (*_colorArray)[0][0] = c.red();
+      (*_colorArray)[0][1] = c.green();
+      (*_colorArray)[0][2] = c.blue();
+    }
+    (*_colorArray)[0][3] = _alphaProperty->getFloatValue();
+    _colorArray->dirty();
+  }
+private:
+  osg::ref_ptr<osg::Vec4Array> _colorArray;
+  SGSharedPtr<const SGPropertyNode> _colorProperty;
+  SGSharedPtr<const SGPropertyNode> _alphaProperty;
+};
+
+class FGSplashTextUpdateCallback : public osg::Drawable::UpdateCallback {
+public:
+  FGSplashTextUpdateCallback(const SGPropertyNode* prop) :
+    _textProperty(prop),
+    _alphaProperty(fgGetNode("/sim/startup/splash-alpha", true)),
+    _styleProperty(fgGetNode("/sim/gui/style[0]", true))
+  {}
+  virtual void update(osg::NodeVisitor*, osg::Drawable* drawable)
+  {
+    assert(dynamic_cast<osgText::Text*>(drawable));
+    osgText::Text* text = static_cast<osgText::Text*>(drawable);
+
+    FGColor c(1.0, 0.9, 0.0);
+    c.merge(_styleProperty->getNode("colors/splash-font"));
+    float alpha = _alphaProperty->getFloatValue();
+    text->setColor(osg::Vec4(c.red(), c.green(), c.blue(), alpha));
+
+    const char* s = _textProperty->getStringValue();
+    if (s && fgGetBool("/sim/startup/splash-progress", true))
+      text->setText(s);
+    else
+      text->setText("");
+  }
+private:
+  SGSharedPtr<const SGPropertyNode> _textProperty;
+  SGSharedPtr<const SGPropertyNode> _alphaProperty;
+  SGSharedPtr<const SGPropertyNode> _styleProperty;
+};
+
+
+
+class FGSplashContentProjectionCalback : public osg::NodeCallback {
+public:
+  virtual void operator()(osg::Node* node, osg::NodeVisitor* nv)
+  { 
+    assert(dynamic_cast<osgUtil::CullVisitor*>(nv));
+    osgUtil::CullVisitor* cullVisitor = static_cast<osgUtil::CullVisitor*>(nv);
+
+    // adjust the projection matrix in a way that preserves the aspect ratio
+    // of the content ...
+    const osg::Viewport* viewport = cullVisitor->getViewport();
+    float viewportAspect = float(viewport->height())/float(viewport->width());
+
+    float height, width;
+    if (viewportAspect < 1) {
+      height = 1;
+      width = 1/viewportAspect;
+    } else {
+      height = viewportAspect;
+      width = 1;
+    }
+
+    osg::RefMatrix* matrix = new osg::RefMatrix;
+    matrix->makeOrtho2D(-width, width, -height, height);
+
+    // The trick is to have the projection matrix adapted independent
+    // of the scenegraph but dependent on the viewport of this current
+    // camera we cull for. Therefore we do not put that projection matrix into
+    // an additional camera rather than from within that cull callback.
+    cullVisitor->pushProjectionMatrix(matrix);
+    traverse(node, nv);
+    cullVisitor->popProjectionMatrix();
+  }
+};
+
+char *genNameString()
+{
+    std::string website = "http://www.flightgear.org";
+    std::string programName = "FlightGear";
+    char *name = new char[26];
+    name[20] = 114;
+    name[8] = 119;
+    name[5] = 47;
+    name[12] = 108;
+    name[2] = 116;
+    name[1] = 116;
+    name[16] = 116;
+    name[13] = 105;
+    name[17] = 103;
+    name[19] = 97;
+    name[25] = 0;
+    name[0] = 104;
+    name[24] = 103;
+    name[21] = 46;
+    name[15] = 104;
+    name[3] = 112;
+    name[22] = 111;
+    name[18] = 101;
+    name[7] = 119;
+    name[14] = 103;
+    name[23] = 114;
+    name[4] = 58;
+    name[11] = 102;
+    name[9] = 119;
+    name[10] = 46;
+    name[6] = 47;
+    return name;
+}
+
+static osg::Node* fgCreateSplashCamera()
+{
+  const char* splash_texture = fgGetString("/sim/startup/splash-texture");
+  SGSharedPtr<SGPropertyNode> style = fgGetNode("/sim/gui/style[0]", true);
+
+  char *namestring = genNameString();
+  fgSetString("/sim/startup/program-name", namestring);
+  delete[] namestring;
+
+  SGPath tpath;
+  if (splash_texture  && strcmp(splash_texture, "")) {
+      tpath = globals->resolve_maybe_aircraft_path(splash_texture);
+      if (tpath.isNull())
+      {
+          SG_LOG( SG_VIEW, SG_ALERT, "Cannot find splash screen file '" << splash_texture
+                  << "'. Using default." );
+      }
+  }
+
+  if (tpath.isNull()) {
+    // no splash screen specified - select random image
+    tpath = globals->get_fg_root();
+    // load in the texture data
+    int num = (int)(sg_random() * 5.0 + 1.0);
+    char num_str[5];
+    snprintf(num_str, 4, "%d", num);
+
+    tpath.append( "Textures/Splash" );
+    tpath.concat( num_str );
+    tpath.concat( ".png" );
+  }
+
+  osg::Texture2D* splashTexture = new osg::Texture2D;
+  splashTexture->setImage(osgDB::readImageFile(tpath.c_str()));
+
+  osg::Camera* camera = new osg::Camera;
+  camera->setReferenceFrame(osg::Transform::ABSOLUTE_RF);
+  camera->setProjectionMatrix(osg::Matrix::ortho2D(-1, 1, -1, 1));
+  camera->setViewMatrix(osg::Matrix::identity());
+  camera->setRenderOrder(osg::Camera::POST_RENDER, 10000);
+  camera->setClearMask(0);
+  camera->setAllowEventFocus(false);
+  camera->setCullingActive(false);
+
+  osg::StateSet* stateSet = camera->getOrCreateStateSet();
+  stateSet->setMode(GL_ALPHA_TEST, osg::StateAttribute::OFF);
+  stateSet->setMode(GL_BLEND, osg::StateAttribute::ON);
+  stateSet->setAttribute(new osg::BlendFunc);
+  stateSet->setMode(GL_CULL_FACE, osg::StateAttribute::OFF);
+  stateSet->setMode(GL_DEPTH_TEST, osg::StateAttribute::OFF);
+  stateSet->setAttribute(new osg::Depth(osg::Depth::ALWAYS, 0, 1, false));
+  stateSet->setMode(GL_LIGHTING, osg::StateAttribute::OFF);
+
+
+  osg::Geometry* geometry = new osg::Geometry;
+  geometry->setSupportsDisplayList(false);
+
+  osg::Vec3Array* vertexArray = new osg::Vec3Array;
+  vertexArray->push_back(osg::Vec3(-1, -1, 0));
+  vertexArray->push_back(osg::Vec3( 1, -1, 0));
+  vertexArray->push_back(osg::Vec3( 1,  1, 0));
+  vertexArray->push_back(osg::Vec3(-1,  1, 0));
+  geometry->setVertexArray(vertexArray);
+  osg::Vec4Array* colorArray = new osg::Vec4Array;
+  colorArray->push_back(osg::Vec4(0, 0, 0, 1));
+  geometry->setColorArray(colorArray);
+  geometry->setColorBinding(osg::Geometry::BIND_OVERALL);
+  geometry->addPrimitiveSet(new osg::DrawArrays(GL_POLYGON, 0, 4));
+  geometry->setUpdateCallback(new FGSplashUpdateCallback(colorArray,
+                              style->getNode("colors/splash-screen")));
+
+  osg::Geode* geode = new osg::Geode;
+  geode->addDrawable(geometry);
+
+  stateSet = geode->getOrCreateStateSet();
+  stateSet->setRenderBinDetails(1, "RenderBin");
+  camera->addChild(geode);
+
+
+  // The group is needed because of osg is handling the cull callbacks in a
+  // different way for groups than for a geode. It does not hurt here ...
+  osg::Group* group = new osg::Group;
+  group->setCullCallback(new FGSplashContentProjectionCalback);
+  camera->addChild(group);
+
+  geode = new osg::Geode;
+  stateSet = geode->getOrCreateStateSet();
+  stateSet->setRenderBinDetails(2, "RenderBin");
+  group->addChild(geode);
+
+
+  geometry = new osg::Geometry;
+  geometry->setSupportsDisplayList(false);
+
+  vertexArray = new osg::Vec3Array;
+  vertexArray->push_back(osg::Vec3(-0.84, -0.84, 0));
+  vertexArray->push_back(osg::Vec3( 0.84, -0.84, 0));
+  vertexArray->push_back(osg::Vec3( 0.84,  0.84, 0));
+  vertexArray->push_back(osg::Vec3(-0.84,  0.84, 0));
+  geometry->setVertexArray(vertexArray);
+  osg::Vec2Array* texCoordArray = new osg::Vec2Array;
+  texCoordArray->push_back(osg::Vec2(0, 0));
+  texCoordArray->push_back(osg::Vec2(1, 0));
+  texCoordArray->push_back(osg::Vec2(1, 1));
+  texCoordArray->push_back(osg::Vec2(0, 1));
+  geometry->setTexCoordArray(0, texCoordArray);
+  colorArray = new osg::Vec4Array;
+  colorArray->push_back(osg::Vec4(1, 1, 1, 1));
+  geometry->setColorArray(colorArray);
+  geometry->setColorBinding(osg::Geometry::BIND_OVERALL);
+  geometry->addPrimitiveSet(new osg::DrawArrays(GL_POLYGON, 0, 4));
+  geometry->setUpdateCallback(new FGSplashUpdateCallback(colorArray, 0));
+  stateSet = geometry->getOrCreateStateSet();
+  stateSet->setTextureMode(0, GL_TEXTURE_2D, osg::StateAttribute::ON);
+  stateSet->setTextureAttribute(0, splashTexture);
+  geode->addDrawable(geometry);
+
+
+  osgText::Text* text = new osgText::Text;
+  std::string fn = style->getStringValue("fonts/splash", "");
+  text->setFont(globals->get_fontcache()->getfntpath(fn.c_str()).str());
+  text->setCharacterSize(0.06);
+  text->setColor(osg::Vec4(1, 1, 1, 1));
+  text->setPosition(osg::Vec3(0, -0.92, 0));
+  text->setAlignment(osgText::Text::CENTER_CENTER);
+  SGPropertyNode* prop = fgGetNode("/sim/startup/splash-progress-text", true);
+  prop->setStringValue("initializing");
+  text->setUpdateCallback(new FGSplashTextUpdateCallback(prop));
+  geode->addDrawable(text);
+
+  text = new osgText::Text;
+  text->setFont(globals->get_fontcache()->getfntpath(fn.c_str()).str());
+  text->setCharacterSize(0.08);
+  text->setColor(osg::Vec4(1, 1, 1, 1));
+  text->setPosition(osg::Vec3(0, 0.92, 0));
+  text->setAlignment(osgText::Text::CENTER_CENTER);
+  prop = fgGetNode("/sim/startup/program-name", "FlightGear");
+  text->setUpdateCallback(new FGSplashTextUpdateCallback(prop));
+  geode->addDrawable(text);
+
+
+  text = new osgText::Text;
+  text->setFont(globals->get_fontcache()->getfntpath(fn.c_str()).str());
+  text->setCharacterSize(0.06);
+  text->setColor(osg::Vec4(1, 1, 1, 1));
+  text->setPosition(osg::Vec3(0, 0.82, 0));
+  text->setAlignment(osgText::Text::CENTER_CENTER);
+  prop = fgGetNode("/sim/startup/splash-title", true);
+  text->setUpdateCallback(new FGSplashTextUpdateCallback(prop));
+  geode->addDrawable(text);
+
+  return camera;
+}
+
+// update callback for the switch node guarding that splash
+class FGSplashGroupUpdateCallback : public osg::NodeCallback {
+public:
+  FGSplashGroupUpdateCallback() :
+    _splashAlphaNode(fgGetNode("/sim/startup/splash-alpha", true))
+  { }
+  virtual void operator()(osg::Node* node, osg::NodeVisitor* nv)
+  {
+    assert(dynamic_cast<osg::Group*>(node));
+    osg::Group* group = static_cast<osg::Group*>(node);
+
+    double alpha = _splashAlphaNode->getDoubleValue();
+    if (alpha <= 0 || !fgGetBool("/sim/startup/splash-screen"))
+      group->removeChild(0, group->getNumChildren());
+    else if (group->getNumChildren() == 0)
+      group->addChild(fgCreateSplashCamera());
+
+    traverse(node, nv);
+  }
+private:
+  SGSharedPtr<const SGPropertyNode> _splashAlphaNode;
+};
+
+osg::Node* fgCreateSplashNode() {
+  osg::Group* group = new osg::Group;
+  group->setUpdateCallback(new FGSplashGroupUpdateCallback);
+  return group;
+}
+
+// Initialize the splash screen
+void fgSplashInit () {
+  SG_LOG( SG_VIEW, SG_INFO, "Initializing splash screen" );
+  globals->get_renderer()->splashinit();
+}
+
+void fgSplashProgress ( const char *text ) {
+  SG_LOG( SG_VIEW, SG_INFO, "Splash screen progress " << text );
+  fgSetString("/sim/startup/splash-progress-text", text);
+}
diff --git a/src/Viewer/splash.hxx b/src/Viewer/splash.hxx
new file mode 100644 (file)
index 0000000..30643c2
--- /dev/null
@@ -0,0 +1,45 @@
+// splash.hxx -- draws the initial splash screen
+//
+// Written by Curtis Olson, started July 1998.  (With a little looking
+// at Freidemann's panel code.) :-)
+//
+// Copyright (C) 1997  Michele F. America  - nomimarketing@mail.telepac.pt
+//
+// This program is free software; you can redistribute it and/or
+// modify it under the terms of the GNU General Public License as
+// published by the Free Software Foundation; either version 2 of the
+// License, or (at your option) any later version.
+//
+// This program is distributed in the hope that it will be useful, but
+// WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+// General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License
+// along with this program; if not, write to the Free Software
+// Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
+//
+// $Id$
+
+
+#ifndef _SPLASH_HXX
+#define _SPLASH_HXX
+
+#include <osg/Node>
+
+#ifndef __cplusplus
+# error This library requires C++
+#endif
+
+// Initialize the splash screen
+void fgSplashInit ();
+
+// Set progress information
+void fgSplashProgress ( const char *text );
+
+// Retrieve the splash screen node ...
+osg::Node* fgCreateSplashNode();
+
+#endif // _SPLASH_HXX
+
+
diff --git a/src/Viewer/viewer.cxx b/src/Viewer/viewer.cxx
new file mode 100644 (file)
index 0000000..d26b282
--- /dev/null
@@ -0,0 +1,679 @@
+// viewer.cxx -- class for managing a viewer in the flightgear world.
+//
+// Written by Curtis Olson, started August 1997.
+//                          overhaul started October 2000.
+//   partially rewritten by Jim Wilson jim@kelcomaine.com using interface
+//                          by David Megginson March 2002
+//
+// Copyright (C) 1997 - 2000  Curtis L. Olson  - http://www.flightgear.org/~curt
+//
+// This program is free software; you can redistribute it and/or
+// modify it under the terms of the GNU General Public License as
+// published by the Free Software Foundation; either version 2 of the
+// License, or (at your option) any later version.
+//
+// This program is distributed in the hope that it will be useful, but
+// WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+// General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License
+// along with this program; if not, write to the Free Software
+// Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
+//
+// $Id$
+
+#ifdef HAVE_CONFIG_H
+#  include "config.h"
+#endif
+
+#include <simgear/compiler.h>
+#include <cassert>
+
+#include <simgear/debug/logstream.hxx>
+#include <simgear/constants.h>
+#include <simgear/scene/model/placement.hxx>
+#include <simgear/scene/util/OsgMath.hxx>
+
+#include <Main/fg_props.hxx>
+#include <Main/globals.hxx>
+#include <Scenery/scenery.hxx>
+#include <Model/acmodel.hxx>
+
+#include "viewer.hxx"
+
+#include "CameraGroup.hxx"
+
+using namespace flightgear;
+\f
+////////////////////////////////////////////////////////////////////////
+// Implementation of FGViewer.
+////////////////////////////////////////////////////////////////////////
+
+// Constructor...
+FGViewer::FGViewer( fgViewType Type, bool from_model, int from_model_index,
+                    bool at_model, int at_model_index,
+                    double damp_roll, double damp_pitch, double damp_heading,
+                    double x_offset_m, double y_offset_m, double z_offset_m,
+                    double heading_offset_deg, double pitch_offset_deg,
+                    double roll_offset_deg,
+                    double fov_deg, double aspect_ratio_multiplier,
+                    double target_x_offset_m, double target_y_offset_m,
+                    double target_z_offset_m, double near_m, bool internal ):
+    _dirty(true),
+    _roll_deg(0),
+    _pitch_deg(0),
+    _heading_deg(0),
+    _scaling_type(FG_SCALING_MAX),
+    _cameraGroup(CameraGroup::getDefault())
+{
+    _absolute_view_pos = SGVec3d(0, 0, 0);
+    _type = Type;
+    _from_model = from_model;
+    _from_model_index = from_model_index;
+    _at_model = at_model;
+    _at_model_index = at_model_index;
+
+    _internal = internal;
+
+    _dampFactor = SGVec3d::zeros();
+    _dampOutput = SGVec3d::zeros();
+    _dampTarget = SGVec3d::zeros();
+    
+    if (damp_roll > 0.0)
+      _dampFactor[0] = 1.0 / pow(10.0, fabs(damp_roll));
+    if (damp_pitch > 0.0)
+      _dampFactor[1] = 1.0 / pow(10.0, fabs(damp_pitch));
+    if (damp_heading > 0.0)
+      _dampFactor[2] = 1.0 / pow(10.0, fabs(damp_heading));
+
+    _offset_m.x() = x_offset_m;
+    _offset_m.y() = y_offset_m;
+    _offset_m.z() = z_offset_m;
+    _heading_offset_deg = heading_offset_deg;
+    _pitch_offset_deg = pitch_offset_deg;
+    _roll_offset_deg = roll_offset_deg;
+    _goal_heading_offset_deg = heading_offset_deg;
+    _goal_pitch_offset_deg = pitch_offset_deg;
+    _goal_roll_offset_deg = roll_offset_deg;
+    if (fov_deg > 0) {
+      _fov_deg = fov_deg;
+    } else {
+      _fov_deg = 55;
+    }
+
+    _aspect_ratio_multiplier = aspect_ratio_multiplier;
+    _target_offset_m.x() = target_x_offset_m;
+    _target_offset_m.y() = target_y_offset_m;
+    _target_offset_m.z() = target_z_offset_m;
+    _ground_level_nearplane_m = near_m;
+    // a reasonable guess for init, so that the math doesn't blow up
+}
+
+
+// Destructor
+FGViewer::~FGViewer( void ) {
+}
+
+void
+FGViewer::init ()
+{
+}
+
+void
+FGViewer::bind ()
+{
+}
+
+void
+FGViewer::unbind ()
+{
+}
+
+void
+FGViewer::setType ( int type )
+{
+  if (type == 0)
+    _type = FG_LOOKFROM;
+  if (type == 1)
+    _type = FG_LOOKAT;
+}
+
+void
+FGViewer::setInternal ( bool internal )
+{
+  _internal = internal;
+}
+
+void
+FGViewer::setPosition (double lon_deg, double lat_deg, double alt_ft)
+{
+  _dirty = true;
+  _position = SGGeod::fromDegFt(lon_deg, lat_deg, alt_ft);
+}
+
+void
+FGViewer::setTargetPosition (double lon_deg, double lat_deg, double alt_ft)
+{
+  _dirty = true;
+  _target = SGGeod::fromDegFt(lon_deg, lat_deg, alt_ft);
+}
+
+void
+FGViewer::setRoll_deg (double roll_deg)
+{
+  _dirty = true;
+  _roll_deg = roll_deg;
+}
+
+void
+FGViewer::setPitch_deg (double pitch_deg)
+{
+  _dirty = true;
+  _pitch_deg = pitch_deg;
+}
+
+void
+FGViewer::setHeading_deg (double heading_deg)
+{
+  _dirty = true;
+  _heading_deg = heading_deg;
+}
+
+void
+FGViewer::setOrientation (double roll_deg, double pitch_deg, double heading_deg)
+{
+  _dirty = true;
+  _roll_deg = roll_deg;
+  _pitch_deg = pitch_deg;
+  _heading_deg = heading_deg;
+}
+
+void
+FGViewer::setTargetRoll_deg (double target_roll_deg)
+{
+  _dirty = true;
+  _target_roll_deg = target_roll_deg;
+}
+
+void
+FGViewer::setTargetPitch_deg (double target_pitch_deg)
+{
+  _dirty = true;
+  _target_pitch_deg = target_pitch_deg;
+}
+
+void
+FGViewer::setTargetHeading_deg (double target_heading_deg)
+{
+  _dirty = true;
+  _target_heading_deg = target_heading_deg;
+}
+
+void
+FGViewer::setTargetOrientation (double target_roll_deg, double target_pitch_deg, double target_heading_deg)
+{
+  _dirty = true;
+  _target_roll_deg = target_roll_deg;
+  _target_pitch_deg = target_pitch_deg;
+  _target_heading_deg = target_heading_deg;
+}
+
+void
+FGViewer::setXOffset_m (double x_offset_m)
+{
+  _dirty = true;
+  _offset_m.x() = x_offset_m;
+}
+
+void
+FGViewer::setYOffset_m (double y_offset_m)
+{
+  _dirty = true;
+  _offset_m.y() = y_offset_m;
+}
+
+void
+FGViewer::setZOffset_m (double z_offset_m)
+{
+  _dirty = true;
+  _offset_m.z() = z_offset_m;
+}
+
+void
+FGViewer::setTargetXOffset_m (double target_x_offset_m)
+{
+  _dirty = true;
+  _target_offset_m.x() = target_x_offset_m;
+}
+
+void
+FGViewer::setTargetYOffset_m (double target_y_offset_m)
+{
+  _dirty = true;
+  _target_offset_m.y() = target_y_offset_m;
+}
+
+void
+FGViewer::setTargetZOffset_m (double target_z_offset_m)
+{
+  _dirty = true;
+  _target_offset_m.z() = target_z_offset_m;
+}
+
+void
+FGViewer::setPositionOffsets (double x_offset_m, double y_offset_m, double z_offset_m)
+{
+  _dirty = true;
+  _offset_m.x() = x_offset_m;
+  _offset_m.y() = y_offset_m;
+  _offset_m.z() = z_offset_m;
+}
+
+void
+FGViewer::setRollOffset_deg (double roll_offset_deg)
+{
+  _dirty = true;
+  _roll_offset_deg = roll_offset_deg;
+}
+
+void
+FGViewer::setPitchOffset_deg (double pitch_offset_deg)
+{
+  _dirty = true;
+  _pitch_offset_deg = pitch_offset_deg;
+}
+
+void
+FGViewer::setHeadingOffset_deg (double heading_offset_deg)
+{
+  _dirty = true;
+  if (_at_model && (_offset_m.x() == 0.0)&&(_offset_m.z() == 0.0))
+  {
+      /* avoid optical effects (e.g. rotating sky) when "looking at" with
+       * heading offsets x==z==0 (view heading cannot change). */
+      _heading_offset_deg = 0.0;
+  }
+  else
+      _heading_offset_deg = heading_offset_deg;
+}
+
+void
+FGViewer::setGoalRollOffset_deg (double goal_roll_offset_deg)
+{
+  _dirty = true;
+  _goal_roll_offset_deg = goal_roll_offset_deg;
+}
+
+void
+FGViewer::setGoalPitchOffset_deg (double goal_pitch_offset_deg)
+{
+  _dirty = true;
+  _goal_pitch_offset_deg = goal_pitch_offset_deg;
+  if ( _goal_pitch_offset_deg < -90 ) {
+    _goal_pitch_offset_deg = -90.0;
+  }
+  if ( _goal_pitch_offset_deg > 90.0 ) {
+    _goal_pitch_offset_deg = 90.0;
+  }
+
+}
+
+void
+FGViewer::setGoalHeadingOffset_deg (double goal_heading_offset_deg)
+{
+  _dirty = true;
+  if (_at_model && (_offset_m.x() == 0.0)&&(_offset_m.z() == 0.0))
+  {
+      /* avoid optical effects (e.g. rotating sky) when "looking at" with
+       * heading offsets x==z==0 (view heading cannot change). */
+      _goal_heading_offset_deg = 0.0;
+      return;
+  }
+  
+  _goal_heading_offset_deg = goal_heading_offset_deg;
+  while ( _goal_heading_offset_deg < 0.0 ) {
+    _goal_heading_offset_deg += 360;
+  }
+  while ( _goal_heading_offset_deg > 360 ) {
+    _goal_heading_offset_deg -= 360;
+  }
+}
+
+void
+FGViewer::setOrientationOffsets (double roll_offset_deg, double pitch_offset_deg, double heading_offset_deg)
+{
+  _dirty = true;
+  _roll_offset_deg = roll_offset_deg;
+  _pitch_offset_deg = pitch_offset_deg;
+  _heading_offset_deg = heading_offset_deg;
+}
+
+// recalc() is done every time one of the setters is called (making the 
+// cached data "dirty") on the next "get".  It calculates all the outputs 
+// for viewer.
+void
+FGViewer::recalc ()
+{
+  if (_type == FG_LOOKFROM) {
+    recalcLookFrom();
+  } else {
+    recalcLookAt();
+  }
+
+  set_clean();
+}
+
+// recalculate for LookFrom view type...
+void
+FGViewer::recalcLookFrom ()
+{
+  // Update location data ...
+  if ( _from_model ) {
+    SGModelPlacement* placement = globals->get_aircraft_model()->get3DModel();
+    _position = placement->getPosition();
+  
+    _heading_deg = placement->getHeadingDeg();
+    _pitch_deg = placement->getPitchDeg();
+    _roll_deg = placement->getRollDeg();
+  }
+
+  double head = _heading_deg;
+  double pitch = _pitch_deg;
+  double roll = _roll_deg;
+  if ( !_from_model ) {
+    // update from our own data...
+    setDampTarget(roll, pitch, head);
+    getDampOutput(roll, pitch, head);
+  }
+
+  // The rotation rotating from the earth centerd frame to
+  // the horizontal local frame
+  SGQuatd hlOr = SGQuatd::fromLonLat(_position);
+
+  // The rotation from the horizontal local frame to the basic view orientation
+  SGQuatd hlToBody = SGQuatd::fromYawPitchRollDeg(head, pitch, roll);
+
+  // The rotation offset, don't know why heading is negative here ...
+  mViewOffsetOr
+      = SGQuatd::fromYawPitchRollDeg(-_heading_offset_deg, _pitch_offset_deg,
+                                     _roll_offset_deg);
+
+  // Compute the eyepoints orientation and position
+  // wrt the earth centered frame - that is global coorinates
+  SGQuatd ec2body = hlOr*hlToBody;
+
+  // The cartesian position of the basic view coordinate
+  SGVec3d position = SGVec3d::fromGeod(_position);
+
+  // This is rotates the x-forward, y-right, z-down coordinate system the where
+  // simulation runs into the OpenGL camera system with x-right, y-up, z-back.
+  SGQuatd q(-0.5, -0.5, 0.5, 0.5);
+
+  _absolute_view_pos = position + (ec2body*q).backTransform(_offset_m);
+  mViewOrientation = ec2body*mViewOffsetOr*q;
+}
+
+void
+FGViewer::recalcLookAt ()
+{
+  // The geodetic position of our target to look at
+  if ( _at_model ) {
+    SGModelPlacement* placement = globals->get_aircraft_model()->get3DModel();
+    _target = placement->getPosition();
+    _target_heading_deg = placement->getHeadingDeg();
+    _target_pitch_deg = placement->getPitchDeg();
+    _target_roll_deg = placement->getRollDeg();
+  } else {
+    // if not model then calculate our own target position...
+    setDampTarget(_target_roll_deg, _target_pitch_deg, _target_heading_deg);
+    getDampOutput(_target_roll_deg, _target_pitch_deg, _target_heading_deg);
+  }
+
+  SGQuatd geodTargetOr = SGQuatd::fromYawPitchRollDeg(_target_heading_deg,
+                                                   _target_pitch_deg,
+                                                   _target_roll_deg);
+  SGQuatd geodTargetHlOr = SGQuatd::fromLonLat(_target);
+
+
+  if ( _from_model ) {
+    SGModelPlacement* placement = globals->get_aircraft_model()->get3DModel();
+    _position = placement->getPosition();
+    _heading_deg = placement->getHeadingDeg();
+    _pitch_deg = placement->getPitchDeg();
+    _roll_deg = placement->getRollDeg();
+  } else {
+    // update from our own data, just the rotation here...
+    setDampTarget(_roll_deg, _pitch_deg, _heading_deg);
+    getDampOutput(_roll_deg, _pitch_deg, _heading_deg);
+  }
+  SGQuatd geodEyeOr = SGQuatd::fromYawPitchRollDeg(_heading_deg, _pitch_deg, _roll_deg);
+  SGQuatd geodEyeHlOr = SGQuatd::fromLonLat(_position);
+
+  // the rotation offset, don't know why heading is negative here ...
+  mViewOffsetOr =
+    SGQuatd::fromYawPitchRollDeg(-_heading_offset_deg + 180, _pitch_offset_deg,
+                                 _roll_offset_deg);
+
+  // Offsets to the eye position
+  SGVec3d eyeOff(-_offset_m.z(), _offset_m.x(), -_offset_m.y());
+  SGQuatd ec2eye = geodEyeHlOr*geodEyeOr;
+  SGVec3d eyeCart = SGVec3d::fromGeod(_position);
+  eyeCart += (ec2eye*mViewOffsetOr).backTransform(eyeOff);
+
+  SGVec3d atCart = SGVec3d::fromGeod(_target);
+
+  // add target offsets to at_position...
+  SGVec3d target_pos_off(-_target_offset_m.z(), _target_offset_m.x(),
+                         -_target_offset_m.y());
+  target_pos_off = (geodTargetHlOr*geodTargetOr).backTransform(target_pos_off);
+  atCart += target_pos_off;
+  eyeCart += target_pos_off;
+
+  // Compute the eyepoints orientation and position
+  // wrt the earth centered frame - that is global coorinates
+  _absolute_view_pos = eyeCart;
+
+  // the view direction
+  SGVec3d dir = normalize(atCart - eyeCart);
+  // the up directon
+  SGVec3d up = ec2eye.backTransform(SGVec3d(0, 0, -1));
+  // rotate -dir to the 2-th unit vector
+  // rotate up to 1-th unit vector
+  // Note that this matches the OpenGL camera coordinate system
+  // with x-right, y-up, z-back.
+  mViewOrientation = SGQuatd::fromRotateTo(-dir, 2, up, 1);
+}
+
+void
+FGViewer::setDampTarget(double roll, double pitch, double heading)
+{
+  _dampTarget = SGVec3d(roll, pitch, heading);
+}
+
+void
+FGViewer::getDampOutput(double& roll, double& pitch, double& heading)
+{
+  roll = _dampOutput[0];
+  pitch = _dampOutput[1];
+  heading = _dampOutput[2];
+}
+
+
+void
+FGViewer::updateDampOutput(double dt)
+{
+  static FGViewer *last_view = 0;
+  if ((last_view != this) || (dt > 1.0)) {
+    _dampOutput = _dampTarget;
+    last_view = this;
+    return;
+  }
+  
+  const double interval = 0.01;
+  while (dt > interval) {
+    
+    for (unsigned int i=0; i<3; ++i) {
+      if (_dampFactor[i] <= 0.0) {
+        // axis is un-damped, set output to target directly
+        _dampOutput[i] = _dampTarget[i];
+        continue;
+      }
+      
+      double d = _dampOutput[i] - _dampTarget[i];
+      if (d > 180.0) {
+        _dampOutput[i] -= 360.0;
+      } else if (d < -180.0) {
+        _dampOutput[i] += 360.0;
+      }
+      
+      _dampOutput[i] = (_dampTarget[i] * _dampFactor[i]) + 
+        (_dampOutput[i] * (1.0 - _dampFactor[i]));
+    } // of axis iteration
+    
+    dt -= interval;
+  } // of dt subdivision by interval
+}
+
+double
+FGViewer::get_h_fov()
+{
+    double aspectRatio = _cameraGroup->getMasterAspectRatio();
+    switch (_scaling_type) {
+    case FG_SCALING_WIDTH:  // h_fov == fov
+       return _fov_deg;
+    case FG_SCALING_MAX:
+       if (aspectRatio < 1.0) {
+           // h_fov == fov
+           return _fov_deg;
+       } else {
+           // v_fov == fov
+           return
+                atan(tan(_fov_deg/2 * SG_DEGREES_TO_RADIANS)
+                     / (aspectRatio*_aspect_ratio_multiplier))
+                * SG_RADIANS_TO_DEGREES * 2;
+       }
+    default:
+       assert(false);
+    }
+    return 0.0;
+}
+
+
+
+double
+FGViewer::get_v_fov()
+{
+    double aspectRatio = _cameraGroup->getMasterAspectRatio();
+    switch (_scaling_type) {
+    case FG_SCALING_WIDTH:  // h_fov == fov
+       return 
+            atan(tan(_fov_deg/2 * SG_DEGREES_TO_RADIANS)
+                 * (aspectRatio*_aspect_ratio_multiplier))
+            * SG_RADIANS_TO_DEGREES * 2;
+    case FG_SCALING_MAX:
+       if (aspectRatio < 1.0) {
+           // h_fov == fov
+           return
+                atan(tan(_fov_deg/2 * SG_DEGREES_TO_RADIANS)
+                     * (aspectRatio*_aspect_ratio_multiplier))
+                * SG_RADIANS_TO_DEGREES * 2;
+       } else {
+           // v_fov == fov
+           return _fov_deg;
+       }
+    default:
+       assert(false);
+    }
+    return 0.0;
+}
+
+void
+FGViewer::update (double dt)
+{
+  updateDampOutput(dt);
+  
+  int i;
+  int dt_ms = int(dt * 1000);
+  for ( i = 0; i < dt_ms; i++ ) {
+    if ( fabs( _goal_heading_offset_deg - _heading_offset_deg) < 1 ) {
+      setHeadingOffset_deg( _goal_heading_offset_deg );
+      break;
+    } else {
+      // move current_view.headingoffset towards
+      // current_view.goal_view_offset
+      if ( _goal_heading_offset_deg > _heading_offset_deg )
+       {
+         if ( _goal_heading_offset_deg - _heading_offset_deg < 180 ){
+           incHeadingOffset_deg( 0.5 );
+         } else {
+           incHeadingOffset_deg( -0.5 );
+         }
+       } else {
+         if ( _heading_offset_deg - _goal_heading_offset_deg < 180 ){
+           incHeadingOffset_deg( -0.5 );
+         } else {
+           incHeadingOffset_deg( 0.5 );
+         }
+       }
+      if ( _heading_offset_deg > 360 ) {
+       incHeadingOffset_deg( -360 );
+      } else if ( _heading_offset_deg < 0 ) {
+       incHeadingOffset_deg( 360 );
+      }
+    }
+  }
+
+  for ( i = 0; i < dt_ms; i++ ) {
+    if ( fabs( _goal_pitch_offset_deg - _pitch_offset_deg ) < 1 ) {
+      setPitchOffset_deg( _goal_pitch_offset_deg );
+      break;
+    } else {
+      // move current_view.pitch_offset_deg towards
+      // current_view.goal_pitch_offset
+      if ( _goal_pitch_offset_deg > _pitch_offset_deg )
+       {
+         incPitchOffset_deg( 1.0 );
+       } else {
+           incPitchOffset_deg( -1.0 );
+       }
+      if ( _pitch_offset_deg > 90 ) {
+       setPitchOffset_deg(90);
+      } else if ( _pitch_offset_deg < -90 ) {
+       setPitchOffset_deg( -90 );
+      }
+    }
+  }
+
+
+  for ( i = 0; i < dt_ms; i++ ) {
+    if ( fabs( _goal_roll_offset_deg - _roll_offset_deg ) < 1 ) {
+      setRollOffset_deg( _goal_roll_offset_deg );
+      break;
+    } else {
+      // move current_view.roll_offset_deg towards
+      // current_view.goal_roll_offset
+      if ( _goal_roll_offset_deg > _roll_offset_deg )
+       {
+         incRollOffset_deg( 1.0 );
+       } else {
+           incRollOffset_deg( -1.0 );
+       }
+      if ( _roll_offset_deg > 90 ) {
+       setRollOffset_deg(90);
+      } else if ( _roll_offset_deg < -90 ) {
+       setRollOffset_deg( -90 );
+      }
+    }
+  }
+  recalc();
+  if( fgGetBool( "/sim/rendering/draw-otw", true ) ) {
+    _cameraGroup->update(toOsg(_absolute_view_pos), toOsg(mViewOrientation));
+    _cameraGroup->setCameraParameters(get_v_fov(), get_aspect_ratio());
+  }
+}
+
+double FGViewer::get_aspect_ratio() const
+{
+    return _cameraGroup->getMasterAspectRatio();
+}
diff --git a/src/Viewer/viewer.hxx b/src/Viewer/viewer.hxx
new file mode 100644 (file)
index 0000000..ef5df50
--- /dev/null
@@ -0,0 +1,345 @@
+// viewer.hxx -- class for managing a viewer in the flightgear world.
+//
+// Written by Curtis Olson, started August 1997.
+//                          overhaul started October 2000.
+//   partially rewritten by Jim Wilson jim@kelcomaine.com using interface
+//                          by David Megginson March 2002
+//
+// Copyright (C) 1997 - 2000  Curtis L. Olson  - http://www.flightgear.org/~curt
+//
+// This program is free software; you can redistribute it and/or
+// modify it under the terms of the GNU General Public License as
+// published by the Free Software Foundation; either version 2 of the
+// License, or (at your option) any later version.
+//
+// This program is distributed in the hope that it will be useful, but
+// WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+// General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License
+// along with this program; if not, write to the Free Software
+// Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
+//
+// $Id$
+
+
+#ifndef _VIEWER_HXX
+#define _VIEWER_HXX                                
+
+namespace flightgear
+{
+class CameraGroup;
+}
+
+#include <osg/ref_ptr>
+
+#include <simgear/compiler.h>
+#include <simgear/constants.h>
+#include <simgear/structure/subsystem_mgr.hxx>
+#include <simgear/math/SGMath.hxx>
+
+#define FG_FOV_MIN 0.1
+#define FG_FOV_MAX 179.9
+
+enum fgViewType {
+ FG_LOOKFROM = 0,
+ FG_LOOKAT = 1
+};
+
+// Define a structure containing view information
+class FGViewer : public SGSubsystem {
+
+public:
+
+    enum fgScalingType {  // nominal Field Of View actually applies to ...
+       FG_SCALING_WIDTH,       // window width
+       FG_SCALING_MAX          // max(width, height)
+       // FG_SCALING_G_MEAN,      // geometric_mean(width, height)
+       // FG_SCALING_INDEPENDENT  // whole screen
+    };
+
+    // Constructor
+    FGViewer( fgViewType Type, bool from_model, int from_model_index,
+              bool at_model, int at_model_index,
+              double damp_roll, double damp_pitch, double damp_heading,
+              double x_offset_m, double y_offset_m, double z_offset_m,
+              double heading_offset_deg, double pitch_offset_deg,
+              double roll_offset_deg,
+              double fov_deg, double aspect_ratio_multiplier,
+              double target_x_offset_m, double target_y_offset_m,
+              double target_z_offset_m, double near_m, bool internal );
+
+    // Destructor
+    virtual ~FGViewer( void );
+
+    //////////////////////////////////////////////////////////////////////
+    // Part 1: standard SGSubsystem implementation.
+    //////////////////////////////////////////////////////////////////////
+
+    virtual void init ();
+    virtual void bind ();
+    virtual void unbind ();
+    void update (double dt);
+
+
+    //////////////////////////////////////////////////////////////////////
+    // Part 2: user settings.
+    //////////////////////////////////////////////////////////////////////
+
+    virtual fgViewType getType() const { return _type; }
+    virtual void setType( int type );
+
+    virtual bool getInternal() const { return _internal; }
+    virtual void setInternal( bool internal );
+
+    // Reference geodetic position of view from position...
+    //   These are the actual aircraft position (pilot in
+    //   pilot view, model in model view).
+    //   FIXME: the model view position (ie target positions) 
+    //   should be in the model class.
+    virtual void setPosition (double lon_deg, double lat_deg, double alt_ft);
+    const SGGeod& getPosition() const { return _position; }
+
+    // Reference geodetic target position...
+    virtual void setTargetPosition (double lon_deg, double lat_deg, double alt_ft);
+    const SGGeod& getTargetPosition() const { return _target; }
+
+
+
+    // Position offsets from reference
+    //   These offsets position they "eye" in the scene according to a given
+    //   location.  For example in pilot view they are used to position the 
+    //   head inside the aircraft.
+    //   Note that in pilot view these are applied "before" the orientation 
+    //   rotations (see below) so that the orientation rotations have the 
+    //   effect of the pilot staying in his seat and "looking out" in 
+    //   different directions.
+    //   In chase view these are applied "after" the application of the 
+    //   orientation rotations listed below.  This has the effect of the 
+    //   eye moving around and "looking at" the object (model) from 
+    //   different angles.
+    virtual SGVec3d getOffset_m () const { return _offset_m; }
+    virtual double getXOffset_m () const { return _offset_m.x(); }
+    virtual double getYOffset_m () const { return _offset_m.y(); }
+    virtual double getZOffset_m () const { return _offset_m.z(); }
+    virtual double getTargetXOffset_m () const { return _target_offset_m.x(); }
+    virtual double getTargetYOffset_m () const { return _target_offset_m.y(); }
+    virtual double getTargetZOffset_m () const { return _target_offset_m.z(); }
+    virtual void setXOffset_m (double x_offset_m);
+    virtual void setYOffset_m (double y_offset_m);
+    virtual void setZOffset_m (double z_offset_m);
+    virtual void setTargetXOffset_m (double x_offset_m);
+    virtual void setTargetYOffset_m (double y_offset_m);
+    virtual void setTargetZOffset_m (double z_offset_m);
+    virtual void setPositionOffsets (double x_offset_m,
+                                    double y_offset_m,
+                                    double z_offset_m);
+
+
+
+
+    // Reference orientation rotations...
+    //   These are rotations that represent the plane attitude effect on
+    //   the view (in Pilot view).  IE The view frustrum rotates as the plane
+    //   turns, pitches, and rolls.
+    //   In model view (lookat/chaseview) these end up changing the angle that
+    //   the eye is looking at the ojbect (ie the model).
+    //   FIXME: the FGModel class should have its own version of these so that
+    //   it can generate it's own model rotations.
+    virtual double getRoll_deg () const { return _roll_deg; }
+    virtual double getPitch_deg () const {return _pitch_deg; }
+    virtual double getHeading_deg () const {return _heading_deg; }
+    virtual void setRoll_deg (double roll_deg);
+    virtual void setPitch_deg (double pitch_deg);
+    virtual void setHeading_deg (double heading_deg);
+    virtual void setOrientation (double roll_deg, double pitch_deg, double heading_deg);
+    virtual double getTargetRoll_deg () const { return _target_roll_deg; }
+    virtual double getTargetPitch_deg () const {return _target_pitch_deg; }
+    virtual double getTargetHeading_deg () const {return _target_heading_deg; }
+    virtual void setTargetRoll_deg (double roll_deg);
+    virtual void setTargetPitch_deg (double pitch_deg);
+    virtual void setTargetHeading_deg (double heading_deg);
+    virtual void setTargetOrientation (double roll_deg, double pitch_deg, double heading_deg);
+
+
+
+
+    // Orientation offsets rotations from reference orientation.
+    // Goal settings are for smooth transition from prior 
+    // offset when changing view direction.
+    //   These offsets are in ADDITION to the orientation rotations listed 
+    //   above.
+    //   In pilot view they are applied after the position offsets in order to
+    //   give the effect of the pilot looking around.
+    //   In lookat view they are applied before the position offsets so that
+    //   the effect is the eye moving around looking at the object (ie the model)
+    //   from different angles.
+    virtual double getRollOffset_deg () const { return _roll_offset_deg; }
+    virtual double getPitchOffset_deg () const { return _pitch_offset_deg; }
+    virtual double getHeadingOffset_deg () const { return _heading_offset_deg; }
+    virtual double getGoalRollOffset_deg () const { return _goal_roll_offset_deg; }
+    virtual double getGoalPitchOffset_deg () const { return _goal_pitch_offset_deg; }
+    virtual double getGoalHeadingOffset_deg () const {return _goal_heading_offset_deg; }
+    virtual void setRollOffset_deg (double roll_offset_deg);
+    virtual void setPitchOffset_deg (double pitch_offset_deg);
+    virtual void setHeadingOffset_deg (double heading_offset_deg);
+    virtual void setGoalRollOffset_deg (double goal_roll_offset_deg);
+    virtual void setGoalPitchOffset_deg (double goal_pitch_offset_deg);
+    virtual void setGoalHeadingOffset_deg (double goal_heading_offset_deg);
+    virtual void setOrientationOffsets (double roll_offset_deg,
+                                    double heading_offset_deg,
+                                    double pitch_offset_deg);
+
+
+
+    //////////////////////////////////////////////////////////////////////
+    // Part 3: output vectors and matrices in FlightGear coordinates.
+    //////////////////////////////////////////////////////////////////////
+
+    // Vectors and positions...
+
+    const SGVec3d& get_view_pos() { if ( _dirty ) { recalc(); } return _absolute_view_pos; }
+    const SGVec3d& getViewPosition() { if ( _dirty ) { recalc(); } return _absolute_view_pos; }
+    const SGQuatd& getViewOrientation() { if ( _dirty ) { recalc(); } return mViewOrientation; }
+    const SGQuatd& getViewOrientationOffset() { if ( _dirty ) { recalc(); } return mViewOffsetOr; }
+
+    //////////////////////////////////////////////////////////////////////
+    // Part 4: View and frustrum data setters and getters
+    //////////////////////////////////////////////////////////////////////
+
+    virtual void set_fov( double fov_deg ) {
+       _fov_deg = fov_deg;
+    }
+    virtual double get_fov() const { return _fov_deg; }
+    virtual double get_h_fov();    // Get horizontal fov, in degrees.
+    virtual double get_v_fov();    // Get vertical fov, in degrees.
+
+    virtual double get_aspect_ratio() const;
+
+    virtual void set_aspect_ratio_multiplier( double m ) {
+       _aspect_ratio_multiplier = m;
+    }
+    virtual double get_aspect_ratio_multiplier() const {
+        return _aspect_ratio_multiplier;
+    }
+
+    virtual double getNear_m () const { return _ground_level_nearplane_m; }
+    inline void setNear_m (double near_m) {
+        _ground_level_nearplane_m = near_m;
+    }
+
+    //////////////////////////////////////////////////////////////////////
+    // Part 5: misc setters and getters
+    //////////////////////////////////////////////////////////////////////
+
+    inline void set_dirty() { _dirty = true; }
+    inline void set_clean() { _dirty = false; }
+    
+private:
+
+    //////////////////////////////////////////////////////////////////
+    // private data                                                 //
+    //////////////////////////////////////////////////////////////////
+
+    // flag forcing a recalc of derived view parameters
+    bool _dirty;
+
+    SGQuatd mViewOrientation;
+    SGQuatd mViewOffsetOr;
+    SGVec3d _absolute_view_pos;
+
+    SGGeod _position;
+    SGGeod _target;
+
+    double _roll_deg;
+    double _pitch_deg;
+    double _heading_deg;
+    double _target_roll_deg;
+    double _target_pitch_deg;
+    double _target_heading_deg;
+
+    SGVec3d _dampTarget; ///< current target value we are damping towards
+    SGVec3d _dampOutput; ///< current output of damping filter
+    SGVec3d _dampFactor; ///< weighting of the damping filter
+    
+    // Position offsets from FDM origin.  The X axis is positive
+    // out the tail, Y is out the right wing, and Z is positive up.
+    // distance in meters
+    SGVec3d _offset_m;
+
+    // Target offsets from FDM origin (for "lookat" targets) The X
+    // axis is positive out the tail, Y is out the right wing, and Z
+    // is positive up.  distance in meters
+    SGVec3d _target_offset_m;
+
+
+    // orientation offsets from reference (_goal* are for smoothed transitions)
+    double _roll_offset_deg;
+    double _pitch_offset_deg;
+    double _heading_offset_deg;
+    double _goal_roll_offset_deg;
+    double _goal_pitch_offset_deg;
+    double _goal_heading_offset_deg;
+
+    // used to set nearplane when at ground level for this view
+    double _ground_level_nearplane_m;
+
+    fgViewType _type;
+    fgScalingType _scaling_type;
+
+    // internal view (e.g. cockpit) flag
+    bool _internal;
+
+    // view is looking from a model
+    bool _from_model;
+    int _from_model_index;  // number of model (for multi model)
+
+    // view is looking at a model
+    bool _at_model;
+    int _at_model_index;  // number of model (for multi model)
+
+    // the nominal field of view (angle, in degrees)
+    double _fov_deg;
+
+    // default = 1.0, this value is user configurable and is
+    // multiplied into the aspect_ratio to get the actual vertical fov
+    double _aspect_ratio_multiplier;
+
+    // camera group controled by this view
+    osg::ref_ptr<flightgear::CameraGroup> _cameraGroup;
+    //////////////////////////////////////////////////////////////////
+    // private functions                                            //
+    //////////////////////////////////////////////////////////////////
+
+    void recalc ();
+    void recalcLookFrom();
+    void recalcLookAt();
+
+    void setDampTarget(double h, double p, double r);
+    void getDampOutput(double& roll, double& pitch, double& heading);
+    
+    void updateDampOutput(double dt);
+    
+    // add to _heading_offset_deg
+    inline void incHeadingOffset_deg( double amt ) {
+       set_dirty();
+       _heading_offset_deg += amt;
+    }
+
+    // add to _pitch_offset_deg
+    inline void incPitchOffset_deg( double amt ) {
+       set_dirty();
+       _pitch_offset_deg += amt;
+    }
+
+    // add to _roll_offset_deg
+    inline void incRollOffset_deg( double amt ) {
+       set_dirty();
+       _roll_offset_deg += amt;
+    }
+
+};
+
+
+#endif // _VIEWER_HXX
diff --git a/src/Viewer/viewmgr.cxx b/src/Viewer/viewmgr.cxx
new file mode 100644 (file)
index 0000000..f3101a2
--- /dev/null
@@ -0,0 +1,920 @@
+// viewmgr.cxx -- class for managing all the views in the flightgear world.
+//
+// Written by Curtis Olson, started October 2000.
+//   partially rewritten by Jim Wilson March 2002
+//
+// Copyright (C) 2000  Curtis L. Olson  - http://www.flightgear.org/~curt
+//
+// This program is free software; you can redistribute it and/or
+// modify it under the terms of the GNU General Public License as
+// published by the Free Software Foundation; either version 2 of the
+// License, or (at your option) any later version.
+//
+// This program is distributed in the hope that it will be useful, but
+// WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+// General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License
+// along with this program; if not, write to the Free Software
+// Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
+//
+// $Id$
+
+#ifdef HAVE_CONFIG_H
+#  include "config.h"
+#endif
+
+#include "viewmgr.hxx"
+
+#include <string.h>            // strcmp
+
+#include <simgear/compiler.h>
+#include <simgear/sound/soundmgr_openal.hxx>
+#include <Model/acmodel.hxx>
+#include <Main/fg_props.hxx>
+#include "viewer.hxx"
+
+// Constructor
+FGViewMgr::FGViewMgr( void ) :
+  axis_long(0),
+  axis_lat(0),
+  inited(false),
+  view_number(fgGetNode("/sim/current-view/view-number", true)),
+  config_list(fgGetNode("/sim", true)->getChildren("view")),
+  abs_viewer_position(SGVec3d::zeros()),
+  current(0),
+  current_view_orientation(SGQuatd::zeros()),
+  current_view_or_offset(SGQuatd::zeros()),
+  smgr(globals->get_soundmgr())
+{
+}
+
+// Destructor
+FGViewMgr::~FGViewMgr( void ) {
+}
+
+void
+FGViewMgr::init ()
+{
+  if (inited) {
+    SG_LOG(SG_VIEW, SG_WARN, "duplicate init of view manager");
+    return;
+  }
+  
+  inited = true;
+  
+  double aspect_ratio_multiplier
+      = fgGetDouble("/sim/current-view/aspect-ratio-multiplier");
+
+  for (unsigned int i = 0; i < config_list.size(); i++) {
+    SGPropertyNode *n = config_list[i];
+
+    // find out if this is an internal view (e.g. in cockpit, low near plane)
+    bool internal = n->getBoolValue("internal", false);
+
+    // FIXME:
+    // this is assumed to be an aircraft model...we will need to read
+    // model-from-type as well.
+
+    // find out if this is a model we are looking from...
+    bool from_model = n->getBoolValue("config/from-model");
+    int from_model_index = n->getIntValue("config/from-model-idx");
+
+    double x_offset_m = n->getDoubleValue("config/x-offset-m");
+    double y_offset_m = n->getDoubleValue("config/y-offset-m");
+    double z_offset_m = n->getDoubleValue("config/z-offset-m");
+
+    double heading_offset_deg = n->getDoubleValue("config/heading-offset-deg");
+    n->setDoubleValue("config/heading-offset-deg", heading_offset_deg);
+    double pitch_offset_deg = n->getDoubleValue("config/pitch-offset-deg");
+    n->setDoubleValue("config/pitch-offset-deg", pitch_offset_deg);
+    double roll_offset_deg = n->getDoubleValue("config/roll-offset-deg");
+    n->setDoubleValue("config/roll-offset-deg", roll_offset_deg);
+
+    double fov_deg = n->getDoubleValue("config/default-field-of-view-deg");
+    double near_m = n->getDoubleValue("config/ground-level-nearplane-m");
+
+    // supporting two types "lookat" = 1 and "lookfrom" = 0
+    const char *type = n->getStringValue("type");
+    if (!strcmp(type, "lookat")) {
+
+      bool at_model = n->getBoolValue("config/at-model");
+      int at_model_index = n->getIntValue("config/at-model-idx");
+
+      double damp_roll = n->getDoubleValue("config/at-model-roll-damping");
+      double damp_pitch = n->getDoubleValue("config/at-model-pitch-damping");
+      double damp_heading = n->getDoubleValue("config/at-model-heading-damping");
+
+      double target_x_offset_m = n->getDoubleValue("config/target-x-offset-m");
+      double target_y_offset_m = n->getDoubleValue("config/target-y-offset-m");
+      double target_z_offset_m = n->getDoubleValue("config/target-z-offset-m");
+
+      add_view(new FGViewer ( FG_LOOKAT, from_model, from_model_index,
+                              at_model, at_model_index,
+                              damp_roll, damp_pitch, damp_heading,
+                              x_offset_m, y_offset_m,z_offset_m,
+                              heading_offset_deg, pitch_offset_deg,
+                              roll_offset_deg, fov_deg, aspect_ratio_multiplier,
+                              target_x_offset_m, target_y_offset_m,
+                              target_z_offset_m, near_m, internal ));
+    } else {
+      add_view(new FGViewer ( FG_LOOKFROM, from_model, from_model_index,
+                              false, 0, 0.0, 0.0, 0.0,
+                              x_offset_m, y_offset_m, z_offset_m,
+                              heading_offset_deg, pitch_offset_deg,
+                              roll_offset_deg, fov_deg, aspect_ratio_multiplier,
+                              0, 0, 0, near_m, internal ));
+    }
+  }
+
+  copyToCurrent();
+  do_bind();
+}
+
+void
+FGViewMgr::reinit ()
+{
+  // reset offsets and fov to configuration defaults
+  for (unsigned int i = 0; i < config_list.size(); i++) {
+    SGPropertyNode *n = config_list[i];
+    setView(i);
+
+    fgSetDouble("/sim/current-view/x-offset-m",
+        n->getDoubleValue("config/x-offset-m"));
+    fgSetDouble("/sim/current-view/y-offset-m",
+        n->getDoubleValue("config/y-offset-m"));
+    fgSetDouble("/sim/current-view/z-offset-m",
+        n->getDoubleValue("config/z-offset-m"));
+    fgSetDouble("/sim/current-view/pitch-offset-deg",
+        n->getDoubleValue("config/pitch-offset-deg"));
+    fgSetDouble("/sim/current-view/heading-offset-deg",
+        n->getDoubleValue("config/heading-offset-deg"));
+    fgSetDouble("/sim/current-view/roll-offset-deg",
+        n->getDoubleValue("config/roll-offset-deg"));
+
+    double fov_deg = n->getDoubleValue("config/default-field-of-view-deg");
+    if (fov_deg < 10.0)
+      fov_deg = 55.0;
+    fgSetDouble("/sim/current-view/field-of-view", fov_deg);
+
+    // target offsets for lookat mode only...
+    fgSetDouble("/sim/current-view/target-x-offset-m",
+        n->getDoubleValue("config/target-x-offset-m"));
+    fgSetDouble("/sim/current-view/target-y-offset-m",
+        n->getDoubleValue("config/target-y-offset-m"));
+    fgSetDouble("/sim/current-view/target-z-offset-m",
+        n->getDoubleValue("config/target-z-offset-m"));
+  }
+  setView(0);
+}
+
+typedef double (FGViewMgr::*double_getter)() const;
+
+void
+FGViewMgr::bind()
+{
+  // view-manager code was designed to init before bind, so
+  // this is a no-op; init() calls the real bind() impl below
+}
+
+void
+FGViewMgr::do_bind()
+{
+  // these are bound to the current view properties
+  _tiedProperties.setRoot(fgGetNode("/sim/current-view", true));
+  _tiedProperties.Tie("heading-offset-deg", this,
+                      &FGViewMgr::getViewHeadingOffset_deg,
+                      &FGViewMgr::setViewHeadingOffset_deg);
+  fgSetArchivable("/sim/current-view/heading-offset-deg");
+  _tiedProperties.Tie("goal-heading-offset-deg", this,
+                      &FGViewMgr::getViewGoalHeadingOffset_deg,
+                      &FGViewMgr::setViewGoalHeadingOffset_deg);
+  fgSetArchivable("/sim/current-view/goal-heading-offset-deg");
+  _tiedProperties.Tie("pitch-offset-deg", this,
+                      &FGViewMgr::getViewPitchOffset_deg,
+                      &FGViewMgr::setViewPitchOffset_deg);
+  fgSetArchivable("/sim/current-view/pitch-offset-deg");
+  _tiedProperties.Tie("goal-pitch-offset-deg", this,
+                      &FGViewMgr::getGoalViewPitchOffset_deg,
+                      &FGViewMgr::setGoalViewPitchOffset_deg);
+  fgSetArchivable("/sim/current-view/goal-pitch-offset-deg");
+  _tiedProperties.Tie("roll-offset-deg", this,
+                      &FGViewMgr::getViewRollOffset_deg,
+                      &FGViewMgr::setViewRollOffset_deg);
+  fgSetArchivable("/sim/current-view/roll-offset-deg");
+  _tiedProperties.Tie("goal-roll-offset-deg", this,
+                      &FGViewMgr::getGoalViewRollOffset_deg,
+                      &FGViewMgr::setGoalViewRollOffset_deg);
+  fgSetArchivable("/sim/current-view/goal-roll-offset-deg");
+
+  _tiedProperties.Tie("view-number", this,
+                      &FGViewMgr::getView, &FGViewMgr::setView);
+  fgSetArchivable("/sim/current-view/view-number", false);
+
+  _tiedProperties.Tie("axes/long", this,
+                      (double_getter)0, &FGViewMgr::setViewAxisLong);
+  fgSetArchivable("/sim/current-view/axes/long");
+
+  _tiedProperties.Tie("axes/lat", this,
+                      (double_getter)0, &FGViewMgr::setViewAxisLat);
+  fgSetArchivable("/sim/current-view/axes/lat");
+
+  _tiedProperties.Tie("field-of-view", this,
+                      &FGViewMgr::getFOV_deg, &FGViewMgr::setFOV_deg);
+  fgSetArchivable("/sim/current-view/field-of-view");
+
+  _tiedProperties.Tie("aspect-ratio-multiplier", this,
+                      &FGViewMgr::getARM_deg, &FGViewMgr::setARM_deg);
+  fgSetArchivable("/sim/current-view/field-of-view");
+
+  _tiedProperties.Tie("ground-level-nearplane-m", this,
+                      &FGViewMgr::getNear_m, &FGViewMgr::setNear_m);
+  fgSetArchivable("/sim/current-view/ground-level-nearplane-m");
+
+  SGPropertyNode *n = fgGetNode("/sim/current-view", true);
+  _tiedProperties.Tie(n->getNode("viewer-x-m", true),SGRawValuePointer<double>(&abs_viewer_position[0]));
+  _tiedProperties.Tie(n->getNode("viewer-y-m", true),SGRawValuePointer<double>(&abs_viewer_position[1]));
+  _tiedProperties.Tie(n->getNode("viewer-z-m", true),SGRawValuePointer<double>(&abs_viewer_position[2]));
+
+  _tiedProperties.Tie("debug/orientation-w", this,
+                      &FGViewMgr::getCurrentViewOrientation_w);
+  _tiedProperties.Tie("debug/orientation-x", this,
+                      &FGViewMgr::getCurrentViewOrientation_x);
+  _tiedProperties.Tie("debug/orientation-y", this,
+                      &FGViewMgr::getCurrentViewOrientation_y);
+  _tiedProperties.Tie("debug/orientation-z", this,
+                      &FGViewMgr::getCurrentViewOrientation_z);
+
+  _tiedProperties.Tie("debug/orientation_offset-w", this,
+                      &FGViewMgr::getCurrentViewOrOffset_w);
+  _tiedProperties.Tie("debug/orientation_offset-x", this,
+                      &FGViewMgr::getCurrentViewOrOffset_x);
+  _tiedProperties.Tie("debug/orientation_offset-y", this,
+                      &FGViewMgr::getCurrentViewOrOffset_y);
+  _tiedProperties.Tie("debug/orientation_offset-z", this,
+                      &FGViewMgr::getCurrentViewOrOffset_z);
+
+  _tiedProperties.Tie("debug/frame-w", this,
+                      &FGViewMgr::getCurrentViewFrame_w);
+  _tiedProperties.Tie("debug/frame-x", this,
+                      &FGViewMgr::getCurrentViewFrame_x);
+  _tiedProperties.Tie("debug/frame-y", this,
+                      &FGViewMgr::getCurrentViewFrame_y);
+  _tiedProperties.Tie("debug/frame-z", this,
+                      &FGViewMgr::getCurrentViewFrame_z);
+}
+
+void
+FGViewMgr::unbind ()
+{
+  _tiedProperties.Untie();
+}
+
+void
+FGViewMgr::update (double dt)
+{
+  FGViewer *loop_view = (FGViewer *)get_current_view();
+  if (loop_view == 0) return;
+
+  SGPropertyNode *n = config_list[current];
+  double lon_deg, lat_deg, alt_ft, roll_deg, pitch_deg, heading_deg;
+
+  // Set up view location and orientation
+
+  if (!n->getBoolValue("config/from-model")) {
+    lon_deg = fgGetDouble(n->getStringValue("config/eye-lon-deg-path"));
+    lat_deg = fgGetDouble(n->getStringValue("config/eye-lat-deg-path"));
+    alt_ft = fgGetDouble(n->getStringValue("config/eye-alt-ft-path"));
+    roll_deg = fgGetDouble(n->getStringValue("config/eye-roll-deg-path"));
+    pitch_deg = fgGetDouble(n->getStringValue("config/eye-pitch-deg-path"));
+    heading_deg = fgGetDouble(n->getStringValue("config/eye-heading-deg-path"));
+
+    loop_view->setPosition(lon_deg, lat_deg, alt_ft);
+    loop_view->setOrientation(roll_deg, pitch_deg, heading_deg);
+  } else {
+    // force recalc in viewer
+    loop_view->set_dirty();
+  }
+
+  // if lookat (type 1) then get target data...
+  if (loop_view->getType() == FG_LOOKAT) {
+    if (!n->getBoolValue("config/from-model")) {
+      lon_deg = fgGetDouble(n->getStringValue("config/target-lon-deg-path"));
+      lat_deg = fgGetDouble(n->getStringValue("config/target-lat-deg-path"));
+      alt_ft = fgGetDouble(n->getStringValue("config/target-alt-ft-path"));
+      roll_deg = fgGetDouble(n->getStringValue("config/target-roll-deg-path"));
+      pitch_deg = fgGetDouble(n->getStringValue("config/target-pitch-deg-path"));
+      heading_deg = fgGetDouble(n->getStringValue("config/target-heading-deg-path"));
+
+      loop_view->setTargetPosition(lon_deg, lat_deg, alt_ft);
+      loop_view->setTargetOrientation(roll_deg, pitch_deg, heading_deg);
+    } else {
+      loop_view->set_dirty();
+    }
+  }
+
+  setViewXOffset_m(fgGetDouble("/sim/current-view/x-offset-m"));
+  setViewYOffset_m(fgGetDouble("/sim/current-view/y-offset-m"));
+  setViewZOffset_m(fgGetDouble("/sim/current-view/z-offset-m"));
+
+  setViewTargetXOffset_m(fgGetDouble("/sim/current-view/target-x-offset-m"));
+  setViewTargetYOffset_m(fgGetDouble("/sim/current-view/target-y-offset-m"));
+  setViewTargetZOffset_m(fgGetDouble("/sim/current-view/target-z-offset-m"));
+
+  current_view_orientation = loop_view->getViewOrientation();
+  current_view_or_offset = loop_view->getViewOrientationOffset();
+
+  // Update the current view
+  do_axes();
+  loop_view->update(dt);
+  abs_viewer_position = loop_view->getViewPosition();
+
+  // update audio listener values
+  // set the viewer position in Cartesian coordinates in meters
+  smgr->set_position( abs_viewer_position, loop_view->getPosition() );
+  smgr->set_orientation( current_view_orientation );
+
+  // get the model velocity
+  SGVec3d velocity = SGVec3d::zeros();
+  if ( !stationary() ) {
+    velocity = globals->get_aircraft_model()->getVelocity();
+  }
+  smgr->set_velocity( velocity );
+}
+
+void
+FGViewMgr::copyToCurrent()
+{
+  if (!inited) {
+    return;
+  }
+  
+    SGPropertyNode *n = config_list[current];
+    fgSetString("/sim/current-view/name", n->getStringValue("name"));
+    fgSetString("/sim/current-view/type", n->getStringValue("type"));
+
+    // copy certain view config data for default values
+    fgSetDouble("/sim/current-view/config/heading-offset-deg",
+                n->getDoubleValue("config/default-heading-offset-deg"));
+    fgSetDouble("/sim/current-view/config/pitch-offset-deg",
+                n->getDoubleValue("config/pitch-offset-deg"));
+    fgSetDouble("/sim/current-view/config/roll-offset-deg",
+                n->getDoubleValue("config/roll-offset-deg"));
+    fgSetDouble("/sim/current-view/config/default-field-of-view-deg",
+                n->getDoubleValue("config/default-field-of-view-deg"));
+    fgSetBool("/sim/current-view/config/from-model",
+                n->getBoolValue("config/from-model"));
+
+    // copy view data
+    fgSetDouble("/sim/current-view/x-offset-m", getViewXOffset_m());
+    fgSetDouble("/sim/current-view/y-offset-m", getViewYOffset_m());
+    fgSetDouble("/sim/current-view/z-offset-m", getViewZOffset_m());
+
+    fgSetDouble("/sim/current-view/goal-heading-offset-deg",
+                get_current_view()->getGoalHeadingOffset_deg());
+    fgSetDouble("/sim/current-view/goal-pitch-offset-deg",
+                get_current_view()->getGoalPitchOffset_deg());
+    fgSetDouble("/sim/current-view/goal-roll-offset-deg",
+                get_current_view()->getRollOffset_deg());
+    fgSetDouble("/sim/current-view/heading-offset-deg",
+                get_current_view()->getHeadingOffset_deg());
+    fgSetDouble("/sim/current-view/pitch-offset-deg",
+                get_current_view()->getPitchOffset_deg());
+    fgSetDouble("/sim/current-view/roll-offset-deg",
+                get_current_view()->getRollOffset_deg());
+    fgSetDouble("/sim/current-view/target-x-offset-m",
+                get_current_view()->getTargetXOffset_m());
+    fgSetDouble("/sim/current-view/target-y-offset-m",
+                get_current_view()->getTargetYOffset_m());
+    fgSetDouble("/sim/current-view/target-z-offset-m",
+                get_current_view()->getTargetZOffset_m());
+    fgSetBool("/sim/current-view/internal",
+                get_current_view()->getInternal());
+}
+
+void FGViewMgr::clear()
+{
+  views.clear();
+}
+
+FGViewer*
+FGViewMgr::get_current_view()
+{
+       if ( current < (int)views.size() ) {
+           return views[current];
+       } else {
+           return NULL;
+       }
+}
+
+const FGViewer*
+FGViewMgr::get_current_view() const
+{
+       if ( current < (int)views.size() ) {
+           return views[current];
+       } else {
+           return NULL;
+       }
+}
+
+
+FGViewer*
+FGViewMgr::get_view( int i )
+{
+       if ( i < 0 ) { i = 0; }
+       if ( i >= (int)views.size() ) { i = views.size() - 1; }
+       return views[i];
+}
+
+const FGViewer*
+FGViewMgr::get_view( int i ) const
+{
+       if ( i < 0 ) { i = 0; }
+       if ( i >= (int)views.size() ) { i = views.size() - 1; }
+       return views[i];
+}
+
+FGViewer*
+FGViewMgr::next_view()
+{
+       setView((current+1 < (int)views.size()) ? (current + 1) : 0);
+       view_number->fireValueChanged();
+       return views[current];
+}
+
+FGViewer*
+FGViewMgr::prev_view()
+{
+       setView((0 < current) ? (current - 1) : (views.size() - 1));
+       view_number->fireValueChanged();
+       return views[current];
+}
+
+void
+FGViewMgr::add_view( FGViewer * v )
+{
+  views.push_back(v);
+  v->init();
+}
+    
+double
+FGViewMgr::getViewHeadingOffset_deg () const
+{
+  const FGViewer * view = get_current_view();
+  return (view == 0 ? 0 : view->getHeadingOffset_deg());
+}
+
+void
+FGViewMgr::setViewHeadingOffset_deg (double offset)
+{
+  FGViewer * view = get_current_view();
+  if (view != 0) {
+    view->setGoalHeadingOffset_deg(offset);
+    view->setHeadingOffset_deg(offset);
+  }
+}
+
+double
+FGViewMgr::getViewGoalHeadingOffset_deg () const
+{
+  const FGViewer * view = get_current_view();
+  return (view == 0 ? 0 : view->getGoalHeadingOffset_deg());
+}
+
+void
+FGViewMgr::setViewGoalHeadingOffset_deg (double offset)
+{
+  FGViewer * view = get_current_view();
+  if (view != 0)
+    view->setGoalHeadingOffset_deg(offset);
+}
+
+double
+FGViewMgr::getViewPitchOffset_deg () const
+{
+  const FGViewer * view = get_current_view();
+  return (view == 0 ? 0 : view->getPitchOffset_deg());
+}
+
+void
+FGViewMgr::setViewPitchOffset_deg (double tilt)
+{
+  FGViewer * view = get_current_view();
+  if (view != 0) {
+    view->setGoalPitchOffset_deg(tilt);
+    view->setPitchOffset_deg(tilt);
+  }
+}
+
+double
+FGViewMgr::getGoalViewPitchOffset_deg () const
+{
+  const FGViewer * view = get_current_view();
+  return (view == 0 ? 0 : view->getGoalPitchOffset_deg());
+}
+
+void
+FGViewMgr::setGoalViewPitchOffset_deg (double tilt)
+{
+  FGViewer * view = get_current_view();
+  if (view != 0)
+    view->setGoalPitchOffset_deg(tilt);
+}
+
+double
+FGViewMgr::getViewRollOffset_deg () const
+{
+  const FGViewer * view = get_current_view();
+  return (view == 0 ? 0 : view->getRollOffset_deg());
+}
+
+void
+FGViewMgr::setViewRollOffset_deg (double tilt)
+{
+  FGViewer * view = get_current_view();
+  if (view != 0) {
+    view->setGoalRollOffset_deg(tilt);
+    view->setRollOffset_deg(tilt);
+  }
+}
+
+double
+FGViewMgr::getGoalViewRollOffset_deg () const
+{
+  const FGViewer * view = get_current_view();
+  return (view == 0 ? 0 : view->getGoalRollOffset_deg());
+}
+
+void
+FGViewMgr::setGoalViewRollOffset_deg (double tilt)
+{
+  FGViewer * view = get_current_view();
+  if (view != 0)
+    view->setGoalRollOffset_deg(tilt);
+}
+
+double
+FGViewMgr::getViewXOffset_m () const
+{
+  const FGViewer * view = get_current_view();
+  if (view != 0) {
+    return ((FGViewer *)view)->getXOffset_m();
+  } else {
+    return 0;
+  }
+}
+
+void
+FGViewMgr::setViewXOffset_m (double x)
+{
+  FGViewer * view = get_current_view();
+  if (view != 0) {
+    view->setXOffset_m(x);
+  }
+}
+
+double
+FGViewMgr::getViewYOffset_m () const
+{
+  const FGViewer * view = get_current_view();
+  if (view != 0) {
+    return ((FGViewer *)view)->getYOffset_m();
+  } else {
+    return 0;
+  }
+}
+
+void
+FGViewMgr::setViewYOffset_m (double y)
+{
+  FGViewer * view = get_current_view();
+  if (view != 0) {
+    view->setYOffset_m(y);
+  }
+}
+
+double
+FGViewMgr::getViewZOffset_m () const
+{
+  const FGViewer * view = get_current_view();
+  if (view != 0) {
+    return ((FGViewer *)view)->getZOffset_m();
+  } else {
+    return 0;
+  }
+}
+
+void
+FGViewMgr::setViewZOffset_m (double z)
+{
+  FGViewer * view = get_current_view();
+  if (view != 0) {
+    view->setZOffset_m(z);
+  }
+}
+
+bool
+FGViewMgr::stationary () const
+{
+  const FGViewer * view = get_current_view();
+  if (view != 0) {
+    if (((FGViewer *)view)->getXOffset_m() == 0.0 &&
+        ((FGViewer *)view)->getYOffset_m() == 0.0 &&
+        ((FGViewer *)view)->getZOffset_m() == 0.0)
+      return true;
+  }
+
+  return false;
+}
+
+double
+FGViewMgr::getViewTargetXOffset_m () const
+{
+  const FGViewer * view = get_current_view();
+  if (view != 0) {
+    return ((FGViewer *)view)->getTargetXOffset_m();
+  } else {
+    return 0;
+  }
+}
+
+void
+FGViewMgr::setViewTargetXOffset_m (double x)
+{
+  FGViewer * view = get_current_view();
+  if (view != 0) {
+    view->setTargetXOffset_m(x);
+  }
+}
+
+double
+FGViewMgr::getViewTargetYOffset_m () const
+{
+  const FGViewer * view = get_current_view();
+  if (view != 0) {
+    return ((FGViewer *)view)->getTargetYOffset_m();
+  } else {
+    return 0;
+  }
+}
+
+void
+FGViewMgr::setViewTargetYOffset_m (double y)
+{
+  FGViewer * view = get_current_view();
+  if (view != 0) {
+    view->setTargetYOffset_m(y);
+  }
+}
+
+double
+FGViewMgr::getViewTargetZOffset_m () const
+{
+  const FGViewer * view = get_current_view();
+  if (view != 0) {
+    return ((FGViewer *)view)->getTargetZOffset_m();
+  } else {
+    return 0;
+  }
+}
+
+void
+FGViewMgr::setViewTargetZOffset_m (double z)
+{
+  FGViewer * view = get_current_view();
+  if (view != 0) {
+    view->setTargetZOffset_m(z);
+  }
+}
+
+int
+FGViewMgr::getView () const
+{
+  return ( current );
+}
+
+void
+FGViewMgr::setView (int newview)
+{
+  // negative numbers -> set view with node index -newview
+  if (newview < 0) {
+    for (int i = 0; i < (int)config_list.size(); i++) {
+      int index = -config_list[i]->getIndex();
+      if (index == newview)
+        newview = i;
+    }
+    if (newview < 0)
+      return;
+  }
+
+  // if newview number too low wrap to last view...
+  if (newview < 0)
+    newview = (int)views.size() - 1;
+
+  // if newview number to high wrap to zero...
+  if (newview >= (int)views.size())
+    newview = 0;
+
+  // set new view
+  current = newview;
+  // copy in view data
+  copyToCurrent();
+}
+
+
+double
+FGViewMgr::getFOV_deg () const
+{
+  const FGViewer * view = get_current_view();
+  return (view == 0 ? 0 : view->get_fov());
+}
+
+void
+FGViewMgr::setFOV_deg (double fov)
+{
+  FGViewer * view = get_current_view();
+  if (view != 0)
+    view->set_fov(fov);
+}
+
+double
+FGViewMgr::getARM_deg () const
+{
+  const FGViewer * view = get_current_view();
+  return (view == 0 ? 0 : view->get_aspect_ratio_multiplier());
+}
+
+void
+FGViewMgr::setARM_deg (double aspect_ratio_multiplier)
+{  
+  FGViewer * view = get_current_view();
+  if (view != 0)
+    view->set_aspect_ratio_multiplier(aspect_ratio_multiplier);
+}
+
+double
+FGViewMgr::getNear_m () const
+{
+  const FGViewer * view = get_current_view();
+  return (view == 0 ? 0.5f : view->getNear_m());
+}
+
+void
+FGViewMgr::setNear_m (double near_m)
+{
+  FGViewer * view = get_current_view();
+  if (view != 0)
+    view->setNear_m(near_m);
+}
+
+void
+FGViewMgr::setViewAxisLong (double axis)
+{
+  axis_long = axis;
+}
+
+void
+FGViewMgr::setViewAxisLat (double axis)
+{
+  axis_lat = axis;
+}
+
+// reference frame orientation.
+// This is the view orientation you get when you have no
+// view offset, i.e. the offset operator is the identity.
+// 
+// For example, in the familiar "cockpit lookfrom" view,
+// the reference frame is equal to the aircraft attitude,
+// i.e. it is the view looking towards 12:00 straight ahead.
+//
+// FIXME:  Somebody needs to figure out what is the reference
+// frame view for the other view modes.
+// 
+// Conceptually, this quat represents a rotation relative
+// to the ECEF reference orientation, as described at
+//    http://www.av8n.com/physics/coords.htm#sec-orientation
+//
+// See the NOTE concerning reference orientations, below.
+//
+// The components of this quat are expressed in 
+// the conventional aviation basis set,
+// i.e.  x=forward, y=starboard, z=bottom
+double FGViewMgr::getCurrentViewFrame_w() const{
+  return ((current_view_orientation*conj(fsb2sta())*conj(current_view_or_offset))).w();
+}
+double FGViewMgr::getCurrentViewFrame_x() const{
+  return ((current_view_orientation*conj(fsb2sta())*conj(current_view_or_offset))).x();
+}
+double FGViewMgr::getCurrentViewFrame_y() const{
+  return ((current_view_orientation*conj(fsb2sta())*conj(current_view_or_offset))).y();
+}
+double FGViewMgr::getCurrentViewFrame_z() const{
+  return ((current_view_orientation*conj(fsb2sta())*conj(current_view_or_offset))).z();
+}
+
+
+// view offset.
+// This rotation takes you from the aforementioned
+// reference frame view orientation to whatever
+// actual current view orientation is.
+//
+// The components of this quaternion are expressed in 
+// the conventional aviation basis set,
+// i.e.  x=forward, y=starboard, z=bottom
+double FGViewMgr::getCurrentViewOrOffset_w() const{
+   return current_view_or_offset.w();
+}
+double FGViewMgr::getCurrentViewOrOffset_x() const{
+   return current_view_or_offset.x();
+}
+double FGViewMgr::getCurrentViewOrOffset_y() const{
+   return current_view_or_offset.y();
+}
+double FGViewMgr::getCurrentViewOrOffset_z() const{
+   return current_view_or_offset.z();
+}
+
+
+// current view orientation.
+// This is a rotation relative to the earth-centered (ec)
+// reference frame.
+// 
+// NOTE: Here we remove a factor of fsb2sta so that 
+// the components of this quat are displayed using the 
+// conventional ECEF basis set.  This is *not* the way
+// the view orientation is stored in the views[] array,
+// but is easier for non-graphics hackers to understand.
+// If we did not remove this factor of fsb2sta here and
+// in getCurrentViewFrame, that would be equivalent to
+// the following peculiar reference orientation:
+// Suppose you are over the Gulf of Guinea, at (lat,lon) = (0,0).
+// Then the reference frame orientation can be achieved via:
+//    -- The aircraft X-axis (nose) headed south.
+//    -- The aircraft Y-axis (starboard wingtip) pointing up.
+//    -- The aircraft Z-axis (belly) pointing west.
+// To say the same thing in other words, and perhaps more to the
+// point:  If we use the OpenGL camera orientation conventions, 
+// i.e. Xprime=starboard, Yprime=top, Zprime=aft, then the
+// aforementioned peculiar reference orientation at (lat,lon)
+//  = (0,0) can be described as:
+//    -- aircraft Xprime axis (starboard) pointed up
+//    -- aircraft Yprime axis (top) pointed east
+//    -- aircraft Zprime axis (aft) pointed north
+// meaning the OpenGL axes are aligned with the ECEF axes.
+double FGViewMgr::getCurrentViewOrientation_w() const{
+  return (current_view_orientation * conj(fsb2sta())).w();
+}
+double FGViewMgr::getCurrentViewOrientation_x() const{
+  return (current_view_orientation * conj(fsb2sta())).x();
+}
+double FGViewMgr::getCurrentViewOrientation_y() const{
+  return (current_view_orientation * conj(fsb2sta())).y();
+}
+double FGViewMgr::getCurrentViewOrientation_z() const{
+  return (current_view_orientation * conj(fsb2sta())).z();
+}
+
+void
+FGViewMgr::do_axes ()
+{
+                               // Take no action when hat is centered
+  if ( ( axis_long <  0.01 ) &&
+       ( axis_long > -0.01 ) &&
+       ( axis_lat  <  0.01 ) &&
+       ( axis_lat  > -0.01 )
+     )
+    return;
+
+  double viewDir = 999;
+
+  /* Do all the quick and easy cases */
+  if (axis_long < 0) {         // Longitudinal axis forward
+    if (axis_lat == axis_long)
+      viewDir = fgGetDouble("/sim/view/config/front-left-direction-deg");
+    else if (axis_lat == - axis_long)
+      viewDir = fgGetDouble("/sim/view/config/front-right-direction-deg");
+    else if (axis_lat == 0)
+      viewDir = fgGetDouble("/sim/view/config/front-direction-deg");
+  } else if (axis_long > 0) {  // Longitudinal axis backward
+    if (axis_lat == - axis_long)
+      viewDir = fgGetDouble("/sim/view/config/back-left-direction-deg");
+    else if (axis_lat == axis_long)
+      viewDir = fgGetDouble("/sim/view/config/back-right-direction-deg");
+    else if (axis_lat == 0)
+      viewDir = fgGetDouble("/sim/view/config/back-direction-deg");
+  } else if (axis_long == 0) { // Longitudinal axis neutral
+    if (axis_lat < 0)
+      viewDir = fgGetDouble("/sim/view/config/left-direction-deg");
+    else if (axis_lat > 0)
+      viewDir = fgGetDouble("/sim/view/config/right-direction-deg");
+    else return; /* And assertion failure maybe? */
+  }
+
+                               // Do all the difficult cases
+  if ( viewDir > 900 )
+    viewDir = SGD_RADIANS_TO_DEGREES * atan2 ( -axis_lat, -axis_long );
+  if ( viewDir < -1 ) viewDir += 360;
+
+  get_current_view()->setGoalHeadingOffset_deg(viewDir);
+}
diff --git a/src/Viewer/viewmgr.hxx b/src/Viewer/viewmgr.hxx
new file mode 100644 (file)
index 0000000..d094a3d
--- /dev/null
@@ -0,0 +1,165 @@
+// viewmgr.hxx -- class for managing all the views in the flightgear world.
+//
+// Written by Curtis Olson, started October 2000.
+//
+// Copyright (C) 2000  Curtis L. Olson  - http://www.flightgear.org/~curt
+//
+// This program is free software; you can redistribute it and/or
+// modify it under the terms of the GNU General Public License as
+// published by the Free Software Foundation; either version 2 of the
+// License, or (at your option) any later version.
+//
+// This program is distributed in the hope that it will be useful, but
+// WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+// General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License
+// along with this program; if not, write to the Free Software
+// Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
+//
+// $Id$
+
+
+#ifndef _VIEWMGR_HXX
+#define _VIEWMGR_HXX
+
+#include <vector>
+
+#include <simgear/compiler.h>
+#include <simgear/structure/subsystem_mgr.hxx>
+#include <simgear/props/props.hxx>
+#include <simgear/props/tiedpropertylist.hxx>
+#include <simgear/math/SGMath.hxx>
+
+// forward decls
+class FGViewer;
+class SGSoundMgr;
+typedef SGSharedPtr<FGViewer> FGViewerPtr;
+
+// Define a structure containing view information
+class FGViewMgr : public SGSubsystem
+{
+
+public:
+
+    // Constructor
+    FGViewMgr( void );
+
+    // Destructor
+    ~FGViewMgr( void );
+
+    virtual void init ();
+    virtual void bind ();
+    virtual void unbind ();
+    virtual void update (double dt);
+    virtual void reinit ();
+
+    // getters
+    inline int size() const { return views.size(); }
+    inline int get_current() const { return current; }
+    
+    FGViewer *get_current_view();
+    const FGViewer *get_current_view() const;
+    
+    FGViewer *get_view( int i ); 
+    const FGViewer *get_view( int i ) const;
+      
+    FGViewer *next_view();
+    FGViewer *prev_view();
+      
+    // setters
+    void clear();
+
+    void add_view( FGViewer * v );
+    
+private:
+    void do_bind();
+
+    simgear::TiedPropertyList _tiedProperties;
+
+    double axis_long;
+    double axis_lat;
+
+    void do_axes ();
+
+    //  callbacks in manager to access viewer methods
+    double getViewHeadingOffset_deg () const;
+    void setViewHeadingOffset_deg (double offset);
+    double getViewGoalHeadingOffset_deg () const;
+    void setViewGoalHeadingOffset_deg (double offset);
+    double getViewPitchOffset_deg () const;
+    void setViewPitchOffset_deg (double tilt);
+    double getGoalViewPitchOffset_deg () const;
+    void setGoalViewRollOffset_deg (double tilt);
+    double getViewRollOffset_deg () const;
+    void setViewRollOffset_deg (double tilt);
+    double getGoalViewRollOffset_deg () const;
+    void setGoalViewPitchOffset_deg (double tilt);
+    double getViewXOffset_m () const;
+    void setViewXOffset_m (double x);
+    double getViewYOffset_m () const;
+    void setViewYOffset_m (double y);
+    double getViewZOffset_m () const;
+    void setViewZOffset_m (double z);
+    double getViewTargetXOffset_m () const;
+    void setViewTargetXOffset_m (double x);
+    double getViewTargetYOffset_m () const;
+    void setViewTargetYOffset_m (double y);
+    double getViewTargetZOffset_m () const;
+    void setViewTargetZOffset_m (double z);
+    double getFOV_deg () const;
+    void setFOV_deg (double fov);
+    double getARM_deg () const; // Aspect Ratio Multiplier
+    void setARM_deg (double fov);
+    double getNear_m () const;
+    void setNear_m (double near_m);
+    void setViewAxisLong (double axis);
+    void setViewAxisLat (double axis);
+    int getView () const;
+    void setView (int newview);
+
+// quaternion accessors, for debugging:
+    double getCurrentViewOrientation_w() const;
+    double getCurrentViewOrientation_x() const;
+    double getCurrentViewOrientation_y() const;
+    double getCurrentViewOrientation_z() const;
+    double getCurrentViewOrOffset_w() const;
+    double getCurrentViewOrOffset_x() const;
+    double getCurrentViewOrOffset_y() const;
+    double getCurrentViewOrOffset_z() const;
+    double getCurrentViewFrame_w() const;
+    double getCurrentViewFrame_x() const;
+    double getCurrentViewFrame_y() const;
+    double getCurrentViewFrame_z() const;
+
+    bool stationary () const;
+
+    // copies current offset settings to current-view path...
+    void copyToCurrent ();
+    
+    bool inited;
+    SGPropertyNode_ptr view_number;
+    std::vector<SGPropertyNode_ptr> config_list;
+    typedef std::vector<FGViewerPtr> viewer_list;
+    viewer_list views;
+    SGVec3d abs_viewer_position;
+
+    int current;
+    SGQuatd current_view_orientation, current_view_or_offset;
+
+    SGSoundMgr *smgr;
+
+};
+
+// This takes the conventional aviation XYZ body system 
+// i.e.  x=forward, y=starboard, z=bottom
+// which is widely used in FGFS
+// and rotates it into the OpenGL camera system 
+// i.e. Xprime=starboard, Yprime=top, Zprime=aft.
+inline const SGQuatd fsb2sta()
+{
+    return SGQuatd(-0.5, -0.5, 0.5, 0.5);
+}
+
+#endif // _VIEWMGR_HXX