]> git.mxchange.org Git - flightgear.git/blob - src/Main/fg_os_osgviewer.cxx
63bb3e41e6101cb538ab74a8ad3d2588bcd9bf87
[flightgear.git] / src / Main / fg_os_osgviewer.cxx
1 // fg_os_common.cxx -- common functions for fg_os interface
2 // implemented as an osgViewer
3 //
4 // Copyright (C) 2007  Tim Moore timoore@redhat.com
5 // Copyright (C) 2007 Mathias Froehlich 
6 //
7 // This program is free software; you can redistribute it and/or
8 // modify it under the terms of the GNU General Public License as
9 // published by the Free Software Foundation; either version 2 of the
10 // License, or (at your option) any later version.
11 //
12 // This program is distributed in the hope that it will be useful, but
13 // WITHOUT ANY WARRANTY; without even the implied warranty of
14 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
15 // General Public License for more details.
16 //
17 // You should have received a copy of the GNU General Public License
18 // along with this program; if not, write to the Free Software
19 // Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
20
21 #ifdef HAVE_CONFIG_H
22 #  include <config.h>
23 #endif
24
25 #include <stdlib.h>
26
27 #include <simgear/compiler.h>
28 #include <simgear/structure/exception.hxx>
29 #include <simgear/debug/logstream.hxx>
30
31 #include <osg/GraphicsContext>
32 #include <osg/Group>
33 #include <osg/Matrixd>
34 #include <osg/Viewport>
35 #include <osg/Version>
36 #include <osgViewer/ViewerEventHandlers>
37 #include <osgViewer/Viewer>
38 #include <osgGA/MatrixManipulator>
39
40 #include <Include/general.hxx>
41 #include <Scenery/scenery.hxx>
42 #include "fg_os.hxx"
43 #include "fg_props.hxx"
44 #include "util.hxx"
45 #include "globals.hxx"
46 #include "renderer.hxx"
47
48 #if (FG_OSG_VERSION >= 19008)
49 #define OSG_HAS_MOUSE_CURSOR_PATCH
50 #endif
51
52 // fg_os implementation using OpenSceneGraph's osgViewer::Viewer class
53 // to create the graphics window and run the event/update/render loop.
54
55 //
56 // fg_os implementation
57 //
58
59 static osg::ref_ptr<osgViewer::Viewer> viewer;
60 static osg::ref_ptr<osg::Camera> mainCamera;
61
62 void fgOSOpenWindow(int w, int h, int bpp,
63                     bool alpha, bool stencil, bool fullscreen)
64 {
65     osg::GraphicsContext::WindowingSystemInterface* wsi;
66     wsi = osg::GraphicsContext::getWindowingSystemInterface();
67
68     viewer = new osgViewer::Viewer;
69     viewer->setDatabasePager(FGScenery::getPagerSingleton());
70     // Avoid complications with fg's custom drawables.
71     std::string mode;
72     mode = fgGetString("/sim/rendering/multithreading-mode", "SingleThreaded");
73     if (mode == "AutomaticSelection")
74       viewer->setThreadingModel(osgViewer::Viewer::AutomaticSelection);
75     else if (mode == "CullDrawThreadPerContext")
76       viewer->setThreadingModel(osgViewer::Viewer::CullDrawThreadPerContext);
77     else if (mode == "DrawThreadPerContext")
78       viewer->setThreadingModel(osgViewer::Viewer::DrawThreadPerContext);
79     else if (mode == "CullThreadPerCameraDrawThreadPerContext")
80       viewer->setThreadingModel(osgViewer::Viewer::CullThreadPerCameraDrawThreadPerContext);
81     else
82       viewer->setThreadingModel(osgViewer::Viewer::SingleThreaded);
83     osg::ref_ptr<osg::GraphicsContext::Traits> traits;
84     traits = new osg::GraphicsContext::Traits;
85     traits->readDISPLAY();
86     int cbits = (bpp <= 16) ?  5 :  8;
87     int zbits = (bpp <= 16) ? 16 : 24;
88     traits->red = traits->green = traits->blue = cbits;
89     traits->depth = zbits;
90     if (alpha)
91         traits->alpha = 8;
92     if (stencil)
93         traits->stencil = 8;
94     traits->doubleBuffer = true;
95     traits->mipMapGeneration = true;
96     traits->windowName = "FlightGear";
97     traits->sampleBuffers = fgGetBool("/sim/rendering/multi-sample-buffers", traits->sampleBuffers);
98     traits->samples = fgGetBool("/sim/rendering/multi-samples", traits->samples);
99     traits->vsync = fgGetBool("/sim/rendering/vsync-enable", traits->vsync);
100
101     if (fullscreen) {
102         unsigned width = 0;
103         unsigned height = 0;
104         wsi->getScreenResolution(*traits, width, height);
105         traits->windowDecoration = false;
106         traits->width = width;
107         traits->height = height;
108         traits->supportsResize = false;
109     } else {
110         traits->windowDecoration = true;
111         traits->width = w;
112         traits->height = h;
113 #ifdef WIN32
114         // Ugly Hack, why does CW_USEDEFAULT works like phase of the moon?
115         traits->x = 100;
116         traits->y = 100;
117 #endif
118         traits->supportsResize = true;
119     }
120
121     osg::Camera::ProjectionResizePolicy rsp = osg::Camera::VERTICAL;
122
123     // Ok, first the children.
124     // that achieves some magic ordering og the slaves so that we end up
125     // in the main window more often.
126     // This can be sorted out better when we got rid of glut and sdl.
127     FGManipulator* manipulator = globals->get_renderer()->getManipulator();
128     int nCameras = 0;
129     if (fgHasNode("/sim/rendering/camera")) {
130       SGPropertyNode* renderingNode = fgGetNode("/sim/rendering");
131       for (int i = 0; i < renderingNode->nChildren(); ++i) {
132         SGPropertyNode* cameraNode = renderingNode->getChild(i);
133         if (strcmp(cameraNode->getName(), "camera") != 0)
134           continue;
135
136         nCameras++;
137         // get a new copy of the traits struct
138         osg::ref_ptr<osg::GraphicsContext::Traits> cameraTraits;
139         cameraTraits = new osg::GraphicsContext::Traits(*traits);
140
141         double shearx = cameraNode->getDoubleValue("shear-x", 0);
142         double sheary = cameraNode->getDoubleValue("shear-y", 0);
143         cameraTraits->hostName
144           = cameraNode->getStringValue("host-name", traits->hostName.c_str());
145         cameraTraits->displayNum
146           = cameraNode->getIntValue("display", traits->displayNum);
147         cameraTraits->screenNum
148           = cameraNode->getIntValue("screen", traits->screenNum);
149         if (cameraNode->getBoolValue("fullscreen", fullscreen)) {
150           unsigned width = 0;
151           unsigned height = 0;
152           wsi->getScreenResolution(*cameraTraits, width, height);
153           cameraTraits->windowDecoration = false;
154           cameraTraits->width = width;
155           cameraTraits->height = height;
156           cameraTraits->supportsResize = false;
157         } else {
158           cameraTraits->windowDecoration = true;
159           cameraTraits->width = cameraNode->getIntValue("width", w);
160           cameraTraits->height = cameraNode->getIntValue("height", h);
161           cameraTraits->supportsResize = true;
162         }
163         // FIXME, currently this is too much of a problem to route the resize
164         // events. When we do no longer need sdl and such this
165         // can be simplified
166         cameraTraits->supportsResize = false;
167
168         // ok found a camera configuration, add a new slave ...
169         osg::ref_ptr<osg::Camera> camera = new osg::Camera;
170
171         osg::GraphicsContext* gc;
172         gc = osg::GraphicsContext::createGraphicsContext(cameraTraits.get());
173         gc->realize();
174         camera->setGraphicsContext(gc);
175         // If a viewport isn't set on the camera, then it's hard to dig it
176         // out of the SceneView objects in the viewer, and the coordinates
177         // of mouse events are somewhat bizzare.
178         camera->setViewport(new osg::Viewport(0, 0, cameraTraits->width, cameraTraits->height));
179         camera->setProjectionResizePolicy(rsp);
180         viewer->addSlave(camera.get(), osg::Matrix::translate(-shearx, -sheary, 0), osg::Matrix());
181       }
182       if (nCameras > 1)
183         manipulator->setResizable(false);
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     globals->get_renderer()->getManipulator()->setMouseWarped();
235     // Hack, currently the pointer is just recentered. So, we know the
236     // relative coordinates ...
237     if (!mainCamera.valid()) {
238         viewer->requestWarpPointer(0, 0);
239         return;
240     }
241     float xsize = (float)mainCamera->getGraphicsContext()->getTraits()->width;
242     float ysize = (float)mainCamera->getGraphicsContext()->getTraits()->height;
243     viewer->requestWarpPointer(2.0f * (float)x / xsize - 1.0f,
244                                1.0f - 2.0f * (float)y / ysize);
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 }