1
0
Fork 0

CameraGroup class for managing multiple cameras.

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.
This commit is contained in:
timoore 2008-08-01 15:57:29 +00:00
parent a8c27e0cf1
commit 6f802959ce
24 changed files with 1599 additions and 536 deletions

View file

@ -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>

View file

@ -49,7 +49,8 @@
#include "gui.h" #include "gui.h"
#include "layout.hxx" #include "layout.hxx"
using namespace osg; #include <osg/GraphicsContext>
using namespace flightgear; using namespace flightgear;
puFont guiFnt = 0; puFont guiFnt = 0;
@ -67,7 +68,7 @@ public:
GUIInitOperation() : GraphicsContextOperation(std::string("GUI init")) GUIInitOperation() : GraphicsContextOperation(std::string("GUI init"))
{ {
} }
void run(GraphicsContext* gc) void run(osg::GraphicsContext* gc)
{ {
WindowSystemAdapter* wsa = WindowSystemAdapter::getWSA(); WindowSystemAdapter* wsa = WindowSystemAdapter::getWSA();
wsa->puInitialize(); 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; if (gc) {
WindowSystemAdapter* wsa = WindowSystemAdapter::getWSA(); initOp = new GUIInitOperation;
GraphicsContext* gc = wsa->getGUIGraphicsContext(); gc->add(initOp.get());
gc->add(initOp.get()); }
} }
bool guiFinishInit() bool guiFinishInit()
{ {
if (!initOp.valid()) if (!initOp.valid())
return false; return true;
if (!initOp->isFinished()) if (!initOp->isFinished())
return false; return false;
initOp = 0; initOp = 0;

View file

@ -35,9 +35,12 @@
#define TR_HIRES_SNAP 1 #define TR_HIRES_SNAP 1
namespace osg
{
class GraphicsContext;
}
// gui.cxx // gui.cxx
extern void guiStartInit(); extern void guiStartInit(osg::GraphicsContext*);
extern bool guiFinishInit(); extern bool guiFinishInit();
extern void mkDialog(const char *txt); extern void mkDialog(const char *txt);
extern void guiErrorMessage(const char *txt); extern void guiErrorMessage(const char *txt);

View 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 nearest one is the first one and the deepest
// (the most specialized one in the scenegraph) is the first. // (the most specialized one in the scenegraph) is the first.
std::vector<SGSceneryPick> pickList; std::vector<SGSceneryPick> pickList;
if (FGRenderer::pick(x, y, pickList, ea)) { if (FGRenderer::pick(pickList, ea)) {
std::vector<SGSceneryPick>::const_iterator i; std::vector<SGSceneryPick>::const_iterator i;
for (i = pickList.begin(); i != pickList.end(); ++i) { for (i = pickList.begin(); i != pickList.end(); ++i) {
if (i->callback->buttonPressed(b, i->info)) { if (i->callback->buttonPressed(b, i->info)) {

383
src/Main/CameraGroup.cxx Normal file
View file

@ -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);
}
}

198
src/Main/CameraGroup.hxx Normal file
View file

@ -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

View file

@ -1,16 +1,24 @@
#ifdef HAVE_CONFIG_H #ifdef HAVE_CONFIG_H
# include <config.h> # include <config.h>
#endif #endif
#include <osg/Camera>
#include <osg/GraphicsContext>
#include <osg/Math> #include <osg/Math>
#include <osg/Viewport>
#include <osgViewer/Viewer> #include <osgViewer/Viewer>
#include <plib/pu.h> #include <plib/pu.h>
#include <Main/fg_props.hxx> #include <Main/fg_props.hxx>
#include "CameraGroup.hxx"
#include "FGManipulator.hxx" #include "FGManipulator.hxx"
#include "WindowSystemAdapter.hxx"
#if !defined(X_DISPLAY_MISSING) #if !defined(X_DISPLAY_MISSING)
#define X_DOUBLE_SCROLL_BUG 1 #define X_DOUBLE_SCROLL_BUG 1
#endif #endif
namespace flightgear
{
const int displayStatsKey = 1; const int displayStatsKey = 1;
const int printStatsKey = 2; const int printStatsKey = 2;
@ -91,8 +99,10 @@ osg::Node* FGManipulator::getNode()
return _node.get(); return _node.get();
} }
namespace
{
// Translate OSG modifier mask to FG modifier mask. // Translate OSG modifier mask to FG modifier mask.
static int osgToFGModifiers(int modifiers) int osgToFGModifiers(int modifiers)
{ {
int result = 0; int result = 0;
if (modifiers & osgGA::GUIEventAdapter::MODKEY_SHIFT) if (modifiers & osgGA::GUIEventAdapter::MODKEY_SHIFT)
@ -114,6 +124,7 @@ static int osgToFGModifiers(int modifiers)
result |= KEYMOD_HYPER; result |= KEYMOD_HYPER;
return result; return result;
} }
}
void FGManipulator::init(const osgGA::GUIEventAdapter& ea, void FGManipulator::init(const osgGA::GUIEventAdapter& ea,
osgGA::GUIActionAdapter& us) osgGA::GUIActionAdapter& us)
@ -122,29 +133,42 @@ void FGManipulator::init(const osgGA::GUIEventAdapter& ea,
(void)handle(ea, us); (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, eventToViewport(const osgGA::GUIEventAdapter& ea, osgGA::GUIActionAdapter& us,
int& x, int& y) int& x, int& y)
{ {
x = -1; x = -1;
y = -1; y = -1;
const osgViewer::Viewer* viewer; const osg::GraphicsContext* eventGC = ea.getGraphicsContext();
viewer = dynamic_cast<const osgViewer::Viewer*>(&us); const osg::GraphicsContext::Traits* traits = eventGC->getTraits();
if (!viewer) osg::Camera* guiCamera = getGUICamera(CameraGroup::getDefault());
if (!guiCamera)
return false; return false;
osg::Viewport* vport = guiCamera->getViewport();
float lx, ly; if (!vport)
const osg::Camera* camera;
camera = viewer->getCameraContainingPosition(ea.getX(), ea.getY(), lx, ly);
if (!(camera && fgOSIsMainCamera(camera)))
return false; return false;
x = int(lx); // Scale x, y to the dimensions of the window
y = int(camera->getViewport()->height() - ly); double wx = (((ea.getX() - ea.getXmin()) / (ea.getXmax() - ea.getXmin()))
* (float)traits->width);
return true; 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, 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;
}
}

View file

@ -8,6 +8,8 @@
#include "fg_os.hxx" #include "fg_os.hxx"
namespace flightgear
{
class FGManipulator : public osgGA::MatrixManipulator { class FGManipulator : public osgGA::MatrixManipulator {
public: public:
FGManipulator(); FGManipulator();
@ -142,4 +144,9 @@ protected:
int release_keys[128]; int release_keys[128];
void handleStats(osgGA::GUIActionAdapter& us); 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 #endif

View file

@ -60,9 +60,11 @@ libMain_a_SOURCES = \
util.cxx util.hxx \ util.cxx util.hxx \
viewer.cxx viewer.hxx \ viewer.cxx viewer.hxx \
viewmgr.cxx viewmgr.hxx \ viewmgr.cxx viewmgr.hxx \
CameraGroup.cxx CameraGroup.hxx \
FGManipulator.cxx FGManipulator.hxx \ FGManipulator.cxx FGManipulator.hxx \
ViewPartitionNode.cxx ViewPartitionNode.hxx \ ViewPartitionNode.cxx ViewPartitionNode.hxx \
WindowSystemAdapter.hxx WindowSystemAdapter.cxx \ WindowSystemAdapter.hxx WindowSystemAdapter.cxx \
WindowBuilder.hxx WindowBuilder.cxx \
$(GFX_CODE) $(GFX_CODE)
fgfs_SOURCES = bootstrap.cxx fgfs_SOURCES = bootstrap.cxx

228
src/Main/WindowBuilder.cxx Normal file
View file

@ -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;
}
}
}

View file

@ -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

View file

@ -22,13 +22,18 @@
#include<algorithm> #include<algorithm>
#include <functional> #include <functional>
#include "CameraGroup.hxx"
#include "WindowSystemAdapter.hxx" #include "WindowSystemAdapter.hxx"
#include <osg/Camera>
#include <osg/GraphicsContext>
#include <osg/Viewport>
using namespace osg; using namespace osg;
using namespace std; using namespace std;
using namespace flightgear; namespace flightgear
{
ref_ptr<WindowSystemAdapter> WindowSystemAdapter::_wsa; ref_ptr<WindowSystemAdapter> WindowSystemAdapter::_wsa;
void GraphicsContextOperation::operator()(GraphicsContext* gc) void GraphicsContextOperation::operator()(GraphicsContext* gc)
@ -38,7 +43,7 @@ void GraphicsContextOperation::operator()(GraphicsContext* gc)
} }
WindowSystemAdapter::WindowSystemAdapter() : WindowSystemAdapter::WindowSystemAdapter() :
_nextWindowID(0), _nextCameraID(0), _isPuInitialized(false) _nextWindowID(0), _isPuInitialized(false)
{ {
} }
@ -52,63 +57,25 @@ WindowSystemAdapter::registerWindow(GraphicsContext* gc,
return window; return window;
} }
Camera3D* // The pu getWindow callback is supposed to return a window ID that
WindowSystemAdapter::registerCamera3D(GraphicsWindow* gw, Camera* camera, // would allow drawing a GUI on different windows. All that stuff is
const string& cameraName) // broken in multi-threaded OSG, and we only have one GUI "window"
{ // anyway, so just return a constant.
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();
}
int WindowSystemAdapter::puGetWindow() int WindowSystemAdapter::puGetWindow()
{ {
WindowSystemAdapter* wsa = getWSA(); return 1;
return wsa->getGUIWindowID();
} }
void WindowSystemAdapter::puGetWindowSize(int* width, int* height) void WindowSystemAdapter::puGetWindowSize(int* width, int* height)
{ {
// XXX This will have to be different when multiple cameras share *width = 0;
// a single window. *height = 0;
WindowSystemAdapter* wsa = getWSA(); Camera* camera = getGUICamera(CameraGroup::getDefault());
const GraphicsContext* gc = wsa->getGUIGraphicsContext(); if (!camera)
const GraphicsContext::Traits *traits = gc->getTraits(); return;
*width = traits->width; Viewport* vport = camera->getViewport();
*height = traits->height; *width = (int)vport->width();
*height = (int)vport->height();
} }
void WindowSystemAdapter::puInitialize() void WindowSystemAdapter::puInitialize()
@ -116,3 +83,15 @@ void WindowSystemAdapter::puInitialize()
puSetWindowFuncs(puGetWindow, 0, puGetWindowSize, 0); puSetWindowFuncs(puGetWindow, 0, puGetWindowSize, 0);
puRealInit(); 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;
}
}

View file

@ -22,15 +22,20 @@
#include <osg/Referenced> #include <osg/Referenced>
#include <osg/Camera> #include <osg/Camera>
#include <osg/GraphicsContext>
#include <osg/GraphicsThread> #include <osg/GraphicsThread>
#include <osg/ref_ptr>
#include <simgear/structure/SGAtomic.hxx> #include <simgear/structure/SGAtomic.hxx>
// Flexible Camera and window support namespace osg
{
class GraphicsContext;
}
// Flexible window support
namespace flightgear 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 class GraphicsWindow : public osg::Referenced
{ {
@ -46,42 +51,23 @@ public:
/** The window's internal name. /** The window's internal name.
*/ */
std::string name; std::string name;
enum Flags { /** A unique ID for the window.
/** The GUI (and 2D cockpit) will be drawn on this window. */
*/
GUI = 1
};
int id; 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 { enum Flags {
SHARES_WINDOW = 1, /**< Camera shares window with other cameras*/ GUI = 1 /**< The GUI (and 2D cockpit) will be drawn on this window. */
MASTER = 2 /**< Camera has same view as master camera*/
}; };
/** Flags for the window.
*/
unsigned flags; unsigned flags;
}; };
typedef std::vector<osg::ref_ptr<GraphicsWindow> > WindowVector; 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 * 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 class GraphicsContextOperation : public osg::GraphicsOperation
{ {
@ -90,8 +76,15 @@ public:
osg::GraphicsOperation(name, false) osg::GraphicsOperation(name, false)
{ {
} }
/** Don't override this!
*/
virtual void operator()(osg::GraphicsContext* gc); virtual void operator()(osg::GraphicsContext* gc);
/** The body of the operation.
*/
virtual void run(osg::GraphicsContext* gc) = 0; 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; } bool isFinished() const { return done != 0; }
private: private:
SGAtomic done; SGAtomic done;
@ -99,7 +92,7 @@ private:
/** Adapter from windows system / graphics context management API to /** Adapter from windows system / graphics context management API to
* functions used by flightgear. This papers over the difference * 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. * threads, etc., and the embedded viewer used with GLUT and SDL.
*/ */
class WindowSystemAdapter : public osg::Referenced class WindowSystemAdapter : public osg::Referenced
@ -107,37 +100,35 @@ class WindowSystemAdapter : public osg::Referenced
public: public:
WindowSystemAdapter(); WindowSystemAdapter();
virtual ~WindowSystemAdapter() {} virtual ~WindowSystemAdapter() {}
/** Vector of all the registered windows.
*/
WindowVector 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, GraphicsWindow* registerWindow(osg::GraphicsContext* gc,
const std::string& windowName); 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 /** Initialize the plib pui interface library. This might happen
*in another thread and may be deferred. *in another thread and may be deferred.
*/ */
virtual void puInitialize(); 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(); } static WindowSystemAdapter* getWSA() { return _wsa.get(); }
/** Set the global adapter
* @param wsa the adapter
*/
static void setWSA(WindowSystemAdapter* wsa) { _wsa = wsa; } static void setWSA(WindowSystemAdapter* wsa) { _wsa = wsa; }
protected: protected:
int _nextWindowID; int _nextWindowID;
int _nextCameraID;
osg::ref_ptr<GraphicsContextOperation> _puInitOp; osg::ref_ptr<GraphicsContextOperation> _puInitOp;
bool _isPuInitialized; bool _isPuInitialized;
static osg::ref_ptr<WindowSystemAdapter> _wsa; static osg::ref_ptr<WindowSystemAdapter> _wsa;
@ -146,5 +137,29 @@ protected:
static void puGetWindowSize(int* width, int* height); 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 #endif

View file

@ -7,6 +7,7 @@
# include <config.h> # include <config.h>
#endif #endif
#include <osg/Matrix>
#include <osgViewer/Viewer> #include <osgViewer/Viewer>
#include <osgViewer/ViewerEventHandlers> #include <osgViewer/ViewerEventHandlers>
@ -25,6 +26,7 @@
#include "renderer.hxx" #include "renderer.hxx"
#include "fg_props.hxx" #include "fg_props.hxx"
#include "WindowSystemAdapter.hxx" #include "WindowSystemAdapter.hxx"
#include "CameraGroup.hxx"
using namespace flightgear; using namespace flightgear;
@ -34,7 +36,6 @@ using namespace flightgear;
// //
static osg::ref_ptr<osgViewer::Viewer> viewer; static osg::ref_ptr<osgViewer::Viewer> viewer;
static osg::ref_ptr<osg::Camera> mainCamera;
static osg::ref_ptr<osgViewer::GraphicsWindowEmbedded> gw; static osg::ref_ptr<osgViewer::GraphicsWindowEmbedded> gw;
static int GlutModifiers = 0; static int GlutModifiers = 0;
@ -274,16 +275,17 @@ void fgOSOpenWindow(bool stencil)
viewer->setDatabasePager(FGScenery::getPagerSingleton()); viewer->setDatabasePager(FGScenery::getPagerSingleton());
// now the main camera ... // now the main camera ...
osg::Camera* camera = new osg::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 // 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 // out of the SceneView objects in the viewer, and the coordinates
// of mouse events are somewhat bizzare. // of mouse events are somewhat bizzare.
camera->setViewport(new osg::Viewport(0, 0, realw, realh)); camera->setViewport(new osg::Viewport(0, 0, realw, realh));
camera->setProjectionResizePolicy(osg::Camera::FIXED); camera->setProjectionResizePolicy(osg::Camera::FIXED);
Camera3D* cam3D = wsa->registerCamera3D(window, camera, string("main")); CameraGroup* cgroup = new CameraGroup(viewer.get());
cam3D->flags |= Camera3D::MASTER; cgroup->addCamera(CameraGroup::DO_INTERSECTION_TEST, camera,
// Add as a slave for compatibility with the non-embedded osgViewer. osg::Matrixd::identity(), osg::Matrixd::identity(),
viewer->addSlave(camera); true);
cgroup->buildGUICamera(0, window);
CameraGroup::setDefault(cgroup);
viewer->setCameraManipulator(globals->get_renderer()->getManipulator()); viewer->setCameraManipulator(globals->get_renderer()->getManipulator());
// Let FG handle the escape key with a confirmation // Let FG handle the escape key with a confirmation
viewer->setKeyEventSetsDone(0); viewer->setKeyEventSetsDone(0);
@ -295,18 +297,3 @@ void fgOSOpenWindow(bool stencil)
viewer->setSceneData(new osg::Group); viewer->setSceneData(new osg::Group);
globals->get_renderer()->setViewer(viewer.get()); 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();
}

