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>
13 #include <Scenery/scenery.hxx>
15 #include "globals.hxx"
16 #include "renderer.hxx"
19 // fg_os callback registration APIs
22 static int CurrentModifiers = 0;
23 static int CurrentMouseX = 0;
24 static int CurrentMouseY = 0;
25 static int CurrentMouseCursor = MOUSE_CURSOR_POINTER;
26 static int VidMask = SDL_OPENGL|SDL_RESIZABLE;
29 // fg_os implementation
31 static void initCursors();
33 static osg::ref_ptr<osgViewer::Viewer> viewer;
34 static osg::ref_ptr<osg::Camera> mainCamera;
35 static osg::ref_ptr<osgViewer::GraphicsWindowEmbedded> gw;
37 void fgOSOpenWindow(int w, int h, int bpp,
38 bool alpha, bool stencil, bool fullscreen)
40 int cbits = (bpp <= 16) ? 5 : 8;
41 int zbits = (bpp <= 16) ? 16 : 24;
43 if (SDL_Init(SDL_INIT_VIDEO|SDL_INIT_NOPARACHUTE) == -1)
44 throw sg_throwable(string("Failed to initialize SDL: ")
48 SDL_WM_SetCaption("FlightGear", "FlightGear");
50 SDL_GL_SetAttribute(SDL_GL_RED_SIZE, cbits);
51 SDL_GL_SetAttribute(SDL_GL_GREEN_SIZE, cbits);
52 SDL_GL_SetAttribute(SDL_GL_BLUE_SIZE, cbits);
54 SDL_GL_SetAttribute(SDL_GL_ALPHA_SIZE, 8);
55 if(bpp > 16 && stencil)
56 SDL_GL_SetAttribute(SDL_GL_STENCIL_SIZE, 8);
57 SDL_GL_SetAttribute(SDL_GL_DEPTH_SIZE, zbits);
58 SDL_GL_SetAttribute(SDL_GL_DOUBLEBUFFER, 1);
61 VidMask |= SDL_FULLSCREEN;
63 SDL_Surface* screen = SDL_SetVideoMode(w, h, 16, VidMask);
65 throw sg_throwable(string("Failed to set SDL video mode: ")
68 // This enables keycode translation (e.g. capital letters when
69 // shift is pressed, as well as i18n input methods). Eventually,
70 // we may want to port the input maps to specify <mod-shift>
71 // explicitly, and will turn this off.
73 SDL_EnableKeyRepeat(SDL_DEFAULT_REPEAT_DELAY, SDL_DEFAULT_REPEAT_INTERVAL);
76 fgSetMouseCursor(MOUSE_CURSOR_POINTER);
78 // FIXME: we may not get what we asked for (especially in full
79 // screen modes), so these need to be propagated back to the
80 // property tree for the rest of the code to inspect...
82 int realw = screen->w;
83 int realh = screen->h;
84 viewer = new osgViewer::Viewer;
85 viewer->setDatabasePager(FGScenery::getPagerSingleton());
86 gw = viewer->setUpViewerAsEmbeddedInWindow(0, 0, realw, realh);
87 // now the main camera ...
88 //osg::ref_ptr<osg::Camera> camera = new osg::Camera;
89 osg::ref_ptr<osg::Camera> camera = viewer->getCamera();
91 osg::Camera::ProjectionResizePolicy rsp = osg::Camera::VERTICAL;
92 // If a viewport isn't set on the camera, then it's hard to dig it
93 // out of the SceneView objects in the viewer, and the coordinates
94 // of mouse events are somewhat bizzare.
95 camera->setViewport(new osg::Viewport(0, 0, realw, realh));
96 camera->setProjectionResizePolicy(rsp);
97 //viewer->addSlave(camera.get());
98 viewer->setCameraManipulator(globals->get_renderer()->getManipulator());
99 // Let FG handle the escape key with a confirmation
100 viewer->setKeyEventSetsDone(0);
101 osgViewer::StatsHandler* statsHandler = new osgViewer::StatsHandler;
102 statsHandler->setKeyEventTogglesOnScreenStats('*');
103 statsHandler->setKeyEventPrintsOutStats(0);
104 viewer->addEventHandler(statsHandler);
105 // The viewer won't start without some root.
106 viewer->setSceneData(new osg::Group);
107 globals->get_renderer()->setViewer(viewer.get());
110 // Cheap trick to avoid typing GUIEventAdapter over and over...
111 class SDLKeyTranslator : osgGA::GUIEventAdapter
114 static int handleKey(int key, int raw, int keyup);
117 int SDLKeyTranslator::handleKey(int key, int raw, int keyup)
119 using namespace osgGA;
125 // Don't pass capslock or numlock to the FGManipulator; SDL
126 // already transforms the key properly, so FGManipulator will get
128 if (key == SDLK_CAPSLOCK || key == SDLK_NUMLOCK)
131 case SDLK_RSHIFT: modmask = KEYMOD_SHIFT; osgKey = KEY_Shift_R; break;
132 case SDLK_LSHIFT: modmask = KEYMOD_SHIFT; osgKey = KEY_Shift_L; break;
133 case SDLK_RCTRL: modmask = KEYMOD_CTRL; osgKey = KEY_Control_R; break;
134 case SDLK_LCTRL: modmask = KEYMOD_CTRL; osgKey = KEY_Control_L; break;
135 case SDLK_RALT: modmask = KEYMOD_ALT; osgKey = KEY_Alt_R; break;
136 case SDLK_LALT: modmask = KEYMOD_ALT; osgKey = KEY_Alt_L; break;
137 case SDLK_RMETA: modmask = KEYMOD_META; osgKey = KEY_Meta_R; break;
138 case SDLK_LMETA: modmask = KEYMOD_META; osgKey = KEY_Meta_L; break;
139 case SDLK_RSUPER: modmask = KEYMOD_SUPER; osgKey = KEY_Super_R; break;
140 case SDLK_LSUPER: modmask = KEYMOD_SUPER; osgKey = KEY_Super_L; break;
142 case SDLK_LEFT: osgKey = KEY_Left; break;
143 case SDLK_UP: osgKey = KEY_Up; break;
144 case SDLK_RIGHT: osgKey = KEY_Right; break;
145 case SDLK_DOWN: osgKey = KEY_Down; break;
146 case SDLK_PAGEUP: osgKey = KEY_Page_Up; break;
147 case SDLK_PAGEDOWN: osgKey = KEY_Page_Down; break;
148 case SDLK_HOME: osgKey = KEY_Home; break;
149 case SDLK_END: osgKey = KEY_End; break;
150 case SDLK_INSERT: osgKey = KEY_Insert; break;
151 case SDLK_F1: osgKey = KEY_F1; break;
152 case SDLK_F2: osgKey = KEY_F2; break;
153 case SDLK_F3: osgKey = KEY_F3; break;
154 case SDLK_F4: osgKey = KEY_F4; break;
155 case SDLK_F5: osgKey = KEY_F5; break;
156 case SDLK_F6: osgKey = KEY_F6; break;
157 case SDLK_F7: osgKey = KEY_F7; break;
158 case SDLK_F8: osgKey = KEY_F8; break;
159 case SDLK_F9: osgKey = KEY_F9; break;
160 case SDLK_F10: osgKey = KEY_F10; break;
161 case SDLK_F11: osgKey = KEY_F11; break;
162 case SDLK_F12: osgKey = KEY_F12; break;
168 CurrentModifiers &= ~modmask;
169 keymod = CurrentModifiers | KEYMOD_RELEASED;
171 CurrentModifiers |= modmask;
172 keymod = CurrentModifiers & ~KEYMOD_RELEASED;
177 // FIXME: Integrate with existing fgExit() in util.cxx.
178 void fgOSExit(int code)
180 viewer->setDone(true);
184 // originally from osgexamples/osgviewerSDL.cpp
185 bool convertEvent(SDL_Event& event, osgGA::EventQueue& eventQueue)
187 using namespace osgGA;
188 switch (event.type) {
190 case SDL_MOUSEMOTION:
191 eventQueue.mouseMotion(event.motion.x, event.motion.y);
194 case SDL_MOUSEBUTTONDOWN:
195 eventQueue.mouseButtonPress(event.button.x, event.button.y, event.button.button);
198 case SDL_MOUSEBUTTONUP:
199 eventQueue.mouseButtonRelease(event.button.x, event.button.y, event.button.button);
205 int realKey = SDLKeyTranslator::handleKey(event.key.keysym.unicode,
206 event.key.keysym.sym,
207 event.type == SDL_KEYUP);
210 if (event.type == SDL_KEYUP)
211 eventQueue.keyRelease((osgGA::GUIEventAdapter::KeySymbol)realKey);
213 eventQueue.keyPress((osgGA::GUIEventAdapter::KeySymbol)realKey);
216 case SDL_VIDEORESIZE:
217 if (SDL_SetVideoMode(event.resize.w, event.resize.h, 16, VidMask) == 0)
218 throw sg_throwable(string("Failed to set SDL video mode: ")
220 eventQueue.windowResize(0, 0, event.resize.w, event.resize.h );
234 while(SDL_PollEvent(&e)) {
235 // pass the SDL event into the viewers event queue
236 convertEvent(e, *(gw->getEventQueue()));
242 case SDL_VIDEORESIZE:
243 gw->resized(0, 0, e.resize.w, e.resize.h );
247 // draw the new frame
251 SDL_GL_SwapBuffers();
255 int fgGetKeyModifiers()
257 return CurrentModifiers;
260 void fgWarpMouse(int x, int y)
262 globals->get_renderer()->getManipulator()->setMouseWarped();
266 void fgOSInit(int* argc, char** argv)
268 // Nothing to do here. SDL has no command line options.
271 void fgOSFullScreen()
273 // Noop. SDL must set fullscreen at window open time and cannot
277 static struct cursor_rec {
279 SDL_Cursor* sdlCursor;
284 char *img[32]; // '.' == white, '#' == black, ' ' == transparent
286 { MOUSE_CURSOR_POINTER, 0, // must be first!
304 { MOUSE_CURSOR_CROSSHAIR, 0,
323 { MOUSE_CURSOR_WAIT, 0,
341 { MOUSE_CURSOR_LEFTRIGHT, 0,
352 { MOUSE_CURSOR_NONE, 0, // must come last!
353 1, 1, 0, 0, { " " } },
356 #define NCURSORS (sizeof(cursors)/sizeof(struct cursor_rec))
358 void fgSetMouseCursor(int cursor)
360 if(cursor == MOUSE_CURSOR_NONE) {
361 SDL_ShowCursor(SDL_DISABLE);
364 SDL_ShowCursor(SDL_ENABLE);
365 for(unsigned int i=0; i<NCURSORS; i++) {
366 if(cursor == cursors[i].name) {
367 CurrentMouseCursor = cursor;
368 SDL_SetCursor(cursors[i].sdlCursor);
372 // Default to pointer
373 CurrentMouseCursor = MOUSE_CURSOR_POINTER;
374 SDL_SetCursor(cursors[0].sdlCursor);
377 int fgGetMouseCursor()
379 return CurrentMouseCursor;
382 static void initCursors()
384 unsigned char mask[128], img[128];
385 for(unsigned int i=0; i<NCURSORS; i++) {
386 if(cursors[i].name == MOUSE_CURSOR_NONE) break;
387 for(int j=0; j<128; j++) mask[j] = img[j] = 0;
388 for(int y=0; y<cursors[i].h; y++) {
389 for(int x=0; x<cursors[i].w; x++) {
390 int byte = (4 * y) + (x >> 3);
391 int bit = 1 << (7 - (x & 7));
392 int pix = cursors[i].img[y][x];
393 if(pix != ' ') { mask[byte] |= bit; }
394 if(pix == '#') { img[byte] |= bit; }
397 cursors[i].sdlCursor = SDL_CreateCursor(img, mask, 32, 32,
403 // Noop; the graphics context is always current
408 bool fgOSIsMainCamera(const osg::Camera*)
413 bool fgOSIsMainContext(const osg::GraphicsContext*)