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>
28 #include <Carbon/Carbon.h>
29 #include <IOKit/hidsystem/IOHIDLib.h>
30 #include <IOKit/hidsystem/IOHIDParameter.h>
31 #include <IOKit/hidsystem/event_status_driver.h>
32 static cvar_t apple_mouse_noaccel = {CVAR_SAVE, "apple_mouse_noaccel", "1", "disables mouse acceleration while DarkPlaces is active"};
33 static qboolean vid_usingnoaccel;
34 static double originalMouseSpeed = -1.0;
35 io_connect_t IN_GetIOHandle(void)
37 io_connect_t iohandle = MACH_PORT_NULL;
39 io_service_t iohidsystem = MACH_PORT_NULL;
40 mach_port_t masterport;
42 status = IOMasterPort(MACH_PORT_NULL, &masterport);
43 if(status != KERN_SUCCESS)
46 iohidsystem = IORegistryEntryFromPath(masterport, kIOServicePlane ":/IOResources/IOHIDSystem");
50 status = IOServiceOpen(iohidsystem, mach_task_self(), kIOHIDParamConnectType, &iohandle);
51 IOObjectRelease(iohidsystem);
61 // Tell startup code that we have a client
62 int cl_available = true;
64 qboolean vid_supportrefreshrate = false;
66 cvar_t joy_detected = {CVAR_READONLY, "joy_detected", "0", "number of joysticks detected by engine"};
67 cvar_t joy_enable = {CVAR_SAVE, "joy_enable", "0", "enables joystick support"};
68 cvar_t joy_index = {0, "joy_index", "0", "selects which joystick to use if you have multiple"};
69 cvar_t joy_axisforward = {0, "joy_axisforward", "1", "which joystick axis to query for forward/backward movement"};
70 cvar_t joy_axisside = {0, "joy_axisside", "0", "which joystick axis to query for right/left movement"};
71 cvar_t joy_axisup = {0, "joy_axisup", "-1", "which joystick axis to query for up/down movement"};
72 cvar_t joy_axispitch = {0, "joy_axispitch", "3", "which joystick axis to query for looking up/down"};
73 cvar_t joy_axisyaw = {0, "joy_axisyaw", "2", "which joystick axis to query for looking right/left"};
74 cvar_t joy_axisroll = {0, "joy_axisroll", "-1", "which joystick axis to query for tilting head right/left"};
75 cvar_t joy_deadzoneforward = {0, "joy_deadzoneforward", "0", "deadzone tolerance, suggested values are in the range 0 to 0.01"};
76 cvar_t joy_deadzoneside = {0, "joy_deadzoneside", "0", "deadzone tolerance, suggested values are in the range 0 to 0.01"};
77 cvar_t joy_deadzoneup = {0, "joy_deadzoneup", "0", "deadzone tolerance, suggested values are in the range 0 to 0.01"};
78 cvar_t joy_deadzonepitch = {0, "joy_deadzonepitch", "0", "deadzone tolerance, suggested values are in the range 0 to 0.01"};
79 cvar_t joy_deadzoneyaw = {0, "joy_deadzoneyaw", "0", "deadzone tolerance, suggested values are in the range 0 to 0.01"};
80 cvar_t joy_deadzoneroll = {0, "joy_deadzoneroll", "0", "deadzone tolerance, suggested values are in the range 0 to 0.01"};
81 cvar_t joy_sensitivityforward = {0, "joy_sensitivityforward", "-1", "movement multiplier"};
82 cvar_t joy_sensitivityside = {0, "joy_sensitivityside", "1", "movement multiplier"};
83 cvar_t joy_sensitivityup = {0, "joy_sensitivityup", "1", "movement multiplier"};
84 cvar_t joy_sensitivitypitch = {0, "joy_sensitivitypitch", "1", "movement multiplier"};
85 cvar_t joy_sensitivityyaw = {0, "joy_sensitivityyaw", "-1", "movement multiplier"};
86 cvar_t joy_sensitivityroll = {0, "joy_sensitivityroll", "1", "movement multiplier"};
88 static qboolean vid_usingmouse = false;
89 static qboolean vid_usinghidecursor = false;
90 static qboolean vid_isfullscreen;
91 static int vid_numjoysticks = 0;
92 #define MAX_JOYSTICKS 8
93 static SDL_Joystick *vid_joysticks[MAX_JOYSTICKS];
95 static int win_half_width = 50;
96 static int win_half_height = 50;
97 static int video_bpp, video_flags;
99 static SDL_Surface *screen;
101 /////////////////////////
104 //TODO: Add joystick support
105 //TODO: Add error checking
108 //keysym to quake keysym mapping
109 #define tenoh 0,0,0,0,0, 0,0,0,0,0
110 #define fiftyoh tenoh, tenoh, tenoh, tenoh, tenoh
111 #define hundredoh fiftyoh, fiftyoh
112 static unsigned int tbl_sdltoquake[] =
114 0,0,0,0, //SDLK_UNKNOWN = 0,
115 0,0,0,0, //SDLK_FIRST = 0,
116 K_BACKSPACE, //SDLK_BACKSPACE = 8,
117 K_TAB, //SDLK_TAB = 9,
119 0, //SDLK_CLEAR = 12,
120 K_ENTER, //SDLK_RETURN = 13,
122 K_PAUSE, //SDLK_PAUSE = 19,
124 K_ESCAPE, //SDLK_ESCAPE = 27,
126 K_SPACE, //SDLK_SPACE = 32,
127 '!', //SDLK_EXCLAIM = 33,
128 '"', //SDLK_QUOTEDBL = 34,
129 '#', //SDLK_HASH = 35,
130 '$', //SDLK_DOLLAR = 36,
132 '&', //SDLK_AMPERSAND = 38,
133 '\'', //SDLK_QUOTE = 39,
134 '(', //SDLK_LEFTPAREN = 40,
135 ')', //SDLK_RIGHTPAREN = 41,
136 '*', //SDLK_ASTERISK = 42,
137 '+', //SDLK_PLUS = 43,
138 ',', //SDLK_COMMA = 44,
139 '-', //SDLK_MINUS = 45,
140 '.', //SDLK_PERIOD = 46,
141 '/', //SDLK_SLASH = 47,
152 ':', //SDLK_COLON = 58,
153 ';', //SDLK_SEMICOLON = 59,
154 '<', //SDLK_LESS = 60,
155 '=', //SDLK_EQUALS = 61,
156 '>', //SDLK_GREATER = 62,
157 '?', //SDLK_QUESTION = 63,
159 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,
160 '[', //SDLK_LEFTBRACKET = 91,
161 '\\', //SDLK_BACKSLASH = 92,
162 ']', //SDLK_RIGHTBRACKET = 93,
163 '^', //SDLK_CARET = 94,
164 '_', //SDLK_UNDERSCORE = 95,
165 '`', //SDLK_BACKQUOTE = 96,
193 K_DEL, //SDLK_DELETE = 127,
194 hundredoh /*227*/, tenoh, tenoh, 0,0,0,0,0,0,0,0,
195 K_KP_0, //SDLK_KP0 = 256,
196 K_KP_1, //SDLK_KP1 = 257,
197 K_KP_2, //SDLK_KP2 = 258,
198 K_KP_3, //SDLK_KP3 = 259,
199 K_KP_4, //SDLK_KP4 = 260,
200 K_KP_5, //SDLK_KP5 = 261,
201 K_KP_6, //SDLK_KP6 = 262,
202 K_KP_7, //SDLK_KP7 = 263,
203 K_KP_8, //SDLK_KP8 = 264,
204 K_KP_9, //SDLK_KP9 = 265,
205 K_KP_PERIOD,//SDLK_KP_PERIOD = 266,
206 K_KP_DIVIDE,//SDLK_KP_DIVIDE = 267,
207 K_KP_MULTIPLY,//SDLK_KP_MULTIPLY= 268,
208 K_KP_MINUS, //SDLK_KP_MINUS = 269,
209 K_KP_PLUS, //SDLK_KP_PLUS = 270,
210 K_KP_ENTER, //SDLK_KP_ENTER = 271,
211 K_KP_EQUALS,//SDLK_KP_EQUALS = 272,
212 K_UPARROW, //SDLK_UP = 273,
213 K_DOWNARROW,//SDLK_DOWN = 274,
214 K_RIGHTARROW,//SDLK_RIGHT = 275,
215 K_LEFTARROW,//SDLK_LEFT = 276,
216 K_INS, //SDLK_INSERT = 277,
217 K_HOME, //SDLK_HOME = 278,
218 K_END, //SDLK_END = 279,
219 K_PGUP, //SDLK_PAGEUP = 280,
220 K_PGDN, //SDLK_PAGEDOWN = 281,
221 K_F1, //SDLK_F1 = 282,
222 K_F2, //SDLK_F2 = 283,
223 K_F3, //SDLK_F3 = 284,
224 K_F4, //SDLK_F4 = 285,
225 K_F5, //SDLK_F5 = 286,
226 K_F6, //SDLK_F6 = 287,
227 K_F7, //SDLK_F7 = 288,
228 K_F8, //SDLK_F8 = 289,
229 K_F9, //SDLK_F9 = 290,
230 K_F10, //SDLK_F10 = 291,
231 K_F11, //SDLK_F11 = 292,
232 K_F12, //SDLK_F12 = 293,
237 K_NUMLOCK, //SDLK_NUMLOCK = 300,
238 K_CAPSLOCK, //SDLK_CAPSLOCK = 301,
239 K_SCROLLOCK,//SDLK_SCROLLOCK= 302,
240 K_SHIFT, //SDLK_RSHIFT = 303,
241 K_SHIFT, //SDLK_LSHIFT = 304,
242 K_CTRL, //SDLK_RCTRL = 305,
243 K_CTRL, //SDLK_LCTRL = 306,
244 K_ALT, //SDLK_RALT = 307,
245 K_ALT, //SDLK_LALT = 308,
246 0, //SDLK_RMETA = 309,
247 0, //SDLK_LMETA = 310,
248 0, //SDLK_LSUPER = 311, /* Left "Windows" key */
249 0, //SDLK_RSUPER = 312, /* Right "Windows" key */
250 K_ALT, //SDLK_MODE = 313, /* "Alt Gr" key */
251 0, //SDLK_COMPOSE = 314, /* Multi-key compose key */
252 0, //SDLK_HELP = 315,
253 0, //SDLK_PRINT = 316,
254 0, //SDLK_SYSREQ = 317,
255 K_PAUSE, //SDLK_BREAK = 318,
256 0, //SDLK_MENU = 319,
257 0, //SDLK_POWER = 320, /* Power Macintosh power key */
258 'e', //SDLK_EURO = 321, /* Some european keyboards */
259 0 //SDLK_UNDO = 322, /* Atari keyboard has Undo */
265 static int MapKey( unsigned int sdlkey )
267 if( sdlkey > sizeof(tbl_sdltoquake)/ sizeof(int) )
269 return tbl_sdltoquake[ sdlkey ];
272 void VID_SetMouse(qboolean fullscreengrab, qboolean relative, qboolean hidecursor)
276 if(vid_usingmouse && (vid_usingnoaccel != !!apple_mouse_noaccel.integer))
277 VID_SetMouse(false, false, false); // ungrab first!
279 if (vid_usingmouse != relative)
281 vid_usingmouse = relative;
282 cl_ignoremousemoves = 2;
283 SDL_WM_GrabInput( relative ? SDL_GRAB_ON : SDL_GRAB_OFF );
287 // Save the status of mouse acceleration
288 originalMouseSpeed = -1.0; // in case of error
289 if(apple_mouse_noaccel.integer)
291 io_connect_t mouseDev = IN_GetIOHandle();
294 if(IOHIDGetAccelerationWithKey(mouseDev, CFSTR(kIOHIDMouseAccelerationType), &originalMouseSpeed) == kIOReturnSuccess)
296 Con_DPrintf("previous mouse acceleration: %f\n", originalMouseSpeed);
297 if(IOHIDSetAccelerationWithKey(mouseDev, CFSTR(kIOHIDMouseAccelerationType), -1.0) != kIOReturnSuccess)
299 Con_Print("Could not disable mouse acceleration (failed at IOHIDSetAccelerationWithKey).\n");
300 Cvar_SetValueQuick(&apple_mouse_noaccel, 0);
305 Con_Print("Could not disable mouse acceleration (failed at IOHIDGetAccelerationWithKey).\n");
306 Cvar_SetValueQuick(&apple_mouse_noaccel, 0);
308 IOServiceClose(mouseDev);
312 Con_Print("Could not disable mouse acceleration (failed at IO_GetIOHandle).\n");
313 Cvar_SetValueQuick(&apple_mouse_noaccel, 0);
317 vid_usingnoaccel = !!apple_mouse_noaccel.integer;
321 if(originalMouseSpeed != -1.0)
323 io_connect_t mouseDev = IN_GetIOHandle();
326 Con_DPrintf("restoring mouse acceleration to: %f\n", originalMouseSpeed);
327 if(IOHIDSetAccelerationWithKey(mouseDev, CFSTR(kIOHIDMouseAccelerationType), originalMouseSpeed) != kIOReturnSuccess)
328 Con_Print("Could not re-enable mouse acceleration (failed at IOHIDSetAccelerationWithKey).\n");
329 IOServiceClose(mouseDev);
332 Con_Print("Could not re-enable mouse acceleration (failed at IO_GetIOHandle).\n");
337 if (vid_usinghidecursor != hidecursor)
339 vid_usinghidecursor = hidecursor;
340 SDL_ShowCursor( hidecursor ? SDL_DISABLE : SDL_ENABLE);
344 static double IN_JoystickGetAxis(SDL_Joystick *joy, int axis, double sensitivity, double deadzone)
347 if (axis < 0 || axis >= SDL_JoystickNumAxes(joy))
348 return 0; // no such axis on this joystick
349 value = SDL_JoystickGetAxis(joy, axis) * (1.0 / 32767.0);
350 value = bound(-1, value, 1);
351 if (fabs(value) < deadzone)
352 return 0; // within deadzone around center
353 return value * sensitivity;
359 static int old_x = 0, old_y = 0;
360 static int stuck = 0;
364 if(vid_stick_mouse.integer)
366 // have the mouse stuck in the middle, example use: prevent expose effect of beryl during the game when not using
367 // window grabbing. --blub
369 // we need 2 frames to initialize the center position
372 SDL_WarpMouse(win_half_width, win_half_height);
373 SDL_GetMouseState(&x, &y);
374 SDL_GetRelativeMouseState(&x, &y);
377 SDL_GetRelativeMouseState(&x, &y);
378 in_mouse_x = x + old_x;
379 in_mouse_y = y + old_y;
380 SDL_GetMouseState(&x, &y);
381 old_x = x - win_half_width;
382 old_y = y - win_half_height;
383 SDL_WarpMouse(win_half_width, win_half_height);
386 SDL_GetRelativeMouseState( &x, &y );
392 SDL_GetMouseState(&x, &y);
393 in_windowmouse_x = x;
394 in_windowmouse_y = y;
396 if (vid_numjoysticks && joy_enable.integer && joy_index.integer >= 0 && joy_index.integer < vid_numjoysticks)
398 SDL_Joystick *joy = vid_joysticks[joy_index.integer];
399 int numballs = SDL_JoystickNumBalls(joy);
400 for (j = 0;j < numballs;j++)
402 SDL_JoystickGetBall(joy, j, &x, &y);
406 cl.cmd.forwardmove += IN_JoystickGetAxis(joy, joy_axisforward.integer, joy_sensitivityforward.value, joy_deadzoneforward.value) * cl_forwardspeed.value;
407 cl.cmd.sidemove += IN_JoystickGetAxis(joy, joy_axisside.integer, joy_sensitivityside.value, joy_deadzoneside.value) * cl_sidespeed.value;
408 cl.cmd.upmove += IN_JoystickGetAxis(joy, joy_axisup.integer, joy_sensitivityup.value, joy_deadzoneup.value) * cl_upspeed.value;
409 cl.viewangles[0] += IN_JoystickGetAxis(joy, joy_axispitch.integer, joy_sensitivitypitch.value, joy_deadzonepitch.value) * cl.realframetime * cl_pitchspeed.value;
410 cl.viewangles[1] += IN_JoystickGetAxis(joy, joy_axisyaw.integer, joy_sensitivityyaw.value, joy_deadzoneyaw.value) * cl.realframetime * cl_yawspeed.value;
411 //cl.viewangles[2] += IN_JoystickGetAxis(joy, joy_axisroll.integer, joy_sensitivityroll.value, joy_deadzoneroll.value) * cl.realframetime * cl_rollspeed.value;
415 /////////////////////
419 static int Sys_EventFilter( SDL_Event *event )
421 //TODO: Add a quit query in linux, too - though linux user are more likely to know what they do
422 if (event->type == SDL_QUIT)
425 if (MessageBox( NULL, "Are you sure you want to quit?", "Confirm Exit", MB_YESNO | MB_SETFOREGROUND | MB_ICONQUESTION ) == IDNO)
433 static qboolean sdl_needs_restart;
434 static void sdl_start(void)
437 static void sdl_shutdown(void)
439 sdl_needs_restart = false;
441 static void sdl_newmap(void)
446 static keynum_t buttonremap[18] =
468 void Sys_SendKeyEvents( void )
470 static qboolean sound_active = true;
473 while( SDL_PollEvent( &event ) )
474 switch( event.type ) {
480 Key_Event( MapKey( event.key.keysym.sym ), event.key.keysym.unicode, (event.key.state == SDL_PRESSED) );
482 case SDL_ACTIVEEVENT:
483 if( event.active.state & SDL_APPACTIVE )
485 if( event.active.gain )
491 case SDL_MOUSEBUTTONDOWN:
492 case SDL_MOUSEBUTTONUP:
493 if (event.button.button <= 18)
494 Key_Event( buttonremap[event.button.button - 1], 0, event.button.state == SDL_PRESSED );
496 case SDL_JOYBUTTONDOWN:
497 if (!joy_enable.integer)
498 break; // ignore down events if joystick has been disabled
499 case SDL_JOYBUTTONUP:
500 if (event.jbutton.button < 48)
501 Key_Event( event.jbutton.button + (event.jbutton.button < 16 ? K_JOY1 : K_AUX1 - 16), 0, (event.jbutton.state == SDL_PRESSED) );
503 case SDL_VIDEORESIZE:
504 if(vid_resizable.integer < 2)
506 vid.width = event.resize.w;
507 vid.height = event.resize.h;
508 SDL_SetVideoMode(vid.width, vid.height, video_bpp, video_flags);
510 // better not call R_Modules_Restart from here directly, as this may wreak havoc...
511 // so, let's better queue it for next frame
512 if(!sdl_needs_restart)
514 Cbuf_AddText("\nr_restart\n");
515 sdl_needs_restart = true;
522 // enable/disable sound on focus gain/loss
523 if ((!vid_hidden && vid_activewindow) || !snd_mutewhenidle.integer)
536 sound_active = false;
545 void *GL_GetProcAddress(const char *name)
548 p = SDL_GL_GetProcAddress(name);
552 static int Sys_EventFilter( SDL_Event *event );
553 static qboolean vid_sdl_initjoysticksystem = false;
558 Cvar_RegisterVariable(&apple_mouse_noaccel);
560 Cvar_RegisterVariable(&joy_detected);
561 Cvar_RegisterVariable(&joy_enable);
562 Cvar_RegisterVariable(&joy_index);
563 Cvar_RegisterVariable(&joy_axisforward);
564 Cvar_RegisterVariable(&joy_axisside);
565 Cvar_RegisterVariable(&joy_axisup);
566 Cvar_RegisterVariable(&joy_axispitch);
567 Cvar_RegisterVariable(&joy_axisyaw);
568 //Cvar_RegisterVariable(&joy_axisroll);
569 Cvar_RegisterVariable(&joy_deadzoneforward);
570 Cvar_RegisterVariable(&joy_deadzoneside);
571 Cvar_RegisterVariable(&joy_deadzoneup);
572 Cvar_RegisterVariable(&joy_deadzonepitch);
573 Cvar_RegisterVariable(&joy_deadzoneyaw);
574 //Cvar_RegisterVariable(&joy_deadzoneroll);
575 Cvar_RegisterVariable(&joy_sensitivityforward);
576 Cvar_RegisterVariable(&joy_sensitivityside);
577 Cvar_RegisterVariable(&joy_sensitivityup);
578 Cvar_RegisterVariable(&joy_sensitivitypitch);
579 Cvar_RegisterVariable(&joy_sensitivityyaw);
580 //Cvar_RegisterVariable(&joy_sensitivityroll);
583 R_RegisterModule("SDL", sdl_start, sdl_shutdown, sdl_newmap, NULL, NULL);
586 if (SDL_Init(SDL_INIT_VIDEO) < 0)
587 Sys_Error ("Failed to init SDL video subsystem: %s", SDL_GetError());
588 vid_sdl_initjoysticksystem = SDL_Init(SDL_INIT_JOYSTICK) >= 0;
589 if (vid_sdl_initjoysticksystem)
590 Con_Printf("Failed to init SDL joystick subsystem: %s\n", SDL_GetError());
591 vid_isfullscreen = false;
594 // set the icon (we dont use SDL here since it would be too much a PITA)
596 #include "resource.h"
597 #include <SDL_syswm.h>
598 static void VID_SetCaption(void)
604 SDL_WM_SetCaption( gamename, NULL );
606 // get the HWND handle
607 SDL_VERSION( &info.version );
608 if( !SDL_GetWMInfo( &info ) )
611 icon = LoadIcon( GetModuleHandle( NULL ), MAKEINTRESOURCE( IDI_ICON1 ) );
612 #ifndef _W64 //If Windows 64bit data types don't exist
613 #ifndef SetClassLongPtr
614 #define SetClassLongPtr SetClassLong
617 #define GCLP_HICON GCL_HICON
620 #define LONG_PTR LONG
623 SetClassLongPtr( info.window, GCLP_HICON, (LONG_PTR)icon );
625 static void VID_SetIcon_Pre(void)
628 static void VID_SetIcon_Post(void)
632 // Adding the OS independent XPM version --blub
633 #include "darkplaces.xpm"
634 #include "nexuiz.xpm"
635 static SDL_Surface *icon = NULL;
636 static void VID_SetIcon_Pre(void)
639 * Somewhat restricted XPM reader. Only supports XPMs saved by GIMP 2.4 at
640 * default settings with less than 91 colors and transparency.
643 int width, height, colors, isize, i, j;
645 static SDL_Color palette[256];
646 unsigned short palenc[256]; // store color id by char
649 const SDL_version *version;
651 version = SDL_Linked_Version();
652 // only use non-XPM icon support in SDL v1.3 and higher
653 // SDL v1.2 does not support "smooth" transparency, and thus is better
655 if(version->major >= 2 || (version->major == 1 && version->minor >= 3))
657 data = (char *) loadimagepixelsbgra("darkplaces-icon", false, false, false, NULL);
660 unsigned int red = 0x00FF0000;
661 unsigned int green = 0x0000FF00;
662 unsigned int blue = 0x000000FF;
663 unsigned int alpha = 0xFF000000;
665 height = image_height;
667 // reallocate with malloc, as this is in tempmempool (do not want)
669 data = malloc(width * height * 4);
670 memcpy(data, xpm, width * height * 4);
674 icon = SDL_CreateRGBSurface(SDL_SRCALPHA, width, height, 32, LittleLong(red), LittleLong(green), LittleLong(blue), LittleLong(alpha));
677 Con_Printf( "Failed to create surface for the window Icon!\n"
678 "%s\n", SDL_GetError());
687 // we only get here if non-XPM icon was missing, or SDL version is not
688 // sufficient for transparent non-XPM icons
691 xpm = (char *) FS_LoadFile("darkplaces-icon.xpm", tempmempool, false, NULL);
694 idata = XPM_DecodeString(xpm);
702 if(sscanf(data, "%i %i %i %i", &width, &height, &colors, &isize) != 4)
704 // NOTE: Only 1-char colornames are supported
705 Con_Printf("Sorry, but this does not even look similar to an XPM.\n");
711 // NOTE: Only 1-char colornames are supported
712 Con_Printf("This XPM's palette is either huge or idiotically unoptimized. It's key size is %i\n", isize);
716 for(i = 0; i < colors; ++i)
718 unsigned int r, g, b;
721 if(sscanf(idata[i+1], "%c c #%02x%02x%02x", &idx, &r, &g, &b) != 4)
724 if(sscanf(idata[i+1], "%c c Non%1[e]", &idx, foo) != 2) // I take the DailyWTF credit for this. --div0
726 Con_Printf("This XPM's palette looks odd. Can't continue.\n");
731 palette[i].r = 255; // color key
734 thenone = i; // weeeee
739 palette[i].r = r - (r == 255 && g == 0 && b == 255); // change 255/0/255 pink to 254/0/255 for color key
744 palenc[(unsigned char) idx] = i;
747 // allocate the image data
748 data = (char*) malloc(width*height);
750 for(j = 0; j < height; ++j)
752 for(i = 0; i < width; ++i)
754 // casting to the safest possible datatypes ^^
755 data[j * width + i] = palenc[((unsigned char*)idata[colors+j+1])[i]];
761 // SDL_FreeSurface should free the data too
762 // but for completeness' sake...
763 if(icon->flags & SDL_PREALLOC)
766 icon->pixels = NULL; // safety
768 SDL_FreeSurface(icon);
771 icon = SDL_CreateRGBSurface(SDL_SRCCOLORKEY, width, height, 8, 0,0,0,0);// rmask, gmask, bmask, amask); no mask needed
772 // 8 bit surfaces get an empty palette allocated according to the docs
773 // so it's a palette image for sure :) no endian check necessary for the mask
776 Con_Printf( "Failed to create surface for the window Icon!\n"
777 "%s\n", SDL_GetError());
783 SDL_SetPalette(icon, SDL_PHYSPAL|SDL_LOGPAL, palette, 0, colors);
784 SDL_SetColorKey(icon, SDL_SRCCOLORKEY, thenone);
787 SDL_WM_SetIcon(icon, NULL);
789 static void VID_SetIcon_Post(void)
791 #if SDL_VIDEO_DRIVER_X11 && !SDL_VIDEO_DRIVER_QUARTZ
794 const SDL_version *version;
796 version = SDL_Linked_Version();
797 // only use non-XPM icon support in SDL v1.3 and higher
798 // SDL v1.2 does not support "smooth" transparency, and thus is better
800 if(!(version->major >= 2 || (version->major == 1 && version->minor >= 3)))
802 // in this case, we did not set the good icon yet
804 SDL_VERSION(&info.version);
805 if(SDL_GetWMInfo(&info) == 1 && info.subsystem == SDL_SYSWM_X11)
807 data = (char *) loadimagepixelsbgra("darkplaces-icon", false, false, false, NULL);
810 // use _NET_WM_ICON too
811 static long netwm_icon[MAX_NETWM_ICON];
817 if(pos + 2 * image_width * image_height < MAX_NETWM_ICON)
819 netwm_icon[pos++] = image_width;
820 netwm_icon[pos++] = image_height;
821 for(i = 0; i < image_height; ++i)
822 for(j = 0; j < image_width; ++j)
823 netwm_icon[pos++] = BuffLittleLong((unsigned char *) &data[(i*image_width+j)*4]);
827 Con_Printf("Skipping NETWM icon #%d because there is no space left\n", i);
831 data = (char *) loadimagepixelsbgra(va("darkplaces-icon%d", i), false, false, false, NULL);
834 info.info.x11.lock_func();
836 Atom net_wm_icon = XInternAtom(info.info.x11.display, "_NET_WM_ICON", false);
837 XChangeProperty(info.info.x11.display, info.info.x11.wmwindow, net_wm_icon, XA_CARDINAL, 32, PropModeReplace, (const unsigned char *) netwm_icon, pos);
839 info.info.x11.unlock_func();
847 static void VID_SetCaption(void)
849 SDL_WM_SetCaption( gamename, NULL );
853 static void VID_OutputVersion(void)
855 const SDL_version *version;
856 version = SDL_Linked_Version();
857 Con_Printf( "Linked against SDL version %d.%d.%d\n"
858 "Using SDL library version %d.%d.%d\n",
859 SDL_MAJOR_VERSION, SDL_MINOR_VERSION, SDL_PATCHLEVEL,
860 version->major, version->minor, version->patch );
863 qboolean VID_InitMode(viddef_mode_t *mode)
866 static int notfirstvideomode = false;
867 int flags = SDL_OPENGL;
868 const char *drivername;
870 win_half_width = mode->width>>1;
871 win_half_height = mode->height>>1;
873 if(vid_resizable.integer)
874 flags |= SDL_RESIZABLE;
880 We cant switch from one OpenGL video mode to another.
881 Thus we first switch to some stupid 2D mode and then back to OpenGL.
883 if (notfirstvideomode)
884 SDL_SetVideoMode( 0, 0, 0, 0 );
885 notfirstvideomode = true;
887 // SDL usually knows best
890 // 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
891 i = COM_CheckParm("-gl_driver");
892 if (i && i < com_argc - 1)
893 drivername = com_argv[i + 1];
894 if (SDL_GL_LoadLibrary(drivername) < 0)
896 Con_Printf("Unable to load GL driver \"%s\": %s\n", drivername, SDL_GetError());
900 if ((qglGetString = (const GLubyte* (GLAPIENTRY *)(GLenum name))GL_GetProcAddress("glGetString")) == NULL)
903 Con_Print("Required OpenGL function glGetString not found\n");
907 // Knghtbrd: should do platform-specific extension string function here
909 vid_isfullscreen = false;
910 if (mode->fullscreen) {
911 flags |= SDL_FULLSCREEN;
912 vid_isfullscreen = true;
914 //flags |= SDL_HWSURFACE;
916 SDL_GL_SetAttribute (SDL_GL_DOUBLEBUFFER, 1);
917 if (mode->bitsperpixel >= 32)
919 SDL_GL_SetAttribute (SDL_GL_RED_SIZE, 8);
920 SDL_GL_SetAttribute (SDL_GL_GREEN_SIZE, 8);
921 SDL_GL_SetAttribute (SDL_GL_BLUE_SIZE, 8);
922 SDL_GL_SetAttribute (SDL_GL_ALPHA_SIZE, 8);
923 SDL_GL_SetAttribute (SDL_GL_DEPTH_SIZE, 24);
924 SDL_GL_SetAttribute (SDL_GL_STENCIL_SIZE, 8);
928 SDL_GL_SetAttribute (SDL_GL_RED_SIZE, 5);
929 SDL_GL_SetAttribute (SDL_GL_GREEN_SIZE, 5);
930 SDL_GL_SetAttribute (SDL_GL_BLUE_SIZE, 5);
931 SDL_GL_SetAttribute (SDL_GL_DEPTH_SIZE, 16);
933 if (mode->stereobuffer)
934 SDL_GL_SetAttribute (SDL_GL_STEREO, 1);
935 if (vid_vsync.integer)
936 SDL_GL_SetAttribute (SDL_GL_SWAP_CONTROL, 1);
938 SDL_GL_SetAttribute (SDL_GL_SWAP_CONTROL, 0);
939 if (mode->samples > 1)
941 SDL_GL_SetAttribute (SDL_GL_MULTISAMPLEBUFFERS, 1);
942 SDL_GL_SetAttribute (SDL_GL_MULTISAMPLESAMPLES, mode->samples);
945 video_bpp = mode->bitsperpixel;
948 screen = SDL_SetVideoMode(mode->width, mode->height, mode->bitsperpixel, flags);
953 Con_Printf("Failed to set video mode to %ix%i: %s\n", mode->width, mode->height, SDL_GetError());
960 // set up an event filter to ask confirmation on close button in WIN32
961 SDL_SetEventFilter( (SDL_EventFilter) Sys_EventFilter );
963 SDL_EnableUNICODE( SDL_ENABLE );
964 // enable key repeat since everyone expects it
965 SDL_EnableKeyRepeat(SDL_DEFAULT_REPEAT_DELAY, SDL_DEFAULT_REPEAT_INTERVAL);
968 gl_platformextensions = "";
972 vid_numjoysticks = SDL_NumJoysticks();
973 vid_numjoysticks = bound(0, vid_numjoysticks, MAX_JOYSTICKS);
974 Cvar_SetValueQuick(&joy_detected, vid_numjoysticks);
975 Con_Printf("%d SDL joystick(s) found:\n", vid_numjoysticks);
976 memset(vid_joysticks, 0, sizeof(vid_joysticks));
977 for (i = 0;i < vid_numjoysticks;i++)
980 joy = vid_joysticks[i] = SDL_JoystickOpen(i);
983 Con_Printf("joystick #%i: open failed: %s\n", i, SDL_GetError());
986 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));
990 vid_activewindow = false;
991 vid_usingmouse = false;
992 vid_usinghidecursor = false;
994 SDL_WM_GrabInput(SDL_GRAB_OFF);
998 void VID_Shutdown (void)
1000 VID_SetMouse(false, false, false);
1001 VID_RestoreSystemGamma();
1003 SDL_QuitSubSystem(SDL_INIT_VIDEO);
1008 gl_platformextensions = "";
1011 int VID_SetGamma (unsigned short *ramps, int rampsize)
1013 return !SDL_SetGammaRamp (ramps, ramps + rampsize, ramps + rampsize*2);
1016 int VID_GetGamma (unsigned short *ramps, int rampsize)
1018 return !SDL_GetGammaRamp (ramps, ramps + rampsize, ramps + rampsize*2);
1021 void VID_Finish (void)
1025 //react on appstate changes
1026 appstate = SDL_GetAppState();
1028 vid_hidden = !(appstate & SDL_APPACTIVE);
1030 if( vid_hidden || !( appstate & SDL_APPMOUSEFOCUS ) || !( appstate & SDL_APPINPUTFOCUS ) )
1031 vid_activewindow = false;
1033 vid_activewindow = true;
1035 VID_UpdateGamma(false, 256);
1040 if (r_speeds.integer == 2 || gl_finish.integer)
1042 qglFinish();CHECKGLERROR
1044 SDL_GL_SwapBuffers();
1048 size_t VID_ListModes(vid_mode_t *modes, size_t maxcount)
1051 SDL_Rect **vidmodes;
1052 int bpp = SDL_GetVideoInfo()->vfmt->BitsPerPixel;
1055 for(vidmodes = SDL_ListModes(NULL, SDL_FULLSCREEN|SDL_HWSURFACE); *vidmodes; ++vidmodes)
1059 modes[k].width = (*vidmodes)->w;
1060 modes[k].height = (*vidmodes)->h;
1062 modes[k].refreshrate = 60; // no support for refresh rate in SDL
1063 modes[k].pixelheight_num = 1;
1064 modes[k].pixelheight_denom = 1; // SDL does not provide this