View file

@ -84,18 +84,4 @@ void fgRegisterWindowResizeHandler(fgWindowResizeHandler func);
void fgRegisterKeyHandler(fgKeyHandler func); void fgRegisterKeyHandler(fgKeyHandler func);
void fgRegisterMouseClickHandler(fgMouseClickHandler func); void fgRegisterMouseClickHandler(fgMouseClickHandler func);
void fgRegisterMouseMotionHandler(fgMouseMotionHandler 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 #endif // _FG_OS_HXX

View file

@ -18,10 +18,6 @@
// along with this program; if not, write to the Free Software // along with this program; if not, write to the Free Software
// Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. // Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
#ifdef HAVE_CONFIG_H
# include <config.h>
#endif
#include <algorithm> #include <algorithm>
#include <iostream> #include <iostream>
#include <sstream> #include <sstream>
@ -33,6 +29,7 @@
#include <simgear/structure/exception.hxx> #include <simgear/structure/exception.hxx>
#include <simgear/debug/logstream.hxx> #include <simgear/debug/logstream.hxx>
#include <osg/Camera>
#include <osg/GraphicsContext> #include <osg/GraphicsContext>
#include <osg/Group> #include <osg/Group>
#include <osg/Matrixd> #include <osg/Matrixd>
@ -50,6 +47,8 @@
#include "util.hxx" #include "util.hxx"
#include "globals.hxx" #include "globals.hxx"
#include "renderer.hxx" #include "renderer.hxx"
#include "CameraGroup.hxx"
#include "WindowBuilder.hxx"
#include "WindowSystemAdapter.hxx" #include "WindowSystemAdapter.hxx"
#if (FG_OSG_VERSION >= 19008) #if (FG_OSG_VERSION >= 19008)
@ -67,113 +66,66 @@ using namespace std;
using namespace flightgear; using namespace flightgear;
using namespace osg; using namespace osg;
static osg::ref_ptr<osgViewer::Viewer> viewer; static osg::ref_ptr<osgViewer::Viewer> viewer;
static osg::ref_ptr<osg::Camera> mainCamera; static osg::ref_ptr<osg::Camera> mainCamera;
// Callback to prevent the GraphicsContext resized function from messing
// with the projection matrix of the slave
namespace namespace
{ {
// silly function for making the default window and camera names // If a camera group isn't specified, build one from the top-level
std::string makeName(const string& prefix, int num) // 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; WindowSystemAdapter* wsa = WindowSystemAdapter::getWSA();
stream << prefix << num; CameraGroup* cgroup = CameraGroup::buildCameraGroup(viewer, gnode);
return stream.str(); // Look for a camera with no shear
} Camera* masterCamera = 0;
for (CameraGroup::CameraIterator iter = cgroup->camerasBegin(),
GraphicsContext::Traits* e = cgroup->camerasEnd();
makeDefaultTraits(GraphicsContext::WindowingSystemInterface* wsi, bool stencil) iter != e;
{ ++iter) {
int w = fgGetInt("/sim/startup/xsize"); const View::Slave& slave = viewer->getSlave((*iter)->slaveIndex);
int h = fgGetInt("/sim/startup/ysize"); if (slave._projectionOffset.isIdentity()) {
int bpp = fgGetInt("/sim/rendering/bits-per-pixel"); masterCamera = (*iter)->camera.get();
bool alpha = fgGetBool("/sim/rendering/clouds3d-enable"); break;
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; if (!masterCamera) {
} // No master camera found; better add one.
GraphicsWindow* window
void setTraitsFromProperties(GraphicsContext::Traits* traits, = WindowBuilder::getWindowBuilder()->getDefaultWindow();
const SGPropertyNode* winNode, masterCamera = new Camera();
GraphicsContext::WindowingSystemInterface* wsi) masterCamera->setGraphicsContext(window->gc.get());
{ const GraphicsContext::Traits *traits = window->gc->getTraits();
traits->hostName masterCamera->setViewport(new Viewport(0, 0,
= winNode->getStringValue("host-name", traits->hostName.c_str()); traits->width, traits->height));
traits->displayNum = winNode->getIntValue("display", traits->displayNum); cgroup->addCamera(CameraGroup::DO_INTERSECTION_TEST, masterCamera,
traits->screenNum = winNode->getIntValue("screen", traits->screenNum); Matrix(), Matrix());
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;
} }
traits->x = winNode->getIntValue("x", traits->x); // Find window on which the GUI is drawn.
traits->y = winNode->getIntValue("y", traits->y); WindowVector::iterator iter = wsa->windows.begin();
if (winNode->hasChild("window-name")) WindowVector::iterator end = wsa->windows.end();
traits->windowName = winNode->getStringValue("window-name"); for (; iter != end; ++iter) {
else if (winNode->hasChild("name")) if ((*iter)->gc.get() == masterCamera->getGraphicsContext())
traits->windowName = winNode->getStringValue("name"); break;
}
if (iter != end) { // Better not happen
(*iter)->flags |= GraphicsWindow::GUI;
cgroup->buildGUICamera(0, iter->get());
}
return cgroup;
}
} }
} //namespace
void fgOSOpenWindow(bool stencil) void fgOSOpenWindow(bool stencil)
{ {
osg::GraphicsContext::WindowingSystemInterface* wsi; osg::GraphicsContext::WindowingSystemInterface* wsi
wsi = osg::GraphicsContext::getWindowingSystemInterface(); = osg::GraphicsContext::getWindowingSystemInterface();
viewer = new osgViewer::Viewer; viewer = new osgViewer::Viewer;
viewer->setDatabasePager(FGScenery::getPagerSingleton()); viewer->setDatabasePager(FGScenery::getPagerSingleton());
CameraGroup* cameraGroup = 0;
std::string mode; std::string mode;
mode = fgGetString("/sim/rendering/multithreading-mode", "SingleThreaded"); mode = fgGetString("/sim/rendering/multithreading-mode", "SingleThreaded");
if (mode == "AutomaticSelection") if (mode == "AutomaticSelection")
@ -186,111 +138,32 @@ void fgOSOpenWindow(bool stencil)
viewer->setThreadingModel(osgViewer::Viewer::CullThreadPerCameraDrawThreadPerContext); viewer->setThreadingModel(osgViewer::Viewer::CullThreadPerCameraDrawThreadPerContext);
else else
viewer->setThreadingModel(osgViewer::Viewer::SingleThreaded); viewer->setThreadingModel(osgViewer::Viewer::SingleThreaded);
osg::ref_ptr<osg::GraphicsContext::Traits> traits WindowBuilder::initWindowBuilder(stencil);
= makeDefaultTraits(wsi, stencil); WindowBuilder *windowBuilder = WindowBuilder::getWindowBuilder();
// Ok, first the children. // Look for windows, camera groups, and the old syntax of
// that achieves some magic ordering og the slaves so that we end up // top-level cameras
// in the main window more often. const SGPropertyNode* renderingNode = fgGetNode("/sim/rendering");
// This can be sorted out better when we got rid of glut and sdl. for (int i = 0; i < renderingNode->nChildren(); ++i) {
FGManipulator* manipulator = globals->get_renderer()->getManipulator(); const SGPropertyNode* propNode = renderingNode->getChild(i);
string defaultName("slave"); const char* propName = propNode->getName();
WindowSystemAdapter* wsa = WindowSystemAdapter::getWSA(); if (!strcmp(propName, "window")) {
if (fgHasNode("/sim/rendering/camera")) { windowBuilder->buildWindow(propNode);
SGPropertyNode* renderingNode = fgGetNode("/sim/rendering"); } else if (!strcmp(propName, "camera-group")) {
for (int i = 0; i < renderingNode->nChildren(); ++i) { cameraGroup = CameraGroup::buildCameraGroup(viewer.get(), propNode);
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);
}
} }
} }
// now the main camera ... if (!cameraGroup)
// XXX mainCamera's purpose is to establish a "main graphics cameraGroup = buildDefaultCameraGroup(viewer.get(), renderingNode);
// context" that can be made current (if necessary). But that Camera* guiCamera = getGUICamera(cameraGroup);
// should be a context established with a window. It's used to if (guiCamera) {
// choose whether to render the GUI and panel camera nodes, but Viewport* guiViewport = guiCamera->getViewport();
// that's obsolete because the GUI is rendered in its own fgSetInt("/sim/startup/xsize", guiViewport->width());
// slave. And it's used to translate mouse event coordinates, but fgSetInt("/sim/startup/ysize", guiViewport->height());
// 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 (wsa->cameras.size() != 1) { FGManipulator* manipulator = globals->get_renderer()->getManipulator();
WindowSystemAdapter* wsa = WindowSystemAdapter::getWSA();
if (wsa->windows.size() != 1) {
manipulator->setResizable(false); manipulator->setResizable(false);
} }
viewer->getCamera()->setProjectionResizePolicy(osg::Camera::FIXED); viewer->getCamera()->setProjectionResizePolicy(osg::Camera::FIXED);
@ -300,6 +173,7 @@ void fgOSOpenWindow(bool stencil)
// The viewer won't start without some root. // The viewer won't start without some root.
viewer->setSceneData(new osg::Group); viewer->setSceneData(new osg::Group);
globals->get_renderer()->setViewer(viewer.get()); globals->get_renderer()->setViewer(viewer.get());
CameraGroup::setDefault(cameraGroup);
} }
static int status = 0; static int status = 0;
@ -324,17 +198,7 @@ int fgGetKeyModifiers()
void fgWarpMouse(int x, int y) void fgWarpMouse(int x, int y)
{ {
globals->get_renderer()->getManipulator()->setMouseWarped(); warpGUIPointer(CameraGroup::getDefault(), x, y);
// 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);
} }
void fgOSInit(int* argc, char** argv) void fgOSInit(int* argc, char** argv)
@ -393,36 +257,3 @@ int fgGetMouseCursor()
{ {
return _cursor; 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();
}

View file

@ -14,6 +14,7 @@
#include "globals.hxx" #include "globals.hxx"
#include "renderer.hxx" #include "renderer.hxx"
#include "fg_props.hxx" #include "fg_props.hxx"
#include "CameraGroup.hxx"
#include "WindowSystemAdapter.hxx" #include "WindowSystemAdapter.hxx"
using namespace flightgear; using namespace flightgear;
@ -34,7 +35,6 @@ static int VidMask = SDL_OPENGL|SDL_RESIZABLE;
static void initCursors(); static void initCursors();
static osg::ref_ptr<osgViewer::Viewer> viewer; static osg::ref_ptr<osgViewer::Viewer> viewer;
static osg::ref_ptr<osg::Camera> mainCamera;
static osg::ref_ptr<osgViewer::GraphicsWindowEmbedded> gw; static osg::ref_ptr<osgViewer::GraphicsWindowEmbedded> gw;
void fgOSOpenWindow(bool stencil) void fgOSOpenWindow(bool stencil)
@ -96,16 +96,17 @@ void fgOSOpenWindow(bool stencil)
window->flags |= GraphicsWindow::GUI; window->flags |= GraphicsWindow::GUI;
// now the main camera ... // now the main camera ...
osg::Camera* camera = new osg::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 // 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 // out of the SceneView objects in the viewer, and the coordinates
// of mouse events are somewhat bizzare. // of mouse events are somewhat bizzare.
camera->setViewport(new osg::Viewport(0, 0, realw, realh)); camera->setViewport(new osg::Viewport(0, 0, realw, realh));
camera->setProjectionResizePolicy(osg::Camera::FIXED); camera->setProjectionResizePolicy(osg::Camera::FIXED);
Camera3D* cam3D = wsa->registerCamera3D(window, camera, string("main")); CameraGroup* cgroup = new CameraGroup(viewer.get());
cam3D->flags |= Camera3D::MASTER; cgroup->addCamera(CameraGroup::DO_INTERSECTION_TEST, camera,
// Add as a slave for compatibility with the non-embedded osgViewer. osg::Matrixd::identity(), osg::Matrixd::identity(),
viewer->addSlave(camera); true);
cgroup->buildGUICamera(0, window);
CameraGroup::setDefault(cgroup);
viewer->setCameraManipulator(globals->get_renderer()->getManipulator()); viewer->setCameraManipulator(globals->get_renderer()->getManipulator());
// Let FG handle the escape key with a confirmation // Let FG handle the escape key with a confirmation
viewer->setKeyEventSetsDone(0); viewer->setKeyEventSetsDone(0);
@ -410,18 +411,3 @@ static void initCursors()
cursors[i].hoty); cursors[i].hoty);
} }
} }
bool fgOSIsMainCamera(const osg::Camera*)
{
return true;
}
bool fgOSIsMainContext(const osg::GraphicsContext*)
{
return true;
}
osg::GraphicsContext* fgOSGetMainContext()
{
return gw.get();
}

