Vegastrike 0.5.1 rc1  1.0
Original sources for Vegastrike Evolved
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Macros Groups Pages
winsys.cpp
Go to the documentation of this file.
1 /*
2  * Tux Racer
3  * Copyright (C) 1999-2001 Jasmin F. Patry
4  *
5  * This program is free software; you can redistribute it and/or
6  * modify it under the terms of the GNU General Public License
7  * as published by the Free Software Foundation; either version 2
8  * of the License, or (at your option) any later version.
9  *
10  * This program is distributed in the hope that it will be useful,
11  * but WITHOUT ANY WARRANTY; without even the implied warranty of
12  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13  * GNU General Public License for more details.
14  *
15  * You should have received a copy of the GNU General Public License
16  * along with this program; if not, write to the Free Software
17  * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
18  */
19 #include "config.h"
20 #include "gl_globals.h"
21 #include "winsys.h"
22 #include "vs_globals.h"
23 #include "xml_support.h"
24 #include "config_xml.h"
25 #include "vs_globals.h"
26 #include <assert.h>
27 #include <sstream>
28 //#include <sys/signal.h>
29 /*
30  * Windowing System Abstraction Layer
31  * Abstracts creation of windows, handling of events, etc.
32  */
33 
34 #if defined (SDL_WINDOWING) && defined (HAVE_SDL)
35 
36 /*
37  * *---------------------------------------------------------------------------
38  * *---------------------------------------------------------------------------
39  * SDL version
40  *******************************---------------------------------------------------------------------------
41  *******************************---------------------------------------------------------------------------
42  */
43 
44 static SDL_Surface *screen = NULL;
45 
46 static winsys_display_func_t display_func = NULL;
47 static winsys_idle_func_t idle_func = NULL;
48 static winsys_reshape_func_t reshape_func = NULL;
50 static winsys_mouse_func_t mouse_func = NULL;
51 static winsys_motion_func_t motion_func = NULL;
52 static winsys_motion_func_t passive_motion_func = NULL;
53 static winsys_atexit_func_t atexit_func = NULL;
54 
55 static bool redisplay = false;
56 static bool keepRunning = true;
57 
58 /*---------------------------------------------------------------------------*/
66 {
67  redisplay = true;
68 }
69 
70 /*---------------------------------------------------------------------------*/
78 {
79  display_func = func;
80 }
81 
82 /*---------------------------------------------------------------------------*/
90 {
91  idle_func = func;
92 }
93 
94 /*---------------------------------------------------------------------------*/
102 {
103  reshape_func = func;
104 }
105 
106 /*---------------------------------------------------------------------------*/
114 {
115  keyboard_func = func;
116 }
117 
118 /*---------------------------------------------------------------------------*/
126 {
127  mouse_func = func;
128 }
129 
130 /*---------------------------------------------------------------------------*/
138 {
139  motion_func = func;
140 }
141 
142 /*---------------------------------------------------------------------------*/
150 {
151  passive_motion_func = func;
152 }
153 
154 /*---------------------------------------------------------------------------*/
161 void winsys_swap_buffers()
162 {
163  SDL_GL_SwapBuffers();
164 }
165 
166 /*---------------------------------------------------------------------------*/
173 void winsys_warp_pointer( int x, int y )
174 {
175  SDL_WarpMouse( x, y );
176 }
177 
178 /*---------------------------------------------------------------------------*/
185 static bool setup_sdl_video_mode()
186 {
187  Uint32 video_flags = SDL_OPENGL;
188  int bpp = 0;
189  int width, height;
190  if (gl_options.fullscreen) {
191  video_flags |= SDL_FULLSCREEN;
192  } else {
193 #ifndef _WIN32
194  video_flags |= SDL_RESIZABLE;
195 #endif
196  }
197  bpp = gl_options.color_depth;
198 
199  int rs, gs, bs, zs;
200  rs = gs = bs = (bpp == 16) ? 5 : 8;
201  string rgbfmt = vs_config->getVariable( "graphics", "rgb_pixel_format", ( (bpp == 16) ? "555" : "888" ) );
202  bool gl_accelerated_visual = XMLSupport::parse_bool(
203  vs_config->getVariable( "graphics", "gl_accelerated_visual", "true" ) );
204  zs = XMLSupport::parse_int( vs_config->getVariable( "graphics", "z_pixel_format", "24" ) );
205  if ( (rgbfmt.length() == 3) && isdigit( rgbfmt[0] ) && isdigit( rgbfmt[1] ) && isdigit( rgbfmt[2] ) ) {
206  rs = rgbfmt[0]-'0';
207  gs = rgbfmt[1]-'0';
208  bs = rgbfmt[2]-'0';
209  }
210  int otherbpp;
211  int otherattributes;
212  if (bpp == 16) {
213  otherattributes = 8;
214  otherbpp = 32;
215  SDL_GL_SetAttribute( SDL_GL_RED_SIZE, rs );
216  SDL_GL_SetAttribute( SDL_GL_GREEN_SIZE, gs );
217  SDL_GL_SetAttribute( SDL_GL_BLUE_SIZE, bs );
218  SDL_GL_SetAttribute( SDL_GL_DEPTH_SIZE, zs );
219  SDL_GL_SetAttribute( SDL_GL_DOUBLEBUFFER, 1 );
220  } else {
221  otherattributes = 5;
222  otherbpp = 16;
223  SDL_GL_SetAttribute( SDL_GL_RED_SIZE, rs );
224  SDL_GL_SetAttribute( SDL_GL_GREEN_SIZE, gs );
225  SDL_GL_SetAttribute( SDL_GL_BLUE_SIZE, bs );
226  SDL_GL_SetAttribute( SDL_GL_DEPTH_SIZE, zs );
227  SDL_GL_SetAttribute( SDL_GL_DOUBLEBUFFER, 1 );
228  }
229 #if SDL_VERSION_ATLEAST( 1, 2, 10 )
230  if (gl_accelerated_visual)
231  SDL_GL_SetAttribute( SDL_GL_ACCELERATED_VISUAL, 1 );
232 #endif
233  width = g_game.x_resolution;
234  height = g_game.y_resolution;
235  if ( ( screen = SDL_SetVideoMode( width, height, bpp, video_flags ) )
236  == NULL ) {
237  VSFileSystem::vs_dprintf( 1, "Couldn't initialize video: %s",
238  SDL_GetError() );
239  for (int counter = 0; screen == NULL && counter < 2; ++counter) {
240  for (int bpd = 4; bpd > 1; --bpd) {
241  SDL_GL_SetAttribute( SDL_GL_DEPTH_SIZE, bpd*8 );
242  if ( ( screen = SDL_SetVideoMode( width, height, bpp, video_flags|SDL_ANYFORMAT ) )
243  == NULL )
244  VSFileSystem::vs_dprintf( 1, "Couldn't initialize video bpp %d depth %d: %s\n",
245  bpp, bpd*8, SDL_GetError() );
246  else
247  break;
248  }
249  if (screen == NULL) {
250  SDL_GL_SetAttribute( SDL_GL_RED_SIZE, otherattributes );
251  SDL_GL_SetAttribute( SDL_GL_GREEN_SIZE, otherattributes );
252  SDL_GL_SetAttribute( SDL_GL_BLUE_SIZE, otherattributes );
253  gl_options.color_depth = bpp = otherbpp;
254  }
255  }
256  if (screen == NULL) {
257  VSFileSystem::vs_fprintf( stderr, "FAILED to initialize video\n" );
258  exit( 1 );
259  }
260  }
261 
262  std::string version = (const char*)glGetString(GL_RENDERER);
263  if (version == "GDI Generic")
264  {
265  if (gl_accelerated_visual) {
266  VSFileSystem::vs_fprintf( stderr, "GDI Generic software driver reported, trying to reset.\n" );
267  SDL_Quit();
268  vs_config->setVariable( "graphics", "gl_accelerated_visual", "false" );
269  return false;
270  } else {
271  VSFileSystem::vs_fprintf( stderr,
272  "GDI Generic software driver reported, reset failed.\n "
273  "Please make sure a graphics card driver is installed and functioning properly.\n" );
274  }
275  }
276 
277  VSFileSystem::vs_dprintf( 3, "Setting Screen to w %d h %d and pitch of %d and %d bpp %d bytes per pix mode\n",
278  screen->w,
279  screen->h,
280  screen->pitch,
281  screen->format->BitsPerPixel,
282  screen->format->BytesPerPixel );
283 
284  return true;
285 }
286 
287 /*---------------------------------------------------------------------------*/
296 void winsys_init( int *argc, char **argv, char const *window_title, char const *icon_title )
297 {
298  keepRunning = true;
299 
300  //SDL_INIT_AUDIO|
301  Uint32 sdl_flags = SDL_INIT_VIDEO|SDL_INIT_JOYSTICK;
302  g_game.x_resolution = XMLSupport::parse_int( vs_config->getVariable( "graphics", "x_resolution", "1024" ) );
303  g_game.y_resolution = XMLSupport::parse_int( vs_config->getVariable( "graphics", "y_resolution", "768" ) );
304  gl_options.fullscreen = XMLSupport::parse_bool( vs_config->getVariable( "graphics", "fullscreen", "false" ) );
305  gl_options.color_depth = XMLSupport::parse_int( vs_config->getVariable( "graphics", "colordepth", "32" ) );
306  /*
307  * Initialize SDL
308  */
309  if (SDL_Init( sdl_flags ) < 0) {
310  VSFileSystem::vs_fprintf( stderr, "Couldn't initialize SDL: %s", SDL_GetError() );
311  exit( 1 );
312  }
313  SDL_EnableUNICODE( 1 ); //supposedly fixes int'l keyboards.
314 
315  //signal( SIGSEGV, SIG_DFL );
316  SDL_Surface *icon = NULL;
317 #if 1
318  if (icon_title) icon = SDL_LoadBMP( icon_title );
319  if (icon)
320  SDL_SetColorKey( icon, SDL_SRCCOLORKEY, ( (Uint32*) (icon->pixels) )[0] );
321 #endif
322  /*
323  * Init video
324  */
325  SDL_GL_SetAttribute( SDL_GL_DOUBLEBUFFER, 1 );
326 
327 #if defined (USE_STENCIL_BUFFER)
328  /* Not sure if this is sufficient to activate stencil buffer */
329  SDL_GL_SetAttribute( SDL_GL_STENCIL_SIZE, 8 );
330 #endif
331 
332  SDL_WM_SetCaption( window_title, window_title );
333  if (icon) SDL_WM_SetIcon( icon, 0 );
334 
335  if (!setup_sdl_video_mode()) {
336  winsys_init(argc, argv, window_title, icon_title);
337  } else {
338  glutInit( argc, argv );
339  }
340 }
341 
342 /*---------------------------------------------------------------------------*/
349 void winsys_cleanup()
350 {
351  static bool cleanup = false;
352  if (!cleanup) {
353  cleanup = true;
354  SDL_Quit();
355  }
356 }
357 
358 void winsys_shutdown()
359 {
360  keepRunning = false;
361 }
362 
363 /*---------------------------------------------------------------------------*/
371 void winsys_enable_key_repeat( bool enabled )
372 {
373  if (enabled)
374  SDL_EnableKeyRepeat( SDL_DEFAULT_REPEAT_DELAY,
375  SDL_DEFAULT_REPEAT_INTERVAL );
376  else
377  SDL_EnableKeyRepeat( 0, 0 );
378 }
379 
380 /*---------------------------------------------------------------------------*/
387 void winsys_show_cursor( bool visible )
388 {
389  static bool vis = true;
390  if (visible != vis) {
391  SDL_ShowCursor( visible );
392  vis = visible;
393  }
394 }
395 
396 /*---------------------------------------------------------------------------*/
406 extern int shiftdown( int );
407 extern int shiftup( int );
408 
410 {
411  SDL_Event event;
412  unsigned int key;
413  int x, y;
414  bool state;
415 
416  static bool handle_unicode_kb = XMLSupport::parse_bool( vs_config->getVariable( "keyboard", "enable_unicode", "true" ) );
417 
418  static unsigned int keysym_to_unicode[256];
419  static bool keysym_to_unicode_init = false;
420  if (!keysym_to_unicode_init) {
421  keysym_to_unicode_init = true;
422  memset( keysym_to_unicode, 0, sizeof (keysym_to_unicode) );
423  }
424  while (keepRunning)
425  {
426  SDL_LockAudio();
427  SDL_UnlockAudio();
428  while ( SDL_PollEvent( &event ) ) {
429  state = false;
430  switch (event.type)
431  {
432  case SDL_KEYUP:
433  state = true;
434  //does same thing as KEYDOWN, but with different state.
435  case SDL_KEYDOWN:
436  if (keyboard_func) {
437  SDL_GetMouseState( &x, &y );
438 
439  bool maybe_unicode = handle_unicode_kb && !(event.key.keysym.sym&~0xFF);
440  //Translate untranslated release events
441  if (state && maybe_unicode
442  && keysym_to_unicode[event.key.keysym.sym&0xFF])
443  event.key.keysym.unicode = keysym_to_unicode[event.key.keysym.sym&0xFF];
444  bool is_unicode = maybe_unicode && event.key.keysym.unicode;
445  //Remember translation for translating release events
446  if (is_unicode)
447  keysym_to_unicode[event.key.keysym.sym&0xFF] = event.key.keysym.unicode;
448  //Ugly hack: prevent shiftup/shiftdown screwups on intl keyboard
449  //Note: Thank god we'll have OIS for 0.5.x
450  bool shifton = event.key.keysym.mod&(KMOD_LSHIFT|KMOD_RSHIFT|KMOD_CAPS);
451  if (shifton && is_unicode
452  && shiftup( shiftdown( event.key.keysym.unicode ) ) != event.key.keysym.unicode) {
453  event.key.keysym.mod = SDLMod( event.key.keysym.mod&~(KMOD_LSHIFT|KMOD_RSHIFT|KMOD_CAPS) );
454  shifton = false;
455  }
456  //Choose unicode or symbolic, depending on whether ther is or not a unicode code
457  //(unicode codes must be postprocessed to make sure application of the shiftup
458  //modifier does not destroy it)
459  key = is_unicode
460  ? ( (shifton)
461  ? shiftdown( event.key.keysym.unicode )
462  : event.key.keysym.unicode
463  ) : event.key.keysym.sym;
464  //Send the event
465  (*keyboard_func)(key,
466  event.key.keysym.mod,
467  state,
468  x, y);
469  }
470  break;
471 
472  case SDL_MOUSEBUTTONDOWN:
473  case SDL_MOUSEBUTTONUP:
474  if (mouse_func)
475  (*mouse_func)(event.button.button,
476  event.button.state,
477  event.button.x,
478  event.button.y);
479  break;
480 
481  case SDL_MOUSEMOTION:
482  if (event.motion.state) {
483  /* buttons are down */
484  if (motion_func)
485  (*motion_func)(event.motion.x,
486  event.motion.y);
487  } else
488  /* no buttons are down */
489  if (passive_motion_func) {
490  (*passive_motion_func)(event.motion.x,
491  event.motion.y);
492  }
493  break;
494 
495  case SDL_VIDEORESIZE:
496 #if !(defined (_WIN32) && defined (SDL_WINDOWING ) )
497  g_game.x_resolution = event.resize.w;
498  g_game.y_resolution = event.resize.h;
499  setup_sdl_video_mode();
500  if (reshape_func)
501  (*reshape_func)(event.resize.w,
502  event.resize.h);
503 #endif
504  break;
505  }
506  SDL_LockAudio();
507  SDL_UnlockAudio();
508  }
509  if (redisplay && display_func) {
510  redisplay = false;
511  (*display_func)();
512  } else if (idle_func) {
513  (*idle_func)();
514  /* Delay for 1 ms. This allows the other threads to do some
515  * work (otherwise the audio thread gets starved). */
516  }
517  SDL_Delay( 1 );
518  }
519  winsys_cleanup();
520 }
521 
522 /*---------------------------------------------------------------------------*/
530 {
531  static bool called = false;
532  if (called != false)
533  VSFileSystem::vs_dprintf( 1, "winsys_atexit called twice" );
534  called = true;
535  //atexit_func = func;
536  //atexit (func);
537 }
538 
539 /*---------------------------------------------------------------------------*/
546 void winsys_exit( int code )
547 {
548  winsys_shutdown();
549  if (atexit_func)
550  (*atexit_func)();
551  // exit( code );
552 }
553 
554 #else
555 
556 /*
557  * *---------------------------------------------------------------------------
558  * *---------------------------------------------------------------------------
559  * GLUT version
560  *******************************---------------------------------------------------------------------------
561  *******************************---------------------------------------------------------------------------
562  */
563 
565 
566 static bool redisplay = false;
567 
568 /*---------------------------------------------------------------------------*/
576 {
577  redisplay = true;
578 }
579 
580 /*---------------------------------------------------------------------------*/
588 {
589  glutDisplayFunc( func );
590 }
591 
592 /*---------------------------------------------------------------------------*/
600 {
601  glutIdleFunc( func );
602 }
603 
604 /*---------------------------------------------------------------------------*/
612 {
613  glutReshapeFunc( func );
614 }
615 
616 char AdjustKeyCtrl( char ch )
617 {
618  if (ch == '\0') {
619  ch = '2';
620  } else if (ch >= '0' && ch <= '9') {} else if (ch >= 27 && ch <= 31) {
621  ch = ch+'0'-24;
622  } else if (ch == 127) {
623  ch = '8';
624  } else if (ch <= 26) {
625  ch += 'a'-1;
626  }
627  return ch;
628 }
629 
630 /* Keyboard callbacks */
631 static void glut_keyboard_cb( unsigned char ch, int x, int y )
632 {
633  if (keyboard_func) {
634  int gm = glutGetModifiers();
635  if (gm)
636  VSFileSystem::vs_dprintf('3', "Down Modifier %d for char %d %c\n", gm, (int) ch, ch );
637  if (gm&GLUT_ACTIVE_CTRL)
638  ch = AdjustKeyCtrl( ch );
639  (*keyboard_func)(ch, gm, false, x, y);
640  }
641 }
642 
643 static void glut_special_cb( int key, int x, int y )
644 {
645  if (keyboard_func)
646  (*keyboard_func)(key+128, glutGetModifiers(), false, x, y);
647 }
648 
649 static void glut_keyboard_up_cb( unsigned char ch, int x, int y )
650 {
651  if (keyboard_func) {
652  int gm = glutGetModifiers();
653  if (gm)
654  VSFileSystem::vs_dprintf('3',"Up Modifier %d for char %d %c\n", gm, (int) ch, ch );
655  if (gm&GLUT_ACTIVE_CTRL)
656  ch = AdjustKeyCtrl( ch );
657  (*keyboard_func)(ch, gm, true, x, y);
658  }
659 }
660 
661 static void glut_special_up_cb( int key, int x, int y )
662 {
663  if (keyboard_func)
664  (*keyboard_func)(key+128, glutGetModifiers(), true, x, y);
665 }
666 
667 /*---------------------------------------------------------------------------*/
675 {
676  keyboard_func = func;
677 }
678 
679 /*---------------------------------------------------------------------------*/
687 {
688  glutMouseFunc( func );
689 }
690 
691 /*---------------------------------------------------------------------------*/
699 {
700  glutMotionFunc( func );
701 }
702 
703 /*---------------------------------------------------------------------------*/
711 {
712  glutPassiveMotionFunc( func );
713 }
714 
715 /*---------------------------------------------------------------------------*/
723 {
724  glutSwapBuffers();
725 }
726 
727 /*---------------------------------------------------------------------------*/
734 void winsys_warp_pointer( int x, int y )
735 {
736  glutWarpPointer( x, y );
737 }
738 
739 /*---------------------------------------------------------------------------*/
747 void winsys_init( int *argc, char **argv, char const *window_title, char const *icon_title )
748 {
749  int width, height;
750  int glutWindow;
751  g_game.x_resolution = XMLSupport::parse_int( vs_config->getVariable( "graphics", "x_resolution", "1024" ) );
752  g_game.y_resolution = XMLSupport::parse_int( vs_config->getVariable( "graphics", "y_resolution", "768" ) );
753  gl_options.fullscreen = XMLSupport::parse_bool( vs_config->getVariable( "graphics", "fullscreen", "false" ) );
754  gl_options.color_depth = XMLSupport::parse_int( vs_config->getVariable( "graphics", "colordepth", "32" ) );
755  glutInit( argc, argv );
756  static bool get_stencil = XMLSupport::parse_bool( vs_config->getVariable( "graphics", "glut_stencil", "true" ) );
757  if (get_stencil) {
758 #ifdef __APPLE__
759  if ( !(glutInitDisplayMode( GLUT_RGBA|GLUT_DEPTH|GLUT_DOUBLE|GLUT_STENCIL ), 1) )
760  glutInitDisplayMode( GLUT_RGBA|GLUT_DEPTH|GLUT_DOUBLE );
761 #else
762  glutInitDisplayMode( GLUT_RGBA|GLUT_DEPTH|GLUT_DOUBLE|GLUT_STENCIL );
763 #endif
764  } else {
765  glutInitDisplayMode( GLUT_RGBA|GLUT_DEPTH|GLUT_DOUBLE );
766  }
767  char str[1024];
768  sprintf( str, "%dx%d:%d@60", g_game.x_resolution, g_game.y_resolution, gl_options.color_depth );
769  glutGameModeString( str );
770  VSFileSystem::vs_dprintf('3', "Game Mode Params %dx%d at depth %d @ %d Hz\n", glutGameModeGet( GLUT_GAME_MODE_WIDTH ),
771  glutGameModeGet( GLUT_GAME_MODE_WIDTH ), glutGameModeGet( GLUT_GAME_MODE_PIXEL_DEPTH ),
772  glutGameModeGet( GLUT_GAME_MODE_REFRESH_RATE ) );
773  /* Create a window */
774  if ( gl_options.fullscreen && (glutGameModeGet( GLUT_GAME_MODE_POSSIBLE ) != -1) ) {
775  glutInitWindowPosition( 0, 0 );
776  glutEnterGameMode();
777  VSFileSystem::vs_dprintf('3', "Game Mode Params %dx%d at depth %d @ %d Hz\n", glutGameModeGet(
778  GLUT_GAME_MODE_WIDTH ), glutGameModeGet( GLUT_GAME_MODE_WIDTH ), glutGameModeGet(
779  GLUT_GAME_MODE_PIXEL_DEPTH ), glutGameModeGet( GLUT_GAME_MODE_REFRESH_RATE ) );
780  } else {
781  /* Set the initial window size */
782  glutInitWindowSize( g_game.x_resolution, g_game.y_resolution );
783 
784  glutWindow = glutCreateWindow( window_title );
785  if (glutWindow == 0) {
786  (void) VSFileSystem::vs_fprintf( stderr, "Couldn't create a window.\n" );
787  exit( 1 );
788  }
789  }
790 }
791 
792 /*---------------------------------------------------------------------------*/
800 {
801  static bool shutdown = false;
802  if (!shutdown) {
803  shutdown = true;
805  glutLeaveGameMode();
806  }
807 }
808 
809 /*---------------------------------------------------------------------------*/
817 void winsys_enable_key_repeat( bool enabled )
818 {
819  glutIgnoreKeyRepeat( !enabled );
820 }
821 
822 /*---------------------------------------------------------------------------*/
829 void winsys_show_cursor( bool visible )
830 {
831  static bool vis = true;
832  if (visible != vis) {
833  if (visible)
834  glutSetCursor( GLUT_CURSOR_LEFT_ARROW );
835  else
836  glutSetCursor( GLUT_CURSOR_NONE );
837  vis = visible;
838  }
839 }
840 
841 /*---------------------------------------------------------------------------*/
850 {
851  /* Set up keyboard callbacks */
852  glutKeyboardFunc( glut_keyboard_cb );
853  glutKeyboardUpFunc( glut_keyboard_up_cb );
854  glutSpecialFunc( glut_special_cb );
855  glutSpecialUpFunc( glut_special_up_cb );
856 
857  glutMainLoop();
858 }
859 
860 /*---------------------------------------------------------------------------*/
868 {
869  static bool called = false;
870  if (called)
871  VSFileSystem::vs_fprintf( stderr, "winsys_atexit called twice\n" );
872  called = true;
873 
874  //atexit(func);
875 }
876 
877 /*---------------------------------------------------------------------------*/
884 void winsys_exit( int code )
885 {
886  winsys_shutdown();
887  exit( code );
888 }
889 
890 #endif /* defined( SDL_WINDOWING ) */
891 
892 /* EOF */
893