3 #include <osgViewer/ViewerEventHandlers>
4 #include <osgViewer/Viewer>
6 #include <simgear/compiler.h>
7 #include <simgear/structure/exception.hxx>
8 #include <simgear/debug/logstream.hxx>
12 #include <Scenery/scenery.hxx>
14 #include "globals.hxx"
15 #include "renderer.hxx"
16 #include "fg_props.hxx"
17 #include "WindowSystemAdapter.hxx"
19 using namespace flightgear;
22 // fg_os callback registration APIs
25 static int CurrentModifiers = 0;
26 static int CurrentMouseX = 0;
27 static int CurrentMouseY = 0;
28 static int CurrentMouseCursor = MOUSE_CURSOR_POINTER;
29 static int VidMask = SDL_OPENGL|SDL_RESIZABLE;
32 // fg_os implementation
34 static void initCursors();
36 static osg::ref_ptr<osgViewer::Viewer> viewer;
37 static osg::ref_ptr<osg::Camera> mainCamera;
38 static osg::ref_ptr<osgViewer::GraphicsWindowEmbedded> gw;
40 void fgOSOpenWindow(bool stencil)
42 int w = fgGetInt("/sim/startup/xsize");
43 int h = fgGetInt("/sim/startup/ysize");
44 int bpp = fgGetInt("/sim/rendering/bits-per-pixel");
45 bool alpha = fgGetBool("/sim/rendering/clouds3d-enable");
46 bool fullscreen = fgGetBool("/sim/startup/fullscreen");
47 int cbits = (bpp <= 16) ? 5 : 8;
48 int zbits = (bpp <= 16) ? 16 : 24;
49 WindowSystemAdapter* wsa = WindowSystemAdapter::getWSA();
51 if (SDL_Init(SDL_INIT_VIDEO|SDL_INIT_NOPARACHUTE) == -1)
52 throw sg_throwable(string("Failed to initialize SDL: ")
56 SDL_WM_SetCaption("FlightGear", "FlightGear");
58 SDL_GL_SetAttribute(SDL_GL_RED_SIZE, cbits);
59 SDL_GL_SetAttribute(SDL_GL_GREEN_SIZE, cbits);
60 SDL_GL_SetAttribute(SDL_GL_BLUE_SIZE, cbits);
62 SDL_GL_SetAttribute(SDL_GL_ALPHA_SIZE, 8);
63 if(bpp > 16 && stencil)
64 SDL_GL_SetAttribute(SDL_GL_STENCIL_SIZE, 8);
65 SDL_GL_SetAttribute(SDL_GL_DEPTH_SIZE, zbits);
66 SDL_GL_SetAttribute(SDL_GL_DOUBLEBUFFER, 1);
69 VidMask |= SDL_FULLSCREEN;
71 SDL_Surface* screen = SDL_SetVideoMode(w, h, 16, VidMask);
73 throw sg_throwable(string("Failed to set SDL video mode: ")
76 // This enables keycode translation (e.g. capital letters when
77 // shift is pressed, as well as i18n input methods). Eventually,
78 // we may want to port the input maps to specify <mod-shift>
79 // explicitly, and will turn this off.
81 SDL_EnableKeyRepeat(SDL_DEFAULT_REPEAT_DELAY, SDL_DEFAULT_REPEAT_INTERVAL);
84 fgSetMouseCursor(MOUSE_CURSOR_POINTER);
86 // FIXME: we may not get what we asked for (especially in full
87 // screen modes), so these need to be propagated back to the
88 // property tree for the rest of the code to inspect...
90 int realw = screen->w;
91 int realh = screen->h;
92 viewer = new osgViewer::Viewer;
93 viewer->setDatabasePager(FGScenery::getPagerSingleton());
94 gw = viewer->setUpViewerAsEmbeddedInWindow(0, 0, realw, realh);
95 GraphicsWindow* window = wsa->registerWindow(gw.get(), string("main"));
96 window->flags |= GraphicsWindow::GUI;
97 // now the main camera ...
98 osg::Camera* camera = new osg::Camera;
100 // If a viewport isn't set on the camera, then it's hard to dig it
101 // out of the SceneView objects in the viewer, and the coordinates
102 // of mouse events are somewhat bizzare.
103 camera->setViewport(new osg::Viewport(0, 0, realw, realh));
104 camera->setProjectionResizePolicy(osg::Camera::FIXED);
105 Camera3D* cam3D = wsa->registerCamera3D(window, camera, string("main"));
106 cam3D->flags |= Camera3D::MASTER;
107 // Add as a slave for compatibility with the non-embedded osgViewer.
108 viewer->addSlave(camera);
109 viewer->setCameraManipulator(globals->get_renderer()->getManipulator());
110 // Let FG handle the escape key with a confirmation
111 viewer->setKeyEventSetsDone(0);
112 osgViewer::StatsHandler* statsHandler = new osgViewer::StatsHandler;
113 statsHandler->setKeyEventTogglesOnScreenStats('*');
114 statsHandler->setKeyEventPrintsOutStats(0);
115 viewer->addEventHandler(statsHandler);
116 // The viewer won't start without some root.
117 viewer->setSceneData(new osg::Group);
118 globals->get_renderer()->setViewer(viewer.get());
121 // Cheap trick to avoid typing GUIEventAdapter over and over...
122 class SDLKeyTranslator : osgGA::GUIEventAdapter
125 static int handleKey(int key, int raw, int keyup);
128 int SDLKeyTranslator::handleKey(int key, int raw, int keyup)
130 using namespace osgGA;
136 // Don't pass capslock or numlock to the FGManipulator; SDL
137 // already transforms the key properly, so FGManipulator will get
139 if (key == SDLK_CAPSLOCK || key == SDLK_NUMLOCK)
142 case SDLK_RSHIFT: modmask = KEYMOD_SHIFT; osgKey = KEY_Shift_R; break;
143 case SDLK_LSHIFT: modmask = KEYMOD_SHIFT; osgKey = KEY_Shift_L; break;
144 case SDLK_RCTRL: modmask = KEYMOD_CTRL; osgKey = KEY_Control_R; break;
145 case SDLK_LCTRL: modmask = KEYMOD_CTRL; osgKey = KEY_Control_L; break;
146 case SDLK_RALT: modmask = KEYMOD_ALT; osgKey = KEY_Alt_R; break;
147 case SDLK_LALT: modmask = KEYMOD_ALT; osgKey = KEY_Alt_L; break;
148 case SDLK_RMETA: modmask = KEYMOD_META; osgKey = KEY_Meta_R; break;
149 case SDLK_LMETA: modmask = KEYMOD_META; osgKey = KEY_Meta_L; break;
150 case SDLK_RSUPER: modmask = KEYMOD_SUPER; osgKey = KEY_Super_R; break;
151 case SDLK_LSUPER: modmask = KEYMOD_SUPER; osgKey = KEY_Super_L; break;
153 case SDLK_LEFT: osgKey = KEY_Left; break;
154 case SDLK_UP: osgKey = KEY_Up; break;
155 case SDLK_RIGHT: osgKey = KEY_Right; break;
156 case SDLK_DOWN: osgKey = KEY_Down; break;
157 case SDLK_PAGEUP: osgKey = KEY_Page_Up; break;
158 case SDLK_PAGEDOWN: osgKey = KEY_Page_Down; break;
159 case SDLK_HOME: osgKey = KEY_Home; break;
160 case SDLK_END: osgKey = KEY_End; break;
161 case SDLK_INSERT: osgKey = KEY_Insert; break;
162 case SDLK_F1: osgKey = KEY_F1; break;
163 case SDLK_F2: osgKey = KEY_F2; break;
164 case SDLK_F3: osgKey = KEY_F3; break;
165 case SDLK_F4: osgKey = KEY_F4; break;
166 case SDLK_F5: osgKey = KEY_F5; break;
167 case SDLK_F6: osgKey = KEY_F6; break;
168 case SDLK_F7: osgKey = KEY_F7; break;
169 case SDLK_F8: osgKey = KEY_F8; break;
170 case SDLK_F9: osgKey = KEY_F9; break;
171 case SDLK_F10: osgKey = KEY_F10; break;
172 case SDLK_F11: osgKey = KEY_F11; break;
173 case SDLK_F12: osgKey = KEY_F12; break;
179 CurrentModifiers &= ~modmask;
180 keymod = CurrentModifiers | KEYMOD_RELEASED;
182 CurrentModifiers |= modmask;
183 keymod = CurrentModifiers & ~KEYMOD_RELEASED;
188 // FIXME: Integrate with existing fgExit() in util.cxx.
189 void fgOSExit(int code)
191 viewer->setDone(true);
195 // originally from osgexamples/osgviewerSDL.cpp
196 bool convertEvent(SDL_Event& event, osgGA::EventQueue& eventQueue)
198 using namespace osgGA;
199 switch (event.type) {
201 case SDL_MOUSEMOTION:
202 eventQueue.mouseMotion(event.motion.x, event.motion.y);
205 case SDL_MOUSEBUTTONDOWN:
206 eventQueue.mouseButtonPress(event.button.x, event.button.y, event.button.button);
209 case SDL_MOUSEBUTTONUP:
210 eventQueue.mouseButtonRelease(event.button.x, event.button.y, event.button.button);
216 int realKey = SDLKeyTranslator::handleKey(event.key.keysym.unicode,
217 event.key.keysym.sym,
218 event.type == SDL_KEYUP);
221 if (event.type == SDL_KEYUP)
222 eventQueue.keyRelease((osgGA::GUIEventAdapter::KeySymbol)realKey);
224 eventQueue.keyPress((osgGA::GUIEventAdapter::KeySymbol)realKey);
227 case SDL_VIDEORESIZE:
228 if (SDL_SetVideoMode(event.resize.w, event.resize.h, 16, VidMask) == 0)
229 throw sg_throwable(string("Failed to set SDL video mode: ")
231 eventQueue.windowResize(0, 0, event.resize.w, event.resize.h );
245 while(SDL_PollEvent(&e)) {
246 // pass the SDL event into the viewers event queue
247 convertEvent(e, *(gw->getEventQueue()));
253 case SDL_VIDEORESIZE:
254 gw->resized(0, 0, e.resize.w, e.resize.h );
258 // draw the new frame
262 SDL_GL_SwapBuffers();
266 int fgGetKeyModifiers()
268 return CurrentModifiers;
271 void fgWarpMouse(int x, int y)
273 globals->get_renderer()->getManipulator()->setMouseWarped();
277 void fgOSInit(int* argc, char** argv)
279 WindowSystemAdapter::setWSA(new WindowSystemAdapter);
282 void fgOSFullScreen()
284 // Noop. SDL must set fullscreen at window open time and cannot
288 static struct cursor_rec {
290 SDL_Cursor* sdlCursor;
295 const char *img[32]; // '.' == white, '#' == black, ' ' == transparent
297 { MOUSE_CURSOR_POINTER, 0, // must be first!
315 { MOUSE_CURSOR_CROSSHAIR, 0,
334 { MOUSE_CURSOR_WAIT, 0,
352 { MOUSE_CURSOR_LEFTRIGHT, 0,
363 { MOUSE_CURSOR_NONE, 0, // must come last!
364 1, 1, 0, 0, { " " } },
367 #define NCURSORS (sizeof(cursors)/sizeof(struct cursor_rec))
369 void fgSetMouseCursor(int cursor)
371 if(cursor == MOUSE_CURSOR_NONE) {
372 SDL_ShowCursor(SDL_DISABLE);
375 SDL_ShowCursor(SDL_ENABLE);
376 for(unsigned int i=0; i<NCURSORS; i++) {
377 if(cursor == cursors[i].name) {
378 CurrentMouseCursor = cursor;
379 SDL_SetCursor(cursors[i].sdlCursor);
383 // Default to pointer
384 CurrentMouseCursor = MOUSE_CURSOR_POINTER;
385 SDL_SetCursor(cursors[0].sdlCursor);
388 int fgGetMouseCursor()
390 return CurrentMouseCursor;
393 static void initCursors()
395 unsigned char mask[128], img[128];
396 for(unsigned int i=0; i<NCURSORS; i++) {
397 if(cursors[i].name == MOUSE_CURSOR_NONE) break;
398 for(int j=0; j<128; j++) mask[j] = img[j] = 0;
399 for(int y=0; y<cursors[i].h; y++) {
400 for(int x=0; x<cursors[i].w; x++) {
401 int byte = (4 * y) + (x >> 3);
402 int bit = 1 << (7 - (x & 7));
403 int pix = cursors[i].img[y][x];
404 if(pix != ' ') { mask[byte] |= bit; }
405 if(pix == '#') { img[byte] |= bit; }
408 cursors[i].sdlCursor = SDL_CreateCursor(img, mask, 32, 32,
414 bool fgOSIsMainCamera(const osg::Camera*)
419 bool fgOSIsMainContext(const osg::GraphicsContext*)
424 osg::GraphicsContext* fgOSGetMainContext()