]> git.mxchange.org Git - flightgear.git/commitdiff
CameraGroup class for managing multiple cameras.
authortimoore <timoore>
Fri, 1 Aug 2008 15:57:29 +0000 (15:57 +0000)
committertimoore <timoore>
Fri, 1 Aug 2008 15:57:29 +0000 (15:57 +0000)
CameraGroup supports cameras opened in different windows or in the
same window, with flexible view and perspective specification.

Clean up mouse click handling via osgViewer. Don't let any camera
"have focus;" this forces events to be reported in window coordinates
and simplifies life. Don't use the osgViewer::View::requestWarpPointer
method; instead use our own code which only deals with window
coordinates.

Make glut and sdl versions work with CameraGroup too.

24 files changed:
docs-mini/README.multiscreen [new file with mode: 0644]
src/GUI/gui.cxx
src/GUI/gui.h
src/Input/input.cxx
src/Main/CameraGroup.cxx [new file with mode: 0644]
src/Main/CameraGroup.hxx [new file with mode: 0644]
src/Main/FGManipulator.cxx
src/Main/FGManipulator.hxx
src/Main/Makefile.am
src/Main/WindowBuilder.cxx [new file with mode: 0644]
src/Main/WindowBuilder.hxx [new file with mode: 0644]
src/Main/WindowSystemAdapter.cxx
src/Main/WindowSystemAdapter.hxx
src/Main/fg_os.cxx
src/Main/fg_os.hxx
src/Main/fg_os_osgviewer.cxx
src/Main/fg_os_sdl.cxx
src/Main/main.cxx
src/Main/options.cxx
src/Main/renderer.cxx
src/Main/renderer.hxx
src/Main/viewer.cxx
src/Main/viewer.hxx
src/Scenery/tilemgr.hxx

diff --git a/docs-mini/README.multiscreen b/docs-mini/README.multiscreen
new file mode 100644 (file)
index 0000000..9954f13
--- /dev/null
@@ -0,0 +1,315 @@
+The Open Scene Graph library, which current FlightGear uses for its 3D
+graphics, provides excellent support for multiple views of a
+scene. FlightGear uses the osgViewer::Viewer class, which implements a
+"master" camera with "slave" cameras that are offset from the master's
+position and orientation. FlightGear provides the "camera group"
+abstraction which allows the configuration of slave cameras via the
+property tree.
+
+Slave cameras can be mapped to windows that are open on different
+screens, or all in one window, or a combination of those two schemes,
+according to the video hardware capabilities of a machine. It is not
+advisable to open more than one window on a single graphics card due
+to the added cost of OpenGL context switching between the
+windows. Usually, multiple monitors attached to a single graphics card
+are mapped to different pieces of the same desktop, so a window can be
+opened that spans all the monitors. This is implemented by Nvidia's
+TwinView technology and the Matrox TripleHead2Go hardware.
+
+The camera group is configured by the /sim/rendering/camera-group node
+in the property tree. It can be set up by, among other things, XML in
+preferences.xml or in an XML file specified on the command line with
+the --config option.
+
+Here are the XML tags for defining camera groups.
+
+camera-group
+For the moment there can be only one camera group. It can contain
+window, camera, or gui tags.
+
+ window
+ A window defines a graphics window. It can be at the camera-group
+ level or defined within a camera. The window contains these tags:
+
+  name - string
+  The name of the window which might be displayed in the window's
+  title bar. It is also used to refer to a previously defined
+  window. A window can contain just a name node, in which case
+  the whole window definition refers to a previously defined window.
+
+  host-name - string
+  The name of the host on which the window is opened. Usually this is
+  empty.
+
+  display - int
+  The display number on which the window is opened.
+
+  screen - int
+  The screen number on which the window is opened.
+
+  x, y - int
+  The location on the screen at which the window is opened. This is in
+  the window system coordinates, which usually puts 0,0 at the upper
+  left of the screen XXX check this for Windows.
+
+  width, height - int
+  The dimensions of the window.
+
+  decoration - bool
+  Whether the window manager should decorate the window.
+
+  fullscreen - bool
+  Shorthand for a window that occupies the entire screen with no
+  decoration.
+
+ camera
+ The camera node contains viewing parameters.
+
+  window
+  This specifies the window which displays the camera. Either it
+  contains just a name that refers to a previous window definition, or
+  it is a full window definition.
+
+  viewport
+  The viewport positions a camera within a window. It is most useful
+  when several cameras share a window.
+
+   x, y - int
+   The position of the lower left corner of the viewport, in y-up
+   coordinates.
+
+   width, height - int
+   The dimensions of the viewport
+
+  view
+  The view node specifies the origin and direction of the camera in
+  relation to the whole camera group. The coordinate system is +y up,
+  -z forward in the direction of the camera group view. This is the
+  same as the OpenGL viewing coordinates.
+
+   x,y,z - double
+   Coordinates of the view origin.
+
+   heading-deg, pitch-deg, roll-deg - double
+   Orientation of the view in degrees. These are specified using the
+   right-hand rule, so a positive heading turns the view to the left,
+   a positive roll rolls the view to the left.
+
+  perspective
+  This node is one way of specifying the viewing volume camera
+  parameters. It corresponds to the OpenGL gluPerspective function. 
+
+   fovy-deg - double
+   The vertical field-of-view
+
+   aspect-ratio - double
+   Aspect ratio of camera rectangle (not the ratio between the
+   vertical and horizontal fields of view).
+
+   near, far - double
+   The near and far planes, in meters from the camera eye point. Note
+   that FlightGear assumes that the far plane is far away, currently
+   120km. The far plane specified here will be respected, but the sky
+   and other background elements may not be drawn if the view plane is
+   closer than 120km.
+
+   offset-x, offset-y - double
+   Offsets of the viewing volume specified by the other parameters in
+   the near plane, in meters.
+
+  frustum
+  This specifies the perspective viewing volume using values for the near
+  and far planes and coordinates of the viewing rectangle in the near
+  plane.
+
+   left, bottom - double
+   right, top - double
+   The coordinates of the viewing rectangle.
+
+   near, far - double
+   The near and far planes, in meters from the camera eye point.
+
+  ortho
+  This specifies an orthographic view. The parameters are the sames as
+  the frustum node's.
+
+ gui
+ This is a special camera node that displays the 2D GUI.
+
+  viewport
+  This specifies the position and dimensions of the GUI within a
+  window, *however* at the moment the origin must be at 0,0.
+
+Here's an example that uses a single window mapped across 3
+displays. The displays are in a video wall configuration in a
+horizontal row.
+
+<PropertyList>
+  <sim>
+    <rendering>
+      <camera-group>
+        <window>
+          <name>wide</name>
+          <host-name type="string"></host-name>
+          <display>0</display>
+          <screen>0</screen>
+          <width>3840</width>
+          <height>1024</height>
+          <decoration type = "bool">false</decoration>
+        </window>
+        <camera>
+          <window>
+            <name>wide</name>
+          </window>
+          <viewport>
+            <x>0</x>
+            <y>0</y>
+            <width>1280</width>
+            <height>1024</height>
+          </viewport>
+          <view>
+            <heading-deg type = "double">0</heading-deg>
+          </view>
+          <frustum>
+            <top>0.133</top>
+            <bottom>-0.133</bottom>
+            <left>-.5004</left>
+            <right>-.1668</right>
+            <near>0.4</near>
+            <far>120000.0</far>
+          </frustum>
+        </camera>
+        <camera>
+          <window>
+            <name type="string">wide</name>
+          </window>
+          <viewport>
+            <x>1280</x>
+            <y>0</y>
+            <width>1280</width>
+            <height>1024</height>
+          </viewport>
+          <view>
+            <heading-deg type = "double">0</heading-deg>
+          </view>
+          <frustum>
+            <top>0.133</top>
+            <bottom>-0.133</bottom>
+            <left>-.1668</left>
+            <right>.1668</right>
+            <near>0.4</near>
+            <far>120000.0</far>
+          </frustum>
+        </camera>
+        <camera>
+          <window>
+            <name>wide</name>
+          </window>
+          <viewport>
+            <x>2560</x>
+            <y>0</y>
+            <width>1280</width>
+            <height>1024</height>
+          </viewport>
+          <view>
+            <heading-deg type = "double">0</heading-deg>
+          </view>
+          <frustum>
+            <top>0.133</top>
+            <bottom>-0.133</bottom>
+            <left>.1668</left>
+            <right>.5004</right>
+            <near>0.4</near>
+            <far>120000.0</far>
+          </frustum>
+        </camera>
+        <gui>
+          <window>
+            <name type="string">wide</name>
+          </window>
+        </gui>
+      </camera-group>
+    </rendering>
+  </sim>
+</PropertyList>
+
+Here's a complete example that uses a seperate window on each
+display. The displays are arranged in a shallow arc with the left and
+right displays at a 45.3 degree angle to the center display because,
+at the assumed screen dimensions, the horizontal field of view of one
+display is 45.3 degrees. Each camera has its own window definition;
+the center window is given the name "main" so that the GUI definition
+can refer to it.  Note that the borders of the displays are not
+accounted for.
+
+<PropertyList>
+  <sim>
+    <rendering>
+      <camera-group>
+        <camera>
+          <window>
+            <host-name type="string"></host-name>
+            <display>0</display>
+            <screen>0</screen>
+            <fullscreen type = "bool">true</fullscreen>
+          </window>
+          <view>
+            <heading-deg type = "double">45.3</heading-deg>
+          </view>
+          <frustum>
+            <top>0.133</top>
+            <bottom>-0.133</bottom>
+            <left>-.1668</left>
+            <right>.1668</right>
+            <near>0.4</near>
+            <far>120000.0</far>
+          </frustum>
+        </camera>
+        <camera>
+          <window>
+            <name type="string">main</name>
+            <host-name type="string"></host-name>
+            <display>0</display>
+            <screen>1</screen>
+            <fullscreen type = "bool">true</fullscreen>
+          </window>
+          <view>
+            <heading-deg type = "double">0</heading-deg>
+          </view>
+          <frustum>
+            <top>0.133</top>
+            <bottom>-0.133</bottom>
+            <left>-.1668</left>
+            <right>.1668</right>
+            <near>0.4</near>
+            <far>120000.0</far>
+          </frustum>
+        </camera>
+        <camera>
+          <window>
+            <host-name type="string"></host-name>
+            <display>0</display>
+            <screen>2</screen>
+            <fullscreen type = "bool">true</fullscreen>
+          </window>
+          <view>
+            <heading-deg type = "double">-45.3</heading-deg>
+          </view>
+          <frustum>
+            <top>0.133</top>
+            <bottom>-0.133</bottom>
+            <left>-.1668</left>
+            <right>.1668</right>
+            <near>0.4</near>
+            <far>120000.0</far>
+          </frustum>
+        </camera>
+        <gui>
+          <window>
+            <name type="string">main</name>
+          </window>
+        </gui>
+      </camera-group>
+    </rendering>
+  </sim>
+</PropertyList>
index 77c98d9edeb826f7fbe4cf13a10bdf00f0524dc4..2e8305ba419b6b9adf25aba261b78b8224c6a06d 100644 (file)
@@ -49,7 +49,8 @@
 #include "gui.h"
 #include "layout.hxx"
 
