]> git.mxchange.org Git - flightgear.git/blob - src/Main/fg_os_osgviewer.cxx
puInitialize returns nothing.
[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 <algorithm>
26 #include <iostream>
27 #include <sstream>
28 #include <string>
29
30 #include <stdlib.h>
31
32 #include <simgear/compiler.h>
33 #include <simgear/structure/exception.hxx>
34 #include <simgear/debug/logstream.hxx>
35
36 #include <osg/GraphicsContext>
37 #include <osg/Group>
38 #include <osg/Matrixd>
39 #include <osg/Viewport>
40 #include <osg/Version>
41 #include <osg/View>
42 #include <osgViewer/ViewerEventHandlers>
43 #include <osgViewer/Viewer>
44 #include <osgGA/MatrixManipulator>
45
46 #include <Include/general.hxx>
47 #include <Scenery/scenery.hxx>
48 #include "fg_os.hxx"
49 #include "fg_props.hxx"
50 #include "util.hxx"
51 #include "globals.hxx"
52 #include "renderer.hxx"
53 #include "WindowSystemAdapter.hxx"
54
55 #if (FG_OSG_VERSION >= 19008)
56 #define OSG_HAS_MOUSE_CURSOR_PATCH
57 #endif
58
59 // fg_os implementation using OpenSceneGraph's osgViewer::Viewer class
60 // to create the graphics window and run the event/update/render loop.
61
62 //
63 // fg_os implementation
64 //
65
66 using namespace std;    
67 using namespace flightgear;
68 using namespace osg;
69
70
71
72 static osg::ref_ptr<osgViewer::Viewer> viewer;
73 static osg::ref_ptr<osg::Camera> mainCamera;
74
75 // Callback to prevent the GraphicsContext resized function from messing
76 // with the projection matrix of the slave
77
78 namespace
79 {
80 // silly function for making the default window and camera names
81 std::string makeName(const string& prefix, int num)
82 {
83     std::stringstream stream;
84     stream << prefix << num;
85     return stream.str();
86 }
87
88 GraphicsContext::Traits*
89 makeDefaultTraits(GraphicsContext::WindowingSystemInterface* wsi, bool stencil)
90 {
91     int w = fgGetInt("/sim/startup/xsize");
92     int h = fgGetInt("/sim/startup/ysize");
93     int bpp = fgGetInt("/sim/rendering/bits-per-pixel");
94     bool alpha = fgGetBool("/sim/rendering/clouds3d-enable");
95     bool fullscreen = fgGetBool("/sim/startup/fullscreen");
96
97     GraphicsContext::Traits* traits = new osg::GraphicsContext::Traits;
98     traits->readDISPLAY();
99     int cbits = (bpp <= 16) ?  5 :  8;
100     int zbits = (bpp <= 16) ? 16 : 24;
101     traits->red = traits->green = traits->blue = cbits;
102     traits->depth = zbits;
103     if (alpha)
104         traits->alpha = 8;
105     if (stencil)
106         traits->stencil = 8;
107     traits->doubleBuffer = true;
108     traits->mipMapGeneration = true;
109     traits->windowName = "FlightGear";
110     // XXX should check per window too.
111     traits->sampleBuffers = fgGetBool("/sim/rendering/multi-sample-buffers", traits->sampleBuffers);
112     traits->samples = fgGetBool("/sim/rendering/multi-samples", traits->samples);
113     traits->vsync = fgGetBool("/sim/rendering/vsync-enable", traits->vsync);
114     if (fullscreen) {
115         unsigned width = 0;
116         unsigned height = 0;
117         wsi->getScreenResolution(*traits, width, height);
118         traits->windowDecoration = false;
119         traits->width = width;
120         traits->height = height;
121         traits->supportsResize = false;
122     } else {
123         traits->windowDecoration = true;
124         traits->width = w;
125         traits->height = h;
126 #if defined(WIN32) || defined(__APPLE__)
127         // Ugly Hack, why does CW_USEDEFAULT works like phase of the moon?
128         // Mac also needs this to show window frame, menubar and Docks
129         traits->x = 100;
130         traits->y = 100;
131 #endif
132         traits->supportsResize = true;
133     }
134     return traits;
135 }
136
137 void setTraitsFromProperties(GraphicsContext::Traits* traits,
138                              const SGPropertyNode* winNode,
139                              GraphicsContext::WindowingSystemInterface* wsi)
140 {
141     traits->hostName
142         = winNode->getStringValue("host-name", traits->hostName.c_str());
143     traits->displayNum = winNode->getIntValue("display", traits->displayNum);
144     traits->screenNum = winNode->getIntValue("screen", traits->screenNum);
145     if (winNode->getBoolValue("fullscreen",
146                               fgGetBool("/sim/startup/fullscreen"))) {
147         unsigned width = 0;
148         unsigned height = 0;
149         wsi->getScreenResolution(*traits, width, height);
150         traits->windowDecoration = false;
151         traits->width = width;
152         traits->height = height;
153         traits->supportsResize = false;
154     } else {
155         traits->windowDecoration = winNode->getBoolValue("decoration", true);
156         traits->width = winNode->getIntValue("width", traits->width);
157         traits->height = winNode->getIntValue("height", traits->height);
158         traits->supportsResize = true;
159     }
160     traits->x = winNode->getIntValue("x", traits->x);
161     traits->y = winNode->getIntValue("y", traits->y);
162     if (winNode->hasChild("window-name"))
163         traits->windowName = winNode->getStringValue("window-name");
164     else if (winNode->hasChild("name")) 
165         traits->windowName = winNode->getStringValue("name");
166 }
167
168 } //namespace
169
170 void fgOSOpenWindow(bool stencil)
171 {
172     osg::GraphicsContext::WindowingSystemInterface* wsi;
173     wsi = osg::GraphicsContext::getWindowingSystemInterface();
174
175     viewer = new osgViewer::Viewer;
176     viewer->setDatabasePager(FGScenery::getPagerSingleton());
177     std::string mode;
178     mode = fgGetString("/sim/rendering/multithreading-mode", "SingleThreaded");
179     if (mode == "AutomaticSelection")
180       viewer->setThreadingModel(osgViewer::Viewer::AutomaticSelection);
181     else if (mode == "CullDrawThreadPerContext")
182       viewer->setThreadingModel(osgViewer::Viewer::CullDrawThreadPerContext);
183     else if (mode == "DrawThreadPerContext")
184       viewer->setThreadingModel(osgViewer::Viewer::DrawThreadPerContext);
185     else if (mode == "CullThreadPerCameraDrawThreadPerContext")
186       viewer->setThreadingModel(osgViewer::Viewer::CullThreadPerCameraDrawThreadPerContext);
187     else
188       viewer->setThreadingModel(osgViewer::Viewer::SingleThreaded);
189     osg::ref_ptr<osg::GraphicsContext::Traits> traits
190         = makeDefaultTraits(wsi, stencil);
191
192     // Ok, first the children.
193     // that achieves some magic ordering og the slaves so that we end up
194     // in the main window more often.
195     // This can be sorted out better when we got rid of glut and sdl.
196     FGManipulator* manipulator = globals->get_renderer()->getManipulator();
197     string defaultName("slave");
198     WindowSystemAdapter* wsa = WindowSystemAdapter::getWSA();
199     if (fgHasNode("/sim/rendering/camera")) {
200         SGPropertyNode* renderingNode = fgGetNode("/sim/rendering");
201         for (int i = 0; i < renderingNode->nChildren(); ++i) {
202             SGPropertyNode* cameraNode = renderingNode->getChild(i);
203             if (strcmp(cameraNode->getName(), "camera") != 0)
204                 continue;
205
206             // get a new copy of the traits struct
207             osg::ref_ptr<osg::GraphicsContext::Traits> cameraTraits;
208             cameraTraits = new osg::GraphicsContext::Traits(*traits);
209             double shearx = cameraNode->getDoubleValue("shear-x", 0);
210             double sheary = cameraNode->getDoubleValue("shear-y", 0);
211             setTraitsFromProperties(cameraTraits.get(), cameraNode, wsi);
212             // FIXME, currently this is too much of a problem to route
213             // the resize events. When we do no longer need sdl and
214             // such this can be simplified
215             cameraTraits->supportsResize = false;
216
217             // ok found a camera configuration, add a new slave if possible
218             GraphicsContext* gc
219                 = GraphicsContext::createGraphicsContext(cameraTraits.get());
220             if (gc) {
221                 gc->realize();
222                 Camera *camera = new Camera;
223                 camera->setGraphicsContext(gc);
224                 // If a viewport isn't set on the camera, then it's
225                 // hard to dig it out of the SceneView objects in the
226                 // viewer, and the coordinates of mouse events are
227                 // somewhat bizzare.
228                 camera->setViewport(new Viewport(0, 0, cameraTraits->width,
229                                                  cameraTraits->height));
230                 const char* cameraName = cameraNode->getStringValue("name");
231                 string cameraNameString = (cameraName ? string(cameraName)
232                                            : makeName(defaultName, i));
233                 GraphicsWindow* window = wsa->registerWindow(gc,
234                                                              cameraNameString);
235                 Camera3D* cam3D = wsa->registerCamera3D(window, camera,
236                                                         cameraNameString);
237                 if (shearx == 0 && sheary == 0)
238                     cam3D->flags |= Camera3D::MASTER;
239                 viewer->addSlave(camera, Matrix::translate(-shearx, -sheary, 0),
240                                  Matrix());
241             } else {
242                 SG_LOG(SG_GENERAL, SG_WARN,
243                        "Couldn't create graphics context on "
244                        << cameraTraits->hostName << ":"
245                        << cameraTraits->displayNum
246                        << "." << cameraTraits->screenNum);
247             }
248         }
249     }
250     // now the main camera ...
251     // XXX mainCamera's purpose is to establish a "main graphics
252     // context" that can be made current (if necessary). But that
253     // should be a context established with a window. It's used to
254     // choose whether to render the GUI and panel camera nodes, but
255     // that's obsolete because the GUI is rendered in its own
256     // slave. And it's used to translate mouse event coordinates, but
257     // that's bogus because mouse clicks should work on any camera. In
258     // short, mainCamera must die :)
259     Camera3DVector::iterator citr
260         = find_if(wsa->cameras.begin(), wsa->cameras.end(),
261                   WindowSystemAdapter::FlagTester<Camera3D>(Camera3D::MASTER));
262     if (citr == wsa->cameras.end()) {
263         // Create a camera aligned with the master camera. Eventually
264         // this will be optional.
265         Camera* camera = new osg::Camera;
266         mainCamera = camera;
267         osg::GraphicsContext* gc
268             = osg::GraphicsContext::createGraphicsContext(traits.get());
269         gc->realize();
270         gc->makeCurrent();
271         camera->setGraphicsContext(gc);
272         // If a viewport isn't set on the camera, then it's hard to dig it
273         // out of the SceneView objects in the viewer, and the coordinates
274         // of mouse events are somewhat bizzare.
275         camera->setViewport(new osg::Viewport(0, 0,
276                                               traits->width, traits->height));
277         GraphicsWindow* window = wsa->registerWindow(gc, string("main"));
278         window->flags |= GraphicsWindow::GUI;
279         Camera3D* camera3d = wsa->registerCamera3D(window, camera,
280                                                    string("main"));
281         camera3d->flags |= Camera3D::MASTER;
282         // Why a slave? It seems to be the easiest way to assign cameras,
283         // for which we've created the graphics context ourselves, to
284         // the viewer. 
285         viewer->addSlave(camera);
286     } else {
287         mainCamera = (*citr)->camera;
288     }
289     if (wsa->cameras.size() != 1) {
290         manipulator->setResizable(false);
291     }
292     viewer->getCamera()->setProjectionResizePolicy(osg::Camera::FIXED);
293     viewer->setCameraManipulator(manipulator);
294     // Let FG handle the escape key with a confirmation
295     viewer->setKeyEventSetsDone(0);
296     // The viewer won't start without some root.
297     viewer->setSceneData(new osg::Group);
298     globals->get_renderer()->setViewer(viewer.get());
299 }
300
301 static int status = 0;
302
303 void fgOSExit(int code)
304 {
305     viewer->setDone(true);
306     viewer->getDatabasePager()->cancel();
307     status = code;
308 }
309
310 void fgOSMainLoop()
311 {
312     viewer->run();
313     fgExit(status);
314 }
315
316 int fgGetKeyModifiers()
317 {
318     return globals->get_renderer()->getManipulator()->getCurrentModifiers();
319 }
320
321 void fgWarpMouse(int x, int y)
322 {
323     globals->get_renderer()->getManipulator()->setMouseWarped();
324     // Hack, currently the pointer is just recentered. So, we know the
325     // relative coordinates ...
326     if (!mainCamera.valid()) {
327         viewer->requestWarpPointer(0, 0);
328         return;
329     }
330     float xsize = (float)mainCamera->getGraphicsContext()->getTraits()->width;
331     float ysize = (float)mainCamera->getGraphicsContext()->getTraits()->height;
332     viewer->requestWarpPointer(2.0f * (float)x / xsize - 1.0f,
333                                1.0f - 2.0f * (float)y / ysize);
334 }
335
336 void fgOSInit(int* argc, char** argv)
337 {
338     WindowSystemAdapter::setWSA(new WindowSystemAdapter);
339 }
340
341 // Noop
342 void fgOSFullScreen()
343 {
344 }
345
346 #ifdef OSG_HAS_MOUSE_CURSOR_PATCH
347 static void setMouseCursor(osg::Camera* camera, int cursor)
348 {
349     if (!camera)
350         return;
351     osg::GraphicsContext* gc = camera->getGraphicsContext();
352     if (!gc)
353         return;
354     osgViewer::GraphicsWindow* gw;
355     gw = dynamic_cast<osgViewer::GraphicsWindow*>(gc);
356     if (!gw)
357         return;
358     
359     osgViewer::GraphicsWindow::MouseCursor mouseCursor;
360     mouseCursor = osgViewer::GraphicsWindow::InheritCursor;
361     if     (cursor == MOUSE_CURSOR_NONE)
362         mouseCursor = osgViewer::GraphicsWindow::NoCursor;
363     else if(cursor == MOUSE_CURSOR_POINTER)
364         mouseCursor = osgViewer::GraphicsWindow::RightArrowCursor;
365     else if(cursor == MOUSE_CURSOR_WAIT)
366         mouseCursor = osgViewer::GraphicsWindow::WaitCursor;
367     else if(cursor == MOUSE_CURSOR_CROSSHAIR)
368         mouseCursor = osgViewer::GraphicsWindow::CrosshairCursor;
369     else if(cursor == MOUSE_CURSOR_LEFTRIGHT)
370         mouseCursor = osgViewer::GraphicsWindow::LeftRightCursor;
371
372     gw->setCursor(mouseCursor);
373 }
374 #endif
375
376 static int _cursor = -1;
377
378 void fgSetMouseCursor(int cursor)
379 {
380     _cursor = cursor;
381 #ifdef OSG_HAS_MOUSE_CURSOR_PATCH
382     setMouseCursor(viewer->getCamera(), cursor);
383     for (unsigned i = 0; i < viewer->getNumSlaves(); ++i)
384         setMouseCursor(viewer->getSlave(i)._camera.get(), cursor);
385 #endif
386 }
387
388 int fgGetMouseCursor()
389 {
390     return _cursor;
391 }
392
393 bool fgOSIsMainContext(const osg::GraphicsContext* context)
394 {
395     if (!mainCamera.valid())
396         return false;
397     return context == mainCamera->getGraphicsContext();
398 }
399
400 bool fgOSIsMainCamera(const osg::Camera* camera)
401 {
402   if (!camera)
403     return false;
404   if (camera == mainCamera.get())
405     return true;
406   if (!viewer.valid())
407     return false;
408   if (camera == viewer->getCamera())
409     return true;
410   return false;
411 }
412
413 GraphicsContext* fgOSGetMainContext()
414 {
415     WindowSystemAdapter* wsa = WindowSystemAdapter::getWSA();
416     WindowVector::iterator contextIter
417         = std::find_if(wsa->windows.begin(), wsa->windows.end(),
418                        WindowSystemAdapter::FlagTester<GraphicsWindow>(GraphicsWindow::GUI));
419     if (contextIter == wsa->windows.end())
420         return 0;
421     else
422         return (*contextIter)->gc.get();
423 }
424