]> git.mxchange.org Git - flightgear.git/blob - src/Main/fg_os_osgviewer.cxx
a713e0627e16fa74a2eee4b3453bc08ef8f4838f
[flightgear.git] / src / Main / fg_os_osgviewer.cxx
1 // fg_os_common.cxx -- common functions for fg_os interface
2 // implemented as an osgViewer
3 //
4 // Copyright (C) 2007  Tim Moore timoore@redhat.com
5 // Copyright (C) 2007 Mathias Froehlich 
6 //
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.
11 //
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.
16 //
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.
20
21 #ifdef HAVE_CONFIG_H
22 #  include <config.h>
23 #endif
24
25 #include <stdlib.h>
26
27 #include <simgear/compiler.h>
28 #include <simgear/structure/exception.hxx>
29 #include <simgear/debug/logstream.hxx>
30
31 #include <osg/GraphicsContext>
32 #include <osg/Group>
33 #include <osg/Matrixd>
34 #include <osg/Viewport>
35 #include <osg/Version>
36 #include <osg/View>
37 #include <osgViewer/ViewerEventHandlers>
38 #include <osgViewer/Viewer>
39 #include <osgGA/MatrixManipulator>
40
41 #include <Include/general.hxx>
42 #include <Scenery/scenery.hxx>
43 #include "fg_os.hxx"
44 #include "fg_props.hxx"
45 #include "util.hxx"
46 #include "globals.hxx"
47 #include "renderer.hxx"
48
49 #if (FG_OSG_VERSION >= 19008)
50 #define OSG_HAS_MOUSE_CURSOR_PATCH
51 #endif
52
53 // fg_os implementation using OpenSceneGraph's osgViewer::Viewer class
54 // to create the graphics window and run the event/update/render loop.
55
56 //
57 // fg_os implementation
58 //
59
60 using namespace osg;
61
62 static osg::ref_ptr<osgViewer::Viewer> viewer;
63 static osg::ref_ptr<osg::Camera> mainCamera;
64
65 // Callback to prevent the GraphicsContext resized function from messing
66 // with the projection matrix of the slave
67
68 namespace
69 {
70 struct fgResizeCallback : public GraphicsContext::ResizedCallback
71 {
72     fgResizeCallback(Camera* slaveCamera)
73         : mainSlaveCamera(slaveCamera)
74     {}
75     
76     virtual void resizedImplementation(GraphicsContext* gc, int x, int y,
77                                        int width, int height);
78     ref_ptr<Camera> mainSlaveCamera;
79 };
80
81 void fgResizeCallback::resizedImplementation(GraphicsContext* gc,
82                                              int x, int y,
83                                              int width, int height)
84 {
85     View* view = mainSlaveCamera->getView();
86     View::Slave* slave = (view ?
87                           view->findSlaveForCamera(mainSlaveCamera.get()) : 0);
88     if (slave) {
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;
94     } else {
95         gc->resizedImplementation(x, y, width, height);
96     }
97     
98 }
99
100 }
101 void fgOSOpenWindow(int w, int h, int bpp,
102                     bool alpha, bool stencil, bool fullscreen)
103 {
104     osg::GraphicsContext::WindowingSystemInterface* wsi;
105     wsi = osg::GraphicsContext::getWindowingSystemInterface();
106
107     viewer = new osgViewer::Viewer;
108     viewer->setDatabasePager(FGScenery::getPagerSingleton());
109     std::string mode;
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);
119     else
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;
128     if (alpha)
129         traits->alpha = 8;
130     if (stencil)
131         traits->stencil = 8;
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);
138
139     if (fullscreen) {
140         unsigned width = 0;
141         unsigned height = 0;
142         wsi->getScreenResolution(*traits, width, height);
143         traits->windowDecoration = false;
144         traits->width = width;
145         traits->height = height;
146         traits->supportsResize = false;
147     } else {
148         traits->windowDecoration = true;
149         traits->width = w;
150         traits->height = h;
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
154         traits->x = 100;
155         traits->y = 100;
156 #endif
157         traits->supportsResize = true;
158     }
159
160     osg::Camera::ProjectionResizePolicy rsp = osg::Camera::VERTICAL;
161
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();
167     int nCameras = 0;
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)
173           continue;
174
175         nCameras++;
176         // get a new copy of the traits struct
177         osg::ref_ptr<osg::GraphicsContext::Traits> cameraTraits;
178         cameraTraits = new osg::GraphicsContext::Traits(*traits);
179
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)) {
189           unsigned width = 0;
190           unsigned height = 0;
191           wsi->getScreenResolution(*cameraTraits, width, height);
192           cameraTraits->windowDecoration = false;
193           cameraTraits->width = width;
194           cameraTraits->height = height;
195           cameraTraits->supportsResize = false;
196         } else {
197           cameraTraits->windowDecoration = true;
198           cameraTraits->width = cameraNode->getIntValue("width", w);
199           cameraTraits->height = cameraNode->getIntValue("height", h);
200           cameraTraits->supportsResize = true;
201         }
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
204         // can be simplified
205         cameraTraits->supportsResize = false;
206
207         // ok found a camera configuration, add a new slave ...
208         osg::ref_ptr<osg::Camera> camera = new osg::Camera;
209
210         osg::GraphicsContext* gc;
211         gc = osg::GraphicsContext::createGraphicsContext(cameraTraits.get());
212         gc->realize();
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());
220       }
221       if (nCameras > 1)
222         manipulator->setResizable(false);
223     }
224
225     // now the main camera ...
226     osg::ref_ptr<osg::Camera> camera = new osg::Camera;
227     mainCamera = camera;
228     osg::GraphicsContext* gc;
229     gc = osg::GraphicsContext::createGraphicsContext(traits.get());
230     gc->realize();
231     gc->makeCurrent();
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);
238     if (nCameras == 0) {
239         // Only one principal camera
240         gc->setResizedCallback(new fgResizeCallback(camera.get()));
241     }
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());
245
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());
256 }
257
258 static int status = 0;
259
260 void fgOSExit(int code)
261 {
262     viewer->setDone(true);
263     viewer->getDatabasePager()->cancel();
264     status = code;
265 }
266
267 void fgOSMainLoop()
268 {
269     viewer->run();
270     fgExit(status);
271 }
272
273 int fgGetKeyModifiers()
274 {
275     return globals->get_renderer()->getManipulator()->getCurrentModifiers();
276 }
277
278 void fgWarpMouse(int x, int y)
279 {
280     globals->get_renderer()->getManipulator()->setMouseWarped();
281     // Hack, currently the pointer is just recentered. So, we know the
282     // relative coordinates ...
283     if (!mainCamera.valid()) {
284         viewer->requestWarpPointer(0, 0);
285         return;
286     }
287     float xsize = (float)mainCamera->getGraphicsContext()->getTraits()->width;
288     float ysize = (float)mainCamera->getGraphicsContext()->getTraits()->height;
289     viewer->requestWarpPointer(2.0f * (float)x / xsize - 1.0f,
290                                1.0f - 2.0f * (float)y / ysize);
291 }
292
293 // Noop
294 void fgOSInit(int* argc, char** argv)
295 {
296 }
297
298 // Noop
299 void fgOSFullScreen()
300 {
301 }
302
303 #ifdef OSG_HAS_MOUSE_CURSOR_PATCH
304 static void setMouseCursor(osg::Camera* camera, int cursor)
305 {
306     if (!camera)
307         return;
308     osg::GraphicsContext* gc = camera->getGraphicsContext();
309     if (!gc)
310         return;
311     osgViewer::GraphicsWindow* gw;
312     gw = dynamic_cast<osgViewer::GraphicsWindow*>(gc);
313     if (!gw)
314         return;
315     
316     osgViewer::GraphicsWindow::MouseCursor mouseCursor;
317     mouseCursor = osgViewer::GraphicsWindow::InheritCursor;
318     if     (cursor == MOUSE_CURSOR_NONE)
319         mouseCursor = osgViewer::GraphicsWindow::NoCursor;
320     else if(cursor == MOUSE_CURSOR_POINTER)
321         mouseCursor = osgViewer::GraphicsWindow::RightArrowCursor;
322     else if(cursor == MOUSE_CURSOR_WAIT)
323         mouseCursor = osgViewer::GraphicsWindow::WaitCursor;
324     else if(cursor == MOUSE_CURSOR_CROSSHAIR)
325         mouseCursor = osgViewer::GraphicsWindow::CrosshairCursor;
326     else if(cursor == MOUSE_CURSOR_LEFTRIGHT)
327         mouseCursor = osgViewer::GraphicsWindow::LeftRightCursor;
328
329     gw->setCursor(mouseCursor);
330 }
331 #endif
332
333 static int _cursor = -1;
334
335 void fgSetMouseCursor(int cursor)
336 {
337     _cursor = cursor;
338 #ifdef OSG_HAS_MOUSE_CURSOR_PATCH
339     setMouseCursor(viewer->getCamera(), cursor);
340     for (unsigned i = 0; i < viewer->getNumSlaves(); ++i)
341         setMouseCursor(viewer->getSlave(i)._camera.get(), cursor);
342 #endif
343 }
344
345 int fgGetMouseCursor()
346 {
347     return _cursor;
348 }
349
350 void fgMakeCurrent()
351 {
352     if (!mainCamera.valid())
353         return;
354     osg::GraphicsContext* gc = mainCamera->getGraphicsContext();
355     if (!gc)
356         return;
357     gc->makeCurrent();
358 }
359
360 bool fgOSIsMainContext(const osg::GraphicsContext* context)
361 {
362     if (!mainCamera.valid())
363         return false;
364     return context == mainCamera->getGraphicsContext();
365 }
366
367 bool fgOSIsMainCamera(const osg::Camera* camera)
368 {
369   if (!camera)
370     return false;
371   if (camera == mainCamera.get())
372     return true;
373   if (!viewer.valid())
374     return false;
375   if (camera == viewer->getCamera())
376     return true;
377   return false;
378 }