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