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:
parent
a8c27e0cf1
commit
6f802959ce
24 changed files with 1599 additions and 536 deletions
315
docs-mini/README.multiscreen
Normal file
315
docs-mini/README.multiscreen
Normal 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>
|
|
@ -49,7 +49,8 @@
|
|||
#include "gui.h"
|
||||
#include "layout.hxx"
|
||||
|
||||
using namespace osg;
|
||||
#include <osg/GraphicsContext>
|
||||
|
||||
using namespace flightgear;
|
||||
|
||||
puFont guiFnt = 0;
|
||||
|
@ -67,7 +68,7 @@ public:
|
|||
GUIInitOperation() : GraphicsContextOperation(std::string("GUI init"))
|
||||
{
|
||||
}
|
||||
void run(GraphicsContext* gc)
|
||||
void run(osg::GraphicsContext* gc)
|
||||
{
|
||||
WindowSystemAdapter* wsa = WindowSystemAdapter::getWSA();
|
||||
wsa->puInitialize();
|
||||
|
@ -96,21 +97,21 @@ public:
|
|||
}
|
||||
};
|
||||
|
||||
ref_ptr<GUIInitOperation> initOp;
|
||||
osg::ref_ptr<GUIInitOperation> initOp;
|
||||
}
|
||||
|
||||
void guiStartInit()
|
||||
void guiStartInit(osg::GraphicsContext* gc)
|
||||
{
|
||||
initOp = new GUIInitOperation;
|
||||
WindowSystemAdapter* wsa = WindowSystemAdapter::getWSA();
|
||||
GraphicsContext* gc = wsa->getGUIGraphicsContext();
|
||||
gc->add(initOp.get());
|
||||
if (gc) {
|
||||
initOp = new GUIInitOperation;
|
||||
gc->add(initOp.get());
|
||||
}
|
||||
}
|
||||
|
||||
bool guiFinishInit()
|
||||
{
|
||||
if (!initOp.valid())
|
||||
return false;
|
||||
return true;
|
||||
if (!initOp->isFinished())
|
||||
return false;
|
||||
initOp = 0;
|
||||
|
|
|
@ -35,9 +35,12 @@
|
|||
|
||||
#define TR_HIRES_SNAP 1
|
||||
|
||||
|
||||
namespace osg
|
||||
{
|
||||
class GraphicsContext;
|
||||
}
|
||||
// gui.cxx
|
||||
extern void guiStartInit();
|
||||
extern void guiStartInit(osg::GraphicsContext*);
|
||||
extern bool guiFinishInit();
|
||||
extern void mkDialog(const char *txt);
|
||||
extern void guiErrorMessage(const char *txt);
|
||||
|
|
|
@ -342,7 +342,7 @@ FGInput::doMouseClick (int b, int updown, int x, int y, bool mainWindow, const o
|
|||
// The nearest one is the first one and the deepest
|
||||
// (the most specialized one in the scenegraph) is the first.
|
||||
std::vector<SGSceneryPick> pickList;
|
||||
if (FGRenderer::pick(x, y, pickList, ea)) {
|
||||
if (FGRenderer::pick(pickList, ea)) {
|
||||
std::vector<SGSceneryPick>::const_iterator i;
|
||||
for (i = pickList.begin(); i != pickList.end(); ++i) {
|
||||
if (i->callback->buttonPressed(b, i->info)) {
|
||||
|
|
383
src/Main/CameraGroup.cxx
Normal file
383
src/Main/CameraGroup.cxx
Normal 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
198
src/Main/CameraGroup.hxx
Normal 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
|
|
@ -1,16 +1,24 @@
|
|||
#ifdef HAVE_CONFIG_H
|
||||
# include <config.h>
|
||||
#endif
|
||||
#include <osg/Camera>
|
||||
#include <osg/GraphicsContext>
|
||||
#include <osg/Math>
|
||||
#include <osg/Viewport>
|
||||
#include <osgViewer/Viewer>
|
||||
|
||||
#include <plib/pu.h>
|
||||
#include <Main/fg_props.hxx>
|
||||
#include "CameraGroup.hxx"
|
||||
#include "FGManipulator.hxx"
|
||||
#include "WindowSystemAdapter.hxx"
|
||||
|
||||
#if !defined(X_DISPLAY_MISSING)
|
||||
#define X_DOUBLE_SCROLL_BUG 1
|
||||
#endif
|
||||
|
||||
namespace flightgear
|
||||
{
|
||||
const int displayStatsKey = 1;
|
||||
const int printStatsKey = 2;
|
||||
|
||||
|
@ -91,8 +99,10 @@ osg::Node* FGManipulator::getNode()
|
|||
return _node.get();
|
||||
}
|
||||
|
||||
namespace
|
||||
{
|
||||
// Translate OSG modifier mask to FG modifier mask.
|
||||
static int osgToFGModifiers(int modifiers)
|
||||
int osgToFGModifiers(int modifiers)
|
||||
{
|
||||
int result = 0;
|
||||
if (modifiers & osgGA::GUIEventAdapter::MODKEY_SHIFT)
|
||||
|
@ -114,6 +124,7 @@ static int osgToFGModifiers(int modifiers)
|
|||
result |= KEYMOD_HYPER;
|
||||
return result;
|
||||
}
|
||||
}
|
||||
|
||||
void FGManipulator::init(const osgGA::GUIEventAdapter& ea,
|
||||
osgGA::GUIActionAdapter& us)
|
||||
|
@ -122,29 +133,42 @@ void FGManipulator::init(const osgGA::GUIEventAdapter& ea,
|
|||
(void)handle(ea, us);
|
||||
}
|
||||
|
||||
static bool
|
||||
// Calculate event coordinates in the viewport of the GUI camera, if
|
||||
// possible. Otherwise return false and (-1, -1).
|
||||
namespace
|
||||
{
|
||||
bool
|
||||
eventToViewport(const osgGA::GUIEventAdapter& ea, osgGA::GUIActionAdapter& us,
|
||||
int& x, int& y)
|
||||
{
|
||||
x = -1;
|
||||
y = -1;
|
||||
|
||||
const osgViewer::Viewer* viewer;
|
||||
viewer = dynamic_cast<const osgViewer::Viewer*>(&us);
|
||||
if (!viewer)
|
||||
const osg::GraphicsContext* eventGC = ea.getGraphicsContext();
|
||||
const osg::GraphicsContext::Traits* traits = eventGC->getTraits();
|
||||
osg::Camera* guiCamera = getGUICamera(CameraGroup::getDefault());
|
||||
if (!guiCamera)
|
||||
return false;
|
||||
osg::Viewport* vport = guiCamera->getViewport();
|
||||
if (!vport)
|
||||
return false;
|
||||
|
||||
float lx, ly;
|
||||
const osg::Camera* camera;
|
||||
camera = viewer->getCameraContainingPosition(ea.getX(), ea.getY(), lx, ly);
|
||||
|
||||
if (!(camera && fgOSIsMainCamera(camera)))
|
||||
// Scale x, y to the dimensions of the window
|
||||
double wx = (((ea.getX() - ea.getXmin()) / (ea.getXmax() - ea.getXmin()))
|
||||
* (float)traits->width);
|
||||
double wy = (((ea.getY() - ea.getYmin()) / (ea.getYmax() - ea.getYmin()))
|
||||
* (float)traits->height);
|
||||
if (vport->x() <= wx && wx <= vport->x() + vport->width()
|
||||
&& vport->y() <= wy && wy <= vport->y() + vport->height()) {
|
||||
// Finally, into viewport coordinates. Change y to "increasing
|
||||
// downwards".
|
||||
x = wx - vport->x();
|
||||
y = vport->height() - (wy - vport->y());
|
||||
return true;
|
||||
} else {
|
||||
return false;
|
||||
|
||||
x = int(lx);
|
||||
y = int(camera->getViewport()->height() - ly);
|
||||
|
||||
return true;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
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;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -8,6 +8,8 @@
|
|||
|
||||
#include "fg_os.hxx"
|
||||
|
||||
namespace flightgear
|
||||
{
|
||||
class FGManipulator : public osgGA::MatrixManipulator {
|
||||
public:
|
||||
FGManipulator();
|
||||
|
@ -142,4 +144,9 @@ protected:
|
|||
int release_keys[128];
|
||||
void handleStats(osgGA::GUIActionAdapter& us);
|
||||
};
|
||||
|
||||
void eventToWindowCoords(const osgGA::GUIEventAdapter* ea, double& x, double& y);
|
||||
void eventToWindowCoordsYDown(const osgGA::GUIEventAdapter* ea,
|
||||
double& x, double& y);
|
||||
}
|
||||
#endif
|
||||
|
|
|
@ -60,9 +60,11 @@ libMain_a_SOURCES = \
|
|||
util.cxx util.hxx \
|
||||
viewer.cxx viewer.hxx \
|
||||
viewmgr.cxx viewmgr.hxx \
|
||||
CameraGroup.cxx CameraGroup.hxx \
|
||||
FGManipulator.cxx FGManipulator.hxx \
|
||||
ViewPartitionNode.cxx ViewPartitionNode.hxx \
|
||||
WindowSystemAdapter.hxx WindowSystemAdapter.cxx \
|
||||
WindowBuilder.hxx WindowBuilder.cxx \
|
||||
$(GFX_CODE)
|
||||
|
||||
fgfs_SOURCES = bootstrap.cxx
|
||||
|
|
228
src/Main/WindowBuilder.cxx
Normal file
228
src/Main/WindowBuilder.cxx
Normal 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;
|
||||
}
|
||||
}
|
||||
}
|
72
src/Main/WindowBuilder.hxx
Normal file
72
src/Main/WindowBuilder.hxx
Normal 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
|
|
@ -22,13 +22,18 @@
|
|||
#include<algorithm>
|
||||
#include <functional>
|
||||
|
||||
#include "CameraGroup.hxx"
|
||||
#include "WindowSystemAdapter.hxx"
|
||||
|
||||
#include <osg/Camera>
|
||||
#include <osg/GraphicsContext>
|
||||
#include <osg/Viewport>
|
||||
|
||||
using namespace osg;
|
||||
using namespace std;
|
||||
|
||||
using namespace flightgear;
|
||||
|
||||
namespace flightgear
|
||||
{
|
||||
ref_ptr<WindowSystemAdapter> WindowSystemAdapter::_wsa;
|
||||
|
||||
void GraphicsContextOperation::operator()(GraphicsContext* gc)
|
||||
|
@ -38,7 +43,7 @@ void GraphicsContextOperation::operator()(GraphicsContext* gc)
|
|||
}
|
||||
|
||||
WindowSystemAdapter::WindowSystemAdapter() :
|
||||
_nextWindowID(0), _nextCameraID(0), _isPuInitialized(false)
|
||||
_nextWindowID(0), _isPuInitialized(false)
|
||||
{
|
||||
}
|
||||
|
||||
|
@ -52,63 +57,25 @@ WindowSystemAdapter::registerWindow(GraphicsContext* gc,
|
|||
return window;
|
||||
}
|
||||
|
||||
Camera3D*
|
||||
WindowSystemAdapter::registerCamera3D(GraphicsWindow* gw, Camera* camera,
|
||||
const string& cameraName)
|
||||
{
|
||||
Camera3D* camera3D = new Camera3D(gw, camera, cameraName);
|
||||
cameras.push_back(camera3D);
|
||||
return camera3D;
|
||||
}
|
||||
|
||||
GraphicsWindow*
|
||||
WindowSystemAdapter::getGUIWindow()
|
||||
{
|
||||
WindowVector::const_iterator contextIter
|
||||
= std::find_if(windows.begin(), windows.end(),
|
||||
FlagTester<GraphicsWindow>(GraphicsWindow::GUI));
|
||||
if (contextIter == windows.end())
|
||||
return 0;
|
||||
else
|
||||
return contextIter->get();
|
||||
}
|
||||
|
||||
int
|
||||
WindowSystemAdapter::getGUIWindowID()
|
||||
{
|
||||
const GraphicsWindow* gw = getGUIWindow();
|
||||
if (!gw)
|
||||
return -1;
|
||||
else
|
||||
return gw->id;
|
||||
}
|
||||
|
||||
GraphicsContext*
|
||||
WindowSystemAdapter::getGUIGraphicsContext()
|
||||
{
|
||||
GraphicsWindow* gw = getGUIWindow();
|
||||
if (!gw)
|
||||
return 0;
|
||||
else
|
||||
return gw->gc.get();
|
||||
}
|
||||
|
||||
|
||||
// The pu getWindow callback is supposed to return a window ID that
|
||||
// would allow drawing a GUI on different windows. All that stuff is
|
||||
// broken in multi-threaded OSG, and we only have one GUI "window"
|
||||
// anyway, so just return a constant.
|
||||
int WindowSystemAdapter::puGetWindow()
|
||||
{
|
||||
WindowSystemAdapter* wsa = getWSA();
|
||||
return wsa->getGUIWindowID();
|
||||
return 1;
|
||||
}
|
||||
|
||||
void WindowSystemAdapter::puGetWindowSize(int* width, int* height)
|
||||
{
|
||||
// XXX This will have to be different when multiple cameras share
|
||||
// a single window.
|
||||
WindowSystemAdapter* wsa = getWSA();
|
||||
const GraphicsContext* gc = wsa->getGUIGraphicsContext();
|
||||
const GraphicsContext::Traits *traits = gc->getTraits();
|
||||
*width = traits->width;
|
||||
*height = traits->height;
|
||||
*width = 0;
|
||||
*height = 0;
|
||||
Camera* camera = getGUICamera(CameraGroup::getDefault());
|
||||
if (!camera)
|
||||
return;
|
||||
Viewport* vport = camera->getViewport();
|
||||
*width = (int)vport->width();
|
||||
*height = (int)vport->height();
|
||||
}
|
||||
|
||||
void WindowSystemAdapter::puInitialize()
|
||||
|
@ -116,3 +83,15 @@ void WindowSystemAdapter::puInitialize()
|
|||
puSetWindowFuncs(puGetWindow, 0, puGetWindowSize, 0);
|
||||
puRealInit();
|
||||
}
|
||||
|
||||
GraphicsWindow* WindowSystemAdapter::findWindow(const string& name)
|
||||
{
|
||||
for (WindowVector::iterator iter = windows.begin(), e = windows.end();
|
||||
iter != e;
|
||||
++iter) {
|
||||
if ((*iter)->name == name)
|
||||
return iter->get();
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -22,15 +22,20 @@
|
|||
|
||||
#include <osg/Referenced>
|
||||
#include <osg/Camera>
|
||||
#include <osg/GraphicsContext>
|
||||
#include <osg/GraphicsThread>
|
||||
#include <osg/ref_ptr>
|
||||
|
||||
#include <simgear/structure/SGAtomic.hxx>
|
||||
|
||||
// Flexible Camera and window support
|
||||
namespace osg
|
||||
{
|
||||
class GraphicsContext;
|
||||
}
|
||||
|
||||
// Flexible window support
|
||||
namespace flightgear
|
||||
{
|
||||
/** A window opened by default or via rendering properties
|
||||
/** A window with a graphics context and an integer ID
|
||||
*/
|
||||
class GraphicsWindow : public osg::Referenced
|
||||
{
|
||||
|
@ -46,42 +51,23 @@ public:
|
|||
/** The window's internal name.
|
||||
*/
|
||||
std::string name;
|
||||
enum Flags {
|
||||
/** The GUI (and 2D cockpit) will be drawn on this window.
|
||||
*/
|
||||
GUI = 1
|
||||
};
|
||||
/** A unique ID for the window.
|
||||
*/
|
||||
int id;
|
||||
unsigned flags;
|
||||
};
|
||||
|
||||
/** Camera associated with a 3d view. The camera might occupy an
|
||||
* entire window or share one with other cameras.
|
||||
*/
|
||||
class Camera3D : public osg::Referenced
|
||||
{
|
||||
public:
|
||||
Camera3D(GraphicsWindow* window_, osg::Camera* camera_, const std::string& name_,
|
||||
unsigned flags_ = 0) :
|
||||
window(window_), camera(camera_), name(name_), flags(flags_)
|
||||
{
|
||||
}
|
||||
osg::ref_ptr<GraphicsWindow> window;
|
||||
osg::ref_ptr<osg::Camera> camera;
|
||||
std::string name;
|
||||
enum Flags {
|
||||
SHARES_WINDOW = 1, /**< Camera shares window with other cameras*/
|
||||
MASTER = 2 /**< Camera has same view as master camera*/
|
||||
GUI = 1 /**< The GUI (and 2D cockpit) will be drawn on this window. */
|
||||
};
|
||||
/** Flags for the window.
|
||||
*/
|
||||
unsigned flags;
|
||||
};
|
||||
|
||||
typedef std::vector<osg::ref_ptr<GraphicsWindow> > WindowVector;
|
||||
typedef std::vector<osg::ref_ptr<Camera3D> > Camera3DVector;
|
||||
|
||||
/**
|
||||
* An operation that is run once with a particular GraphicsContext
|
||||
* current.
|
||||
* current. It will probably be deferred and may run in a different
|
||||
* thread.
|
||||
*/
|
||||
class GraphicsContextOperation : public osg::GraphicsOperation
|
||||
{
|
||||
|
@ -90,8 +76,15 @@ public:
|
|||
osg::GraphicsOperation(name, false)
|
||||
{
|
||||
}
|
||||
/** Don't override this!
|
||||
*/
|
||||
virtual void operator()(osg::GraphicsContext* gc);
|
||||
/** The body of the operation.
|
||||
*/
|
||||
virtual void run(osg::GraphicsContext* gc) = 0;
|
||||
/** Test if the operation has completed.
|
||||
* @return true if the run() method has finished.
|
||||
*/
|
||||
bool isFinished() const { return done != 0; }
|
||||
private:
|
||||
SGAtomic done;
|
||||
|
@ -99,7 +92,7 @@ private:
|
|||
|
||||
/** Adapter from windows system / graphics context management API to
|
||||
* functions used by flightgear. This papers over the difference
|
||||
* between osgViewer Viewer, which handles multiple windows, graphics
|
||||
* between osgViewer::Viewer, which handles multiple windows, graphics
|
||||
* threads, etc., and the embedded viewer used with GLUT and SDL.
|
||||
*/
|
||||
class WindowSystemAdapter : public osg::Referenced
|
||||
|
@ -107,37 +100,35 @@ class WindowSystemAdapter : public osg::Referenced
|
|||
public:
|
||||
WindowSystemAdapter();
|
||||
virtual ~WindowSystemAdapter() {}
|
||||
/** Vector of all the registered windows.
|
||||
*/
|
||||
WindowVector windows;
|
||||
Camera3DVector cameras;
|
||||
/** Register a window, assigning it an ID.
|
||||
* @param gc graphics context
|
||||
* @param windowName internal name (not displayed)
|
||||
* @return a graphics window
|
||||
*/
|
||||
GraphicsWindow* registerWindow(osg::GraphicsContext* gc,
|
||||
const std::string& windowName);
|
||||
Camera3D* registerCamera3D(GraphicsWindow* gw, osg::Camera* camera,
|
||||
const std::string& cameraName);
|
||||
GraphicsWindow* getGUIWindow();
|
||||
int getGUIWindowID();
|
||||
osg::GraphicsContext* getGUIGraphicsContext();
|
||||
/** Initialize the plib pui interface library. This might happen
|
||||
*in another thread and may be deferred.
|
||||
*/
|
||||
virtual void puInitialize();
|
||||
/** Returns true if pui initialization has finished.
|
||||
/** Find a window by name.
|
||||
* @param name the window name
|
||||
* @return the window or 0
|
||||
*/
|
||||
GraphicsWindow* findWindow(const std::string& name);
|
||||
/** Get the global WindowSystemAdapter
|
||||
* @return the adapter
|
||||
*/
|
||||
template<typename T>
|
||||
class FlagTester : public std::unary_function<osg::ref_ptr<T>, bool>
|
||||
{
|
||||
public:
|
||||
FlagTester(unsigned flags_) : flags(flags_) {}
|
||||
bool operator() (const osg::ref_ptr<T>& obj)
|
||||
{
|
||||
return (obj->flags & flags) != 0;
|
||||
}
|
||||
unsigned flags;
|
||||
};
|
||||
static WindowSystemAdapter* getWSA() { return _wsa.get(); }
|
||||
/** Set the global adapter
|
||||
* @param wsa the adapter
|
||||
*/
|
||||
static void setWSA(WindowSystemAdapter* wsa) { _wsa = wsa; }
|
||||
protected:
|
||||
int _nextWindowID;
|
||||
int _nextCameraID;
|
||||
osg::ref_ptr<GraphicsContextOperation> _puInitOp;
|
||||
bool _isPuInitialized;
|
||||
static osg::ref_ptr<WindowSystemAdapter> _wsa;
|
||||
|
@ -146,5 +137,29 @@ protected:
|
|||
static void puGetWindowSize(int* width, int* height);
|
||||
|
||||
};
|
||||
|
||||
/**
|
||||
* Class for testing if flags are set in an object with a flags member.
|
||||
*/
|
||||
template<typename T>
|
||||
class FlagTester : public std::unary_function<osg::ref_ptr<T>, bool>
|
||||
{
|
||||
public:
|
||||
/** Initialize with flags to test for.
|
||||
* @param flags logical or of flags to test.
|
||||
*/
|
||||
FlagTester(unsigned flags_) : flags(flags_) {}
|
||||
/** test operator
|
||||
* @param obj An object with a flags member
|
||||
* @return true if flags member of obj contains any of the flags
|
||||
* (bitwise and with flags is nonzero).
|
||||
*/
|
||||
bool operator() (const osg::ref_ptr<T>& obj)
|
||||
{
|
||||
return (obj->flags & flags) != 0;
|
||||
}
|
||||
unsigned flags;
|
||||
};
|
||||
|
||||
}
|
||||
#endif
|
||||
|
|
|
@ -7,6 +7,7 @@
|
|||
# include <config.h>
|
||||
#endif
|
||||
|
||||
#include <osg/Matrix>
|
||||
#include <osgViewer/Viewer>
|
||||
#include <osgViewer/ViewerEventHandlers>
|
||||
|
||||
|
@ -25,6 +26,7 @@
|
|||
#include "renderer.hxx"
|
||||
#include "fg_props.hxx"
|
||||
#include "WindowSystemAdapter.hxx"
|
||||
#include "CameraGroup.hxx"
|
||||
|
||||
using namespace flightgear;
|
||||
|
||||
|
@ -34,7 +36,6 @@ using namespace flightgear;
|
|||
//
|
||||
|
||||
static osg::ref_ptr<osgViewer::Viewer> viewer;
|
||||
static osg::ref_ptr<osg::Camera> mainCamera;
|
||||
static osg::ref_ptr<osgViewer::GraphicsWindowEmbedded> gw;
|
||||
|
||||
static int GlutModifiers = 0;
|
||||
|
@ -274,16 +275,17 @@ void fgOSOpenWindow(bool stencil)
|
|||
viewer->setDatabasePager(FGScenery::getPagerSingleton());
|
||||
// now the main camera ...
|
||||
osg::Camera* camera = new osg::Camera;
|
||||
mainCamera = camera;
|
||||
// If a viewport isn't set on the camera, then it's hard to dig it
|
||||
// out of the SceneView objects in the viewer, and the coordinates
|
||||
// of mouse events are somewhat bizzare.
|
||||
camera->setViewport(new osg::Viewport(0, 0, realw, realh));
|
||||
camera->setProjectionResizePolicy(osg::Camera::FIXED);
|
||||
Camera3D* cam3D = wsa->registerCamera3D(window, camera, string("main"));
|
||||
cam3D->flags |= Camera3D::MASTER;
|
||||
// Add as a slave for compatibility with the non-embedded osgViewer.
|
||||
viewer->addSlave(camera);
|
||||
CameraGroup* cgroup = new CameraGroup(viewer.get());
|
||||
cgroup->addCamera(CameraGroup::DO_INTERSECTION_TEST, camera,
|
||||
osg::Matrixd::identity(), osg::Matrixd::identity(),
|
||||
true);
|
||||
cgroup->buildGUICamera(0, window);
|
||||
CameraGroup::setDefault(cgroup);
|
||||
viewer->setCameraManipulator(globals->get_renderer()->getManipulator());
|
||||
// Let FG handle the escape key with a confirmation
|
||||
viewer->setKeyEventSetsDone(0);
|
||||
|
@ -295,18 +297,3 @@ void fgOSOpenWindow(bool stencil)
|
|||
viewer->setSceneData(new osg::Group);
|
||||
globals->get_renderer()->setViewer(viewer.get());
|
||||
}
|
||||
|
||||
bool fgOSIsMainCamera(const osg::Camera*)
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
bool fgOSIsMainContext(const osg::GraphicsContext*)
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
osg::GraphicsContext* fgOSGetMainContext()
|
||||
{
|
||||
return gw.get();
|
||||
}
|
||||
|
|
|
@ -84,18 +84,4 @@ void fgRegisterWindowResizeHandler(fgWindowResizeHandler func);
|
|||
void fgRegisterKeyHandler(fgKeyHandler func);
|
||||
void fgRegisterMouseClickHandler(fgMouseClickHandler func);
|
||||
void fgRegisterMouseMotionHandler(fgMouseMotionHandler func);
|
||||
|
||||
bool fgOSIsMainCamera(const osg::Camera* camera);
|
||||
bool fgOSIsMainContext(const osg::GraphicsContext* context);
|
||||
|
||||
/** Get graphics context of the main camera. This is the principal
|
||||
* window in multi-window configurations, or the only window in an
|
||||
* embedded configuration. The GUI will be added to this context.
|
||||
*/
|
||||
osg::GraphicsContext* fgOSGetMainContext();
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
#endif // _FG_OS_HXX
|
||||
|
|
|
@ -18,10 +18,6 @@
|
|||
// along with this program; if not, write to the Free Software
|
||||
// Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
|
||||
|
||||
#ifdef HAVE_CONFIG_H
|
||||
# include <config.h>
|
||||
#endif
|
||||
|
||||
#include <algorithm>
|
||||
#include <iostream>
|
||||
#include <sstream>
|
||||
|
@ -33,6 +29,7 @@
|
|||
#include <simgear/structure/exception.hxx>
|
||||
#include <simgear/debug/logstream.hxx>
|
||||
|
||||
#include <osg/Camera>
|
||||
#include <osg/GraphicsContext>
|
||||
#include <osg/Group>
|
||||
#include <osg/Matrixd>
|
||||
|
@ -50,6 +47,8 @@
|
|||
#include "util.hxx"
|
||||
#include "globals.hxx"
|
||||
#include "renderer.hxx"
|
||||
#include "CameraGroup.hxx"
|
||||
#include "WindowBuilder.hxx"
|
||||
#include "WindowSystemAdapter.hxx"
|
||||
|
||||
#if (FG_OSG_VERSION >= 19008)
|
||||
|
@ -67,113 +66,66 @@ using namespace std;
|
|||
using namespace flightgear;
|
||||
using namespace osg;
|
||||
|
||||
|
||||
|
||||
static osg::ref_ptr<osgViewer::Viewer> viewer;
|
||||
static osg::ref_ptr<osg::Camera> mainCamera;
|
||||
|
||||
// Callback to prevent the GraphicsContext resized function from messing
|
||||
// with the projection matrix of the slave
|
||||
|
||||
namespace
|
||||
{
|
||||
// silly function for making the default window and camera names
|
||||
std::string makeName(const string& prefix, int num)
|
||||
// If a camera group isn't specified, build one from the top-level
|
||||
// camera specs and then add a camera aligned with the master camera
|
||||
// if it doesn't seem to exist.
|
||||
CameraGroup* buildDefaultCameraGroup(osgViewer::Viewer* viewer,
|
||||
const SGPropertyNode* gnode)
|
||||
{
|
||||
std::stringstream stream;
|
||||
stream << prefix << num;
|
||||
return stream.str();
|
||||
}
|
||||
|
||||
GraphicsContext::Traits*
|
||||
makeDefaultTraits(GraphicsContext::WindowingSystemInterface* wsi, bool stencil)
|
||||
{
|
||||
int w = fgGetInt("/sim/startup/xsize");
|
||||
int h = fgGetInt("/sim/startup/ysize");
|
||||
int bpp = fgGetInt("/sim/rendering/bits-per-pixel");
|
||||
bool alpha = fgGetBool("/sim/rendering/clouds3d-enable");
|
||||
bool fullscreen = fgGetBool("/sim/startup/fullscreen");
|
||||
|
||||
GraphicsContext::Traits* traits = new osg::GraphicsContext::Traits;
|
||||
traits->readDISPLAY();
|
||||
int cbits = (bpp <= 16) ? 5 : 8;
|
||||
int zbits = (bpp <= 16) ? 16 : 24;
|
||||
traits->red = traits->green = traits->blue = cbits;
|
||||
traits->depth = zbits;
|
||||
if (alpha)
|
||||
traits->alpha = 8;
|
||||
if (stencil)
|
||||
traits->stencil = 8;
|
||||
traits->doubleBuffer = true;
|
||||
traits->mipMapGeneration = true;
|
||||
traits->windowName = "FlightGear";
|
||||
// XXX should check per window too.
|
||||
traits->sampleBuffers = fgGetBool("/sim/rendering/multi-sample-buffers", traits->sampleBuffers);
|
||||
traits->samples = fgGetBool("/sim/rendering/multi-samples", traits->samples);
|
||||
traits->vsync = fgGetBool("/sim/rendering/vsync-enable", traits->vsync);
|
||||
if (fullscreen) {
|
||||
unsigned width = 0;
|
||||
unsigned height = 0;
|
||||
wsi->getScreenResolution(*traits, width, height);
|
||||
traits->windowDecoration = false;
|
||||
traits->width = width;
|
||||
traits->height = height;
|
||||
traits->supportsResize = false;
|
||||
} else {
|
||||
traits->windowDecoration = true;
|
||||
traits->width = w;
|
||||
traits->height = h;
|
||||
#if defined(WIN32) || defined(__APPLE__)
|
||||
// Ugly Hack, why does CW_USEDEFAULT works like phase of the moon?
|
||||
// Mac also needs this to show window frame, menubar and Docks
|
||||
traits->x = 100;
|
||||
traits->y = 100;
|
||||
#endif
|
||||
traits->supportsResize = true;
|
||||
WindowSystemAdapter* wsa = WindowSystemAdapter::getWSA();
|
||||
CameraGroup* cgroup = CameraGroup::buildCameraGroup(viewer, gnode);
|
||||
// Look for a camera with no shear
|
||||
Camera* masterCamera = 0;
|
||||
for (CameraGroup::CameraIterator iter = cgroup->camerasBegin(),
|
||||
e = cgroup->camerasEnd();
|
||||
iter != e;
|
||||
++iter) {
|
||||
const View::Slave& slave = viewer->getSlave((*iter)->slaveIndex);
|
||||
if (slave._projectionOffset.isIdentity()) {
|
||||
masterCamera = (*iter)->camera.get();
|
||||
break;
|
||||
}
|
||||
}
|
||||
return traits;
|
||||
}
|
||||
|
||||
void setTraitsFromProperties(GraphicsContext::Traits* traits,
|
||||
const SGPropertyNode* winNode,
|
||||
GraphicsContext::WindowingSystemInterface* wsi)
|
||||
{
|
||||
traits->hostName
|
||||
= winNode->getStringValue("host-name", traits->hostName.c_str());
|
||||
traits->displayNum = winNode->getIntValue("display", traits->displayNum);
|
||||
traits->screenNum = winNode->getIntValue("screen", traits->screenNum);
|
||||
if (winNode->getBoolValue("fullscreen",
|
||||
fgGetBool("/sim/startup/fullscreen"))) {
|
||||
unsigned width = 0;
|
||||
unsigned height = 0;
|
||||
wsi->getScreenResolution(*traits, width, height);
|
||||
traits->windowDecoration = false;
|
||||
traits->width = width;
|
||||
traits->height = height;
|
||||
traits->supportsResize = false;
|
||||
} else {
|
||||
traits->windowDecoration = winNode->getBoolValue("decoration", true);
|
||||
traits->width = winNode->getIntValue("width", traits->width);
|
||||
traits->height = winNode->getIntValue("height", traits->height);
|
||||
traits->supportsResize = true;
|
||||
if (!masterCamera) {
|
||||
// No master camera found; better add one.
|
||||
GraphicsWindow* window
|
||||
= WindowBuilder::getWindowBuilder()->getDefaultWindow();
|
||||
masterCamera = new Camera();
|
||||
masterCamera->setGraphicsContext(window->gc.get());
|
||||
const GraphicsContext::Traits *traits = window->gc->getTraits();
|
||||
masterCamera->setViewport(new Viewport(0, 0,
|
||||
traits->width, traits->height));
|
||||
cgroup->addCamera(CameraGroup::DO_INTERSECTION_TEST, masterCamera,
|
||||
Matrix(), Matrix());
|
||||
}
|
||||
traits->x = winNode->getIntValue("x", traits->x);
|
||||
traits->y = winNode->getIntValue("y", traits->y);
|
||||
if (winNode->hasChild("window-name"))
|
||||
traits->windowName = winNode->getStringValue("window-name");
|
||||
else if (winNode->hasChild("name"))
|
||||
traits->windowName = winNode->getStringValue("name");
|
||||
// Find window on which the GUI is drawn.
|
||||
WindowVector::iterator iter = wsa->windows.begin();
|
||||
WindowVector::iterator end = wsa->windows.end();
|
||||
for (; iter != end; ++iter) {
|
||||
if ((*iter)->gc.get() == masterCamera->getGraphicsContext())
|
||||
break;
|
||||
}
|
||||
if (iter != end) { // Better not happen
|
||||
(*iter)->flags |= GraphicsWindow::GUI;
|
||||
cgroup->buildGUICamera(0, iter->get());
|
||||
}
|
||||
return cgroup;
|
||||
}
|
||||
}
|
||||
|
||||
} //namespace
|
||||
|
||||
void fgOSOpenWindow(bool stencil)
|
||||
{
|
||||
osg::GraphicsContext::WindowingSystemInterface* wsi;
|
||||
wsi = osg::GraphicsContext::getWindowingSystemInterface();
|
||||
osg::GraphicsContext::WindowingSystemInterface* wsi
|
||||
= osg::GraphicsContext::getWindowingSystemInterface();
|
||||
|
||||
viewer = new osgViewer::Viewer;
|
||||
viewer->setDatabasePager(FGScenery::getPagerSingleton());
|
||||
CameraGroup* cameraGroup = 0;
|
||||
std::string mode;
|
||||
mode = fgGetString("/sim/rendering/multithreading-mode", "SingleThreaded");
|
||||
if (mode == "AutomaticSelection")
|
||||
|
@ -186,111 +138,32 @@ void fgOSOpenWindow(bool stencil)
|
|||
viewer->setThreadingModel(osgViewer::Viewer::CullThreadPerCameraDrawThreadPerContext);
|
||||
else
|
||||
viewer->setThreadingModel(osgViewer::Viewer::SingleThreaded);
|
||||
osg::ref_ptr<osg::GraphicsContext::Traits> traits
|
||||
= makeDefaultTraits(wsi, stencil);
|
||||
WindowBuilder::initWindowBuilder(stencil);
|
||||
WindowBuilder *windowBuilder = WindowBuilder::getWindowBuilder();
|
||||
|
||||
// Ok, first the children.
|
||||
// that achieves some magic ordering og the slaves so that we end up
|
||||
// in the main window more often.
|
||||
// This can be sorted out better when we got rid of glut and sdl.
|
||||
FGManipulator* manipulator = globals->get_renderer()->getManipulator();
|
||||
string defaultName("slave");
|
||||
WindowSystemAdapter* wsa = WindowSystemAdapter::getWSA();
|
||||
if (fgHasNode("/sim/rendering/camera")) {
|
||||
SGPropertyNode* renderingNode = fgGetNode("/sim/rendering");
|
||||
for (int i = 0; i < renderingNode->nChildren(); ++i) {
|
||||
SGPropertyNode* cameraNode = renderingNode->getChild(i);
|
||||
if (strcmp(cameraNode->getName(), "camera") != 0)
|
||||
continue;
|
||||
|
||||
// get a new copy of the traits struct
|
||||
osg::ref_ptr<osg::GraphicsContext::Traits> cameraTraits;
|
||||
cameraTraits = new osg::GraphicsContext::Traits(*traits);
|
||||
double shearx = cameraNode->getDoubleValue("shear-x", 0);
|
||||
double sheary = cameraNode->getDoubleValue("shear-y", 0);
|
||||
double heading = cameraNode->getDoubleValue("heading-deg", 0);
|
||||
setTraitsFromProperties(cameraTraits.get(), cameraNode, wsi);
|
||||
// FIXME, currently this is too much of a problem to route
|
||||
// the resize events. When we do no longer need sdl and
|
||||
// such this can be simplified
|
||||
cameraTraits->supportsResize = false;
|
||||
|
||||
// ok found a camera configuration, add a new slave if possible
|
||||
GraphicsContext* gc
|
||||
= GraphicsContext::createGraphicsContext(cameraTraits.get());
|
||||
if (gc) {
|
||||
gc->realize();
|
||||
Camera *camera = new Camera;
|
||||
camera->setGraphicsContext(gc);
|
||||
// If a viewport isn't set on the camera, then it's
|
||||
// hard to dig it out of the SceneView objects in the
|
||||
// viewer, and the coordinates of mouse events are
|
||||
// somewhat bizzare.
|
||||
camera->setViewport(new Viewport(0, 0, cameraTraits->width,
|
||||
cameraTraits->height));
|
||||
const char* cameraName = cameraNode->getStringValue("name");
|
||||
string cameraNameString = (cameraName ? string(cameraName)
|
||||
: makeName(defaultName, i));
|
||||
GraphicsWindow* window = wsa->registerWindow(gc,
|
||||
cameraNameString);
|
||||
Camera3D* cam3D = wsa->registerCamera3D(window, camera,
|
||||
cameraNameString);
|
||||
if (shearx == 0 && sheary == 0)
|
||||
cam3D->flags |= Camera3D::MASTER;
|
||||
|
||||
osg::Matrix pOff = osg::Matrix::translate(-shearx, -sheary, 0);
|
||||
osg::Matrix vOff;
|
||||
vOff.makeRotate(SGMiscd::deg2rad(heading), osg::Vec3(0, 1, 0));
|
||||
viewer->addSlave(camera, pOff, vOff);
|
||||
} else {
|
||||
SG_LOG(SG_GENERAL, SG_WARN,
|
||||
"Couldn't create graphics context on "
|
||||
<< cameraTraits->hostName << ":"
|
||||
<< cameraTraits->displayNum
|
||||
<< "." << cameraTraits->screenNum);
|
||||
}
|
||||
// Look for windows, camera groups, and the old syntax of
|
||||
// top-level cameras
|
||||
const SGPropertyNode* renderingNode = fgGetNode("/sim/rendering");
|
||||
for (int i = 0; i < renderingNode->nChildren(); ++i) {
|
||||
const SGPropertyNode* propNode = renderingNode->getChild(i);
|
||||
const char* propName = propNode->getName();
|
||||
if (!strcmp(propName, "window")) {
|
||||
windowBuilder->buildWindow(propNode);
|
||||
} else if (!strcmp(propName, "camera-group")) {
|
||||
cameraGroup = CameraGroup::buildCameraGroup(viewer.get(), propNode);
|
||||
}
|
||||
}
|
||||
// now the main camera ...
|
||||
// XXX mainCamera's purpose is to establish a "main graphics
|
||||
// context" that can be made current (if necessary). But that
|
||||
// should be a context established with a window. It's used to
|
||||
// choose whether to render the GUI and panel camera nodes, but
|
||||
// that's obsolete because the GUI is rendered in its own
|
||||
// slave. And it's used to translate mouse event coordinates, but
|
||||
// that's bogus because mouse clicks should work on any camera. In
|
||||
// short, mainCamera must die :)
|
||||
Camera3DVector::iterator citr
|
||||
= find_if(wsa->cameras.begin(), wsa->cameras.end(),
|
||||
WindowSystemAdapter::FlagTester<Camera3D>(Camera3D::MASTER));
|
||||
if (citr == wsa->cameras.end()) {
|
||||
// Create a camera aligned with the master camera. Eventually
|
||||
// this will be optional.
|
||||
Camera* camera = new osg::Camera;
|
||||
mainCamera = camera;
|
||||
osg::GraphicsContext* gc
|
||||
= osg::GraphicsContext::createGraphicsContext(traits.get());
|
||||
gc->realize();
|
||||
gc->makeCurrent();
|
||||
camera->setGraphicsContext(gc);
|
||||
// If a viewport isn't set on the camera, then it's hard to dig it
|
||||
// out of the SceneView objects in the viewer, and the coordinates
|
||||
// of mouse events are somewhat bizzare.
|
||||
camera->setViewport(new osg::Viewport(0, 0,
|
||||
traits->width, traits->height));
|
||||
GraphicsWindow* window = wsa->registerWindow(gc, string("main"));
|
||||
window->flags |= GraphicsWindow::GUI;
|
||||
Camera3D* camera3d = wsa->registerCamera3D(window, camera,
|
||||
string("main"));
|
||||
camera3d->flags |= Camera3D::MASTER;
|
||||
// Why a slave? It seems to be the easiest way to assign cameras,
|
||||
// for which we've created the graphics context ourselves, to
|
||||
// the viewer.
|
||||
viewer->addSlave(camera);
|
||||
} else {
|
||||
mainCamera = (*citr)->camera;
|
||||
if (!cameraGroup)
|
||||
cameraGroup = buildDefaultCameraGroup(viewer.get(), renderingNode);
|
||||
Camera* guiCamera = getGUICamera(cameraGroup);
|
||||
if (guiCamera) {
|
||||
Viewport* guiViewport = guiCamera->getViewport();
|
||||
fgSetInt("/sim/startup/xsize", guiViewport->width());
|
||||
fgSetInt("/sim/startup/ysize", guiViewport->height());
|
||||
}
|
||||
if (wsa->cameras.size() != 1) {
|
||||
FGManipulator* manipulator = globals->get_renderer()->getManipulator();
|
||||
WindowSystemAdapter* wsa = WindowSystemAdapter::getWSA();
|
||||
if (wsa->windows.size() != 1) {
|
||||
manipulator->setResizable(false);
|
||||
}
|
||||
viewer->getCamera()->setProjectionResizePolicy(osg::Camera::FIXED);
|
||||
|
@ -300,6 +173,7 @@ void fgOSOpenWindow(bool stencil)
|
|||
// The viewer won't start without some root.
|
||||
viewer->setSceneData(new osg::Group);
|
||||
globals->get_renderer()->setViewer(viewer.get());
|
||||
CameraGroup::setDefault(cameraGroup);
|
||||
}
|
||||
|
||||
static int status = 0;
|
||||
|
@ -324,17 +198,7 @@ int fgGetKeyModifiers()
|
|||
|
||||
void fgWarpMouse(int x, int y)
|
||||
{
|
||||
globals->get_renderer()->getManipulator()->setMouseWarped();
|
||||
// Hack, currently the pointer is just recentered. So, we know the
|
||||
// relative coordinates ...
|
||||
if (!mainCamera.valid()) {
|
||||
viewer->requestWarpPointer(0, 0);
|
||||
return;
|
||||
}
|
||||
float xsize = (float)mainCamera->getGraphicsContext()->getTraits()->width;
|
||||
float ysize = (float)mainCamera->getGraphicsContext()->getTraits()->height;
|
||||
viewer->requestWarpPointer(2.0f * (float)x / xsize - 1.0f,
|
||||
1.0f - 2.0f * (float)y / ysize);
|
||||
warpGUIPointer(CameraGroup::getDefault(), x, y);
|
||||
}
|
||||
|
||||
void fgOSInit(int* argc, char** argv)
|
||||
|
@ -393,36 +257,3 @@ int fgGetMouseCursor()
|
|||
{
|
||||
return _cursor;
|
||||
}
|
||||
|
||||
bool fgOSIsMainContext(const osg::GraphicsContext* context)
|
||||
{
|
||||
if (!mainCamera.valid())
|
||||
return false;
|
||||
return context == mainCamera->getGraphicsContext();
|
||||
}
|
||||
|
||||
bool fgOSIsMainCamera(const osg::Camera* camera)
|
||||
{
|
||||
if (!camera)
|
||||
return false;
|
||||
if (camera == mainCamera.get())
|
||||
return true;
|
||||
if (!viewer.valid())
|
||||
return false;
|
||||
if (camera == viewer->getCamera())
|
||||
return true;
|
||||
return false;
|
||||
}
|
||||
|
||||
GraphicsContext* fgOSGetMainContext()
|
||||
{
|
||||
WindowSystemAdapter* wsa = WindowSystemAdapter::getWSA();
|
||||
WindowVector::iterator contextIter
|
||||
= std::find_if(wsa->windows.begin(), wsa->windows.end(),
|
||||
WindowSystemAdapter::FlagTester<GraphicsWindow>(GraphicsWindow::GUI));
|
||||
if (contextIter == wsa->windows.end())
|
||||
return 0;
|
||||
else
|
||||
return (*contextIter)->gc.get();
|
||||
}
|
||||
|
||||
|
|
|
@ -14,6 +14,7 @@
|
|||
#include "globals.hxx"
|
||||
#include "renderer.hxx"
|
||||
#include "fg_props.hxx"
|
||||
#include "CameraGroup.hxx"
|
||||
#include "WindowSystemAdapter.hxx"
|
||||
|
||||
using namespace flightgear;
|
||||
|
@ -34,7 +35,6 @@ static int VidMask = SDL_OPENGL|SDL_RESIZABLE;
|
|||
static void initCursors();
|
||||
|
||||
static osg::ref_ptr<osgViewer::Viewer> viewer;
|
||||
static osg::ref_ptr<osg::Camera> mainCamera;
|
||||
static osg::ref_ptr<osgViewer::GraphicsWindowEmbedded> gw;
|
||||
|
||||
void fgOSOpenWindow(bool stencil)
|
||||
|
@ -96,16 +96,17 @@ void fgOSOpenWindow(bool stencil)
|
|||
window->flags |= GraphicsWindow::GUI;
|
||||
// now the main camera ...
|
||||
osg::Camera* camera = new osg::Camera;
|
||||
mainCamera = camera;
|
||||
// If a viewport isn't set on the camera, then it's hard to dig it
|
||||
// out of the SceneView objects in the viewer, and the coordinates
|
||||
// of mouse events are somewhat bizzare.
|
||||
camera->setViewport(new osg::Viewport(0, 0, realw, realh));
|
||||
camera->setProjectionResizePolicy(osg::Camera::FIXED);
|
||||
Camera3D* cam3D = wsa->registerCamera3D(window, camera, string("main"));
|
||||
cam3D->flags |= Camera3D::MASTER;
|
||||
// Add as a slave for compatibility with the non-embedded osgViewer.
|
||||
viewer->addSlave(camera);
|
||||
CameraGroup* cgroup = new CameraGroup(viewer.get());
|
||||
cgroup->addCamera(CameraGroup::DO_INTERSECTION_TEST, camera,
|
||||
osg::Matrixd::identity(), osg::Matrixd::identity(),
|
||||
true);
|
||||
cgroup->buildGUICamera(0, window);
|
||||
CameraGroup::setDefault(cgroup);
|
||||
viewer->setCameraManipulator(globals->get_renderer()->getManipulator());
|
||||
// Let FG handle the escape key with a confirmation
|
||||
viewer->setKeyEventSetsDone(0);
|
||||
|
@ -410,18 +411,3 @@ static void initCursors()
|
|||
cursors[i].hoty);
|
||||
}
|
||||
}
|
||||
|
||||
bool fgOSIsMainCamera(const osg::Camera*)
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
bool fgOSIsMainContext(const osg::GraphicsContext*)
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
osg::GraphicsContext* fgOSGetMainContext()
|
||||
{
|
||||
return gw.get();
|
||||
}
|
||||
|
|
|
@ -34,6 +34,8 @@
|
|||
|
||||
#include <plib/netSocket.h>
|
||||
|
||||
#include <osg/Camera>
|
||||
#include <osg/GraphicsContext>
|
||||
#include <osgDB/Registry>
|
||||
|
||||
// Class references
|
||||
|
@ -68,6 +70,7 @@
|
|||
#include <GUI/new_gui.hxx>
|
||||
#include <MultiPlayer/multiplaymgr.hxx>
|
||||
|
||||
#include "CameraGroup.hxx"
|
||||
#include "fg_commands.hxx"
|
||||
#include "fg_io.hxx"
|
||||
#include "renderer.hxx"
|
||||
|
@ -75,11 +78,15 @@
|
|||
#include "main.hxx"
|
||||
#include "util.hxx"
|
||||
#include "fg_init.hxx"
|
||||
#include "WindowSystemAdapter.hxx"
|
||||
|
||||
|
||||
static double real_delta_time_sec = 0.0;
|
||||
double delta_time_sec = 0.0;
|
||||
extern float init_volume;
|
||||
|
||||
using namespace flightgear;
|
||||
|
||||
// This is a record containing a bit of global housekeeping information
|
||||
FGGeneral general;
|
||||
|
||||
|
@ -650,21 +657,18 @@ static void fgMainLoop( void ) {
|
|||
SG_LOG( SG_ALL, SG_DEBUG, "" );
|
||||
}
|
||||
|
||||
|
||||
// This is the top level master main function that is registered as
|
||||
// our idle funciton
|
||||
|
||||
// The first few passes take care of initialization things (a couple
|
||||
// per pass) and once everything has been initialized fgMainLoop from
|
||||
// then on.
|
||||
|
||||
static void fgIdleFunction ( void ) {
|
||||
if ( idle_state == 0 ) {
|
||||
idle_state++;
|
||||
|
||||
// This seems to be the absolute earliest in the init sequence
|
||||
// that these calls will return valid info. Too bad it's after
|
||||
// we've already created and sized our window. :-(
|
||||
// Operation for querying OpenGL parameters. This must be done in a
|
||||
// valid OpenGL context, potentially in another thread.
|
||||
namespace
|
||||
{
|
||||
struct GeneralInitOperation : public GraphicsContextOperation
|
||||
{
|
||||
GeneralInitOperation()
|
||||
: GraphicsContextOperation(std::string("General init"))
|
||||
{
|
||||
}
|
||||
void run(osg::GraphicsContext* gc)
|
||||
{
|
||||
general.set_glVendor( (char *)glGetString ( GL_VENDOR ) );
|
||||
general.set_glRenderer( (char *)glGetString ( GL_RENDERER ) );
|
||||
general.set_glVersion( (char *)glGetString ( GL_VERSION ) );
|
||||
|
@ -678,12 +682,42 @@ static void fgIdleFunction ( void ) {
|
|||
glGetIntegerv( GL_DEPTH_BITS, &tmp );
|
||||
general.set_glDepthBits( tmp );
|
||||
SG_LOG ( SG_GENERAL, SG_INFO, "Depth buffer bits = " << tmp );
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
// Initialize the user interface so that we can use fonts
|
||||
guiStartInit();
|
||||
// This is the top level master main function that is registered as
|
||||
// our idle funciton
|
||||
|
||||
// The first few passes take care of initialization things (a couple
|
||||
// per pass) and once everything has been initialized fgMainLoop from
|
||||
// then on.
|
||||
|
||||
static void fgIdleFunction ( void ) {
|
||||
static osg::ref_ptr<GeneralInitOperation> genOp;
|
||||
if ( idle_state == 0 ) {
|
||||
idle_state++;
|
||||
// Pick some window on which to do queries.
|
||||
// XXX Perhaps all this graphics initialization code should be
|
||||
// moved to renderer.cxx?
|
||||
genOp = new GeneralInitOperation;
|
||||
osg::Camera* guiCamera = getGUICamera(CameraGroup::getDefault());
|
||||
WindowSystemAdapter* wsa = WindowSystemAdapter::getWSA();
|
||||
osg::GraphicsContext* gc = 0;
|
||||
if (guiCamera)
|
||||
gc = guiCamera->getGraphicsContext();
|
||||
if (gc) {
|
||||
gc->add(genOp.get());
|
||||
} else {
|
||||
wsa->windows[0]->gc->add(genOp.get());
|
||||
}
|
||||
guiStartInit(gc);
|
||||
} else if ( idle_state == 1 ) {
|
||||
if (genOp.valid()) {
|
||||
if (!genOp->isFinished())
|
||||
return;
|
||||
genOp = 0;
|
||||
}
|
||||
if (!guiFinishInit())
|
||||
return;
|
||||
idle_state++;
|
||||
|
|
|
@ -1227,12 +1227,12 @@ where:
|
|||
|
||||
enum OptionType { OPTION_BOOL, OPTION_STRING, OPTION_DOUBLE, OPTION_INT, OPTION_CHANNEL, OPTION_FUNC };
|
||||
struct OptionDesc {
|
||||
char *option;
|
||||
const char *option;
|
||||
bool has_param;
|
||||
enum OptionType type;
|
||||
char *property;
|
||||
const char *property;
|
||||
bool b_param;
|
||||
char *s_param;
|
||||
const char *s_param;
|
||||
int (*func)( const char * );
|
||||
} fgOptionArray[] = {
|
||||
|
||||
|
|
|
@ -37,6 +37,7 @@
|
|||
#include <osg/Light>
|
||||
#include <osg/LightModel>
|
||||
#include <osg/LightSource>
|
||||
#include <osg/Material>
|
||||
#include <osg/NodeCallback>
|
||||
#include <osg/Notify>
|
||||
#include <osg/PolygonMode>
|
||||
|
@ -60,6 +61,7 @@
|
|||
#include <simgear/scene/material/matlib.hxx>
|
||||
#include <simgear/scene/model/animation.hxx>
|
||||
#include <simgear/scene/model/placement.hxx>
|
||||
#include <simgear/scene/sky/sky.hxx>
|
||||
#include <simgear/scene/util/SGUpdateVisitor.hxx>
|
||||
#include <simgear/scene/util/RenderConstants.hxx>
|
||||
#include <simgear/scene/tgdb/GroundLightManager.hxx>
|
||||
|
@ -95,6 +97,7 @@
|
|||
#include "splash.hxx"
|
||||
#include "renderer.hxx"
|
||||
#include "main.hxx"
|
||||
#include "CameraGroup.hxx"
|
||||
#include "ViewPartitionNode.hxx"
|
||||
|
||||
// XXX Make this go away when OSG 2.2 is released.
|
||||
|
@ -102,6 +105,8 @@
|
|||
#define UPDATE_VISITOR_IN_VIEWER 1
|
||||
#endif
|
||||
|
||||
using namespace flightgear;
|
||||
|
||||
class FGHintUpdateCallback : public osg::StateAttribute::Callback {
|
||||
public:
|
||||
FGHintUpdateCallback(const char* configNode) :
|
||||
|
@ -153,8 +158,6 @@ public:
|
|||
{ drawImplementation(*renderInfo.getState()); }
|
||||
void drawImplementation(osg::State& state) const
|
||||
{
|
||||
if (!fgOSIsMainContext(state.getGraphicsContext()))
|
||||
return;
|
||||
state.setActiveTextureUnit(0);
|
||||
state.setClientActiveTextureUnit(0);
|
||||
|
||||
|
@ -198,8 +201,6 @@ public:
|
|||
{ drawImplementation(*renderInfo.getState()); }
|
||||
void drawImplementation(osg::State& state) const
|
||||
{
|
||||
if (!fgOSIsMainContext(state.getGraphicsContext()))
|
||||
return;
|
||||
state.setActiveTextureUnit(0);
|
||||
state.setClientActiveTextureUnit(0);
|
||||
state.disableAllVertexArrays();
|
||||
|
@ -406,38 +407,6 @@ FGRenderer::splashinit( void ) {
|
|||
#endif
|
||||
}
|
||||
|
||||
namespace
|
||||
{
|
||||
// Create a slave camera that will be used to render a fixed GUI-like
|
||||
// element.
|
||||
osg::Camera*
|
||||
makeSlaveCamera(osg::Camera::RenderOrder renderOrder, int orderNum)
|
||||
{
|
||||
using namespace osg;
|
||||
Camera* camera = new osg::Camera;
|
||||
GraphicsContext *gc = fgOSGetMainContext();
|
||||
|
||||
camera->setRenderOrder(renderOrder, orderNum);
|
||||
camera->setClearMask(0);
|
||||
camera->setInheritanceMask(CullSettings::ALL_VARIABLES
|
||||
& ~(CullSettings::COMPUTE_NEAR_FAR_MODE
|
||||
| CullSettings::CULLING_MODE));
|
||||
camera->setComputeNearFarMode(osg::CullSettings::DO_NOT_COMPUTE_NEAR_FAR);
|
||||
camera->setCullingMode(osg::CullSettings::NO_CULLING);
|
||||
camera->setGraphicsContext(gc);
|
||||
// Establish an initial viewport. This may be altered,
|
||||
// particularly when drawing a 2d panel.
|
||||
const GraphicsContext::Traits *traits = gc->getTraits();
|
||||
camera->setViewport(new Viewport(0, 0, traits->width, traits->height));
|
||||
camera->setProjectionResizePolicy(Camera::FIXED);
|
||||
camera->setReferenceFrame(Transform::ABSOLUTE_RF);
|
||||
camera->setAllowEventFocus(false);
|
||||
globals->get_renderer()->getViewer()->addSlave(camera, false);
|
||||
return camera;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
void
|
||||
FGRenderer::init( void )
|
||||
{
|
||||
|
@ -541,13 +510,13 @@ FGRenderer::init( void )
|
|||
stateSet->setUpdateCallback(new FGFogEnableUpdateCallback);
|
||||
|
||||
// plug in the GUI
|
||||
osg::Camera* guiCamera = makeSlaveCamera(osg::Camera::POST_RENDER, 100);
|
||||
guiCamera->setName("GUI");
|
||||
osg::Geode* geode = new osg::Geode;
|
||||
geode->addDrawable(new SGPuDrawable);
|
||||
geode->addDrawable(new SGHUDAndPanelDrawable);
|
||||
guiCamera->addChild(geode);
|
||||
|
||||
osg::Camera* guiCamera = getGUICamera(CameraGroup::getDefault());
|
||||
if (guiCamera) {
|
||||
osg::Geode* geode = new osg::Geode;
|
||||
geode->addDrawable(new SGPuDrawable);
|
||||
geode->addDrawable(new SGHUDAndPanelDrawable);
|
||||
guiCamera->addChild(geode);
|
||||
}
|
||||
osg::Switch* sw = new osg::Switch;
|
||||
sw->setUpdateCallback(new FGScenerySwitchCallback);
|
||||
sw->addChild(mRoot.get());
|
||||
|
@ -612,14 +581,14 @@ FGRenderer::update( bool refresh_camera_settings ) {
|
|||
// update view port
|
||||
resize( fgGetInt("/sim/startup/xsize"),
|
||||
fgGetInt("/sim/startup/ysize") );
|
||||
|
||||
#if 0
|
||||
SGVec3d position = current__view->getViewPosition();
|
||||
SGQuatd attitude = current__view->getViewOrientation();
|
||||
SGVec3d osgPosition = attitude.transform(-position);
|
||||
|
||||
FGManipulator *manipulator = globals->get_renderer()->getManipulator();
|
||||
manipulator->setPosition(position.osg());
|
||||
manipulator->setAttitude(attitude.osg());
|
||||
#endif
|
||||
}
|
||||
osg::Camera *camera = viewer->getCamera();
|
||||
|
||||
|
@ -743,7 +712,7 @@ FGRenderer::update( bool refresh_camera_settings ) {
|
|||
}
|
||||
|
||||
// sgEnviro.setLight(l->adj_fog_color());
|
||||
|
||||
#if 0
|
||||
double agl = current__view->getAltitudeASL_ft()*SG_FEET_TO_METER
|
||||
- current__view->getSGLocation()->get_cur_elev_m();
|
||||
|
||||
|
@ -761,7 +730,7 @@ FGRenderer::update( bool refresh_camera_settings ) {
|
|||
setCameraParameters(current__view->get_v_fov(),
|
||||
current__view->get_aspect_ratio(),
|
||||
scene_nearplane, scene_farplane);
|
||||
|
||||
#endif
|
||||
// sgEnviro.startOfFrame(current__view->get_view_pos(),
|
||||
// current__view->get_world_up(),
|
||||
// current__view->getLongitude_deg(),
|
||||
|
@ -850,44 +819,40 @@ void FGRenderer::setCameraParameters(float vfov, float aspectRatio,
|
|||
|
||||
}
|
||||
bool
|
||||
FGRenderer::pick( unsigned x, unsigned y,
|
||||
std::vector<SGSceneryPick>& pickList,
|
||||
const osgGA::GUIEventAdapter* ea )
|
||||
FGRenderer::pick(std::vector<SGSceneryPick>& pickList,
|
||||
const osgGA::GUIEventAdapter* ea)
|
||||
{
|
||||
osgViewer::Viewer* viewer = globals->get_renderer()->getViewer();
|
||||
// wipe out the return ...
|
||||
pickList.resize(0);
|
||||
|
||||
if (viewer) {
|
||||
// just compute intersections in the viewers method ...
|
||||
osgViewer::Viewer* viewer = globals->get_renderer()->getViewer();
|
||||
// wipe out the return ...
|
||||
pickList.clear();
|
||||
typedef osgUtil::LineSegmentIntersector::Intersections Intersections;
|
||||
Intersections intersections;
|
||||
viewer->computeIntersections(ea->getX(), ea->getY(), intersections);
|
||||
|
||||
Intersections::iterator hit;
|
||||
for (hit = intersections.begin(); hit != intersections.end(); ++hit) {
|
||||
const osg::NodePath& np = hit->nodePath;
|
||||
osg::NodePath::const_reverse_iterator npi;
|
||||
for (npi = np.rbegin(); npi != np.rend(); ++npi) {
|
||||
SGSceneUserData* ud = SGSceneUserData::getSceneUserData(*npi);
|
||||
if (!ud)
|
||||
continue;
|
||||
for (unsigned i = 0; i < ud->getNumPickCallbacks(); ++i) {
|
||||
SGPickCallback* pickCallback = ud->getPickCallback(i);
|
||||
if (!pickCallback)
|
||||
continue;
|
||||
SGSceneryPick sceneryPick;
|
||||
sceneryPick.info.local = SGVec3d(hit->getLocalIntersectPoint());
|
||||
sceneryPick.info.wgs84 = SGVec3d(hit->getWorldIntersectPoint());
|
||||
sceneryPick.callback = pickCallback;
|
||||
pickList.push_back(sceneryPick);
|
||||
if (!computeIntersections(CameraGroup::getDefault(), ea, intersections))
|
||||
return false;
|
||||
for (Intersections::iterator hit = intersections.begin(),
|
||||
e = intersections.end();
|
||||
hit != e;
|
||||
++hit) {
|
||||
const osg::NodePath& np = hit->nodePath;
|
||||
osg::NodePath::const_reverse_iterator npi;
|
||||
for (npi = np.rbegin(); npi != np.rend(); ++npi) {
|
||||
SGSceneUserData* ud = SGSceneUserData::getSceneUserData(*npi);
|
||||
if (!ud)
|
||||
continue;
|
||||
for (unsigned i = 0; i < ud->getNumPickCallbacks(); ++i) {
|
||||
SGPickCallback* pickCallback = ud->getPickCallback(i);
|
||||
if (!pickCallback)
|
||||
continue;
|
||||
SGSceneryPick sceneryPick;
|
||||
sceneryPick.info.local = SGVec3d(hit->getLocalIntersectPoint());
|
||||
sceneryPick.info.wgs84 = SGVec3d(hit->getWorldIntersectPoint());
|
||||
sceneryPick.callback = pickCallback;
|
||||
pickList.push_back(sceneryPick);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
return !pickList.empty();
|
||||
} else { // we can get called early ...
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
|
|
|
@ -3,7 +3,6 @@
|
|||
#define __FG_RENDERER_HXX 1
|
||||
|
||||
#include <simgear/screen/extensions.hxx>
|
||||
#include <simgear/scene/sky/sky.hxx>
|
||||
#include <simgear/scene/util/SGPickCallback.hxx>
|
||||
|
||||
#include <osg/Camera>
|
||||
|
@ -46,8 +45,7 @@ public:
|
|||
float zNear, float zFar);
|
||||
/** Just pick into the scene and return the pick callbacks on the way ...
|
||||
*/
|
||||
static bool pick( unsigned x, unsigned y,
|
||||
std::vector<SGSceneryPick>& pickList,
|
||||
static bool pick( std::vector<SGSceneryPick>& pickList,
|
||||
const osgGA::GUIEventAdapter* ea );
|
||||
|
||||
/** Get and set the OSG Viewer object, if any.
|
||||
|
@ -57,9 +55,9 @@ public:
|
|||
void setViewer(osgViewer::Viewer* viewer) { this->viewer = viewer; }
|
||||
/** Get and set the manipulator object, if any.
|
||||
*/
|
||||
FGManipulator* getManipulator() { return manipulator.get(); }
|
||||
const FGManipulator* getManipulator() const { return manipulator.get(); }
|
||||
void setManipulator(FGManipulator* manipulator) {
|
||||
flightgear::FGManipulator* getManipulator() { return manipulator.get(); }
|
||||
const flightgear::FGManipulator* getManipulator() const { return manipulator.get(); }
|
||||
void setManipulator(flightgear::FGManipulator* manipulator) {
|
||||
this->manipulator = manipulator;
|
||||
}
|
||||
|
||||
|
@ -69,7 +67,7 @@ public:
|
|||
|
||||
protected:
|
||||
osg::ref_ptr<osgViewer::Viewer> viewer;
|
||||
osg::ref_ptr<FGManipulator> manipulator;
|
||||
osg::ref_ptr<flightgear::FGManipulator> manipulator;
|
||||
};
|
||||
|
||||
bool fgDumpSceneGraphToFile(const char* filename);
|
||||
|
|
|
@ -50,6 +50,9 @@
|
|||
|
||||
#include "viewer.hxx"
|
||||
|
||||
#include "CameraGroup.hxx"
|
||||
|
||||
using namespace flightgear;
|
||||
|
||||
////////////////////////////////////////////////////////////////////////
|
||||
// Implementation of FGViewer.
|
||||
|
@ -81,7 +84,8 @@ FGViewer::FGViewer( fgViewType Type, bool from_model, int from_model_index,
|
|||
_damp_heading(0),
|
||||
_scaling_type(FG_SCALING_MAX),
|
||||
_location(0),
|
||||
_target_location(0)
|
||||
_target_location(0),
|
||||
_cameraGroup(CameraGroup::getDefault())
|
||||
{
|
||||
_absolute_view_pos = SGVec3d(0, 0, 0);
|
||||
_type = Type;
|
||||
|
@ -764,5 +768,7 @@ FGViewer::update (double dt)
|
|||
}
|
||||
}
|
||||
}
|
||||
|
||||
recalc();
|
||||
_cameraGroup->update(_absolute_view_pos.osg(), mViewOrientation.osg());
|
||||
_cameraGroup->setCameraParameters(get_v_fov(), get_aspect_ratio());
|
||||
}
|
||||
|
|
|
@ -32,6 +32,13 @@
|
|||
# error This library requires C++
|
||||
#endif
|
||||
|
||||
namespace flightgear
|
||||
{
|
||||
class CameraGroup;
|
||||
}
|
||||
|
||||
#include <osg/ref_ptr>
|
||||
|
||||
#include <simgear/compiler.h>
|
||||
#include <simgear/constants.h>
|
||||
#include <simgear/structure/subsystem_mgr.hxx>
|
||||
|
@ -361,6 +368,8 @@ private:
|
|||
// surface at the spot we are directly above
|
||||
SGVec3f _world_up;
|
||||
|
||||
// camera group controled by this view
|
||||
osg::ref_ptr<flightgear::CameraGroup> _cameraGroup;
|
||||
//////////////////////////////////////////////////////////////////
|
||||
// private functions //
|
||||
//////////////////////////////////////////////////////////////////
|
||||
|
|
|
@ -33,7 +33,11 @@
|
|||
#include <simgear/scene/tgdb/TileCache.hxx>
|
||||
|
||||
class SGReaderWriterBTGOptions;
|
||||
class osg::Node;
|
||||
|
||||
namespace osg
|
||||
{
|
||||
class Node;
|
||||
}
|
||||
|
||||
class FGTileMgr : public simgear::ModelLoadHelper {
|
||||
|
||||
|
|
Loading…
Reference in a new issue