1 // fg_os_common.cxx -- common functions for fg_os interface
2 // implemented as an osgViewer
4 // Copyright (C) 2007 Tim Moore timoore@redhat.com
5 // Copyright (C) 2007 Mathias Froehlich
7 // This program is free software; you can redistribute it and/or
8 // modify it under the terms of the GNU General Public License as
9 // published by the Free Software Foundation; either version 2 of the
10 // License, or (at your option) any later version.
12 // This program is distributed in the hope that it will be useful, but
13 // WITHOUT ANY WARRANTY; without even the implied warranty of
14 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
15 // General Public License for more details.
17 // You should have received a copy of the GNU General Public License
18 // along with this program; if not, write to the Free Software
19 // Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
27 #include <simgear/compiler.h>
28 #include <simgear/structure/exception.hxx>
29 #include <simgear/debug/logstream.hxx>
31 #include <osg/GraphicsContext>
33 #include <osg/Matrixd>
34 #include <osg/Viewport>
35 #include <osg/Version>
37 #include <osgViewer/ViewerEventHandlers>
38 #include <osgViewer/Viewer>
39 #include <osgGA/MatrixManipulator>
41 #include <Include/general.hxx>
42 #include <Scenery/scenery.hxx>
44 #include "fg_props.hxx"
46 #include "globals.hxx"
47 #include "renderer.hxx"
49 #if (FG_OSG_VERSION >= 19008)
50 #define OSG_HAS_MOUSE_CURSOR_PATCH
53 // fg_os implementation using OpenSceneGraph's osgViewer::Viewer class
54 // to create the graphics window and run the event/update/render loop.
57 // fg_os implementation
62 static osg::ref_ptr<osgViewer::Viewer> viewer;
63 static osg::ref_ptr<osg::Camera> mainCamera;
65 // Callback to prevent the GraphicsContext resized function from messing
66 // with the projection matrix of the slave
70 struct fgResizeCallback : public GraphicsContext::ResizedCallback
72 fgResizeCallback(Camera* slaveCamera)
73 : mainSlaveCamera(slaveCamera)
76 virtual void resizedImplementation(GraphicsContext* gc, int x, int y,
77 int width, int height);
78 ref_ptr<Camera> mainSlaveCamera;
81 void fgResizeCallback::resizedImplementation(GraphicsContext* gc,
83 int width, int height)
85 View* view = mainSlaveCamera->getView();
86 View::Slave* slave = (view ?
87 view->findSlaveForCamera(mainSlaveCamera.get()) : 0);
89 Matrixd projOffset(slave->_projectionOffset);
90 gc->resizedImplementation(x, y, width, height);
91 // Restore projection offsets changed by
92 // GraphicsContext::resizedImplementation
93 slave->_projectionOffset = projOffset;
95 gc->resizedImplementation(x, y, width, height);
101 void fgOSOpenWindow(int w, int h, int bpp,
102 bool alpha, bool stencil, bool fullscreen)
104 osg::GraphicsContext::WindowingSystemInterface* wsi;
105 wsi = osg::GraphicsContext::getWindowingSystemInterface();
107 viewer = new osgViewer::Viewer;
108 viewer->setDatabasePager(FGScenery::getPagerSingleton());
110 mode = fgGetString("/sim/rendering/multithreading-mode", "SingleThreaded");
111 if (mode == "AutomaticSelection")
112 viewer->setThreadingModel(osgViewer::Viewer::AutomaticSelection);
113 else if (mode == "CullDrawThreadPerContext")
114 viewer->setThreadingModel(osgViewer::Viewer::CullDrawThreadPerContext);
115 else if (mode == "DrawThreadPerContext")
116 viewer->setThreadingModel(osgViewer::Viewer::DrawThreadPerContext);
117 else if (mode == "CullThreadPerCameraDrawThreadPerContext")
118 viewer->setThreadingModel(osgViewer::Viewer::CullThreadPerCameraDrawThreadPerContext);
120 viewer->setThreadingModel(osgViewer::Viewer::SingleThreaded);
121 osg::ref_ptr<osg::GraphicsContext::Traits> traits;
122 traits = new osg::GraphicsContext::Traits;
123 traits->readDISPLAY();
124 int cbits = (bpp <= 16) ? 5 : 8;
125 int zbits = (bpp <= 16) ? 16 : 24;
126 traits->red = traits->green = traits->blue = cbits;
127 traits->depth = zbits;
132 traits->doubleBuffer = true;
133 traits->mipMapGeneration = true;
134 traits->windowName = "FlightGear";
135 traits->sampleBuffers = fgGetBool("/sim/rendering/multi-sample-buffers", traits->sampleBuffers);
136 traits->samples = fgGetBool("/sim/rendering/multi-samples", traits->samples);
137 traits->vsync = fgGetBool("/sim/rendering/vsync-enable", traits->vsync);
142 wsi->getScreenResolution(*traits, width, height);
143 traits->windowDecoration = false;
144 traits->width = width;
145 traits->height = height;
146 traits->supportsResize = false;
148 traits->windowDecoration = true;
151 #if defined(WIN32) || defined(__APPLE__)
152 // Ugly Hack, why does CW_USEDEFAULT works like phase of the moon?
153 // Mac also needs this to show window frame, menubar and Docks
157 traits->supportsResize = true;
160 osg::Camera::ProjectionResizePolicy rsp = osg::Camera::VERTICAL;
162 // Ok, first the children.
163 // that achieves some magic ordering og the slaves so that we end up
164 // in the main window more often.
165 // This can be sorted out better when we got rid of glut and sdl.
166 FGManipulator* manipulator = globals->get_renderer()->getManipulator();
168 if (fgHasNode("/sim/rendering/camera")) {
169 SGPropertyNode* renderingNode = fgGetNode("/sim/rendering");
170 for (int i = 0; i < renderingNode->nChildren(); ++i) {
171 SGPropertyNode* cameraNode = renderingNode->getChild(i);
172 if (strcmp(cameraNode->getName(), "camera") != 0)
176 // get a new copy of the traits struct
177 osg::ref_ptr<osg::GraphicsContext::Traits> cameraTraits;
178 cameraTraits = new osg::GraphicsContext::Traits(*traits);
180 double shearx = cameraNode->getDoubleValue("shear-x", 0);
181 double sheary = cameraNode->getDoubleValue("shear-y", 0);
182 cameraTraits->hostName
183 = cameraNode->getStringValue("host-name", traits->hostName.c_str());
184 cameraTraits->displayNum
185 = cameraNode->getIntValue("display", traits->displayNum);
186 cameraTraits->screenNum
187 = cameraNode->getIntValue("screen", traits->screenNum);
188 if (cameraNode->getBoolValue("fullscreen", fullscreen)) {
191 wsi->getScreenResolution(*cameraTraits, width, height);
192 cameraTraits->windowDecoration = false;
193 cameraTraits->width = width;
194 cameraTraits->height = height;
195 cameraTraits->supportsResize = false;
197 cameraTraits->windowDecoration = true;
198 cameraTraits->width = cameraNode->getIntValue("width", w);
199 cameraTraits->height = cameraNode->getIntValue("height", h);
200 cameraTraits->supportsResize = true;
202 // FIXME, currently this is too much of a problem to route the resize
203 // events. When we do no longer need sdl and such this
205 cameraTraits->supportsResize = false;
207 // ok found a camera configuration, add a new slave ...
208 osg::ref_ptr<osg::Camera> camera = new osg::Camera;
210 osg::GraphicsContext* gc;
211 gc = osg::GraphicsContext::createGraphicsContext(cameraTraits.get());
213 camera->setGraphicsContext(gc);
214 // If a viewport isn't set on the camera, then it's hard to dig it
215 // out of the SceneView objects in the viewer, and the coordinates
216 // of mouse events are somewhat bizzare.
217 camera->setViewport(new osg::Viewport(0, 0, cameraTraits->width, cameraTraits->height));
218 camera->setProjectionResizePolicy(rsp);
219 viewer->addSlave(camera.get(), osg::Matrix::translate(-shearx, -sheary, 0), osg::Matrix());
222 manipulator->setResizable(false);
225 // now the main camera ...
226 osg::ref_ptr<osg::Camera> camera = new osg::Camera;
228 osg::GraphicsContext* gc;
229 gc = osg::GraphicsContext::createGraphicsContext(traits.get());
232 camera->setGraphicsContext(gc);
233 // If a viewport isn't set on the camera, then it's hard to dig it
234 // out of the SceneView objects in the viewer, and the coordinates
235 // of mouse events are somewhat bizzare.
236 camera->setViewport(new osg::Viewport(0, 0, traits->width, traits->height));
237 camera->setProjectionResizePolicy(rsp);
239 // Only one principal camera
240 gc->setResizedCallback(new fgResizeCallback(camera.get()));
242 // Why a slave? It seems to be the easiest way to assign cameras,
243 // for which we've created the graphics context ourselves, to the viewer.
244 viewer->addSlave(camera.get());
246 viewer->setCameraManipulator(globals->get_renderer()->getManipulator());
247 // Let FG handle the escape key with a confirmation
248 viewer->setKeyEventSetsDone(0);
249 osgViewer::StatsHandler* statsHandler = new osgViewer::StatsHandler;
250 statsHandler->setKeyEventTogglesOnScreenStats('*');
251 statsHandler->setKeyEventPrintsOutStats(0);
252 viewer->addEventHandler(statsHandler);
253 // The viewer won't start without some root.
254 viewer->setSceneData(new osg::Group);
255 globals->get_renderer()->setViewer(viewer.get());
258 static int status = 0;
260 void fgOSExit(int code)
262 viewer->setDone(true);
272 int fgGetKeyModifiers()
274 return globals->get_renderer()->getManipulator()->getCurrentModifiers();
277 void fgWarpMouse(int x, int y)
279 globals->get_renderer()->getManipulator()->setMouseWarped();
280 // Hack, currently the pointer is just recentered. So, we know the
281 // relative coordinates ...
282 if (!mainCamera.valid()) {
283 viewer->requestWarpPointer(0, 0);
286 float xsize = (float)mainCamera->getGraphicsContext()->getTraits()->width;
287 float ysize = (float)mainCamera->getGraphicsContext()->getTraits()->height;
288 viewer->requestWarpPointer(2.0f * (float)x / xsize - 1.0f,
289 1.0f - 2.0f * (float)y / ysize);
293 void fgOSInit(int* argc, char** argv)
298 void fgOSFullScreen()
302 #ifdef OSG_HAS_MOUSE_CURSOR_PATCH
303 static void setMouseCursor(osg::Camera* camera, int cursor)
307 osg::GraphicsContext* gc = camera->getGraphicsContext();
310 osgViewer::GraphicsWindow* gw;
311 gw = dynamic_cast<osgViewer::GraphicsWindow*>(gc);
315 osgViewer::GraphicsWindow::MouseCursor mouseCursor;
316 mouseCursor = osgViewer::GraphicsWindow::InheritCursor;
317 if (cursor == MOUSE_CURSOR_NONE)
318 mouseCursor = osgViewer::GraphicsWindow::NoCursor;
319 else if(cursor == MOUSE_CURSOR_POINTER)
320 mouseCursor = osgViewer::GraphicsWindow::RightArrowCursor;
321 else if(cursor == MOUSE_CURSOR_WAIT)
322 mouseCursor = osgViewer::GraphicsWindow::WaitCursor;
323 else if(cursor == MOUSE_CURSOR_CROSSHAIR)
324 mouseCursor = osgViewer::GraphicsWindow::CrosshairCursor;
325 else if(cursor == MOUSE_CURSOR_LEFTRIGHT)
326 mouseCursor = osgViewer::GraphicsWindow::LeftRightCursor;
328 gw->setCursor(mouseCursor);
332 static int _cursor = -1;
334 void fgSetMouseCursor(int cursor)
337 #ifdef OSG_HAS_MOUSE_CURSOR_PATCH
338 setMouseCursor(viewer->getCamera(), cursor);
339 for (unsigned i = 0; i < viewer->getNumSlaves(); ++i)
340 setMouseCursor(viewer->getSlave(i)._camera.get(), cursor);
344 int fgGetMouseCursor()
351 if (!mainCamera.valid())
353 osg::GraphicsContext* gc = mainCamera->getGraphicsContext();
359 bool fgOSIsMainContext(const osg::GraphicsContext* context)
361 if (!mainCamera.valid())
363 return context == mainCamera->getGraphicsContext();
366 bool fgOSIsMainCamera(const osg::Camera* camera)
370 if (camera == mainCamera.get())
374 if (camera == viewer->getCamera())