View file

@ -34,6 +34,8 @@
#include <plib/netSocket.h> #include <plib/netSocket.h>
#include <osg/Camera>
#include <osg/GraphicsContext>
#include <osgDB/Registry> #include <osgDB/Registry>
// Class references // Class references
@ -68,6 +70,7 @@
#include <GUI/new_gui.hxx> #include <GUI/new_gui.hxx>
#include <MultiPlayer/multiplaymgr.hxx> #include <MultiPlayer/multiplaymgr.hxx>
#include "CameraGroup.hxx"
#include "fg_commands.hxx" #include "fg_commands.hxx"
#include "fg_io.hxx" #include "fg_io.hxx"
#include "renderer.hxx" #include "renderer.hxx"
@ -75,11 +78,15 @@
#include "main.hxx" #include "main.hxx"
#include "util.hxx" #include "util.hxx"
#include "fg_init.hxx" #include "fg_init.hxx"
#include "WindowSystemAdapter.hxx"
static double real_delta_time_sec = 0.0; static double real_delta_time_sec = 0.0;
double delta_time_sec = 0.0; double delta_time_sec = 0.0;
extern float init_volume; extern float init_volume;
using namespace flightgear;
// This is a record containing a bit of global housekeeping information // This is a record containing a bit of global housekeeping information
FGGeneral general; FGGeneral general;
@ -650,21 +657,18 @@ static void fgMainLoop( void ) {
SG_LOG( SG_ALL, SG_DEBUG, "" ); SG_LOG( SG_ALL, SG_DEBUG, "" );
} }
// Operation for querying OpenGL parameters. This must be done in a
// This is the top level master main function that is registered as // valid OpenGL context, potentially in another thread.
// our idle funciton namespace
{
// The first few passes take care of initialization things (a couple struct GeneralInitOperation : public GraphicsContextOperation
// per pass) and once everything has been initialized fgMainLoop from {
// then on. GeneralInitOperation()
: GraphicsContextOperation(std::string("General init"))
static void fgIdleFunction ( void ) { {
if ( idle_state == 0 ) { }
idle_state++; void run(osg::GraphicsContext* gc)
{
// 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. :-(
general.set_glVendor( (char *)glGetString ( GL_VENDOR ) ); general.set_glVendor( (char *)glGetString ( GL_VENDOR ) );
general.set_glRenderer( (char *)glGetString ( GL_RENDERER ) ); general.set_glRenderer( (char *)glGetString ( GL_RENDERER ) );
general.set_glVersion( (char *)glGetString ( GL_VERSION ) ); general.set_glVersion( (char *)glGetString ( GL_VERSION ) );
@ -678,12 +682,42 @@ static void fgIdleFunction ( void ) {
glGetIntegerv( GL_DEPTH_BITS, &tmp ); glGetIntegerv( GL_DEPTH_BITS, &tmp );
general.set_glDepthBits( tmp ); general.set_glDepthBits( tmp );
SG_LOG ( SG_GENERAL, SG_INFO, "Depth buffer bits = " << tmp ); SG_LOG ( SG_GENERAL, SG_INFO, "Depth buffer bits = " << tmp );
}
};
}
// Initialize the user interface so that we can use fonts // This is the top level master main function that is registered as
guiStartInit(); // 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 ) { } else if ( idle_state == 1 ) {
if (genOp.valid()) {
if (!genOp->isFinished())
return;
genOp = 0;
}
if (!guiFinishInit()) if (!guiFinishInit())
return; return;
idle_state++; idle_state++;

View file

@ -1227,12 +1227,12 @@ where:
enum OptionType { OPTION_BOOL, OPTION_STRING, OPTION_DOUBLE, OPTION_INT, OPTION_CHANNEL, OPTION_FUNC }; enum OptionType { OPTION_BOOL, OPTION_STRING, OPTION_DOUBLE, OPTION_INT, OPTION_CHANNEL, OPTION_FUNC };
struct OptionDesc { struct OptionDesc {
char *option; const char *option;
bool has_param; bool has_param;
enum OptionType type; enum OptionType type;
char *property; const char *property;
bool b_param; bool b_param;
char *s_param; const char *s_param;
int (*func)( const char * ); int (*func)( const char * );
} fgOptionArray[] = { } fgOptionArray[] = {

View file

@ -37,6 +37,7 @@
#include <osg/Light> #include <osg/Light>
#include <osg/LightModel> #include <osg/LightModel>
#include <osg/LightSource> #include <osg/LightSource>
#include <osg/Material>
#include <osg/NodeCallback> #include <osg/NodeCallback>
#include <osg/Notify> #include <osg/Notify>
#include <osg/PolygonMode> #include <osg/PolygonMode>
@ -60,6 +61,7 @@
#include <simgear/scene/material/matlib.hxx> #include <simgear/scene/material/matlib.hxx>
#include <simgear/scene/model/animation.hxx> #include <simgear/scene/model/animation.hxx>
#include <simgear/scene/model/placement.hxx> #include <simgear/scene/model/placement.hxx>
#include <simgear/scene/sky/sky.hxx>
#include <simgear/scene/util/SGUpdateVisitor.hxx> #include <simgear/scene/util/SGUpdateVisitor.hxx>
#include <simgear/scene/util/RenderConstants.hxx> #include <simgear/scene/util/RenderConstants.hxx>
#include <simgear/scene/tgdb/GroundLightManager.hxx> #include <simgear/scene/tgdb/GroundLightManager.hxx>
@ -95,6 +97,7 @@
#include "splash.hxx" #include "splash.hxx"
#include "renderer.hxx" #include "renderer.hxx"
#include "main.hxx" #include "main.hxx"
#include "CameraGroup.hxx"
#include "ViewPartitionNode.hxx" #include "ViewPartitionNode.hxx"
// XXX Make this go away when OSG 2.2 is released. // XXX Make this go away when OSG 2.2 is released.
@ -102,6 +105,8 @@
#define UPDATE_VISITOR_IN_VIEWER 1 #define UPDATE_VISITOR_IN_VIEWER 1
#endif #endif
using namespace flightgear;
class FGHintUpdateCallback : public osg::StateAttribute::Callback { class FGHintUpdateCallback : public osg::StateAttribute::Callback {
public: public:
FGHintUpdateCallback(const char* configNode) : FGHintUpdateCallback(const char* configNode) :
@ -153,8 +158,6 @@ public:
{ drawImplementation(*renderInfo.getState()); } { drawImplementation(*renderInfo.getState()); }
void drawImplementation(osg::State& state) const void drawImplementation(osg::State& state) const
{ {
if (!fgOSIsMainContext(state.getGraphicsContext()))
return;
state.setActiveTextureUnit(0); state.setActiveTextureUnit(0);
state.setClientActiveTextureUnit(0); state.setClientActiveTextureUnit(0);
@ -198,8 +201,6 @@ public:
{ drawImplementation(*renderInfo.getState()); } { drawImplementation(*renderInfo.getState()); }
void drawImplementation(osg::State& state) const void drawImplementation(osg::State& state) const
{ {
if (!fgOSIsMainContext(state.getGraphicsContext()))
return;
state.setActiveTextureUnit(0); state.setActiveTextureUnit(0);
state.setClientActiveTextureUnit(0); state.setClientActiveTextureUnit(0);
state.disableAllVertexArrays(); state.disableAllVertexArrays();
@ -406,38 +407,6 @@ FGRenderer::splashinit( void ) {
#endif #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 void
FGRenderer::init( void ) FGRenderer::init( void )
{ {
@ -541,13 +510,13 @@ FGRenderer::init( void )
stateSet->setUpdateCallback(new FGFogEnableUpdateCallback); stateSet->setUpdateCallback(new FGFogEnableUpdateCallback);
// plug in the GUI // plug in the GUI
osg::Camera* guiCamera = makeSlaveCamera(osg::Camera::POST_RENDER, 100); osg::Camera* guiCamera = getGUICamera(CameraGroup::getDefault());
guiCamera->setName("GUI"); if (guiCamera) {
osg::Geode* geode = new osg::Geode; osg::Geode* geode = new osg::Geode;
geode->addDrawable(new SGPuDrawable); geode->addDrawable(new SGPuDrawable);
geode->addDrawable(new SGHUDAndPanelDrawable); geode->addDrawable(new SGHUDAndPanelDrawable);
guiCamera->addChild(geode); guiCamera->addChild(geode);
}
osg::Switch* sw = new osg::Switch; osg::Switch* sw = new osg::Switch;
sw->setUpdateCallback(new FGScenerySwitchCallback); sw->setUpdateCallback(new FGScenerySwitchCallback);
sw->addChild(mRoot.get()); sw->addChild(mRoot.get());
@ -612,14 +581,14 @@ FGRenderer::update( bool refresh_camera_settings ) {
// update view port // update view port
resize( fgGetInt("/sim/startup/xsize"), resize( fgGetInt("/sim/startup/xsize"),
fgGetInt("/sim/startup/ysize") ); fgGetInt("/sim/startup/ysize") );
#if 0
SGVec3d position = current__view->getViewPosition(); SGVec3d position = current__view->getViewPosition();
SGQuatd attitude = current__view->getViewOrientation(); SGQuatd attitude = current__view->getViewOrientation();
SGVec3d osgPosition = attitude.transform(-position);
FGManipulator *manipulator = globals->get_renderer()->getManipulator(); FGManipulator *manipulator = globals->get_renderer()->getManipulator();
manipulator->setPosition(position.osg()); manipulator->setPosition(position.osg());
manipulator->setAttitude(attitude.osg()); manipulator->setAttitude(attitude.osg());
#endif
} }
osg::Camera *camera = viewer->getCamera(); osg::Camera *camera = viewer->getCamera();
@ -743,7 +712,7 @@ FGRenderer::update( bool refresh_camera_settings ) {
} }
// sgEnviro.setLight(l->adj_fog_color()); // sgEnviro.setLight(l->adj_fog_color());
#if 0
double agl = current__view->getAltitudeASL_ft()*SG_FEET_TO_METER double agl = current__view->getAltitudeASL_ft()*SG_FEET_TO_METER
- current__view->getSGLocation()->get_cur_elev_m(); - current__view->getSGLocation()->get_cur_elev_m();
@ -761,7 +730,7 @@ FGRenderer::update( bool refresh_camera_settings ) {
setCameraParameters(current__view->get_v_fov(), setCameraParameters(current__view->get_v_fov(),
current__view->get_aspect_ratio(), current__view->get_aspect_ratio(),
scene_nearplane, scene_farplane); scene_nearplane, scene_farplane);
#endif
// sgEnviro.startOfFrame(current__view->get_view_pos(), // sgEnviro.startOfFrame(current__view->get_view_pos(),
// current__view->get_world_up(), // current__view->get_world_up(),
// current__view->getLongitude_deg(), // current__view->getLongitude_deg(),
@ -850,44 +819,40 @@ void FGRenderer::setCameraParameters(float vfov, float aspectRatio,
} }
bool bool
FGRenderer::pick( unsigned x, unsigned y, FGRenderer::pick(std::vector<SGSceneryPick>& pickList,
std::vector<SGSceneryPick>& pickList, const osgGA::GUIEventAdapter* ea)
const osgGA::GUIEventAdapter* ea )
{ {
osgViewer::Viewer* viewer = globals->get_renderer()->getViewer(); osgViewer::Viewer* viewer = globals->get_renderer()->getViewer();
// wipe out the return ... // wipe out the return ...
pickList.resize(0); pickList.clear();
if (viewer) {
// just compute intersections in the viewers method ...
typedef osgUtil::LineSegmentIntersector::Intersections Intersections; typedef osgUtil::LineSegmentIntersector::Intersections Intersections;
Intersections intersections; Intersections intersections;
viewer->computeIntersections(ea->getX(), ea->getY(), intersections);
Intersections::iterator hit; if (!computeIntersections(CameraGroup::getDefault(), ea, intersections))
for (hit = intersections.begin(); hit != intersections.end(); ++hit) { return false;
const osg::NodePath& np = hit->nodePath; for (Intersections::iterator hit = intersections.begin(),
osg::NodePath::const_reverse_iterator npi; e = intersections.end();
for (npi = np.rbegin(); npi != np.rend(); ++npi) { hit != e;
SGSceneUserData* ud = SGSceneUserData::getSceneUserData(*npi); ++hit) {
if (!ud) const osg::NodePath& np = hit->nodePath;
continue; osg::NodePath::const_reverse_iterator npi;
for (unsigned i = 0; i < ud->getNumPickCallbacks(); ++i) { for (npi = np.rbegin(); npi != np.rend(); ++npi) {
SGPickCallback* pickCallback = ud->getPickCallback(i); SGSceneUserData* ud = SGSceneUserData::getSceneUserData(*npi);
if (!pickCallback) if (!ud)
continue; continue;
SGSceneryPick sceneryPick; for (unsigned i = 0; i < ud->getNumPickCallbacks(); ++i) {
sceneryPick.info.local = SGVec3d(hit->getLocalIntersectPoint()); SGPickCallback* pickCallback = ud->getPickCallback(i);
sceneryPick.info.wgs84 = SGVec3d(hit->getWorldIntersectPoint()); if (!pickCallback)
sceneryPick.callback = pickCallback; continue;
pickList.push_back(sceneryPick); SGSceneryPick sceneryPick;
sceneryPick.info.local = SGVec3d(hit->getLocalIntersectPoint());
sceneryPick.info.wgs84 = SGVec3d(hit->getWorldIntersectPoint());
sceneryPick.callback = pickCallback;
pickList.push_back(sceneryPick);
}
} }
}
} }
return !pickList.empty(); return !pickList.empty();
} else { // we can get called early ...
return false;
}
} }
void void

View file

@ -3,7 +3,6 @@
#define __FG_RENDERER_HXX 1 #define __FG_RENDERER_HXX 1
#include <simgear/screen/extensions.hxx> #include <simgear/screen/extensions.hxx>
#include <simgear/scene/sky/sky.hxx>
#include <simgear/scene/util/SGPickCallback.hxx> #include <simgear/scene/util/SGPickCallback.hxx>
#include <osg/Camera> #include <osg/Camera>
@ -46,8 +45,7 @@ public:
float zNear, float zFar); float zNear, float zFar);
/** Just pick into the scene and return the pick callbacks on the way ... /** Just pick into the scene and return the pick callbacks on the way ...
*/ */
static bool pick( unsigned x, unsigned y, static bool pick( std::vector<SGSceneryPick>& pickList,
std::vector<SGSceneryPick>& pickList,
const osgGA::GUIEventAdapter* ea ); const osgGA::GUIEventAdapter* ea );
/** Get and set the OSG Viewer object, if any. /** Get and set the OSG Viewer object, if any.
@ -57,9 +55,9 @@ public:
void setViewer(osgViewer::Viewer* viewer) { this->viewer = viewer; } void setViewer(osgViewer::Viewer* viewer) { this->viewer = viewer; }
/** Get and set the manipulator object, if any. /** Get and set the manipulator object, if any.
*/ */
FGManipulator* getManipulator() { return manipulator.get(); } flightgear::FGManipulator* getManipulator() { return manipulator.get(); }
const FGManipulator* getManipulator() const { return manipulator.get(); } const flightgear::FGManipulator* getManipulator() const { return manipulator.get(); }
void setManipulator(FGManipulator* manipulator) { void setManipulator(flightgear::FGManipulator* manipulator) {
this->manipulator = manipulator; this->manipulator = manipulator;
} }
@ -69,7 +67,7 @@ public:
protected: protected:
osg::ref_ptr<osgViewer::Viewer> viewer; osg::ref_ptr<osgViewer::Viewer> viewer;
osg::ref_ptr<FGManipulator> manipulator; osg::ref_ptr<flightgear::FGManipulator> manipulator;
}; };
bool fgDumpSceneGraphToFile(const char* filename); bool fgDumpSceneGraphToFile(const char* filename);

View file

@ -50,6 +50,9 @@
#include "viewer.hxx" #include "viewer.hxx"
#include "CameraGroup.hxx"
using namespace flightgear;
//////////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////////
// Implementation of FGViewer. // Implementation of FGViewer.
@ -81,7 +84,8 @@ FGViewer::FGViewer( fgViewType Type, bool from_model, int from_model_index,
_damp_heading(0), _damp_heading(0),
_scaling_type(FG_SCALING_MAX), _scaling_type(FG_SCALING_MAX),
_location(0), _location(0),
_target_location(0) _target_location(0),
_cameraGroup(CameraGroup::getDefault())
{ {
_absolute_view_pos = SGVec3d(0, 0, 0); _absolute_view_pos = SGVec3d(0, 0, 0);
_type = Type; _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());
} }

View file

@ -32,6 +32,13 @@
# error This library requires C++ # error This library requires C++
#endif #endif
namespace flightgear
{
class CameraGroup;
}
#include <osg/ref_ptr>
#include <simgear/compiler.h> #include <simgear/compiler.h>
#include <simgear/constants.h> #include <simgear/constants.h>
#include <simgear/structure/subsystem_mgr.hxx> #include <simgear/structure/subsystem_mgr.hxx>
@ -361,6 +368,8 @@ private:
// surface at the spot we are directly above // surface at the spot we are directly above
SGVec3f _world_up; SGVec3f _world_up;
// camera group controled by this view
osg::ref_ptr<flightgear::CameraGroup> _cameraGroup;
////////////////////////////////////////////////////////////////// //////////////////////////////////////////////////////////////////
// private functions // // private functions //
////////////////////////////////////////////////////////////////// //////////////////////////////////////////////////////////////////

View file

@ -33,7 +33,11 @@
#include <simgear/scene/tgdb/TileCache.hxx> #include <simgear/scene/tgdb/TileCache.hxx>
class SGReaderWriterBTGOptions; class SGReaderWriterBTGOptions;
class osg::Node;
namespace osg
{
class Node;
}
class FGTileMgr : public simgear::ModelLoadHelper { class FGTileMgr : public simgear::ModelLoadHelper {