]> git.mxchange.org Git - flightgear.git/commitdiff
Add seamless view muliscreen configuration.
authorMathias Froehlich <Mathias.Froehlich@web.de>
Sun, 23 Oct 2011 13:40:15 +0000 (15:40 +0200)
committerMathias Froehlich <Mathias.Froehlich@web.de>
Sun, 23 Oct 2011 14:40:13 +0000 (16:40 +0200)
Add a new way to configure multi screen systems.
The new version allows easier configuration of displays
that need to fit at the edges as well as configurations
where the screens match at reference points.
This kind of screen configuration will again zoom.

docs-mini/README.multiscreen
src/Main/CameraGroup.cxx
src/Main/CameraGroup.hxx

index 042bbac8495384d328b72d4541a6df0b6e995efa..0f8a9b707fea3145ef6b284eb6775d4bbd3e2455 100644 (file)
@@ -81,6 +81,31 @@ window, camera, or gui tags.
    width, height - int
    The dimensions of the viewport
 
+  physical-dimensions
+  The physical dimension of the projection surface.
+  Use this together with the master-perspective, right-of-perspective
+  left-of-perspective, above-perspective, below-perspective or
+  reference-points-perspective
+
+   width, height - double
+   The dimensions of the projection plane, if unset the veiwport values
+   are taken as default.
+
+   bezel
+   Gives informantion about the bezel of monitors for a seamless view.
+
+    right
+    right bezel with in the same units than with and height above
+
+    left
+    left bezel with in the same units than with and height above
+
+    top
+    top bezel with in the same units than with and height above
+
+    bottom
+    bottom bezel with in the same units than with and height above
+
   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,
@@ -133,6 +158,63 @@ window, camera, or gui tags.
   This specifies an orthographic view. The parameters are the sames as
   the frustum node's.
 
+  master-perspective
+  Defines a persective projection matrix for use as the leading display
+  in a seamless multiscreen configuration. This kind of perspective
+  projection is zoomable.
+
+   eye-distance - double
+   The distance of the eyepoint from the projection surface in units of
+   the physical-dimensions values above.
+
+   x-offset, y-offset - double
+   Offset of the eyelpint from the center of the screen in units of
+   the physical-dimensions values above.
+
+  left-of-perspective, right-of-perspective, above-perspective,
+  below-perspective
+  Defines a perspective projection matrix for use as derived display
+  in a seamless multiscreen configuration. The projection matrix
+  is computed so that the respective edge of this display matches the
+  assiciated other edge of the other display. For example the right edge
+  of a left-of-perspective display matches the left edge of the parent
+  display. This also works with different zoom levels, leading to distorted
+  but still seamless multiview configurations.
+  The bezel with configured in the physical dimensions of this screen and
+  the parent screen are taken into account for this type of projection.
+
+   parent-camera - string
+   Name of the parent camera.
+
+  reference-points-perspective
+  Defines a perspective projection matrix for use as derived display
+  in a seamless multiscreen configuration. This type is very similar to
+  left-of-perspective and friends. It is just a more flexible but less
+  convenient way to get the same effect. A child display is configured
+  by 2 sets of reference points one in this current camera and one in
+  the parrent camera which should match in the final view.
+
+   parent-camera - string
+   Name of the parent camera.
+
+   this
+   reference points for this projection.
+
+    point - array of two points
+
+     x, y - double
+     x and y coodinates of the reference points in units of this
+     physical-dimensions.
+
+   parent
+   reference points for the parent projection.
+
+    point - array of two points
+
+     x, y - double
+     x and y coodinates of the reference points in units of the
+     parents physical-dimensions.
+
   texture
   This tag indicates that the camera renders to a texture instead of the
   framebuffer. For now the following tags are supported, but obviously
@@ -395,3 +477,170 @@ This example renders the scene for projection onto a spherical screen.
   </sim>
 </PropertyList>
  
