8 #include <simgear/compiler.h>
9 #include <simgear/structure/exception.hxx>
10 #include <simgear/debug/logstream.hxx>
12 #include <osg/GraphicsContext>
14 #include <osg/Matrixd>
15 #include <osg/Viewport>
16 #include <osg/Version>
17 #include <osgViewer/ViewerEventHandlers>
18 #include <osgViewer/Viewer>
19 #include <osgGA/MatrixManipulator>
22 #include "fg_props.hxx"
24 #include "globals.hxx"
25 #include "renderer.hxx"
27 #if ((2 <= OSG_VERSION_MAJOR) || \
28 (1 == OSG_VERSION_MAJOR) && (9 == OSG_VERSION_MINOR) && \
29 (8 <= OSG_VERSION_PATCH)) || \
30 ((1 == OSG_VERSION_MAJOR) && (9 < OSG_VERSION_MINOR)) || \
31 (1 < OSG_VERSION_MAJOR)
32 #define OSG_HAS_MOUSE_CURSOR_PATCH
35 // fg_os implementation using OpenSceneGraph's osgViewer::Viewer class
36 // to create the graphics window and run the event/update/render loop.
38 // fg_os callback registration APIs
42 // Event handling and scene graph update is all handled by a
43 // manipulator. See FGManipulator.cpp
44 void fgRegisterIdleHandler(fgIdleHandler func)
46 globals->get_renderer()->getManipulator()->setIdleHandler(func);
49 void fgRegisterDrawHandler(fgDrawHandler func)
51 globals->get_renderer()->getManipulator()->setDrawHandler(func);
54 void fgRegisterWindowResizeHandler(fgWindowResizeHandler func)
56 globals->get_renderer()->getManipulator()->setWindowResizeHandler(func);
59 void fgRegisterKeyHandler(fgKeyHandler func)
61 globals->get_renderer()->getManipulator()->setKeyHandler(func);
64 void fgRegisterMouseClickHandler(fgMouseClickHandler func)
66 globals->get_renderer()->getManipulator()->setMouseClickHandler(func);
69 void fgRegisterMouseMotionHandler(fgMouseMotionHandler func)
71 globals->get_renderer()->getManipulator()->setMouseMotionHandler(func);
74 // Redraw "happens" every frame whether you want it or not.
75 void fgRequestRedraw()
80 // fg_os implementation
83 static osg::ref_ptr<osgViewer::Viewer> viewer;
84 static osg::ref_ptr<osg::Camera> mainCamera;
86 void fgOSOpenWindow(int w, int h, int bpp,
87 bool alpha, bool stencil, bool fullscreen)
89 osg::GraphicsContext::WindowingSystemInterface* wsi;
90 wsi = osg::GraphicsContext::getWindowingSystemInterface();
92 viewer = new osgViewer::Viewer;
93 // Avoid complications with fg's custom drawables.
95 mode = fgGetString("/sim/rendering/multithreading-mode", "SingleThreaded");
96 if (mode == "AutomaticSelection")
97 viewer->setThreadingModel(osgViewer::Viewer::AutomaticSelection);
98 else if (mode == "CullDrawThreadPerContext")
99 viewer->setThreadingModel(osgViewer::Viewer::CullDrawThreadPerContext);
100 else if (mode == "DrawThreadPerContext")
101 viewer->setThreadingModel(osgViewer::Viewer::DrawThreadPerContext);
102 else if (mode == "CullThreadPerCameraDrawThreadPerContext")
103 viewer->setThreadingModel(osgViewer::Viewer::CullThreadPerCameraDrawThreadPerContext);
105 viewer->setThreadingModel(osgViewer::Viewer::SingleThreaded);
106 osg::ref_ptr<osg::GraphicsContext::Traits> traits;
107 traits = new osg::GraphicsContext::Traits;
108 int cbits = (bpp <= 16) ? 5 : 8;
109 int zbits = (bpp <= 16) ? 16 : 24;
110 traits->red = traits->green = traits->blue = cbits;
111 traits->depth = zbits;
116 traits->doubleBuffer = true;
117 traits->mipMapGeneration = true;
118 traits->windowName = "FlightGear";
119 traits->sampleBuffers = fgGetBool("/sim/rendering/multi-sample-buffers", traits->sampleBuffers);
120 traits->samples = fgGetBool("/sim/rendering/multi-samples", traits->samples);
121 traits->vsync = fgGetBool("/sim/rendering/vsync-enable", traits->vsync);
126 wsi->getScreenResolution(*traits, width, height);
127 traits->windowDecoration = false;
128 traits->width = width;
129 traits->height = height;
130 traits->supportsResize = false;
132 traits->windowDecoration = true;
136 // Ugly Hack, why does CW_USEDEFAULT works like phase of the moon?
140 traits->supportsResize = true;
143 osg::Camera::ProjectionResizePolicy rsp = osg::Camera::VERTICAL;
145 // Ok, first the children.
146 // that achieves some magic ordering og the slaves so that we end up
147 // in the main window more often.
148 // This can be sorted out better when we got rid of glut and sdl.
149 FGManipulator* manipulator = globals->get_renderer()->getManipulator();
151 if (fgHasNode("/sim/rendering/camera")) {
152 SGPropertyNode* renderingNode = fgGetNode("/sim/rendering");
153 for (int i = 0; i < renderingNode->nChildren(); ++i) {
154 SGPropertyNode* cameraNode = renderingNode->getChild(i);
155 if (strcmp(cameraNode->getName(), "camera") != 0)
159 // get a new copy of the traits struct
160 osg::ref_ptr<osg::GraphicsContext::Traits> cameraTraits;
161 cameraTraits = new osg::GraphicsContext::Traits(*traits);
163 double shearx = cameraNode->getDoubleValue("shear-x", 0);
164 double sheary = cameraNode->getDoubleValue("shear-y", 0);
165 cameraTraits->hostName = cameraNode->getStringValue("host-name", "");
166 cameraTraits->displayNum = cameraNode->getIntValue("display", 0);
167 cameraTraits->screenNum = cameraNode->getIntValue("screen", 0);
168 if (cameraNode->getBoolValue("fullscreen", fullscreen)) {
171 wsi->getScreenResolution(*cameraTraits, width, height);
172 cameraTraits->windowDecoration = false;
173 cameraTraits->width = width;
174 cameraTraits->height = height;
175 cameraTraits->supportsResize = false;
177 cameraTraits->windowDecoration = true;
178 cameraTraits->width = cameraNode->getIntValue("width", w);
179 cameraTraits->height = cameraNode->getIntValue("height", h);
180 cameraTraits->supportsResize = true;
182 // FIXME, currently this is too much of a problem to route the resize
183 // events. When we do no longer need sdl and such this
185 cameraTraits->supportsResize = false;
187 // ok found a camera configuration, add a new slave ...
188 osg::ref_ptr<osg::Camera> camera = new osg::Camera;
190 osg::GraphicsContext* gc;
191 gc = osg::GraphicsContext::createGraphicsContext(cameraTraits.get());
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, cameraTraits->width, cameraTraits->height));
198 camera->setProjectionResizePolicy(rsp);
199 viewer->addSlave(camera.get(), osg::Matrix::translate(-shearx, -sheary, 0), osg::Matrix());
202 manipulator->setResizable(false);
205 // now the main camera ...
206 osg::ref_ptr<osg::Camera> camera = new osg::Camera;
208 osg::GraphicsContext* gc;
209 gc = osg::GraphicsContext::createGraphicsContext(traits.get());
212 camera->setGraphicsContext(gc);
213 // If a viewport isn't set on the camera, then it's hard to dig it
214 // out of the SceneView objects in the viewer, and the coordinates
215 // of mouse events are somewhat bizzare.
216 camera->setViewport(new osg::Viewport(0, 0, traits->width, traits->height));
217 camera->setProjectionResizePolicy(rsp);
218 viewer->addSlave(camera.get());
220 viewer->setCameraManipulator(globals->get_renderer()->getManipulator());
221 // Let FG handle the escape key with a confirmation
222 viewer->setKeyEventSetsDone(0);
223 osgViewer::StatsHandler* statsHandler = new osgViewer::StatsHandler;
224 statsHandler->setKeyEventTogglesOnScreenStats('*');
225 statsHandler->setKeyEventPrintsOutStats(0);
226 viewer->addEventHandler(statsHandler);
227 // The viewer won't start without some root.
228 viewer->setSceneData(new osg::Group);
229 globals->get_renderer()->setViewer(viewer.get());
232 static int status = 0;
234 void fgOSExit(int code)
236 viewer->setDone(true);
246 int fgGetKeyModifiers()
248 return globals->get_renderer()->getManipulator()->getCurrentModifiers();
251 void fgWarpMouse(int x, int y)
253 // Hack, currently the pointer is just recentered. So, we know the
254 // relative coordinates ...
255 if (!mainCamera.valid()) {
256 viewer->requestWarpPointer(0, 0);
259 float xsize = (float)mainCamera->getGraphicsContext()->getTraits()->width;
260 float ysize = (float)mainCamera->getGraphicsContext()->getTraits()->height;
261 viewer->requestWarpPointer(2.0f * (float)x / xsize - 1.0f,
262 1.0f - 2.0f * (float)y / ysize);
267 void fgOSInit(int* argc, char** argv)
272 void fgOSFullScreen()
276 #ifdef OSG_HAS_MOUSE_CURSOR_PATCH
277 static void setMouseCursor(osg::Camera* camera, int cursor)
281 osg::GraphicsContext* gc = camera->getGraphicsContext();
284 osgViewer::GraphicsWindow* gw;
285 gw = dynamic_cast<osgViewer::GraphicsWindow*>(gc);
289 osgViewer::GraphicsWindow::MouseCursor mouseCursor;
290 mouseCursor = osgViewer::GraphicsWindow::InheritCursor;
291 if (cursor == MOUSE_CURSOR_NONE)
292 mouseCursor = osgViewer::GraphicsWindow::NoCursor;
293 else if(cursor == MOUSE_CURSOR_POINTER)
294 mouseCursor = osgViewer::GraphicsWindow::RightArrowCursor;
295 else if(cursor == MOUSE_CURSOR_WAIT)
296 mouseCursor = osgViewer::GraphicsWindow::WaitCursor;
297 else if(cursor == MOUSE_CURSOR_CROSSHAIR)
298 mouseCursor = osgViewer::GraphicsWindow::CrosshairCursor;
299 else if(cursor == MOUSE_CURSOR_LEFTRIGHT)
300 mouseCursor = osgViewer::GraphicsWindow::LeftRightCursor;
302 gw->setCursor(mouseCursor);
306 static int _cursor = -1;
308 void fgSetMouseCursor(int cursor)
311 #ifdef OSG_HAS_MOUSE_CURSOR_PATCH
312 setMouseCursor(viewer->getCamera(), cursor);
313 for (unsigned i = 0; i < viewer->getNumSlaves(); ++i)
314 setMouseCursor(viewer->getSlave(i)._camera.get(), cursor);
318 int fgGetMouseCursor()
325 if (!mainCamera.valid())
327 osg::GraphicsContext* gc = mainCamera->getGraphicsContext();
333 bool fgOSIsMainContext(const osg::GraphicsContext* context)
335 if (!mainCamera.valid())
337 return context == mainCamera->getGraphicsContext();
340 bool fgOSIsMainCamera(const osg::Camera* camera)
344 if (camera == mainCamera.get())
348 if (camera == viewer->getCamera())