+// fg_os_osgviewer.cxx -- common functions for fg_os interface
+// implemented as an osgViewer
+//
+// Copyright (C) 2007 Tim Moore timoore@redhat.com
+// Copyright (C) 2007 Mathias Froehlich
+//
+// This program is free software; you can redistribute it and/or
+// modify it under the terms of the GNU General Public License as
+// published by the Free Software Foundation; either version 2 of the
+// License, or (at your option) any later version.
+//
+// This program is distributed in the hope that it will be useful, but
+// WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+// General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License
+// along with this program; if not, write to the Free Software
+// Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+
+#include <algorithm>
+#include <iostream>
+#include <sstream>
+#include <string>
+
#include <stdlib.h>
+#include <boost/foreach.hpp>
+
#include <simgear/compiler.h>
#include <simgear/structure/exception.hxx>
#include <simgear/debug/logstream.hxx>
+#include <simgear/props/props_io.hxx>
+#include <osg/Camera>
#include <osg/GraphicsContext>
#include <osg/Group>
#include <osg/Matrixd>
#include <osg/Viewport>
-#include <osgViewer/StatsHandler>
+#include <osg/Version>
+#include <osg/View>
+#include <osgViewer/ViewerEventHandlers>
#include <osgViewer/Viewer>
-#include <osgGA/MatrixManipulator>
+#include <osgViewer/GraphicsWindow>
+#include <Scenery/scenery.hxx>
#include "fg_os.hxx"
#include "fg_props.hxx"
#include "util.hxx"
#include "globals.hxx"
#include "renderer.hxx"
+#include "CameraGroup.hxx"
+#include "FGEventHandler.hxx"
+#include "WindowBuilder.hxx"
+#include "WindowSystemAdapter.hxx"
+
+// Static linking of OSG needs special macros
+#ifdef OSG_LIBRARY_STATIC
+#include <osgDB/Registry>
+USE_GRAPHICSWINDOW();
+// Image formats
+USE_OSGPLUGIN(bmp);
+USE_OSGPLUGIN(dds);
+USE_OSGPLUGIN(hdr);
+USE_OSGPLUGIN(pic);
+USE_OSGPLUGIN(pnm);
+USE_OSGPLUGIN(rgb);
+USE_OSGPLUGIN(tga);
+#ifdef OSG_JPEG_ENABLED
+ USE_OSGPLUGIN(jpeg);
+#endif
+#ifdef OSG_PNG_ENABLED
+ USE_OSGPLUGIN(png);
+#endif
+#ifdef OSG_TIFF_ENABLED
+ USE_OSGPLUGIN(tiff);
+#endif
+// Model formats
+USE_OSGPLUGIN(3ds);
+USE_OSGPLUGIN(ac);
+USE_OSGPLUGIN(ive);
+USE_OSGPLUGIN(osg);
+USE_OSGPLUGIN(txf);
+#endif
// fg_os implementation using OpenSceneGraph's osgViewer::Viewer class
// to create the graphics window and run the event/update/render loop.
+
//
-// fg_os callback registration APIs
+// fg_os implementation
//
+using namespace std;
+using namespace flightgear;
+using namespace osg;
-// Event handling and scene graph update is all handled by a
-// manipulator. See FGManipulator.cpp
-void fgRegisterIdleHandler(fgIdleHandler func)
-{
- globals->get_renderer()->getManipulator()->setIdleHandler(func);
-}
-
-void fgRegisterDrawHandler(fgDrawHandler func)
-{
- globals->get_renderer()->getManipulator()->setDrawHandler(func);
-}
-
-void fgRegisterWindowResizeHandler(fgWindowResizeHandler func)
-{
- globals->get_renderer()->getManipulator()->setWindowResizeHandler(func);
-}
+static osg::ref_ptr<osgViewer::Viewer> viewer;
+static osg::ref_ptr<osg::Camera> mainCamera;
-void fgRegisterKeyHandler(fgKeyHandler func)
+static void setStereoMode( const char * mode )
{
- globals->get_renderer()->getManipulator()->setKeyHandler(func);
-}
+ DisplaySettings::StereoMode stereoMode = DisplaySettings::QUAD_BUFFER;
+ bool stereoOn = true;
-void fgRegisterMouseClickHandler(fgMouseClickHandler func)
-{
- globals->get_renderer()->getManipulator()->setMouseClickHandler(func);
+ if (strcmp(mode,"QUAD_BUFFER")==0)
+ {
+ stereoMode = DisplaySettings::QUAD_BUFFER;
+ }
+ else if (strcmp(mode,"ANAGLYPHIC")==0)
+ {
+ stereoMode = DisplaySettings::ANAGLYPHIC;
+ }
+ else if (strcmp(mode,"HORIZONTAL_SPLIT")==0)
+ {
+ stereoMode = DisplaySettings::HORIZONTAL_SPLIT;
+ }
+ else if (strcmp(mode,"VERTICAL_SPLIT")==0)
+ {
+ stereoMode = DisplaySettings::VERTICAL_SPLIT;
+ }
+ else if (strcmp(mode,"LEFT_EYE")==0)
+ {
+ stereoMode = DisplaySettings::LEFT_EYE;
+ }
+ else if (strcmp(mode,"RIGHT_EYE")==0)
+ {
+ stereoMode = DisplaySettings::RIGHT_EYE;
+ }
+ else if (strcmp(mode,"HORIZONTAL_INTERLACE")==0)
+ {
+ stereoMode = DisplaySettings::HORIZONTAL_INTERLACE;
+ }
+ else if (strcmp(mode,"VERTICAL_INTERLACE")==0)
+ {
+ stereoMode = DisplaySettings::VERTICAL_INTERLACE;
+ }
+ else if (strcmp(mode,"CHECKERBOARD")==0)
+ {
+ stereoMode = DisplaySettings::CHECKERBOARD;
+ } else {
+ stereoOn = false;
+ }
+ DisplaySettings::instance()->setStereo( stereoOn );
+ DisplaySettings::instance()->setStereoMode( stereoMode );
}
-void fgRegisterMouseMotionHandler(fgMouseMotionHandler func)
+static const char * getStereoMode()
{
- globals->get_renderer()->getManipulator()->setMouseMotionHandler(func);
+ DisplaySettings::StereoMode stereoMode = DisplaySettings::instance()->getStereoMode();
+ bool stereoOn = DisplaySettings::instance()->getStereo();
+ if( !stereoOn ) return "OFF";
+ if( stereoMode == DisplaySettings::QUAD_BUFFER ) {
+ return "QUAD_BUFFER";
+ } else if( stereoMode == DisplaySettings::ANAGLYPHIC ) {
+ return "ANAGLYPHIC";
+ } else if( stereoMode == DisplaySettings::HORIZONTAL_SPLIT ) {
+ return "HORIZONTAL_SPLIT";
+ } else if( stereoMode == DisplaySettings::VERTICAL_SPLIT ) {
+ return "VERTICAL_SPLIT";
+ } else if( stereoMode == DisplaySettings::LEFT_EYE ) {
+ return "LEFT_EYE";
+ } else if( stereoMode == DisplaySettings::RIGHT_EYE ) {
+ return "RIGHT_EYE";
+ } else if( stereoMode == DisplaySettings::HORIZONTAL_INTERLACE ) {
+ return "HORIZONTAL_INTERLACE";
+ } else if( stereoMode == DisplaySettings::VERTICAL_INTERLACE ) {
+ return "VERTICAL_INTERLACE";
+ } else if( stereoMode == DisplaySettings::CHECKERBOARD ) {
+ return "CHECKERBOARD";
+ }
+ return "OFF";
}
-// Redraw "happens" every frame whether you want it or not.
-void fgRequestRedraw()
+void fgOSOpenWindow(bool stencil)
{
-}
-
-//
-// fg_os implementation
-//
-
-static osg::ref_ptr<osgViewer::Viewer> viewer;
-static osg::ref_ptr<osg::Camera> mainCamera;
-
-void fgOSOpenWindow(int w, int h, int bpp,
- bool alpha, bool stencil, bool fullscreen)
-{
- osg::GraphicsContext::WindowingSystemInterface* wsi;
- wsi = osg::GraphicsContext::getWindowingSystemInterface();
-
viewer = new osgViewer::Viewer;
- // Avoid complications with fg's custom drawables.
+ viewer->setDatabasePager(FGScenery::getPagerSingleton());
+ CameraGroup* cameraGroup = 0;
std::string mode;
mode = fgGetString("/sim/rendering/multithreading-mode", "SingleThreaded");
if (mode == "AutomaticSelection")
viewer->setThreadingModel(osgViewer::Viewer::CullThreadPerCameraDrawThreadPerContext);
else
viewer->setThreadingModel(osgViewer::Viewer::SingleThreaded);
- osg::ref_ptr<osg::GraphicsContext::Traits> traits;
- traits = new osg::GraphicsContext::Traits;
- 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";
- 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;
-#ifdef WIN32
- // Ugly Hack, why does CW_USEDEFAULT works like phase of the moon?
- traits->x = 100;
- traits->y = 100;
-#endif
- traits->supportsResize = true;
- }
-
- osg::Camera::ProjectionResizePolicy rsp = osg::Camera::VERTICAL;
-
- // 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.
- 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);
- cameraTraits->hostName = cameraNode->getStringValue("host-name", "");
- cameraTraits->displayNum = cameraNode->getIntValue("display", 0);
- cameraTraits->screenNum = cameraNode->getIntValue("screen", 0);
- if (cameraNode->getBoolValue("fullscreen", fullscreen)) {
- unsigned width = 0;
- unsigned height = 0;
- wsi->getScreenResolution(*cameraTraits, width, height);
- cameraTraits->windowDecoration = false;
- cameraTraits->width = width;
- cameraTraits->height = height;
- cameraTraits->supportsResize = false;
- } else {
- cameraTraits->windowDecoration = true;
- cameraTraits->width = cameraNode->getIntValue("width", w);
- cameraTraits->height = cameraNode->getIntValue("height", h);
- cameraTraits->supportsResize = true;
+ WindowBuilder::initWindowBuilder(stencil);
+ WindowBuilder *windowBuilder = WindowBuilder::getWindowBuilder();
+
+ // Look for windows, camera groups, and the old syntax of
+ // top-level cameras
+ SGPropertyNode* renderingNode = fgGetNode("/sim/rendering");
+ SGPropertyNode* cgroupNode = renderingNode->getNode("camera-group", true);
+ bool oldSyntax = !cgroupNode->hasChild("camera");
+ if (oldSyntax) {
+ for (int i = 0; i < renderingNode->nChildren(); ++i) {
+ SGPropertyNode* propNode = renderingNode->getChild(i);
+ const char* propName = propNode->getName();
+ if (!strcmp(propName, "window") || !strcmp(propName, "camera")) {
+ SGPropertyNode* copiedNode
+ = cgroupNode->getNode(propName, propNode->getIndex(), true);
+ copyProperties(propNode, copiedNode);
+ }
}
- // 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 ...
- osg::ref_ptr<osg::Camera> camera = new osg::Camera;
-
- osg::GraphicsContext* gc;
- gc = osg::GraphicsContext::createGraphicsContext(cameraTraits.get());
- gc->realize();
- 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, cameraTraits->width, cameraTraits->height));
- camera->setProjectionResizePolicy(rsp);
- viewer->addSlave(camera.get(), osg::Matrix::translate(-shearx, -sheary, 0), osg::Matrix());
- }
+ vector<SGPropertyNode_ptr> cameras = cgroupNode->getChildren("camera");
+ SGPropertyNode* masterCamera = 0;
+ BOOST_FOREACH(SGPropertyNode_ptr& camera, cameras) {
+ if (camera->getDoubleValue("shear-x", 0.0) == 0.0
+ && camera->getDoubleValue("shear-y", 0.0) == 0.0) {
+ masterCamera = camera.ptr();
+ break;
+ }
+ }
+ if (!masterCamera) {
+ masterCamera = cgroupNode->getChild("camera", cameras.size(), true);
+ setValue(masterCamera->getNode("window/name", true),
+ windowBuilder->getDefaultWindowName());
+ }
+ SGPropertyNode* nameNode = masterCamera->getNode("window/name");
+ if (nameNode)
+ setValue(cgroupNode->getNode("gui/window/name", true),
+ nameNode->getStringValue());
}
-
- // now the main camera ...
- osg::ref_ptr<osg::Camera> camera = new osg::Camera;
- mainCamera = camera;
- osg::GraphicsContext* gc;
- 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));
- camera->setProjectionResizePolicy(rsp);
- viewer->addSlave(camera.get());
-
- viewer->setCameraManipulator(globals->get_renderer()->getManipulator());
+ cameraGroup = CameraGroup::buildCameraGroup(viewer.get(), cgroupNode);
+ Camera* guiCamera = getGUICamera(cameraGroup);
+ if (guiCamera) {
+ Viewport* guiViewport = guiCamera->getViewport();
+ fgSetInt("/sim/startup/xsize", guiViewport->width());
+ fgSetInt("/sim/startup/ysize", guiViewport->height());
+ }
+ FGEventHandler* manipulator = globals->get_renderer()->getEventHandler();
+ WindowSystemAdapter* wsa = WindowSystemAdapter::getWSA();
+ if (wsa->windows.size() != 1) {
+ manipulator->setResizable(false);
+ }
+ viewer->getCamera()->setProjectionResizePolicy(osg::Camera::FIXED);
+ viewer->addEventHandler(manipulator);
// Let FG handle the escape key with a confirmation
viewer->setKeyEventSetsDone(0);
- osgViewer::StatsHandler* statsHandler = new osgViewer::StatsHandler;
- statsHandler->setKeyEventTogglesOnScreenStats('*');
- statsHandler->setKeyEventPrintsOutStats(0);
- viewer->addEventHandler(statsHandler);
// The viewer won't start without some root.
viewer->setSceneData(new osg::Group);
globals->get_renderer()->setViewer(viewer.get());
+ CameraGroup::setDefault(cameraGroup);
+
+ DisplaySettings * displaySettings = DisplaySettings::instance();
+ fgTie("/sim/rendering/osg-displaysettings/eye-separation", displaySettings, &DisplaySettings::getEyeSeparation, &DisplaySettings::setEyeSeparation );
+ fgTie("/sim/rendering/osg-displaysettings/screen-distance", displaySettings, &DisplaySettings::getScreenDistance, &DisplaySettings::setScreenDistance );
+ fgTie("/sim/rendering/osg-displaysettings/screen-width", displaySettings, &DisplaySettings::getScreenWidth, &DisplaySettings::setScreenWidth );
+ fgTie("/sim/rendering/osg-displaysettings/screen-height", displaySettings, &DisplaySettings::getScreenHeight, &DisplaySettings::setScreenHeight );
+ fgTie("/sim/rendering/osg-displaysettings/stereo-mode", getStereoMode, setStereoMode );
+ fgTie("/sim/rendering/osg-displaysettings/double-buffer", displaySettings, &DisplaySettings::getDoubleBuffer, &DisplaySettings::setDoubleBuffer );
+ fgTie("/sim/rendering/osg-displaysettings/depth-buffer", displaySettings, &DisplaySettings::getDepthBuffer, &DisplaySettings::setDepthBuffer );
+ fgTie("/sim/rendering/osg-displaysettings/rgb", displaySettings, &DisplaySettings::getRGB, &DisplaySettings::setRGB );
}
+
static int status = 0;
void fgOSExit(int code)
{
viewer->setDone(true);
+ viewer->getDatabasePager()->cancel();
status = code;
}
-void fgOSMainLoop()
+int fgOSMainLoop()
{
- viewer->run();
- fgExit(status);
+ ref_ptr<FGEventHandler> manipulator
+ = globals->get_renderer()->getEventHandler();
+ viewer->setReleaseContextAtEndOfFrameHint(false);
+ if (!viewer->isRealized())
+ viewer->realize();
+ while (!viewer->done()) {
+ fgIdleHandler idleFunc = manipulator->getIdleHandler();
+ if (idleFunc)
+ (*idleFunc)();
+ globals->get_renderer()->update();
+ viewer->frame();
+ }
+
+ return status;
}
int fgGetKeyModifiers()
{
- return globals->get_renderer()->getManipulator()->getCurrentModifiers();
+ if (!globals->get_renderer()) { // happens during shutdown
+ return 0;
+ }
+
+ return globals->get_renderer()->getEventHandler()->getCurrentModifiers();
}
void fgWarpMouse(int x, int y)
{
- // Hack, currently the pointer is just recentered. So, we know the relative coordinates ...
- viewer->requestWarpPointer(0, 0);
+ warpGUIPointer(CameraGroup::getDefault(), x, y);
}
-// Noop
void fgOSInit(int* argc, char** argv)
{
+ globals->get_renderer()->init();
+ WindowSystemAdapter::setWSA(new WindowSystemAdapter);
}
// Noop
{
}
-// #define OSG_HAS_MOUSE_CURSOR_PATCH
-#ifdef OSG_HAS_MOUSE_CURSOR_PATCH
-static void setMouseCursor(osg::Camera* camera, int cursor)
+static void setMouseCursor(osgViewer::GraphicsWindow* gw, int cursor)
{
- if (!camera)
+ if (!gw) {
return;
- osg::GraphicsContext* gc = camera->getGraphicsContext();
- if (!gc)
- return;
- osgViewer::GraphicsWindow* gw;
- gw = dynamic_cast<osgViewer::GraphicsWindow*>(gc);
- if (!gw)
- return;
-
+ }
+
osgViewer::GraphicsWindow::MouseCursor mouseCursor;
mouseCursor = osgViewer::GraphicsWindow::InheritCursor;
- if (cursor == MOUSE_CURSOR_NONE)
+ if (cursor == MOUSE_CURSOR_NONE)
mouseCursor = osgViewer::GraphicsWindow::NoCursor;
else if(cursor == MOUSE_CURSOR_POINTER)
+#ifdef SG_MAC
+ // osgViewer-Cocoa lacks RightArrowCursor, use Left
+ mouseCursor = osgViewer::GraphicsWindow::LeftArrowCursor;
+#else
mouseCursor = osgViewer::GraphicsWindow::RightArrowCursor;
+#endif
else if(cursor == MOUSE_CURSOR_WAIT)
mouseCursor = osgViewer::GraphicsWindow::WaitCursor;
else if(cursor == MOUSE_CURSOR_CROSSHAIR)
mouseCursor = osgViewer::GraphicsWindow::CrosshairCursor;
else if(cursor == MOUSE_CURSOR_LEFTRIGHT)
mouseCursor = osgViewer::GraphicsWindow::LeftRightCursor;
+ else if(cursor == MOUSE_CURSOR_TOPSIDE)
+ mouseCursor = osgViewer::GraphicsWindow::TopSideCursor;
+ else if(cursor == MOUSE_CURSOR_BOTTOMSIDE)
+ mouseCursor = osgViewer::GraphicsWindow::BottomSideCursor;
+ else if(cursor == MOUSE_CURSOR_LEFTSIDE)
+ mouseCursor = osgViewer::GraphicsWindow::LeftSideCursor;
+ else if(cursor == MOUSE_CURSOR_RIGHTSIDE)
+ mouseCursor = osgViewer::GraphicsWindow::RightSideCursor;
+ else if(cursor == MOUSE_CURSOR_TOPLEFT)
+ mouseCursor = osgViewer::GraphicsWindow::TopLeftCorner;
+ else if(cursor == MOUSE_CURSOR_TOPRIGHT)
+ mouseCursor = osgViewer::GraphicsWindow::TopRightCorner;
+ else if(cursor == MOUSE_CURSOR_BOTTOMLEFT)
+ mouseCursor = osgViewer::GraphicsWindow::BottomLeftCorner;
+ else if(cursor == MOUSE_CURSOR_BOTTOMRIGHT)
+ mouseCursor = osgViewer::GraphicsWindow::BottomRightCorner;
gw->setCursor(mouseCursor);
}
-#endif
static int _cursor = -1;
void fgSetMouseCursor(int cursor)
{
_cursor = cursor;
-#ifdef OSG_HAS_MOUSE_CURSOR_PATCH
- setMouseCursor(viewer->getCamera(), cursor);
- for (unsigned i = 0; i < viewer->getNumSlaves(); ++i)
- setMouseCursor(viewer->getSlave(i)._camera.get(), cursor);
-#endif
+
+ std::vector<osgViewer::GraphicsWindow*> windows;
+ viewer->getWindows(windows);
+ BOOST_FOREACH(osgViewer::GraphicsWindow* gw, windows) {
+ setMouseCursor(gw, cursor);
+ }
}
int fgGetMouseCursor()
{
return _cursor;
}
-
-void fgMakeCurrent()
-{
- if (!mainCamera.valid())
- return;
- osg::GraphicsContext* gc = mainCamera->getGraphicsContext();
- if (!gc)
- return;
- gc->makeCurrent();
-}
-
-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;
-}