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