]> git.mxchange.org Git - flightgear.git/blob - src/Main/fg_os_osgviewer.cxx
Tatsuhiro NISHIOKA: initialize classes (fixes segfault on exit on MacOS)
[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 <osgViewer/ViewerEventHandlers>
37 #include <osgViewer/Viewer>
38 #include <osgGA/MatrixManipulator>
39
40 #include <Include/general.hxx>
41 #include "fg_os.hxx"
42 #include "fg_props.hxx"
43 #include "util.hxx"
44 #include "globals.hxx"
45 #include "renderer.hxx"
46
47 #if (FG_OSG_VERSION >= 19008)
48 #define OSG_HAS_MOUSE_CURSOR_PATCH
49 #endif
50
51 // fg_os implementation using OpenSceneGraph's osgViewer::Viewer class
52 // to create the graphics window and run the event/update/render loop.
53
54 //
55 // fg_os implementation
56 //
57
58 static osg::ref_ptr<osgViewer::Viewer> viewer;
59 static osg::ref_ptr<osg::Camera> mainCamera;
60
61 void fgOSOpenWindow(int w, int h, int bpp,
62                     bool alpha, bool stencil, bool fullscreen)
63 {
64     osg::GraphicsContext::WindowingSystemInterface* wsi;
65     wsi = osg::GraphicsContext::getWindowingSystemInterface();
66
67     viewer = new osgViewer::Viewer;
68     // Avoid complications with fg's custom drawables.
69     std::string mode;
70     mode = fgGetString("/sim/rendering/multithreading-mode", "SingleThreaded");
71     if (mode == "AutomaticSelection")
72       viewer->setThreadingModel(osgViewer::Viewer::AutomaticSelection);
73     else if (mode == "CullDrawThreadPerContext")
74       viewer->setThreadingModel(osgViewer::Viewer::CullDrawThreadPerContext);
75     else if (mode == "DrawThreadPerContext")
76       viewer->setThreadingModel(osgViewer::Viewer::DrawThreadPerContext);
77     else if (mode == "CullThreadPerCameraDrawThreadPerContext")
78       viewer->setThreadingModel(osgViewer::Viewer::CullThreadPerCameraDrawThreadPerContext);
79     else
80       viewer->setThreadingModel(osgViewer::Viewer::SingleThreaded);
81     osg::ref_ptr<osg::GraphicsContext::Traits> traits;
82     traits = new osg::GraphicsContext::Traits;
83     int cbits = (bpp <= 16) ?  5 :  8;
84     int zbits = (bpp <= 16) ? 16 : 24;
85     traits->red = traits->green = traits->blue = cbits;
86     traits->depth = zbits;
87     if (alpha)
88         traits->alpha = 8;
89     if (stencil)
90         traits->stencil = 8;
91     traits->doubleBuffer = true;
92     traits->mipMapGeneration = true;
93     traits->windowName = "FlightGear";
94     traits->sampleBuffers = fgGetBool("/sim/rendering/multi-sample-buffers", traits->sampleBuffers);
95     traits->samples = fgGetBool("/sim/rendering/multi-samples", traits->samples);
96     traits->vsync = fgGetBool("/sim/rendering/vsync-enable", traits->vsync);
97
98     if (fullscreen) {
99         unsigned width = 0;
100         unsigned height = 0;
101         wsi->getScreenResolution(*traits, width, height);
102         traits->windowDecoration = false;
103         traits->width = width;
104         traits->height = height;
105         traits->supportsResize = false;
106     } else {
107         traits->windowDecoration = true;
108         traits->width = w;
109         traits->height = h;
110 #ifdef WIN32
111         // Ugly Hack, why does CW_USEDEFAULT works like phase of the moon?
112         traits->x = 100;
113         traits->y = 100;
114 #endif
115         traits->supportsResize = true;
116     }
117
118     osg::Camera::ProjectionResizePolicy rsp = osg::Camera::VERTICAL;
119
120     // Ok, first the children.
121     // that achieves some magic ordering og the slaves so that we end up
122     // in the main window more often.
123     // This can be sorted out better when we got rid of glut and sdl.
124     FGManipulator* manipulator = globals->get_renderer()->getManipulator();
125     int nCameras = 0;
126     if (fgHasNode("/sim/rendering/camera")) {
127       SGPropertyNode* renderingNode = fgGetNode("/sim/rendering");
128       for (int i = 0; i < renderingNode->nChildren(); ++i) {
129         SGPropertyNode* cameraNode = renderingNode->getChild(i);
130         if (strcmp(cameraNode->getName(), "camera") != 0)
131           continue;
132
133         nCameras++;
134         // get a new copy of the traits struct
135         osg::ref_ptr<osg::GraphicsContext::Traits> cameraTraits;
136         cameraTraits = new osg::GraphicsContext::Traits(*traits);
137
138         double shearx = cameraNode->getDoubleValue("shear-x", 0);
139         double sheary = cameraNode->getDoubleValue("shear-y", 0);
140         cameraTraits->hostName = cameraNode->getStringValue("host-name", "");
141         cameraTraits->displayNum = cameraNode->getIntValue("display", 0);
142         cameraTraits->screenNum = cameraNode->getIntValue("screen", 0);
143         if (cameraNode->getBoolValue("fullscreen", fullscreen)) {
144           unsigned width = 0;
145           unsigned height = 0;
146           wsi->getScreenResolution(*cameraTraits, width, height);
147           cameraTraits->windowDecoration = false;
148           cameraTraits->width = width;
149           cameraTraits->height = height;
150           cameraTraits->supportsResize = false;
151         } else {
152           cameraTraits->windowDecoration = true;
153           cameraTraits->width = cameraNode->getIntValue("width", w);
154           cameraTraits->height = cameraNode->getIntValue("height", h);
155           cameraTraits->supportsResize = true;
156         }
157         // FIXME, currently this is too much of a problem to route the resize
158         // events. When we do no longer need sdl and such this
159         // can be simplified
160         cameraTraits->supportsResize = false;
161
162         // ok found a camera configuration, add a new slave ...
163         osg::ref_ptr<osg::Camera> camera = new osg::Camera;
164
165         osg::GraphicsContext* gc;
166         gc = osg::GraphicsContext::createGraphicsContext(cameraTraits.get());
167         gc->realize();
168         camera->setGraphicsContext(gc);
169         // If a viewport isn't set on the camera, then it's hard to dig it
170         // out of the SceneView objects in the viewer, and the coordinates
171         // of mouse events are somewhat bizzare.
172         camera->setViewport(new osg::Viewport(0, 0, cameraTraits->width, cameraTraits->height));
173         camera->setProjectionResizePolicy(rsp);
174         viewer->addSlave(camera.get(), osg::Matrix::translate(-shearx, -sheary, 0), osg::Matrix());
175       }
176       if (nCameras > 1)
177         manipulator->setResizable(false);
178     }
179
180     // now the main camera ...
181     osg::ref_ptr<osg::Camera> camera = new osg::Camera;
182     mainCamera = camera;
183     osg::GraphicsContext* gc;
184     gc = osg::GraphicsContext::createGraphicsContext(traits.get());
185     gc->realize();
186     gc->makeCurrent();
187     camera->setGraphicsContext(gc);
188     // If a viewport isn't set on the camera, then it's hard to dig it
189     // out of the SceneView objects in the viewer, and the coordinates
190     // of mouse events are somewhat bizzare.
191     camera->setViewport(new osg::Viewport(0, 0, traits->width, traits->height));
192     camera->setProjectionResizePolicy(rsp);
193     viewer->addSlave(camera.get());
194
195     viewer->setCameraManipulator(globals->get_renderer()->getManipulator());
196     // Let FG handle the escape key with a confirmation
197     viewer->setKeyEventSetsDone(0);
198     osgViewer::StatsHandler* statsHandler = new osgViewer::StatsHandler;
199     statsHandler->setKeyEventTogglesOnScreenStats('*');
200     statsHandler->setKeyEventPrintsOutStats(0);
201     viewer->addEventHandler(statsHandler);
202     // The viewer won't start without some root.
203     viewer->setSceneData(new osg::Group);
204     globals->get_renderer()->setViewer(viewer.get());
205 }
206
207 static int status = 0;
208
209 void fgOSExit(int code)
210 {
211     viewer->setDone(true);
212     status = code;
213 }
214
215 void fgOSMainLoop()
216 {
217     viewer->run();
218     fgExit(status);
219 }
220
221 int fgGetKeyModifiers()
222 {
223     return globals->get_renderer()->getManipulator()->getCurrentModifiers();
224 }
225
226 void fgWarpMouse(int x, int y)
227 {
228     globals->get_renderer()->getManipulator()->setMouseWarped();
229     // Hack, currently the pointer is just recentered. So, we know the
230     // relative coordinates ...
231     if (!mainCamera.valid()) {
232         viewer->requestWarpPointer(0, 0);
233         return;
234     }
235     float xsize = (float)mainCamera->getGraphicsContext()->getTraits()->width;
236     float ysize = (float)mainCamera->getGraphicsContext()->getTraits()->height;
237     viewer->requestWarpPointer(2.0f * (float)x / xsize - 1.0f,
238                                1.0f - 2.0f * (float)y / ysize);
239 }
240
241 // Noop
242 void fgOSInit(int* argc, char** argv)
243 {
244 }
245
246 // Noop
247 void fgOSFullScreen()
248 {
249 }
250
251 #ifdef OSG_HAS_MOUSE_CURSOR_PATCH
252 static void setMouseCursor(osg::Camera* camera, int cursor)
253 {
254     if (!camera)
255         return;
256     osg::GraphicsContext* gc = camera->getGraphicsContext();
257     if (!gc)
258         return;
259     osgViewer::GraphicsWindow* gw;
260     gw = dynamic_cast<osgViewer::GraphicsWindow*>(gc);
261     if (!gw)
262         return;
263     
264     osgViewer::GraphicsWindow::MouseCursor mouseCursor;
265     mouseCursor = osgViewer::GraphicsWindow::InheritCursor;
266     if     (cursor == MOUSE_CURSOR_NONE)
267         mouseCursor = osgViewer::GraphicsWindow::NoCursor;
268     else if(cursor == MOUSE_CURSOR_POINTER)
269         mouseCursor = osgViewer::GraphicsWindow::RightArrowCursor;
270     else if(cursor == MOUSE_CURSOR_WAIT)
271         mouseCursor = osgViewer::GraphicsWindow::WaitCursor;
272     else if(cursor == MOUSE_CURSOR_CROSSHAIR)
273         mouseCursor = osgViewer::GraphicsWindow::CrosshairCursor;
274     else if(cursor == MOUSE_CURSOR_LEFTRIGHT)
275         mouseCursor = osgViewer::GraphicsWindow::LeftRightCursor;
276
277     gw->setCursor(mouseCursor);
278 }
279 #endif
280
281 static int _cursor = -1;
282
283 void fgSetMouseCursor(int cursor)
284 {
285     _cursor = cursor;
286 #ifdef OSG_HAS_MOUSE_CURSOR_PATCH
287     setMouseCursor(viewer->getCamera(), cursor);
288     for (unsigned i = 0; i < viewer->getNumSlaves(); ++i)
289         setMouseCursor(viewer->getSlave(i)._camera.get(), cursor);
290 #endif
291 }
292
293 int fgGetMouseCursor()
294 {
295     return _cursor;
296 }
297
298 void fgMakeCurrent()
299 {
300     if (!mainCamera.valid())
301         return;
302     osg::GraphicsContext* gc = mainCamera->getGraphicsContext();
303     if (!gc)
304         return;
305     gc->makeCurrent();
306 }
307
308 bool fgOSIsMainContext(const osg::GraphicsContext* context)
309 {
310     if (!mainCamera.valid())
311         return false;
312     return context == mainCamera->getGraphicsContext();
313 }
314
315 bool fgOSIsMainCamera(const osg::Camera* camera)
316 {
317   if (!camera)
318     return false;
319   if (camera == mainCamera.get())
320     return true;
321   if (!viewer.valid())
322     return false;
323   if (camera == viewer->getCamera())
324     return true;
325   return false;
326 }