2 Copyright (C) 2003 T. Joseph Carter
4 This program is free software; you can redistribute it and/or
5 modify it under the terms of the GNU General Public License
6 as published by the Free Software Foundation; either version 2
7 of the License, or (at your option) any later version.
9 This program is distributed in the hope that it will be useful,
10 but WITHOUT ANY WARRANTY; without even the implied warranty of
11 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
13 See the GNU General Public License for more details.
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.
19 #undef WIN32_LEAN_AND_MEAN //hush a warning, SDL.h redefines this
29 // Tell startup code that we have a client
30 int cl_available = true;
32 qboolean vid_supportrefreshrate = false;
34 cvar_t joy_detected = {CVAR_READONLY, "joy_detected", "0", "number of joysticks detected by engine"};
35 cvar_t joy_enable = {CVAR_SAVE, "joy_enable", "0", "enables joystick support"};
36 cvar_t joy_index = {0, "joy_index", "0", "selects which joystick to use if you have multiple"};
37 cvar_t joy_axisforward = {0, "joy_axisforward", "1", "which joystick axis to query for forward/backward movement"};
38 cvar_t joy_axisside = {0, "joy_axisside", "0", "which joystick axis to query for right/left movement"};
39 cvar_t joy_axisup = {0, "joy_axisup", "-1", "which joystick axis to query for up/down movement"};
40 cvar_t joy_axispitch = {0, "joy_axispitch", "3", "which joystick axis to query for looking up/down"};
41 cvar_t joy_axisyaw = {0, "joy_axisyaw", "2", "which joystick axis to query for looking right/left"};
42 cvar_t joy_axisroll = {0, "joy_axisroll", "-1", "which joystick axis to query for tilting head right/left"};
43 cvar_t joy_deadzoneforward = {0, "joy_deadzoneforward", "0", "deadzone tolerance, suggested values are in the range 0 to 0.01"};
44 cvar_t joy_deadzoneside = {0, "joy_deadzoneside", "0", "deadzone tolerance, suggested values are in the range 0 to 0.01"};
45 cvar_t joy_deadzoneup = {0, "joy_deadzoneup", "0", "deadzone tolerance, suggested values are in the range 0 to 0.01"};
46 cvar_t joy_deadzonepitch = {0, "joy_deadzonepitch", "0", "deadzone tolerance, suggested values are in the range 0 to 0.01"};
47 cvar_t joy_deadzoneyaw = {0, "joy_deadzoneyaw", "0", "deadzone tolerance, suggested values are in the range 0 to 0.01"};
48 cvar_t joy_deadzoneroll = {0, "joy_deadzoneroll", "0", "deadzone tolerance, suggested values are in the range 0 to 0.01"};
49 cvar_t joy_sensitivityforward = {0, "joy_sensitivityforward", "-1", "movement multiplier"};
50 cvar_t joy_sensitivityside = {0, "joy_sensitivityside", "1", "movement multiplier"};
51 cvar_t joy_sensitivityup = {0, "joy_sensitivityup", "1", "movement multiplier"};
52 cvar_t joy_sensitivitypitch = {0, "joy_sensitivitypitch", "1", "movement multiplier"};
53 cvar_t joy_sensitivityyaw = {0, "joy_sensitivityyaw", "-1", "movement multiplier"};
54 cvar_t joy_sensitivityroll = {0, "joy_sensitivityroll", "1", "movement multiplier"};
56 static qboolean vid_usingmouse = false;
57 static qboolean vid_usinghidecursor = false;
58 static qboolean vid_isfullscreen;
59 static int vid_numjoysticks = 0;
60 #define MAX_JOYSTICKS 8
61 static SDL_Joystick *vid_joysticks[MAX_JOYSTICKS];
63 static int win_half_width = 50;
64 static int win_half_height = 50;
65 static int video_bpp, video_flags;
67 static SDL_Surface *screen;
69 /////////////////////////
72 //TODO: Add joystick support
73 //TODO: Add error checking
76 //keysym to quake keysym mapping
77 #define tenoh 0,0,0,0,0, 0,0,0,0,0
78 #define fiftyoh tenoh, tenoh, tenoh, tenoh, tenoh
79 #define hundredoh fiftyoh, fiftyoh
80 static unsigned int tbl_sdltoquake[] =
82 0,0,0,0, //SDLK_UNKNOWN = 0,
83 0,0,0,0, //SDLK_FIRST = 0,
84 K_BACKSPACE, //SDLK_BACKSPACE = 8,
85 K_TAB, //SDLK_TAB = 9,
88 K_ENTER, //SDLK_RETURN = 13,
90 K_PAUSE, //SDLK_PAUSE = 19,
92 K_ESCAPE, //SDLK_ESCAPE = 27,
94 K_SPACE, //SDLK_SPACE = 32,
95 '!', //SDLK_EXCLAIM = 33,
96 '"', //SDLK_QUOTEDBL = 34,
97 '#', //SDLK_HASH = 35,
98 '$', //SDLK_DOLLAR = 36,
100 '&', //SDLK_AMPERSAND = 38,
101 '\'', //SDLK_QUOTE = 39,
102 '(', //SDLK_LEFTPAREN = 40,
103 ')', //SDLK_RIGHTPAREN = 41,
104 '*', //SDLK_ASTERISK = 42,
105 '+', //SDLK_PLUS = 43,
106 ',', //SDLK_COMMA = 44,
107 '-', //SDLK_MINUS = 45,
108 '.', //SDLK_PERIOD = 46,
109 '/', //SDLK_SLASH = 47,
120 ':', //SDLK_COLON = 58,
121 ';', //SDLK_SEMICOLON = 59,
122 '<', //SDLK_LESS = 60,
123 '=', //SDLK_EQUALS = 61,
124 '>', //SDLK_GREATER = 62,
125 '?', //SDLK_QUESTION = 63,
127 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
128 '[', //SDLK_LEFTBRACKET = 91,
129 '\\', //SDLK_BACKSLASH = 92,
130 ']', //SDLK_RIGHTBRACKET = 93,
131 '^', //SDLK_CARET = 94,
132 '_', //SDLK_UNDERSCORE = 95,
133 '`', //SDLK_BACKQUOTE = 96,
161 K_DEL, //SDLK_DELETE = 127,
162 hundredoh /*227*/, tenoh, tenoh, 0,0,0,0,0,0,0,0,
163 K_KP_0, //SDLK_KP0 = 256,
164 K_KP_1, //SDLK_KP1 = 257,
165 K_KP_2, //SDLK_KP2 = 258,
166 K_KP_3, //SDLK_KP3 = 259,
167 K_KP_4, //SDLK_KP4 = 260,
168 K_KP_5, //SDLK_KP5 = 261,
169 K_KP_6, //SDLK_KP6 = 262,
170 K_KP_7, //SDLK_KP7 = 263,
171 K_KP_8, //SDLK_KP8 = 264,
172 K_KP_9, //SDLK_KP9 = 265,
173 K_KP_PERIOD,//SDLK_KP_PERIOD = 266,
174 K_KP_DIVIDE,//SDLK_KP_DIVIDE = 267,
175 K_KP_MULTIPLY,//SDLK_KP_MULTIPLY= 268,
176 K_KP_MINUS, //SDLK_KP_MINUS = 269,
177 K_KP_PLUS, //SDLK_KP_PLUS = 270,
178 K_KP_ENTER, //SDLK_KP_ENTER = 271,
179 K_KP_EQUALS,//SDLK_KP_EQUALS = 272,
180 K_UPARROW, //SDLK_UP = 273,
181 K_DOWNARROW,//SDLK_DOWN = 274,
182 K_RIGHTARROW,//SDLK_RIGHT = 275,
183 K_LEFTARROW,//SDLK_LEFT = 276,
184 K_INS, //SDLK_INSERT = 277,
185 K_HOME, //SDLK_HOME = 278,
186 K_END, //SDLK_END = 279,
187 K_PGUP, //SDLK_PAGEUP = 280,
188 K_PGDN, //SDLK_PAGEDOWN = 281,
189 K_F1, //SDLK_F1 = 282,
190 K_F2, //SDLK_F2 = 283,
191 K_F3, //SDLK_F3 = 284,
192 K_F4, //SDLK_F4 = 285,
193 K_F5, //SDLK_F5 = 286,
194 K_F6, //SDLK_F6 = 287,
195 K_F7, //SDLK_F7 = 288,
196 K_F8, //SDLK_F8 = 289,
197 K_F9, //SDLK_F9 = 290,
198 K_F10, //SDLK_F10 = 291,
199 K_F11, //SDLK_F11 = 292,
200 K_F12, //SDLK_F12 = 293,
205 K_NUMLOCK, //SDLK_NUMLOCK = 300,
206 K_CAPSLOCK, //SDLK_CAPSLOCK = 301,
207 K_SCROLLOCK,//SDLK_SCROLLOCK= 302,
208 K_SHIFT, //SDLK_RSHIFT = 303,
209 K_SHIFT, //SDLK_LSHIFT = 304,
210 K_CTRL, //SDLK_RCTRL = 305,
211 K_CTRL, //SDLK_LCTRL = 306,
212 K_ALT, //SDLK_RALT = 307,
213 K_ALT, //SDLK_LALT = 308,
214 0, //SDLK_RMETA = 309,
215 0, //SDLK_LMETA = 310,
216 0, //SDLK_LSUPER = 311, /* Left "Windows" key */
217 0, //SDLK_RSUPER = 312, /* Right "Windows" key */
218 K_ALT, //SDLK_MODE = 313, /* "Alt Gr" key */
219 0, //SDLK_COMPOSE = 314, /* Multi-key compose key */
220 0, //SDLK_HELP = 315,
221 0, //SDLK_PRINT = 316,
222 0, //SDLK_SYSREQ = 317,
223 K_PAUSE, //SDLK_BREAK = 318,
224 0, //SDLK_MENU = 319,
225 0, //SDLK_POWER = 320, /* Power Macintosh power key */
226 'e', //SDLK_EURO = 321, /* Some european keyboards */
227 0 //SDLK_UNDO = 322, /* Atari keyboard has Undo */
233 static int MapKey( unsigned int sdlkey )
235 if( sdlkey > sizeof(tbl_sdltoquake)/ sizeof(int) )
237 return tbl_sdltoquake[ sdlkey ];
240 void VID_SetMouse(qboolean fullscreengrab, qboolean relative, qboolean hidecursor)
242 if (vid_usingmouse != relative)
244 vid_usingmouse = relative;
245 cl_ignoremousemoves = 2;
246 SDL_WM_GrabInput( relative ? SDL_GRAB_ON : SDL_GRAB_OFF );
248 if (vid_usinghidecursor != hidecursor)
250 vid_usinghidecursor = hidecursor;
251 SDL_ShowCursor( hidecursor ? SDL_DISABLE : SDL_ENABLE);
255 static double IN_JoystickGetAxis(SDL_Joystick *joy, int axis, double sensitivity, double deadzone)
258 if (axis < 0 || axis >= SDL_JoystickNumAxes(joy))
259 return 0; // no such axis on this joystick
260 value = SDL_JoystickGetAxis(joy, axis) * (1.0 / 32767.0);
261 value = bound(-1, value, 1);
262 if (fabs(value) < deadzone)
263 return 0; // within deadzone around center
264 return value * sensitivity;
270 static int old_x = 0, old_y = 0;
271 static int stuck = 0;
275 if(vid_stick_mouse.integer)
277 // have the mouse stuck in the middle, example use: prevent expose effect of beryl during the game when not using
278 // window grabbing. --blub
280 // we need 2 frames to initialize the center position
283 SDL_WarpMouse(win_half_width, win_half_height);
284 SDL_GetMouseState(&x, &y);
285 SDL_GetRelativeMouseState(&x, &y);
288 SDL_GetRelativeMouseState(&x, &y);
289 in_mouse_x = x + old_x;
290 in_mouse_y = y + old_y;
291 SDL_GetMouseState(&x, &y);
292 old_x = x - win_half_width;
293 old_y = y - win_half_height;
294 SDL_WarpMouse(win_half_width, win_half_height);
297 SDL_GetRelativeMouseState( &x, &y );
303 SDL_GetMouseState(&x, &y);
304 in_windowmouse_x = x;
305 in_windowmouse_y = y;
307 if (vid_numjoysticks && joy_enable.integer && joy_index.integer >= 0 && joy_index.integer < vid_numjoysticks)
309 SDL_Joystick *joy = vid_joysticks[joy_index.integer];
310 int numballs = SDL_JoystickNumBalls(joy);
311 for (j = 0;j < numballs;j++)
313 SDL_JoystickGetBall(joy, j, &x, &y);
317 cl.cmd.forwardmove += IN_JoystickGetAxis(joy, joy_axisforward.integer, joy_sensitivityforward.value, joy_deadzoneforward.value) * cl_forwardspeed.value;
318 cl.cmd.sidemove += IN_JoystickGetAxis(joy, joy_axisside.integer, joy_sensitivityside.value, joy_deadzoneside.value) * cl_sidespeed.value;
319 cl.cmd.upmove += IN_JoystickGetAxis(joy, joy_axisup.integer, joy_sensitivityup.value, joy_deadzoneup.value) * cl_upspeed.value;
320 cl.viewangles[0] += IN_JoystickGetAxis(joy, joy_axispitch.integer, joy_sensitivitypitch.value, joy_deadzonepitch.value) * cl.realframetime * cl_pitchspeed.value;
321 cl.viewangles[1] += IN_JoystickGetAxis(joy, joy_axisyaw.integer, joy_sensitivityyaw.value, joy_deadzoneyaw.value) * cl.realframetime * cl_yawspeed.value;
322 //cl.viewangles[2] += IN_JoystickGetAxis(joy, joy_axisroll.integer, joy_sensitivityroll.value, joy_deadzoneroll.value) * cl.realframetime * cl_rollspeed.value;
326 /////////////////////
330 static int Sys_EventFilter( SDL_Event *event )
332 //TODO: Add a quit query in linux, too - though linux user are more likely to know what they do
333 if (event->type == SDL_QUIT)
336 if (MessageBox( NULL, "Are you sure you want to quit?", "Confirm Exit", MB_YESNO | MB_SETFOREGROUND | MB_ICONQUESTION ) == IDNO)
344 static qboolean sdl_needs_restart;
345 static void sdl_start(void)
348 static void sdl_shutdown(void)
350 sdl_needs_restart = false;
352 static void sdl_newmap(void)
357 static keynum_t buttonremap[18] =
379 void Sys_SendKeyEvents( void )
381 static qboolean sound_active = true;
384 while( SDL_PollEvent( &event ) )
385 switch( event.type ) {
391 Key_Event( MapKey( event.key.keysym.sym ), event.key.keysym.unicode, (event.key.state == SDL_PRESSED) );
393 case SDL_ACTIVEEVENT:
394 if( event.active.state & SDL_APPACTIVE )
396 if( event.active.gain )
402 case SDL_MOUSEBUTTONDOWN:
403 case SDL_MOUSEBUTTONUP:
404 if (event.button.button <= 18)
405 Key_Event( buttonremap[event.button.button - 1], 0, event.button.state == SDL_PRESSED );
407 case SDL_JOYBUTTONDOWN:
408 if (!joy_enable.integer)
409 break; // ignore down events if joystick has been disabled
410 case SDL_JOYBUTTONUP:
411 if (event.jbutton.button < 48)
412 Key_Event( event.jbutton.button + (event.jbutton.button < 16 ? K_JOY1 : K_AUX1 - 16), 0, (event.jbutton.state == SDL_PRESSED) );
414 case SDL_VIDEORESIZE:
415 if(vid_resizable.integer < 2)
417 vid.width = event.resize.w;
418 vid.height = event.resize.h;
419 SDL_SetVideoMode(vid.width, vid.height, video_bpp, video_flags);
421 // better not call R_Modules_Restart from here directly, as this may wreak havoc...
422 // so, let's better queue it for next frame
423 if(!sdl_needs_restart)
425 Cbuf_AddText("\nr_restart\n");
426 sdl_needs_restart = true;
433 // enable/disable sound on focus gain/loss
434 if ((!vid_hidden && vid_activewindow) || !snd_mutewhenidle.integer)
447 sound_active = false;
456 void *GL_GetProcAddress(const char *name)
459 p = SDL_GL_GetProcAddress(name);
463 static int Sys_EventFilter( SDL_Event *event );
464 static qboolean vid_sdl_initjoysticksystem = false;
468 Cvar_RegisterVariable(&joy_detected);
469 Cvar_RegisterVariable(&joy_enable);
470 Cvar_RegisterVariable(&joy_index);
471 Cvar_RegisterVariable(&joy_axisforward);
472 Cvar_RegisterVariable(&joy_axisside);
473 Cvar_RegisterVariable(&joy_axisup);
474 Cvar_RegisterVariable(&joy_axispitch);
475 Cvar_RegisterVariable(&joy_axisyaw);
476 //Cvar_RegisterVariable(&joy_axisroll);
477 Cvar_RegisterVariable(&joy_deadzoneforward);
478 Cvar_RegisterVariable(&joy_deadzoneside);
479 Cvar_RegisterVariable(&joy_deadzoneup);
480 Cvar_RegisterVariable(&joy_deadzonepitch);
481 Cvar_RegisterVariable(&joy_deadzoneyaw);
482 //Cvar_RegisterVariable(&joy_deadzoneroll);
483 Cvar_RegisterVariable(&joy_sensitivityforward);
484 Cvar_RegisterVariable(&joy_sensitivityside);
485 Cvar_RegisterVariable(&joy_sensitivityup);
486 Cvar_RegisterVariable(&joy_sensitivitypitch);
487 Cvar_RegisterVariable(&joy_sensitivityyaw);
488 //Cvar_RegisterVariable(&joy_sensitivityroll);
491 R_RegisterModule("SDL", sdl_start, sdl_shutdown, sdl_newmap, NULL, NULL);
494 if (SDL_Init(SDL_INIT_VIDEO) < 0)
495 Sys_Error ("Failed to init SDL video subsystem: %s", SDL_GetError());
496 vid_sdl_initjoysticksystem = SDL_Init(SDL_INIT_JOYSTICK) >= 0;
497 if (vid_sdl_initjoysticksystem)
498 Con_Printf("Failed to init SDL joystick subsystem: %s\n", SDL_GetError());
499 vid_isfullscreen = false;
502 // set the icon (we dont use SDL here since it would be too much a PITA)
504 #include "resource.h"
505 #include <SDL_syswm.h>
506 static void VID_SetCaption(void)
512 SDL_WM_SetCaption( gamename, NULL );
514 // get the HWND handle
515 SDL_VERSION( &info.version );
516 if( !SDL_GetWMInfo( &info ) )
519 icon = LoadIcon( GetModuleHandle( NULL ), MAKEINTRESOURCE( IDI_ICON1 ) );
520 #ifndef _W64 //If Windows 64bit data types don't exist
521 #ifndef SetClassLongPtr
522 #define SetClassLongPtr SetClassLong
525 #define GCLP_HICON GCL_HICON
528 #define LONG_PTR LONG
531 SetClassLongPtr( info.window, GCLP_HICON, (LONG_PTR)icon );
533 static void VID_SetIcon(void)
537 // Adding the OS independent XPM version --blub
538 #include "darkplaces.xpm"
539 #include "nexuiz.xpm"
540 static SDL_Surface *icon = NULL;
541 static void VID_SetIcon(void)
544 * Somewhat restricted XPM reader. Only supports XPMs saved by GIMP 2.4 at
545 * default settings with less than 91 colors and transparency.
548 int width, height, colors, isize, i, j;
550 static SDL_Color palette[256];
551 unsigned short palenc[256]; // store color id by char
555 xpm = (char *) FS_LoadFile("darkplaces-icon.xpm", tempmempool, false, NULL);
558 idata = XPM_DecodeString(xpm);
566 if(sscanf(data, "%i %i %i %i", &width, &height, &colors, &isize) != 4)
568 // NOTE: Only 1-char colornames are supported
569 Con_Printf("Sorry, but this does not even look similar to an XPM.\n");
575 // NOTE: Only 1-char colornames are supported
576 Con_Printf("This XPM's palette is either huge or idiotically unoptimized. It's key size is %i\n", isize);
580 for(i = 0; i < colors; ++i)
582 unsigned int r, g, b;
585 if(sscanf(idata[i+1], "%c c #%02x%02x%02x", &idx, &r, &g, &b) != 4)
588 if(sscanf(idata[i+1], "%c c Non%1[e]", &idx, foo) != 2) // I take the DailyWTF credit for this. --div0
590 Con_Printf("This XPM's palette looks odd. Can't continue.\n");
595 palette[i].r = 255; // color key
598 thenone = i; // weeeee
603 palette[i].r = r - (r == 255 && g == 0 && b == 255); // change 255/0/255 pink to 254/0/255 for color key
608 palenc[(unsigned char) idx] = i;
611 // allocate the image data
612 data = (char*) malloc(width*height);
614 for(j = 0; j < height; ++j)
616 for(i = 0; i < width; ++i)
618 // casting to the safest possible datatypes ^^
619 data[j * width + i] = palenc[((unsigned char*)idata[colors+j+1])[i]];
625 // SDL_FreeSurface should free the data too
626 // but for completeness' sake...
627 if(icon->flags & SDL_PREALLOC)
630 icon->pixels = NULL; // safety
632 SDL_FreeSurface(icon);
635 icon = SDL_CreateRGBSurface(SDL_SRCCOLORKEY, width, height, 8, 0,0,0,0);// rmask, gmask, bmask, amask); no mask needed
636 // 8 bit surfaces get an empty palette allocated according to the docs
637 // so it's a palette image for sure :) no endian check necessary for the mask
640 Con_Printf( "Failed to create surface for the window Icon!\n"
641 "%s\n", SDL_GetError());
646 SDL_SetPalette(icon, SDL_PHYSPAL|SDL_LOGPAL, palette, 0, colors);
647 SDL_SetColorKey(icon, SDL_SRCCOLORKEY, thenone);
649 SDL_WM_SetIcon(icon, NULL);
653 static void VID_SetCaption(void)
655 SDL_WM_SetCaption( gamename, NULL );
659 static void VID_OutputVersion(void)
661 const SDL_version *version;
662 version = SDL_Linked_Version();
663 Con_Printf( "Linked against SDL version %d.%d.%d\n"
664 "Using SDL library version %d.%d.%d\n",
665 SDL_MAJOR_VERSION, SDL_MINOR_VERSION, SDL_PATCHLEVEL,
666 version->major, version->minor, version->patch );
669 qboolean VID_InitMode(viddef_mode_t *mode)
672 static int notfirstvideomode = false;
673 int flags = SDL_OPENGL;
674 const char *drivername;
676 win_half_width = mode->width>>1;
677 win_half_height = mode->height>>1;
679 if(vid_resizable.integer)
680 flags |= SDL_RESIZABLE;
686 We cant switch from one OpenGL video mode to another.
687 Thus we first switch to some stupid 2D mode and then back to OpenGL.
689 if (notfirstvideomode)
690 SDL_SetVideoMode( 0, 0, 0, 0 );
691 notfirstvideomode = true;
693 // SDL usually knows best
696 // COMMANDLINEOPTION: SDL GL: -gl_driver <drivername> selects a GL driver library, default is whatever SDL recommends, useful only for 3dfxogl.dll/3dfxvgl.dll or fxmesa or similar, if you don't know what this is for, you don't need it
697 i = COM_CheckParm("-gl_driver");
698 if (i && i < com_argc - 1)
699 drivername = com_argv[i + 1];
700 if (SDL_GL_LoadLibrary(drivername) < 0)
702 Con_Printf("Unable to load GL driver \"%s\": %s\n", drivername, SDL_GetError());
706 if ((qglGetString = (const GLubyte* (GLAPIENTRY *)(GLenum name))GL_GetProcAddress("glGetString")) == NULL)
709 Con_Print("Required OpenGL function glGetString not found\n");
713 // Knghtbrd: should do platform-specific extension string function here
715 vid_isfullscreen = false;
716 if (mode->fullscreen) {
717 flags |= SDL_FULLSCREEN;
718 vid_isfullscreen = true;
720 //flags |= SDL_HWSURFACE;
722 SDL_GL_SetAttribute (SDL_GL_DOUBLEBUFFER, 1);
723 if (mode->bitsperpixel >= 32)
725 SDL_GL_SetAttribute (SDL_GL_RED_SIZE, 8);
726 SDL_GL_SetAttribute (SDL_GL_GREEN_SIZE, 8);
727 SDL_GL_SetAttribute (SDL_GL_BLUE_SIZE, 8);
728 SDL_GL_SetAttribute (SDL_GL_ALPHA_SIZE, 8);
729 SDL_GL_SetAttribute (SDL_GL_DEPTH_SIZE, 24);
730 SDL_GL_SetAttribute (SDL_GL_STENCIL_SIZE, 8);
734 SDL_GL_SetAttribute (SDL_GL_RED_SIZE, 5);
735 SDL_GL_SetAttribute (SDL_GL_GREEN_SIZE, 5);
736 SDL_GL_SetAttribute (SDL_GL_BLUE_SIZE, 5);
737 SDL_GL_SetAttribute (SDL_GL_DEPTH_SIZE, 16);
739 if (mode->stereobuffer)
740 SDL_GL_SetAttribute (SDL_GL_STEREO, 1);
741 if (vid_vsync.integer)
742 SDL_GL_SetAttribute (SDL_GL_SWAP_CONTROL, 1);
744 SDL_GL_SetAttribute (SDL_GL_SWAP_CONTROL, 0);
745 if (mode->samples > 1)
747 SDL_GL_SetAttribute (SDL_GL_MULTISAMPLEBUFFERS, 1);
748 SDL_GL_SetAttribute (SDL_GL_MULTISAMPLESAMPLES, mode->samples);
751 video_bpp = mode->bitsperpixel;
754 screen = SDL_SetVideoMode(mode->width, mode->height, mode->bitsperpixel, flags);
758 Con_Printf("Failed to set video mode to %ix%i: %s\n", mode->width, mode->height, SDL_GetError());
765 // set up an event filter to ask confirmation on close button in WIN32
766 SDL_SetEventFilter( (SDL_EventFilter) Sys_EventFilter );
768 SDL_EnableUNICODE( SDL_ENABLE );
769 // enable key repeat since everyone expects it
770 SDL_EnableKeyRepeat(SDL_DEFAULT_REPEAT_DELAY, SDL_DEFAULT_REPEAT_INTERVAL);
773 gl_platformextensions = "";
777 vid_numjoysticks = SDL_NumJoysticks();
778 vid_numjoysticks = bound(0, vid_numjoysticks, MAX_JOYSTICKS);
779 Cvar_SetValueQuick(&joy_detected, vid_numjoysticks);
780 Con_Printf("%d SDL joystick(s) found:\n", vid_numjoysticks);
781 memset(vid_joysticks, 0, sizeof(vid_joysticks));
782 for (i = 0;i < vid_numjoysticks;i++)
785 joy = vid_joysticks[i] = SDL_JoystickOpen(i);
788 Con_Printf("joystick #%i: open failed: %s\n", i, SDL_GetError());
791 Con_Printf("joystick #%i: opened \"%s\" with %i axes, %i buttons, %i balls\n", i, SDL_JoystickName(i), (int)SDL_JoystickNumAxes(joy), (int)SDL_JoystickNumButtons(joy), (int)SDL_JoystickNumBalls(joy));
795 vid_activewindow = false;
796 vid_usingmouse = false;
797 vid_usinghidecursor = false;
799 SDL_WM_GrabInput(SDL_GRAB_OFF);
803 void VID_Shutdown (void)
805 VID_SetMouse(false, false, false);
806 VID_RestoreSystemGamma();
808 SDL_QuitSubSystem(SDL_INIT_VIDEO);
813 gl_platformextensions = "";
816 int VID_SetGamma (unsigned short *ramps, int rampsize)
818 return !SDL_SetGammaRamp (ramps, ramps + rampsize, ramps + rampsize*2);
821 int VID_GetGamma (unsigned short *ramps, int rampsize)
823 return !SDL_GetGammaRamp (ramps, ramps + rampsize, ramps + rampsize*2);
826 void VID_Finish (void)
830 //react on appstate changes
831 appstate = SDL_GetAppState();
833 vid_hidden = !(appstate & SDL_APPACTIVE);
835 if( vid_hidden || !( appstate & SDL_APPMOUSEFOCUS ) || !( appstate & SDL_APPINPUTFOCUS ) )
836 vid_activewindow = false;
838 vid_activewindow = true;
840 VID_UpdateGamma(false, 256);
845 if (r_speeds.integer == 2 || gl_finish.integer)
847 qglFinish();CHECKGLERROR
849 SDL_GL_SwapBuffers();
853 size_t VID_ListModes(vid_mode_t *modes, size_t maxcount)
857 int bpp = SDL_GetVideoInfo()->vfmt->BitsPerPixel;
860 for(vidmodes = SDL_ListModes(NULL, SDL_FULLSCREEN|SDL_HWSURFACE); *vidmodes; ++vidmodes)
864 modes[k].width = (*vidmodes)->w;
865 modes[k].height = (*vidmodes)->h;
867 modes[k].refreshrate = 60; // no support for refresh rate in SDL
868 modes[k].pixelheight_num = 1;
869 modes[k].pixelheight_denom = 1; // SDL does not provide this