+Here is an example for a 3 screen seamless zoomable multiscreen
+configuration using 3 533mmx300mm displays each with a 23mm bezel.
+The side views are angled with 45 deg.
+The commented out reference-points-perspective shows the
+aequivalent configuration than the active right-of-perspective.
+This is done by just using two reference points at the outer
+edge of the bezel of the respective display.
+
+<PropertyList>
+  <sim>
+    <view n="0">
+      <config>
+        <pitch-offset-deg>0.0</pitch-offset-deg>
+      </config>
+    </view>
+
+    <rendering>
+      <camera-group>
+        <window>
+          <name type="string">0.0</name>
+          <host-name type="string"></host-name>
+          <display>0</display>
+          <screen>0</screen>
+          <fullscreen type="bool">true</fullscreen>
+        </window>
+
+        <window>
+          <name type="string">0.1</name>
+          <host-name type="string"></host-name>
+          <display>0</display>
+          <screen>1</screen>
+          <fullscreen type="bool">true</fullscreen>
+        </window>
+
+        <camera>
+          <name type="string">CenterCamera</name>
+          <window>
+            <name>0.0</name>
+          </window>
+          <viewport>
+            <x>0</x>
+            <y>0</y>
+            <width>1920</width>
+            <height>1080</height>
+          </viewport>
+          <view>
+            <heading-deg type="double">0.0</heading-deg>
+            <roll-deg type="double">0.0</roll-deg>
+            <pitch-deg type="double">0.0</pitch-deg>
+          </view>
+          <physical-dimensions>
+            <!-- The size of the projection plane: 533mm 300mm -->
+            <width>533</width>
+            <height>300</height>
+            <bezel>
+              <right>23</right>
+              <left>23</left>
+              <top>23</top>
+              <bottom>23</bottom>
+            </bezel>
+          </physical-dimensions>
+          <master-perspective>
+            <!-- Cheating, the real distance is about 800mm.
+                 But then the screen does not show what is needed to fly.
+                 By shortening this pictures get bigger but the view also gets
+                 less realistic.
+            -->
+            <eye-distance>450</eye-distance>
+            <x-offset>0</x-offset>
+            <y-offset>130</y-offset>
+          </master-perspective>
+        </camera>
+        <camera>
+          <name type="string">RightCamera</name>
+          <window>
+            <name>0.0</name>
+          </window>
+          <viewport>
+            <x>1920</x>
+            <y>0</y>
+            <width>1920</width>
+            <height>1080</height>
+          </viewport>
+          <view>
+            <heading-deg type="double">-45</heading-deg>
+            <roll-deg type="double">0</roll-deg>
+            <pitch-deg type="double">0</pitch-deg>
+          </view>
+          <physical-dimensions>
+            <!-- The size of the projection plane: 533mm 300mm -->
+            <width>533</width>
+            <height>300</height>
+            <bezel>
+              <right>23</right>
+              <left>23</left>
+              <top>23</top>
+              <bottom>23</bottom>
+            </bezel>
+          </physical-dimensions>
+          <right-of-perspective>
+            <parent-camera type="string">CenterCamera</parent-camera>
+          </right-of-perspective>
+          <!-- <reference-points-perspective> -->
+          <!--   <parent-camera type="string">CenterCamera</parent-camera> -->
+          <!--   <parent> -->
+          <!--     <point n="0"> -->
+          <!--       <x>289.5</x> -->
+          <!--       <y>100</y> -->
+          <!--     </point> -->
+          <!--     <point n="1"> -->
+          <!--       <x>289.5</x> -->
+          <!--       <y>-100</y> -->
+          <!--     </point> -->
+          <!--   </parent> -->
+          <!--   <this> -->
+          <!--     <point n="0"> -->
+          <!--       <x>-289.5</x> -->
+          <!--       <y>100</y> -->
+          <!--     </point> -->
+          <!--     <point n="1"> -->
+          <!--       <x>-289.5</x> -->
+          <!--       <y>-100</y> -->
+          <!--     </point> -->
+          <!--   </this> -->
+          <!-- </reference-points-perspective> -->
+        </camera>
+
+        <camera>
+          <name type="string">LeftCamera</name>
+          <window>
+            <name>0.1</name>
+          </window>
+          <viewport>
+            <x>0</x>
+            <y>0</y>
+            <width>1920</width>
+            <height>1080</height>
+          </viewport>
+          <view>
+            <heading-deg type="double">45</heading-deg>
+            <roll-deg type="double">0</roll-deg>
+            <pitch-deg type="double">0</pitch-deg>
+          </view>
+          <physical-dimensions>
+            <!-- The size of the projection plane: 533mm 300mm -->
+            <width>533</width>
+            <height>300</height>
+            <bezel>
+              <right>23</right>
+              <left>23</left>
+              <top>23</top>
+              <bottom>23</bottom>
+            </bezel>
+          </physical-dimensions>
+          <left-of-perspective>
+            <parent-camera type="string">CenterCamera</parent-camera>
+          </left-of-perspective>
+        </camera>
+        <gui>
+          <window>
+            <name type="string">0.0</name>
+          </window>
+        </gui>
+      </camera-group>
+    </rendering>
+  </sim>
+</PropertyList>
index 2a312391b353ad6403f067589e4d6052177bf946..a69cebca6ccf5e46f0646e27df42fdd37013d941 100644 (file)
@@ -21,6 +21,7 @@
 
 #include "CameraGroup.hxx"
 
