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