-using namespace osg;
+#include <osg/GraphicsContext>
+
 using namespace flightgear;
 
 puFont guiFnt = 0;
@@ -67,7 +68,7 @@ public:
     GUIInitOperation() : GraphicsContextOperation(std::string("GUI init"))
     {
     }
-    void run(GraphicsContext* gc)
+    void run(osg::GraphicsContext* gc)
     {
         WindowSystemAdapter* wsa = WindowSystemAdapter::getWSA();
         wsa->puInitialize();
@@ -96,21 +97,21 @@ public:
     }
 };
 
-ref_ptr<GUIInitOperation> initOp;
+osg::ref_ptr<GUIInitOperation> initOp;
 }
 
-void guiStartInit()
+void guiStartInit(osg::GraphicsContext* gc)
 {
-    initOp = new GUIInitOperation;
-    WindowSystemAdapter* wsa = WindowSystemAdapter::getWSA();
-    GraphicsContext* gc = wsa->getGUIGraphicsContext();
-    gc->add(initOp.get());
+    if (gc) {
+        initOp = new GUIInitOperation;
+        gc->add(initOp.get());
+    }
 }
 
 bool guiFinishInit()
 {
     if (!initOp.valid())
-        return false;
+        return true;
     if (!initOp->isFinished())
         return false;
     initOp = 0;
index aeb7861678d94199602c7f491f4973b492818fde..5b8478e95f2023cf21db372f9c358742017279ed 100644 (file)
 
 #define TR_HIRES_SNAP   1
 
-
+namespace osg
+{
+class GraphicsContext;
+}
 // gui.cxx
-extern void guiStartInit();
+extern void guiStartInit(osg::GraphicsContext*);
 extern bool guiFinishInit();
 extern void mkDialog(const char *txt);
 extern void guiErrorMessage(const char *txt);
index 7197b27f9ed614ba9706ea20c43821d8ba771ff4..af71173b6d8c232e99ba62cda610cb681f2f4825 100644 (file)
@@ -342,7 +342,7 @@ FGInput::doMouseClick (int b, int updown, int x, int y, bool mainWindow, const o
         // The nearest one is the first one and the deepest
         // (the most specialized one in the scenegraph) is the first.
         std::vector<SGSceneryPick> pickList;
-        if (FGRenderer::pick(x, y, pickList, ea)) {
+        if (FGRenderer::pick(pickList, ea)) {
           std::vector<SGSceneryPick>::const_iterator i;
           for (i = pickList.begin(); i != pickList.end(); ++i) {
             if (i->callback->buttonPressed(b, i->info)) {
diff --git a/src/Main/CameraGroup.cxx b/src/Main/CameraGroup.cxx
new file mode 100644 (file)
index 0000000..b5298d6
--- /dev/null
@@ -0,0 +1,383 @@
+// 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.
+
+#include "CameraGroup.hxx"
+
+#include "globals.hxx"
+#include "renderer.hxx"
+#include "FGManipulator.hxx"
+#include "WindowBuilder.hxx"
+#include "WindowSystemAdapter.hxx"
+#include <simgear/props/props.hxx>
+
+#include <algorithm>
+#include <cstring>
+#include <string>
+
+#include <osg/Camera>
+#include <osg/GraphicsContext>
+#include <osg/Math>
+#include <osg/Matrix>
+#include <osg/Quat>
+#include <osg/Vec3d>
+#include <osg/Viewport>
+
+#include <osgUtil/IntersectionVisitor>
+
+#include <osgViewer/GraphicsWindow>
+
+namespace flightgear
+{
+using namespace osg;
+
+using std::strcmp;
+using std::string;
+
+ref_ptr<CameraGroup> CameraGroup::_defaultGroup;
+
+CameraGroup::CameraGroup(osgViewer::Viewer* viewer) :
+    _viewer(viewer)
+{
+}
+
+CameraInfo* CameraGroup::addCamera(unsigned flags, Camera* camera,
+                                   const Matrix& view,
+                                   const Matrix& projection,
+                                   bool useMasterSceneData)
+{
+    if ((flags & (VIEW_ABSOLUTE | PROJECTION_ABSOLUTE)) != 0)
+        camera->setReferenceFrame(Transform::ABSOLUTE_RF);
+    else
+        camera->setReferenceFrame(Transform::RELATIVE_RF);
+    CameraInfo* info = new CameraInfo(flags, camera);
+    _cameras.push_back(info);
+    _viewer->addSlave(camera, view, projection, useMasterSceneData);
+    info->slaveIndex = _viewer->getNumSlaves() - 1;
+    return info;
+}
+
+void CameraGroup::update(const osg::Vec3d& position,
+                         const osg::Quat& orientation)
+{
+    FGManipulator *manipulator
+        = dynamic_cast<FGManipulator*>(_viewer->getCameraManipulator());
+    if (!manipulator)
+        return;
+    manipulator->setPosition(position);
+    manipulator->setAttitude(orientation);
+    const Matrix masterView(manipulator->getInverseMatrix());
+    const Matrix& masterProj = _viewer->getCamera()->getProjectionMatrix();
+    for (CameraList::iterator i = _cameras.begin(); i != _cameras.end(); ++i) {
+        const CameraInfo* info = i->get();
+        if ((info->flags & (VIEW_ABSOLUTE | PROJECTION_ABSOLUTE)) == 0) {
+            // Camera has relative reference frame and is updated by
+            // osg::View.
+            continue;
+        }
+        const View::Slave& slave = _viewer->getSlave(info->slaveIndex);
+        Camera* camera = info->camera.get();
+        if ((info->flags & VIEW_ABSOLUTE) != 0)
+            camera->setViewMatrix(slave._viewOffset);
+        else
+            camera->setViewMatrix(masterView * slave._viewOffset);
+        if ((info->flags & PROJECTION_ABSOLUTE) != 0)
+            camera->setProjectionMatrix(slave._projectionOffset);
+        else
+            camera->setViewMatrix(masterProj * slave._projectionOffset);
+    }
+}
+
+void CameraGroup::setCameraParameters(float vfov, float aspectRatio)
+{
+    const float zNear = .1f;
+    const float zFar = 120000.0f;
+    _viewer->getCamera()->setProjectionMatrixAsPerspective(vfov,
+                                                           1.0f / aspectRatio,
+                                                           zNear, zFar);
+}
+}
+
+namespace
+{
+osg::Viewport* buildViewport(const SGPropertyNode* viewportNode)
+{
+    double x = viewportNode->getDoubleValue("x", 0.0);
+    double y = viewportNode->getDoubleValue("y", 0.0);
+    double width = viewportNode->getDoubleValue("width", 0.0);
+    double height = viewportNode->getDoubleValue("height", 0.0);
+    return new osg::Viewport(x, y, width, height);
+}
+}
+
+namespace flightgear
+{
+CameraInfo* CameraGroup::buildCamera(const SGPropertyNode* cameraNode)
+{
+    WindowBuilder *wBuild = WindowBuilder::getWindowBuilder();
+    const SGPropertyNode* windowNode = cameraNode->getNode("window");
+    GraphicsWindow* window = 0;
+    static int cameraNum = 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());
+    // 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.
+    const SGPropertyNode* viewportNode = cameraNode->getNode("viewport");
+    Viewport* viewport = 0;
+    if (viewportNode) {
+        viewport = buildViewport(viewportNode);
+    } else {
+        const GraphicsContext::Traits *traits = window->gc->getTraits();
+        viewport = new Viewport(0, 0, traits->width, traits->height);
+    }
+    camera->setViewport(viewport);
+    osg::Matrix pOff;
+    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));
+    }
+    const 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", 0.0);
+        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;
+    } 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", 0.0);
+        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);
+        }
+    } else {
+        // old style shear parameters
+        double shearx = cameraNode->getDoubleValue("shear-x", 0);
+        double sheary = cameraNode->getDoubleValue("shear-y", 0);
+        pOff.makeTranslate(-shearx, -sheary, 0);
+    }
+    return addCamera(cameraFlags, camera, pOff, vOff);
+}
+
+CameraInfo* CameraGroup::buildGUICamera(const SGPropertyNode* cameraNode,
+                                        GraphicsWindow* window)
+{
+    WindowBuilder *wBuild = WindowBuilder::getWindowBuilder();
+    const SGPropertyNode* windowNode = (cameraNode
+                                        ? cameraNode->getNode("window")
+                                        : 0);
+    static int cameraNum = 0;
+    if (!window) {
+        if (windowNode) {
+            // New style window declaration / definition
+            window = wBuild->buildWindow(windowNode);
+            
+        } else {
+            return 0;
+        }
+    }
+    Camera* camera = new Camera;
+    camera->setAllowEventFocus(false);
+    camera->setGraphicsContext(window->gc.get());
+    const SGPropertyNode* viewportNode = (cameraNode
+                                          ? cameraNode->getNode("viewport")
+                                          : 0);
+    Viewport* viewport = 0;
+    if (viewportNode) {
+        viewport = buildViewport(viewportNode);
+    } else {
+        const GraphicsContext::Traits *traits = window->gc->getTraits();
+        viewport = new Viewport(0, 0, traits->width, traits->height);
+    }
+    camera->setViewport(viewport);
+    // XXX Camera needs to be drawn last; eventually the render order
+    // should be assigned by a camera manager.
+    camera->setRenderOrder(osg::Camera::POST_RENDER, 100);
+        camera->setClearMask(0);
+    camera->setInheritanceMask(CullSettings::ALL_VARIABLES
+                               & ~(CullSettings::COMPUTE_NEAR_FAR_MODE
+                                   | CullSettings::CULLING_MODE));
+    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;
+    return addCamera(cameraFlags, camera,
+                     Matrixd::identity(), Matrixd::identity(), false);
+}
+
+CameraGroup* CameraGroup::buildCameraGroup(osgViewer::Viewer* viewer,
+                                           const SGPropertyNode* gnode)
+{
+    CameraGroup* cgroup = new CameraGroup(viewer);
+    for (int i = 0; i < gnode->nChildren(); ++i) {
+        const 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);
+        }
+    }
+    return cgroup;
+}
+
+Camera* getGUICamera(CameraGroup* cgroup)
+{
+    CameraGroup::CameraIterator end = cgroup->camerasEnd();
+    CameraGroup::CameraIterator result
+        = std::find_if(cgroup->camerasBegin(), end,
+                       FlagTester<CameraInfo>(CameraGroup::GUI));
+    if (result != end)
+        return (*result)->camera.get();
+    else
+        return 0;
+}
+
+bool computeIntersections(const CameraGroup* cgroup,
+                          const osgGA::GUIEventAdapter* ea,
+                          osgUtil::LineSegmentIntersector::Intersections& intersections)
+{
+    using osgUtil::Intersector;
+    using osgUtil::LineSegmentIntersector;
+    double x, y;
+    eventToWindowCoords(ea, x, y);
+    // Find camera that contains event
+    for (CameraGroup::ConstCameraIterator iter = cgroup->camerasBegin(),
+             e = cgroup->camerasEnd();
+         iter != e;
+         ++iter) {
+        const CameraInfo* cinfo = iter->get();
+        if ((cinfo->flags & CameraGroup::DO_INTERSECTION_TEST) == 0)
+            continue;
+        const Camera* camera = cinfo->camera.get();
+        if (camera->getGraphicsContext() != ea->getGraphicsContext())
+            continue;
+        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))
+            continue;
+        LineSegmentIntersector::CoordinateFrame cf = Intersector::WINDOW;
+        ref_ptr<LineSegmentIntersector> picker
+            = new LineSegmentIntersector(cf, x, y);
+        osgUtil::IntersectionVisitor iv(picker.get());
+        const_cast<Camera*>(camera)->accept(iv);
+        if (picker->containsIntersections()) {
+            intersections = picker->getIntersections();
+            return true;
+        } else {
+            break;
+        }
+    }
+    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()->getManipulator()->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
new file mode 100644 (file)
index 0000000..e76f3a5
--- /dev/null
@@ -0,0 +1,198 @@
+// 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 <string>
+#include <vector>
+
+#include <osg/Matrix>
+#include <osg/ref_ptr>
+#include <osg/Referenced>
+
+// 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;
+
+/** A wrapper around osg::Camera that contains some extra information.
+ */
+struct CameraInfo : public osg::Referenced
+{
+    CameraInfo(unsigned flags_, osg::Camera* camera_)
+        : flags(flags_), camera(camera_), slaveIndex(-1)
+    {
+    }
+    /** Properties of the camera. @see CameraGroup::Flags.
+     */
+    unsigned flags;
+    /** the camera object
+     */
+    osg::ref_ptr<osg::Camera> camera;
+    /** Index of this camera in the osgViewer::Viewer slave list.
+     */
+    int slaveIndex;
+};
+
+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. */
+    };
+    /** 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(); }
+    /** 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.
+     */
+    CameraInfo* addCamera(unsigned flags, osg::Camera* camera,
+                          const osg::Matrix& projection,
+                          const osg::Matrix& view,
+                          bool useMasterSceneData = true);
+    /** 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(const 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(const 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(); }
+    /** 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,
+                                         const SGPropertyNode* node);
+protected:
+    CameraList _cameras;
+    osg::ref_ptr<osgViewer::Viewer> _viewer;
+    static osg::ref_ptr<CameraGroup> _defaultGroup;
+};
+
+}
+
+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
index 9c9af6805c14a7014fef1a57725c864aadb23a47..b6d761f48070ffc1a902ebad59a2ac91fc5ae4b7 100644 (file)
@@ -1,16 +1,24 @@
 #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 "FGManipulator.hxx"
+#include "WindowSystemAdapter.hxx"
 
 #if !defined(X_DISPLAY_MISSING)
 #define X_DOUBLE_SCROLL_BUG 1
 #endif
 
+namespace flightgear
+{
 const int displayStatsKey = 1;
 const int printStatsKey = 2;
 
@@ -91,8 +99,10 @@ osg::Node* FGManipulator::getNode()
     return _node.get();
 }
 
+namespace
+{
 // Translate OSG modifier mask to FG modifier mask.
-static int osgToFGModifiers(int modifiers)
+int osgToFGModifiers(int modifiers)
 {
     int result = 0;
     if (modifiers & osgGA::GUIEventAdapter::MODKEY_SHIFT)
@@ -114,6 +124,7 @@ static int osgToFGModifiers(int modifiers)
         result |= KEYMOD_HYPER;
     return result;
 }
+}
 
 void FGManipulator::init(const osgGA::GUIEventAdapter& ea,
                          osgGA::GUIActionAdapter& us)
@@ -122,29 +133,42 @@ void FGManipulator::init(const osgGA::GUIEventAdapter& ea,
     (void)handle(ea, us);
 }
 
-static bool
+// 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 osgViewer::Viewer* viewer;
-    viewer = dynamic_cast<const osgViewer::Viewer*>(&us);
-    if (!viewer)
+    const osg::GraphicsContext* eventGC = ea.getGraphicsContext();
+    const osg::GraphicsContext::Traits* traits = eventGC->getTraits();
+    osg::Camera* guiCamera = getGUICamera(CameraGroup::getDefault());
+    if (!guiCamera)
         return false;
-
-    float lx, ly;
-    const osg::Camera* camera;
-    camera = viewer->getCameraContainingPosition(ea.getX(), ea.getY(), lx, ly);
-
-    if (!(camera && fgOSIsMainCamera(camera)))
+    osg::Viewport* vport = guiCamera->getViewport();
+    if (!vport)
         return false;
-
-    x = int(lx);
-    y = int(camera->getViewport()->height() - ly);
-
-    return true;
+    
+    // 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 FGManipulator::handle(const osgGA::GUIEventAdapter& ea,
@@ -337,3 +361,33 @@ void FGManipulator::handleStats(osgGA::GUIActionAdapter& us)
     }
 }
 
+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;
+}
+}
index 95329c19cb467df7c332a27ba0a8de69e8d64abe..cc1c5f5525fc91e33ade14a81fadb2c276d3885b 100644 (file)
@@ -8,6 +8,8 @@
 
 #include "fg_os.hxx"
 
+namespace flightgear
+{
 class FGManipulator : public osgGA::MatrixManipulator {
 public:
     FGManipulator();
@@ -142,4 +144,9 @@ protected:
     int release_keys[128];
     void handleStats(osgGA::GUIActionAdapter& us);
 };
+
+void eventToWindowCoords(const osgGA::GUIEventAdapter* ea, double& x, double& y);
+void eventToWindowCoordsYDown(const osgGA::GUIEventAdapter* ea,
+                              double& x, double& y);
+}
 #endif
index 343d2fb752c5f99fdb8c74a8b6a4ad25cacec0e8..0930f31217820830c0e685aff506b76796d699f1 100644 (file)
@@ -60,9 +60,11 @@ libMain_a_SOURCES = \
        util.cxx util.hxx \
        viewer.cxx viewer.hxx \
        viewmgr.cxx viewmgr.hxx \
+       CameraGroup.cxx CameraGroup.hxx \
        FGManipulator.cxx FGManipulator.hxx \
        ViewPartitionNode.cxx ViewPartitionNode.hxx \
        WindowSystemAdapter.hxx WindowSystemAdapter.cxx \
+       WindowBuilder.hxx WindowBuilder.cxx \
        $(GFX_CODE)
 
 fgfs_SOURCES = bootstrap.cxx
diff --git a/src/Main/WindowBuilder.cxx b/src/Main/WindowBuilder.cxx
new file mode 100644 (file)
index 0000000..aaabbb2
--- /dev/null
@@ -0,0 +1,228 @@
+// 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.
+
+#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;
+
+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();
+    int w = fgGetInt("/sim/startup/xsize");
+    int h = fgGetInt("/sim/startup/ysize");
+    int bpp = fgGetInt("/sim/rendering/bits-per-pixel");
+    bool alpha = fgGetBool("/sim/rendering/clouds3d-enable");
+    bool fullscreen = fgGetBool("/sim/startup/fullscreen");
+
+    GraphicsContext::Traits* traits = new osg::GraphicsContext::Traits;
+    traits->readDISPLAY();
+    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;
+    traits->doubleBuffer = true;
+    traits->mipMapGeneration = true;
+    traits->windowName = "FlightGear";
+    // XXX should check per window too.
+    traits->sampleBuffers = fgGetBool("/sim/rendering/multi-sample-buffers", traits->sampleBuffers);
+    traits->samples = fgGetBool("/sim/rendering/multi-samples", traits->samples);
+    traits->vsync = fgGetBool("/sim/rendering/vsync-enable", traits->vsync);
+    if (fullscreen) {
+        unsigned width = 0;
+        unsigned height = 0;
+        wsi->getScreenResolution(*traits, width, height);
+       traits->windowDecoration = false;
+        traits->width = width;
+        traits->height = height;
+        traits->supportsResize = false;
+    } else {
+       traits->windowDecoration = true;
+        traits->width = w;
+        traits->height = h;
+#if defined(WIN32) || defined(__APPLE__)
+        // Ugly Hack, why does CW_USEDEFAULT works like phase of the moon?
+        // Mac also needs this to show window frame, menubar and Docks
+        traits->x = 100;
+        traits->y = 100;
+#endif
+        traits->supportsResize = true;
+    }
+    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()) {
+        unsigned width = 0;
+        unsigned height = 0;
+        wsi->getScreenResolution(*traits, width, height);
+        traits->windowDecoration = false;
+        traits->width = width;
+        traits->height = height;
+        traits->supportsResize = false;
+        traitsSet = 1;
+    } else {
+        int resizable = 0;
+        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) {
+            gc->realize();
+            GraphicsWindow* window = WindowSystemAdapter::getWSA()
+                ->registerWindow(gc, traits->windowName);
+            if (drawGUI)
+                window->flags |= GraphicsWindow::GUI;
+            return window;
+        } else {
+            return 0;
+        }
+    } else {
+        return getDefaultWindow();
+    }
+}
+
+GraphicsWindow* WindowBuilder::getDefaultWindow()
+{
+    if (defaultWindow.valid())
+        return defaultWindow.get();
+    GraphicsContext::Traits* traits
+        = new GraphicsContext::Traits(*defaultTraits);
+    traits->windowName = "FlightGear";
+    GraphicsContext* gc = GraphicsContext::createGraphicsContext(traits);
+    if (gc) {
+        gc->realize();
+        defaultWindow = WindowSystemAdapter::getWSA()
+            ->registerWindow(gc, traits->windowName);
+        return defaultWindow.get();
+    } else {
+        return 0;
+    }
+}
+}
diff --git a/src/Main/WindowBuilder.hxx b/src/Main/WindowBuilder.hxx
new file mode 100644 (file)
index 0000000..287d4ce
--- /dev/null
@@ -0,0 +1,72 @@
+// 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();
+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;
+    osg::ref_ptr<GraphicsWindow> defaultWindow;
+};
+
+/** 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
index 2739cd0452c1211a5aa253489a282b18d9c761f8..9da3400b1b8239d8cc8f8a3be12d9e3c3f950fbd 100644 (file)
 #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;
 
-using namespace flightgear;
-
+namespace flightgear
+{
 ref_ptr<WindowSystemAdapter> WindowSystemAdapter::_wsa;
 
 void GraphicsContextOperation::operator()(GraphicsContext* gc)
@@ -38,7 +43,7 @@ void GraphicsContextOperation::operator()(GraphicsContext* gc)
 }
 
 WindowSystemAdapter::WindowSystemAdapter() :
-    _nextWindowID(0), _nextCameraID(0), _isPuInitialized(false)
+    _nextWindowID(0), _isPuInitialized(false)
 {
 }
 
@@ -52,63 +57,25 @@ WindowSystemAdapter::registerWindow(GraphicsContext* gc,
     return window;
 }
 
-Camera3D*
-WindowSystemAdapter::registerCamera3D(GraphicsWindow* gw, Camera* camera,
-                                      const string& cameraName)
-{
-    Camera3D* camera3D = new Camera3D(gw, camera, cameraName);
-    cameras.push_back(camera3D);
-    return camera3D;
-}
-
-GraphicsWindow*
-WindowSystemAdapter::getGUIWindow()
-{
-    WindowVector::const_iterator contextIter
-        = std::find_if(windows.begin(), windows.end(),
-                       FlagTester<GraphicsWindow>(GraphicsWindow::GUI));
-    if (contextIter == windows.end())
-        return 0;
-    else
-        return contextIter->get();
-}
-
-int
-WindowSystemAdapter::getGUIWindowID()
-{
-    const GraphicsWindow* gw = getGUIWindow();
-    if (!gw)
-        return -1;
-    else
-        return gw->id;
-}
-
-GraphicsContext*
-WindowSystemAdapter::getGUIGraphicsContext()
-{
-    GraphicsWindow* gw = getGUIWindow();
-    if (!gw)
-        return 0;
-    else
-        return gw->gc.get();
-}
-
-
+// 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()
 {
-    WindowSystemAdapter* wsa = getWSA();
-    return wsa->getGUIWindowID();
+    return 1;
 }
 
 void WindowSystemAdapter::puGetWindowSize(int* width, int* height)
 {
-    // XXX This will have to be different when multiple cameras share
-    // a single window.
-    WindowSystemAdapter* wsa = getWSA();
-    const GraphicsContext* gc = wsa->getGUIGraphicsContext();
-    const GraphicsContext::Traits *traits = gc->getTraits();
-    *width = traits->width;
-    *height = traits->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()
@@ -116,3 +83,15 @@ 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;
+}
+}
index 8683632b36de1cbc3dc131f7f0c86e70fc1df599..b359f8e97f3ff2c4339b4c65ae8bca1f7b02a878 100644 (file)
 
 #include <osg/Referenced>
 #include <osg/Camera>
-#include <osg/GraphicsContext>
 #include <osg/GraphicsThread>
+#include <osg/ref_ptr>
 
 #include <simgear/structure/SGAtomic.hxx>
 
-// Flexible Camera and window support
+namespace osg
+{
+class GraphicsContext;
+}
+
+// Flexible window support
 namespace flightgear
 {
-/** A window opened by default or via rendering properties
+/** A window with a graphics context and an integer ID
  */
 class GraphicsWindow : public osg::Referenced
 {
@@ -46,42 +51,23 @@ public:
     /** The window's internal name.
      */
     std::string name;
-    enum Flags {
-        /** The GUI (and 2D cockpit) will be drawn on this window.
-         */
-        GUI = 1
-    };
+    /** A unique ID for the window.
+     */
     int id;
-    unsigned flags;
-};
-
-/** Camera associated with a 3d view. The camera might occupy an
- * entire window or share one with other cameras.
- */
-class Camera3D : public osg::Referenced
-{
-public:
-    Camera3D(GraphicsWindow* window_, osg::Camera* camera_, const std::string& name_,
-             unsigned flags_ = 0) :
-        window(window_), camera(camera_), name(name_), flags(flags_)
-    {
-    }
-    osg::ref_ptr<GraphicsWindow> window;
-    osg::ref_ptr<osg::Camera> camera;
-    std::string name;
     enum Flags {
-        SHARES_WINDOW = 1,      /**< Camera shares window with other cameras*/
-        MASTER = 2              /**< Camera has same view as master camera*/
+        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;
-typedef std::vector<osg::ref_ptr<Camera3D> >  Camera3DVector;
 
 /**
  * An operation that is run once with a particular GraphicsContext
- * current.
+ * current. It will probably be deferred and may run in a different
+ * thread.
  */
 class GraphicsContextOperation : public osg::GraphicsOperation
 {
@@ -90,8 +76,15 @@ public:
         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;
@@ -99,7 +92,7 @@ private:
 
 /** 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
+ * between osgViewer::Viewer, which handles multiple windows, graphics
  * threads, etc., and the embedded viewer used with GLUT and SDL.
  */
 class WindowSystemAdapter : public osg::Referenced
@@ -107,37 +100,35 @@ class WindowSystemAdapter : public osg::Referenced
 public:
     WindowSystemAdapter();
     virtual ~WindowSystemAdapter() {}
+    /** Vector of all the registered windows.
+     */
     WindowVector windows;
-    Camera3DVector cameras;
+    /** 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);
-    Camera3D* registerCamera3D(GraphicsWindow* gw, osg::Camera* camera,
-                               const std::string& cameraName);
-    GraphicsWindow* getGUIWindow();
-    int getGUIWindowID();
-    osg::GraphicsContext* getGUIGraphicsContext();
     /** Initialize the plib pui interface library. This might happen
      *in another thread and may be deferred.
      */
     virtual void puInitialize();
-    /** Returns true if pui initialization has finished.
+    /** 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
      */
-    template<typename T>
-    class FlagTester : public std::unary_function<osg::ref_ptr<T>, bool>
-    {
-    public:
-        FlagTester(unsigned flags_) : flags(flags_) {}
-        bool operator() (const osg::ref_ptr<T>& obj)
-        {
-            return (obj->flags & flags) != 0;
-        }
-        unsigned flags;
-    };
     static WindowSystemAdapter* getWSA() { return _wsa.get(); }
+    /** Set the global adapter
+     * @param wsa the adapter
+     */
     static void setWSA(WindowSystemAdapter* wsa) { _wsa = wsa; }
 protected:
     int _nextWindowID;
-    int _nextCameraID;
     osg::ref_ptr<GraphicsContextOperation> _puInitOp;
     bool _isPuInitialized;
     static osg::ref_ptr<WindowSystemAdapter> _wsa;
@@ -146,5 +137,29 @@ protected:
     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 0ecde2c921f7dc8a67b36ddaf4b43fa23499b085..dfce9b2aaad59e61957e7b334271683764f90d6d 100644 (file)
@@ -7,6 +7,7 @@
 #  include <config.h>
 #endif
 
+#include <osg/Matrix>
 #include <osgViewer/Viewer>
 #include <osgViewer/ViewerEventHandlers>
 
@@ -25,6 +26,7 @@
 #include "renderer.hxx"
 #include "fg_props.hxx"
 #include "WindowSystemAdapter.hxx"
+#include "CameraGroup.hxx"
 
 using namespace flightgear;
 
@@ -34,7 +36,6 @@ using namespace flightgear;
 //
 
 static osg::ref_ptr<osgViewer::Viewer> viewer;
-static osg::ref_ptr<osg::Camera> mainCamera;
 static osg::ref_ptr<osgViewer::GraphicsWindowEmbedded> gw;
 
 static int GlutModifiers = 0;
@@ -274,16 +275,17 @@ void fgOSOpenWindow(bool stencil)
     viewer->setDatabasePager(FGScenery::getPagerSingleton());
     // now the main camera ...
     osg::Camera* camera = new osg::Camera;
-    mainCamera = camera;
     // 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.
     camera->setViewport(new osg::Viewport(0, 0, realw, realh));
     camera->setProjectionResizePolicy(osg::Camera::FIXED);
-    Camera3D* cam3D = wsa->registerCamera3D(window, camera, string("main"));
-    cam3D->flags |= Camera3D::MASTER; 
-    // Add as a slave for compatibility with the non-embedded osgViewer.
-    viewer->addSlave(camera);
+    CameraGroup* cgroup = new CameraGroup(viewer.get());
+    cgroup->addCamera(CameraGroup::DO_INTERSECTION_TEST, camera,
+                      osg::Matrixd::identity(), osg::Matrixd::identity(),
+                      true);
+    cgroup->buildGUICamera(0, window);
+    CameraGroup::setDefault(cgroup);
     viewer->setCameraManipulator(globals->get_renderer()->getManipulator());
     // Let FG handle the escape key with a confirmation
     viewer->setKeyEventSetsDone(0);
@@ -295,18 +297,3 @@ void fgOSOpenWindow(bool stencil)
     viewer->setSceneData(new osg::Group);
     globals->get_renderer()->setViewer(viewer.get());
 }
-
-bool fgOSIsMainCamera(const osg::Camera*)
-{
-  return true;
-}
-
-bool fgOSIsMainContext(const osg::GraphicsContext*)
-{
-  return true;
-}
-
-osg::GraphicsContext* fgOSGetMainContext()
-{
-    return gw.get();
-}
index c12e79b7bd0d9aa27d4a662139a5c7ff18ce65ad..86710b680621e8d1a2d93ea664c71504cefa5842 100644 (file)
@@ -84,18 +84,4 @@ void fgRegisterWindowResizeHandler(fgWindowResizeHandler func);
 void fgRegisterKeyHandler(fgKeyHandler func);
 void fgRegisterMouseClickHandler(fgMouseClickHandler func);
 void fgRegisterMouseMotionHandler(fgMouseMotionHandler func);
-
-bool fgOSIsMainCamera(const osg::Camera* camera);
-bool fgOSIsMainContext(const osg::GraphicsContext* context);
-
-/** Get graphics context of the main camera. This is the principal
- * window in multi-window configurations, or the only window in an
- * embedded configuration. The GUI will be added to this context.
- */
-osg::GraphicsContext* fgOSGetMainContext();
-
-
-
-
-
 #endif // _FG_OS_HXX
index 5f3ecbdba363436cbd6fee93ecc0460f0be5faa1..ee7367ef02d19fe69ad453d523556bbf8032286f 100644 (file)
 // 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>
@@ -33,6 +29,7 @@
 #include <simgear/structure/exception.hxx>
 #include <simgear/debug/logstream.hxx>
 
+#include <osg/Camera>
 #include <osg/GraphicsContext>
 #include <osg/Group>
 #include <osg/Matrixd>
@@ -50,6 +47,8 @@
 #include "util.hxx"
 #include "globals.hxx"
 #include "renderer.hxx"
+#include "CameraGroup.hxx"
+#include "WindowBuilder.hxx"
 #include "WindowSystemAdapter.hxx"
 
 #if (FG_OSG_VERSION >= 19008)
@@ -67,113 +66,66 @@ using namespace std;
 using namespace flightgear;
 using namespace osg;
 
-
-
 static osg::ref_ptr<osgViewer::Viewer> viewer;
 static osg::ref_ptr<osg::Camera> mainCamera;
 
-// Callback to prevent the GraphicsContext resized function from messing
-// with the projection matrix of the slave
-
 namespace
 {
-// silly function for making the default window and camera names
-std::string makeName(const string& prefix, int num)
+// If a camera group isn't specified, build one from the top-level
+// camera specs and then add a camera aligned with the master camera
+// if it doesn't seem to exist.
+CameraGroup* buildDefaultCameraGroup(osgViewer::Viewer* viewer,
+                                     const SGPropertyNode* gnode)
 {
-    std::stringstream stream;
-    stream << prefix << num;
-    return stream.str();
-}
-
-GraphicsContext::Traits*
-makeDefaultTraits(GraphicsContext::WindowingSystemInterface* wsi, bool stencil)
-{
-    int w = fgGetInt("/sim/startup/xsize");
-    int h = fgGetInt("/sim/startup/ysize");
-    int bpp = fgGetInt("/sim/rendering/bits-per-pixel");
-    bool alpha = fgGetBool("/sim/rendering/clouds3d-enable");
-    bool fullscreen = fgGetBool("/sim/startup/fullscreen");
-
-    GraphicsContext::Traits* traits = new osg::GraphicsContext::Traits;
-    traits->readDISPLAY();
-    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;
-    traits->doubleBuffer = true;
-    traits->mipMapGeneration = true;
-    traits->windowName = "FlightGear";
-    // XXX should check per window too.
-    traits->sampleBuffers = fgGetBool("/sim/rendering/multi-sample-buffers", traits->sampleBuffers);
-    traits->samples = fgGetBool("/sim/rendering/multi-samples", traits->samples);
-    traits->vsync = fgGetBool("/sim/rendering/vsync-enable", traits->vsync);
-    if (fullscreen) {
-        unsigned width = 0;
-        unsigned height = 0;
-        wsi->getScreenResolution(*traits, width, height);
-       traits->windowDecoration = false;
-        traits->width = width;
-        traits->height = height;
-        traits->supportsResize = false;
-    } else {
-       traits->windowDecoration = true;
-        traits->width = w;
-        traits->height = h;
-#if defined(WIN32) || defined(__APPLE__)
-        // Ugly Hack, why does CW_USEDEFAULT works like phase of the moon?
-        // Mac also needs this to show window frame, menubar and Docks
-        traits->x = 100;
-        traits->y = 100;
-#endif
-        traits->supportsResize = true;
+    WindowSystemAdapter* wsa = WindowSystemAdapter::getWSA();
+    CameraGroup* cgroup = CameraGroup::buildCameraGroup(viewer, gnode);
+    // Look for a camera with no shear
+    Camera* masterCamera = 0;
+    for (CameraGroup::CameraIterator iter = cgroup->camerasBegin(),
+             e = cgroup->camerasEnd();
+         iter != e;
+         ++iter) {
+        const View::Slave& slave = viewer->getSlave((*iter)->slaveIndex);
+        if (slave._projectionOffset.isIdentity()) {
+            masterCamera = (*iter)->camera.get();
+            break;
+        }
     }
-    return traits;
-}
-
-void setTraitsFromProperties(GraphicsContext::Traits* traits,
-                             const SGPropertyNode* winNode,
-                             GraphicsContext::WindowingSystemInterface* wsi)
-{
-    traits->hostName
-        = winNode->getStringValue("host-name", traits->hostName.c_str());
-    traits->displayNum = winNode->getIntValue("display", traits->displayNum);
-    traits->screenNum = winNode->getIntValue("screen", traits->screenNum);
-    if (winNode->getBoolValue("fullscreen",
-                              fgGetBool("/sim/startup/fullscreen"))) {
-        unsigned width = 0;
-        unsigned height = 0;
-        wsi->getScreenResolution(*traits, width, height);
-        traits->windowDecoration = false;
-        traits->width = width;
-        traits->height = height;
-        traits->supportsResize = false;
-    } else {
-        traits->windowDecoration = winNode->getBoolValue("decoration", true);
-        traits->width = winNode->getIntValue("width", traits->width);
-        traits->height = winNode->getIntValue("height", traits->height);
-        traits->supportsResize = true;
+    if (!masterCamera) {
+        // No master camera found; better add one.
+        GraphicsWindow* window
+            = WindowBuilder::getWindowBuilder()->getDefaultWindow();
+        masterCamera = new Camera();
+        masterCamera->setGraphicsContext(window->gc.get());
+        const GraphicsContext::Traits *traits = window->gc->getTraits();
+        masterCamera->setViewport(new Viewport(0, 0,
+                                               traits->width, traits->height));
+        cgroup->addCamera(CameraGroup::DO_INTERSECTION_TEST, masterCamera,
+                          Matrix(), Matrix());
     }
-    traits->x = winNode->getIntValue("x", traits->x);
-    traits->y = winNode->getIntValue("y", traits->y);
-    if (winNode->hasChild("window-name"))
-        traits->windowName = winNode->getStringValue("window-name");
-    else if (winNode->hasChild("name")) 
-        traits->windowName = winNode->getStringValue("name");
+    // Find window on which the GUI is drawn.
+    WindowVector::iterator iter = wsa->windows.begin();
+    WindowVector::iterator end = wsa->windows.end();
+    for (; iter != end; ++iter) {
+        if ((*iter)->gc.get() == masterCamera->getGraphicsContext())
+            break;
+    }
+    if (iter != end) {            // Better not happen
+        (*iter)->flags |= GraphicsWindow::GUI;
+        cgroup->buildGUICamera(0, iter->get());
+    }
+    return cgroup;
+}
 }
-
-} //namespace
 
 void fgOSOpenWindow(bool stencil)
 {
-    osg::GraphicsContext::WindowingSystemInterface* wsi;
-    wsi = osg::GraphicsContext::getWindowingSystemInterface();
+    osg::GraphicsContext::WindowingSystemInterface* wsi
+        = osg::GraphicsContext::getWindowingSystemInterface();
 
     viewer = new osgViewer::Viewer;
     viewer->setDatabasePager(FGScenery::getPagerSingleton());
+    CameraGroup* cameraGroup = 0;
     std::string mode;
     mode = fgGetString("/sim/rendering/multithreading-mode", "SingleThreaded");
     if (mode == "AutomaticSelection")
@@ -186,111 +138,32 @@ void fgOSOpenWindow(bool stencil)
       viewer->setThreadingModel(osgViewer::Viewer::CullThreadPerCameraDrawThreadPerContext);
     else
       viewer->setThreadingModel(osgViewer::Viewer::SingleThreaded);
-    osg::ref_ptr<osg::GraphicsContext::Traits> traits
-        = makeDefaultTraits(wsi, stencil);
-
-    // Ok, first the children.
-    // that achieves some magic ordering og the slaves so that we end up
-    // in the main window more often.
-    // This can be sorted out better when we got rid of glut and sdl.
-    FGManipulator* manipulator = globals->get_renderer()->getManipulator();
-    string defaultName("slave");
-    WindowSystemAdapter* wsa = WindowSystemAdapter::getWSA();
-    if (fgHasNode("/sim/rendering/camera")) {
-        SGPropertyNode* renderingNode = fgGetNode("/sim/rendering");
-        for (int i = 0; i < renderingNode->nChildren(); ++i) {
-            SGPropertyNode* cameraNode = renderingNode->getChild(i);
-            if (strcmp(cameraNode->getName(), "camera") != 0)
-                continue;
-
-            // get a new copy of the traits struct
-            osg::ref_ptr<osg::GraphicsContext::Traits> cameraTraits;
-            cameraTraits = new osg::GraphicsContext::Traits(*traits);
-            double shearx = cameraNode->getDoubleValue("shear-x", 0);
-            double sheary = cameraNode->getDoubleValue("shear-y", 0);
-            double heading = cameraNode->getDoubleValue("heading-deg", 0);
-            setTraitsFromProperties(cameraTraits.get(), cameraNode, wsi);
-            // FIXME, currently this is too much of a problem to route
-            // the resize events. When we do no longer need sdl and
-            // such this can be simplified
-            cameraTraits->supportsResize = false;
-
-            // ok found a camera configuration, add a new slave if possible
-            GraphicsContext* gc
-                = GraphicsContext::createGraphicsContext(cameraTraits.get());
-            if (gc) {
-                gc->realize();
-                Camera *camera = new Camera;
-                camera->setGraphicsContext(gc);
-                // 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.
-                camera->setViewport(new Viewport(0, 0, cameraTraits->width,
-                                                 cameraTraits->height));
-                const char* cameraName = cameraNode->getStringValue("name");
-                string cameraNameString = (cameraName ? string(cameraName)
-                                           : makeName(defaultName, i));
-                GraphicsWindow* window = wsa->registerWindow(gc,
-                                                             cameraNameString);
-                Camera3D* cam3D = wsa->registerCamera3D(window, camera,
-                                                        cameraNameString);
-                if (shearx == 0 && sheary == 0)
-                    cam3D->flags |= Camera3D::MASTER;
-                
-                osg::Matrix pOff = osg::Matrix::translate(-shearx, -sheary, 0);
-                osg::Matrix vOff;
-                vOff.makeRotate(SGMiscd::deg2rad(heading), osg::Vec3(0, 1, 0));
-                viewer->addSlave(camera, pOff, vOff);
-            } else {
-                SG_LOG(SG_GENERAL, SG_WARN,
-                       "Couldn't create graphics context on "
-                       << cameraTraits->hostName << ":"
-                       << cameraTraits->displayNum
-                       << "." << cameraTraits->screenNum);
-            }
+    WindowBuilder::initWindowBuilder(stencil);
+    WindowBuilder *windowBuilder = WindowBuilder::getWindowBuilder();
+
+    // Look for windows, camera groups, and the old syntax of
+    // top-level cameras
+    const SGPropertyNode* renderingNode = fgGetNode("/sim/rendering");
+    for (int i = 0; i < renderingNode->nChildren(); ++i) {
+        const SGPropertyNode* propNode = renderingNode->getChild(i);
+        const char* propName = propNode->getName();
+        if (!strcmp(propName, "window")) {
+            windowBuilder->buildWindow(propNode);
+        } else if (!strcmp(propName, "camera-group")) {
+            cameraGroup = CameraGroup::buildCameraGroup(viewer.get(), propNode);
         }
     }
-    // now the main camera ...
-    // XXX mainCamera's purpose is to establish a "main graphics
-    // context" that can be made current (if necessary). But that
-    // should be a context established with a window. It's used to
-    // choose whether to render the GUI and panel camera nodes, but
-    // that's obsolete because the GUI is rendered in its own
-    // slave. And it's used to translate mouse event coordinates, but
-    // that's bogus because mouse clicks should work on any camera. In
-    // short, mainCamera must die :)
-    Camera3DVector::iterator citr
-        = find_if(wsa->cameras.begin(), wsa->cameras.end(),
-                  WindowSystemAdapter::FlagTester<Camera3D>(Camera3D::MASTER));
-    if (citr == wsa->cameras.end()) {
-        // Create a camera aligned with the master camera. Eventually
-        // this will be optional.
-        Camera* camera = new osg::Camera;
-        mainCamera = camera;
-        osg::GraphicsContext* gc
-            = osg::GraphicsContext::createGraphicsContext(traits.get());
-        gc->realize();
-        gc->makeCurrent();
-        camera->setGraphicsContext(gc);
-        // 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.
-        camera->setViewport(new osg::Viewport(0, 0,
-                                              traits->width, traits->height));
-        GraphicsWindow* window = wsa->registerWindow(gc, string("main"));
-        window->flags |= GraphicsWindow::GUI;
-        Camera3D* camera3d = wsa->registerCamera3D(window, camera,
-                                                   string("main"));
-        camera3d->flags |= Camera3D::MASTER;
-        // Why a slave? It seems to be the easiest way to assign cameras,
-        // for which we've created the graphics context ourselves, to
-        // the viewer. 
-        viewer->addSlave(camera);
-    } else {
-        mainCamera = (*citr)->camera;
+    if (!cameraGroup)
+        cameraGroup = buildDefaultCameraGroup(viewer.get(), renderingNode);
+    Camera* guiCamera = getGUICamera(cameraGroup);
+    if (guiCamera) {
+        Viewport* guiViewport = guiCamera->getViewport();
+        fgSetInt("/sim/startup/xsize", guiViewport->width());
+        fgSetInt("/sim/startup/ysize", guiViewport->height());
     }
-    if (wsa->cameras.size() != 1) {
+    FGManipulator* manipulator = globals->get_renderer()->getManipulator();
+    WindowSystemAdapter* wsa = WindowSystemAdapter::getWSA();
+    if (wsa->windows.size() != 1) {
         manipulator->setResizable(false);
     }
     viewer->getCamera()->setProjectionResizePolicy(osg::Camera::FIXED);
@@ -300,6 +173,7 @@ void fgOSOpenWindow(bool stencil)
     // The viewer won't start without some root.
     viewer->setSceneData(new osg::Group);
     globals->get_renderer()->setViewer(viewer.get());
+    CameraGroup::setDefault(cameraGroup);
 }
 
 static int status = 0;
@@ -324,17 +198,7 @@ int fgGetKeyModifiers()
 
 void fgWarpMouse(int x, int y)
 {
-    globals->get_renderer()->getManipulator()->setMouseWarped();
-    // Hack, currently the pointer is just recentered. So, we know the
-    // relative coordinates ...
-    if (!mainCamera.valid()) {
-        viewer->requestWarpPointer(0, 0);
-        return;
-    }
-    float xsize = (float)mainCamera->getGraphicsContext()->getTraits()->width;
-    float ysize = (float)mainCamera->getGraphicsContext()->getTraits()->height;
-    viewer->requestWarpPointer(2.0f * (float)x / xsize - 1.0f,
-                               1.0f - 2.0f * (float)y / ysize);
+    warpGUIPointer(CameraGroup::getDefault(), x, y);
 }
 
 void fgOSInit(int* argc, char** argv)
@@ -393,36 +257,3 @@ int fgGetMouseCursor()
 {
     return _cursor;
 }
-
-bool fgOSIsMainContext(const osg::GraphicsContext* context)
-{
-    if (!mainCamera.valid())
-        return false;
-    return context == mainCamera->getGraphicsContext();
-}
-
-bool fgOSIsMainCamera(const osg::Camera* camera)
-{
-  if (!camera)
-    return false;
-  if (camera == mainCamera.get())
-    return true;
-  if (!viewer.valid())
-    return false;
-  if (camera == viewer->getCamera())
-    return true;
-  return false;
-}
-
-GraphicsContext* fgOSGetMainContext()
-{
-    WindowSystemAdapter* wsa = WindowSystemAdapter::getWSA();
-    WindowVector::iterator contextIter
-        = std::find_if(wsa->windows.begin(), wsa->windows.end(),
-                       WindowSystemAdapter::FlagTester<GraphicsWindow>(GraphicsWindow::GUI));
-    if (contextIter == wsa->windows.end())
-        return 0;
-    else
-        return (*contextIter)->gc.get();
-}
-
index 917fff9a0d7f0a9422cf4f78924cf4d2dbab28b3..687788e05e8884366b7cf09c3badbce3700c7797 100644 (file)
@@ -14,6 +14,7 @@
 #include "globals.hxx"
 #include "renderer.hxx"
 #include "fg_props.hxx"
+#include "CameraGroup.hxx"
 #include "WindowSystemAdapter.hxx"
 
 using namespace flightgear;
@@ -34,7 +35,6 @@ static int VidMask = SDL_OPENGL|SDL_RESIZABLE;
 static void initCursors();
 
 static osg::ref_ptr<osgViewer::Viewer> viewer;
-static osg::ref_ptr<osg::Camera> mainCamera;
 static osg::ref_ptr<osgViewer::GraphicsWindowEmbedded> gw;
 
 void fgOSOpenWindow(bool stencil)
@@ -96,16 +96,17 @@ void fgOSOpenWindow(bool stencil)
     window->flags |= GraphicsWindow::GUI;
     // now the main camera ...
     osg::Camera* camera = new osg::Camera;
-    mainCamera = camera;
     // 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.
     camera->setViewport(new osg::Viewport(0, 0, realw, realh));
     camera->setProjectionResizePolicy(osg::Camera::FIXED);
-    Camera3D* cam3D = wsa->registerCamera3D(window, camera, string("main"));
-    cam3D->flags |= Camera3D::MASTER; 
-    // Add as a slave for compatibility with the non-embedded osgViewer.
-    viewer->addSlave(camera);
+    CameraGroup* cgroup = new CameraGroup(viewer.get());
+    cgroup->addCamera(CameraGroup::DO_INTERSECTION_TEST, camera,
+                      osg::Matrixd::identity(), osg::Matrixd::identity(),
+                      true);
+    cgroup->buildGUICamera(0, window);
+    CameraGroup::setDefault(cgroup);
     viewer->setCameraManipulator(globals->get_renderer()->getManipulator());
     // Let FG handle the escape key with a confirmation
     viewer->setKeyEventSetsDone(0);
@@ -410,18 +411,3 @@ static void initCursors()
                                                 cursors[i].hoty);
     }
 }
-
-bool fgOSIsMainCamera(const osg::Camera*)
-{
-  return true;
-}
-
-bool fgOSIsMainContext(const osg::GraphicsContext*)
-{
-  return true;
-}
-
-osg::GraphicsContext* fgOSGetMainContext()
-{
-    return gw.get();
-}
index d2d6787614c3dd51a183f41868df979f5d71841c..712eb1a5f22a2f080bf2f532607fcca4e5c3553b 100644 (file)
@@ -34,6 +34,8 @@
 
 #include <plib/netSocket.h>
 
+#include <osg/Camera>
+#include <osg/GraphicsContext>
 #include <osgDB/Registry>
 
 // Class references
@@ -68,6 +70,7 @@
 #include <GUI/new_gui.hxx>
 #include <MultiPlayer/multiplaymgr.hxx>
 
+#include "CameraGroup.hxx"
 #include "fg_commands.hxx"
 #include "fg_io.hxx"
 #include "renderer.hxx"
 #include "main.hxx"
 #include "util.hxx"
 #include "fg_init.hxx"
+#include "WindowSystemAdapter.hxx"
+
 
 static double real_delta_time_sec = 0.0;
 double delta_time_sec = 0.0;
 extern float init_volume;
 
+using namespace flightgear;
+
 // This is a record containing a bit of global housekeeping information
 FGGeneral general;
 
@@ -650,21 +657,18 @@ static void fgMainLoop( void ) {
     SG_LOG( SG_ALL, SG_DEBUG, "" );
 }
 
-
-// This is the top level master main function that is registered as
-// our idle funciton
-
-// The first few passes take care of initialization things (a couple
-// per pass) and once everything has been initialized fgMainLoop from
-// then on.
-
-static void fgIdleFunction ( void ) {
-    if ( idle_state == 0 ) {
-        idle_state++;
-
-        // This seems to be the absolute earliest in the init sequence
-        // that these calls will return valid info.  Too bad it's after
-        // we've already created and sized our window. :-(
+// Operation for querying OpenGL parameters. This must be done in a
+// valid OpenGL context, potentially in another thread.
+namespace
+{
+struct GeneralInitOperation : public GraphicsContextOperation
+{
+    GeneralInitOperation()
+        : GraphicsContextOperation(std::string("General init"))
+    {
+    }
+    void run(osg::GraphicsContext* gc)
+    {
         general.set_glVendor( (char *)glGetString ( GL_VENDOR ) );
         general.set_glRenderer( (char *)glGetString ( GL_RENDERER ) );
         general.set_glVersion( (char *)glGetString ( GL_VERSION ) );
@@ -678,12 +682,42 @@ static void fgIdleFunction ( void ) {
         glGetIntegerv( GL_DEPTH_BITS, &tmp );
         general.set_glDepthBits( tmp );
         SG_LOG ( SG_GENERAL, SG_INFO, "Depth buffer bits = " << tmp );
+    }
+};
+}
 
-        // Initialize the user interface so that we can use fonts
-        guiStartInit();
+// This is the top level master main function that is registered as
+// our idle funciton
 
+// The first few passes take care of initialization things (a couple
+// per pass) and once everything has been initialized fgMainLoop from
+// then on.
 
+static void fgIdleFunction ( void ) {
+    static osg::ref_ptr<GeneralInitOperation> genOp;
+    if ( idle_state == 0 ) {
+        idle_state++;
+        // Pick some window on which to do queries.
+        // XXX Perhaps all this graphics initialization code should be
+        // moved to renderer.cxx?
+        genOp = new GeneralInitOperation;
+        osg::Camera* guiCamera = getGUICamera(CameraGroup::getDefault());
+        WindowSystemAdapter* wsa = WindowSystemAdapter::getWSA();
+        osg::GraphicsContext* gc = 0;
+        if (guiCamera)
+            gc = guiCamera->getGraphicsContext();
+        if (gc) {
+            gc->add(genOp.get());
+        } else {
+            wsa->windows[0]->gc->add(genOp.get());
+        }
+        guiStartInit(gc);
     } else if ( idle_state == 1 ) {
+        if (genOp.valid()) {
+            if (!genOp->isFinished())
+                return;
+            genOp = 0;
+        }
         if (!guiFinishInit())
             return;
         idle_state++;
index 6286578af3d6fa355e57e2cbb0020ade8e7d8729..c16f3c690f97ac802cbb43eea8c1dd9d6bd1176b 100644 (file)
@@ -1227,12 +1227,12 @@ where:
 
 enum OptionType { OPTION_BOOL, OPTION_STRING, OPTION_DOUBLE, OPTION_INT, OPTION_CHANNEL, OPTION_FUNC };
 struct OptionDesc {
-    char *option;
+    const char *option;
     bool has_param;
     enum OptionType type;
-    char *property;
+    const char *property;
     bool b_param;
-    char *s_param;
+    const char *s_param;
     int (*func)( const char * );
     } fgOptionArray[] = {
        
index 368dba6429f914682813d34b50558b620045f257..8dd73cae4b0e35c091a8cabede3b03a62ccfbf0e 100644 (file)
@@ -37,6 +37,7 @@
 #include <osg/Light>
 #include <osg/LightModel>
 #include <osg/LightSource>
+#include <osg/Material>
 #include <osg/NodeCallback>
 #include <osg/Notify>
 #include <osg/PolygonMode>
@@ -60,6 +61,7 @@
 #include <simgear/scene/material/matlib.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/tgdb/GroundLightManager.hxx>
@@ -95,6 +97,7 @@
 #include "splash.hxx"
 #include "renderer.hxx"
 #include "main.hxx"
+#include "CameraGroup.hxx"
 #include "ViewPartitionNode.hxx"
 
 // XXX Make this go away when OSG 2.2 is released.
 #define UPDATE_VISITOR_IN_VIEWER 1
 #endif
 
+using namespace flightgear;
+
 class FGHintUpdateCallback : public osg::StateAttribute::Callback {
 public:
   FGHintUpdateCallback(const char* configNode) :
@@ -153,8 +158,6 @@ public:
   { drawImplementation(*renderInfo.getState()); }
   void drawImplementation(osg::State& state) const
   {
-    if (!fgOSIsMainContext(state.getGraphicsContext()))
-      return;
     state.setActiveTextureUnit(0);
     state.setClientActiveTextureUnit(0);
 
@@ -198,8 +201,6 @@ public:
   { drawImplementation(*renderInfo.getState()); }
   void drawImplementation(osg::State& state) const
   {
-    if (!fgOSIsMainContext(state.getGraphicsContext()))
-      return;
     state.setActiveTextureUnit(0);
     state.setClientActiveTextureUnit(0);
     state.disableAllVertexArrays();
@@ -406,38 +407,6 @@ FGRenderer::splashinit( void ) {
 #endif
 }
 
-namespace
-{
-// Create a slave camera that will be used to render a fixed GUI-like
-// element.
-osg::Camera*
-makeSlaveCamera(osg::Camera::RenderOrder renderOrder, int orderNum)
-{
-    using namespace osg;
-    Camera* camera = new osg::Camera;
-    GraphicsContext *gc = fgOSGetMainContext();
-    
-    camera->setRenderOrder(renderOrder, orderNum);
-    camera->setClearMask(0);
-    camera->setInheritanceMask(CullSettings::ALL_VARIABLES
-                               & ~(CullSettings::COMPUTE_NEAR_FAR_MODE
-                                   | CullSettings::CULLING_MODE));
-    camera->setComputeNearFarMode(osg::CullSettings::DO_NOT_COMPUTE_NEAR_FAR);
-    camera->setCullingMode(osg::CullSettings::NO_CULLING);
-    camera->setGraphicsContext(gc);
-    // Establish an initial viewport. This may be altered,
-    // particularly when drawing a 2d panel.
-    const GraphicsContext::Traits *traits = gc->getTraits();
-    camera->setViewport(new Viewport(0, 0, traits->width, traits->height));
-    camera->setProjectionResizePolicy(Camera::FIXED);
-    camera->setReferenceFrame(Transform::ABSOLUTE_RF);
-    camera->setAllowEventFocus(false);
-    globals->get_renderer()->getViewer()->addSlave(camera, false);
-    return camera;
-}
-
-}
-
 void
 FGRenderer::init( void )
 {
@@ -541,13 +510,13 @@ FGRenderer::init( void )
     stateSet->setUpdateCallback(new FGFogEnableUpdateCallback);
 
     // plug in the GUI
-    osg::Camera* guiCamera = makeSlaveCamera(osg::Camera::POST_RENDER, 100);
-    guiCamera->setName("GUI");
-    osg::Geode* geode = new osg::Geode;
-    geode->addDrawable(new SGPuDrawable);
-    geode->addDrawable(new SGHUDAndPanelDrawable);
-    guiCamera->addChild(geode);
-
+    osg::Camera* guiCamera = getGUICamera(CameraGroup::getDefault());
+    if (guiCamera) {
+        osg::Geode* geode = new osg::Geode;
+        geode->addDrawable(new SGPuDrawable);
+        geode->addDrawable(new SGHUDAndPanelDrawable);
+        guiCamera->addChild(geode);
+    }
     osg::Switch* sw = new osg::Switch;
     sw->setUpdateCallback(new FGScenerySwitchCallback);
     sw->addChild(mRoot.get());
@@ -612,14 +581,14 @@ FGRenderer::update( bool refresh_camera_settings ) {
         // update view port
         resize( fgGetInt("/sim/startup/xsize"),
                 fgGetInt("/sim/startup/ysize") );
-
+#if 0
         SGVec3d position = current__view->getViewPosition();
         SGQuatd attitude = current__view->getViewOrientation();
-        SGVec3d osgPosition = attitude.transform(-position);
 
         FGManipulator *manipulator = globals->get_renderer()->getManipulator();
         manipulator->setPosition(position.osg());
         manipulator->setAttitude(attitude.osg());
+#endif
     }
     osg::Camera *camera = viewer->getCamera();
 
@@ -743,7 +712,7 @@ FGRenderer::update( bool refresh_camera_settings ) {
     }
 
 //     sgEnviro.setLight(l->adj_fog_color());
-
+#if 0
     double agl = current__view->getAltitudeASL_ft()*SG_FEET_TO_METER
       - current__view->getSGLocation()->get_cur_elev_m();
 
@@ -761,7 +730,7 @@ FGRenderer::update( bool refresh_camera_settings ) {
     setCameraParameters(current__view->get_v_fov(),
                         current__view->get_aspect_ratio(),
                         scene_nearplane, scene_farplane);
-
+#endif
 //     sgEnviro.startOfFrame(current__view->get_view_pos(), 
 //         current__view->get_world_up(),
 //         current__view->getLongitude_deg(),
@@ -850,44 +819,40 @@ void FGRenderer::setCameraParameters(float vfov, float aspectRatio,
     
 }
 bool
-FGRenderer::pick( unsigned x, unsigned y,
-                  std::vector<SGSceneryPick>& pickList,
-                  const osgGA::GUIEventAdapter* ea )
+FGRenderer::pick(std::vector<SGSceneryPick>& pickList,
+                 const osgGA::GUIEventAdapter* ea)
 {
-  osgViewer::Viewer* viewer = globals->get_renderer()->getViewer();
-  // wipe out the return ...
-  pickList.resize(0);
-
-  if (viewer) {
-    // just compute intersections in the viewers method ...
+    osgViewer::Viewer* viewer = globals->get_renderer()->getViewer();
+    // wipe out the return ...
+    pickList.clear();
     typedef osgUtil::LineSegmentIntersector::Intersections Intersections;
     Intersections intersections;
-    viewer->computeIntersections(ea->getX(), ea->getY(), intersections);
-
-    Intersections::iterator hit;
-    for (hit = intersections.begin(); hit != intersections.end(); ++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 = SGVec3d(hit->getLocalIntersectPoint());
-          sceneryPick.info.wgs84 = SGVec3d(hit->getWorldIntersectPoint());
-          sceneryPick.callback = pickCallback;
-          pickList.push_back(sceneryPick);
+
+    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 = SGVec3d(hit->getLocalIntersectPoint());
+                sceneryPick.info.wgs84 = SGVec3d(hit->getWorldIntersectPoint());
+                sceneryPick.callback = pickCallback;
+                pickList.push_back(sceneryPick);
+            }
         }
-      }
     }
     return !pickList.empty();
-  } else {                     // we can get called early ...
-    return false;
-  }
 }
 
 void
index 918408bcd548bf29afbc4362fa279e488dc5ece1..f126f2feb1d41f2cc265bc15949795f18f524f57 100644 (file)
@@ -3,7 +3,6 @@
 #define __FG_RENDERER_HXX 1
 
 #include <simgear/screen/extensions.hxx>
-#include <simgear/scene/sky/sky.hxx>
 #include <simgear/scene/util/SGPickCallback.hxx>
 
 #include <osg/Camera>
@@ -46,8 +45,7 @@ public:
                                     float zNear, float zFar);
     /** Just pick into the scene and return the pick callbacks on the way ...
      */
-    static bool pick( unsigned x, unsigned y,
-                      std::vector<SGSceneryPick>& pickList,
+    static bool pick( std::vector<SGSceneryPick>& pickList,
                       const osgGA::GUIEventAdapter* ea );
 
     /** Get and set the OSG Viewer object, if any.
@@ -57,9 +55,9 @@ public:
     void setViewer(osgViewer::Viewer* viewer) { this->viewer = viewer; }
     /** Get and set the manipulator object, if any.
      */
-    FGManipulator* getManipulator() { return manipulator.get(); }
-    const FGManipulator* getManipulator() const { return manipulator.get(); }
-    void setManipulator(FGManipulator* manipulator) {
+    flightgear::FGManipulator* getManipulator() { return manipulator.get(); }
+    const flightgear::FGManipulator* getManipulator() const { return manipulator.get(); }
+    void setManipulator(flightgear::FGManipulator* manipulator) {
         this->manipulator = manipulator;
     }
 
@@ -69,7 +67,7 @@ public:
 
 protected:
     osg::ref_ptr<osgViewer::Viewer> viewer;
-    osg::ref_ptr<FGManipulator> manipulator;
+    osg::ref_ptr<flightgear::FGManipulator> manipulator;
 };
 
 bool fgDumpSceneGraphToFile(const char* filename);
index 7c4388b16a78c202ec93d989121b02f40981d602..c0318761930a25788ddc4b62acfb81700ee7ef7e 100644 (file)
@@ -50,6 +50,9 @@
 
 #include "viewer.hxx"
 
+#include "CameraGroup.hxx"
+
+using namespace flightgear;
 \f
 ////////////////////////////////////////////////////////////////////////
 // Implementation of FGViewer.
@@ -81,7 +84,8 @@ FGViewer::FGViewer( fgViewType Type, bool from_model, int from_model_index,
     _damp_heading(0),
     _scaling_type(FG_SCALING_MAX),
     _location(0),
-    _target_location(0)
+    _target_location(0),
+    _cameraGroup(CameraGroup::getDefault())
 {
     _absolute_view_pos = SGVec3d(0, 0, 0);
     _type = Type;
@@ -764,5 +768,7 @@ FGViewer::update (double dt)
       }
     }
   }
-
+  recalc();
+  _cameraGroup->update(_absolute_view_pos.osg(), mViewOrientation.osg());
+  _cameraGroup->setCameraParameters(get_v_fov(), get_aspect_ratio());
 }
index 8085838225fc8b9aeb0ced8f8b9ea13c6bef9139..345828846a77d328dee13fed2584f1ab4d0f614d 100644 (file)
 # error This library requires C++
 #endif                                   
 
+namespace flightgear
+{
+class CameraGroup;
+}
+
+#include <osg/ref_ptr>
+
 #include <simgear/compiler.h>
 #include <simgear/constants.h>
 #include <simgear/structure/subsystem_mgr.hxx>
@@ -361,6 +368,8 @@ private:
     // surface at the spot we are directly above
     SGVec3f _world_up;
 
+    // camera group controled by this view
+    osg::ref_ptr<flightgear::CameraGroup> _cameraGroup;
     //////////////////////////////////////////////////////////////////
     // private functions                                            //
     //////////////////////////////////////////////////////////////////
index 60752f9109bc222e91845ba87c6f446e419d431d..985abb2a588aa7abf77d70ff28c6518e612f1b66 100644 (file)
 #include <simgear/scene/tgdb/TileCache.hxx>
 
 class SGReaderWriterBTGOptions;
-class osg::Node;
+
+namespace osg
+{
+class Node;
+}
 
 class FGTileMgr : public simgear::ModelLoadHelper {