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