3 #include <simgear/compiler.h>
4 #include <simgear/structure/exception.hxx>
5 #include <simgear/debug/logstream.hxx>
7 #include <osg/GraphicsContext>
10 #include <osg/Viewport>
11 #include <osg/Version>
12 #include <osgViewer/StatsHandler>
13 #include <osgViewer/Viewer>
14 #include <osgGA/MatrixManipulator>
17 #include "fg_props.hxx"
19 #include "globals.hxx"
20 #include "renderer.hxx"
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
30 // fg_os implementation using OpenSceneGraph's osgViewer::Viewer class
31 // to create the graphics window and run the event/update/render loop.
33 // fg_os callback registration APIs
37 // Event handling and scene graph update is all handled by a
38 // manipulator. See FGManipulator.cpp
39 void fgRegisterIdleHandler(fgIdleHandler func)
41 globals->get_renderer()->getManipulator()->setIdleHandler(func);
44 void fgRegisterDrawHandler(fgDrawHandler func)
46 globals->get_renderer()->getManipulator()->setDrawHandler(func);
49 void fgRegisterWindowResizeHandler(fgWindowResizeHandler func)
51 globals->get_renderer()->getManipulator()->setWindowResizeHandler(func);
54 void fgRegisterKeyHandler(fgKeyHandler func)
56 globals->get_renderer()->getManipulator()->setKeyHandler(func);
59 void fgRegisterMouseClickHandler(fgMouseClickHandler func)
61 globals->get_renderer()->getManipulator()->setMouseClickHandler(func);
64 void fgRegisterMouseMotionHandler(fgMouseMotionHandler func)
66 globals->get_renderer()->getManipulator()->setMouseMotionHandler(func);
69 // Redraw "happens" every frame whether you want it or not.
70 void fgRequestRedraw()
75 // fg_os implementation
78 static osg::ref_ptr<osgViewer::Viewer> viewer;
79 static osg::ref_ptr<osg::Camera> mainCamera;
81 void fgOSOpenWindow(int w, int h, int bpp,
82 bool alpha, bool stencil, bool fullscreen)
84 osg::GraphicsContext::WindowingSystemInterface* wsi;
85 wsi = osg::GraphicsContext::getWindowingSystemInterface();
87 viewer = new osgViewer::Viewer;
88 // Avoid complications with fg's custom drawables.
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);
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;
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);
121 wsi->getScreenResolution(*traits, width, height);
122 traits->windowDecoration = false;
123 traits->width = width;
124 traits->height = height;
125 traits->supportsResize = false;
127 traits->windowDecoration = true;
131 // Ugly Hack, why does CW_USEDEFAULT works like phase of the moon?
135 traits->supportsResize = true;
138 osg::Camera::ProjectionResizePolicy rsp = osg::Camera::VERTICAL;
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)
151 // get a new copy of the traits struct
152 osg::ref_ptr<osg::GraphicsContext::Traits> cameraTraits;
153 cameraTraits = new osg::GraphicsContext::Traits(*traits);
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)) {
163 wsi->getScreenResolution(*cameraTraits, width, height);
164 cameraTraits->windowDecoration = false;
165 cameraTraits->width = width;
166 cameraTraits->height = height;
167 cameraTraits->supportsResize = false;
169 cameraTraits->windowDecoration = true;
170 cameraTraits->width = cameraNode->getIntValue("width", w);
171 cameraTraits->height = cameraNode->getIntValue("height", h);
172 cameraTraits->supportsResize = true;
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
177 cameraTraits->supportsResize = false;
179 // ok found a camera configuration, add a new slave ...
180 osg::ref_ptr<osg::Camera> camera = new osg::Camera;
182 osg::GraphicsContext* gc;
183 gc = osg::GraphicsContext::createGraphicsContext(cameraTraits.get());
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());
195 // now the main camera ...
196 osg::ref_ptr<osg::Camera> camera = new osg::Camera;
198 osg::GraphicsContext* gc;
199 gc = osg::GraphicsContext::createGraphicsContext(traits.get());
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());
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());
222 static int status = 0;
224 void fgOSExit(int code)
226 viewer->setDone(true);
236 int fgGetKeyModifiers()
238 return globals->get_renderer()->getManipulator()->getCurrentModifiers();
241 void fgWarpMouse(int x, int y)
243 // Hack, currently the pointer is just recentered. So, we know the relative coordinates ...
244 viewer->requestWarpPointer(0, 0);
248 void fgOSInit(int* argc, char** argv)
253 void fgOSFullScreen()
257 #ifdef OSG_HAS_MOUSE_CURSOR_PATCH
258 static void setMouseCursor(osg::Camera* camera, int cursor)
262 osg::GraphicsContext* gc = camera->getGraphicsContext();
265 osgViewer::GraphicsWindow* gw;
266 gw = dynamic_cast<osgViewer::GraphicsWindow*>(gc);
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;
283 gw->setCursor(mouseCursor);
287 static int _cursor = -1;
289 void fgSetMouseCursor(int 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);
299 int fgGetMouseCursor()
306 if (!mainCamera.valid())
308 osg::GraphicsContext* gc = mainCamera->getGraphicsContext();
314 bool fgOSIsMainContext(const osg::GraphicsContext* context)
316 if (!mainCamera.valid())
318 return context == mainCamera->getGraphicsContext();
321 bool fgOSIsMainCamera(const osg::Camera* camera)
325 if (camera == mainCamera.get())
329 if (camera == viewer->getCamera())