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