]> git.mxchange.org Git - flightgear.git/blob - src/Main/fg_os_sdl.cxx
cosmetic changes *only*:
[flightgear.git] / src / Main / fg_os_sdl.cxx
1 #include <stdlib.h>
2
3 #include <osgViewer/ViewerEventHandlers>
4 #include <osgViewer/Viewer>
5
6 #include <simgear/compiler.h>
7 #include <simgear/structure/exception.hxx>
8 #include <simgear/debug/logstream.hxx>
9
10 #include <SDL/SDL.h>
11
12 #include <Scenery/scenery.hxx>
13 #include "fg_os.hxx"
14 #include "globals.hxx"
15 #include "renderer.hxx"
16 #include "fg_props.hxx"
17 #include "WindowSystemAdapter.hxx"
18
19 using namespace flightgear;
20
21 //
22 // fg_os callback registration APIs
23 //
24
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;
30
31 //
32 // fg_os implementation
33 //
34 static void initCursors();
35
36 static osg::ref_ptr<osgViewer::Viewer> viewer;
37 static osg::ref_ptr<osg::Camera> mainCamera;
38 static osg::ref_ptr<osgViewer::GraphicsWindowEmbedded> gw;
39
40 void fgOSOpenWindow(bool stencil)
41 {
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();
50
51     if (SDL_Init(SDL_INIT_VIDEO|SDL_INIT_NOPARACHUTE) == -1)
52         throw sg_throwable(string("Failed to initialize SDL: ")
53                            + SDL_GetError());
54     atexit(SDL_Quit);
55
56     SDL_WM_SetCaption("FlightGear", "FlightGear");
57
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);
61     if(alpha)
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);
67
68     if(fullscreen) {
69         VidMask |= SDL_FULLSCREEN;
70     }
71     SDL_Surface* screen = SDL_SetVideoMode(w, h, 16, VidMask);
72     if ( screen == 0)
73         throw sg_throwable(string("Failed to set SDL video mode: ")
74                                    + SDL_GetError());
75
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.
80     SDL_EnableUNICODE(1);
81     SDL_EnableKeyRepeat(SDL_DEFAULT_REPEAT_DELAY, SDL_DEFAULT_REPEAT_INTERVAL);
82
83     initCursors();
84     fgSetMouseCursor(MOUSE_CURSOR_POINTER);
85
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...
89     //
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     mainCamera = 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());
119 }
120
121 // Cheap trick to avoid typing GUIEventAdapter over and over...
122 class SDLKeyTranslator : osgGA::GUIEventAdapter
123 {
124 public:
125     static int handleKey(int key, int raw, int keyup);
126 };
127
128 int SDLKeyTranslator::handleKey(int key, int raw, int keyup)
129 {
130     using namespace osgGA;
131     
132     int modmask = 0;
133     int osgKey = 0;
134     if (key == 0)
135         key = raw;
136     // Don't pass capslock or numlock to the FGManipulator; SDL
137     // already transforms the key properly, so FGManipulator will get
138     // confused.
139     if (key == SDLK_CAPSLOCK || key == SDLK_NUMLOCK)
140         return -1;
141     switch(key) {
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;
152
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;
174     default:
175         osgKey = key;
176     }
177     int keymod = 0;
178     if(keyup) {
179         CurrentModifiers &= ~modmask;
180         keymod = CurrentModifiers | KEYMOD_RELEASED;
181     } else {
182         CurrentModifiers |= modmask;
183         keymod = CurrentModifiers & ~KEYMOD_RELEASED;
184     }
185     return osgKey;
186 }
187
188 // FIXME: Integrate with existing fgExit() in util.cxx.
189 void fgOSExit(int code)
190 {
191     viewer->setDone(true);
192     exit(code);
193 }
194
195 // originally from osgexamples/osgviewerSDL.cpp
196 bool convertEvent(SDL_Event& event, osgGA::EventQueue& eventQueue)
197 {
198     using namespace osgGA;
199     switch (event.type) {
200
201     case SDL_MOUSEMOTION:
202         eventQueue.mouseMotion(event.motion.x, event.motion.y);
203         return true;
204
205     case SDL_MOUSEBUTTONDOWN:
206         eventQueue.mouseButtonPress(event.button.x, event.button.y, event.button.button);
207         return true;
208
209     case SDL_MOUSEBUTTONUP:
210         eventQueue.mouseButtonRelease(event.button.x, event.button.y, event.button.button);
211         return true;
212
213     case SDL_KEYUP:
214     case SDL_KEYDOWN:
215     {
216         int realKey = SDLKeyTranslator::handleKey(event.key.keysym.unicode,
217                                                   event.key.keysym.sym,
218                                                   event.type == SDL_KEYUP);
219         if (realKey < -1)
220             return true;
221         if (event.type == SDL_KEYUP)
222             eventQueue.keyRelease((osgGA::GUIEventAdapter::KeySymbol)realKey);
223         else
224             eventQueue.keyPress((osgGA::GUIEventAdapter::KeySymbol)realKey);
225         return true;
226     }
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: ")
230                                + SDL_GetError());
231         eventQueue.windowResize(0, 0, event.resize.w, event.resize.h );
232         return true;
233
234     default:
235         break;
236     }
237     return false;
238 }
239
240 void fgOSMainLoop()
241 {
242     while(1) {
243         SDL_Event e;
244         int key;
245         while(SDL_PollEvent(&e)) {
246             // pass the SDL event into the viewers event queue
247             convertEvent(e, *(gw->getEventQueue()));
248
249             switch(e.type) {
250             case SDL_QUIT:
251                 fgOSExit(0);
252                 break;
253             case SDL_VIDEORESIZE:
254                 gw->resized(0, 0, e.resize.w, e.resize.h );
255                 break;
256             }
257         }
258         // draw the new frame
259         viewer->frame();
260
261         // Swap Buffers
262         SDL_GL_SwapBuffers();
263     }
264 }
265
266 int fgGetKeyModifiers()
267 {
268     return CurrentModifiers;
269 }
270
271 void fgWarpMouse(int x, int y)
272 {
273     globals->get_renderer()->getManipulator()->setMouseWarped();
274     SDL_WarpMouse(x, y);
275 }
276
277 void fgOSInit(int* argc, char** argv)
278 {
279     WindowSystemAdapter::setWSA(new WindowSystemAdapter);
280 }
281
282 void fgOSFullScreen()
283 {
284     // Noop.  SDL must set fullscreen at window open time and cannot
285     // change modes.
286 }
287
288 static struct cursor_rec {
289     int name;
290     SDL_Cursor* sdlCursor;
291     int w;
292     int h;
293     int hotx;
294     int hoty;
295     const char *img[32]; // '.' == white, '#' == black, ' ' == transparent
296 } cursors[] = {
297     { MOUSE_CURSOR_POINTER, 0, // must be first!
298       10, 16, 1, 1,
299       { "..        ",
300         ".#.       ",
301         ".##.      ",
302         ".###.     ",
303         ".####.    ",
304         ".#####.   ",
305         ".######.  ",
306         ".#######. ",
307         ".########.",
308         ".#####....",
309         ".##.##.   ",
310         ".#. .##.  ",
311         "..  .##.  ",
312         "     .##. ",
313         "     .##. ",
314         "      ..  " } },
315     { MOUSE_CURSOR_CROSSHAIR, 0,
316       17, 17, 8, 8,
317       { "       ...       ",
318         "       .#.       ",
319         "       .#.       ",
320         "       .#.       ",
321         "       .#.       ",
322         "       .#.       ",
323         "       .#.       ",
324         "........#........",
325         ".#######.#######.",
326         "........#........",
327         "       .#.       ",
328         "       .#.       ",
329         "       .#.       ",
330         "       .#.       ",
331         "       .#.       ",
332         "       .#.       ",
333         "       ...       " } },
334     { MOUSE_CURSOR_WAIT, 0,
335       16, 16, 7, 7,
336       { "  .########.    ",
337         "  .########.    ",
338         "  .########.    ",
339         " .##########.   ",
340         ".##....#...##.  ",
341         "##.....#....##..",
342         "#......#.....###",
343         "#.....###....###",
344         "#.....###....###",
345         "#....#.......###",
346         "##..#.......##..",
347         ".##........##.  ",
348         " .##########.   ",
349         "  .########.    ",
350         "  .########.    ",
351         "  .########.    " } },
352     { MOUSE_CURSOR_LEFTRIGHT, 0,
353       17, 9, 8, 4,
354       { "    ..     ..    ",
355         "   .#.     .#.   ",
356         "  .##.......##.  ",
357         " .#############. ",
358         ".####.......####.",
359         " .#############. ",
360         "  .##.......##.  ",
361         "   .#.     .#.   ",
362         "    ..     ..    " } },
363     { MOUSE_CURSOR_NONE, 0, // must come last!
364       1, 1, 0, 0, { " " } },
365 };
366
367 #define NCURSORS (sizeof(cursors)/sizeof(struct cursor_rec))
368
369 void fgSetMouseCursor(int cursor)
370 {
371     if(cursor == MOUSE_CURSOR_NONE) {
372         SDL_ShowCursor(SDL_DISABLE);
373         return;
374     }
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);
380             return;
381         }
382     }
383     // Default to pointer
384     CurrentMouseCursor = MOUSE_CURSOR_POINTER;
385     SDL_SetCursor(cursors[0].sdlCursor);
386 }
387
388 int fgGetMouseCursor()
389 {
390     return CurrentMouseCursor;
391 }
392
393 static void initCursors()
394 {
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; }
406             }
407         }
408         cursors[i].sdlCursor = SDL_CreateCursor(img, mask, 32, 32, 
409                                                 cursors[i].hotx,
410                                                 cursors[i].hoty);
411     }
412 }
413
414 bool fgOSIsMainCamera(const osg::Camera*)
415 {
416   return true;
417 }
418
419 bool fgOSIsMainContext(const osg::GraphicsContext*)
420 {
421   return true;
422 }
423
424 osg::GraphicsContext* fgOSGetMainContext()
425 {
426     return gw.get();
427 }