+#include "fg_props.hxx"
 #include "globals.hxx"
 #include "renderer.hxx"
 #include "FGEventHandler.hxx"
 #include <osgViewer/GraphicsWindow>
 #include <osgViewer/Renderer>
 
+static osg::Matrix
+invert(const osg::Matrix& matrix)
+{
+    return osg::Matrix::inverse(matrix);
+}
+
+/// Returns the zoom factor of the master camera.
+/// The reference fov is the historic 55 deg
+static double
+zoomFactor()
+{
+    double fov = fgGetDouble("/sim/current-view/field-of-view", 55);
+    if (fov < 1)
+        fov = 1;
+    return tan(55*0.5*SG_DEGREES_TO_RADIANS)/tan(fov*0.5*SG_DEGREES_TO_RADIANS);
+}
+
+static osg::Vec2d
+preMult(const osg::Vec2d& v, const osg::Matrix& m)
+{
+  osg::Vec3d tmp = m.preMult(osg::Vec3(v, 0));
+  return osg::Vec2d(tmp[0], tmp[1]);
+}
+
+static osg::Matrix
+relativeProjection(const osg::Matrix& P0, const osg::Matrix& R, const osg::Vec2d ref[2],
+                   const osg::Matrix& pP, const osg::Matrix& pR, const osg::Vec2d pRef[2])
+{
+  // Track the way from one projection space to the other:
+  // We want
+  //  P = T*S*P0
+  // where P0 is the projection template sensible for the given window size,
+  // T is a translation matrix and S a scale matrix.
+  // We need to determine T and S so that the reference points in the parents
+  // projection space match the two reference points in this cameras projection space.
+
+  // Starting from the parents camera projection space, we get into this cameras
+  // projection space by the transform matrix:
+  //  P*R*inv(pP*pR) = T*S*P0*R*inv(pP*pR)
+  // So, at first compute that matrix without T*S and determine S and T from that
+
+  // Ok, now osg uses the inverse matrix multiplication order, thus:
+  osg::Matrix PtoPwithoutTS = invert(pR*pP)*R*P0;
+  // Compute the parents reference points in the current projection space
+  // without the yet unknown T and S
+  osg::Vec2d pRefInThis[2] = {
+    preMult(pRef[0], PtoPwithoutTS),
+    preMult(pRef[1], PtoPwithoutTS)
+  };
+
+  // To get the same zoom, rescale to match the parents size
+  double s = (ref[0] - ref[1]).length()/(pRefInThis[0] - pRefInThis[1]).length();
+  osg::Matrix S = osg::Matrix::scale(s, s, 1);
+
+  // For the translation offset, incorporate the now known scale
+  // and recompute the position ot the first reference point in the
+  // currents projection space without the yet unknown T.
+  pRefInThis[0] = preMult(pRef[0], PtoPwithoutTS*S);
+  // The translation is then the difference of the reference points
+  osg::Matrix T = osg::Matrix::translate(osg::Vec3d(ref[0] - pRefInThis[0], 0));
+
+  // Compose and return the desired final projection matrix
+  return P0*S*T;
+}
+
 namespace flightgear
 {
 using namespace osg;
@@ -205,6 +271,7 @@ void CameraGroup::update(const osg::Vec3d& position,
                             * osg::Matrix::rotate(orientation.inverse()));
     _viewer->getCamera()->setViewMatrix(masterView);
     const Matrix& masterProj = _viewer->getCamera()->getProjectionMatrix();
+    double masterZoomFactor = zoomFactor();
     for (CameraList::iterator i = _cameras.begin(); i != _cameras.end(); ++i) {
         const CameraInfo* info = i->get();
         const View::Slave& slave = _viewer->getSlave(info->slaveIndex);
@@ -220,10 +287,33 @@ void CameraGroup::update(const osg::Vec3d& position,
             viewMatrix = masterView * slave._viewOffset;
         camera->setViewMatrix(viewMatrix);
         Matrix projectionMatrix;
-        if ((info->flags & PROJECTION_ABSOLUTE) != 0)
-            projectionMatrix = slave._projectionOffset;
-        else
+        if ((info->flags & PROJECTION_ABSOLUTE) != 0) {
+            if (info->flags & ENABLE_MASTER_ZOOM) {
+                if (info->relativeCameraParent < _cameras.size()) {
+                    // template projection matrix and view matrix of the current camera
+                    osg::Matrix P0 = slave._projectionOffset;
+                    osg::Matrix R = viewMatrix;
+
+                    // The already known projection and view matrix of the parent camera
+                    const CameraInfo* parentInfo = _cameras[info->relativeCameraParent].get();
+                    osg::Matrix pP = parentInfo->camera->getProjectionMatrix();
+                    osg::Matrix pR = parentInfo->camera->getViewMatrix();
+                    
+                    // And the projection matrix derived from P0 so that the reference points match
+                    projectionMatrix = relativeProjection(P0, R, info->thisReference,
+                                                          pP, pR, info->parentReference);
+                    
+                } else {
+                    // We want to zoom, so take the original matrix and apply the zoom to it.
+                    projectionMatrix = slave._projectionOffset;
+                    projectionMatrix.postMultScale(osg::Vec3d(masterZoomFactor, masterZoomFactor, 1));
+                }
+            } else {
+                projectionMatrix = slave._projectionOffset;
+            }
+        } else {
             projectionMatrix = masterProj * slave._projectionOffset;
+        }
 
         if (!info->farCamera.valid()) {
             camera->setProjectionMatrix(projectionMatrix);
@@ -575,7 +665,6 @@ CameraInfo* CameraGroup::buildCamera(SGPropertyNode* cameraNode)
 #endif
                                    ));
 
-    osg::Matrix pOff;
     osg::Matrix vOff;
     const SGPropertyNode* viewNode = cameraNode->getNode("view");
     if (viewNode) {
@@ -601,7 +690,31 @@ CameraInfo* CameraGroup::buildCamera(SGPropertyNode* cameraNode)
         double heading = cameraNode->getDoubleValue("heading-deg", 0.0);
         vOff.makeRotate(DegreesToRadians(heading), osg::Vec3(0, 1, 0));
     }
-    const SGPropertyNode* projectionNode = 0;
+    // Configuring the physical dimensions of a monitor
+    SGPropertyNode* viewportNode = cameraNode->getNode("viewport", true);
+    double physicalWidth = viewportNode->getDoubleValue("width", 1024);
+    double physicalHeight = viewportNode->getDoubleValue("height", 768);
+    double bezelHeightTop = 0;
+    double bezelHeightBottom = 0;
+    double bezelWidthLeft = 0;
+    double bezelWidthRight = 0;
+    const SGPropertyNode* physicalDimensionsNode = 0;
+    if ((physicalDimensionsNode = cameraNode->getNode("physical-dimensions")) != 0) {
+        physicalWidth = physicalDimensionsNode->getDoubleValue("width", physicalWidth);
+        physicalHeight = physicalDimensionsNode->getDoubleValue("height", physicalHeight);
+        const SGPropertyNode* bezelNode = 0;
+        if ((bezelNode = physicalDimensionsNode->getNode("bezel")) != 0) {
+            bezelHeightTop = bezelNode->getDoubleValue("top", bezelHeightTop);
+            bezelHeightBottom = bezelNode->getDoubleValue("bottom", bezelHeightBottom);
+            bezelWidthLeft = bezelNode->getDoubleValue("left", bezelWidthLeft);
+            bezelWidthRight = bezelNode->getDoubleValue("right", bezelWidthRight);
+        }
+    }
+    osg::Matrix pOff;
+    unsigned parentCameraIndex = ~0u;
+    osg::Vec2d parentReference[2];
+    osg::Vec2d thisReference[2];
+    SGPropertyNode* projectionNode = 0;
     if ((projectionNode = cameraNode->getNode("perspective")) != 0) {
         double fovy = projectionNode->getDoubleValue("fovy-deg", 55.0);
         double aspectRatio = projectionNode->getDoubleValue("aspect-ratio",
@@ -636,6 +749,83 @@ CameraInfo* CameraGroup::buildCamera(SGPropertyNode* cameraNode)
         }
         if (projectionNode->getBoolValue("fixed-near-far", true))
             cameraFlags |= FIXED_NEAR_FAR;
+    } else if ((projectionNode = cameraNode->getNode("master-perspective")) != 0) {
+        double zNear = projectionNode->getDoubleValue("eye-distance", 0.4*physicalWidth);
+        double xoff = projectionNode->getDoubleValue("x-offset", 0);
+        double yoff = projectionNode->getDoubleValue("y-offset", 0);
+        double left = -0.5*physicalWidth - xoff;
+        double right = 0.5*physicalWidth - xoff;
+        double bottom = -0.5*physicalHeight - yoff;
+        double top = 0.5*physicalHeight - yoff;
+        pOff.makeFrustum(left, right, bottom, top, zNear, zNear*1000);
+        cameraFlags |= PROJECTION_ABSOLUTE | ENABLE_MASTER_ZOOM;
+    } else if ((projectionNode = cameraNode->getNode("right-of-perspective"))
+               || (projectionNode = cameraNode->getNode("left-of-perspective"))
+               || (projectionNode = cameraNode->getNode("above-perspective"))
+               || (projectionNode = cameraNode->getNode("below-perspective"))
+               || (projectionNode = cameraNode->getNode("reference-points-perspective"))) {
+        std::string name = projectionNode->getStringValue("parent-camera");
+        for (unsigned i = 0; i < _cameras.size(); ++i) {
+            if (_cameras[i]->name != name)
+                continue;
+            parentCameraIndex = i;
+        }
+        if (_cameras.size() <= parentCameraIndex) {
+            SG_LOG(SG_GENERAL, SG_ALERT, "CameraGroup::buildCamera: "
+                   "failed to find parent camera for relative camera!");
+            return 0;
+        }
+        const CameraInfo* parentInfo = _cameras[parentCameraIndex].get();
+        if (projectionNode->getNameString() == "right-of-perspective") {
+            double tmp = (parentInfo->physicalWidth + 2*parentInfo->bezelWidthRight)/parentInfo->physicalWidth;
+            parentReference[0] = osg::Vec2d(tmp, -1);
+            parentReference[1] = osg::Vec2d(tmp, 1);
+            tmp = (physicalWidth + 2*bezelWidthLeft)/physicalWidth;
+            thisReference[0] = osg::Vec2d(-tmp, -1);
+            thisReference[1] = osg::Vec2d(-tmp, 1);
+        } else if (projectionNode->getNameString() == "left-of-perspective") {
+            double tmp = (parentInfo->physicalWidth + 2*parentInfo->bezelWidthLeft)/parentInfo->physicalWidth;
+            parentReference[0] = osg::Vec2d(-tmp, -1);
+            parentReference[1] = osg::Vec2d(-tmp, 1);
+            tmp = (physicalWidth + 2*bezelWidthRight)/physicalWidth;
+            thisReference[0] = osg::Vec2d(tmp, -1);
+            thisReference[1] = osg::Vec2d(tmp, 1);
+        } else if (projectionNode->getNameString() == "above-perspective") {
+            double tmp = (parentInfo->physicalHeight + 2*parentInfo->bezelHeightTop)/parentInfo->physicalHeight;
+            parentReference[0] = osg::Vec2d(-1, tmp);
+            parentReference[1] = osg::Vec2d(1, tmp);
+            tmp = (physicalHeight + 2*bezelHeightBottom)/physicalHeight;
+            thisReference[0] = osg::Vec2d(-1, -tmp);
+            thisReference[1] = osg::Vec2d(1, -tmp);
+        } else if (projectionNode->getNameString() == "below-perspective") {
+            double tmp = (parentInfo->physicalHeight + 2*parentInfo->bezelHeightBottom)/parentInfo->physicalHeight;
+            parentReference[0] = osg::Vec2d(-1, -tmp);
+            parentReference[1] = osg::Vec2d(1, -tmp);
+            tmp = (physicalHeight + 2*bezelHeightTop)/physicalHeight;
+            thisReference[0] = osg::Vec2d(-1, tmp);
+            thisReference[1] = osg::Vec2d(1, tmp);
+        } else if (projectionNode->getNameString() == "reference-points-perspective") {
+            SGPropertyNode* parentNode = projectionNode->getNode("parent", true);
+            SGPropertyNode* thisNode = projectionNode->getNode("this", true);
+            SGPropertyNode* pointNode;
+
+            pointNode = parentNode->getNode("point", 0, true);
+            parentReference[0][0] = pointNode->getDoubleValue("x", 0)*2/parentInfo->physicalWidth;
+            parentReference[0][1] = pointNode->getDoubleValue("y", 0)*2/parentInfo->physicalHeight;
+            pointNode = parentNode->getNode("point", 1, true);
+            parentReference[1][0] = pointNode->getDoubleValue("x", 0)*2/parentInfo->physicalWidth;
+            parentReference[1][1] = pointNode->getDoubleValue("y", 0)*2/parentInfo->physicalHeight;
+
+            pointNode = thisNode->getNode("point", 0, true);
+            thisReference[0][0] = pointNode->getDoubleValue("x", 0)*2/physicalWidth;
+            thisReference[0][1] = pointNode->getDoubleValue("y", 0)*2/physicalHeight;
+            pointNode = thisNode->getNode("point", 1, true);
+            thisReference[1][0] = pointNode->getDoubleValue("x", 0)*2/physicalWidth;
+            thisReference[1][1] = pointNode->getDoubleValue("y", 0)*2/physicalHeight;
+        }
+
+        pOff = osg::Matrix::perspective(45, physicalWidth/physicalHeight, 1, 20000);
+        cameraFlags |= PROJECTION_ABSOLUTE | ENABLE_MASTER_ZOOM;
     } else {
         // old style shear parameters
         double shearx = cameraNode->getDoubleValue("shear-x", 0);
@@ -668,10 +858,21 @@ CameraInfo* CameraGroup::buildCamera(SGPropertyNode* cameraNode)
     bool useMasterSceneGraph = !psNode;
     CameraInfo* info = addCamera(cameraFlags, camera, vOff, pOff,
                                  useMasterSceneGraph);
+    info->name = cameraNode->getStringValue("name");
+    info->physicalWidth = physicalWidth;
+    info->physicalHeight = physicalHeight;
+    info->bezelHeightTop = bezelHeightTop;
+    info->bezelHeightBottom = bezelHeightBottom;
+    info->bezelWidthLeft = bezelWidthLeft;
+    info->bezelWidthRight = bezelWidthRight;
+    info->relativeCameraParent = parentCameraIndex;
+    info->parentReference[0] = parentReference[0];
+    info->parentReference[1] = parentReference[1];
+    info->thisReference[0] = thisReference[0];
+    info->thisReference[1] = thisReference[1];
     // If a viewport isn't set on the camera, then it's hard to dig it
     // out of the SceneView objects in the viewer, and the coordinates
     // of mouse events are somewhat bizzare.
-    SGPropertyNode* viewportNode = cameraNode->getNode("viewport", true);
     buildViewport(info, viewportNode, window->gc->getTraits());
     updateCameras(info);
     // Distortion camera needs the viewport which is created by addCamera().
index 9f37ce5d273bfa9ea6c36b43292c94984abef904..a74895e467f7946e155d1199815c559f30b8a950 100644 (file)
@@ -52,9 +52,15 @@ struct CameraInfo : public osg::Referenced
 {
     CameraInfo(unsigned flags_, osg::Camera* camera_ = 0)
         : flags(flags_), camera(camera_), slaveIndex(-1), farSlaveIndex(-1),
-          x(0.0), y(0.0), width(0.0), height(0.0)
+          x(0.0), y(0.0), width(0.0), height(0.0),
+          physicalWidth(0), physicalHeight(0), bezelHeightTop(0),
+          bezelHeightBottom(0), bezelWidthLeft(0), bezelWidthRight(0),
+          relativeCameraParent(~0u)
     {
     }
+    /** The name as given in the config file.
+     */
+    std::string name;
     /** Properties of the camera. @see CameraGroup::Flags.
      */
     unsigned flags;
@@ -76,6 +82,23 @@ struct CameraInfo : public osg::Referenced
     double y;
     double width;
     double height;
+    /** Physical size parameters.
+     */
+    double physicalWidth;
+    double physicalHeight;
+    double bezelHeightTop;
+    double bezelHeightBottom;
+    double bezelWidthLeft;
+    double bezelWidthRight;
+    /** The parent camera for relative camera configurations.
+     */
+    unsigned relativeCameraParent;
+    /** The reference points in the parents projection space.
+     */
+    osg::Vec2d parentReference[2];
+    /** The reference points in the current projection space.
+     */
+    osg::Vec2d thisReference[2];
 };
 
 /** Update the OSG cameras from the camera info.
@@ -96,8 +119,9 @@ public:
         GUI = 0x8,                 /**< Camera draws the GUI. */
         DO_INTERSECTION_TEST = 0x10,/**< scene intersection tests this
                                        camera. */
-        FIXED_NEAR_FAR = 0x20      /**< take the near far values in the
+        FIXED_NEAR_FAR = 0x20,     /**< take the near far values in the
                                       projection for real. */
+        ENABLE_MASTER_ZOOM = 0x40  /**< Can apply the zoom algorithm. */
     };
     /** Create a camera group associated with an osgViewer::Viewer.
      * @param viewer the viewer