2007-06-16 16:15:49 +00:00
|
|
|
|
|
|
|
#ifdef HAVE_CONFIG_H
|
|
|
|
# include <config.h>
|
|
|
|
#endif
|
|
|
|
|
2007-05-21 17:50:02 +00:00
|
|
|
#include <stdlib.h>
|
|
|
|
|
|
|
|
#include <simgear/compiler.h>
|
|
|
|
#include <simgear/structure/exception.hxx>
|
|
|
|
#include <simgear/debug/logstream.hxx>
|
|
|
|
|
|
|
|
#include <osg/GraphicsContext>
|
|
|
|
#include <osg/Group>
|
|
|
|
#include <osg/Matrixd>
|
|
|
|
#include <osg/Viewport>
|
2007-06-08 07:14:56 +00:00
|
|
|
#include <osg/Version>
|
2007-06-16 16:15:49 +00:00
|
|
|
#include <osgViewer/ViewerEventHandlers>
|
2007-05-21 17:50:02 +00:00
|
|
|
#include <osgViewer/Viewer>
|
|
|
|
#include <osgGA/MatrixManipulator>
|
|
|
|
|
|
|
|
#include "fg_os.hxx"
|
2007-05-26 13:53:46 +00:00
|
|
|
#include "fg_props.hxx"
|
2007-05-21 17:50:02 +00:00
|
|
|
#include "util.hxx"
|
|
|
|
#include "globals.hxx"
|
|
|
|
#include "renderer.hxx"
|
|
|
|
|
2007-06-16 09:39:56 +00:00
|
|
|
#if ((2 <= OSG_VERSION_MAJOR) || \
|
|
|
|
(1 == OSG_VERSION_MAJOR) && (9 == OSG_VERSION_MINOR) && \
|
2007-06-08 07:14:56 +00:00
|
|
|
(8 <= OSG_VERSION_PATCH)) || \
|
|
|
|
((1 == OSG_VERSION_MAJOR) && (9 < OSG_VERSION_MINOR)) || \
|
|
|
|
(1 < OSG_VERSION_MAJOR)
|
|
|
|
#define OSG_HAS_MOUSE_CURSOR_PATCH
|
|
|
|
#endif
|
|
|
|
|
2007-05-21 17:50:02 +00:00
|
|
|
// 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
|
|
|
|
//
|
|
|
|
|
|
|
|
|
|
|
|
// 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);
|
|
|
|
}
|
|
|
|
|
|
|
|
void fgRegisterKeyHandler(fgKeyHandler func)
|
|
|
|
{
|
|
|
|
globals->get_renderer()->getManipulator()->setKeyHandler(func);
|
|
|
|
}
|
|
|
|
|
|
|
|
void fgRegisterMouseClickHandler(fgMouseClickHandler func)
|
|
|
|
{
|
|
|
|
globals->get_renderer()->getManipulator()->setMouseClickHandler(func);
|
|
|
|
}
|
|
|
|
|
|
|
|
void fgRegisterMouseMotionHandler(fgMouseMotionHandler func)
|
|
|
|
{
|
|
|
|
globals->get_renderer()->getManipulator()->setMouseMotionHandler(func);
|
|
|
|
}
|
|
|
|
|
|
|
|
// Redraw "happens" every frame whether you want it or not.
|
|
|
|
void fgRequestRedraw()
|
|
|
|
{
|
|
|
|
}
|
|
|
|
|
|
|
|
//
|
|
|
|
// fg_os implementation
|
|
|
|
//
|
|
|
|
|
|
|
|
static osg::ref_ptr<osgViewer::Viewer> viewer;
|
2007-05-26 13:53:46 +00:00
|
|
|
static osg::ref_ptr<osg::Camera> mainCamera;
|
2007-05-21 17:50:02 +00:00
|
|
|
|
|
|
|
void fgOSOpenWindow(int w, int h, int bpp,
|
|
|
|
bool alpha, bool stencil, bool fullscreen)
|
|
|
|
{
|
2007-05-26 13:53:46 +00:00
|
|
|
osg::GraphicsContext::WindowingSystemInterface* wsi;
|
|
|
|
wsi = osg::GraphicsContext::getWindowingSystemInterface();
|
|
|
|
|
2007-05-21 17:50:02 +00:00
|
|
|
viewer = new osgViewer::Viewer;
|
|
|
|
// Avoid complications with fg's custom drawables.
|
2007-05-26 13:53:46 +00:00
|
|
|
std::string mode;
|
|
|
|
mode = fgGetString("/sim/rendering/multithreading-mode", "SingleThreaded");
|
|
|
|
if (mode == "AutomaticSelection")
|
|
|
|
viewer->setThreadingModel(osgViewer::Viewer::AutomaticSelection);
|
|
|
|
else if (mode == "CullDrawThreadPerContext")
|
|
|
|
viewer->setThreadingModel(osgViewer::Viewer::CullDrawThreadPerContext);
|
|
|
|
else if (mode == "DrawThreadPerContext")
|
|
|
|
viewer->setThreadingModel(osgViewer::Viewer::DrawThreadPerContext);
|
|
|
|
else if (mode == "CullThreadPerCameraDrawThreadPerContext")
|
|
|
|
viewer->setThreadingModel(osgViewer::Viewer::CullThreadPerCameraDrawThreadPerContext);
|
|
|
|
else
|
|
|
|
viewer->setThreadingModel(osgViewer::Viewer::SingleThreaded);
|
|
|
|
osg::ref_ptr<osg::GraphicsContext::Traits> traits;
|
|
|
|
traits = new osg::GraphicsContext::Traits;
|
2007-05-21 17:50:02 +00:00
|
|
|
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;
|
2007-05-26 13:53:46 +00:00
|
|
|
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);
|
2007-05-21 17:50:02 +00:00
|
|
|
traits->windowDecoration = false;
|
2007-05-26 13:53:46 +00:00
|
|
|
traits->width = width;
|
|
|
|
traits->height = height;
|
|
|
|
traits->supportsResize = false;
|
|
|
|
} else {
|
2007-05-21 17:50:02 +00:00
|
|
|
traits->windowDecoration = true;
|
2007-05-26 13:53:46 +00:00
|
|
|
traits->width = w;
|
|
|
|
traits->height = h;
|
2007-05-30 13:15:14 +00:00
|
|
|
#ifdef WIN32
|
|
|
|
// Ugly Hack, why does CW_USEDEFAULT works like phase of the moon?
|
|
|
|
traits->x = 100;
|
|
|
|
traits->y = 100;
|
|
|
|
#endif
|
2007-05-26 13:53:46 +00:00
|
|
|
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.
|
2007-07-01 16:39:52 +00:00
|
|
|
FGManipulator* manipulator = globals->get_renderer()->getManipulator();
|
|
|
|
int nCameras = 0;
|
2007-05-26 13:53:46 +00:00
|
|
|
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;
|
|
|
|
|
2007-07-01 16:39:52 +00:00
|
|
|
nCameras++;
|
2007-05-26 13:53:46 +00:00
|
|
|
// 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;
|
|
|
|
}
|
|
|
|
// 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());
|
|
|
|
}
|
2007-07-01 16:39:52 +00:00
|
|
|
if (nCameras > 1)
|
|
|
|
manipulator->setResizable(false);
|
2007-05-26 13:53:46 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
// 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);
|
2007-05-21 17:50:02 +00:00
|
|
|
// 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.
|
2007-05-26 13:53:46 +00:00
|
|
|
camera->setViewport(new osg::Viewport(0, 0, traits->width, traits->height));
|
|
|
|
camera->setProjectionResizePolicy(rsp);
|
|
|
|
viewer->addSlave(camera.get());
|
|
|
|
|
2007-05-21 17:50:02 +00:00
|
|
|
viewer->setCameraManipulator(globals->get_renderer()->getManipulator());
|
|
|
|
// 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());
|
|
|
|
}
|
|
|
|
|
|
|
|
static int status = 0;
|
|
|
|
|
|
|
|
void fgOSExit(int code)
|
|
|
|
{
|
|
|
|
viewer->setDone(true);
|
|
|
|
status = code;
|
|
|
|
}
|
|
|
|
|
|
|
|
void fgOSMainLoop()
|
|
|
|
{
|
|
|
|
viewer->run();
|
|
|
|
fgExit(status);
|
|
|
|
}
|
|
|
|
|
|
|
|
int fgGetKeyModifiers()
|
|
|
|
{
|
|
|
|
return globals->get_renderer()->getManipulator()->getCurrentModifiers();
|
|
|
|
}
|
|
|
|
|
|
|
|
void fgWarpMouse(int x, int y)
|
|
|
|
{
|
2007-05-26 13:53:46 +00:00
|
|
|
// Hack, currently the pointer is just recentered. So, we know the relative coordinates ...
|
|
|
|
viewer->requestWarpPointer(0, 0);
|
2007-05-21 17:50:02 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
// Noop
|
|
|
|
void fgOSInit(int* argc, char** argv)
|
|
|
|
{
|
|
|
|
}
|
|
|
|
|
2007-05-26 13:53:46 +00:00
|
|
|
// Noop
|
2007-05-21 17:50:02 +00:00
|
|
|
void fgOSFullScreen()
|
|
|
|
{
|
2007-05-26 13:53:46 +00:00
|
|
|
}
|
2007-05-21 17:50:02 +00:00
|
|
|
|
2007-05-26 13:53:46 +00:00
|
|
|
#ifdef OSG_HAS_MOUSE_CURSOR_PATCH
|
|
|
|
static void setMouseCursor(osg::Camera* camera, int cursor)
|
|
|
|
{
|
|
|
|
if (!camera)
|
|
|
|
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)
|
|
|
|
mouseCursor = osgViewer::GraphicsWindow::NoCursor;
|
|
|
|
else if(cursor == MOUSE_CURSOR_POINTER)
|
|
|
|
mouseCursor = osgViewer::GraphicsWindow::RightArrowCursor;
|
|
|
|
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;
|
|
|
|
|
|
|
|
gw->setCursor(mouseCursor);
|
2007-05-21 17:50:02 +00:00
|
|
|
}
|
2007-05-26 13:53:46 +00:00
|
|
|
#endif
|
|
|
|
|
|
|
|
static int _cursor = -1;
|
2007-05-21 17:50:02 +00:00
|
|
|
|
|
|
|
void fgSetMouseCursor(int cursor)
|
|
|
|
{
|
2007-05-26 13:53:46 +00:00
|
|
|
_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
|
2007-05-21 17:50:02 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
int fgGetMouseCursor()
|
|
|
|
{
|
2007-05-26 13:53:46 +00:00
|
|
|
return _cursor;
|
2007-05-21 17:50:02 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
void fgMakeCurrent()
|
|
|
|
{
|
2007-05-26 13:53:46 +00:00
|
|
|
if (!mainCamera.valid())
|
|
|
|
return;
|
|
|
|
osg::GraphicsContext* gc = mainCamera->getGraphicsContext();
|
|
|
|
if (!gc)
|
|
|
|
return;
|
2007-05-21 17:50:02 +00:00
|
|
|
gc->makeCurrent();
|
|
|
|
}
|
2007-05-26 13:53:46 +00:00
|
|
|
|
|
|
|
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;
|
|
|
|
}
|