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
21 #include <SDL_syswm.h>
31 // Tell startup code that we have a client
32 int cl_available = true;
34 qboolean vid_supportrefreshrate = false;
36 cvar_t joy_detected = {CVAR_READONLY, "joy_detected", "0", "number of joysticks detected by engine"};
37 cvar_t joy_enable = {CVAR_SAVE, "joy_enable", "0", "enables joystick support"};
38 cvar_t joy_index = {0, "joy_index", "0", "selects which joystick to use if you have multiple"};
39 cvar_t joy_axisforward = {0, "joy_axisforward", "1", "which joystick axis to query for forward/backward movement"};
40 cvar_t joy_axisside = {0, "joy_axisside", "0", "which joystick axis to query for right/left movement"};
41 cvar_t joy_axisup = {0, "joy_axisup", "-1", "which joystick axis to query for up/down movement"};
42 cvar_t joy_axispitch = {0, "joy_axispitch", "3", "which joystick axis to query for looking up/down"};
43 cvar_t joy_axisyaw = {0, "joy_axisyaw", "2", "which joystick axis to query for looking right/left"};
44 cvar_t joy_axisroll = {0, "joy_axisroll", "-1", "which joystick axis to query for tilting head right/left"};
45 cvar_t joy_deadzoneforward = {0, "joy_deadzoneforward", "0", "deadzone tolerance, suggested values are in the range 0 to 0.01"};
46 cvar_t joy_deadzoneside = {0, "joy_deadzoneside", "0", "deadzone tolerance, suggested values are in the range 0 to 0.01"};
47 cvar_t joy_deadzoneup = {0, "joy_deadzoneup", "0", "deadzone tolerance, suggested values are in the range 0 to 0.01"};
48 cvar_t joy_deadzonepitch = {0, "joy_deadzonepitch", "0", "deadzone tolerance, suggested values are in the range 0 to 0.01"};
49 cvar_t joy_deadzoneyaw = {0, "joy_deadzoneyaw", "0", "deadzone tolerance, suggested values are in the range 0 to 0.01"};
50 cvar_t joy_deadzoneroll = {0, "joy_deadzoneroll", "0", "deadzone tolerance, suggested values are in the range 0 to 0.01"};
51 cvar_t joy_sensitivityforward = {0, "joy_sensitivityforward", "-1", "movement multiplier"};
52 cvar_t joy_sensitivityside = {0, "joy_sensitivityside", "1", "movement multiplier"};
53 cvar_t joy_sensitivityup = {0, "joy_sensitivityup", "1", "movement multiplier"};
54 cvar_t joy_sensitivitypitch = {0, "joy_sensitivitypitch", "1", "movement multiplier"};
55 cvar_t joy_sensitivityyaw = {0, "joy_sensitivityyaw", "-1", "movement multiplier"};
56 cvar_t joy_sensitivityroll = {0, "joy_sensitivityroll", "1", "movement multiplier"};
58 static qboolean vid_usingmouse = false;
59 static qboolean vid_usinghidecursor = false;
60 static qboolean vid_isfullscreen;
61 static int vid_numjoysticks = 0;
62 #define MAX_JOYSTICKS 8
63 static SDL_Joystick *vid_joysticks[MAX_JOYSTICKS];
65 static int win_half_width = 50;
66 static int win_half_height = 50;
67 static int video_bpp, video_flags;
69 static SDL_Surface *screen;
71 /////////////////////////
74 //TODO: Add joystick support
75 //TODO: Add error checking
78 //keysym to quake keysym mapping
79 #define tenoh 0,0,0,0,0, 0,0,0,0,0
80 #define fiftyoh tenoh, tenoh, tenoh, tenoh, tenoh
81 #define hundredoh fiftyoh, fiftyoh
82 static unsigned int tbl_sdltoquake[] =
84 0,0,0,0, //SDLK_UNKNOWN = 0,
85 0,0,0,0, //SDLK_FIRST = 0,
86 K_BACKSPACE, //SDLK_BACKSPACE = 8,
87 K_TAB, //SDLK_TAB = 9,
90 K_ENTER, //SDLK_RETURN = 13,
92 K_PAUSE, //SDLK_PAUSE = 19,
94 K_ESCAPE, //SDLK_ESCAPE = 27,
96 K_SPACE, //SDLK_SPACE = 32,
97 '!', //SDLK_EXCLAIM = 33,
98 '"', //SDLK_QUOTEDBL = 34,
99 '#', //SDLK_HASH = 35,
100 '$', //SDLK_DOLLAR = 36,
102 '&', //SDLK_AMPERSAND = 38,
103 '\'', //SDLK_QUOTE = 39,
104 '(', //SDLK_LEFTPAREN = 40,
105 ')', //SDLK_RIGHTPAREN = 41,
106 '*', //SDLK_ASTERISK = 42,
107 '+', //SDLK_PLUS = 43,
108 ',', //SDLK_COMMA = 44,
109 '-', //SDLK_MINUS = 45,
110 '.', //SDLK_PERIOD = 46,
111 '/', //SDLK_SLASH = 47,
122 ':', //SDLK_COLON = 58,
123 ';', //SDLK_SEMICOLON = 59,
124 '<', //SDLK_LESS = 60,
125 '=', //SDLK_EQUALS = 61,
126 '>', //SDLK_GREATER = 62,
127 '?', //SDLK_QUESTION = 63,
129 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,
130 '[', //SDLK_LEFTBRACKET = 91,
131 '\\', //SDLK_BACKSLASH = 92,
132 ']', //SDLK_RIGHTBRACKET = 93,
133 '^', //SDLK_CARET = 94,
134 '_', //SDLK_UNDERSCORE = 95,
135 '`', //SDLK_BACKQUOTE = 96,
163 K_DEL, //SDLK_DELETE = 127,
164 hundredoh /*227*/, tenoh, tenoh, 0,0,0,0,0,0,0,0,
165 K_KP_0, //SDLK_KP0 = 256,
166 K_KP_1, //SDLK_KP1 = 257,
167 K_KP_2, //SDLK_KP2 = 258,
168 K_KP_3, //SDLK_KP3 = 259,
169 K_KP_4, //SDLK_KP4 = 260,
170 K_KP_5, //SDLK_KP5 = 261,
171 K_KP_6, //SDLK_KP6 = 262,
172 K_KP_7, //SDLK_KP7 = 263,
173 K_KP_8, //SDLK_KP8 = 264,
174 K_KP_9, //SDLK_KP9 = 265,
175 K_KP_PERIOD,//SDLK_KP_PERIOD = 266,
176 K_KP_DIVIDE,//SDLK_KP_DIVIDE = 267,
177 K_KP_MULTIPLY,//SDLK_KP_MULTIPLY= 268,
178 K_KP_MINUS, //SDLK_KP_MINUS = 269,
179 K_KP_PLUS, //SDLK_KP_PLUS = 270,
180 K_KP_ENTER, //SDLK_KP_ENTER = 271,
181 K_KP_EQUALS,//SDLK_KP_EQUALS = 272,
182 K_UPARROW, //SDLK_UP = 273,
183 K_DOWNARROW,//SDLK_DOWN = 274,
184 K_RIGHTARROW,//SDLK_RIGHT = 275,
185 K_LEFTARROW,//SDLK_LEFT = 276,
186 K_INS, //SDLK_INSERT = 277,
187 K_HOME, //SDLK_HOME = 278,
188 K_END, //SDLK_END = 279,
189 K_PGUP, //SDLK_PAGEUP = 280,
190 K_PGDN, //SDLK_PAGEDOWN = 281,
191 K_F1, //SDLK_F1 = 282,
192 K_F2, //SDLK_F2 = 283,
193 K_F3, //SDLK_F3 = 284,
194 K_F4, //SDLK_F4 = 285,
195 K_F5, //SDLK_F5 = 286,
196 K_F6, //SDLK_F6 = 287,
197 K_F7, //SDLK_F7 = 288,
198 K_F8, //SDLK_F8 = 289,
199 K_F9, //SDLK_F9 = 290,
200 K_F10, //SDLK_F10 = 291,
201 K_F11, //SDLK_F11 = 292,
202 K_F12, //SDLK_F12 = 293,
207 K_NUMLOCK, //SDLK_NUMLOCK = 300,
208 K_CAPSLOCK, //SDLK_CAPSLOCK = 301,
209 K_SCROLLOCK,//SDLK_SCROLLOCK= 302,
210 K_SHIFT, //SDLK_RSHIFT = 303,
211 K_SHIFT, //SDLK_LSHIFT = 304,
212 K_CTRL, //SDLK_RCTRL = 305,
213 K_CTRL, //SDLK_LCTRL = 306,
214 K_ALT, //SDLK_RALT = 307,
215 K_ALT, //SDLK_LALT = 308,
216 0, //SDLK_RMETA = 309,
217 0, //SDLK_LMETA = 310,
218 0, //SDLK_LSUPER = 311, /* Left "Windows" key */
219 0, //SDLK_RSUPER = 312, /* Right "Windows" key */
220 K_ALT, //SDLK_MODE = 313, /* "Alt Gr" key */
221 0, //SDLK_COMPOSE = 314, /* Multi-key compose key */
222 0, //SDLK_HELP = 315,
223 0, //SDLK_PRINT = 316,
224 0, //SDLK_SYSREQ = 317,
225 K_PAUSE, //SDLK_BREAK = 318,
226 0, //SDLK_MENU = 319,
227 0, //SDLK_POWER = 320, /* Power Macintosh power key */
228 'e', //SDLK_EURO = 321, /* Some european keyboards */
229 0 //SDLK_UNDO = 322, /* Atari keyboard has Undo */
235 static int MapKey( unsigned int sdlkey )
237 if( sdlkey > sizeof(tbl_sdltoquake)/ sizeof(int) )
239 return tbl_sdltoquake[ sdlkey ];
242 void VID_SetMouse(qboolean fullscreengrab, qboolean relative, qboolean hidecursor)
244 if (vid_usingmouse != relative)
246 vid_usingmouse = relative;
247 cl_ignoremousemoves = 2;
248 SDL_WM_GrabInput( relative ? SDL_GRAB_ON : SDL_GRAB_OFF );
250 if (vid_usinghidecursor != hidecursor)
252 vid_usinghidecursor = hidecursor;
253 SDL_ShowCursor( hidecursor ? SDL_DISABLE : SDL_ENABLE);
257 static double IN_JoystickGetAxis(SDL_Joystick *joy, int axis, double sensitivity, double deadzone)
260 if (axis < 0 || axis >= SDL_JoystickNumAxes(joy))
261 return 0; // no such axis on this joystick
262 value = SDL_JoystickGetAxis(joy, axis) * (1.0 / 32767.0);
263 value = bound(-1, value, 1);
264 if (fabs(value) < deadzone)
265 return 0; // within deadzone around center
266 return value * sensitivity;
272 static int old_x = 0, old_y = 0;
273 static int stuck = 0;
277 if(vid_stick_mouse.integer)
279 // have the mouse stuck in the middle, example use: prevent expose effect of beryl during the game when not using
280 // window grabbing. --blub
282 // we need 2 frames to initialize the center position
285 SDL_WarpMouse(win_half_width, win_half_height);
286 SDL_GetMouseState(&x, &y);
287 SDL_GetRelativeMouseState(&x, &y);
290 SDL_GetRelativeMouseState(&x, &y);
291 in_mouse_x = x + old_x;
292 in_mouse_y = y + old_y;
293 SDL_GetMouseState(&x, &y);
294 old_x = x - win_half_width;
295 old_y = y - win_half_height;
296 SDL_WarpMouse(win_half_width, win_half_height);
299 SDL_GetRelativeMouseState( &x, &y );
305 SDL_GetMouseState(&x, &y);
306 in_windowmouse_x = x;
307 in_windowmouse_y = y;
309 if (vid_numjoysticks && joy_enable.integer && joy_index.integer >= 0 && joy_index.integer < vid_numjoysticks)
311 SDL_Joystick *joy = vid_joysticks[joy_index.integer];
312 int numballs = SDL_JoystickNumBalls(joy);
313 for (j = 0;j < numballs;j++)
315 SDL_JoystickGetBall(joy, j, &x, &y);
319 cl.cmd.forwardmove += IN_JoystickGetAxis(joy, joy_axisforward.integer, joy_sensitivityforward.value, joy_deadzoneforward.value) * cl_forwardspeed.value;
320 cl.cmd.sidemove += IN_JoystickGetAxis(joy, joy_axisside.integer, joy_sensitivityside.value, joy_deadzoneside.value) * cl_sidespeed.value;
321 cl.cmd.upmove += IN_JoystickGetAxis(joy, joy_axisup.integer, joy_sensitivityup.value, joy_deadzoneup.value) * cl_upspeed.value;
322 cl.viewangles[0] += IN_JoystickGetAxis(joy, joy_axispitch.integer, joy_sensitivitypitch.value, joy_deadzonepitch.value) * cl.realframetime * cl_pitchspeed.value;
323 cl.viewangles[1] += IN_JoystickGetAxis(joy, joy_axisyaw.integer, joy_sensitivityyaw.value, joy_deadzoneyaw.value) * cl.realframetime * cl_yawspeed.value;
324 //cl.viewangles[2] += IN_JoystickGetAxis(joy, joy_axisroll.integer, joy_sensitivityroll.value, joy_deadzoneroll.value) * cl.realframetime * cl_rollspeed.value;
328 /////////////////////
332 static int Sys_EventFilter( SDL_Event *event )
334 //TODO: Add a quit query in linux, too - though linux user are more likely to know what they do
335 if (event->type == SDL_QUIT)
338 if (MessageBox( NULL, "Are you sure you want to quit?", "Confirm Exit", MB_YESNO | MB_SETFOREGROUND | MB_ICONQUESTION ) == IDNO)
346 static qboolean sdl_needs_restart;
347 static void sdl_start(void)
350 static void sdl_shutdown(void)
352 sdl_needs_restart = false;
354 static void sdl_newmap(void)
359 static keynum_t buttonremap[18] =
381 void Sys_SendKeyEvents( void )
383 static qboolean sound_active = true;
386 while( SDL_PollEvent( &event ) )
387 switch( event.type ) {
393 Key_Event( MapKey( event.key.keysym.sym ), event.key.keysym.unicode, (event.key.state == SDL_PRESSED) );
395 case SDL_ACTIVEEVENT:
396 if( event.active.state & SDL_APPACTIVE )
398 if( event.active.gain )
404 case SDL_MOUSEBUTTONDOWN:
405 case SDL_MOUSEBUTTONUP:
406 if (event.button.button <= 18)
407 Key_Event( buttonremap[event.button.button - 1], 0, event.button.state == SDL_PRESSED );
409 case SDL_JOYBUTTONDOWN:
410 if (!joy_enable.integer)
411 break; // ignore down events if joystick has been disabled
412 case SDL_JOYBUTTONUP:
413 if (event.jbutton.button < 48)
414 Key_Event( event.jbutton.button + (event.jbutton.button < 16 ? K_JOY1 : K_AUX1 - 16), 0, (event.jbutton.state == SDL_PRESSED) );
416 case SDL_VIDEORESIZE:
417 if(vid_resizable.integer < 2)
419 vid.width = event.resize.w;
420 vid.height = event.resize.h;
421 SDL_SetVideoMode(vid.width, vid.height, video_bpp, video_flags);
423 // better not call R_Modules_Restart from here directly, as this may wreak havoc...
424 // so, let's better queue it for next frame
425 if(!sdl_needs_restart)
427 Cbuf_AddText("\nr_restart\n");
428 sdl_needs_restart = true;
435 // enable/disable sound on focus gain/loss
436 if ((!vid_hidden && vid_activewindow) || !snd_mutewhenidle.integer)
449 sound_active = false;
458 void *GL_GetProcAddress(const char *name)
461 p = SDL_GL_GetProcAddress(name);
465 static int Sys_EventFilter( SDL_Event *event );
466 static qboolean vid_sdl_initjoysticksystem = false;
470 Cvar_RegisterVariable(&joy_detected);
471 Cvar_RegisterVariable(&joy_enable);
472 Cvar_RegisterVariable(&joy_index);
473 Cvar_RegisterVariable(&joy_axisforward);
474 Cvar_RegisterVariable(&joy_axisside);
475 Cvar_RegisterVariable(&joy_axisup);
476 Cvar_RegisterVariable(&joy_axispitch);
477 Cvar_RegisterVariable(&joy_axisyaw);
478 //Cvar_RegisterVariable(&joy_axisroll);
479 Cvar_RegisterVariable(&joy_deadzoneforward);
480 Cvar_RegisterVariable(&joy_deadzoneside);
481 Cvar_RegisterVariable(&joy_deadzoneup);
482 Cvar_RegisterVariable(&joy_deadzonepitch);
483 Cvar_RegisterVariable(&joy_deadzoneyaw);
484 //Cvar_RegisterVariable(&joy_deadzoneroll);
485 Cvar_RegisterVariable(&joy_sensitivityforward);
486 Cvar_RegisterVariable(&joy_sensitivityside);
487 Cvar_RegisterVariable(&joy_sensitivityup);
488 Cvar_RegisterVariable(&joy_sensitivitypitch);
489 Cvar_RegisterVariable(&joy_sensitivityyaw);
490 //Cvar_RegisterVariable(&joy_sensitivityroll);
493 R_RegisterModule("SDL", sdl_start, sdl_shutdown, sdl_newmap, NULL, NULL);
496 if (SDL_Init(SDL_INIT_VIDEO) < 0)
497 Sys_Error ("Failed to init SDL video subsystem: %s", SDL_GetError());
498 vid_sdl_initjoysticksystem = SDL_Init(SDL_INIT_JOYSTICK) >= 0;
499 if (vid_sdl_initjoysticksystem)
500 Con_Printf("Failed to init SDL joystick subsystem: %s\n", SDL_GetError());
501 vid_isfullscreen = false;
504 // set the icon (we dont use SDL here since it would be too much a PITA)
506 #include "resource.h"
507 #include <SDL_syswm.h>
508 static void VID_SetCaption(void)
514 SDL_WM_SetCaption( gamename, NULL );
516 // get the HWND handle
517 SDL_VERSION( &info.version );
518 if( !SDL_GetWMInfo( &info ) )
521 icon = LoadIcon( GetModuleHandle( NULL ), MAKEINTRESOURCE( IDI_ICON1 ) );
522 #ifndef _W64 //If Windows 64bit data types don't exist
523 #ifndef SetClassLongPtr
524 #define SetClassLongPtr SetClassLong
527 #define GCLP_HICON GCL_HICON
530 #define LONG_PTR LONG
533 SetClassLongPtr( info.window, GCLP_HICON, (LONG_PTR)icon );
535 static void VID_SetIcon(void)
539 // Adding the OS independent XPM version --blub
540 #include "darkplaces.xpm"
541 #include "nexuiz.xpm"
542 static SDL_Surface *icon = NULL;
543 static void VID_SetIcon(void)
546 * Somewhat restricted XPM reader. Only supports XPMs saved by GIMP 2.4 at
547 * default settings with less than 91 colors and transparency.
550 int width, height, colors, isize, i, j;
552 static SDL_Color palette[256];
553 unsigned short palenc[256]; // store color id by char
556 const SDL_version *version;
558 version = SDL_Linked_Version();
559 // only use non-XPM icon support in SDL v1.3 and higher
560 // SDL v1.2 does not support "smooth" transparency, and thus is better
562 if(version->major >= 2 || (version->major == 1 && version->minor >= 3))
564 data = (char *) loadimagepixelsbgra("darkplaces-icon", false, false, false, NULL);
567 unsigned int red = 0x00FF0000;
568 unsigned int green = 0x0000FF00;
569 unsigned int blue = 0x000000FF;
570 unsigned int alpha = 0xFF000000;
572 height = image_height;
574 // reallocate with malloc, as this is in tempmempool (do not want)
576 data = malloc(width * height * 4);
577 memcpy(data, xpm, width * height * 4);
581 icon = SDL_CreateRGBSurface(SDL_SRCALPHA, width, height, 32, LittleLong(red), LittleLong(green), LittleLong(blue), LittleLong(alpha));
584 Con_Printf( "Failed to create surface for the window Icon!\n"
585 "%s\n", SDL_GetError());
593 #if SDL_VIDEO_DRIVER_X11 && !SDL_VIDEO_DRIVER_QUARTZ
594 // ugly hack to upload a good icon on X11 too
598 SDL_VERSION(&info.version);
599 if(SDL_GetWMInfo(&info) == 1 && info.subsystem == SDL_SYSWM_X11)
601 data = (char *) loadimagepixelsbgra("darkplaces-icon", false, false, false, NULL);
604 // use _NET_WM_ICON too
605 static long netwm_icon[MAX_NETWM_ICON];
611 if(pos + 2 * image_width * image_height < MAX_NETWM_ICON)
613 netwm_icon[pos++] = image_width;
614 netwm_icon[pos++] = image_height;
615 for(i = 0; i < image_height; ++i)
616 for(j = 0; j < image_width; ++j)
617 netwm_icon[pos++] = BuffLittleLong((unsigned char *) &data[(i*image_width+j)*4]);
621 Con_Printf("Skipping NETWM icon #%d because there is no space left\n", i);
625 data = (char *) loadimagepixelsbgra(va("darkplaces-icon%d", i), false, false, false, NULL);
628 info.info.x11.lock_func();
630 Atom net_wm_icon = XInternAtom(info.info.x11.display, "_NET_WM_ICON", false);
631 XChangeProperty(info.info.x11.display, info.info.x11.wmwindow, net_wm_icon, XA_CARDINAL, 32, PropModeReplace, (const unsigned char *) netwm_icon, pos);
633 info.info.x11.unlock_func();
639 // we only get here if non-XPM icon was missing, or SDL version is not
640 // sufficient for transparent non-XPM icons
643 xpm = (char *) FS_LoadFile("darkplaces-icon.xpm", tempmempool, false, NULL);
646 idata = XPM_DecodeString(xpm);
654 if(sscanf(data, "%i %i %i %i", &width, &height, &colors, &isize) != 4)
656 // NOTE: Only 1-char colornames are supported
657 Con_Printf("Sorry, but this does not even look similar to an XPM.\n");
663 // NOTE: Only 1-char colornames are supported
664 Con_Printf("This XPM's palette is either huge or idiotically unoptimized. It's key size is %i\n", isize);
668 for(i = 0; i < colors; ++i)
670 unsigned int r, g, b;
673 if(sscanf(idata[i+1], "%c c #%02x%02x%02x", &idx, &r, &g, &b) != 4)
676 if(sscanf(idata[i+1], "%c c Non%1[e]", &idx, foo) != 2) // I take the DailyWTF credit for this. --div0
678 Con_Printf("This XPM's palette looks odd. Can't continue.\n");
683 palette[i].r = 255; // color key
686 thenone = i; // weeeee
691 palette[i].r = r - (r == 255 && g == 0 && b == 255); // change 255/0/255 pink to 254/0/255 for color key
696 palenc[(unsigned char) idx] = i;
699 // allocate the image data
700 data = (char*) malloc(width*height);
702 for(j = 0; j < height; ++j)
704 for(i = 0; i < width; ++i)
706 // casting to the safest possible datatypes ^^
707 data[j * width + i] = palenc[((unsigned char*)idata[colors+j+1])[i]];
713 // SDL_FreeSurface should free the data too
714 // but for completeness' sake...
715 if(icon->flags & SDL_PREALLOC)
718 icon->pixels = NULL; // safety
720 SDL_FreeSurface(icon);
723 icon = SDL_CreateRGBSurface(SDL_SRCCOLORKEY, width, height, 8, 0,0,0,0);// rmask, gmask, bmask, amask); no mask needed
724 // 8 bit surfaces get an empty palette allocated according to the docs
725 // so it's a palette image for sure :) no endian check necessary for the mask
728 Con_Printf( "Failed to create surface for the window Icon!\n"
729 "%s\n", SDL_GetError());
735 SDL_SetPalette(icon, SDL_PHYSPAL|SDL_LOGPAL, palette, 0, colors);
736 SDL_SetColorKey(icon, SDL_SRCCOLORKEY, thenone);
739 SDL_WM_SetIcon(icon, NULL);
743 static void VID_SetCaption(void)
745 SDL_WM_SetCaption( gamename, NULL );
749 static void VID_OutputVersion(void)
751 const SDL_version *version;
752 version = SDL_Linked_Version();
753 Con_Printf( "Linked against SDL version %d.%d.%d\n"
754 "Using SDL library version %d.%d.%d\n",
755 SDL_MAJOR_VERSION, SDL_MINOR_VERSION, SDL_PATCHLEVEL,
756 version->major, version->minor, version->patch );
759 qboolean VID_InitMode(viddef_mode_t *mode)
762 static int notfirstvideomode = false;
763 int flags = SDL_OPENGL;
764 const char *drivername;
766 win_half_width = mode->width>>1;
767 win_half_height = mode->height>>1;
769 if(vid_resizable.integer)
770 flags |= SDL_RESIZABLE;
776 We cant switch from one OpenGL video mode to another.
777 Thus we first switch to some stupid 2D mode and then back to OpenGL.
779 if (notfirstvideomode)
780 SDL_SetVideoMode( 0, 0, 0, 0 );
781 notfirstvideomode = true;
783 // SDL usually knows best
786 // 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
787 i = COM_CheckParm("-gl_driver");
788 if (i && i < com_argc - 1)
789 drivername = com_argv[i + 1];
790 if (SDL_GL_LoadLibrary(drivername) < 0)
792 Con_Printf("Unable to load GL driver \"%s\": %s\n", drivername, SDL_GetError());
796 if ((qglGetString = (const GLubyte* (GLAPIENTRY *)(GLenum name))GL_GetProcAddress("glGetString")) == NULL)
799 Con_Print("Required OpenGL function glGetString not found\n");
803 // Knghtbrd: should do platform-specific extension string function here
805 vid_isfullscreen = false;
806 if (mode->fullscreen) {
807 flags |= SDL_FULLSCREEN;
808 vid_isfullscreen = true;
810 //flags |= SDL_HWSURFACE;
812 SDL_GL_SetAttribute (SDL_GL_DOUBLEBUFFER, 1);
813 if (mode->bitsperpixel >= 32)
815 SDL_GL_SetAttribute (SDL_GL_RED_SIZE, 8);
816 SDL_GL_SetAttribute (SDL_GL_GREEN_SIZE, 8);
817 SDL_GL_SetAttribute (SDL_GL_BLUE_SIZE, 8);
818 SDL_GL_SetAttribute (SDL_GL_ALPHA_SIZE, 8);
819 SDL_GL_SetAttribute (SDL_GL_DEPTH_SIZE, 24);
820 SDL_GL_SetAttribute (SDL_GL_STENCIL_SIZE, 8);
824 SDL_GL_SetAttribute (SDL_GL_RED_SIZE, 5);
825 SDL_GL_SetAttribute (SDL_GL_GREEN_SIZE, 5);
826 SDL_GL_SetAttribute (SDL_GL_BLUE_SIZE, 5);
827 SDL_GL_SetAttribute (SDL_GL_DEPTH_SIZE, 16);
829 if (mode->stereobuffer)
830 SDL_GL_SetAttribute (SDL_GL_STEREO, 1);
831 if (vid_vsync.integer)
832 SDL_GL_SetAttribute (SDL_GL_SWAP_CONTROL, 1);
834 SDL_GL_SetAttribute (SDL_GL_SWAP_CONTROL, 0);
835 if (mode->samples > 1)
837 SDL_GL_SetAttribute (SDL_GL_MULTISAMPLEBUFFERS, 1);
838 SDL_GL_SetAttribute (SDL_GL_MULTISAMPLESAMPLES, mode->samples);
841 video_bpp = mode->bitsperpixel;
844 screen = SDL_SetVideoMode(mode->width, mode->height, mode->bitsperpixel, flags);
848 Con_Printf("Failed to set video mode to %ix%i: %s\n", mode->width, mode->height, SDL_GetError());
855 // set up an event filter to ask confirmation on close button in WIN32
856 SDL_SetEventFilter( (SDL_EventFilter) Sys_EventFilter );
858 SDL_EnableUNICODE( SDL_ENABLE );
859 // enable key repeat since everyone expects it
860 SDL_EnableKeyRepeat(SDL_DEFAULT_REPEAT_DELAY, SDL_DEFAULT_REPEAT_INTERVAL);
863 gl_platformextensions = "";
867 vid_numjoysticks = SDL_NumJoysticks();
868 vid_numjoysticks = bound(0, vid_numjoysticks, MAX_JOYSTICKS);
869 Cvar_SetValueQuick(&joy_detected, vid_numjoysticks);
870 Con_Printf("%d SDL joystick(s) found:\n", vid_numjoysticks);
871 memset(vid_joysticks, 0, sizeof(vid_joysticks));
872 for (i = 0;i < vid_numjoysticks;i++)
875 joy = vid_joysticks[i] = SDL_JoystickOpen(i);
878 Con_Printf("joystick #%i: open failed: %s\n", i, SDL_GetError());
881 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));
885 vid_activewindow = false;
886 vid_usingmouse = false;
887 vid_usinghidecursor = false;
889 SDL_WM_GrabInput(SDL_GRAB_OFF);
893 void VID_Shutdown (void)
895 VID_SetMouse(false, false, false);
896 VID_RestoreSystemGamma();
898 SDL_QuitSubSystem(SDL_INIT_VIDEO);
903 gl_platformextensions = "";
906 int VID_SetGamma (unsigned short *ramps, int rampsize)
908 return !SDL_SetGammaRamp (ramps, ramps + rampsize, ramps + rampsize*2);
911 int VID_GetGamma (unsigned short *ramps, int rampsize)
913 return !SDL_GetGammaRamp (ramps, ramps + rampsize, ramps + rampsize*2);
916 void VID_Finish (void)
920 //react on appstate changes
921 appstate = SDL_GetAppState();
923 vid_hidden = !(appstate & SDL_APPACTIVE);
925 if( vid_hidden || !( appstate & SDL_APPMOUSEFOCUS ) || !( appstate & SDL_APPINPUTFOCUS ) )
926 vid_activewindow = false;
928 vid_activewindow = true;
930 VID_UpdateGamma(false, 256);
935 if (r_speeds.integer == 2 || gl_finish.integer)
937 qglFinish();CHECKGLERROR
939 SDL_GL_SwapBuffers();
943 size_t VID_ListModes(vid_mode_t *modes, size_t maxcount)
947 int bpp = SDL_GetVideoInfo()->vfmt->BitsPerPixel;
950 for(vidmodes = SDL_ListModes(NULL, SDL_FULLSCREEN|SDL_HWSURFACE); *vidmodes; ++vidmodes)
954 modes[k].width = (*vidmodes)->w;
955 modes[k].height = (*vidmodes)->h;
957 modes[k].refreshrate = 60; // no support for refresh rate in SDL
958 modes[k].pixelheight_num = 1;
959 modes[k].pixelheight_denom = 1; // SDL does not provide this