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
30 // Tell startup code that we have a client
31 int cl_available = true;
33 qboolean vid_supportrefreshrate = false;
35 cvar_t joy_detected = {CVAR_READONLY, "joy_detected", "0", "number of joysticks detected by engine"};
36 cvar_t joy_enable = {CVAR_SAVE, "joy_enable", "0", "enables joystick support"};
37 cvar_t joy_index = {0, "joy_index", "0", "selects which joystick to use if you have multiple"};
38 cvar_t joy_axisforward = {0, "joy_axisforward", "1", "which joystick axis to query for forward/backward movement"};
39 cvar_t joy_axisside = {0, "joy_axisside", "0", "which joystick axis to query for right/left movement"};
40 cvar_t joy_axisup = {0, "joy_axisup", "-1", "which joystick axis to query for up/down movement"};
41 cvar_t joy_axispitch = {0, "joy_axispitch", "3", "which joystick axis to query for looking up/down"};
42 cvar_t joy_axisyaw = {0, "joy_axisyaw", "2", "which joystick axis to query for looking right/left"};
43 cvar_t joy_axisroll = {0, "joy_axisroll", "-1", "which joystick axis to query for tilting head right/left"};
44 cvar_t joy_deadzoneforward = {0, "joy_deadzoneforward", "0", "deadzone tolerance, suggested values are in the range 0 to 0.01"};
45 cvar_t joy_deadzoneside = {0, "joy_deadzoneside", "0", "deadzone tolerance, suggested values are in the range 0 to 0.01"};
46 cvar_t joy_deadzoneup = {0, "joy_deadzoneup", "0", "deadzone tolerance, suggested values are in the range 0 to 0.01"};
47 cvar_t joy_deadzonepitch = {0, "joy_deadzonepitch", "0", "deadzone tolerance, suggested values are in the range 0 to 0.01"};
48 cvar_t joy_deadzoneyaw = {0, "joy_deadzoneyaw", "0", "deadzone tolerance, suggested values are in the range 0 to 0.01"};
49 cvar_t joy_deadzoneroll = {0, "joy_deadzoneroll", "0", "deadzone tolerance, suggested values are in the range 0 to 0.01"};
50 cvar_t joy_sensitivityforward = {0, "joy_sensitivityforward", "-1", "movement multiplier"};
51 cvar_t joy_sensitivityside = {0, "joy_sensitivityside", "1", "movement multiplier"};
52 cvar_t joy_sensitivityup = {0, "joy_sensitivityup", "1", "movement multiplier"};
53 cvar_t joy_sensitivitypitch = {0, "joy_sensitivitypitch", "1", "movement multiplier"};
54 cvar_t joy_sensitivityyaw = {0, "joy_sensitivityyaw", "-1", "movement multiplier"};
55 cvar_t joy_sensitivityroll = {0, "joy_sensitivityroll", "1", "movement multiplier"};
57 static qboolean vid_usingmouse = false;
58 static qboolean vid_usinghidecursor = false;
59 static qboolean vid_isfullscreen;
60 static int vid_numjoysticks = 0;
61 #define MAX_JOYSTICKS 8
62 static SDL_Joystick *vid_joysticks[MAX_JOYSTICKS];
64 static int win_half_width = 50;
65 static int win_half_height = 50;
66 static int video_bpp, video_flags;
68 static SDL_Surface *screen;
70 /////////////////////////
73 //TODO: Add joystick support
74 //TODO: Add error checking
77 //keysym to quake keysym mapping
78 #define tenoh 0,0,0,0,0, 0,0,0,0,0
79 #define fiftyoh tenoh, tenoh, tenoh, tenoh, tenoh
80 #define hundredoh fiftyoh, fiftyoh
81 static unsigned int tbl_sdltoquake[] =
83 0,0,0,0, //SDLK_UNKNOWN = 0,
84 0,0,0,0, //SDLK_FIRST = 0,
85 K_BACKSPACE, //SDLK_BACKSPACE = 8,
86 K_TAB, //SDLK_TAB = 9,
89 K_ENTER, //SDLK_RETURN = 13,
91 K_PAUSE, //SDLK_PAUSE = 19,
93 K_ESCAPE, //SDLK_ESCAPE = 27,
95 K_SPACE, //SDLK_SPACE = 32,
96 '!', //SDLK_EXCLAIM = 33,
97 '"', //SDLK_QUOTEDBL = 34,
98 '#', //SDLK_HASH = 35,
99 '$', //SDLK_DOLLAR = 36,
101 '&', //SDLK_AMPERSAND = 38,
102 '\'', //SDLK_QUOTE = 39,
103 '(', //SDLK_LEFTPAREN = 40,
104 ')', //SDLK_RIGHTPAREN = 41,
105 '*', //SDLK_ASTERISK = 42,
106 '+', //SDLK_PLUS = 43,
107 ',', //SDLK_COMMA = 44,
108 '-', //SDLK_MINUS = 45,
109 '.', //SDLK_PERIOD = 46,
110 '/', //SDLK_SLASH = 47,
121 ':', //SDLK_COLON = 58,
122 ';', //SDLK_SEMICOLON = 59,
123 '<', //SDLK_LESS = 60,
124 '=', //SDLK_EQUALS = 61,
125 '>', //SDLK_GREATER = 62,
126 '?', //SDLK_QUESTION = 63,
128 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,
129 '[', //SDLK_LEFTBRACKET = 91,
130 '\\', //SDLK_BACKSLASH = 92,
131 ']', //SDLK_RIGHTBRACKET = 93,
132 '^', //SDLK_CARET = 94,
133 '_', //SDLK_UNDERSCORE = 95,
134 '`', //SDLK_BACKQUOTE = 96,
162 K_DEL, //SDLK_DELETE = 127,
163 hundredoh /*227*/, tenoh, tenoh, 0,0,0,0,0,0,0,0,
164 K_KP_0, //SDLK_KP0 = 256,
165 K_KP_1, //SDLK_KP1 = 257,
166 K_KP_2, //SDLK_KP2 = 258,
167 K_KP_3, //SDLK_KP3 = 259,
168 K_KP_4, //SDLK_KP4 = 260,
169 K_KP_5, //SDLK_KP5 = 261,
170 K_KP_6, //SDLK_KP6 = 262,
171 K_KP_7, //SDLK_KP7 = 263,
172 K_KP_8, //SDLK_KP8 = 264,
173 K_KP_9, //SDLK_KP9 = 265,
174 K_KP_PERIOD,//SDLK_KP_PERIOD = 266,
175 K_KP_DIVIDE,//SDLK_KP_DIVIDE = 267,
176 K_KP_MULTIPLY,//SDLK_KP_MULTIPLY= 268,
177 K_KP_MINUS, //SDLK_KP_MINUS = 269,
178 K_KP_PLUS, //SDLK_KP_PLUS = 270,
179 K_KP_ENTER, //SDLK_KP_ENTER = 271,
180 K_KP_EQUALS,//SDLK_KP_EQUALS = 272,
181 K_UPARROW, //SDLK_UP = 273,
182 K_DOWNARROW,//SDLK_DOWN = 274,
183 K_RIGHTARROW,//SDLK_RIGHT = 275,
184 K_LEFTARROW,//SDLK_LEFT = 276,
185 K_INS, //SDLK_INSERT = 277,
186 K_HOME, //SDLK_HOME = 278,
187 K_END, //SDLK_END = 279,
188 K_PGUP, //SDLK_PAGEUP = 280,
189 K_PGDN, //SDLK_PAGEDOWN = 281,
190 K_F1, //SDLK_F1 = 282,
191 K_F2, //SDLK_F2 = 283,
192 K_F3, //SDLK_F3 = 284,
193 K_F4, //SDLK_F4 = 285,
194 K_F5, //SDLK_F5 = 286,
195 K_F6, //SDLK_F6 = 287,
196 K_F7, //SDLK_F7 = 288,
197 K_F8, //SDLK_F8 = 289,
198 K_F9, //SDLK_F9 = 290,
199 K_F10, //SDLK_F10 = 291,
200 K_F11, //SDLK_F11 = 292,
201 K_F12, //SDLK_F12 = 293,
206 K_NUMLOCK, //SDLK_NUMLOCK = 300,
207 K_CAPSLOCK, //SDLK_CAPSLOCK = 301,
208 K_SCROLLOCK,//SDLK_SCROLLOCK= 302,
209 K_SHIFT, //SDLK_RSHIFT = 303,
210 K_SHIFT, //SDLK_LSHIFT = 304,
211 K_CTRL, //SDLK_RCTRL = 305,
212 K_CTRL, //SDLK_LCTRL = 306,
213 K_ALT, //SDLK_RALT = 307,
214 K_ALT, //SDLK_LALT = 308,
215 0, //SDLK_RMETA = 309,
216 0, //SDLK_LMETA = 310,
217 0, //SDLK_LSUPER = 311, /* Left "Windows" key */
218 0, //SDLK_RSUPER = 312, /* Right "Windows" key */
219 K_ALT, //SDLK_MODE = 313, /* "Alt Gr" key */
220 0, //SDLK_COMPOSE = 314, /* Multi-key compose key */
221 0, //SDLK_HELP = 315,
222 0, //SDLK_PRINT = 316,
223 0, //SDLK_SYSREQ = 317,
224 K_PAUSE, //SDLK_BREAK = 318,
225 0, //SDLK_MENU = 319,
226 0, //SDLK_POWER = 320, /* Power Macintosh power key */
227 'e', //SDLK_EURO = 321, /* Some european keyboards */
228 0 //SDLK_UNDO = 322, /* Atari keyboard has Undo */
234 static int MapKey( unsigned int sdlkey )
236 if( sdlkey > sizeof(tbl_sdltoquake)/ sizeof(int) )
238 return tbl_sdltoquake[ sdlkey ];
241 void VID_SetMouse(qboolean fullscreengrab, qboolean relative, qboolean hidecursor)
243 if (vid_usingmouse != relative)
245 vid_usingmouse = relative;
246 cl_ignoremousemoves = 2;
247 SDL_WM_GrabInput( relative ? SDL_GRAB_ON : SDL_GRAB_OFF );
249 if (vid_usinghidecursor != hidecursor)
251 vid_usinghidecursor = hidecursor;
252 SDL_ShowCursor( hidecursor ? SDL_DISABLE : SDL_ENABLE);
256 static double IN_JoystickGetAxis(SDL_Joystick *joy, int axis, double sensitivity, double deadzone)
259 if (axis < 0 || axis >= SDL_JoystickNumAxes(joy))
260 return 0; // no such axis on this joystick
261 value = SDL_JoystickGetAxis(joy, axis) * (1.0 / 32767.0);
262 value = bound(-1, value, 1);
263 if (fabs(value) < deadzone)
264 return 0; // within deadzone around center
265 return value * sensitivity;
271 static int old_x = 0, old_y = 0;
272 static int stuck = 0;
276 if(vid_stick_mouse.integer)
278 // have the mouse stuck in the middle, example use: prevent expose effect of beryl during the game when not using
279 // window grabbing. --blub
281 // we need 2 frames to initialize the center position
284 SDL_WarpMouse(win_half_width, win_half_height);
285 SDL_GetMouseState(&x, &y);
286 SDL_GetRelativeMouseState(&x, &y);
289 SDL_GetRelativeMouseState(&x, &y);
290 in_mouse_x = x + old_x;
291 in_mouse_y = y + old_y;
292 SDL_GetMouseState(&x, &y);
293 old_x = x - win_half_width;
294 old_y = y - win_half_height;
295 SDL_WarpMouse(win_half_width, win_half_height);
298 SDL_GetRelativeMouseState( &x, &y );
304 SDL_GetMouseState(&x, &y);
305 in_windowmouse_x = x;
306 in_windowmouse_y = y;
308 if (vid_numjoysticks && joy_enable.integer && joy_index.integer >= 0 && joy_index.integer < vid_numjoysticks)
310 SDL_Joystick *joy = vid_joysticks[joy_index.integer];
311 int numballs = SDL_JoystickNumBalls(joy);
312 for (j = 0;j < numballs;j++)
314 SDL_JoystickGetBall(joy, j, &x, &y);
318 cl.cmd.forwardmove += IN_JoystickGetAxis(joy, joy_axisforward.integer, joy_sensitivityforward.value, joy_deadzoneforward.value) * cl_forwardspeed.value;
319 cl.cmd.sidemove += IN_JoystickGetAxis(joy, joy_axisside.integer, joy_sensitivityside.value, joy_deadzoneside.value) * cl_sidespeed.value;
320 cl.cmd.upmove += IN_JoystickGetAxis(joy, joy_axisup.integer, joy_sensitivityup.value, joy_deadzoneup.value) * cl_upspeed.value;
321 cl.viewangles[0] += IN_JoystickGetAxis(joy, joy_axispitch.integer, joy_sensitivitypitch.value, joy_deadzonepitch.value) * cl.realframetime * cl_pitchspeed.value;
322 cl.viewangles[1] += IN_JoystickGetAxis(joy, joy_axisyaw.integer, joy_sensitivityyaw.value, joy_deadzoneyaw.value) * cl.realframetime * cl_yawspeed.value;
323 //cl.viewangles[2] += IN_JoystickGetAxis(joy, joy_axisroll.integer, joy_sensitivityroll.value, joy_deadzoneroll.value) * cl.realframetime * cl_rollspeed.value;
327 /////////////////////
331 static int Sys_EventFilter( SDL_Event *event )
333 //TODO: Add a quit query in linux, too - though linux user are more likely to know what they do
334 if (event->type == SDL_QUIT)
337 if (MessageBox( NULL, "Are you sure you want to quit?", "Confirm Exit", MB_YESNO | MB_SETFOREGROUND | MB_ICONQUESTION ) == IDNO)
345 static qboolean sdl_needs_restart;
346 static void sdl_start(void)
349 static void sdl_shutdown(void)
351 sdl_needs_restart = false;
353 static void sdl_newmap(void)
358 static keynum_t buttonremap[18] =
380 void Sys_SendKeyEvents( void )
382 static qboolean sound_active = true;
385 while( SDL_PollEvent( &event ) )
386 switch( event.type ) {
392 Key_Event( MapKey( event.key.keysym.sym ), event.key.keysym.unicode, (event.key.state == SDL_PRESSED) );
394 case SDL_ACTIVEEVENT:
395 if( event.active.state & SDL_APPACTIVE )
397 if( event.active.gain )
403 case SDL_MOUSEBUTTONDOWN:
404 case SDL_MOUSEBUTTONUP:
405 if (event.button.button <= 18)
406 Key_Event( buttonremap[event.button.button - 1], 0, event.button.state == SDL_PRESSED );
408 case SDL_JOYBUTTONDOWN:
409 if (!joy_enable.integer)
410 break; // ignore down events if joystick has been disabled
411 case SDL_JOYBUTTONUP:
412 if (event.jbutton.button < 48)
413 Key_Event( event.jbutton.button + (event.jbutton.button < 16 ? K_JOY1 : K_AUX1 - 16), 0, (event.jbutton.state == SDL_PRESSED) );
415 case SDL_VIDEORESIZE:
416 if(vid_resizable.integer < 2)
418 vid.width = event.resize.w;
419 vid.height = event.resize.h;
420 SDL_SetVideoMode(vid.width, vid.height, video_bpp, video_flags);
422 // better not call R_Modules_Restart from here directly, as this may wreak havoc...
423 // so, let's better queue it for next frame
424 if(!sdl_needs_restart)
426 Cbuf_AddText("\nr_restart\n");
427 sdl_needs_restart = true;
434 // enable/disable sound on focus gain/loss
435 if ((!vid_hidden && vid_activewindow) || !snd_mutewhenidle.integer)
448 sound_active = false;
457 void *GL_GetProcAddress(const char *name)
460 p = SDL_GL_GetProcAddress(name);
464 static int Sys_EventFilter( SDL_Event *event );
465 static qboolean vid_sdl_initjoysticksystem = false;
469 Cvar_RegisterVariable(&joy_detected);
470 Cvar_RegisterVariable(&joy_enable);
471 Cvar_RegisterVariable(&joy_index);
472 Cvar_RegisterVariable(&joy_axisforward);
473 Cvar_RegisterVariable(&joy_axisside);
474 Cvar_RegisterVariable(&joy_axisup);
475 Cvar_RegisterVariable(&joy_axispitch);
476 Cvar_RegisterVariable(&joy_axisyaw);
477 //Cvar_RegisterVariable(&joy_axisroll);
478 Cvar_RegisterVariable(&joy_deadzoneforward);
479 Cvar_RegisterVariable(&joy_deadzoneside);
480 Cvar_RegisterVariable(&joy_deadzoneup);
481 Cvar_RegisterVariable(&joy_deadzonepitch);
482 Cvar_RegisterVariable(&joy_deadzoneyaw);
483 //Cvar_RegisterVariable(&joy_deadzoneroll);
484 Cvar_RegisterVariable(&joy_sensitivityforward);
485 Cvar_RegisterVariable(&joy_sensitivityside);
486 Cvar_RegisterVariable(&joy_sensitivityup);
487 Cvar_RegisterVariable(&joy_sensitivitypitch);
488 Cvar_RegisterVariable(&joy_sensitivityyaw);
489 //Cvar_RegisterVariable(&joy_sensitivityroll);
492 R_RegisterModule("SDL", sdl_start, sdl_shutdown, sdl_newmap, NULL, NULL);
495 if (SDL_Init(SDL_INIT_VIDEO) < 0)
496 Sys_Error ("Failed to init SDL video subsystem: %s", SDL_GetError());
497 vid_sdl_initjoysticksystem = SDL_Init(SDL_INIT_JOYSTICK) >= 0;
498 if (vid_sdl_initjoysticksystem)
499 Con_Printf("Failed to init SDL joystick subsystem: %s\n", SDL_GetError());
500 vid_isfullscreen = false;
503 // set the icon (we dont use SDL here since it would be too much a PITA)
505 #include "resource.h"
506 #include <SDL_syswm.h>
507 static void VID_SetCaption(void)
513 SDL_WM_SetCaption( gamename, NULL );
515 // get the HWND handle
516 SDL_VERSION( &info.version );
517 if( !SDL_GetWMInfo( &info ) )
520 icon = LoadIcon( GetModuleHandle( NULL ), MAKEINTRESOURCE( IDI_ICON1 ) );
521 #ifndef _W64 //If Windows 64bit data types don't exist
522 #ifndef SetClassLongPtr
523 #define SetClassLongPtr SetClassLong
526 #define GCLP_HICON GCL_HICON
529 #define LONG_PTR LONG
532 SetClassLongPtr( info.window, GCLP_HICON, (LONG_PTR)icon );
534 static void VID_SetIcon(void)
538 // Adding the OS independent XPM version --blub
539 #include "darkplaces.xpm"
540 #include "nexuiz.xpm"
541 static SDL_Surface *icon = NULL;
542 static void VID_SetIcon(void)
545 * Somewhat restricted XPM reader. Only supports XPMs saved by GIMP 2.4 at
546 * default settings with less than 91 colors and transparency.
549 int width, height, colors, isize, i, j;
551 static SDL_Color palette[256];
552 unsigned short palenc[256]; // store color id by char
555 const SDL_version *version;
557 version = SDL_Linked_Version();
558 // only use non-XPM icon support in SDL v1.3 and higher
559 // SDL v1.2 does not support "smooth" transparency, and thus is better
561 if(version->major >= 2 || version->major == 1 && version->minor >= 3)
563 data = (char *) loadimagepixelsbgra("darkplaces-icon", false, false, false, NULL);
566 unsigned int red = 0x00FF0000;
567 unsigned int green = 0x0000FF00;
568 unsigned int blue = 0x000000FF;
569 unsigned int alpha = 0xFF000000;
571 height = image_height;
573 // reallocate with malloc, as this is in tempmempool (do not want)
575 data = malloc(width * height * 4);
576 memcpy(data, xpm, width * height * 4);
580 icon = SDL_CreateRGBSurface(SDL_SRCALPHA, width, height, 32, LittleLong(red), LittleLong(green), LittleLong(blue), LittleLong(alpha));
583 Con_Printf( "Failed to create surface for the window Icon!\n"
584 "%s\n", SDL_GetError());
593 // we only get here if non-XPM icon was missing, or SDL version is not
594 // sufficient for transparent non-XPM icons
597 xpm = (char *) FS_LoadFile("darkplaces-icon.xpm", tempmempool, false, NULL);
600 idata = XPM_DecodeString(xpm);
608 if(sscanf(data, "%i %i %i %i", &width, &height, &colors, &isize) != 4)
610 // NOTE: Only 1-char colornames are supported
611 Con_Printf("Sorry, but this does not even look similar to an XPM.\n");
617 // NOTE: Only 1-char colornames are supported
618 Con_Printf("This XPM's palette is either huge or idiotically unoptimized. It's key size is %i\n", isize);
622 for(i = 0; i < colors; ++i)
624 unsigned int r, g, b;
627 if(sscanf(idata[i+1], "%c c #%02x%02x%02x", &idx, &r, &g, &b) != 4)
630 if(sscanf(idata[i+1], "%c c Non%1[e]", &idx, foo) != 2) // I take the DailyWTF credit for this. --div0
632 Con_Printf("This XPM's palette looks odd. Can't continue.\n");
637 palette[i].r = 255; // color key
640 thenone = i; // weeeee
645 palette[i].r = r - (r == 255 && g == 0 && b == 255); // change 255/0/255 pink to 254/0/255 for color key
650 palenc[(unsigned char) idx] = i;
653 // allocate the image data
654 data = (char*) malloc(width*height);
656 for(j = 0; j < height; ++j)
658 for(i = 0; i < width; ++i)
660 // casting to the safest possible datatypes ^^
661 data[j * width + i] = palenc[((unsigned char*)idata[colors+j+1])[i]];
667 // SDL_FreeSurface should free the data too
668 // but for completeness' sake...
669 if(icon->flags & SDL_PREALLOC)
672 icon->pixels = NULL; // safety
674 SDL_FreeSurface(icon);
677 icon = SDL_CreateRGBSurface(SDL_SRCCOLORKEY, width, height, 8, 0,0,0,0);// rmask, gmask, bmask, amask); no mask needed
678 // 8 bit surfaces get an empty palette allocated according to the docs
679 // so it's a palette image for sure :) no endian check necessary for the mask
682 Con_Printf( "Failed to create surface for the window Icon!\n"
683 "%s\n", SDL_GetError());
689 SDL_SetPalette(icon, SDL_PHYSPAL|SDL_LOGPAL, palette, 0, colors);
690 SDL_SetColorKey(icon, SDL_SRCCOLORKEY, thenone);
693 SDL_WM_SetIcon(icon, NULL);
697 static void VID_SetCaption(void)
699 SDL_WM_SetCaption( gamename, NULL );
703 static void VID_OutputVersion(void)
705 const SDL_version *version;
706 version = SDL_Linked_Version();
707 Con_Printf( "Linked against SDL version %d.%d.%d\n"
708 "Using SDL library version %d.%d.%d\n",
709 SDL_MAJOR_VERSION, SDL_MINOR_VERSION, SDL_PATCHLEVEL,
710 version->major, version->minor, version->patch );
713 qboolean VID_InitMode(viddef_mode_t *mode)
716 static int notfirstvideomode = false;
717 int flags = SDL_OPENGL;
718 const char *drivername;
720 win_half_width = mode->width>>1;
721 win_half_height = mode->height>>1;
723 if(vid_resizable.integer)
724 flags |= SDL_RESIZABLE;
730 We cant switch from one OpenGL video mode to another.
731 Thus we first switch to some stupid 2D mode and then back to OpenGL.
733 if (notfirstvideomode)
734 SDL_SetVideoMode( 0, 0, 0, 0 );
735 notfirstvideomode = true;
737 // SDL usually knows best
740 // 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
741 i = COM_CheckParm("-gl_driver");
742 if (i && i < com_argc - 1)
743 drivername = com_argv[i + 1];
744 if (SDL_GL_LoadLibrary(drivername) < 0)
746 Con_Printf("Unable to load GL driver \"%s\": %s\n", drivername, SDL_GetError());
750 if ((qglGetString = (const GLubyte* (GLAPIENTRY *)(GLenum name))GL_GetProcAddress("glGetString")) == NULL)
753 Con_Print("Required OpenGL function glGetString not found\n");
757 // Knghtbrd: should do platform-specific extension string function here
759 vid_isfullscreen = false;
760 if (mode->fullscreen) {
761 flags |= SDL_FULLSCREEN;
762 vid_isfullscreen = true;
764 //flags |= SDL_HWSURFACE;
766 SDL_GL_SetAttribute (SDL_GL_DOUBLEBUFFER, 1);
767 if (mode->bitsperpixel >= 32)
769 SDL_GL_SetAttribute (SDL_GL_RED_SIZE, 8);
770 SDL_GL_SetAttribute (SDL_GL_GREEN_SIZE, 8);
771 SDL_GL_SetAttribute (SDL_GL_BLUE_SIZE, 8);
772 SDL_GL_SetAttribute (SDL_GL_ALPHA_SIZE, 8);
773 SDL_GL_SetAttribute (SDL_GL_DEPTH_SIZE, 24);
774 SDL_GL_SetAttribute (SDL_GL_STENCIL_SIZE, 8);
778 SDL_GL_SetAttribute (SDL_GL_RED_SIZE, 5);
779 SDL_GL_SetAttribute (SDL_GL_GREEN_SIZE, 5);
780 SDL_GL_SetAttribute (SDL_GL_BLUE_SIZE, 5);
781 SDL_GL_SetAttribute (SDL_GL_DEPTH_SIZE, 16);
783 if (mode->stereobuffer)
784 SDL_GL_SetAttribute (SDL_GL_STEREO, 1);
785 if (vid_vsync.integer)
786 SDL_GL_SetAttribute (SDL_GL_SWAP_CONTROL, 1);
788 SDL_GL_SetAttribute (SDL_GL_SWAP_CONTROL, 0);
789 if (mode->samples > 1)
791 SDL_GL_SetAttribute (SDL_GL_MULTISAMPLEBUFFERS, 1);
792 SDL_GL_SetAttribute (SDL_GL_MULTISAMPLESAMPLES, mode->samples);
795 video_bpp = mode->bitsperpixel;
798 screen = SDL_SetVideoMode(mode->width, mode->height, mode->bitsperpixel, flags);
802 Con_Printf("Failed to set video mode to %ix%i: %s\n", mode->width, mode->height, SDL_GetError());
809 // set up an event filter to ask confirmation on close button in WIN32
810 SDL_SetEventFilter( (SDL_EventFilter) Sys_EventFilter );
812 SDL_EnableUNICODE( SDL_ENABLE );
813 // enable key repeat since everyone expects it
814 SDL_EnableKeyRepeat(SDL_DEFAULT_REPEAT_DELAY, SDL_DEFAULT_REPEAT_INTERVAL);
817 gl_platformextensions = "";
821 vid_numjoysticks = SDL_NumJoysticks();
822 vid_numjoysticks = bound(0, vid_numjoysticks, MAX_JOYSTICKS);
823 Cvar_SetValueQuick(&joy_detected, vid_numjoysticks);
824 Con_Printf("%d SDL joystick(s) found:\n", vid_numjoysticks);
825 memset(vid_joysticks, 0, sizeof(vid_joysticks));
826 for (i = 0;i < vid_numjoysticks;i++)
829 joy = vid_joysticks[i] = SDL_JoystickOpen(i);
832 Con_Printf("joystick #%i: open failed: %s\n", i, SDL_GetError());
835 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));
839 vid_activewindow = false;
840 vid_usingmouse = false;
841 vid_usinghidecursor = false;
843 SDL_WM_GrabInput(SDL_GRAB_OFF);
847 void VID_Shutdown (void)
849 VID_SetMouse(false, false, false);
850 VID_RestoreSystemGamma();
852 SDL_QuitSubSystem(SDL_INIT_VIDEO);
857 gl_platformextensions = "";
860 int VID_SetGamma (unsigned short *ramps, int rampsize)
862 return !SDL_SetGammaRamp (ramps, ramps + rampsize, ramps + rampsize*2);
865 int VID_GetGamma (unsigned short *ramps, int rampsize)
867 return !SDL_GetGammaRamp (ramps, ramps + rampsize, ramps + rampsize*2);
870 void VID_Finish (void)
874 //react on appstate changes
875 appstate = SDL_GetAppState();
877 vid_hidden = !(appstate & SDL_APPACTIVE);
879 if( vid_hidden || !( appstate & SDL_APPMOUSEFOCUS ) || !( appstate & SDL_APPINPUTFOCUS ) )
880 vid_activewindow = false;
882 vid_activewindow = true;
884 VID_UpdateGamma(false, 256);
889 if (r_speeds.integer == 2 || gl_finish.integer)
891 qglFinish();CHECKGLERROR
893 SDL_GL_SwapBuffers();
897 size_t VID_ListModes(vid_mode_t *modes, size_t maxcount)
901 int bpp = SDL_GetVideoInfo()->vfmt->BitsPerPixel;
904 for(vidmodes = SDL_ListModes(NULL, SDL_FULLSCREEN|SDL_HWSURFACE); *vidmodes; ++vidmodes)
908 modes[k].width = (*vidmodes)->w;
909 modes[k].height = (*vidmodes)->h;
911 modes[k].refreshrate = 60; // no support for refresh rate in SDL
912 modes[k].pixelheight_num = 1;
913 modes[k].pixelheight_denom = 1; // SDL does not provide this