]> de.git.xonotic.org Git - xonotic/darkplaces.git/blob - vid_sdl.c
ca3fa057aa94f546f6ed2fe62233eef030132ec8
[xonotic/darkplaces.git] / vid_sdl.c
1 /*
2 Copyright (C) 2003  T. Joseph Carter
3
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.
8
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.
12
13 See the GNU General Public License for more details.
14
15 You should have received a copy of the GNU General Public License
16 along with this program; if not, write to the Free Software
17 Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
18 */
19 #undef WIN32_LEAN_AND_MEAN  //hush a warning, SDL.h redefines this
20 #include <SDL.h>
21 #include <stdio.h>
22
23 #include "quakedef.h"
24 #include "image.h"
25 #include "utf8lib.h"
26
27 #ifndef __IPHONEOS__
28 #ifdef MACOSX
29 #include <Carbon/Carbon.h>
30 #include <IOKit/hidsystem/IOHIDLib.h>
31 #include <IOKit/hidsystem/IOHIDParameter.h>
32 #include <IOKit/hidsystem/event_status_driver.h>
33 static cvar_t apple_mouse_noaccel = {CVAR_SAVE, "apple_mouse_noaccel", "1", "disables mouse acceleration while DarkPlaces is active"};
34 static qboolean vid_usingnoaccel;
35 static double originalMouseSpeed = -1.0;
36 io_connect_t IN_GetIOHandle(void)
37 {
38         io_connect_t iohandle = MACH_PORT_NULL;
39         kern_return_t status;
40         io_service_t iohidsystem = MACH_PORT_NULL;
41         mach_port_t masterport;
42
43         status = IOMasterPort(MACH_PORT_NULL, &masterport);
44         if(status != KERN_SUCCESS)
45                 return 0;
46
47         iohidsystem = IORegistryEntryFromPath(masterport, kIOServicePlane ":/IOResources/IOHIDSystem");
48         if(!iohidsystem)
49                 return 0;
50
51         status = IOServiceOpen(iohidsystem, mach_task_self(), kIOHIDParamConnectType, &iohandle);
52         IOObjectRelease(iohidsystem);
53
54         return iohandle;
55 }
56 #endif
57 #endif
58
59 #ifdef WIN32
60 #define SDL_R_RESTART
61 #endif
62
63 // Tell startup code that we have a client
64 int cl_available = true;
65
66 qboolean vid_supportrefreshrate = false;
67
68 static qboolean vid_usingmouse = false;
69 static qboolean vid_usingmouse_relativeworks = false; // SDL2 workaround for unimplemented RelativeMouse mode
70 static qboolean vid_usinghidecursor = false;
71 static qboolean vid_hasfocus = false;
72 static qboolean vid_isfullscreen;
73 #if SDL_MAJOR_VERSION != 1
74 static qboolean vid_usingvsync = false;
75 #endif
76 static SDL_Joystick *vid_sdljoystick = NULL;
77 // GAME_STEELSTORM specific
78 static cvar_t *steelstorm_showing_map = NULL; // detect but do not create the cvar
79 static cvar_t *steelstorm_showing_mousecursor = NULL; // detect but do not create the cvar
80
81 static int win_half_width = 50;
82 static int win_half_height = 50;
83 static int video_bpp;
84
85 #if SDL_MAJOR_VERSION == 1
86 static SDL_Surface *video_screen;
87 static int video_flags;
88 #else
89 static SDL_GLContext context;
90 static SDL_Window *window;
91 static int window_flags;
92 #endif
93 static vid_mode_t desktop_mode;
94
95 /////////////////////////
96 // Input handling
97 ////
98 //TODO: Add error checking
99
100 #ifndef SDLK_PERCENT
101 #define SDLK_PERCENT '%'
102 #if SDL_MAJOR_VERSION == 1
103 #define SDLK_PRINTSCREEN SDLK_PRINT
104 #define SDLK_SCROLLLOCK SDLK_SCROLLOCK
105 #define SDLK_NUMLOCKCLEAR SDLK_NUMLOCK
106 #define SDLK_KP_1 SDLK_KP1
107 #define SDLK_KP_2 SDLK_KP2
108 #define SDLK_KP_3 SDLK_KP3
109 #define SDLK_KP_4 SDLK_KP4
110 #define SDLK_KP_5 SDLK_KP5
111 #define SDLK_KP_6 SDLK_KP6
112 #define SDLK_KP_7 SDLK_KP7
113 #define SDLK_KP_8 SDLK_KP8
114 #define SDLK_KP_9 SDLK_KP9
115 #define SDLK_KP_0 SDLK_KP0
116 #endif
117 #endif
118
119 static int MapKey( unsigned int sdlkey )
120 {
121         switch(sdlkey)
122         {
123         default: return 0;
124 //      case SDLK_UNKNOWN:            return K_UNKNOWN;
125         case SDLK_RETURN:             return K_ENTER;
126         case SDLK_ESCAPE:             return K_ESCAPE;
127         case SDLK_BACKSPACE:          return K_BACKSPACE;
128         case SDLK_TAB:                return K_TAB;
129         case SDLK_SPACE:              return K_SPACE;
130         case SDLK_EXCLAIM:            return '!';
131         case SDLK_QUOTEDBL:           return '"';
132         case SDLK_HASH:               return '#';
133         case SDLK_PERCENT:            return '%';
134         case SDLK_DOLLAR:             return '$';
135         case SDLK_AMPERSAND:          return '&';
136         case SDLK_QUOTE:              return '\'';
137         case SDLK_LEFTPAREN:          return '(';
138         case SDLK_RIGHTPAREN:         return ')';
139         case SDLK_ASTERISK:           return '*';
140         case SDLK_PLUS:               return '+';
141         case SDLK_COMMA:              return ',';
142         case SDLK_MINUS:              return '-';
143         case SDLK_PERIOD:             return '.';
144         case SDLK_SLASH:              return '/';
145         case SDLK_0:                  return '0';
146         case SDLK_1:                  return '1';
147         case SDLK_2:                  return '2';
148         case SDLK_3:                  return '3';
149         case SDLK_4:                  return '4';
150         case SDLK_5:                  return '5';
151         case SDLK_6:                  return '6';
152         case SDLK_7:                  return '7';
153         case SDLK_8:                  return '8';
154         case SDLK_9:                  return '9';
155         case SDLK_COLON:              return ':';
156         case SDLK_SEMICOLON:          return ';';
157         case SDLK_LESS:               return '<';
158         case SDLK_EQUALS:             return '=';
159         case SDLK_GREATER:            return '>';
160         case SDLK_QUESTION:           return '?';
161         case SDLK_AT:                 return '@';
162         case SDLK_LEFTBRACKET:        return '[';
163         case SDLK_BACKSLASH:          return '\\';
164         case SDLK_RIGHTBRACKET:       return ']';
165         case SDLK_CARET:              return '^';
166         case SDLK_UNDERSCORE:         return '_';
167         case SDLK_BACKQUOTE:          return '`';
168         case SDLK_a:                  return 'a';
169         case SDLK_b:                  return 'b';
170         case SDLK_c:                  return 'c';
171         case SDLK_d:                  return 'd';
172         case SDLK_e:                  return 'e';
173         case SDLK_f:                  return 'f';
174         case SDLK_g:                  return 'g';
175         case SDLK_h:                  return 'h';
176         case SDLK_i:                  return 'i';
177         case SDLK_j:                  return 'j';
178         case SDLK_k:                  return 'k';
179         case SDLK_l:                  return 'l';
180         case SDLK_m:                  return 'm';
181         case SDLK_n:                  return 'n';
182         case SDLK_o:                  return 'o';
183         case SDLK_p:                  return 'p';
184         case SDLK_q:                  return 'q';
185         case SDLK_r:                  return 'r';
186         case SDLK_s:                  return 's';
187         case SDLK_t:                  return 't';
188         case SDLK_u:                  return 'u';
189         case SDLK_v:                  return 'v';
190         case SDLK_w:                  return 'w';
191         case SDLK_x:                  return 'x';
192         case SDLK_y:                  return 'y';
193         case SDLK_z:                  return 'z';
194         case SDLK_CAPSLOCK:           return K_CAPSLOCK;
195         case SDLK_F1:                 return K_F1;
196         case SDLK_F2:                 return K_F2;
197         case SDLK_F3:                 return K_F3;
198         case SDLK_F4:                 return K_F4;
199         case SDLK_F5:                 return K_F5;
200         case SDLK_F6:                 return K_F6;
201         case SDLK_F7:                 return K_F7;
202         case SDLK_F8:                 return K_F8;
203         case SDLK_F9:                 return K_F9;
204         case SDLK_F10:                return K_F10;
205         case SDLK_F11:                return K_F11;
206         case SDLK_F12:                return K_F12;
207         case SDLK_PRINTSCREEN:        return K_PRINTSCREEN;
208         case SDLK_SCROLLLOCK:         return K_SCROLLOCK;
209         case SDLK_PAUSE:              return K_PAUSE;
210         case SDLK_INSERT:             return K_INS;
211         case SDLK_HOME:               return K_HOME;
212         case SDLK_PAGEUP:             return K_PGUP;
213 #ifdef __IPHONEOS__
214         case SDLK_DELETE:             return K_BACKSPACE;
215 #else
216         case SDLK_DELETE:             return K_DEL;
217 #endif
218         case SDLK_END:                return K_END;
219         case SDLK_PAGEDOWN:           return K_PGDN;
220         case SDLK_RIGHT:              return K_RIGHTARROW;
221         case SDLK_LEFT:               return K_LEFTARROW;
222         case SDLK_DOWN:               return K_DOWNARROW;
223         case SDLK_UP:                 return K_UPARROW;
224         case SDLK_NUMLOCKCLEAR:       return K_NUMLOCK;
225         case SDLK_KP_DIVIDE:          return K_KP_DIVIDE;
226         case SDLK_KP_MULTIPLY:        return K_KP_MULTIPLY;
227         case SDLK_KP_MINUS:           return K_KP_MINUS;
228         case SDLK_KP_PLUS:            return K_KP_PLUS;
229         case SDLK_KP_ENTER:           return K_KP_ENTER;
230         case SDLK_KP_1:               return ((SDL_GetModState() & KMOD_NUM) ? K_KP_1 : K_END);
231         case SDLK_KP_2:               return ((SDL_GetModState() & KMOD_NUM) ? K_KP_2 : K_DOWNARROW);
232         case SDLK_KP_3:               return ((SDL_GetModState() & KMOD_NUM) ? K_KP_3 : K_PGDN);
233         case SDLK_KP_4:               return ((SDL_GetModState() & KMOD_NUM) ? K_KP_4 : K_LEFTARROW);
234         case SDLK_KP_5:               return K_KP_5;
235         case SDLK_KP_6:               return ((SDL_GetModState() & KMOD_NUM) ? K_KP_6 : K_RIGHTARROW);
236         case SDLK_KP_7:               return ((SDL_GetModState() & KMOD_NUM) ? K_KP_7 : K_HOME);
237         case SDLK_KP_8:               return ((SDL_GetModState() & KMOD_NUM) ? K_KP_8 : K_UPARROW);
238         case SDLK_KP_9:               return ((SDL_GetModState() & KMOD_NUM) ? K_KP_9 : K_PGUP);
239         case SDLK_KP_0:               return ((SDL_GetModState() & KMOD_NUM) ? K_KP_0 : K_INS);
240         case SDLK_KP_PERIOD:          return ((SDL_GetModState() & KMOD_NUM) ? K_KP_PERIOD : K_DEL);
241 //      case SDLK_APPLICATION:        return K_APPLICATION;
242 //      case SDLK_POWER:              return K_POWER;
243         case SDLK_KP_EQUALS:          return K_KP_EQUALS;
244 //      case SDLK_F13:                return K_F13;
245 //      case SDLK_F14:                return K_F14;
246 //      case SDLK_F15:                return K_F15;
247 //      case SDLK_F16:                return K_F16;
248 //      case SDLK_F17:                return K_F17;
249 //      case SDLK_F18:                return K_F18;
250 //      case SDLK_F19:                return K_F19;
251 //      case SDLK_F20:                return K_F20;
252 //      case SDLK_F21:                return K_F21;
253 //      case SDLK_F22:                return K_F22;
254 //      case SDLK_F23:                return K_F23;
255 //      case SDLK_F24:                return K_F24;
256 //      case SDLK_EXECUTE:            return K_EXECUTE;
257 //      case SDLK_HELP:               return K_HELP;
258 //      case SDLK_MENU:               return K_MENU;
259 //      case SDLK_SELECT:             return K_SELECT;
260 //      case SDLK_STOP:               return K_STOP;
261 //      case SDLK_AGAIN:              return K_AGAIN;
262 //      case SDLK_UNDO:               return K_UNDO;
263 //      case SDLK_CUT:                return K_CUT;
264 //      case SDLK_COPY:               return K_COPY;
265 //      case SDLK_PASTE:              return K_PASTE;
266 //      case SDLK_FIND:               return K_FIND;
267 //      case SDLK_MUTE:               return K_MUTE;
268 //      case SDLK_VOLUMEUP:           return K_VOLUMEUP;
269 //      case SDLK_VOLUMEDOWN:         return K_VOLUMEDOWN;
270 //      case SDLK_KP_COMMA:           return K_KP_COMMA;
271 //      case SDLK_KP_EQUALSAS400:     return K_KP_EQUALSAS400;
272 //      case SDLK_ALTERASE:           return K_ALTERASE;
273 //      case SDLK_SYSREQ:             return K_SYSREQ;
274 //      case SDLK_CANCEL:             return K_CANCEL;
275 //      case SDLK_CLEAR:              return K_CLEAR;
276 //      case SDLK_PRIOR:              return K_PRIOR;
277 //      case SDLK_RETURN2:            return K_RETURN2;
278 //      case SDLK_SEPARATOR:          return K_SEPARATOR;
279 //      case SDLK_OUT:                return K_OUT;
280 //      case SDLK_OPER:               return K_OPER;
281 //      case SDLK_CLEARAGAIN:         return K_CLEARAGAIN;
282 //      case SDLK_CRSEL:              return K_CRSEL;
283 //      case SDLK_EXSEL:              return K_EXSEL;
284 //      case SDLK_KP_00:              return K_KP_00;
285 //      case SDLK_KP_000:             return K_KP_000;
286 //      case SDLK_THOUSANDSSEPARATOR: return K_THOUSANDSSEPARATOR;
287 //      case SDLK_DECIMALSEPARATOR:   return K_DECIMALSEPARATOR;
288 //      case SDLK_CURRENCYUNIT:       return K_CURRENCYUNIT;
289 //      case SDLK_CURRENCYSUBUNIT:    return K_CURRENCYSUBUNIT;
290 //      case SDLK_KP_LEFTPAREN:       return K_KP_LEFTPAREN;
291 //      case SDLK_KP_RIGHTPAREN:      return K_KP_RIGHTPAREN;
292 //      case SDLK_KP_LEFTBRACE:       return K_KP_LEFTBRACE;
293 //      case SDLK_KP_RIGHTBRACE:      return K_KP_RIGHTBRACE;
294 //      case SDLK_KP_TAB:             return K_KP_TAB;
295 //      case SDLK_KP_BACKSPACE:       return K_KP_BACKSPACE;
296 //      case SDLK_KP_A:               return K_KP_A;
297 //      case SDLK_KP_B:               return K_KP_B;
298 //      case SDLK_KP_C:               return K_KP_C;
299 //      case SDLK_KP_D:               return K_KP_D;
300 //      case SDLK_KP_E:               return K_KP_E;
301 //      case SDLK_KP_F:               return K_KP_F;
302 //      case SDLK_KP_XOR:             return K_KP_XOR;
303 //      case SDLK_KP_POWER:           return K_KP_POWER;
304 //      case SDLK_KP_PERCENT:         return K_KP_PERCENT;
305 //      case SDLK_KP_LESS:            return K_KP_LESS;
306 //      case SDLK_KP_GREATER:         return K_KP_GREATER;
307 //      case SDLK_KP_AMPERSAND:       return K_KP_AMPERSAND;
308 //      case SDLK_KP_DBLAMPERSAND:    return K_KP_DBLAMPERSAND;
309 //      case SDLK_KP_VERTICALBAR:     return K_KP_VERTICALBAR;
310 //      case SDLK_KP_DBLVERTICALBAR:  return K_KP_DBLVERTICALBAR;
311 //      case SDLK_KP_COLON:           return K_KP_COLON;
312 //      case SDLK_KP_HASH:            return K_KP_HASH;
313 //      case SDLK_KP_SPACE:           return K_KP_SPACE;
314 //      case SDLK_KP_AT:              return K_KP_AT;
315 //      case SDLK_KP_EXCLAM:          return K_KP_EXCLAM;
316 //      case SDLK_KP_MEMSTORE:        return K_KP_MEMSTORE;
317 //      case SDLK_KP_MEMRECALL:       return K_KP_MEMRECALL;
318 //      case SDLK_KP_MEMCLEAR:        return K_KP_MEMCLEAR;
319 //      case SDLK_KP_MEMADD:          return K_KP_MEMADD;
320 //      case SDLK_KP_MEMSUBTRACT:     return K_KP_MEMSUBTRACT;
321 //      case SDLK_KP_MEMMULTIPLY:     return K_KP_MEMMULTIPLY;
322 //      case SDLK_KP_MEMDIVIDE:       return K_KP_MEMDIVIDE;
323 //      case SDLK_KP_PLUSMINUS:       return K_KP_PLUSMINUS;
324 //      case SDLK_KP_CLEAR:           return K_KP_CLEAR;
325 //      case SDLK_KP_CLEARENTRY:      return K_KP_CLEARENTRY;
326 //      case SDLK_KP_BINARY:          return K_KP_BINARY;
327 //      case SDLK_KP_OCTAL:           return K_KP_OCTAL;
328 //      case SDLK_KP_DECIMAL:         return K_KP_DECIMAL;
329 //      case SDLK_KP_HEXADECIMAL:     return K_KP_HEXADECIMAL;
330         case SDLK_LCTRL:              return K_CTRL;
331         case SDLK_LSHIFT:             return K_SHIFT;
332         case SDLK_LALT:               return K_ALT;
333 //      case SDLK_LGUI:               return K_LGUI;
334         case SDLK_RCTRL:              return K_CTRL;
335         case SDLK_RSHIFT:             return K_SHIFT;
336         case SDLK_RALT:               return K_ALT;
337 //      case SDLK_RGUI:               return K_RGUI;
338 //      case SDLK_MODE:               return K_MODE;
339 #if SDL_MAJOR_VERSION != 1
340 //      case SDLK_AUDIONEXT:          return K_AUDIONEXT;
341 //      case SDLK_AUDIOPREV:          return K_AUDIOPREV;
342 //      case SDLK_AUDIOSTOP:          return K_AUDIOSTOP;
343 //      case SDLK_AUDIOPLAY:          return K_AUDIOPLAY;
344 //      case SDLK_AUDIOMUTE:          return K_AUDIOMUTE;
345 //      case SDLK_MEDIASELECT:        return K_MEDIASELECT;
346 //      case SDLK_WWW:                return K_WWW;
347 //      case SDLK_MAIL:               return K_MAIL;
348 //      case SDLK_CALCULATOR:         return K_CALCULATOR;
349 //      case SDLK_COMPUTER:           return K_COMPUTER;
350 //      case SDLK_AC_SEARCH:          return K_AC_SEARCH; // Android button
351 //      case SDLK_AC_HOME:            return K_AC_HOME; // Android button
352         case SDLK_AC_BACK:            return K_ESCAPE; // Android button
353 //      case SDLK_AC_FORWARD:         return K_AC_FORWARD; // Android button
354 //      case SDLK_AC_STOP:            return K_AC_STOP; // Android button
355 //      case SDLK_AC_REFRESH:         return K_AC_REFRESH; // Android button
356 //      case SDLK_AC_BOOKMARKS:       return K_AC_BOOKMARKS; // Android button
357 //      case SDLK_BRIGHTNESSDOWN:     return K_BRIGHTNESSDOWN;
358 //      case SDLK_BRIGHTNESSUP:       return K_BRIGHTNESSUP;
359 //      case SDLK_DISPLAYSWITCH:      return K_DISPLAYSWITCH;
360 //      case SDLK_KBDILLUMTOGGLE:     return K_KBDILLUMTOGGLE;
361 //      case SDLK_KBDILLUMDOWN:       return K_KBDILLUMDOWN;
362 //      case SDLK_KBDILLUMUP:         return K_KBDILLUMUP;
363 //      case SDLK_EJECT:              return K_EJECT;
364 //      case SDLK_SLEEP:              return K_SLEEP;
365 #endif
366         }
367 }
368
369 qboolean VID_HasScreenKeyboardSupport(void)
370 {
371 #if SDL_MAJOR_VERSION != 1
372         return SDL_HasScreenKeyboardSupport() != SDL_FALSE;
373 #else
374         return false;
375 #endif
376 }
377
378 void VID_ShowKeyboard(qboolean show)
379 {
380 #if SDL_MAJOR_VERSION != 1
381         if (!SDL_HasScreenKeyboardSupport())
382                 return;
383
384         if (show)
385         {
386                 if (!SDL_IsTextInputActive())
387                         SDL_StartTextInput();
388         }
389         else
390         {
391                 if (SDL_IsTextInputActive())
392                         SDL_StopTextInput();
393         }
394 #endif
395 }
396
397 qboolean VID_ShowingKeyboard(void)
398 {
399 #if SDL_MAJOR_VERSION != 1
400         return SDL_IsTextInputActive() != 0;
401 #else
402         return false;
403 #endif
404 }
405
406 void VID_SetMouse(qboolean fullscreengrab, qboolean relative, qboolean hidecursor)
407 {
408 #ifndef DP_MOBILETOUCH
409 #ifdef MACOSX
410         if(relative)
411                 if(vid_usingmouse && (vid_usingnoaccel != !!apple_mouse_noaccel.integer))
412                         VID_SetMouse(false, false, false); // ungrab first!
413 #endif
414         if (vid_usingmouse != relative)
415         {
416                 vid_usingmouse = relative;
417                 cl_ignoremousemoves = 2;
418 #if SDL_MAJOR_VERSION == 1
419                 SDL_WM_GrabInput( relative ? SDL_GRAB_ON : SDL_GRAB_OFF );
420 #else
421                 vid_usingmouse_relativeworks = SDL_SetRelativeMouseMode(relative ? SDL_TRUE : SDL_FALSE) == 0;
422 //              Con_Printf("VID_SetMouse(%i, %i, %i) relativeworks = %i\n", (int)fullscreengrab, (int)relative, (int)hidecursor, (int)vid_usingmouse_relativeworks);
423 #endif
424 #ifdef MACOSX
425                 if(relative)
426                 {
427                         // Save the status of mouse acceleration
428                         originalMouseSpeed = -1.0; // in case of error
429                         if(apple_mouse_noaccel.integer)
430                         {
431                                 io_connect_t mouseDev = IN_GetIOHandle();
432                                 if(mouseDev != 0)
433                                 {
434                                         if(IOHIDGetAccelerationWithKey(mouseDev, CFSTR(kIOHIDMouseAccelerationType), &originalMouseSpeed) == kIOReturnSuccess)
435                                         {
436                                                 Con_DPrintf("previous mouse acceleration: %f\n", originalMouseSpeed);
437                                                 if(IOHIDSetAccelerationWithKey(mouseDev, CFSTR(kIOHIDMouseAccelerationType), -1.0) != kIOReturnSuccess)
438                                                 {
439                                                         Con_Print("Could not disable mouse acceleration (failed at IOHIDSetAccelerationWithKey).\n");
440                                                         Cvar_SetValueQuick(&apple_mouse_noaccel, 0);
441                                                 }
442                                         }
443                                         else
444                                         {
445                                                 Con_Print("Could not disable mouse acceleration (failed at IOHIDGetAccelerationWithKey).\n");
446                                                 Cvar_SetValueQuick(&apple_mouse_noaccel, 0);
447                                         }
448                                         IOServiceClose(mouseDev);
449                                 }
450                                 else
451                                 {
452                                         Con_Print("Could not disable mouse acceleration (failed at IO_GetIOHandle).\n");
453                                         Cvar_SetValueQuick(&apple_mouse_noaccel, 0);
454                                 }
455                         }
456
457                         vid_usingnoaccel = !!apple_mouse_noaccel.integer;
458                 }
459                 else
460                 {
461                         if(originalMouseSpeed != -1.0)
462                         {
463                                 io_connect_t mouseDev = IN_GetIOHandle();
464                                 if(mouseDev != 0)
465                                 {
466                                         Con_DPrintf("restoring mouse acceleration to: %f\n", originalMouseSpeed);
467                                         if(IOHIDSetAccelerationWithKey(mouseDev, CFSTR(kIOHIDMouseAccelerationType), originalMouseSpeed) != kIOReturnSuccess)
468                                                 Con_Print("Could not re-enable mouse acceleration (failed at IOHIDSetAccelerationWithKey).\n");
469                                         IOServiceClose(mouseDev);
470                                 }
471                                 else
472                                         Con_Print("Could not re-enable mouse acceleration (failed at IO_GetIOHandle).\n");
473                         }
474                 }
475 #endif
476         }
477         if (vid_usinghidecursor != hidecursor)
478         {
479                 vid_usinghidecursor = hidecursor;
480                 SDL_ShowCursor( hidecursor ? SDL_DISABLE : SDL_ENABLE);
481         }
482 #endif
483 }
484
485 // multitouch[10][] represents the mouse pointer
486 // multitouch[][0]: finger active
487 // multitouch[][1]: Y
488 // multitouch[][2]: Y
489 // X and Y coordinates are 0-1.
490 #define MAXFINGERS 11
491 float multitouch[MAXFINGERS][3];
492
493 // this one stores how many areas this finger has touched
494 int multitouchs[MAXFINGERS];
495
496 // modified heavily by ELUAN
497 static qboolean VID_TouchscreenArea(int corner, float px, float py, float pwidth, float pheight, const char *icon, float textheight, const char *text, float *resultmove, qboolean *resultbutton, keynum_t key, const char *typedtext, float deadzone, float oversizepixels_x, float oversizepixels_y, qboolean iamexclusive)
498 {
499         int finger;
500         float fx, fy, fwidth, fheight;
501         float overfx, overfy, overfwidth, overfheight;
502         float rel[3];
503         float sqsum;
504         qboolean button = false;
505         VectorClear(rel);
506         if (pwidth > 0 && pheight > 0)
507         {
508                 if (corner & 1) px += vid_conwidth.value;
509                 if (corner & 2) py += vid_conheight.value;
510                 if (corner & 4) px += vid_conwidth.value * 0.5f;
511                 if (corner & 8) py += vid_conheight.value * 0.5f;
512                 if (corner & 16) {px *= vid_conwidth.value * (1.0f / 640.0f);py *= vid_conheight.value * (1.0f / 480.0f);pwidth *= vid_conwidth.value * (1.0f / 640.0f);pheight *= vid_conheight.value * (1.0f / 480.0f);}
513                 fx = px / vid_conwidth.value;
514                 fy = py / vid_conheight.value;
515                 fwidth = pwidth / vid_conwidth.value;
516                 fheight = pheight / vid_conheight.value;
517
518                 // try to prevent oversizepixels_* from interfering with the iamexclusive cvar by not letting we start controlling from too far of the actual touch area (areas without resultbuttons should NEVER have the oversizepixels_* parameters set to anything other than 0)
519                 if (resultbutton)
520                         if (!(*resultbutton))
521                         {
522                                 oversizepixels_x *= 0.2;
523                                 oversizepixels_y *= 0.2;
524                         }
525
526                 oversizepixels_x /= vid_conwidth.value;
527                 oversizepixels_y /= vid_conheight.value;
528
529                 overfx = fx - oversizepixels_x;
530                 overfy = fy - oversizepixels_y;
531                 overfwidth = fwidth + 2*oversizepixels_x;
532                 overfheight = fheight + 2*oversizepixels_y;
533
534                 for (finger = 0;finger < MAXFINGERS;finger++)
535                 {
536                         if (multitouchs[finger] && iamexclusive) // for this to work correctly, you must call touch areas in order of highest to lowest priority
537                                 continue;
538
539                         if (multitouch[finger][0] && multitouch[finger][1] >= overfx && multitouch[finger][2] >= overfy && multitouch[finger][1] < overfx + overfwidth && multitouch[finger][2] < overfy + overfheight)
540                         {
541                                 multitouchs[finger]++;
542
543                                 rel[0] = bound(-1, (multitouch[finger][1] - (fx + 0.5f * fwidth)) * (2.0f / fwidth), 1);
544                                 rel[1] = bound(-1, (multitouch[finger][2] - (fy + 0.5f * fheight)) * (2.0f / fheight), 1);
545                                 rel[2] = 0;
546
547                                 sqsum = rel[0]*rel[0] + rel[1]*rel[1];
548                                 // 2d deadzone
549                                 if (sqsum < deadzone*deadzone)
550                                 {
551                                         rel[0] = 0;
552                                         rel[1] = 0;
553                                 }
554                                 else if (sqsum > 1)
555                                 {
556                                         // ignore the third component
557                                         Vector2Normalize2(rel, rel);
558                                 }
559                                 button = true;
560                                 break;
561                         }
562                 }
563                 if (scr_numtouchscreenareas < 128)
564                 {
565                         scr_touchscreenareas[scr_numtouchscreenareas].pic = icon;
566                         scr_touchscreenareas[scr_numtouchscreenareas].text = text;
567                         scr_touchscreenareas[scr_numtouchscreenareas].textheight = textheight;
568                         scr_touchscreenareas[scr_numtouchscreenareas].rect[0] = px;
569                         scr_touchscreenareas[scr_numtouchscreenareas].rect[1] = py;
570                         scr_touchscreenareas[scr_numtouchscreenareas].rect[2] = pwidth;
571                         scr_touchscreenareas[scr_numtouchscreenareas].rect[3] = pheight;
572                         scr_touchscreenareas[scr_numtouchscreenareas].active = button;
573                         // the pics may have alpha too.
574                         scr_touchscreenareas[scr_numtouchscreenareas].activealpha = 1.f;
575                         scr_touchscreenareas[scr_numtouchscreenareas].inactivealpha = 0.95f;
576                         scr_numtouchscreenareas++;
577                 }
578         }
579         if (resultmove)
580         {
581                 if (button)
582                         VectorCopy(rel, resultmove);
583                 else
584                         VectorClear(resultmove);
585         }
586         if (resultbutton)
587         {
588                 if (*resultbutton != button)
589                 {
590                         if ((int)key > 0)
591                                 Key_Event(key, 0, button);
592                         if (typedtext && typedtext[0] && !*resultbutton)
593                         {
594                                 // FIXME: implement UTF8 support - nothing actually specifies a UTF8 string here yet, but should support it...
595                                 int i;
596                                 for (i = 0;typedtext[i];i++)
597                                 {
598                                         Key_Event(K_TEXT, typedtext[i], true);
599                                         Key_Event(K_TEXT, typedtext[i], false);
600                                 }
601                         }
602                 }
603                 *resultbutton = button;
604         }
605         return button;
606 }
607
608 // ELUAN:
609 // not reentrant, but we only need one mouse cursor anyway...
610 static void VID_TouchscreenCursor(float px, float py, float pwidth, float pheight, qboolean *resultbutton, keynum_t key)
611 {
612         int finger;
613         float fx, fy, fwidth, fheight;
614         qboolean button = false;
615         static int cursorfinger = -1;
616         static int cursorfreemovement = false;
617         static int canclick = false;
618         static int clickxy[2];
619         static int relclickxy[2];
620         static double clickrealtime = 0;
621
622         if (steelstorm_showing_mousecursor && steelstorm_showing_mousecursor->integer)
623         if (pwidth > 0 && pheight > 0)
624         {
625                 fx = px / vid_conwidth.value;
626                 fy = py / vid_conheight.value;
627                 fwidth = pwidth / vid_conwidth.value;
628                 fheight = pheight / vid_conheight.value;
629                 for (finger = 0;finger < MAXFINGERS;finger++)
630                 {
631                         if (multitouch[finger][0] && multitouch[finger][1] >= fx && multitouch[finger][2] >= fy && multitouch[finger][1] < fx + fwidth && multitouch[finger][2] < fy + fheight)
632                         {
633                                 if (cursorfinger == -1)
634                                 {
635                                         clickxy[0] =  multitouch[finger][1] * vid_width.value - 0.5f * pwidth;
636                                         clickxy[1] =  multitouch[finger][2] * vid_height.value - 0.5f * pheight;
637                                         relclickxy[0] =  (multitouch[finger][1] - fx) * vid_width.value - 0.5f * pwidth;
638                                         relclickxy[1] =  (multitouch[finger][2] - fy) * vid_height.value - 0.5f * pheight;
639                                 }
640                                 cursorfinger = finger;
641                                 button = true;
642                                 canclick = true;
643                                 cursorfreemovement = false;
644                                 break;
645                         }
646                 }
647                 if (scr_numtouchscreenareas < 128)
648                 {
649                         if (clickrealtime + 1 > realtime)
650                         {
651                                 scr_touchscreenareas[scr_numtouchscreenareas].pic = "gfx/gui/touch_puck_cur_click.tga";
652                         }
653                         else if (button)
654                         {
655                                 scr_touchscreenareas[scr_numtouchscreenareas].pic = "gfx/gui/touch_puck_cur_touch.tga";
656                         }
657                         else
658                         {
659                                 switch ((int)realtime * 10 % 20)
660                                 {
661                                 case 0:
662                                         scr_touchscreenareas[scr_numtouchscreenareas].pic = "gfx/gui/touch_puck_cur_touch.tga";
663                                         break;
664                                 default:
665                                         scr_touchscreenareas[scr_numtouchscreenareas].pic = "gfx/gui/touch_puck_cur_idle.tga";
666                                 }
667                         }
668                         scr_touchscreenareas[scr_numtouchscreenareas].text = "";
669                         scr_touchscreenareas[scr_numtouchscreenareas].textheight = 0;
670                         scr_touchscreenareas[scr_numtouchscreenareas].rect[0] = px;
671                         scr_touchscreenareas[scr_numtouchscreenareas].rect[1] = py;
672                         scr_touchscreenareas[scr_numtouchscreenareas].rect[2] = pwidth;
673                         scr_touchscreenareas[scr_numtouchscreenareas].rect[3] = pheight;
674                         scr_touchscreenareas[scr_numtouchscreenareas].active = button;
675                         scr_touchscreenareas[scr_numtouchscreenareas].activealpha = 1.0f;
676                         scr_touchscreenareas[scr_numtouchscreenareas].inactivealpha = 1.0f;
677                         scr_numtouchscreenareas++;
678                 }
679         }
680
681         if (cursorfinger != -1)
682         {
683                 if (multitouch[cursorfinger][0])
684                 {
685                         if (multitouch[cursorfinger][1] * vid_width.value - 0.5f * pwidth < clickxy[0] - 1 ||
686                                 multitouch[cursorfinger][1] * vid_width.value - 0.5f * pwidth > clickxy[0] + 1 ||
687                                 multitouch[cursorfinger][2] * vid_height.value - 0.5f * pheight< clickxy[1] - 1 ||
688                                 multitouch[cursorfinger][2] * vid_height.value - 0.5f * pheight> clickxy[1] + 1) // finger drifted more than the allowed amount
689                         {
690                                 cursorfreemovement = true;
691                         }
692                         if (cursorfreemovement)
693                         {
694                                 // in_windowmouse_x* is in screen resolution coordinates, not console resolution
695                                 in_windowmouse_x = multitouch[cursorfinger][1] * vid_width.value - 0.5f * pwidth - relclickxy[0];
696                                 in_windowmouse_y = multitouch[cursorfinger][2] * vid_height.value - 0.5f * pheight - relclickxy[1];
697                         }
698                 }
699                 else
700                 {
701                         cursorfinger = -1;
702                 }
703         }
704
705         if (resultbutton)
706         {
707                 if (/**resultbutton != button && */(int)key > 0)
708                 {
709                         if (!button && !cursorfreemovement && canclick)
710                         {
711                                 Key_Event(key, 0, true);
712                                 canclick = false;
713                                 clickrealtime = realtime;
714                         }
715
716                         // SS:BR can't qc can't cope with presses and releases on the same frame
717                         if (clickrealtime && clickrealtime + 0.1 < realtime)
718                         {
719                                 Key_Event(key, 0, false);
720                                 clickrealtime = 0;
721                         }
722                 }
723
724                 *resultbutton = button;
725         }
726 }
727
728 void VID_BuildJoyState(vid_joystate_t *joystate)
729 {
730         VID_Shared_BuildJoyState_Begin(joystate);
731
732         if (vid_sdljoystick)
733         {
734                 SDL_Joystick *joy = vid_sdljoystick;
735                 int j;
736                 int numaxes;
737                 int numbuttons;
738                 numaxes = SDL_JoystickNumAxes(joy);
739                 for (j = 0;j < numaxes;j++)
740                         joystate->axis[j] = SDL_JoystickGetAxis(joy, j) * (1.0f / 32767.0f);
741                 numbuttons = SDL_JoystickNumButtons(joy);
742                 for (j = 0;j < numbuttons;j++)
743                         joystate->button[j] = SDL_JoystickGetButton(joy, j);
744         }
745
746         VID_Shared_BuildJoyState_Finish(joystate);
747 }
748
749 // clear every touch screen area, except the one with button[skip]
750 #define Vid_ClearAllTouchscreenAreas(skip) \
751         if (skip != 0) \
752                 VID_TouchscreenCursor(0, 0, 0, 0, &buttons[0], K_MOUSE1); \
753         if (skip != 1) \
754                 VID_TouchscreenArea( 0,   0,   0,   0,   0, NULL                         , 0.0f, NULL, move, &buttons[1], K_MOUSE4, NULL, 0, 0, 0, false); \
755         if (skip != 2) \
756                 VID_TouchscreenArea( 0,   0,   0,   0,   0, NULL                         , 0.0f, NULL, aim,  &buttons[2], K_MOUSE5, NULL, 0, 0, 0, false); \
757         if (skip != 3) \
758                 VID_TouchscreenArea( 0,   0,   0,   0,   0, NULL                         , 0.0f, NULL, NULL, &buttons[3], K_SHIFT, NULL, 0, 0, 0, false); \
759         if (skip != 4) \
760                 VID_TouchscreenArea( 0,   0,   0,   0,   0, NULL                         , 0.0f, NULL, NULL, &buttons[4], K_MOUSE2, NULL, 0, 0, 0, false); \
761         if (skip != 9) \
762                 VID_TouchscreenArea( 0,   0,   0,   0,   0, NULL                         , 0.0f, NULL, NULL, &buttons[9], K_MOUSE3, NULL, 0, 0, 0, false); \
763         if (skip != 10) \
764                 VID_TouchscreenArea( 0,   0,   0,   0,   0, NULL                         , 0.0f, NULL, NULL, &buttons[10], (keynum_t)'m', NULL, 0, 0, 0, false); \
765         if (skip != 11) \
766                 VID_TouchscreenArea( 0,   0,   0,   0,   0, NULL                         , 0.0f, NULL, NULL, &buttons[11], (keynum_t)'b', NULL, 0, 0, 0, false); \
767         if (skip != 12) \
768                 VID_TouchscreenArea( 0,   0,   0,   0,   0, NULL                         , 0.0f, NULL, NULL, &buttons[12], (keynum_t)'q', NULL, 0, 0, 0, false); \
769         if (skip != 13) \
770                 VID_TouchscreenArea( 0,   0,   0,   0,   0, NULL                         , 0.0f, NULL, NULL, &buttons[13], (keynum_t)'`', NULL, 0, 0, 0, false); \
771         if (skip != 14) \
772                 VID_TouchscreenArea( 0,   0,   0,   0,   0, NULL                         , 0.0f, NULL, NULL, &buttons[14], K_ESCAPE, NULL, 0, 0, 0, false); \
773         if (skip != 15) \
774                 VID_TouchscreenArea( 0,  0,  0,  0,  0, NULL                         , 0.0f, NULL, NULL, &buttons[15], K_SPACE, NULL, 0, 0, 0, false); \
775
776 /////////////////////
777 // Movement handling
778 ////
779
780 static void IN_Move_TouchScreen_SteelStorm(void)
781 {
782         // ELUAN
783         int i, numfingers;
784         float xscale, yscale;
785         float move[3], aim[3];
786         static qboolean oldbuttons[128];
787         static qboolean buttons[128];
788         keydest_t keydest = (key_consoleactive & KEY_CONSOLEACTIVE_USER) ? key_console : key_dest;
789         memcpy(oldbuttons, buttons, sizeof(oldbuttons));
790         memset(multitouchs, 0, sizeof(multitouchs));
791
792         for (i = 0, numfingers = 0; i < MAXFINGERS - 1; i++)
793                 if (multitouch[i][0])
794                         numfingers++;
795
796         /*
797         Enable this to use a mouse as a touch device (it may conflict with the iamexclusive parameter if a finger is also reported as a mouse at the same location
798         if (numfingers == 1)
799         {
800                 multitouch[MAXFINGERS-1][0] = SDL_GetMouseState(&x, &y) ? 11 : 0;
801                 multitouch[MAXFINGERS-1][1] = (float)x / vid.width;
802                 multitouch[MAXFINGERS-1][2] = (float)y / vid.height;
803         }
804         else
805         {
806                 // disable it so it doesn't get stuck, because SDL seems to stop updating it if there are more than 1 finger on screen
807                 multitouch[MAXFINGERS-1][0] = 0;
808         }*/
809
810         // TODO: make touchscreen areas controlled by a config file or the VMs. THIS IS A MESS!
811         // TODO: can't just clear buttons[] when entering a new keydest, some keys would remain pressed
812         // SS:BR menuqc has many peculiarities, including that it can't accept more than one command per frame and pressing and releasing on the same frame
813
814         // Tuned for the SGS3, use it's value as a base. CLEAN THIS.
815         xscale = vid_touchscreen_density.value / 2.0f;
816         yscale = vid_touchscreen_density.value / 2.0f;
817         switch(keydest)
818         {
819         case key_console:
820                 Vid_ClearAllTouchscreenAreas(14);
821                 VID_TouchscreenArea( 0,   0, 160,  64,  64, "gfx/gui/touch_menu_button.tga"         , 0.0f, NULL, NULL, &buttons[14], K_ESCAPE, NULL, 0, 0, 0, false);
822                 break;
823         case key_game:
824                 if (steelstorm_showing_map && steelstorm_showing_map->integer) // FIXME: another hack to be removed when touchscreen areas go to QC
825                 {
826                         VID_TouchscreenArea( 0,   0,   0, vid_conwidth.value, vid_conheight.value, NULL                         , 0.0f, NULL, NULL, &buttons[10], (keynum_t)'m', NULL, 0, 0, 0, false);
827                         Vid_ClearAllTouchscreenAreas(10);
828                 }
829                 else if (steelstorm_showing_mousecursor && steelstorm_showing_mousecursor->integer)
830                 {
831                         // in_windowmouse_x* is in screen resolution coordinates, not console resolution
832                         VID_TouchscreenCursor((float)in_windowmouse_x/vid_width.value*vid_conwidth.value, (float)in_windowmouse_y/vid_height.value*vid_conheight.value, 192*xscale, 192*yscale, &buttons[0], K_MOUSE1);
833                         Vid_ClearAllTouchscreenAreas(0);
834                 }
835                 else
836                 {
837                         VID_TouchscreenCursor(0, 0, 0, 0, &buttons[0], K_MOUSE1);
838
839                         VID_TouchscreenArea( 2,16*xscale,-240*yscale, 224*xscale, 224*yscale, "gfx/gui/touch_l_thumb_dpad.tga", 0.0f, NULL, move, &buttons[1], (keynum_t)0, NULL, 0.15, 112*xscale, 112*yscale, false);
840
841                         VID_TouchscreenArea( 3,-240*xscale,-160*yscale, 224*xscale, 128*yscale, "gfx/gui/touch_r_thumb_turn_n_shoot.tga"    , 0.0f, NULL, NULL,  0, (keynum_t)0, NULL, 0, 56*xscale, 0, false);
842                         VID_TouchscreenArea( 3,-240*xscale,-256*yscale, 224*xscale, 224*yscale, NULL    , 0.0f, NULL, aim,  &buttons[2], (keynum_t)0, NULL, 0.2, 56*xscale, 0, false);
843
844                         VID_TouchscreenArea( 2, (vid_conwidth.value / 2) - 128,-80,  256,  80, NULL, 0.0f, NULL, NULL, &buttons[3], K_SHIFT, NULL, 0, 0, 0, true);
845
846                         VID_TouchscreenArea( 3,-240*xscale,-256*yscale, 224*xscale,  64*yscale, "gfx/gui/touch_secondary_slide.tga", 0.0f, NULL, NULL, &buttons[4], K_MOUSE2, NULL, 0, 56*xscale, 0, false);
847                         VID_TouchscreenArea( 3,-240*xscale,-256*yscale, 224*xscale,  160*yscale, NULL , 0.0f, NULL, NULL, &buttons[9], K_MOUSE3, NULL, 0.2, 56*xscale, 0, false);
848
849                         VID_TouchscreenArea( 1,-100,   0, 100, 100, NULL                         , 0.0f, NULL, NULL, &buttons[10], (keynum_t)'m', NULL, 0, 0, 0, true);
850                         VID_TouchscreenArea( 1,-100, 120, 100, 100, NULL                         , 0.0f, NULL, NULL, &buttons[11], (keynum_t)'b', NULL, 0, 0, 0, true);
851                         VID_TouchscreenArea( 0,   0,   0,  64,  64, NULL                         , 0.0f, NULL, NULL, &buttons[12], (keynum_t)'q', NULL, 0, 0, 0, true);
852                         if (developer.integer)
853                                 VID_TouchscreenArea( 0,   0,  96,  64,  64, NULL                         , 0.0f, NULL, NULL, &buttons[13], (keynum_t)'`', NULL, 0, 0, 0, true);
854                         else
855                                 VID_TouchscreenArea( 0,   0,   0,   0,   0, NULL                         , 0.0f, NULL, NULL, &buttons[13], (keynum_t)'`', NULL, 0, 0, 0, false);
856                         VID_TouchscreenArea( 0,   0, 160,  64,  64, "gfx/gui/touch_menu_button.tga"         , 0.0f, NULL, NULL, &buttons[14], K_ESCAPE, NULL, 0, 0, 0, true);
857                         switch(cl.activeweapon)
858                         {
859                         case 14:
860                                 VID_TouchscreenArea( 2,  16*xscale,-320*yscale, 224*xscale, 64*yscale, "gfx/gui/touch_booster.tga" , 0.0f, NULL, NULL, &buttons[15], K_SPACE, NULL, 0, 0, 0, true);
861                                 break;
862                         case 12:
863                                 VID_TouchscreenArea( 2,  16*xscale,-320*yscale, 224*xscale, 64*yscale, "gfx/gui/touch_shockwave.tga" , 0.0f, NULL, NULL, &buttons[15], K_SPACE, NULL, 0, 0, 0, true);
864                                 break;
865                         default:
866                                 VID_TouchscreenArea( 0,  0,  0,  0,  0, NULL , 0.0f, NULL, NULL, &buttons[15], K_SPACE, NULL, 0, 0, 0, false);
867                         }
868                 }
869                 break;
870         default:
871                 if (!steelstorm_showing_mousecursor || !steelstorm_showing_mousecursor->integer)
872                 {
873                         Vid_ClearAllTouchscreenAreas(14);
874                         // this way we can skip cutscenes
875                         VID_TouchscreenArea( 0,   0,   0, vid_conwidth.value, vid_conheight.value, NULL                         , 0.0f, NULL, NULL, &buttons[14], K_ESCAPE, NULL, 0, 0, 0, false);
876                 }
877                 else
878                 {
879                         // in_windowmouse_x* is in screen resolution coordinates, not console resolution
880                         VID_TouchscreenCursor((float)in_windowmouse_x/vid_width.value*vid_conwidth.value, (float)in_windowmouse_y/vid_height.value*vid_conheight.value, 192*xscale, 192*yscale, &buttons[0], K_MOUSE1);
881                         Vid_ClearAllTouchscreenAreas(0);
882                 }
883                 break;
884         }
885
886         if (VID_ShowingKeyboard() && (float)in_windowmouse_y > vid_height.value / 2 - 10)
887                 in_windowmouse_y = 128;
888
889         cl.cmd.forwardmove -= move[1] * cl_forwardspeed.value;
890         cl.cmd.sidemove += move[0] * cl_sidespeed.value;
891         cl.viewangles[0] += aim[1] * cl_pitchspeed.value * cl.realframetime;
892         cl.viewangles[1] -= aim[0] * cl_yawspeed.value * cl.realframetime;
893 }
894
895 static void IN_Move_TouchScreen_Quake(void)
896 {
897         int x, y;
898         float move[3], aim[3], click[3];
899         static qboolean oldbuttons[128];
900         static qboolean buttons[128];
901         keydest_t keydest = (key_consoleactive & KEY_CONSOLEACTIVE_USER) ? key_console : key_dest;
902         memcpy(oldbuttons, buttons, sizeof(oldbuttons));
903         memset(multitouchs, 0, sizeof(multitouchs));
904
905         // simple quake controls
906         multitouch[MAXFINGERS-1][0] = SDL_GetMouseState(&x, &y);
907         multitouch[MAXFINGERS-1][1] = x * 32768 / vid.width;
908         multitouch[MAXFINGERS-1][2] = y * 32768 / vid.height;
909
910         // top of screen is toggleconsole and K_ESCAPE
911         switch(keydest)
912         {
913         case key_console:
914                 VID_TouchscreenArea( 0,   0,   0,  64,  64, NULL                         , 0.0f, NULL, NULL, &buttons[13], (keynum_t)'`', NULL, 0, 0, 0, true);
915                 VID_TouchscreenArea( 0,  64,   0,  64,  64, "gfx/touch_menu.tga"         , 0.0f, NULL, NULL, &buttons[14], K_ESCAPE, NULL, 0, 0, 0, true);
916                 if (!VID_ShowingKeyboard())
917                 {
918                         // user entered a command, close the console now
919                         Con_ToggleConsole_f();
920                 }
921                 VID_TouchscreenArea( 0,   0,   0,   0,   0, NULL                         , 0.0f, NULL, NULL, &buttons[15], (keynum_t)0, NULL, 0, 0, 0, true);
922                 VID_TouchscreenArea( 0,   0,   0,   0,   0, NULL                         , 0.0f, NULL, move, &buttons[0], K_MOUSE4, NULL, 0, 0, 0, true);
923                 VID_TouchscreenArea( 0,   0,   0,   0,   0, NULL                         , 0.0f, NULL, aim,  &buttons[1], K_MOUSE5, NULL, 0, 0, 0, true);
924                 VID_TouchscreenArea( 0,   0,   0,   0,   0, NULL                         , 0.0f, NULL, click,&buttons[2], K_MOUSE1, NULL, 0, 0, 0, true);
925                 VID_TouchscreenArea( 0,   0,   0,   0,   0, NULL                         , 0.0f, NULL, NULL, &buttons[3], K_SPACE, NULL, 0, 0, 0, true);
926                 VID_TouchscreenArea( 0,   0,   0,   0,   0, NULL                         , 0.0f, NULL, NULL, &buttons[4], K_MOUSE2, NULL, 0, 0, 0, true);
927                 break;
928         case key_game:
929                 VID_TouchscreenArea( 0,   0,   0,  64,  64, NULL                         , 0.0f, NULL, NULL, &buttons[13], (keynum_t)'`', NULL, 0, 0, 0, true);
930                 VID_TouchscreenArea( 0,  64,   0,  64,  64, "gfx/touch_menu.tga"         , 0.0f, NULL, NULL, &buttons[14], K_ESCAPE, NULL, 0, 0, 0, true);
931                 VID_TouchscreenArea( 2,   0,-128, 128, 128, "gfx/touch_movebutton.tga"   , 0.0f, NULL, move, &buttons[0], K_MOUSE4, NULL, 0, 0, 0, true);
932                 VID_TouchscreenArea( 3,-128,-128, 128, 128, "gfx/touch_aimbutton.tga"    , 0.0f, NULL, aim,  &buttons[1], K_MOUSE5, NULL, 0, 0, 0, true);
933                 VID_TouchscreenArea( 2,   0,-160,  64,  32, "gfx/touch_jumpbutton.tga"   , 0.0f, NULL, NULL, &buttons[3], K_SPACE, NULL, 0, 0, 0, true);
934                 VID_TouchscreenArea( 3,-128,-160,  64,  32, "gfx/touch_attackbutton.tga" , 0.0f, NULL, NULL, &buttons[2], K_MOUSE1, NULL, 0, 0, 0, true);
935                 VID_TouchscreenArea( 3, -64,-160,  64,  32, "gfx/touch_attack2button.tga", 0.0f, NULL, NULL, &buttons[4], K_MOUSE2, NULL, 0, 0, 0, true);
936                 buttons[15] = false;
937                 break;
938         default:
939                 VID_TouchscreenArea( 0,   0,   0,  64,  64, NULL                         , 0.0f, NULL, NULL, &buttons[13], (keynum_t)'`', NULL, 0, 0, 0, true);
940                 VID_TouchscreenArea( 0,  64,   0,  64,  64, "gfx/touch_menu.tga"         , 0.0f, NULL, NULL, &buttons[14], K_ESCAPE, NULL, 0, 0, 0, true);
941                 // in menus, an icon in the corner activates keyboard
942                 VID_TouchscreenArea( 2,   0, -32,  32,  32, "gfx/touch_keyboard.tga"     , 0.0f, NULL, NULL, &buttons[15], (keynum_t)0, NULL, 0, 0, 0, true);
943                 if (buttons[15])
944                         VID_ShowKeyboard(true);
945                 VID_TouchscreenArea( 0,   0,   0,   0,   0, NULL                         , 0.0f, NULL, move, &buttons[0], K_MOUSE4, NULL, 0, 0, 0, true);
946                 VID_TouchscreenArea( 0,   0,   0,   0,   0, NULL                         , 0.0f, NULL, aim,  &buttons[1], K_MOUSE5, NULL, 0, 0, 0, true);
947                 VID_TouchscreenArea(16, -320,-480,640, 960, NULL                         , 0.0f, NULL, click,&buttons[2], K_MOUSE1, NULL, 0, 0, 0, true);
948                 VID_TouchscreenArea( 0,   0,   0,   0,   0, NULL                         , 0.0f, NULL, NULL, &buttons[3], K_SPACE, NULL, 0, 0, 0, true);
949                 VID_TouchscreenArea( 0,   0,   0,   0,   0, NULL                         , 0.0f, NULL, NULL, &buttons[4], K_MOUSE2, NULL, 0, 0, 0, true);
950                 if (buttons[2])
951                 {
952                         in_windowmouse_x = x;
953                         in_windowmouse_y = y;
954                 }
955                 break;
956         }
957
958         cl.cmd.forwardmove -= move[1] * cl_forwardspeed.value;
959         cl.cmd.sidemove += move[0] * cl_sidespeed.value;
960         cl.viewangles[0] += aim[1] * cl_pitchspeed.value * cl.realframetime;
961         cl.viewangles[1] -= aim[0] * cl_yawspeed.value * cl.realframetime;
962 }
963
964 void IN_Move( void )
965 {
966         static int old_x = 0, old_y = 0;
967         static int stuck = 0;
968         static keydest_t oldkeydest;
969         static qboolean oldshowkeyboard;
970         int x, y;
971         vid_joystate_t joystate;
972         keydest_t keydest = (key_consoleactive & KEY_CONSOLEACTIVE_USER) ? key_console : key_dest;
973
974         scr_numtouchscreenareas = 0;
975
976         // Only apply the new keyboard state if the input changes.
977         if (keydest != oldkeydest || !!vid_touchscreen_showkeyboard.integer != oldshowkeyboard)
978         {
979                 switch(keydest)
980                 {
981                         case key_console: VID_ShowKeyboard(true);break;
982                         case key_message: VID_ShowKeyboard(true);break;
983                         default: VID_ShowKeyboard(!!vid_touchscreen_showkeyboard.integer); break;
984                 }
985         }
986         oldkeydest = keydest;
987         oldshowkeyboard = !!vid_touchscreen_showkeyboard.integer;
988
989         if (vid_touchscreen.integer)
990         {
991                 switch(gamemode)
992                 {
993                 case GAME_STEELSTORM:
994                         IN_Move_TouchScreen_SteelStorm();
995                         break;
996                 default:
997                         IN_Move_TouchScreen_Quake();
998                         break;
999                 }
1000         }
1001         else
1002         {
1003                 if (vid_usingmouse)
1004                 {
1005                         if (vid_stick_mouse.integer || !vid_usingmouse_relativeworks)
1006                         {
1007                                 // have the mouse stuck in the middle, example use: prevent expose effect of beryl during the game when not using
1008                                 // window grabbing. --blub
1009         
1010                                 // we need 2 frames to initialize the center position
1011                                 if(!stuck)
1012                                 {
1013 #if SDL_MAJOR_VERSION == 1
1014                                         SDL_WarpMouse(win_half_width, win_half_height);
1015 #else
1016                                         SDL_WarpMouseInWindow(window, win_half_width, win_half_height);
1017 #endif
1018                                         SDL_GetMouseState(&x, &y);
1019                                         SDL_GetRelativeMouseState(&x, &y);
1020                                         ++stuck;
1021                                 } else {
1022                                         SDL_GetRelativeMouseState(&x, &y);
1023                                         in_mouse_x = x + old_x;
1024                                         in_mouse_y = y + old_y;
1025                                         SDL_GetMouseState(&x, &y);
1026                                         old_x = x - win_half_width;
1027                                         old_y = y - win_half_height;
1028 #if SDL_MAJOR_VERSION == 1
1029                                         SDL_WarpMouse(win_half_width, win_half_height);
1030 #else
1031                                         SDL_WarpMouseInWindow(window, win_half_width, win_half_height);
1032 #endif
1033                                 }
1034                         } else {
1035                                 SDL_GetRelativeMouseState( &x, &y );
1036                                 in_mouse_x = x;
1037                                 in_mouse_y = y;
1038                         }
1039                 }
1040
1041                 SDL_GetMouseState(&x, &y);
1042                 in_windowmouse_x = x;
1043                 in_windowmouse_y = y;
1044         }
1045
1046         VID_BuildJoyState(&joystate);
1047         VID_ApplyJoyState(&joystate);
1048 }
1049
1050 /////////////////////
1051 // Message Handling
1052 ////
1053
1054 #ifdef SDL_R_RESTART
1055 static qboolean sdl_needs_restart;
1056 static void sdl_start(void)
1057 {
1058 }
1059 static void sdl_shutdown(void)
1060 {
1061         sdl_needs_restart = false;
1062 }
1063 static void sdl_newmap(void)
1064 {
1065 }
1066 #endif
1067
1068 static keynum_t buttonremap[] =
1069 {
1070         K_MOUSE1,
1071         K_MOUSE3,
1072         K_MOUSE2,
1073 #if SDL_MAJOR_VERSION == 1
1074         // TODO Find out how SDL maps these buttons. It looks like we should
1075         // still include these for sdl2? At least the button indexes don't
1076         // differ between SDL1 and SDL2 for me, thus this array should stay the
1077         // same (in X11 button order).
1078         K_MWHEELUP,
1079         K_MWHEELDOWN,
1080 #endif
1081         K_MOUSE4,
1082         K_MOUSE5,
1083         K_MOUSE6,
1084         K_MOUSE7,
1085         K_MOUSE8,
1086         K_MOUSE9,
1087         K_MOUSE10,
1088         K_MOUSE11,
1089         K_MOUSE12,
1090         K_MOUSE13,
1091         K_MOUSE14,
1092         K_MOUSE15,
1093         K_MOUSE16,
1094 };
1095
1096 #if SDL_MAJOR_VERSION == 1
1097 // SDL
1098 void Sys_SendKeyEvents( void )
1099 {
1100         static qboolean sound_active = true;
1101         int keycode;
1102         SDL_Event event;
1103
1104         VID_EnableJoystick(true);
1105
1106         while( SDL_PollEvent( &event ) )
1107                 switch( event.type ) {
1108                         case SDL_QUIT:
1109                                 Sys_Quit(0);
1110                                 break;
1111                         case SDL_KEYDOWN:
1112                         case SDL_KEYUP:
1113                                 keycode = MapKey(event.key.keysym.sym);
1114                                 if (!VID_JoyBlockEmulatedKeys(keycode))
1115                                 {
1116                                         if(keycode == K_NUMLOCK || keycode == K_CAPSLOCK)
1117                                         {
1118                                                 // simulate down followed by up
1119                                                 Key_Event(keycode, event.key.keysym.unicode, true);
1120                                                 Key_Event(keycode, event.key.keysym.unicode, false);
1121                                                 break;
1122                                         }
1123                                         Key_Event(keycode, event.key.keysym.unicode, (event.key.state == SDL_PRESSED));
1124                                 }
1125                                 break;
1126                         case SDL_ACTIVEEVENT:
1127                                 if( event.active.state & SDL_APPACTIVE )
1128                                 {
1129                                         if( event.active.gain )
1130                                                 vid_hidden = false;
1131                                         else
1132                                                 vid_hidden = true;
1133                                 }
1134                                 break;
1135                         case SDL_MOUSEBUTTONDOWN:
1136                         case SDL_MOUSEBUTTONUP:
1137                                 if (!vid_touchscreen.integer)
1138                                 if (event.button.button > 0 && event.button.button <= ARRAY_SIZE(buttonremap))
1139                                         Key_Event( buttonremap[event.button.button - 1], 0, event.button.state == SDL_PRESSED );
1140                                 break;
1141                         case SDL_JOYBUTTONDOWN:
1142                         case SDL_JOYBUTTONUP:
1143                         case SDL_JOYAXISMOTION:
1144                         case SDL_JOYBALLMOTION:
1145                         case SDL_JOYHATMOTION:
1146                                 break;
1147                         case SDL_VIDEOEXPOSE:
1148                                 break;
1149                         case SDL_VIDEORESIZE:
1150                                 if(vid_resizable.integer < 2 || vid_isfullscreen)
1151                                 {
1152                                         vid.width = event.resize.w;
1153                                         vid.height = event.resize.h;
1154                                         if (!vid_isfullscreen)
1155                                                 video_screen = SDL_SetVideoMode(vid.width, vid.height, video_bpp, video_flags);
1156 #ifdef SDL_R_RESTART
1157                                         // better not call R_Modules_Restart from here directly, as this may wreak havoc...
1158                                         // so, let's better queue it for next frame
1159                                         if(!sdl_needs_restart)
1160                                         {
1161                                                 Cbuf_AddText("\nr_restart\n");
1162                                                 sdl_needs_restart = true;
1163                                         }
1164 #endif
1165                                 }
1166                                 break;
1167 #if SDL_MAJOR_VERSION != 1
1168                         case SDL_TEXTEDITING:
1169                                 break;
1170                         case SDL_TEXTINPUT:
1171                                 break;
1172 #endif
1173                         case SDL_MOUSEMOTION:
1174                                 break;
1175                         default:
1176                                 Con_DPrintf("Received unrecognized SDL_Event type 0x%x\n", event.type);
1177                                 break;
1178                 }
1179
1180         // enable/disable sound on focus gain/loss
1181         if ((!vid_hidden && vid_activewindow) || !snd_mutewhenidle.integer)
1182         {
1183                 if (!sound_active)
1184                 {
1185                         S_UnblockSound ();
1186                         sound_active = true;
1187                 }
1188         }
1189         else
1190         {
1191                 if (sound_active)
1192                 {
1193                         S_BlockSound ();
1194                         sound_active = false;
1195                 }
1196         }
1197 }
1198
1199 #else
1200
1201 //#define DEBUGSDLEVENTS
1202
1203 // SDL2
1204 void Sys_SendKeyEvents( void )
1205 {
1206         static qboolean sound_active = true;
1207         int keycode;
1208         int i;
1209         qboolean isdown;
1210         Uchar unicode;
1211         SDL_Event event;
1212
1213         VID_EnableJoystick(true);
1214
1215         while( SDL_PollEvent( &event ) )
1216                 loop_start:
1217                 switch( event.type ) {
1218                         case SDL_QUIT:
1219 #ifdef DEBUGSDLEVENTS
1220                                 Con_DPrintf("SDL_Event: SDL_QUIT\n");
1221 #endif
1222                                 Sys_Quit(0);
1223                                 break;
1224                         case SDL_KEYDOWN:
1225                         case SDL_KEYUP:
1226 #ifdef DEBUGSDLEVENTS
1227                                 if (event.type == SDL_KEYDOWN)
1228                                         Con_DPrintf("SDL_Event: SDL_KEYDOWN %i\n", event.key.keysym.sym);
1229                                 else
1230                                         Con_DPrintf("SDL_Event: SDL_KEYUP %i\n", event.key.keysym.sym);
1231 #endif
1232                                 keycode = MapKey(event.key.keysym.sym);
1233                                 isdown = (event.key.state == SDL_PRESSED);
1234                                 unicode = 0;
1235                                 if(isdown)
1236                                 {
1237                                         if(SDL_PollEvent(&event))
1238                                         {
1239                                                 if(event.type == SDL_TEXTINPUT)
1240                                                 {
1241                                                         // combine key code from SDL_KEYDOWN event and character
1242                                                         // from SDL_TEXTINPUT event in a single Key_Event call
1243 #ifdef DEBUGSDLEVENTS
1244                                                         Con_DPrintf("SDL_Event: SDL_TEXTINPUT - text: %s\n", event.text.text);
1245 #endif
1246                                                         unicode = u8_getchar_utf8_enabled(event.text.text + (int)u8_bytelen(event.text.text, 0), NULL);
1247                                                 }
1248                                                 else
1249                                                 {
1250                                                         if (!VID_JoyBlockEmulatedKeys(keycode))
1251                                                                 Key_Event(keycode, 0, isdown);
1252                                                         goto loop_start;
1253                                                 }
1254                                         }
1255                                 }
1256                                 if (!VID_JoyBlockEmulatedKeys(keycode))
1257                                         Key_Event(keycode, unicode, isdown);
1258                                 break;
1259                         case SDL_MOUSEBUTTONDOWN:
1260                         case SDL_MOUSEBUTTONUP:
1261 #ifdef DEBUGSDLEVENTS
1262                                 if (event.type == SDL_MOUSEBUTTONDOWN)
1263                                         Con_DPrintf("SDL_Event: SDL_MOUSEBUTTONDOWN\n");
1264                                 else
1265                                         Con_DPrintf("SDL_Event: SDL_MOUSEBUTTONUP\n");
1266 #endif
1267                                 if (!vid_touchscreen.integer)
1268                                 if (event.button.button > 0 && event.button.button <= ARRAY_SIZE(buttonremap))
1269                                         Key_Event( buttonremap[event.button.button - 1], 0, event.button.state == SDL_PRESSED );
1270                                 break;
1271                         case SDL_MOUSEWHEEL:
1272                                 // TODO support wheel x direction.
1273                                 i = event.wheel.y;
1274                                 while (i > 0) {
1275                                         --i;
1276                                         Key_Event( K_MWHEELUP, 0, true );
1277                                         Key_Event( K_MWHEELUP, 0, false );
1278                                 }
1279                                 while (i < 0) {
1280                                         ++i;
1281                                         Key_Event( K_MWHEELDOWN, 0, true );
1282                                         Key_Event( K_MWHEELDOWN, 0, false );
1283                                 }
1284                                 break;
1285                         case SDL_JOYBUTTONDOWN:
1286                         case SDL_JOYBUTTONUP:
1287                         case SDL_JOYAXISMOTION:
1288                         case SDL_JOYBALLMOTION:
1289                         case SDL_JOYHATMOTION:
1290 #ifdef DEBUGSDLEVENTS
1291                                 Con_DPrintf("SDL_Event: SDL_JOY*\n");
1292 #endif
1293                                 break;
1294                         case SDL_WINDOWEVENT:
1295 #ifdef DEBUGSDLEVENTS
1296                                 Con_DPrintf("SDL_Event: SDL_WINDOWEVENT %i\n", (int)event.window.event);
1297 #endif
1298                                 //if (event.window.windowID == window) // how to compare?
1299                                 {
1300                                         switch(event.window.event)
1301                                         {
1302                                         case SDL_WINDOWEVENT_SHOWN:
1303                                                 vid_hidden = false;
1304                                                 break;
1305                                         case  SDL_WINDOWEVENT_HIDDEN:
1306                                                 vid_hidden = true;
1307                                                 break;
1308                                         case SDL_WINDOWEVENT_EXPOSED:
1309 #ifdef DEBUGSDLEVENTS
1310                                                 Con_DPrintf("SDL_Event: SDL_WINDOWEVENT_EXPOSED\n");
1311 #endif
1312                                                 break;
1313                                         case SDL_WINDOWEVENT_MOVED:
1314                                                 break;
1315                                         case SDL_WINDOWEVENT_RESIZED:
1316                                                 if(vid_resizable.integer < 2)
1317                                                 {
1318                                                         vid.width = event.window.data1;
1319                                                         vid.height = event.window.data2;
1320 #ifdef SDL_R_RESTART
1321                                                         // better not call R_Modules_Restart from here directly, as this may wreak havoc...
1322                                                         // so, let's better queue it for next frame
1323                                                         if(!sdl_needs_restart)
1324                                                         {
1325                                                                 Cbuf_AddText("\nr_restart\n");
1326                                                                 sdl_needs_restart = true;
1327                                                         }
1328 #endif
1329                                                 }
1330                                                 break;
1331                                         case SDL_WINDOWEVENT_MINIMIZED:
1332                                                 break;
1333                                         case SDL_WINDOWEVENT_MAXIMIZED:
1334                                                 break;
1335                                         case SDL_WINDOWEVENT_RESTORED:
1336                                                 break;
1337                                         case SDL_WINDOWEVENT_ENTER:
1338                                                 break;
1339                                         case SDL_WINDOWEVENT_LEAVE:
1340                                                 break;
1341                                         case SDL_WINDOWEVENT_FOCUS_GAINED:
1342                                                 vid_hasfocus = true;
1343                                                 break;
1344                                         case SDL_WINDOWEVENT_FOCUS_LOST:
1345                                                 vid_hasfocus = false;
1346                                                 break;
1347                                         case SDL_WINDOWEVENT_CLOSE:
1348                                                 Sys_Quit(0);
1349                                                 break;
1350                                         }
1351                                 }
1352                                 break;
1353                         case SDL_TEXTEDITING:
1354 #ifdef DEBUGSDLEVENTS
1355                                 Con_DPrintf("SDL_Event: SDL_TEXTEDITING - composition = %s, cursor = %d, selection lenght = %d\n", event.edit.text, event.edit.start, event.edit.length);
1356 #endif
1357                                 // FIXME!  this is where composition gets supported
1358                                 break;
1359                         case SDL_TEXTINPUT:
1360 #ifdef DEBUGSDLEVENTS
1361                                 Con_DPrintf("SDL_Event: SDL_TEXTINPUT - text: %s\n", event.text.text);
1362 #endif
1363                                 // convert utf8 string to char
1364                                 // NOTE: this code is supposed to run even if utf8enable is 0
1365                                 unicode = u8_getchar_utf8_enabled(event.text.text + (int)u8_bytelen(event.text.text, 0), NULL);
1366                                 Key_Event(K_TEXT, unicode, true);
1367                                 Key_Event(K_TEXT, unicode, false);
1368                                 break;
1369                         case SDL_MOUSEMOTION:
1370                                 break;
1371                         case SDL_FINGERDOWN:
1372 #ifdef DEBUGSDLEVENTS
1373                                 Con_DPrintf("SDL_FINGERDOWN for finger %i\n", (int)event.tfinger.fingerId);
1374 #endif
1375                                 for (i = 0;i < MAXFINGERS-1;i++)
1376                                 {
1377                                         if (!multitouch[i][0])
1378                                         {
1379                                                 multitouch[i][0] = event.tfinger.fingerId + 1;
1380                                                 multitouch[i][1] = event.tfinger.x;
1381                                                 multitouch[i][2] = event.tfinger.y;
1382                                                 // TODO: use event.tfinger.pressure?
1383                                                 break;
1384                                         }
1385                                 }
1386                                 if (i == MAXFINGERS-1)
1387                                         Con_DPrintf("Too many fingers at once!\n");
1388                                 break;
1389                         case SDL_FINGERUP:
1390 #ifdef DEBUGSDLEVENTS
1391                                 Con_DPrintf("SDL_FINGERUP for finger %i\n", (int)event.tfinger.fingerId);
1392 #endif
1393                                 for (i = 0;i < MAXFINGERS-1;i++)
1394                                 {
1395                                         if (multitouch[i][0] == event.tfinger.fingerId + 1)
1396                                         {
1397                                                 multitouch[i][0] = 0;
1398                                                 break;
1399                                         }
1400                                 }
1401                                 if (i == MAXFINGERS-1)
1402                                         Con_DPrintf("No SDL_FINGERDOWN event matches this SDL_FINGERMOTION event\n");
1403                                 break;
1404                         case SDL_FINGERMOTION:
1405 #ifdef DEBUGSDLEVENTS
1406                                 Con_DPrintf("SDL_FINGERMOTION for finger %i\n", (int)event.tfinger.fingerId);
1407 #endif
1408                                 for (i = 0;i < MAXFINGERS-1;i++)
1409                                 {
1410                                         if (multitouch[i][0] == event.tfinger.fingerId + 1)
1411                                         {
1412                                                 multitouch[i][1] = event.tfinger.x;
1413                                                 multitouch[i][2] = event.tfinger.y;
1414                                                 break;
1415                                         }
1416                                 }
1417                                 if (i == MAXFINGERS-1)
1418                                         Con_DPrintf("No SDL_FINGERDOWN event matches this SDL_FINGERMOTION event\n");
1419                                 break;
1420                         default:
1421 #ifdef DEBUGSDLEVENTS
1422                                 Con_DPrintf("Received unrecognized SDL_Event type 0x%x\n", event.type);
1423 #endif
1424                                 break;
1425                 }
1426
1427         // enable/disable sound on focus gain/loss
1428         if ((!vid_hidden && vid_activewindow) || !snd_mutewhenidle.integer)
1429         {
1430                 if (!sound_active)
1431                 {
1432                         S_UnblockSound ();
1433                         sound_active = true;
1434                 }
1435         }
1436         else
1437         {
1438                 if (sound_active)
1439                 {
1440                         S_BlockSound ();
1441                         sound_active = false;
1442                 }
1443         }
1444 }
1445 #endif
1446
1447 /////////////////
1448 // Video system
1449 ////
1450
1451 #ifdef USE_GLES2
1452 #ifndef qglClear
1453 #ifdef __IPHONEOS__
1454 #include <OpenGLES/ES2/gl.h>
1455 #else
1456 #include <SDL_opengles.h>
1457 #endif
1458
1459 //#define PRECALL //Con_Printf("GLCALL %s:%i\n", __FILE__, __LINE__)
1460 #define PRECALL
1461 #define POSTCALL
1462 GLboolean wrapglIsBuffer(GLuint buffer) {PRECALL;return glIsBuffer(buffer);POSTCALL;}
1463 GLboolean wrapglIsEnabled(GLenum cap) {PRECALL;return glIsEnabled(cap);POSTCALL;}
1464 GLboolean wrapglIsFramebuffer(GLuint framebuffer) {PRECALL;return glIsFramebuffer(framebuffer);POSTCALL;}
1465 //GLboolean wrapglIsQuery(GLuint qid) {PRECALL;return glIsQuery(qid);POSTCALL;}
1466 GLboolean wrapglIsRenderbuffer(GLuint renderbuffer) {PRECALL;return glIsRenderbuffer(renderbuffer);POSTCALL;}
1467 //GLboolean wrapglUnmapBuffer(GLenum target) {PRECALL;return glUnmapBuffer(target);POSTCALL;}
1468 GLenum wrapglCheckFramebufferStatus(GLenum target) {PRECALL;return glCheckFramebufferStatus(target);POSTCALL;}
1469 GLenum wrapglGetError(void) {PRECALL;return glGetError();POSTCALL;}
1470 GLuint wrapglCreateProgram(void) {PRECALL;return glCreateProgram();POSTCALL;}
1471 GLuint wrapglCreateShader(GLenum shaderType) {PRECALL;return glCreateShader(shaderType);POSTCALL;}
1472 //GLuint wrapglGetHandle(GLenum pname) {PRECALL;return glGetHandle(pname);POSTCALL;}
1473 GLint wrapglGetAttribLocation(GLuint programObj, const GLchar *name) {PRECALL;return glGetAttribLocation(programObj, name);POSTCALL;}
1474 GLint wrapglGetUniformLocation(GLuint programObj, const GLchar *name) {PRECALL;return glGetUniformLocation(programObj, name);POSTCALL;}
1475 //GLvoid* wrapglMapBuffer(GLenum target, GLenum access) {PRECALL;return glMapBuffer(target, access);POSTCALL;}
1476 const GLubyte* wrapglGetString(GLenum name) {PRECALL;return (const GLubyte*)glGetString(name);POSTCALL;}
1477 void wrapglActiveStencilFace(GLenum e) {PRECALL;Con_Printf("glActiveStencilFace(e)\n");POSTCALL;}
1478 void wrapglActiveTexture(GLenum e) {PRECALL;glActiveTexture(e);POSTCALL;}
1479 void wrapglArrayElement(GLint i) {PRECALL;Con_Printf("glArrayElement(i)\n");POSTCALL;}
1480 void wrapglAttachShader(GLuint containerObj, GLuint obj) {PRECALL;glAttachShader(containerObj, obj);POSTCALL;}
1481 //void wrapglBeginQuery(GLenum target, GLuint qid) {PRECALL;glBeginQuery(target, qid);POSTCALL;}
1482 void wrapglBindAttribLocation(GLuint programObj, GLuint index, const GLchar *name) {PRECALL;glBindAttribLocation(programObj, index, name);POSTCALL;}
1483 //void wrapglBindFragDataLocation(GLuint programObj, GLuint index, const GLchar *name) {PRECALL;glBindFragDataLocation(programObj, index, name);POSTCALL;}
1484 void wrapglBindBuffer(GLenum target, GLuint buffer) {PRECALL;glBindBuffer(target, buffer);POSTCALL;}
1485 void wrapglBindFramebuffer(GLenum target, GLuint framebuffer) {PRECALL;glBindFramebuffer(target, framebuffer);POSTCALL;}
1486 void wrapglBindRenderbuffer(GLenum target, GLuint renderbuffer) {PRECALL;glBindRenderbuffer(target, renderbuffer);POSTCALL;}
1487 void wrapglBindTexture(GLenum target, GLuint texture) {PRECALL;glBindTexture(target, texture);POSTCALL;}
1488 void wrapglBlendEquation(GLenum e) {PRECALL;glBlendEquation(e);POSTCALL;}
1489 void wrapglBlendFunc(GLenum sfactor, GLenum dfactor) {PRECALL;glBlendFunc(sfactor, dfactor);POSTCALL;}
1490 void wrapglBufferData(GLenum target, GLsizeiptrARB size, const GLvoid *data, GLenum usage) {PRECALL;glBufferData(target, size, data, usage);POSTCALL;}
1491 void wrapglBufferSubData(GLenum target, GLintptrARB offset, GLsizeiptrARB size, const GLvoid *data) {PRECALL;glBufferSubData(target, offset, size, data);POSTCALL;}
1492 void wrapglClear(GLbitfield mask) {PRECALL;glClear(mask);POSTCALL;}
1493 void wrapglClearColor(GLclampf red, GLclampf green, GLclampf blue, GLclampf alpha) {PRECALL;glClearColor(red, green, blue, alpha);POSTCALL;}
1494 void wrapglClearDepth(GLclampd depth) {PRECALL;/*Con_Printf("glClearDepth(%f)\n", depth);glClearDepthf((float)depth);*/POSTCALL;}
1495 void wrapglClearStencil(GLint s) {PRECALL;glClearStencil(s);POSTCALL;}
1496 void wrapglColorMask(GLboolean red, GLboolean green, GLboolean blue, GLboolean alpha) {PRECALL;glColorMask(red, green, blue, alpha);POSTCALL;}
1497 void wrapglCompileShader(GLuint shaderObj) {PRECALL;glCompileShader(shaderObj);POSTCALL;}
1498 void wrapglCompressedTexImage2D(GLenum target, GLint level, GLenum internalformat, GLsizei width, GLsizei height, GLint border,  GLsizei imageSize, const void *data) {PRECALL;glCompressedTexImage2D(target, level, internalformat, width, height, border, imageSize, data);POSTCALL;}
1499 void wrapglCompressedTexImage3D(GLenum target, GLint level, GLenum internalformat, GLsizei width, GLsizei height, GLsizei depth, GLint border, GLsizei imageSize, const void *data) {PRECALL;Con_Printf("glCompressedTexImage3D(target, level, internalformat, width, height, depth, border, imageSize, data)\n");POSTCALL;}
1500 void wrapglCompressedTexSubImage2D(GLenum target, GLint level, GLint xoffset, GLint yoffset, GLsizei width, GLsizei height, GLenum format, GLsizei imageSize, const void *data) {PRECALL;glCompressedTexSubImage2D(target, level, xoffset, yoffset, width, height, format, imageSize, data);POSTCALL;}
1501 void wrapglCompressedTexSubImage3D(GLenum target, GLint level, GLint xoffset, GLint yoffset, GLint zoffset, GLsizei width, GLsizei height, GLsizei depth, GLenum format, GLsizei imageSize, const void *data) {PRECALL;Con_Printf("glCompressedTexSubImage3D(target, level, xoffset, yoffset, zoffset, width, height, depth, format, imageSize, data)\n");POSTCALL;}
1502 void wrapglCopyTexImage2D(GLenum target, GLint level, GLenum internalformat, GLint x, GLint y, GLsizei width, GLsizei height, GLint border) {PRECALL;glCopyTexImage2D(target, level, internalformat, x, y, width, height, border);POSTCALL;}
1503 void wrapglCopyTexSubImage2D(GLenum target, GLint level, GLint xoffset, GLint yoffset, GLint x, GLint y, GLsizei width, GLsizei height) {PRECALL;glCopyTexSubImage2D(target, level, xoffset, yoffset, x, y, width, height);POSTCALL;}
1504 void wrapglCopyTexSubImage3D(GLenum target, GLint level, GLint xoffset, GLint yoffset, GLint zoffset, GLint x, GLint y, GLsizei width, GLsizei height) {PRECALL;Con_Printf("glCopyTexSubImage3D(target, level, xoffset, yoffset, zoffset, x, y, width, height)\n");POSTCALL;}
1505 void wrapglCullFace(GLenum mode) {PRECALL;glCullFace(mode);POSTCALL;}
1506 void wrapglDeleteBuffers(GLsizei n, const GLuint *buffers) {PRECALL;glDeleteBuffers(n, buffers);POSTCALL;}
1507 void wrapglDeleteFramebuffers(GLsizei n, const GLuint *framebuffers) {PRECALL;glDeleteFramebuffers(n, framebuffers);POSTCALL;}
1508 void wrapglDeleteShader(GLuint obj) {PRECALL;glDeleteShader(obj);POSTCALL;}
1509 void wrapglDeleteProgram(GLuint obj) {PRECALL;glDeleteProgram(obj);POSTCALL;}
1510 //void wrapglDeleteQueries(GLsizei n, const GLuint *ids) {PRECALL;glDeleteQueries(n, ids);POSTCALL;}
1511 void wrapglDeleteRenderbuffers(GLsizei n, const GLuint *renderbuffers) {PRECALL;glDeleteRenderbuffers(n, renderbuffers);POSTCALL;}
1512 void wrapglDeleteTextures(GLsizei n, const GLuint *textures) {PRECALL;glDeleteTextures(n, textures);POSTCALL;}
1513 void wrapglDepthFunc(GLenum func) {PRECALL;glDepthFunc(func);POSTCALL;}
1514 void wrapglDepthMask(GLboolean flag) {PRECALL;glDepthMask(flag);POSTCALL;}
1515 //void wrapglDepthRange(GLclampd near_val, GLclampd far_val) {PRECALL;glDepthRangef((float)near_val, (float)far_val);POSTCALL;}
1516 void wrapglDepthRangef(GLclampf near_val, GLclampf far_val) {PRECALL;glDepthRangef(near_val, far_val);POSTCALL;}
1517 void wrapglDetachShader(GLuint containerObj, GLuint attachedObj) {PRECALL;glDetachShader(containerObj, attachedObj);POSTCALL;}
1518 void wrapglDisable(GLenum cap) {PRECALL;glDisable(cap);POSTCALL;}
1519 void wrapglDisableVertexAttribArray(GLuint index) {PRECALL;glDisableVertexAttribArray(index);POSTCALL;}
1520 void wrapglDrawArrays(GLenum mode, GLint first, GLsizei count) {PRECALL;glDrawArrays(mode, first, count);POSTCALL;}
1521 void wrapglDrawBuffer(GLenum mode) {PRECALL;Con_Printf("glDrawBuffer(mode)\n");POSTCALL;}
1522 void wrapglDrawBuffers(GLsizei n, const GLenum *bufs) {PRECALL;Con_Printf("glDrawBuffers(n, bufs)\n");POSTCALL;}
1523 void wrapglDrawElements(GLenum mode, GLsizei count, GLenum type, const GLvoid *indices) {PRECALL;glDrawElements(mode, count, type, indices);POSTCALL;}
1524 //void wrapglDrawRangeElements(GLenum mode, GLuint start, GLuint end, GLsizei count, GLenum type, const GLvoid *indices) {PRECALL;glDrawRangeElements(mode, start, end, count, type, indices);POSTCALL;}
1525 //void wrapglDrawRangeElementsEXT(GLenum mode, GLuint start, GLuint end, GLsizei count, GLenum type, const GLvoid *indices) {PRECALL;glDrawRangeElements(mode, start, end, count, type, indices);POSTCALL;}
1526 void wrapglEnable(GLenum cap) {PRECALL;glEnable(cap);POSTCALL;}
1527 void wrapglEnableVertexAttribArray(GLuint index) {PRECALL;glEnableVertexAttribArray(index);POSTCALL;}
1528 //void wrapglEndQuery(GLenum target) {PRECALL;glEndQuery(target);POSTCALL;}
1529 void wrapglFinish(void) {PRECALL;glFinish();POSTCALL;}
1530 void wrapglFlush(void) {PRECALL;glFlush();POSTCALL;}
1531 void wrapglFramebufferRenderbuffer(GLenum target, GLenum attachment, GLenum renderbuffertarget, GLuint renderbuffer) {PRECALL;glFramebufferRenderbuffer(target, attachment, renderbuffertarget, renderbuffer);POSTCALL;}
1532 void wrapglFramebufferTexture2D(GLenum target, GLenum attachment, GLenum textarget, GLuint texture, GLint level) {PRECALL;glFramebufferTexture2D(target, attachment, textarget, texture, level);POSTCALL;}
1533 void wrapglFramebufferTexture3D(GLenum target, GLenum attachment, GLenum textarget, GLuint texture, GLint level, GLint zoffset) {PRECALL;Con_Printf("glFramebufferTexture3D()\n");POSTCALL;}
1534 void wrapglGenBuffers(GLsizei n, GLuint *buffers) {PRECALL;glGenBuffers(n, buffers);POSTCALL;}
1535 void wrapglGenFramebuffers(GLsizei n, GLuint *framebuffers) {PRECALL;glGenFramebuffers(n, framebuffers);POSTCALL;}
1536 //void wrapglGenQueries(GLsizei n, GLuint *ids) {PRECALL;glGenQueries(n, ids);POSTCALL;}
1537 void wrapglGenRenderbuffers(GLsizei n, GLuint *renderbuffers) {PRECALL;glGenRenderbuffers(n, renderbuffers);POSTCALL;}
1538 void wrapglGenTextures(GLsizei n, GLuint *textures) {PRECALL;glGenTextures(n, textures);POSTCALL;}
1539 void wrapglGenerateMipmap(GLenum target) {PRECALL;glGenerateMipmap(target);POSTCALL;}
1540 void wrapglGetActiveAttrib(GLuint programObj, GLuint index, GLsizei maxLength, GLsizei *length, GLint *size, GLenum *type, GLchar *name) {PRECALL;glGetActiveAttrib(programObj, index, maxLength, length, size, type, name);POSTCALL;}
1541 void wrapglGetActiveUniform(GLuint programObj, GLuint index, GLsizei maxLength, GLsizei *length, GLint *size, GLenum *type, GLchar *name) {PRECALL;glGetActiveUniform(programObj, index, maxLength, length, size, type, name);POSTCALL;}
1542 void wrapglGetAttachedShaders(GLuint containerObj, GLsizei maxCount, GLsizei *count, GLuint *obj) {PRECALL;glGetAttachedShaders(containerObj, maxCount, count, obj);POSTCALL;}
1543 void wrapglGetBooleanv(GLenum pname, GLboolean *params) {PRECALL;glGetBooleanv(pname, params);POSTCALL;}
1544 void wrapglGetCompressedTexImage(GLenum target, GLint lod, void *img) {PRECALL;Con_Printf("glGetCompressedTexImage(target, lod, img)\n");POSTCALL;}
1545 void wrapglGetDoublev(GLenum pname, GLdouble *params) {PRECALL;Con_Printf("glGetDoublev(pname, params)\n");POSTCALL;}
1546 void wrapglGetFloatv(GLenum pname, GLfloat *params) {PRECALL;glGetFloatv(pname, params);POSTCALL;}
1547 void wrapglGetFramebufferAttachmentParameteriv(GLenum target, GLenum attachment, GLenum pname, GLint *params) {PRECALL;glGetFramebufferAttachmentParameteriv(target, attachment, pname, params);POSTCALL;}
1548 void wrapglGetShaderInfoLog(GLuint obj, GLsizei maxLength, GLsizei *length, GLchar *infoLog) {PRECALL;glGetShaderInfoLog(obj, maxLength, length, infoLog);POSTCALL;}
1549 void wrapglGetProgramInfoLog(GLuint obj, GLsizei maxLength, GLsizei *length, GLchar *infoLog) {PRECALL;glGetProgramInfoLog(obj, maxLength, length, infoLog);POSTCALL;}
1550 void wrapglGetIntegerv(GLenum pname, GLint *params) {PRECALL;glGetIntegerv(pname, params);POSTCALL;}
1551 void wrapglGetShaderiv(GLuint obj, GLenum pname, GLint *params) {PRECALL;glGetShaderiv(obj, pname, params);POSTCALL;}
1552 void wrapglGetProgramiv(GLuint obj, GLenum pname, GLint *params) {PRECALL;glGetProgramiv(obj, pname, params);POSTCALL;}
1553 //void wrapglGetQueryObjectiv(GLuint qid, GLenum pname, GLint *params) {PRECALL;glGetQueryObjectiv(qid, pname, params);POSTCALL;}
1554 //void wrapglGetQueryObjectuiv(GLuint qid, GLenum pname, GLuint *params) {PRECALL;glGetQueryObjectuiv(qid, pname, params);POSTCALL;}
1555 //void wrapglGetQueryiv(GLenum target, GLenum pname, GLint *params) {PRECALL;glGetQueryiv(target, pname, params);POSTCALL;}
1556 void wrapglGetRenderbufferParameteriv(GLenum target, GLenum pname, GLint *params) {PRECALL;glGetRenderbufferParameteriv(target, pname, params);POSTCALL;}
1557 void wrapglGetShaderSource(GLuint obj, GLsizei maxLength, GLsizei *length, GLchar *source) {PRECALL;glGetShaderSource(obj, maxLength, length, source);POSTCALL;}
1558 void wrapglGetTexImage(GLenum target, GLint level, GLenum format, GLenum type, GLvoid *pixels) {PRECALL;Con_Printf("glGetTexImage(target, level, format, type, pixels)\n");POSTCALL;}
1559 void wrapglGetTexLevelParameterfv(GLenum target, GLint level, GLenum pname, GLfloat *params) {PRECALL;Con_Printf("glGetTexLevelParameterfv(target, level, pname, params)\n");POSTCALL;}
1560 void wrapglGetTexLevelParameteriv(GLenum target, GLint level, GLenum pname, GLint *params) {PRECALL;Con_Printf("glGetTexLevelParameteriv(target, level, pname, params)\n");POSTCALL;}
1561 void wrapglGetTexParameterfv(GLenum target, GLenum pname, GLfloat *params) {PRECALL;glGetTexParameterfv(target, pname, params);POSTCALL;}
1562 void wrapglGetTexParameteriv(GLenum target, GLenum pname, GLint *params) {PRECALL;glGetTexParameteriv(target, pname, params);POSTCALL;}
1563 void wrapglGetUniformfv(GLuint programObj, GLint location, GLfloat *params) {PRECALL;glGetUniformfv(programObj, location, params);POSTCALL;}
1564 void wrapglGetUniformiv(GLuint programObj, GLint location, GLint *params) {PRECALL;glGetUniformiv(programObj, location, params);POSTCALL;}
1565 void wrapglHint(GLenum target, GLenum mode) {PRECALL;glHint(target, mode);POSTCALL;}
1566 void wrapglLinkProgram(GLuint programObj) {PRECALL;glLinkProgram(programObj);POSTCALL;}
1567 void wrapglPixelStorei(GLenum pname, GLint param) {PRECALL;glPixelStorei(pname, param);POSTCALL;}
1568 void wrapglPointSize(GLfloat size) {PRECALL;Con_Printf("glPointSize(size)\n");POSTCALL;}
1569 //void wrapglPolygonMode(GLenum face, GLenum mode) {PRECALL;Con_Printf("glPolygonMode(face, mode)\n");POSTCALL;}
1570 void wrapglPolygonOffset(GLfloat factor, GLfloat units) {PRECALL;glPolygonOffset(factor, units);POSTCALL;}
1571 void wrapglPolygonStipple(const GLubyte *mask) {PRECALL;Con_Printf("glPolygonStipple(mask)\n");POSTCALL;}
1572 void wrapglReadBuffer(GLenum mode) {PRECALL;Con_Printf("glReadBuffer(mode)\n");POSTCALL;}
1573 void wrapglReadPixels(GLint x, GLint y, GLsizei width, GLsizei height, GLenum format, GLenum type, GLvoid *pixels) {PRECALL;glReadPixels(x, y, width, height, format, type, pixels);POSTCALL;}
1574 void wrapglRenderbufferStorage(GLenum target, GLenum internalformat, GLsizei width, GLsizei height) {PRECALL;glRenderbufferStorage(target, internalformat, width, height);POSTCALL;}
1575 void wrapglScissor(GLint x, GLint y, GLsizei width, GLsizei height) {PRECALL;glScissor(x, y, width, height);POSTCALL;}
1576 void wrapglShaderSource(GLuint shaderObj, GLsizei count, const GLchar **string, const GLint *length) {PRECALL;glShaderSource(shaderObj, count, string, length);POSTCALL;}
1577 void wrapglStencilFunc(GLenum func, GLint ref, GLuint mask) {PRECALL;glStencilFunc(func, ref, mask);POSTCALL;}
1578 void wrapglStencilFuncSeparate(GLenum func1, GLenum func2, GLint ref, GLuint mask) {PRECALL;Con_Printf("glStencilFuncSeparate(func1, func2, ref, mask)\n");POSTCALL;}
1579 void wrapglStencilMask(GLuint mask) {PRECALL;glStencilMask(mask);POSTCALL;}
1580 void wrapglStencilOp(GLenum fail, GLenum zfail, GLenum zpass) {PRECALL;glStencilOp(fail, zfail, zpass);POSTCALL;}
1581 void wrapglStencilOpSeparate(GLenum e1, GLenum e2, GLenum e3, GLenum e4) {PRECALL;Con_Printf("glStencilOpSeparate(e1, e2, e3, e4)\n");POSTCALL;}
1582 void wrapglTexImage2D(GLenum target, GLint level, GLint internalFormat, GLsizei width, GLsizei height, GLint border, GLenum format, GLenum type, const GLvoid *pixels) {PRECALL;glTexImage2D(target, level, internalFormat, width, height, border, format, type, pixels);POSTCALL;}
1583 void wrapglTexImage3D(GLenum target, GLint level, GLenum internalFormat, GLsizei width, GLsizei height, GLsizei depth, GLint border, GLenum format, GLenum type, const GLvoid *pixels) {PRECALL;Con_Printf("glTexImage3D(target, level, internalformat, width, height, depth, border, format, type, pixels)\n");POSTCALL;}
1584 void wrapglTexParameterf(GLenum target, GLenum pname, GLfloat param) {PRECALL;glTexParameterf(target, pname, param);POSTCALL;}
1585 void wrapglTexParameterfv(GLenum target, GLenum pname, GLfloat *params) {PRECALL;glTexParameterfv(target, pname, params);POSTCALL;}
1586 void wrapglTexParameteri(GLenum target, GLenum pname, GLint param) {PRECALL;glTexParameteri(target, pname, param);POSTCALL;}
1587 void wrapglTexSubImage2D(GLenum target, GLint level, GLint xoffset, GLint yoffset, GLsizei width, GLsizei height, GLenum format, GLenum type, const GLvoid *pixels) {PRECALL;glTexSubImage2D(target, level, xoffset, yoffset, width, height, format, type, pixels);POSTCALL;}
1588 void wrapglTexSubImage3D(GLenum target, GLint level, GLint xoffset, GLint yoffset, GLint zoffset, GLsizei width, GLsizei height, GLsizei depth, GLenum format, GLenum type, const GLvoid *pixels) {PRECALL;Con_Printf("glTexSubImage3D(target, level, xoffset, yoffset, zoffset, width, height, depth, format, type, pixels)\n");POSTCALL;}
1589 void wrapglUniform1f(GLint location, GLfloat v0) {PRECALL;glUniform1f(location, v0);POSTCALL;}
1590 void wrapglUniform1fv(GLint location, GLsizei count, const GLfloat *value) {PRECALL;glUniform1fv(location, count, value);POSTCALL;}
1591 void wrapglUniform1i(GLint location, GLint v0) {PRECALL;glUniform1i(location, v0);POSTCALL;}
1592 void wrapglUniform1iv(GLint location, GLsizei count, const GLint *value) {PRECALL;glUniform1iv(location, count, value);POSTCALL;}
1593 void wrapglUniform2f(GLint location, GLfloat v0, GLfloat v1) {PRECALL;glUniform2f(location, v0, v1);POSTCALL;}
1594 void wrapglUniform2fv(GLint location, GLsizei count, const GLfloat *value) {PRECALL;glUniform2fv(location, count, value);POSTCALL;}
1595 void wrapglUniform2i(GLint location, GLint v0, GLint v1) {PRECALL;glUniform2i(location, v0, v1);POSTCALL;}
1596 void wrapglUniform2iv(GLint location, GLsizei count, const GLint *value) {PRECALL;glUniform2iv(location, count, value);POSTCALL;}
1597 void wrapglUniform3f(GLint location, GLfloat v0, GLfloat v1, GLfloat v2) {PRECALL;glUniform3f(location, v0, v1, v2);POSTCALL;}
1598 void wrapglUniform3fv(GLint location, GLsizei count, const GLfloat *value) {PRECALL;glUniform3fv(location, count, value);POSTCALL;}
1599 void wrapglUniform3i(GLint location, GLint v0, GLint v1, GLint v2) {PRECALL;glUniform3i(location, v0, v1, v2);POSTCALL;}
1600 void wrapglUniform3iv(GLint location, GLsizei count, const GLint *value) {PRECALL;glUniform3iv(location, count, value);POSTCALL;}
1601 void wrapglUniform4f(GLint location, GLfloat v0, GLfloat v1, GLfloat v2, GLfloat v3) {PRECALL;glUniform4f(location, v0, v1, v2, v3);POSTCALL;}
1602 void wrapglUniform4fv(GLint location, GLsizei count, const GLfloat *value) {PRECALL;glUniform4fv(location, count, value);POSTCALL;}
1603 void wrapglUniform4i(GLint location, GLint v0, GLint v1, GLint v2, GLint v3) {PRECALL;glUniform4i(location, v0, v1, v2, v3);POSTCALL;}
1604 void wrapglUniform4iv(GLint location, GLsizei count, const GLint *value) {PRECALL;glUniform4iv(location, count, value);POSTCALL;}
1605 void wrapglUniformMatrix2fv(GLint location, GLsizei count, GLboolean transpose, const GLfloat *value) {PRECALL;glUniformMatrix2fv(location, count, transpose, value);POSTCALL;}
1606 void wrapglUniformMatrix3fv(GLint location, GLsizei count, GLboolean transpose, const GLfloat *value) {PRECALL;glUniformMatrix3fv(location, count, transpose, value);POSTCALL;}
1607 void wrapglUniformMatrix4fv(GLint location, GLsizei count, GLboolean transpose, const GLfloat *value) {PRECALL;glUniformMatrix4fv(location, count, transpose, value);POSTCALL;}
1608 void wrapglUseProgram(GLuint programObj) {PRECALL;glUseProgram(programObj);POSTCALL;}
1609 void wrapglValidateProgram(GLuint programObj) {PRECALL;glValidateProgram(programObj);POSTCALL;}
1610 void wrapglVertex2f(GLfloat x, GLfloat y) {PRECALL;Con_Printf("glVertex2f(x, y)\n");POSTCALL;}
1611 void wrapglVertex3f(GLfloat x, GLfloat y, GLfloat z) {PRECALL;Con_Printf("glVertex3f(x, y, z)\n");POSTCALL;}
1612 void wrapglVertex4f(GLfloat x, GLfloat y, GLfloat z, GLfloat w) {PRECALL;Con_Printf("glVertex4f(x, y, z, w)\n");POSTCALL;}
1613 void wrapglVertexAttribPointer(GLuint index, GLint size, GLenum type, GLboolean normalized, GLsizei stride, const GLvoid *pointer) {PRECALL;glVertexAttribPointer(index, size, type, normalized, stride, pointer);POSTCALL;}
1614 void wrapglVertexPointer(GLint size, GLenum type, GLsizei stride, const GLvoid *ptr) {PRECALL;Con_Printf("glVertexPointer(size, type, stride, ptr)\n");POSTCALL;}
1615 void wrapglViewport(GLint x, GLint y, GLsizei width, GLsizei height) {PRECALL;glViewport(x, y, width, height);POSTCALL;}
1616 void wrapglVertexAttrib1f(GLuint index, GLfloat v0) {PRECALL;glVertexAttrib1f(index, v0);POSTCALL;}
1617 //void wrapglVertexAttrib1s(GLuint index, GLshort v0) {PRECALL;glVertexAttrib1s(index, v0);POSTCALL;}
1618 //void wrapglVertexAttrib1d(GLuint index, GLdouble v0) {PRECALL;glVertexAttrib1d(index, v0);POSTCALL;}
1619 void wrapglVertexAttrib2f(GLuint index, GLfloat v0, GLfloat v1) {PRECALL;glVertexAttrib2f(index, v0, v1);POSTCALL;}
1620 //void wrapglVertexAttrib2s(GLuint index, GLshort v0, GLshort v1) {PRECALL;glVertexAttrib2s(index, v0, v1);POSTCALL;}
1621 //void wrapglVertexAttrib2d(GLuint index, GLdouble v0, GLdouble v1) {PRECALL;glVertexAttrib2d(index, v0, v1);POSTCALL;}
1622 void wrapglVertexAttrib3f(GLuint index, GLfloat v0, GLfloat v1, GLfloat v2) {PRECALL;glVertexAttrib3f(index, v0, v1, v2);POSTCALL;}
1623 //void wrapglVertexAttrib3s(GLuint index, GLshort v0, GLshort v1, GLshort v2) {PRECALL;glVertexAttrib3s(index, v0, v1, v2);POSTCALL;}
1624 //void wrapglVertexAttrib3d(GLuint index, GLdouble v0, GLdouble v1, GLdouble v2) {PRECALL;glVertexAttrib3d(index, v0, v1, v2);POSTCALL;}
1625 void wrapglVertexAttrib4f(GLuint index, GLfloat v0, GLfloat v1, GLfloat v2, GLfloat v3) {PRECALL;glVertexAttrib4f(index, v0, v1, v2, v3);POSTCALL;}
1626 //void wrapglVertexAttrib4s(GLuint index, GLshort v0, GLshort v1, GLshort v2, GLshort v3) {PRECALL;glVertexAttrib4s(index, v0, v1, v2, v3);POSTCALL;}
1627 //void wrapglVertexAttrib4d(GLuint index, GLdouble v0, GLdouble v1, GLdouble v2, GLdouble v3) {PRECALL;glVertexAttrib4d(index, v0, v1, v2, v3);POSTCALL;}
1628 //void wrapglVertexAttrib4Nub(GLuint index, GLubyte x, GLubyte y, GLubyte z, GLubyte w) {PRECALL;glVertexAttrib4Nub(index, x, y, z, w);POSTCALL;}
1629 void wrapglVertexAttrib1fv(GLuint index, const GLfloat *v) {PRECALL;glVertexAttrib1fv(index, v);POSTCALL;}
1630 //void wrapglVertexAttrib1sv(GLuint index, const GLshort *v) {PRECALL;glVertexAttrib1sv(index, v);POSTCALL;}
1631 //void wrapglVertexAttrib1dv(GLuint index, const GLdouble *v) {PRECALL;glVertexAttrib1dv(index, v);POSTCALL;}
1632 void wrapglVertexAttrib2fv(GLuint index, const GLfloat *v) {PRECALL;glVertexAttrib2fv(index, v);POSTCALL;}
1633 //void wrapglVertexAttrib2sv(GLuint index, const GLshort *v) {PRECALL;glVertexAttrib2sv(index, v);POSTCALL;}
1634 //void wrapglVertexAttrib2dv(GLuint index, const GLdouble *v) {PRECALL;glVertexAttrib2dv(index, v);POSTCALL;}
1635 void wrapglVertexAttrib3fv(GLuint index, const GLfloat *v) {PRECALL;glVertexAttrib3fv(index, v);POSTCALL;}
1636 //void wrapglVertexAttrib3sv(GLuint index, const GLshort *v) {PRECALL;glVertexAttrib3sv(index, v);POSTCALL;}
1637 //void wrapglVertexAttrib3dv(GLuint index, const GLdouble *v) {PRECALL;glVertexAttrib3dv(index, v);POSTCALL;}
1638 void wrapglVertexAttrib4fv(GLuint index, const GLfloat *v) {PRECALL;glVertexAttrib4fv(index, v);POSTCALL;}
1639 //void wrapglVertexAttrib4sv(GLuint index, const GLshort *v) {PRECALL;glVertexAttrib4sv(index, v);POSTCALL;}
1640 //void wrapglVertexAttrib4dv(GLuint index, const GLdouble *v) {PRECALL;glVertexAttrib4dv(index, v);POSTCALL;}
1641 //void wrapglVertexAttrib4iv(GLuint index, const GLint *v) {PRECALL;glVertexAttrib4iv(index, v);POSTCALL;}
1642 //void wrapglVertexAttrib4bv(GLuint index, const GLbyte *v) {PRECALL;glVertexAttrib4bv(index, v);POSTCALL;}
1643 //void wrapglVertexAttrib4ubv(GLuint index, const GLubyte *v) {PRECALL;glVertexAttrib4ubv(index, v);POSTCALL;}
1644 //void wrapglVertexAttrib4usv(GLuint index, const GLushort *v) {PRECALL;glVertexAttrib4usv(index, GLushort v);POSTCALL;}
1645 //void wrapglVertexAttrib4uiv(GLuint index, const GLuint *v) {PRECALL;glVertexAttrib4uiv(index, v);POSTCALL;}
1646 //void wrapglVertexAttrib4Nbv(GLuint index, const GLbyte *v) {PRECALL;glVertexAttrib4Nbv(index, v);POSTCALL;}
1647 //void wrapglVertexAttrib4Nsv(GLuint index, const GLshort *v) {PRECALL;glVertexAttrib4Nsv(index, v);POSTCALL;}
1648 //void wrapglVertexAttrib4Niv(GLuint index, const GLint *v) {PRECALL;glVertexAttrib4Niv(index, v);POSTCALL;}
1649 //void wrapglVertexAttrib4Nubv(GLuint index, const GLubyte *v) {PRECALL;glVertexAttrib4Nubv(index, v);POSTCALL;}
1650 //void wrapglVertexAttrib4Nusv(GLuint index, const GLushort *v) {PRECALL;glVertexAttrib4Nusv(index, GLushort v);POSTCALL;}
1651 //void wrapglVertexAttrib4Nuiv(GLuint index, const GLuint *v) {PRECALL;glVertexAttrib4Nuiv(index, v);POSTCALL;}
1652 //void wrapglGetVertexAttribdv(GLuint index, GLenum pname, GLdouble *params) {PRECALL;glGetVertexAttribdv(index, pname, params);POSTCALL;}
1653 void wrapglGetVertexAttribfv(GLuint index, GLenum pname, GLfloat *params) {PRECALL;glGetVertexAttribfv(index, pname, params);POSTCALL;}
1654 void wrapglGetVertexAttribiv(GLuint index, GLenum pname, GLint *params) {PRECALL;glGetVertexAttribiv(index, pname, params);POSTCALL;}
1655 void wrapglGetVertexAttribPointerv(GLuint index, GLenum pname, GLvoid **pointer) {PRECALL;glGetVertexAttribPointerv(index, pname, pointer);POSTCALL;}
1656 #endif
1657
1658 #if SDL_MAJOR_VERSION == 1
1659 #define SDL_GL_ExtensionSupported(x) (strstr(gl_extensions, x) || strstr(gl_platformextensions, x))
1660 #endif
1661
1662 void GLES_Init(void)
1663 {
1664 #ifndef qglClear
1665         qglIsBufferARB = wrapglIsBuffer;
1666         qglIsEnabled = wrapglIsEnabled;
1667         qglIsFramebufferEXT = wrapglIsFramebuffer;
1668 //      qglIsQueryARB = wrapglIsQuery;
1669         qglIsRenderbufferEXT = wrapglIsRenderbuffer;
1670 //      qglUnmapBufferARB = wrapglUnmapBuffer;
1671         qglCheckFramebufferStatus = wrapglCheckFramebufferStatus;
1672         qglGetError = wrapglGetError;
1673         qglCreateProgram = wrapglCreateProgram;
1674         qglCreateShader = wrapglCreateShader;
1675 //      qglGetHandleARB = wrapglGetHandle;
1676         qglGetAttribLocation = wrapglGetAttribLocation;
1677         qglGetUniformLocation = wrapglGetUniformLocation;
1678 //      qglMapBufferARB = wrapglMapBuffer;
1679         qglGetString = wrapglGetString;
1680 //      qglActiveStencilFaceEXT = wrapglActiveStencilFace;
1681         qglActiveTexture = wrapglActiveTexture;
1682         qglArrayElement = wrapglArrayElement;
1683         qglAttachShader = wrapglAttachShader;
1684 //      qglBeginQueryARB = wrapglBeginQuery;
1685         qglBindAttribLocation = wrapglBindAttribLocation;
1686 //      qglBindFragDataLocation = wrapglBindFragDataLocation;
1687         qglBindBufferARB = wrapglBindBuffer;
1688         qglBindFramebuffer = wrapglBindFramebuffer;
1689         qglBindRenderbuffer = wrapglBindRenderbuffer;
1690         qglBindTexture = wrapglBindTexture;
1691         qglBlendEquationEXT = wrapglBlendEquation;
1692         qglBlendFunc = wrapglBlendFunc;
1693         qglBufferDataARB = wrapglBufferData;
1694         qglBufferSubDataARB = wrapglBufferSubData;
1695         qglClear = wrapglClear;
1696         qglClearColor = wrapglClearColor;
1697         qglClearDepth = wrapglClearDepth;
1698         qglClearStencil = wrapglClearStencil;
1699         qglColorMask = wrapglColorMask;
1700         qglCompileShader = wrapglCompileShader;
1701         qglCompressedTexImage2DARB = wrapglCompressedTexImage2D;
1702         qglCompressedTexImage3DARB = wrapglCompressedTexImage3D;
1703         qglCompressedTexSubImage2DARB = wrapglCompressedTexSubImage2D;
1704         qglCompressedTexSubImage3DARB = wrapglCompressedTexSubImage3D;
1705         qglCopyTexImage2D = wrapglCopyTexImage2D;
1706         qglCopyTexSubImage2D = wrapglCopyTexSubImage2D;
1707         qglCopyTexSubImage3D = wrapglCopyTexSubImage3D;
1708         qglCullFace = wrapglCullFace;
1709         qglDeleteBuffersARB = wrapglDeleteBuffers;
1710         qglDeleteFramebuffers = wrapglDeleteFramebuffers;
1711         qglDeleteProgram = wrapglDeleteProgram;
1712         qglDeleteShader = wrapglDeleteShader;
1713 //      qglDeleteQueriesARB = wrapglDeleteQueries;
1714         qglDeleteRenderbuffers = wrapglDeleteRenderbuffers;
1715         qglDeleteTextures = wrapglDeleteTextures;
1716         qglDepthFunc = wrapglDepthFunc;
1717         qglDepthMask = wrapglDepthMask;
1718         qglDepthRangef = wrapglDepthRangef;
1719         qglDetachShader = wrapglDetachShader;
1720         qglDisable = wrapglDisable;
1721         qglDisableVertexAttribArray = wrapglDisableVertexAttribArray;
1722         qglDrawArrays = wrapglDrawArrays;
1723 //      qglDrawBuffer = wrapglDrawBuffer;
1724 //      qglDrawBuffersARB = wrapglDrawBuffers;
1725         qglDrawElements = wrapglDrawElements;
1726 //      qglDrawRangeElements = wrapglDrawRangeElements;
1727         qglEnable = wrapglEnable;
1728         qglEnableVertexAttribArray = wrapglEnableVertexAttribArray;
1729 //      qglEndQueryARB = wrapglEndQuery;
1730         qglFinish = wrapglFinish;
1731         qglFlush = wrapglFlush;
1732         qglFramebufferRenderbufferEXT = wrapglFramebufferRenderbuffer;
1733         qglFramebufferTexture2DEXT = wrapglFramebufferTexture2D;
1734         qglFramebufferTexture3DEXT = wrapglFramebufferTexture3D;
1735         qglGenBuffersARB = wrapglGenBuffers;
1736         qglGenFramebuffers = wrapglGenFramebuffers;
1737 //      qglGenQueriesARB = wrapglGenQueries;
1738         qglGenRenderbuffers = wrapglGenRenderbuffers;
1739         qglGenTextures = wrapglGenTextures;
1740         qglGenerateMipmapEXT = wrapglGenerateMipmap;
1741         qglGetActiveAttrib = wrapglGetActiveAttrib;
1742         qglGetActiveUniform = wrapglGetActiveUniform;
1743         qglGetAttachedShaders = wrapglGetAttachedShaders;
1744         qglGetBooleanv = wrapglGetBooleanv;
1745 //      qglGetCompressedTexImageARB = wrapglGetCompressedTexImage;
1746         qglGetDoublev = wrapglGetDoublev;
1747         qglGetFloatv = wrapglGetFloatv;
1748         qglGetFramebufferAttachmentParameterivEXT = wrapglGetFramebufferAttachmentParameteriv;
1749         qglGetProgramInfoLog = wrapglGetProgramInfoLog;
1750         qglGetShaderInfoLog = wrapglGetShaderInfoLog;
1751         qglGetIntegerv = wrapglGetIntegerv;
1752         qglGetShaderiv = wrapglGetShaderiv;
1753         qglGetProgramiv = wrapglGetProgramiv;
1754 //      qglGetQueryObjectivARB = wrapglGetQueryObjectiv;
1755 //      qglGetQueryObjectuivARB = wrapglGetQueryObjectuiv;
1756 //      qglGetQueryivARB = wrapglGetQueryiv;
1757         qglGetRenderbufferParameterivEXT = wrapglGetRenderbufferParameteriv;
1758         qglGetShaderSource = wrapglGetShaderSource;
1759         qglGetTexImage = wrapglGetTexImage;
1760         qglGetTexLevelParameterfv = wrapglGetTexLevelParameterfv;
1761         qglGetTexLevelParameteriv = wrapglGetTexLevelParameteriv;
1762         qglGetTexParameterfv = wrapglGetTexParameterfv;
1763         qglGetTexParameteriv = wrapglGetTexParameteriv;
1764         qglGetUniformfv = wrapglGetUniformfv;
1765         qglGetUniformiv = wrapglGetUniformiv;
1766         qglHint = wrapglHint;
1767         qglLinkProgram = wrapglLinkProgram;
1768         qglPixelStorei = wrapglPixelStorei;
1769         qglPointSize = wrapglPointSize;
1770 //      qglPolygonMode = wrapglPolygonMode;
1771         qglPolygonOffset = wrapglPolygonOffset;
1772 //      qglPolygonStipple = wrapglPolygonStipple;
1773         qglReadBuffer = wrapglReadBuffer;
1774         qglReadPixels = wrapglReadPixels;
1775         qglRenderbufferStorage = wrapglRenderbufferStorage;
1776         qglScissor = wrapglScissor;
1777         qglShaderSource = wrapglShaderSource;
1778         qglStencilFunc = wrapglStencilFunc;
1779         qglStencilFuncSeparate = wrapglStencilFuncSeparate;
1780         qglStencilMask = wrapglStencilMask;
1781         qglStencilOp = wrapglStencilOp;
1782         qglStencilOpSeparate = wrapglStencilOpSeparate;
1783         qglTexImage2D = wrapglTexImage2D;
1784         qglTexImage3D = wrapglTexImage3D;
1785         qglTexParameterf = wrapglTexParameterf;
1786         qglTexParameterfv = wrapglTexParameterfv;
1787         qglTexParameteri = wrapglTexParameteri;
1788         qglTexSubImage2D = wrapglTexSubImage2D;
1789         qglTexSubImage3D = wrapglTexSubImage3D;
1790         qglUniform1f = wrapglUniform1f;
1791         qglUniform1fv = wrapglUniform1fv;
1792         qglUniform1i = wrapglUniform1i;
1793         qglUniform1iv = wrapglUniform1iv;
1794         qglUniform2f = wrapglUniform2f;
1795         qglUniform2fv = wrapglUniform2fv;
1796         qglUniform2i = wrapglUniform2i;
1797         qglUniform2iv = wrapglUniform2iv;
1798         qglUniform3f = wrapglUniform3f;
1799         qglUniform3fv = wrapglUniform3fv;
1800         qglUniform3i = wrapglUniform3i;
1801         qglUniform3iv = wrapglUniform3iv;
1802         qglUniform4f = wrapglUniform4f;
1803         qglUniform4fv = wrapglUniform4fv;
1804         qglUniform4i = wrapglUniform4i;
1805         qglUniform4iv = wrapglUniform4iv;
1806         qglUniformMatrix2fv = wrapglUniformMatrix2fv;
1807         qglUniformMatrix3fv = wrapglUniformMatrix3fv;
1808         qglUniformMatrix4fv = wrapglUniformMatrix4fv;
1809         qglUseProgram = wrapglUseProgram;
1810         qglValidateProgram = wrapglValidateProgram;
1811         qglVertex2f = wrapglVertex2f;
1812         qglVertex3f = wrapglVertex3f;
1813         qglVertex4f = wrapglVertex4f;
1814         qglVertexAttribPointer = wrapglVertexAttribPointer;
1815         qglVertexPointer = wrapglVertexPointer;
1816         qglViewport = wrapglViewport;
1817         qglVertexAttrib1f = wrapglVertexAttrib1f;
1818 //      qglVertexAttrib1s = wrapglVertexAttrib1s;
1819 //      qglVertexAttrib1d = wrapglVertexAttrib1d;
1820         qglVertexAttrib2f = wrapglVertexAttrib2f;
1821 //      qglVertexAttrib2s = wrapglVertexAttrib2s;
1822 //      qglVertexAttrib2d = wrapglVertexAttrib2d;
1823         qglVertexAttrib3f = wrapglVertexAttrib3f;
1824 //      qglVertexAttrib3s = wrapglVertexAttrib3s;
1825 //      qglVertexAttrib3d = wrapglVertexAttrib3d;
1826         qglVertexAttrib4f = wrapglVertexAttrib4f;
1827 //      qglVertexAttrib4s = wrapglVertexAttrib4s;
1828 //      qglVertexAttrib4d = wrapglVertexAttrib4d;
1829 //      qglVertexAttrib4Nub = wrapglVertexAttrib4Nub;
1830         qglVertexAttrib1fv = wrapglVertexAttrib1fv;
1831 //      qglVertexAttrib1sv = wrapglVertexAttrib1sv;
1832 //      qglVertexAttrib1dv = wrapglVertexAttrib1dv;
1833         qglVertexAttrib2fv = wrapglVertexAttrib2fv;
1834 //      qglVertexAttrib2sv = wrapglVertexAttrib2sv;
1835 //      qglVertexAttrib2dv = wrapglVertexAttrib2dv;
1836         qglVertexAttrib3fv = wrapglVertexAttrib3fv;
1837 //      qglVertexAttrib3sv = wrapglVertexAttrib3sv;
1838 //      qglVertexAttrib3dv = wrapglVertexAttrib3dv;
1839         qglVertexAttrib4fv = wrapglVertexAttrib4fv;
1840 //      qglVertexAttrib4sv = wrapglVertexAttrib4sv;
1841 //      qglVertexAttrib4dv = wrapglVertexAttrib4dv;
1842 //      qglVertexAttrib4iv = wrapglVertexAttrib4iv;
1843 //      qglVertexAttrib4bv = wrapglVertexAttrib4bv;
1844 //      qglVertexAttrib4ubv = wrapglVertexAttrib4ubv;
1845 //      qglVertexAttrib4usv = wrapglVertexAttrib4usv;
1846 //      qglVertexAttrib4uiv = wrapglVertexAttrib4uiv;
1847 //      qglVertexAttrib4Nbv = wrapglVertexAttrib4Nbv;
1848 //      qglVertexAttrib4Nsv = wrapglVertexAttrib4Nsv;
1849 //      qglVertexAttrib4Niv = wrapglVertexAttrib4Niv;
1850 //      qglVertexAttrib4Nubv = wrapglVertexAttrib4Nubv;
1851 //      qglVertexAttrib4Nusv = wrapglVertexAttrib4Nusv;
1852 //      qglVertexAttrib4Nuiv = wrapglVertexAttrib4Nuiv;
1853 //      qglGetVertexAttribdv = wrapglGetVertexAttribdv;
1854         qglGetVertexAttribfv = wrapglGetVertexAttribfv;
1855         qglGetVertexAttribiv = wrapglGetVertexAttribiv;
1856         qglGetVertexAttribPointerv = wrapglGetVertexAttribPointerv;
1857 #endif
1858
1859         gl_renderer = (const char *)qglGetString(GL_RENDERER);
1860         gl_vendor = (const char *)qglGetString(GL_VENDOR);
1861         gl_version = (const char *)qglGetString(GL_VERSION);
1862         gl_extensions = (const char *)qglGetString(GL_EXTENSIONS);
1863         
1864         if (!gl_extensions)
1865                 gl_extensions = "";
1866         if (!gl_platformextensions)
1867                 gl_platformextensions = "";
1868         
1869         Con_Printf("GL_VENDOR: %s\n", gl_vendor);
1870         Con_Printf("GL_RENDERER: %s\n", gl_renderer);
1871         Con_Printf("GL_VERSION: %s\n", gl_version);
1872         Con_DPrintf("GL_EXTENSIONS: %s\n", gl_extensions);
1873         Con_DPrintf("%s_EXTENSIONS: %s\n", gl_platform, gl_platformextensions);
1874         
1875         // LordHavoc: report supported extensions
1876         Con_DPrintf("\nQuakeC extensions for server and client: %s\nQuakeC extensions for menu: %s\n", vm_sv_extensions, vm_m_extensions );
1877
1878         // GLES devices in general do not like GL_BGRA, so use GL_RGBA
1879         vid.forcetextype = TEXTYPE_RGBA;
1880         
1881         vid.support.gl20shaders = true;
1882         vid.support.amd_texture_texture4 = false;
1883         vid.support.arb_depth_texture = SDL_GL_ExtensionSupported("GL_OES_depth_texture") != 0; // renderbuffer used anyway on gles2?
1884         vid.support.arb_draw_buffers = false;
1885         vid.support.arb_multitexture = false;
1886         vid.support.arb_occlusion_query = false;
1887         vid.support.arb_query_buffer_object = false;
1888         vid.support.arb_shadow = false;
1889         vid.support.arb_texture_compression = false; // different (vendor-specific) formats than on desktop OpenGL...
1890         vid.support.arb_texture_cube_map = SDL_GL_ExtensionSupported("GL_OES_texture_cube_map") != 0;
1891         vid.support.arb_texture_env_combine = false;
1892         vid.support.arb_texture_gather = false;
1893         vid.support.arb_texture_non_power_of_two = strstr(gl_extensions, "GL_OES_texture_npot") != NULL;
1894         vid.support.arb_vertex_buffer_object = true; // GLES2 core
1895         vid.support.ext_blend_minmax = false;
1896         vid.support.ext_blend_subtract = true; // GLES2 core
1897         vid.support.ext_blend_func_separate = true; // GLES2 core
1898         vid.support.ext_draw_range_elements = false;
1899
1900         /*      ELUAN:
1901                 Note: "In OS 2.1, the functions in GL_OES_framebuffer_object were not usable from the Java API.
1902                 Calling them just threw an exception. Android developer relations confirmed that they forgot to implement these. (yeah...)
1903                 It's apparently been fixed in 2.2, though I haven't tested."
1904         */
1905         // LadyHavoc: Android 2.1 is way old now, enabling this again, it's going to be required soon.
1906         vid.support.ext_framebuffer_object = true;
1907
1908         vid.support.ext_packed_depth_stencil = false;
1909         vid.support.ext_texture_3d = SDL_GL_ExtensionSupported("GL_OES_texture_3D") != 0;
1910         vid.support.ext_texture_compression_s3tc = SDL_GL_ExtensionSupported("GL_EXT_texture_compression_s3tc") != 0;
1911         vid.support.ext_texture_edge_clamp = true; // GLES2 core
1912         vid.support.ext_texture_filter_anisotropic = false; // probably don't want to use it...
1913         vid.support.ext_texture_srgb = false;
1914         vid.support.arb_texture_float = SDL_GL_ExtensionSupported("GL_OES_texture_float") != 0;
1915         vid.support.arb_half_float_pixel = SDL_GL_ExtensionSupported("GL_OES_texture_half_float") != 0;
1916         vid.support.arb_half_float_vertex = SDL_GL_ExtensionSupported("GL_OES_vertex_half_float") != 0;
1917
1918         // NOTE: On some devices, a value of 512 gives better FPS than the maximum.
1919         qglGetIntegerv(GL_MAX_TEXTURE_SIZE, (GLint*)&vid.maxtexturesize_2d);
1920
1921 #ifdef GL_MAX_TEXTURE_MAX_ANISOTROPY_EXT
1922         if (vid.support.ext_texture_filter_anisotropic)
1923                 qglGetIntegerv(GL_MAX_TEXTURE_MAX_ANISOTROPY_EXT, (GLint*)&vid.max_anisotropy);
1924 #endif
1925         if (vid.support.arb_texture_cube_map)
1926                 qglGetIntegerv(GL_MAX_CUBE_MAP_TEXTURE_SIZE, (GLint*)&vid.maxtexturesize_cubemap);
1927 #ifdef GL_MAX_3D_TEXTURE_SIZE
1928         if (vid.support.ext_texture_3d)
1929                 qglGetIntegerv(GL_MAX_3D_TEXTURE_SIZE, (GLint*)&vid.maxtexturesize_3d);
1930 #endif
1931         Con_Printf("GL_MAX_CUBE_MAP_TEXTURE_SIZE = %i\n", vid.maxtexturesize_cubemap);
1932         Con_Printf("GL_MAX_3D_TEXTURE_SIZE = %i\n", vid.maxtexturesize_3d);
1933         {
1934 #define GL_ALPHA_BITS                           0x0D55
1935 #define GL_RED_BITS                             0x0D52
1936 #define GL_GREEN_BITS                           0x0D53
1937 #define GL_BLUE_BITS                            0x0D54
1938 #define GL_DEPTH_BITS                           0x0D56
1939 #define GL_STENCIL_BITS                         0x0D57
1940                 int fb_r = -1, fb_g = -1, fb_b = -1, fb_a = -1, fb_d = -1, fb_s = -1;
1941                 qglGetIntegerv(GL_RED_BITS    , &fb_r);
1942                 qglGetIntegerv(GL_GREEN_BITS  , &fb_g);
1943                 qglGetIntegerv(GL_BLUE_BITS   , &fb_b);
1944                 qglGetIntegerv(GL_ALPHA_BITS  , &fb_a);
1945                 qglGetIntegerv(GL_DEPTH_BITS  , &fb_d);
1946                 qglGetIntegerv(GL_STENCIL_BITS, &fb_s);
1947                 Con_Printf("Framebuffer depth is R%iG%iB%iA%iD%iS%i\n", fb_r, fb_g, fb_b, fb_a, fb_d, fb_s);
1948         }
1949
1950         // verify that cubemap textures are really supported
1951         if (vid.support.arb_texture_cube_map && vid.maxtexturesize_cubemap < 256)
1952                 vid.support.arb_texture_cube_map = false;
1953         
1954         // verify that 3d textures are really supported
1955         if (vid.support.ext_texture_3d && vid.maxtexturesize_3d < 32)
1956         {
1957                 vid.support.ext_texture_3d = false;
1958                 Con_Printf("GL_OES_texture_3d reported bogus GL_MAX_3D_TEXTURE_SIZE, disabled\n");
1959         }
1960
1961         vid.texunits = 4;
1962         vid.teximageunits = 8;
1963         vid.texarrayunits = 5;
1964         //qglGetIntegerv(GL_MAX_TEXTURE_UNITS, (GLint*)&vid.texunits);
1965         qglGetIntegerv(GL_MAX_TEXTURE_IMAGE_UNITS, (GLint*)&vid.teximageunits);CHECKGLERROR
1966         //qglGetIntegerv(GL_MAX_TEXTURE_COORDS, (GLint*)&vid.texarrayunits);CHECKGLERROR
1967         vid.texunits = bound(1, vid.texunits, MAX_TEXTUREUNITS);
1968         vid.teximageunits = bound(1, vid.teximageunits, MAX_TEXTUREUNITS);
1969         vid.texarrayunits = bound(1, vid.texarrayunits, MAX_TEXTUREUNITS);
1970         Con_DPrintf("Using GLES2.0 rendering path - %i texture matrix, %i texture images, %i texcoords%s\n", vid.texunits, vid.teximageunits, vid.texarrayunits, vid.support.ext_framebuffer_object ? ", shadowmapping supported" : "");
1971         vid.renderpath = RENDERPATH_GLES2;
1972         vid.sRGBcapable2D = false;
1973         vid.sRGBcapable3D = false;
1974
1975         // VorteX: set other info (maybe place them in VID_InitMode?)
1976         extern cvar_t gl_info_vendor;
1977         extern cvar_t gl_info_renderer;
1978         extern cvar_t gl_info_version;
1979         extern cvar_t gl_info_platform;
1980         extern cvar_t gl_info_driver;
1981         Cvar_SetQuick(&gl_info_vendor, gl_vendor);
1982         Cvar_SetQuick(&gl_info_renderer, gl_renderer);
1983         Cvar_SetQuick(&gl_info_version, gl_version);
1984         Cvar_SetQuick(&gl_info_platform, gl_platform ? gl_platform : "");
1985         Cvar_SetQuick(&gl_info_driver, gl_driver);
1986 }
1987 #endif
1988
1989 void *GL_GetProcAddress(const char *name)
1990 {
1991         void *p = NULL;
1992         p = SDL_GL_GetProcAddress(name);
1993         return p;
1994 }
1995
1996 static qboolean vid_sdl_initjoysticksystem = false;
1997
1998 void VID_Init (void)
1999 {
2000 #ifndef __IPHONEOS__
2001 #ifdef MACOSX
2002         Cvar_RegisterVariable(&apple_mouse_noaccel);
2003 #endif
2004 #endif
2005 #ifdef DP_MOBILETOUCH
2006         Cvar_SetValueQuick(&vid_touchscreen, 1);
2007 #endif
2008
2009 #ifdef SDL_R_RESTART
2010         R_RegisterModule("SDL", sdl_start, sdl_shutdown, sdl_newmap, NULL, NULL);
2011 #endif
2012
2013         if (SDL_Init(SDL_INIT_VIDEO) < 0)
2014                 Sys_Error ("Failed to init SDL video subsystem: %s", SDL_GetError());
2015         vid_sdl_initjoysticksystem = SDL_InitSubSystem(SDL_INIT_JOYSTICK) >= 0;
2016         if (vid_sdl_initjoysticksystem)
2017                 Con_Printf("Failed to init SDL joystick subsystem: %s\n", SDL_GetError());
2018         vid_isfullscreen = false;
2019 }
2020
2021 static int vid_sdljoystickindex = -1;
2022 void VID_EnableJoystick(qboolean enable)
2023 {
2024         int index = joy_enable.integer > 0 ? joy_index.integer : -1;
2025         int numsdljoysticks;
2026         qboolean success = false;
2027         int sharedcount = 0;
2028         int sdlindex = -1;
2029         sharedcount = VID_Shared_SetJoystick(index);
2030         if (index >= 0 && index < sharedcount)
2031                 success = true;
2032         sdlindex = index - sharedcount;
2033
2034         numsdljoysticks = SDL_NumJoysticks();
2035         if (sdlindex < 0 || sdlindex >= numsdljoysticks)
2036                 sdlindex = -1;
2037
2038         // update cvar containing count of XInput joysticks + SDL joysticks
2039         if (joy_detected.integer != sharedcount + numsdljoysticks)
2040                 Cvar_SetValueQuick(&joy_detected, sharedcount + numsdljoysticks);
2041
2042         if (vid_sdljoystickindex != sdlindex)
2043         {
2044                 vid_sdljoystickindex = sdlindex;
2045                 // close SDL joystick if active
2046                 if (vid_sdljoystick)
2047                         SDL_JoystickClose(vid_sdljoystick);
2048                 vid_sdljoystick = NULL;
2049                 if (sdlindex >= 0)
2050                 {
2051                         vid_sdljoystick = SDL_JoystickOpen(sdlindex);
2052                         if (vid_sdljoystick)
2053                         {
2054 #if SDL_MAJOR_VERSION == 1
2055                                 const char *joystickname = SDL_JoystickName(sdlindex);
2056 #else
2057                                 const char *joystickname = SDL_JoystickName(vid_sdljoystick);
2058 #endif
2059                                 Con_Printf("Joystick %i opened (SDL_Joystick %i is \"%s\" with %i axes, %i buttons, %i balls)\n", index, sdlindex, joystickname, (int)SDL_JoystickNumAxes(vid_sdljoystick), (int)SDL_JoystickNumButtons(vid_sdljoystick), (int)SDL_JoystickNumBalls(vid_sdljoystick));
2060                         }
2061                         else
2062                         {
2063                                 Con_Printf("Joystick %i failed (SDL_JoystickOpen(%i) returned: %s)\n", index, sdlindex, SDL_GetError());
2064                                 sdlindex = -1;
2065                         }
2066                 }
2067         }
2068
2069         if (sdlindex >= 0)
2070                 success = true;
2071
2072         if (joy_active.integer != (success ? 1 : 0))
2073                 Cvar_SetValueQuick(&joy_active, success ? 1 : 0);
2074 }
2075
2076 #if SDL_MAJOR_VERSION == 1
2077 // set the icon (we dont use SDL here since it would be too much a PITA)
2078 #ifdef WIN32
2079 #include "resource.h"
2080 #include <SDL_syswm.h>
2081 static SDL_Surface *VID_WrapSDL_SetVideoMode(int screenwidth, int screenheight, int screenbpp, int screenflags)
2082 {
2083         SDL_Surface *screen = NULL;
2084         SDL_SysWMinfo info;
2085         HICON icon;
2086         SDL_WM_SetCaption( gamename, NULL );
2087         screen = SDL_SetVideoMode(screenwidth, screenheight, screenbpp, screenflags);
2088         if (screen)
2089         {
2090                 // get the HWND handle
2091                 SDL_VERSION( &info.version );
2092                 if (SDL_GetWMInfo(&info))
2093                 {
2094                         icon = LoadIcon( GetModuleHandle( NULL ), MAKEINTRESOURCE( IDI_ICON1 ) );
2095 #ifndef _W64 //If Windows 64bit data types don't exist
2096 #ifndef SetClassLongPtr
2097 #define SetClassLongPtr SetClassLong
2098 #endif
2099 #ifndef GCLP_HICON
2100 #define GCLP_HICON GCL_HICON
2101 #endif
2102 #ifndef LONG_PTR
2103 #define LONG_PTR LONG
2104 #endif
2105 #endif
2106                         SetClassLongPtr( info.window, GCLP_HICON, (LONG_PTR)icon );
2107                 }
2108         }
2109         return screen;
2110 }
2111 #elif defined(MACOSX)
2112 static SDL_Surface *VID_WrapSDL_SetVideoMode(int screenwidth, int screenheight, int screenbpp, int screenflags)
2113 {
2114         SDL_Surface *screen = NULL;
2115         SDL_WM_SetCaption( gamename, NULL );
2116         screen = SDL_SetVideoMode(screenwidth, screenheight, screenbpp, screenflags);
2117         // we don't use SDL_WM_SetIcon here because the icon in the .app should be used
2118         return screen;
2119 }
2120 #else
2121 // Adding the OS independent XPM version --blub
2122 #include "darkplaces.xpm"
2123 #include "nexuiz.xpm"
2124 #if SDL_MAJOR_VERSION == 1
2125 #if SDL_VIDEO_DRIVER_X11 && !SDL_VIDEO_DRIVER_QUARTZ
2126 #include <SDL_syswm.h>
2127 #endif
2128 #endif
2129 static SDL_Surface *icon = NULL;
2130 static SDL_Surface *VID_WrapSDL_SetVideoMode(int screenwidth, int screenheight, int screenbpp, int screenflags)
2131 {
2132         /*
2133          * Somewhat restricted XPM reader. Only supports XPMs saved by GIMP 2.4 at
2134          * default settings with less than 91 colors and transparency.
2135          */
2136
2137         int width, height, colors, isize, i, j;
2138         int thenone = -1;
2139         static SDL_Color palette[256];
2140         unsigned short palenc[256]; // store color id by char
2141         char *xpm;
2142         char **idata, *data;
2143         const SDL_version *version;
2144         SDL_Surface *screen = NULL;
2145
2146         if (icon)
2147                 SDL_FreeSurface(icon);
2148         icon = NULL;
2149         version = SDL_Linked_Version();
2150         // only use non-XPM icon support in SDL v1.3 and higher
2151         // SDL v1.2 does not support "smooth" transparency, and thus is better
2152         // off the xpm way
2153         if(version->major >= 2 || (version->major == 1 && version->minor >= 3))
2154         {
2155                 data = (char *) loadimagepixelsbgra("darkplaces-icon", false, false, false, NULL);
2156                 if(data)
2157                 {
2158                         unsigned int red = 0x00FF0000;
2159                         unsigned int green = 0x0000FF00;
2160                         unsigned int blue = 0x000000FF;
2161                         unsigned int alpha = 0xFF000000;
2162                         width = image_width;
2163                         height = image_height;
2164
2165                         // reallocate with malloc, as this is in tempmempool (do not want)
2166                         xpm = data;
2167                         data = (char *) malloc(width * height * 4);
2168                         memcpy(data, xpm, width * height * 4);
2169                         Mem_Free(xpm);
2170                         xpm = NULL;
2171
2172                         icon = SDL_CreateRGBSurface(SDL_SRCALPHA, width, height, 32, LittleLong(red), LittleLong(green), LittleLong(blue), LittleLong(alpha));
2173
2174                         if (icon)
2175                                 icon->pixels = data;
2176                         else
2177                         {
2178                                 Con_Printf(     "Failed to create surface for the window Icon!\n"
2179                                                 "%s\n", SDL_GetError());
2180                                 free(data);
2181                         }
2182                 }
2183         }
2184
2185         // we only get here if non-XPM icon was missing, or SDL version is not
2186         // sufficient for transparent non-XPM icons
2187         if(!icon)
2188         {
2189                 xpm = (char *) FS_LoadFile("darkplaces-icon.xpm", tempmempool, false, NULL);
2190                 idata = NULL;
2191                 if(xpm)
2192                         idata = XPM_DecodeString(xpm);
2193                 if(!idata)
2194                         idata = ENGINE_ICON;
2195                 if(xpm)
2196                         Mem_Free(xpm);
2197
2198                 data = idata[0];
2199
2200                 if(sscanf(data, "%i %i %i %i", &width, &height, &colors, &isize) == 4)
2201                 {
2202                         if(isize == 1)
2203                         {
2204                                 for(i = 0; i < colors; ++i)
2205                                 {
2206                                         unsigned int r, g, b;
2207                                         char idx;
2208
2209                                         if(sscanf(idata[i+1], "%c c #%02x%02x%02x", &idx, &r, &g, &b) != 4)
2210                                         {
2211                                                 char foo[2];
2212                                                 if(sscanf(idata[i+1], "%c c Non%1[e]", &idx, foo) != 2) // I take the DailyWTF credit for this. --div0
2213                                                         break;
2214                                                 else
2215                                                 {
2216                                                         palette[i].r = 255; // color key
2217                                                         palette[i].g = 0;
2218                                                         palette[i].b = 255;
2219                                                         thenone = i; // weeeee
2220                                                         palenc[(unsigned char) idx] = i;
2221                                                 }
2222                                         }
2223                                         else
2224                                         {
2225                                                 palette[i].r = r - (r == 255 && g == 0 && b == 255); // change 255/0/255 pink to 254/0/255 for color key
2226                                                 palette[i].g = g;
2227                                                 palette[i].b = b;
2228                                                 palenc[(unsigned char) idx] = i;
2229                                         }
2230                                 }
2231
2232                                 if (i == colors)
2233                                 {
2234                                         // allocate the image data
2235                                         data = (char*) malloc(width*height);
2236
2237                                         for(j = 0; j < height; ++j)
2238                                         {
2239                                                 for(i = 0; i < width; ++i)
2240                                                 {
2241                                                         // casting to the safest possible datatypes ^^
2242                                                         data[j * width + i] = palenc[((unsigned char*)idata[colors+j+1])[i]];
2243                                                 }
2244                                         }
2245
2246                                         if(icon != NULL)
2247                                         {
2248                                                 // SDL_FreeSurface should free the data too
2249                                                 // but for completeness' sake...
2250                                                 if(icon->flags & SDL_PREALLOC)
2251                                                 {
2252                                                         free(icon->pixels);
2253                                                         icon->pixels = NULL; // safety
2254                                                 }
2255                                                 SDL_FreeSurface(icon);
2256                                         }
2257
2258                                         icon = SDL_CreateRGBSurface(SDL_SRCCOLORKEY, width, height, 8, 0,0,0,0);// rmask, gmask, bmask, amask); no mask needed
2259                                         // 8 bit surfaces get an empty palette allocated according to the docs
2260                                         // so it's a palette image for sure :) no endian check necessary for the mask
2261
2262                                         if(icon)
2263                                         {
2264                                                 icon->pixels = data;
2265                                                 SDL_SetPalette(icon, SDL_PHYSPAL|SDL_LOGPAL, palette, 0, colors);
2266                                                 SDL_SetColorKey(icon, SDL_SRCCOLORKEY, thenone);
2267                                         }
2268                                         else
2269                                         {
2270                                                 Con_Printf(     "Failed to create surface for the window Icon!\n"
2271                                                                 "%s\n", SDL_GetError());
2272                                                 free(data);
2273                                         }
2274                                 }
2275                                 else
2276                                 {
2277                                         Con_Printf("This XPM's palette looks odd. Can't continue.\n");
2278                                 }
2279                         }
2280                         else
2281                         {
2282                                 // NOTE: Only 1-char colornames are supported
2283                                 Con_Printf("This XPM's palette is either huge or idiotically unoptimized. It's key size is %i\n", isize);
2284                         }
2285                 }
2286                 else
2287                 {
2288                         // NOTE: Only 1-char colornames are supported
2289                         Con_Printf("Sorry, but this does not even look similar to an XPM.\n");
2290                 }
2291         }
2292
2293         if (icon)
2294                 SDL_WM_SetIcon(icon, NULL);
2295
2296         SDL_WM_SetCaption( gamename, NULL );
2297         screen = SDL_SetVideoMode(screenwidth, screenheight, screenbpp, screenflags);
2298
2299 #if SDL_MAJOR_VERSION == 1
2300 // LordHavoc: info.info.x11.lock_func and accompanying code do not seem to compile with SDL 1.3
2301 #if SDL_VIDEO_DRIVER_X11 && !SDL_VIDEO_DRIVER_QUARTZ
2302
2303         version = SDL_Linked_Version();
2304         // only use non-XPM icon support in SDL v1.3 and higher
2305         // SDL v1.2 does not support "smooth" transparency, and thus is better
2306         // off the xpm way
2307         if(screen && (!(version->major >= 2 || (version->major == 1 && version->minor >= 3))))
2308         {
2309                 // in this case, we did not set the good icon yet
2310                 SDL_SysWMinfo info;
2311                 SDL_VERSION(&info.version);
2312                 if(SDL_GetWMInfo(&info) == 1 && info.subsystem == SDL_SYSWM_X11)
2313                 {
2314                         data = (char *) loadimagepixelsbgra("darkplaces-icon", false, false, false, NULL);
2315                         if(data)
2316                         {
2317                                 // use _NET_WM_ICON too
2318                                 static long netwm_icon[MAX_NETWM_ICON];
2319                                 int pos = 0;
2320                                 int i = 1;
2321                                 char vabuf[1024];
2322
2323                                 while(data)
2324                                 {
2325                                         if(pos + 2 * image_width * image_height < MAX_NETWM_ICON)
2326                                         {
2327                                                 netwm_icon[pos++] = image_width;
2328                                                 netwm_icon[pos++] = image_height;
2329                                                 for(i = 0; i < image_height; ++i)
2330                                                         for(j = 0; j < image_width; ++j)
2331                                                                 netwm_icon[pos++] = BuffLittleLong((unsigned char *) &data[(i*image_width+j)*4]);
2332                                         }
2333                                         else
2334                                         {
2335                                                 Con_Printf("Skipping NETWM icon #%d because there is no space left\n", i);
2336                                         }
2337                                         ++i;
2338                                         Mem_Free(data);
2339                                         data = (char *) loadimagepixelsbgra(va(vabuf, sizeof(vabuf), "darkplaces-icon%d", i), false, false, false, NULL);
2340                                 }
2341
2342                                 info.info.x11.lock_func();
2343                                 {
2344                                         Atom net_wm_icon = XInternAtom(info.info.x11.display, "_NET_WM_ICON", false);
2345                                         XChangeProperty(info.info.x11.display, info.info.x11.wmwindow, net_wm_icon, XA_CARDINAL, 32, PropModeReplace, (const unsigned char *) netwm_icon, pos);
2346                                 }
2347                                 info.info.x11.unlock_func();
2348                         }
2349                 }
2350         }
2351 #endif
2352 #endif
2353         return screen;
2354 }
2355
2356 #endif
2357 #endif
2358
2359 static void VID_OutputVersion(void)
2360 {
2361         SDL_version version;
2362 #if SDL_MAJOR_VERSION == 1
2363         version = *SDL_Linked_Version();
2364 #else
2365         SDL_GetVersion(&version);
2366 #endif
2367         Con_Printf(     "Linked against SDL version %d.%d.%d\n"
2368                                         "Using SDL library version %d.%d.%d\n",
2369                                         SDL_MAJOR_VERSION, SDL_MINOR_VERSION, SDL_PATCHLEVEL,
2370                                         version.major, version.minor, version.patch );
2371 }
2372
2373 #ifdef WIN32
2374 static void AdjustWindowBounds(viddef_mode_t *mode, RECT *rect)
2375 {
2376         LONG width = mode->width; // vid_width
2377         LONG height = mode->height; // vid_height
2378
2379         // adjust width and height for the space occupied by window decorators (title bar, borders)
2380         rect->top = 0;
2381         rect->left = 0;
2382         rect->right = width;
2383         rect->bottom = height;
2384         AdjustWindowRectEx(rect, WS_CAPTION|WS_THICKFRAME, false, 0);
2385
2386         RECT workArea;
2387         SystemParametersInfo(SPI_GETWORKAREA, 0, &workArea, 0);
2388         int workWidth = workArea.right - workArea.left;
2389         int workHeight = workArea.bottom - workArea.top;
2390
2391         // SDL forces the window height to be <= screen height - 27px (on Win8.1 - probably intended for the title bar) 
2392         // If the task bar is docked to the the left screen border and we move the window to negative y,
2393         // there would be some part of the regular desktop visible on the bottom of the screen.
2394         int titleBarPixels = 2;
2395         int screenHeight = GetSystemMetrics(SM_CYSCREEN);
2396         if (screenHeight == workHeight)
2397                 titleBarPixels = -rect->top;
2398
2399         //Con_Printf("window mode: %dx%d, workArea: %d/%d-%d/%d (%dx%d), title: %d\n", width, height, workArea.left, workArea.top, workArea.right, workArea.bottom, workArea.right - workArea.left, workArea.bottom - workArea.top, titleBarPixels);
2400
2401         // if height and width matches the physical or previously adjusted screen height and width, adjust it to available desktop area
2402         if ((width == GetSystemMetrics(SM_CXSCREEN) || width == workWidth) && (height == screenHeight || height == workHeight - titleBarPixels))
2403         {
2404                 rect->left = workArea.left;
2405                 mode->width = workWidth;
2406                 rect->top = workArea.top + titleBarPixels;
2407                 mode->height = workHeight - titleBarPixels;
2408         }
2409         else 
2410         {
2411                 rect->left = workArea.left + max(0, (workWidth - width) / 2);
2412                 rect->top = workArea.top + max(0, (workHeight - height) / 2);
2413         }
2414 }
2415 #endif
2416
2417 static qboolean VID_InitModeGL(viddef_mode_t *mode)
2418 {
2419 #if SDL_MAJOR_VERSION == 1
2420         static int notfirstvideomode = false;
2421         int flags = SDL_OPENGL;
2422 #else
2423         int windowflags = SDL_WINDOW_SHOWN | SDL_WINDOW_OPENGL;
2424         int xPos = SDL_WINDOWPOS_UNDEFINED;
2425         int yPos = SDL_WINDOWPOS_UNDEFINED;
2426 #endif
2427 #ifndef USE_GLES2
2428         int i;
2429         const char *drivername;
2430 #endif
2431
2432         win_half_width = mode->width>>1;
2433         win_half_height = mode->height>>1;
2434
2435         if(vid_resizable.integer)
2436 #if SDL_MAJOR_VERSION == 1
2437                 flags |= SDL_RESIZABLE;
2438 #else
2439                 windowflags |= SDL_WINDOW_RESIZABLE;
2440 #endif
2441
2442         VID_OutputVersion();
2443
2444 #if SDL_MAJOR_VERSION == 1
2445         /*
2446         SDL 1.2 Hack
2447                 We cant switch from one OpenGL video mode to another.
2448                 Thus we first switch to some stupid 2D mode and then back to OpenGL.
2449         */
2450         if (notfirstvideomode)
2451                 SDL_SetVideoMode( 0, 0, 0, 0 );
2452         notfirstvideomode = true;
2453 #endif
2454
2455 #ifndef USE_GLES2
2456         // SDL usually knows best
2457         drivername = NULL;
2458
2459 // 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
2460         i = COM_CheckParm("-gl_driver");
2461         if (i && i < com_argc - 1)
2462                 drivername = com_argv[i + 1];
2463         if (SDL_GL_LoadLibrary(drivername) < 0)
2464         {
2465                 Con_Printf("Unable to load GL driver \"%s\": %s\n", drivername, SDL_GetError());
2466                 return false;
2467         }
2468 #endif
2469
2470 #ifdef DP_MOBILETOUCH
2471         // mobile platforms are always fullscreen, we'll get the resolution after opening the window
2472         mode->fullscreen = true;
2473         // hide the menu with SDL_WINDOW_BORDERLESS
2474         windowflags |= SDL_WINDOW_FULLSCREEN | SDL_WINDOW_BORDERLESS;
2475 #endif
2476 #ifndef USE_GLES2
2477         if ((qglGetString = (const GLubyte* (GLAPIENTRY *)(GLenum name))GL_GetProcAddress("glGetString")) == NULL)
2478         {
2479                 VID_Shutdown();
2480                 Con_Print("Required OpenGL function glGetString not found\n");
2481                 return false;
2482         }
2483 #endif
2484
2485         // Knghtbrd: should do platform-specific extension string function here
2486
2487         vid_isfullscreen = false;
2488 #if SDL_MAJOR_VERSION == 1
2489         {
2490                 const SDL_VideoInfo *vi = SDL_GetVideoInfo();
2491                 desktop_mode.width = vi->current_w;
2492                 desktop_mode.height = vi->current_h;
2493                 desktop_mode.bpp = vi->vfmt->BitsPerPixel;
2494                 desktop_mode.pixelheight_num = 1;
2495                 desktop_mode.pixelheight_denom = 1; // SDL does not provide this
2496                 if (mode->fullscreen) {
2497                         if (vid_desktopfullscreen.integer)
2498                         {
2499                                 mode->width = vi->current_w;
2500                                 mode->height = vi->current_h;
2501                                 mode->bitsperpixel = vi->vfmt->BitsPerPixel;
2502                         }
2503                         flags |= SDL_FULLSCREEN;
2504                         vid_isfullscreen = true;
2505                 }
2506         }
2507 #else
2508         {
2509                 if (mode->fullscreen) {
2510                         if (vid_desktopfullscreen.integer)
2511                         {
2512                                 vid_mode_t *m = VID_GetDesktopMode();
2513                                 mode->width = m->width;
2514                                 mode->height = m->height;
2515                                 windowflags |= SDL_WINDOW_FULLSCREEN_DESKTOP;
2516                         }
2517                         else
2518                                 windowflags |= SDL_WINDOW_FULLSCREEN;
2519                         vid_isfullscreen = true;
2520                 }
2521                 else {
2522 #ifdef WIN32
2523                         RECT rect;
2524                         AdjustWindowBounds(mode, &rect);
2525                         xPos = rect.left;
2526                         yPos = rect.top;
2527 #endif
2528                 }
2529         }
2530 #endif
2531         //flags |= SDL_HWSURFACE;
2532
2533         SDL_GL_SetAttribute (SDL_GL_DOUBLEBUFFER, 1);
2534         if (mode->bitsperpixel >= 32)
2535         {
2536                 SDL_GL_SetAttribute (SDL_GL_RED_SIZE, 8);
2537                 SDL_GL_SetAttribute (SDL_GL_GREEN_SIZE, 8);
2538                 SDL_GL_SetAttribute (SDL_GL_BLUE_SIZE, 8);
2539                 SDL_GL_SetAttribute (SDL_GL_ALPHA_SIZE, 8);
2540                 SDL_GL_SetAttribute (SDL_GL_DEPTH_SIZE, 24);
2541                 SDL_GL_SetAttribute (SDL_GL_STENCIL_SIZE, 8);
2542         }
2543         else
2544         {
2545                 SDL_GL_SetAttribute (SDL_GL_RED_SIZE, 5);
2546                 SDL_GL_SetAttribute (SDL_GL_GREEN_SIZE, 5);
2547                 SDL_GL_SetAttribute (SDL_GL_BLUE_SIZE, 5);
2548                 SDL_GL_SetAttribute (SDL_GL_DEPTH_SIZE, 16);
2549         }
2550         if (mode->stereobuffer)
2551                 SDL_GL_SetAttribute (SDL_GL_STEREO, 1);
2552         if (mode->samples > 1)
2553         {
2554                 SDL_GL_SetAttribute (SDL_GL_MULTISAMPLEBUFFERS, 1);
2555                 SDL_GL_SetAttribute (SDL_GL_MULTISAMPLESAMPLES, mode->samples);
2556         }
2557
2558 #if SDL_MAJOR_VERSION == 1
2559         if (vid_vsync.integer)
2560                 SDL_GL_SetAttribute (SDL_GL_SWAP_CONTROL, 1);
2561         else
2562                 SDL_GL_SetAttribute (SDL_GL_SWAP_CONTROL, 0);
2563 #else
2564 #ifdef USE_GLES2
2565         SDL_GL_SetAttribute (SDL_GL_CONTEXT_MAJOR_VERSION, 2);
2566         SDL_GL_SetAttribute (SDL_GL_CONTEXT_MINOR_VERSION, 0);
2567         SDL_GL_SetAttribute (SDL_GL_RETAINED_BACKING, 1);
2568 #endif
2569 #endif
2570
2571         video_bpp = mode->bitsperpixel;
2572 #if SDL_MAJOR_VERSION == 1
2573         video_flags = flags;
2574         video_screen = VID_WrapSDL_SetVideoMode(mode->width, mode->height, mode->bitsperpixel, flags);
2575         if (video_screen == NULL)
2576         {
2577                 Con_Printf("Failed to set video mode to %ix%i: %s\n", mode->width, mode->height, SDL_GetError());
2578                 VID_Shutdown();
2579                 return false;
2580         }
2581         mode->width = video_screen->w;
2582         mode->height = video_screen->h;
2583 #else
2584         window_flags = windowflags;
2585         window = SDL_CreateWindow(gamename, xPos, yPos, mode->width, mode->height, windowflags);
2586         if (window == NULL)
2587         {
2588                 Con_Printf("Failed to set video mode to %ix%i: %s\n", mode->width, mode->height, SDL_GetError());
2589                 VID_Shutdown();
2590                 return false;
2591         }
2592         SDL_GetWindowSize(window, &mode->width, &mode->height);
2593         context = SDL_GL_CreateContext(window);
2594         if (context == NULL)
2595         {
2596                 Con_Printf("Failed to initialize OpenGL context: %s\n", SDL_GetError());
2597                 VID_Shutdown();
2598                 return false;
2599         }
2600 #endif
2601
2602 #if SDL_MAJOR_VERSION == 1
2603         // init keyboard
2604         SDL_EnableUNICODE( SDL_ENABLE );
2605         // enable key repeat since everyone expects it
2606         SDL_EnableKeyRepeat(SDL_DEFAULT_REPEAT_DELAY, SDL_DEFAULT_REPEAT_INTERVAL);
2607 #endif
2608
2609 #if SDL_MAJOR_VERSION != 1
2610         SDL_GL_SetSwapInterval(vid_vsync.integer != 0);
2611         vid_usingvsync = (vid_vsync.integer != 0);
2612 #endif
2613
2614         gl_platform = "SDL";
2615         gl_platformextensions = "";
2616
2617 #ifdef USE_GLES2
2618         GLES_Init();
2619 #else
2620         GL_Init();
2621 #endif
2622
2623         vid_hidden = false;
2624         vid_activewindow = false;
2625         vid_hasfocus = true;
2626         vid_usingmouse = false;
2627         vid_usinghidecursor = false;
2628                 
2629 #if SDL_MAJOR_VERSION == 1
2630         SDL_WM_GrabInput(SDL_GRAB_OFF);
2631 #endif
2632         return true;
2633 }
2634
2635 extern cvar_t gl_info_extensions;
2636 extern cvar_t gl_info_vendor;
2637 extern cvar_t gl_info_renderer;
2638 extern cvar_t gl_info_version;
2639 extern cvar_t gl_info_platform;
2640 extern cvar_t gl_info_driver;
2641
2642 qboolean VID_InitMode(viddef_mode_t *mode)
2643 {
2644         // GAME_STEELSTORM specific
2645         steelstorm_showing_map = Cvar_FindVar("steelstorm_showing_map");
2646         steelstorm_showing_mousecursor = Cvar_FindVar("steelstorm_showing_mousecursor");
2647
2648         if (!SDL_WasInit(SDL_INIT_VIDEO) && SDL_InitSubSystem(SDL_INIT_VIDEO) < 0)
2649                 Sys_Error ("Failed to init SDL video subsystem: %s", SDL_GetError());
2650
2651 #if SDL_MAJOR_VERSION != 1
2652         Cvar_SetValueQuick(&vid_touchscreen_supportshowkeyboard, SDL_HasScreenKeyboardSupport() ? 1 : 0);
2653 #endif
2654         return VID_InitModeGL(mode);
2655 }
2656
2657 void VID_Shutdown (void)
2658 {
2659         VID_EnableJoystick(false);
2660         VID_SetMouse(false, false, false);
2661
2662 #if SDL_MAJOR_VERSION == 1
2663 #ifndef WIN32
2664 #ifndef MACOSX
2665         if (icon)
2666                 SDL_FreeSurface(icon);
2667         icon = NULL;
2668 #endif
2669 #endif
2670 #endif
2671
2672 #if SDL_MAJOR_VERSION != 1
2673         SDL_DestroyWindow(window);
2674         window = NULL;
2675 #endif
2676
2677         SDL_QuitSubSystem(SDL_INIT_VIDEO);
2678
2679         gl_driver[0] = 0;
2680         gl_extensions = "";
2681         gl_platform = "";
2682         gl_platformextensions = "";
2683 }
2684
2685 void VID_Finish (void)
2686 {
2687 #if SDL_MAJOR_VERSION == 1
2688         Uint8 appstate;
2689
2690         //react on appstate changes
2691         appstate = SDL_GetAppState();
2692
2693         vid_hidden = !(appstate & SDL_APPACTIVE);
2694         vid_hasfocus = (appstate & SDL_APPINPUTFOCUS) != 0;
2695 #endif
2696         vid_activewindow = !vid_hidden && vid_hasfocus;
2697
2698         VID_UpdateGamma();
2699
2700         if (!vid_hidden)
2701         {
2702                 switch(vid.renderpath)
2703                 {
2704                 case RENDERPATH_GL20:
2705                 case RENDERPATH_GLES2:
2706                         CHECKGLERROR
2707                         if (r_speeds.integer == 2 || gl_finish.integer)
2708                                 GL_Finish();
2709
2710 #if SDL_MAJOR_VERSION != 1
2711 {
2712         qboolean vid_usevsync;
2713         vid_usevsync = (vid_vsync.integer && !cls.timedemo);
2714         if (vid_usingvsync != vid_usevsync)
2715         {
2716                 vid_usingvsync = vid_usevsync;
2717                 if (SDL_GL_SetSwapInterval(vid_usevsync != 0) >= 0)
2718                         Con_DPrintf("Vsync %s\n", vid_usevsync ? "activated" : "deactivated");
2719                 else
2720                         Con_DPrintf("ERROR: can't %s vsync\n", vid_usevsync ? "activate" : "deactivate");
2721         }
2722 }
2723 #endif
2724 #if SDL_MAJOR_VERSION == 1
2725                         SDL_GL_SwapBuffers();
2726 #else
2727                         SDL_GL_SwapWindow(window);
2728 #endif
2729                         break;
2730                 }
2731         }
2732 }
2733
2734 vid_mode_t *VID_GetDesktopMode(void)
2735 {
2736 #if SDL_MAJOR_VERSION != 1
2737         SDL_DisplayMode mode;
2738         int bpp;
2739         Uint32 rmask, gmask, bmask, amask;
2740         SDL_GetDesktopDisplayMode(0, &mode);
2741         SDL_PixelFormatEnumToMasks(mode.format, &bpp, &rmask, &gmask, &bmask, &amask);
2742         desktop_mode.width = mode.w;
2743         desktop_mode.height = mode.h;
2744         desktop_mode.bpp = bpp;
2745         desktop_mode.refreshrate = mode.refresh_rate;
2746         desktop_mode.pixelheight_num = 1;
2747         desktop_mode.pixelheight_denom = 1; // SDL does not provide this
2748         // TODO check whether this actually works, or whether we do still need
2749         // a read-window-size-after-entering-desktop-fullscreen hack for
2750         // multiscreen setups.
2751 #endif
2752         return &desktop_mode;
2753 }
2754
2755 size_t VID_ListModes(vid_mode_t *modes, size_t maxcount)
2756 {
2757         size_t k = 0;
2758 #if SDL_MAJOR_VERSION == 1
2759         SDL_Rect **vidmodes;
2760         int bpp = SDL_GetVideoInfo()->vfmt->BitsPerPixel;
2761 #ifdef WIN64
2762         SDL_Rect **ENDRECT = (SDL_Rect**)-1LL;
2763 #else
2764         SDL_Rect **ENDRECT = (SDL_Rect**)-1;
2765 #endif
2766
2767         for(vidmodes = SDL_ListModes(NULL, SDL_FULLSCREEN|SDL_HWSURFACE); vidmodes && vidmodes != ENDRECT && *vidmodes; ++vidmodes)
2768         {
2769                 if(k >= maxcount)
2770                         break;
2771                 modes[k].width = (*vidmodes)->w;
2772                 modes[k].height = (*vidmodes)->h;
2773                 modes[k].bpp = bpp;
2774                 modes[k].refreshrate = 60; // no support for refresh rate in SDL
2775                 modes[k].pixelheight_num = 1;
2776                 modes[k].pixelheight_denom = 1; // SDL does not provide this
2777                 ++k;
2778         }
2779 #else
2780         int modenum;
2781         int nummodes = SDL_GetNumDisplayModes(0);
2782         SDL_DisplayMode mode;
2783         for (modenum = 0;modenum < nummodes;modenum++)
2784         {
2785                 if (k >= maxcount)
2786                         break;
2787                 if (SDL_GetDisplayMode(0, modenum, &mode))
2788                         continue;
2789                 modes[k].width = mode.w;
2790                 modes[k].height = mode.h;
2791                 // FIXME bpp?
2792                 modes[k].refreshrate = mode.refresh_rate;
2793                 modes[k].pixelheight_num = 1;
2794                 modes[k].pixelheight_denom = 1; // SDL does not provide this
2795                 k++;
2796         }
2797 #endif
2798         return k;
2799 }