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