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 "CameraGroup.hxx"
18 #include "WindowSystemAdapter.hxx"
20 using namespace flightgear;
23 // fg_os callback registration APIs
26 static int CurrentModifiers = 0;
27 static int CurrentMouseX = 0;
28 static int CurrentMouseY = 0;
29 static int CurrentMouseCursor = MOUSE_CURSOR_POINTER;
30 static int VidMask = SDL_OPENGL|SDL_RESIZABLE;
33 // fg_os implementation
35 static void initCursors();
37 static osg::ref_ptr<osgViewer::Viewer> viewer;
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;
99 // If a viewport isn't set on the camera, then it's hard to dig it
100 // out of the SceneView objects in the viewer, and the coordinates
101 // of mouse events are somewhat bizzare.
102 camera->setViewport(new osg::Viewport(0, 0, realw, realh));
103 camera->setProjectionResizePolicy(osg::Camera::FIXED);
104 CameraGroup* cgroup = new CameraGroup(viewer.get());
105 cgroup->addCamera(CameraGroup::DO_INTERSECTION_TEST, camera,
106 osg::Matrixd::identity(), osg::Matrixd::identity(),
108 cgroup->buildGUICamera(0, window);
109 CameraGroup::setDefault(cgroup);
110 viewer->setCameraManipulator(globals->get_renderer()->getManipulator());
111 // Let FG handle the escape key with a confirmation
112 viewer->setKeyEventSetsDone(0);
113 osgViewer::StatsHandler* statsHandler = new osgViewer::StatsHandler;
114 statsHandler->setKeyEventTogglesOnScreenStats('*');
115 statsHandler->setKeyEventPrintsOutStats(0);
116 viewer->addEventHandler(statsHandler);
117 // The viewer won't start without some root.
118 viewer->setSceneData(new osg::Group);
119 globals->get_renderer()->setViewer(viewer.get());
122 // Cheap trick to avoid typing GUIEventAdapter over and over...
123 class SDLKeyTranslator : osgGA::GUIEventAdapter
126 static int handleKey(int key, int raw, int keyup);
129 int SDLKeyTranslator::handleKey(int key, int raw, int keyup)
131 using namespace osgGA;
137 // Don't pass capslock or numlock to the FGManipulator; SDL
138 // already transforms the key properly, so FGManipulator will get
140 if (key == SDLK_CAPSLOCK || key == SDLK_NUMLOCK)
143 case SDLK_RSHIFT: modmask = KEYMOD_SHIFT; osgKey = KEY_Shift_R; break;
144 case SDLK_LSHIFT: modmask = KEYMOD_SHIFT; osgKey = KEY_Shift_L; break;
145 case SDLK_RCTRL: modmask = KEYMOD_CTRL; osgKey = KEY_Control_R; break;
146 case SDLK_LCTRL: modmask = KEYMOD_CTRL; osgKey = KEY_Control_L; break;
147 case SDLK_RALT: modmask = KEYMOD_ALT; osgKey = KEY_Alt_R; break;
148 case SDLK_LALT: modmask = KEYMOD_ALT; osgKey = KEY_Alt_L; break;
149 case SDLK_RMETA: modmask = KEYMOD_META; osgKey = KEY_Meta_R; break;
150 case SDLK_LMETA: modmask = KEYMOD_META; osgKey = KEY_Meta_L; break;
151 case SDLK_RSUPER: modmask = KEYMOD_SUPER; osgKey = KEY_Super_R; break;
152 case SDLK_LSUPER: modmask = KEYMOD_SUPER; osgKey = KEY_Super_L; break;
154 case SDLK_LEFT: osgKey = KEY_Left; break;
155 case SDLK_UP: osgKey = KEY_Up; break;
156 case SDLK_RIGHT: osgKey = KEY_Right; break;
157 case SDLK_DOWN: osgKey = KEY_Down; break;
158 case SDLK_PAGEUP: osgKey = KEY_Page_Up; break;
159 case SDLK_PAGEDOWN: osgKey = KEY_Page_Down; break;
160 case SDLK_HOME: osgKey = KEY_Home; break;
161 case SDLK_END: osgKey = KEY_End; break;
162 case SDLK_INSERT: osgKey = KEY_Insert; break;
163 case SDLK_F1: osgKey = KEY_F1; break;
164 case SDLK_F2: osgKey = KEY_F2; break;
165 case SDLK_F3: osgKey = KEY_F3; break;
166 case SDLK_F4: osgKey = KEY_F4; break;
167 case SDLK_F5: osgKey = KEY_F5; break;
168 case SDLK_F6: osgKey = KEY_F6; break;
169 case SDLK_F7: osgKey = KEY_F7; break;
170 case SDLK_F8: osgKey = KEY_F8; break;
171 case SDLK_F9: osgKey = KEY_F9; break;
172 case SDLK_F10: osgKey = KEY_F10; break;
173 case SDLK_F11: osgKey = KEY_F11; break;
174 case SDLK_F12: osgKey = KEY_F12; break;
180 CurrentModifiers &= ~modmask;
181 keymod = CurrentModifiers | KEYMOD_RELEASED;
183 CurrentModifiers |= modmask;
184 keymod = CurrentModifiers & ~KEYMOD_RELEASED;
189 // FIXME: Integrate with existing fgExit() in util.cxx.
190 void fgOSExit(int code)
192 viewer->setDone(true);
196 // originally from osgexamples/osgviewerSDL.cpp
197 bool convertEvent(SDL_Event& event, osgGA::EventQueue& eventQueue)
199 using namespace osgGA;
200 switch (event.type) {
202 case SDL_MOUSEMOTION:
203 eventQueue.mouseMotion(event.motion.x, event.motion.y);
206 case SDL_MOUSEBUTTONDOWN:
207 eventQueue.mouseButtonPress(event.button.x, event.button.y, event.button.button);
210 case SDL_MOUSEBUTTONUP:
211 eventQueue.mouseButtonRelease(event.button.x, event.button.y, event.button.button);
217 int realKey = SDLKeyTranslator::handleKey(event.key.keysym.unicode,
218 event.key.keysym.sym,
219 event.type == SDL_KEYUP);
222 if (event.type == SDL_KEYUP)
223 eventQueue.keyRelease((osgGA::GUIEventAdapter::KeySymbol)realKey);
225 eventQueue.keyPress((osgGA::GUIEventAdapter::KeySymbol)realKey);
228 case SDL_VIDEORESIZE:
229 if (SDL_SetVideoMode(event.resize.w, event.resize.h, 16, VidMask) == 0)
230 throw sg_throwable(string("Failed to set SDL video mode: ")
232 eventQueue.windowResize(0, 0, event.resize.w, event.resize.h );
246 while(SDL_PollEvent(&e)) {
247 // pass the SDL event into the viewers event queue
248 convertEvent(e, *(gw->getEventQueue()));
254 case SDL_VIDEORESIZE:
255 gw->resized(0, 0, e.resize.w, e.resize.h );
259 // draw the new frame
263 SDL_GL_SwapBuffers();
267 int fgGetKeyModifiers()
269 return CurrentModifiers;
272 void fgWarpMouse(int x, int y)
274 globals->get_renderer()->getManipulator()->setMouseWarped();
278 void fgOSInit(int* argc, char** argv)
280 WindowSystemAdapter::setWSA(new WindowSystemAdapter);
283 void fgOSFullScreen()
285 // Noop. SDL must set fullscreen at window open time and cannot
289 static struct cursor_rec {
291 SDL_Cursor* sdlCursor;
296 const char *img[32]; // '.' == white, '#' == black, ' ' == transparent
298 { MOUSE_CURSOR_POINTER, 0, // must be first!
316 { MOUSE_CURSOR_CROSSHAIR, 0,
335 { MOUSE_CURSOR_WAIT, 0,
353 { MOUSE_CURSOR_LEFTRIGHT, 0,
364 { MOUSE_CURSOR_NONE, 0, // must come last!
365 1, 1, 0, 0, { " " } },
368 #define NCURSORS (sizeof(cursors)/sizeof(struct cursor_rec))
370 void fgSetMouseCursor(int cursor)
372 if(cursor == MOUSE_CURSOR_NONE) {
373 SDL_ShowCursor(SDL_DISABLE);
376 SDL_ShowCursor(SDL_ENABLE);
377 for(unsigned int i=0; i<NCURSORS; i++) {
378 if(cursor == cursors[i].name) {
379 CurrentMouseCursor = cursor;
380 SDL_SetCursor(cursors[i].sdlCursor);
384 // Default to pointer
385 CurrentMouseCursor = MOUSE_CURSOR_POINTER;
386 SDL_SetCursor(cursors[0].sdlCursor);
389 int fgGetMouseCursor()
391 return CurrentMouseCursor;
394 static void initCursors()
396 unsigned char mask[128], img[128];
397 for(unsigned int i=0; i<NCURSORS; i++) {
398 if(cursors[i].name == MOUSE_CURSOR_NONE) break;
399 for(int j=0; j<128; j++) mask[j] = img[j] = 0;
400 for(int y=0; y<cursors[i].h; y++) {
401 for(int x=0; x<cursors[i].w; x++) {
402 int byte = (4 * y) + (x >> 3);
403 int bit = 1 << (7 - (x & 7));
404 int pix = cursors[i].img[y][x];
405 if(pix != ' ') { mask[byte] |= bit; }
406 if(pix == '#') { img[byte] |= bit; }
409 cursors[i].sdlCursor = SDL_CreateCursor(img, mask, 32, 32,