]> git.xonotic.org Git - xonotic/darkplaces.git/blob - vid_sdl.c
Remove the last remnants of DPSOFTRAST support in vid_glx.c.
[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.ati_separate_stencil = false;
1896         vid.support.ext_blend_minmax = false;
1897         vid.support.ext_blend_subtract = true; // GLES2 core
1898         vid.support.ext_blend_func_separate = true; // GLES2 core
1899         vid.support.ext_draw_range_elements = false;
1900
1901         /*      ELUAN:
1902                 Note: "In OS 2.1, the functions in GL_OES_framebuffer_object were not usable from the Java API.
1903                 Calling them just threw an exception. Android developer relations confirmed that they forgot to implement these. (yeah...)
1904                 It's apparently been fixed in 2.2, though I haven't tested."
1905         */
1906         // LadyHavoc: Android 2.1 is way old now, enabling this again, it's going to be required soon.
1907         vid.support.ext_framebuffer_object = true;
1908
1909         vid.support.ext_packed_depth_stencil = false;
1910         vid.support.ext_stencil_two_side = false;
1911         vid.support.ext_texture_3d = SDL_GL_ExtensionSupported("GL_OES_texture_3D") != 0;
1912         vid.support.ext_texture_compression_s3tc = SDL_GL_ExtensionSupported("GL_EXT_texture_compression_s3tc") != 0;
1913         vid.support.ext_texture_edge_clamp = true; // GLES2 core
1914         vid.support.ext_texture_filter_anisotropic = false; // probably don't want to use it...
1915         vid.support.ext_texture_srgb = false;
1916         vid.support.arb_texture_float = SDL_GL_ExtensionSupported("GL_OES_texture_float") != 0;
1917         vid.support.arb_half_float_pixel = SDL_GL_ExtensionSupported("GL_OES_texture_half_float") != 0;
1918         vid.support.arb_half_float_vertex = SDL_GL_ExtensionSupported("GL_OES_vertex_half_float") != 0;
1919
1920         // NOTE: On some devices, a value of 512 gives better FPS than the maximum.
1921         qglGetIntegerv(GL_MAX_TEXTURE_SIZE, (GLint*)&vid.maxtexturesize_2d);
1922
1923 #ifdef GL_MAX_TEXTURE_MAX_ANISOTROPY_EXT
1924         if (vid.support.ext_texture_filter_anisotropic)
1925                 qglGetIntegerv(GL_MAX_TEXTURE_MAX_ANISOTROPY_EXT, (GLint*)&vid.max_anisotropy);
1926 #endif
1927         if (vid.support.arb_texture_cube_map)
1928                 qglGetIntegerv(GL_MAX_CUBE_MAP_TEXTURE_SIZE, (GLint*)&vid.maxtexturesize_cubemap);
1929 #ifdef GL_MAX_3D_TEXTURE_SIZE
1930         if (vid.support.ext_texture_3d)
1931                 qglGetIntegerv(GL_MAX_3D_TEXTURE_SIZE, (GLint*)&vid.maxtexturesize_3d);
1932 #endif
1933         Con_Printf("GL_MAX_CUBE_MAP_TEXTURE_SIZE = %i\n", vid.maxtexturesize_cubemap);
1934         Con_Printf("GL_MAX_3D_TEXTURE_SIZE = %i\n", vid.maxtexturesize_3d);
1935         {
1936 #define GL_ALPHA_BITS                           0x0D55
1937 #define GL_RED_BITS                             0x0D52
1938 #define GL_GREEN_BITS                           0x0D53
1939 #define GL_BLUE_BITS                            0x0D54
1940 #define GL_DEPTH_BITS                           0x0D56
1941 #define GL_STENCIL_BITS                         0x0D57
1942                 int fb_r = -1, fb_g = -1, fb_b = -1, fb_a = -1, fb_d = -1, fb_s = -1;
1943                 qglGetIntegerv(GL_RED_BITS    , &fb_r);
1944                 qglGetIntegerv(GL_GREEN_BITS  , &fb_g);
1945                 qglGetIntegerv(GL_BLUE_BITS   , &fb_b);
1946                 qglGetIntegerv(GL_ALPHA_BITS  , &fb_a);
1947                 qglGetIntegerv(GL_DEPTH_BITS  , &fb_d);
1948                 qglGetIntegerv(GL_STENCIL_BITS, &fb_s);
1949                 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);
1950         }
1951
1952         // verify that cubemap textures are really supported
1953         if (vid.support.arb_texture_cube_map && vid.maxtexturesize_cubemap < 256)
1954                 vid.support.arb_texture_cube_map = false;
1955         
1956         // verify that 3d textures are really supported
1957         if (vid.support.ext_texture_3d && vid.maxtexturesize_3d < 32)
1958         {
1959                 vid.support.ext_texture_3d = false;
1960                 Con_Printf("GL_OES_texture_3d reported bogus GL_MAX_3D_TEXTURE_SIZE, disabled\n");
1961         }
1962
1963         vid.texunits = 4;
1964         vid.teximageunits = 8;
1965         vid.texarrayunits = 5;
1966         //qglGetIntegerv(GL_MAX_TEXTURE_UNITS, (GLint*)&vid.texunits);
1967         qglGetIntegerv(GL_MAX_TEXTURE_IMAGE_UNITS, (GLint*)&vid.teximageunits);CHECKGLERROR
1968         //qglGetIntegerv(GL_MAX_TEXTURE_COORDS, (GLint*)&vid.texarrayunits);CHECKGLERROR
1969         vid.texunits = bound(1, vid.texunits, MAX_TEXTUREUNITS);
1970         vid.teximageunits = bound(1, vid.teximageunits, MAX_TEXTUREUNITS);
1971         vid.texarrayunits = bound(1, vid.texarrayunits, MAX_TEXTUREUNITS);
1972         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" : "");
1973         vid.renderpath = RENDERPATH_GLES2;
1974         vid.useinterleavedarrays = false;
1975         vid.sRGBcapable2D = false;
1976         vid.sRGBcapable3D = false;
1977
1978         // VorteX: set other info (maybe place them in VID_InitMode?)
1979         extern cvar_t gl_info_vendor;
1980         extern cvar_t gl_info_renderer;
1981         extern cvar_t gl_info_version;
1982         extern cvar_t gl_info_platform;
1983         extern cvar_t gl_info_driver;
1984         Cvar_SetQuick(&gl_info_vendor, gl_vendor);
1985         Cvar_SetQuick(&gl_info_renderer, gl_renderer);
1986         Cvar_SetQuick(&gl_info_version, gl_version);
1987         Cvar_SetQuick(&gl_info_platform, gl_platform ? gl_platform : "");
1988         Cvar_SetQuick(&gl_info_driver, gl_driver);
1989 }
1990 #endif
1991
1992 void *GL_GetProcAddress(const char *name)
1993 {
1994         void *p = NULL;
1995         p = SDL_GL_GetProcAddress(name);
1996         return p;
1997 }
1998
1999 static qboolean vid_sdl_initjoysticksystem = false;
2000
2001 void VID_Init (void)
2002 {
2003 #ifndef __IPHONEOS__
2004 #ifdef MACOSX
2005         Cvar_RegisterVariable(&apple_mouse_noaccel);
2006 #endif
2007 #endif
2008 #ifdef DP_MOBILETOUCH
2009         Cvar_SetValueQuick(&vid_touchscreen, 1);
2010 #endif
2011
2012 #ifdef SDL_R_RESTART
2013         R_RegisterModule("SDL", sdl_start, sdl_shutdown, sdl_newmap, NULL, NULL);
2014 #endif
2015
2016         if (SDL_Init(SDL_INIT_VIDEO) < 0)
2017                 Sys_Error ("Failed to init SDL video subsystem: %s", SDL_GetError());
2018         vid_sdl_initjoysticksystem = SDL_InitSubSystem(SDL_INIT_JOYSTICK) >= 0;
2019         if (vid_sdl_initjoysticksystem)
2020                 Con_Printf("Failed to init SDL joystick subsystem: %s\n", SDL_GetError());
2021         vid_isfullscreen = false;
2022 }
2023
2024 static int vid_sdljoystickindex = -1;
2025 void VID_EnableJoystick(qboolean enable)
2026 {
2027         int index = joy_enable.integer > 0 ? joy_index.integer : -1;
2028         int numsdljoysticks;
2029         qboolean success = false;
2030         int sharedcount = 0;
2031         int sdlindex = -1;
2032         sharedcount = VID_Shared_SetJoystick(index);
2033         if (index >= 0 && index < sharedcount)
2034                 success = true;
2035         sdlindex = index - sharedcount;
2036
2037         numsdljoysticks = SDL_NumJoysticks();
2038         if (sdlindex < 0 || sdlindex >= numsdljoysticks)
2039                 sdlindex = -1;
2040
2041         // update cvar containing count of XInput joysticks + SDL joysticks
2042         if (joy_detected.integer != sharedcount + numsdljoysticks)
2043                 Cvar_SetValueQuick(&joy_detected, sharedcount + numsdljoysticks);
2044
2045         if (vid_sdljoystickindex != sdlindex)
2046         {
2047                 vid_sdljoystickindex = sdlindex;
2048                 // close SDL joystick if active
2049                 if (vid_sdljoystick)
2050                         SDL_JoystickClose(vid_sdljoystick);
2051                 vid_sdljoystick = NULL;
2052                 if (sdlindex >= 0)
2053                 {
2054                         vid_sdljoystick = SDL_JoystickOpen(sdlindex);
2055                         if (vid_sdljoystick)
2056                         {
2057 #if SDL_MAJOR_VERSION == 1
2058                                 const char *joystickname = SDL_JoystickName(sdlindex);
2059 #else
2060                                 const char *joystickname = SDL_JoystickName(vid_sdljoystick);
2061 #endif
2062                                 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));
2063                         }
2064                         else
2065                         {
2066                                 Con_Printf("Joystick %i failed (SDL_JoystickOpen(%i) returned: %s)\n", index, sdlindex, SDL_GetError());
2067                                 sdlindex = -1;
2068                         }
2069                 }
2070         }
2071
2072         if (sdlindex >= 0)
2073                 success = true;
2074
2075         if (joy_active.integer != (success ? 1 : 0))
2076                 Cvar_SetValueQuick(&joy_active, success ? 1 : 0);
2077 }
2078
2079 #if SDL_MAJOR_VERSION == 1
2080 // set the icon (we dont use SDL here since it would be too much a PITA)
2081 #ifdef WIN32
2082 #include "resource.h"
2083 #include <SDL_syswm.h>
2084 static SDL_Surface *VID_WrapSDL_SetVideoMode(int screenwidth, int screenheight, int screenbpp, int screenflags)
2085 {
2086         SDL_Surface *screen = NULL;
2087         SDL_SysWMinfo info;
2088         HICON icon;
2089         SDL_WM_SetCaption( gamename, NULL );
2090         screen = SDL_SetVideoMode(screenwidth, screenheight, screenbpp, screenflags);
2091         if (screen)
2092         {
2093                 // get the HWND handle
2094                 SDL_VERSION( &info.version );
2095                 if (SDL_GetWMInfo(&info))
2096                 {
2097                         icon = LoadIcon( GetModuleHandle( NULL ), MAKEINTRESOURCE( IDI_ICON1 ) );
2098 #ifndef _W64 //If Windows 64bit data types don't exist
2099 #ifndef SetClassLongPtr
2100 #define SetClassLongPtr SetClassLong
2101 #endif
2102 #ifndef GCLP_HICON
2103 #define GCLP_HICON GCL_HICON
2104 #endif
2105 #ifndef LONG_PTR
2106 #define LONG_PTR LONG
2107 #endif
2108 #endif
2109                         SetClassLongPtr( info.window, GCLP_HICON, (LONG_PTR)icon );
2110                 }
2111         }
2112         return screen;
2113 }
2114 #elif defined(MACOSX)
2115 static SDL_Surface *VID_WrapSDL_SetVideoMode(int screenwidth, int screenheight, int screenbpp, int screenflags)
2116 {
2117         SDL_Surface *screen = NULL;
2118         SDL_WM_SetCaption( gamename, NULL );
2119         screen = SDL_SetVideoMode(screenwidth, screenheight, screenbpp, screenflags);
2120         // we don't use SDL_WM_SetIcon here because the icon in the .app should be used
2121         return screen;
2122 }
2123 #else
2124 // Adding the OS independent XPM version --blub
2125 #include "darkplaces.xpm"
2126 #include "nexuiz.xpm"
2127 #if SDL_MAJOR_VERSION == 1
2128 #if SDL_VIDEO_DRIVER_X11 && !SDL_VIDEO_DRIVER_QUARTZ
2129 #include <SDL_syswm.h>
2130 #endif
2131 #endif
2132 static SDL_Surface *icon = NULL;
2133 static SDL_Surface *VID_WrapSDL_SetVideoMode(int screenwidth, int screenheight, int screenbpp, int screenflags)
2134 {
2135         /*
2136          * Somewhat restricted XPM reader. Only supports XPMs saved by GIMP 2.4 at
2137          * default settings with less than 91 colors and transparency.
2138          */
2139
2140         int width, height, colors, isize, i, j;
2141         int thenone = -1;
2142         static SDL_Color palette[256];
2143         unsigned short palenc[256]; // store color id by char
2144         char *xpm;
2145         char **idata, *data;
2146         const SDL_version *version;
2147         SDL_Surface *screen = NULL;
2148
2149         if (icon)
2150                 SDL_FreeSurface(icon);
2151         icon = NULL;
2152         version = SDL_Linked_Version();
2153         // only use non-XPM icon support in SDL v1.3 and higher
2154         // SDL v1.2 does not support "smooth" transparency, and thus is better
2155         // off the xpm way
2156         if(version->major >= 2 || (version->major == 1 && version->minor >= 3))
2157         {
2158                 data = (char *) loadimagepixelsbgra("darkplaces-icon", false, false, false, NULL);
2159                 if(data)
2160                 {
2161                         unsigned int red = 0x00FF0000;
2162                         unsigned int green = 0x0000FF00;
2163                         unsigned int blue = 0x000000FF;
2164                         unsigned int alpha = 0xFF000000;
2165                         width = image_width;
2166                         height = image_height;
2167
2168                         // reallocate with malloc, as this is in tempmempool (do not want)
2169                         xpm = data;
2170                         data = (char *) malloc(width * height * 4);
2171                         memcpy(data, xpm, width * height * 4);
2172                         Mem_Free(xpm);
2173                         xpm = NULL;
2174
2175                         icon = SDL_CreateRGBSurface(SDL_SRCALPHA, width, height, 32, LittleLong(red), LittleLong(green), LittleLong(blue), LittleLong(alpha));
2176
2177                         if (icon)
2178                                 icon->pixels = data;
2179                         else
2180                         {
2181                                 Con_Printf(     "Failed to create surface for the window Icon!\n"
2182                                                 "%s\n", SDL_GetError());
2183                                 free(data);
2184                         }
2185                 }
2186         }
2187
2188         // we only get here if non-XPM icon was missing, or SDL version is not
2189         // sufficient for transparent non-XPM icons
2190         if(!icon)
2191         {
2192                 xpm = (char *) FS_LoadFile("darkplaces-icon.xpm", tempmempool, false, NULL);
2193                 idata = NULL;
2194                 if(xpm)
2195                         idata = XPM_DecodeString(xpm);
2196                 if(!idata)
2197                         idata = ENGINE_ICON;
2198                 if(xpm)
2199                         Mem_Free(xpm);
2200
2201                 data = idata[0];
2202
2203                 if(sscanf(data, "%i %i %i %i", &width, &height, &colors, &isize) == 4)
2204                 {
2205                         if(isize == 1)
2206                         {
2207                                 for(i = 0; i < colors; ++i)
2208                                 {
2209                                         unsigned int r, g, b;
2210                                         char idx;
2211
2212                                         if(sscanf(idata[i+1], "%c c #%02x%02x%02x", &idx, &r, &g, &b) != 4)
2213                                         {
2214                                                 char foo[2];
2215                                                 if(sscanf(idata[i+1], "%c c Non%1[e]", &idx, foo) != 2) // I take the DailyWTF credit for this. --div0
2216                                                         break;
2217                                                 else
2218                                                 {
2219                                                         palette[i].r = 255; // color key
2220                                                         palette[i].g = 0;
2221                                                         palette[i].b = 255;
2222                                                         thenone = i; // weeeee
2223                                                         palenc[(unsigned char) idx] = i;
2224                                                 }
2225                                         }
2226                                         else
2227                                         {
2228                                                 palette[i].r = r - (r == 255 && g == 0 && b == 255); // change 255/0/255 pink to 254/0/255 for color key
2229                                                 palette[i].g = g;
2230                                                 palette[i].b = b;
2231                                                 palenc[(unsigned char) idx] = i;
2232                                         }
2233                                 }
2234
2235                                 if (i == colors)
2236                                 {
2237                                         // allocate the image data
2238                                         data = (char*) malloc(width*height);
2239
2240                                         for(j = 0; j < height; ++j)
2241                                         {
2242                                                 for(i = 0; i < width; ++i)
2243                                                 {
2244                                                         // casting to the safest possible datatypes ^^
2245                                                         data[j * width + i] = palenc[((unsigned char*)idata[colors+j+1])[i]];
2246                                                 }
2247                                         }
2248
2249                                         if(icon != NULL)
2250                                         {
2251                                                 // SDL_FreeSurface should free the data too
2252                                                 // but for completeness' sake...
2253                                                 if(icon->flags & SDL_PREALLOC)
2254                                                 {
2255                                                         free(icon->pixels);
2256                                                         icon->pixels = NULL; // safety
2257                                                 }
2258                                                 SDL_FreeSurface(icon);
2259                                         }
2260
2261                                         icon = SDL_CreateRGBSurface(SDL_SRCCOLORKEY, width, height, 8, 0,0,0,0);// rmask, gmask, bmask, amask); no mask needed
2262                                         // 8 bit surfaces get an empty palette allocated according to the docs
2263                                         // so it's a palette image for sure :) no endian check necessary for the mask
2264
2265                                         if(icon)
2266                                         {
2267                                                 icon->pixels = data;
2268                                                 SDL_SetPalette(icon, SDL_PHYSPAL|SDL_LOGPAL, palette, 0, colors);
2269                                                 SDL_SetColorKey(icon, SDL_SRCCOLORKEY, thenone);
2270                                         }
2271                                         else
2272                                         {
2273                                                 Con_Printf(     "Failed to create surface for the window Icon!\n"
2274                                                                 "%s\n", SDL_GetError());
2275                                                 free(data);
2276                                         }
2277                                 }
2278                                 else
2279                                 {
2280                                         Con_Printf("This XPM's palette looks odd. Can't continue.\n");
2281                                 }
2282                         }
2283                         else
2284                         {
2285                                 // NOTE: Only 1-char colornames are supported
2286                                 Con_Printf("This XPM's palette is either huge or idiotically unoptimized. It's key size is %i\n", isize);
2287                         }
2288                 }
2289                 else
2290                 {
2291                         // NOTE: Only 1-char colornames are supported
2292                         Con_Printf("Sorry, but this does not even look similar to an XPM.\n");
2293                 }
2294         }
2295
2296         if (icon)
2297                 SDL_WM_SetIcon(icon, NULL);
2298
2299         SDL_WM_SetCaption( gamename, NULL );
2300         screen = SDL_SetVideoMode(screenwidth, screenheight, screenbpp, screenflags);
2301
2302 #if SDL_MAJOR_VERSION == 1
2303 // LordHavoc: info.info.x11.lock_func and accompanying code do not seem to compile with SDL 1.3
2304 #if SDL_VIDEO_DRIVER_X11 && !SDL_VIDEO_DRIVER_QUARTZ
2305
2306         version = SDL_Linked_Version();
2307         // only use non-XPM icon support in SDL v1.3 and higher
2308         // SDL v1.2 does not support "smooth" transparency, and thus is better
2309         // off the xpm way
2310         if(screen && (!(version->major >= 2 || (version->major == 1 && version->minor >= 3))))
2311         {
2312                 // in this case, we did not set the good icon yet
2313                 SDL_SysWMinfo info;
2314                 SDL_VERSION(&info.version);
2315                 if(SDL_GetWMInfo(&info) == 1 && info.subsystem == SDL_SYSWM_X11)
2316                 {
2317                         data = (char *) loadimagepixelsbgra("darkplaces-icon", false, false, false, NULL);
2318                         if(data)
2319                         {
2320                                 // use _NET_WM_ICON too
2321                                 static long netwm_icon[MAX_NETWM_ICON];
2322                                 int pos = 0;
2323                                 int i = 1;
2324                                 char vabuf[1024];
2325
2326                                 while(data)
2327                                 {
2328                                         if(pos + 2 * image_width * image_height < MAX_NETWM_ICON)
2329                                         {
2330                                                 netwm_icon[pos++] = image_width;
2331                                                 netwm_icon[pos++] = image_height;
2332                                                 for(i = 0; i < image_height; ++i)
2333                                                         for(j = 0; j < image_width; ++j)
2334                                                                 netwm_icon[pos++] = BuffLittleLong((unsigned char *) &data[(i*image_width+j)*4]);
2335                                         }
2336                                         else
2337                                         {
2338                                                 Con_Printf("Skipping NETWM icon #%d because there is no space left\n", i);
2339                                         }
2340                                         ++i;
2341                                         Mem_Free(data);
2342                                         data = (char *) loadimagepixelsbgra(va(vabuf, sizeof(vabuf), "darkplaces-icon%d", i), false, false, false, NULL);
2343                                 }
2344
2345                                 info.info.x11.lock_func();
2346                                 {
2347                                         Atom net_wm_icon = XInternAtom(info.info.x11.display, "_NET_WM_ICON", false);
2348                                         XChangeProperty(info.info.x11.display, info.info.x11.wmwindow, net_wm_icon, XA_CARDINAL, 32, PropModeReplace, (const unsigned char *) netwm_icon, pos);
2349                                 }
2350                                 info.info.x11.unlock_func();
2351                         }
2352                 }
2353         }
2354 #endif
2355 #endif
2356         return screen;
2357 }
2358
2359 #endif
2360 #endif
2361
2362 static void VID_OutputVersion(void)
2363 {
2364         SDL_version version;
2365 #if SDL_MAJOR_VERSION == 1
2366         version = *SDL_Linked_Version();
2367 #else
2368         SDL_GetVersion(&version);
2369 #endif
2370         Con_Printf(     "Linked against SDL version %d.%d.%d\n"
2371                                         "Using SDL library version %d.%d.%d\n",
2372                                         SDL_MAJOR_VERSION, SDL_MINOR_VERSION, SDL_PATCHLEVEL,
2373                                         version.major, version.minor, version.patch );
2374 }
2375
2376 #ifdef WIN32
2377 static void AdjustWindowBounds(viddef_mode_t *mode, RECT *rect)
2378 {
2379         LONG width = mode->width; // vid_width
2380         LONG height = mode->height; // vid_height
2381
2382         // adjust width and height for the space occupied by window decorators (title bar, borders)
2383         rect->top = 0;
2384         rect->left = 0;
2385         rect->right = width;
2386         rect->bottom = height;
2387         AdjustWindowRectEx(rect, WS_CAPTION|WS_THICKFRAME, false, 0);
2388
2389         RECT workArea;
2390         SystemParametersInfo(SPI_GETWORKAREA, 0, &workArea, 0);
2391         int workWidth = workArea.right - workArea.left;
2392         int workHeight = workArea.bottom - workArea.top;
2393
2394         // SDL forces the window height to be <= screen height - 27px (on Win8.1 - probably intended for the title bar) 
2395         // If the task bar is docked to the the left screen border and we move the window to negative y,
2396         // there would be some part of the regular desktop visible on the bottom of the screen.
2397         int titleBarPixels = 2;
2398         int screenHeight = GetSystemMetrics(SM_CYSCREEN);
2399         if (screenHeight == workHeight)
2400                 titleBarPixels = -rect->top;
2401
2402         //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);
2403
2404         // if height and width matches the physical or previously adjusted screen height and width, adjust it to available desktop area
2405         if ((width == GetSystemMetrics(SM_CXSCREEN) || width == workWidth) && (height == screenHeight || height == workHeight - titleBarPixels))
2406         {
2407                 rect->left = workArea.left;
2408                 mode->width = workWidth;
2409                 rect->top = workArea.top + titleBarPixels;
2410                 mode->height = workHeight - titleBarPixels;
2411         }
2412         else 
2413         {
2414                 rect->left = workArea.left + max(0, (workWidth - width) / 2);
2415                 rect->top = workArea.top + max(0, (workHeight - height) / 2);
2416         }
2417 }
2418 #endif
2419
2420 static qboolean VID_InitModeGL(viddef_mode_t *mode)
2421 {
2422 #if SDL_MAJOR_VERSION == 1
2423         static int notfirstvideomode = false;
2424         int flags = SDL_OPENGL;
2425 #else
2426         int windowflags = SDL_WINDOW_SHOWN | SDL_WINDOW_OPENGL;
2427         int xPos = SDL_WINDOWPOS_UNDEFINED;
2428         int yPos = SDL_WINDOWPOS_UNDEFINED;
2429 #endif
2430 #ifndef USE_GLES2
2431         int i;
2432         const char *drivername;
2433 #endif
2434
2435         win_half_width = mode->width>>1;
2436         win_half_height = mode->height>>1;
2437
2438         if(vid_resizable.integer)
2439 #if SDL_MAJOR_VERSION == 1
2440                 flags |= SDL_RESIZABLE;
2441 #else
2442                 windowflags |= SDL_WINDOW_RESIZABLE;
2443 #endif
2444
2445         VID_OutputVersion();
2446
2447 #if SDL_MAJOR_VERSION == 1
2448         /*
2449         SDL 1.2 Hack
2450                 We cant switch from one OpenGL video mode to another.
2451                 Thus we first switch to some stupid 2D mode and then back to OpenGL.
2452         */
2453         if (notfirstvideomode)
2454                 SDL_SetVideoMode( 0, 0, 0, 0 );
2455         notfirstvideomode = true;
2456 #endif
2457
2458 #ifndef USE_GLES2
2459         // SDL usually knows best
2460         drivername = NULL;
2461
2462 // 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
2463         i = COM_CheckParm("-gl_driver");
2464         if (i && i < com_argc - 1)
2465                 drivername = com_argv[i + 1];
2466         if (SDL_GL_LoadLibrary(drivername) < 0)
2467         {
2468                 Con_Printf("Unable to load GL driver \"%s\": %s\n", drivername, SDL_GetError());
2469                 return false;
2470         }
2471 #endif
2472
2473 #ifdef DP_MOBILETOUCH
2474         // mobile platforms are always fullscreen, we'll get the resolution after opening the window
2475         mode->fullscreen = true;
2476         // hide the menu with SDL_WINDOW_BORDERLESS
2477         windowflags |= SDL_WINDOW_FULLSCREEN | SDL_WINDOW_BORDERLESS;
2478 #endif
2479 #ifndef USE_GLES2
2480         if ((qglGetString = (const GLubyte* (GLAPIENTRY *)(GLenum name))GL_GetProcAddress("glGetString")) == NULL)
2481         {
2482                 VID_Shutdown();
2483                 Con_Print("Required OpenGL function glGetString not found\n");
2484                 return false;
2485         }
2486 #endif
2487
2488         // Knghtbrd: should do platform-specific extension string function here
2489
2490         vid_isfullscreen = false;
2491 #if SDL_MAJOR_VERSION == 1
2492         {
2493                 const SDL_VideoInfo *vi = SDL_GetVideoInfo();
2494                 desktop_mode.width = vi->current_w;
2495                 desktop_mode.height = vi->current_h;
2496                 desktop_mode.bpp = vi->vfmt->BitsPerPixel;
2497                 desktop_mode.pixelheight_num = 1;
2498                 desktop_mode.pixelheight_denom = 1; // SDL does not provide this
2499                 if (mode->fullscreen) {
2500                         if (vid_desktopfullscreen.integer)
2501                         {
2502                                 mode->width = vi->current_w;
2503                                 mode->height = vi->current_h;
2504                                 mode->bitsperpixel = vi->vfmt->BitsPerPixel;
2505                         }
2506                         flags |= SDL_FULLSCREEN;
2507                         vid_isfullscreen = true;
2508                 }
2509         }
2510 #else
2511         {
2512                 if (mode->fullscreen) {
2513                         if (vid_desktopfullscreen.integer)
2514                         {
2515                                 vid_mode_t *m = VID_GetDesktopMode();
2516                                 mode->width = m->width;
2517                                 mode->height = m->height;
2518                                 windowflags |= SDL_WINDOW_FULLSCREEN_DESKTOP;
2519                         }
2520                         else
2521                                 windowflags |= SDL_WINDOW_FULLSCREEN;
2522                         vid_isfullscreen = true;
2523                 }
2524                 else {
2525 #ifdef WIN32
2526                         RECT rect;
2527                         AdjustWindowBounds(mode, &rect);
2528                         xPos = rect.left;
2529                         yPos = rect.top;
2530 #endif
2531                 }
2532         }
2533 #endif
2534         //flags |= SDL_HWSURFACE;
2535
2536         SDL_GL_SetAttribute (SDL_GL_DOUBLEBUFFER, 1);
2537         if (mode->bitsperpixel >= 32)
2538         {
2539                 SDL_GL_SetAttribute (SDL_GL_RED_SIZE, 8);
2540                 SDL_GL_SetAttribute (SDL_GL_GREEN_SIZE, 8);
2541                 SDL_GL_SetAttribute (SDL_GL_BLUE_SIZE, 8);
2542                 SDL_GL_SetAttribute (SDL_GL_ALPHA_SIZE, 8);
2543                 SDL_GL_SetAttribute (SDL_GL_DEPTH_SIZE, 24);
2544                 SDL_GL_SetAttribute (SDL_GL_STENCIL_SIZE, 8);
2545         }
2546         else
2547         {
2548                 SDL_GL_SetAttribute (SDL_GL_RED_SIZE, 5);
2549                 SDL_GL_SetAttribute (SDL_GL_GREEN_SIZE, 5);
2550                 SDL_GL_SetAttribute (SDL_GL_BLUE_SIZE, 5);
2551                 SDL_GL_SetAttribute (SDL_GL_DEPTH_SIZE, 16);
2552         }
2553         if (mode->stereobuffer)
2554                 SDL_GL_SetAttribute (SDL_GL_STEREO, 1);
2555         if (mode->samples > 1)
2556         {
2557                 SDL_GL_SetAttribute (SDL_GL_MULTISAMPLEBUFFERS, 1);
2558                 SDL_GL_SetAttribute (SDL_GL_MULTISAMPLESAMPLES, mode->samples);
2559         }
2560
2561 #if SDL_MAJOR_VERSION == 1
2562         if (vid_vsync.integer)
2563                 SDL_GL_SetAttribute (SDL_GL_SWAP_CONTROL, 1);
2564         else
2565                 SDL_GL_SetAttribute (SDL_GL_SWAP_CONTROL, 0);
2566 #else
2567 #ifdef USE_GLES2
2568         SDL_GL_SetAttribute (SDL_GL_CONTEXT_MAJOR_VERSION, 2);
2569         SDL_GL_SetAttribute (SDL_GL_CONTEXT_MINOR_VERSION, 0);
2570         SDL_GL_SetAttribute (SDL_GL_RETAINED_BACKING, 1);
2571 #endif
2572 #endif
2573
2574         video_bpp = mode->bitsperpixel;
2575 #if SDL_MAJOR_VERSION == 1
2576         video_flags = flags;
2577         video_screen = VID_WrapSDL_SetVideoMode(mode->width, mode->height, mode->bitsperpixel, flags);
2578         if (video_screen == NULL)
2579         {
2580                 Con_Printf("Failed to set video mode to %ix%i: %s\n", mode->width, mode->height, SDL_GetError());
2581                 VID_Shutdown();
2582                 return false;
2583         }
2584         mode->width = video_screen->w;
2585         mode->height = video_screen->h;
2586 #else
2587         window_flags = windowflags;
2588         window = SDL_CreateWindow(gamename, xPos, yPos, mode->width, mode->height, windowflags);
2589         if (window == NULL)
2590         {
2591                 Con_Printf("Failed to set video mode to %ix%i: %s\n", mode->width, mode->height, SDL_GetError());
2592                 VID_Shutdown();
2593                 return false;
2594         }
2595         SDL_GetWindowSize(window, &mode->width, &mode->height);
2596         context = SDL_GL_CreateContext(window);
2597         if (context == NULL)
2598         {
2599                 Con_Printf("Failed to initialize OpenGL context: %s\n", SDL_GetError());
2600                 VID_Shutdown();
2601                 return false;
2602         }
2603 #endif
2604
2605 #if SDL_MAJOR_VERSION == 1
2606         // init keyboard
2607         SDL_EnableUNICODE( SDL_ENABLE );
2608         // enable key repeat since everyone expects it
2609         SDL_EnableKeyRepeat(SDL_DEFAULT_REPEAT_DELAY, SDL_DEFAULT_REPEAT_INTERVAL);
2610 #endif
2611
2612 #if SDL_MAJOR_VERSION != 1
2613         SDL_GL_SetSwapInterval(vid_vsync.integer != 0);
2614         vid_usingvsync = (vid_vsync.integer != 0);
2615 #endif
2616
2617         gl_platform = "SDL";
2618         gl_platformextensions = "";
2619
2620 #ifdef USE_GLES2
2621         GLES_Init();
2622 #else
2623         GL_Init();
2624 #endif
2625
2626         vid_hidden = false;
2627         vid_activewindow = false;
2628         vid_hasfocus = true;
2629         vid_usingmouse = false;
2630         vid_usinghidecursor = false;
2631                 
2632 #if SDL_MAJOR_VERSION == 1
2633         SDL_WM_GrabInput(SDL_GRAB_OFF);
2634 #endif
2635         return true;
2636 }
2637
2638 extern cvar_t gl_info_extensions;
2639 extern cvar_t gl_info_vendor;
2640 extern cvar_t gl_info_renderer;
2641 extern cvar_t gl_info_version;
2642 extern cvar_t gl_info_platform;
2643 extern cvar_t gl_info_driver;
2644
2645 qboolean VID_InitMode(viddef_mode_t *mode)
2646 {
2647         // GAME_STEELSTORM specific
2648         steelstorm_showing_map = Cvar_FindVar("steelstorm_showing_map");
2649         steelstorm_showing_mousecursor = Cvar_FindVar("steelstorm_showing_mousecursor");
2650
2651         if (!SDL_WasInit(SDL_INIT_VIDEO) && SDL_InitSubSystem(SDL_INIT_VIDEO) < 0)
2652                 Sys_Error ("Failed to init SDL video subsystem: %s", SDL_GetError());
2653
2654 #if SDL_MAJOR_VERSION != 1
2655         Cvar_SetValueQuick(&vid_touchscreen_supportshowkeyboard, SDL_HasScreenKeyboardSupport() ? 1 : 0);
2656 #endif
2657         return VID_InitModeGL(mode);
2658 }
2659
2660 void VID_Shutdown (void)
2661 {
2662         VID_EnableJoystick(false);
2663         VID_SetMouse(false, false, false);
2664
2665 #if SDL_MAJOR_VERSION == 1
2666 #ifndef WIN32
2667 #ifndef MACOSX
2668         if (icon)
2669                 SDL_FreeSurface(icon);
2670         icon = NULL;
2671 #endif
2672 #endif
2673 #endif
2674
2675 #if SDL_MAJOR_VERSION != 1
2676         SDL_DestroyWindow(window);
2677         window = NULL;
2678 #endif
2679
2680         SDL_QuitSubSystem(SDL_INIT_VIDEO);
2681
2682         gl_driver[0] = 0;
2683         gl_extensions = "";
2684         gl_platform = "";
2685         gl_platformextensions = "";
2686 }
2687
2688 void VID_Finish (void)
2689 {
2690 #if SDL_MAJOR_VERSION == 1
2691         Uint8 appstate;
2692
2693         //react on appstate changes
2694         appstate = SDL_GetAppState();
2695
2696         vid_hidden = !(appstate & SDL_APPACTIVE);
2697         vid_hasfocus = (appstate & SDL_APPINPUTFOCUS) != 0;
2698 #endif
2699         vid_activewindow = !vid_hidden && vid_hasfocus;
2700
2701         VID_UpdateGamma();
2702
2703         if (!vid_hidden)
2704         {
2705                 switch(vid.renderpath)
2706                 {
2707                 case RENDERPATH_GL20:
2708                 case RENDERPATH_GLES2:
2709                         CHECKGLERROR
2710                         if (r_speeds.integer == 2 || gl_finish.integer)
2711                                 GL_Finish();
2712
2713 #if SDL_MAJOR_VERSION != 1
2714 {
2715         qboolean vid_usevsync;
2716         vid_usevsync = (vid_vsync.integer && !cls.timedemo);
2717         if (vid_usingvsync != vid_usevsync)
2718         {
2719                 vid_usingvsync = vid_usevsync;
2720                 if (SDL_GL_SetSwapInterval(vid_usevsync != 0) >= 0)
2721                         Con_DPrintf("Vsync %s\n", vid_usevsync ? "activated" : "deactivated");
2722                 else
2723                         Con_DPrintf("ERROR: can't %s vsync\n", vid_usevsync ? "activate" : "deactivate");
2724         }
2725 }
2726 #endif
2727 #if SDL_MAJOR_VERSION == 1
2728                         SDL_GL_SwapBuffers();
2729 #else
2730                         SDL_GL_SwapWindow(window);
2731 #endif
2732                         break;
2733                 }
2734         }
2735 }
2736
2737 vid_mode_t *VID_GetDesktopMode(void)
2738 {
2739 #if SDL_MAJOR_VERSION != 1
2740         SDL_DisplayMode mode;
2741         int bpp;
2742         Uint32 rmask, gmask, bmask, amask;
2743         SDL_GetDesktopDisplayMode(0, &mode);
2744         SDL_PixelFormatEnumToMasks(mode.format, &bpp, &rmask, &gmask, &bmask, &amask);
2745         desktop_mode.width = mode.w;
2746         desktop_mode.height = mode.h;
2747         desktop_mode.bpp = bpp;
2748         desktop_mode.refreshrate = mode.refresh_rate;
2749         desktop_mode.pixelheight_num = 1;
2750         desktop_mode.pixelheight_denom = 1; // SDL does not provide this
2751         // TODO check whether this actually works, or whether we do still need
2752         // a read-window-size-after-entering-desktop-fullscreen hack for
2753         // multiscreen setups.
2754 #endif
2755         return &desktop_mode;
2756 }
2757
2758 size_t VID_ListModes(vid_mode_t *modes, size_t maxcount)
2759 {
2760         size_t k = 0;
2761 #if SDL_MAJOR_VERSION == 1
2762         SDL_Rect **vidmodes;
2763         int bpp = SDL_GetVideoInfo()->vfmt->BitsPerPixel;
2764 #ifdef WIN64
2765         SDL_Rect **ENDRECT = (SDL_Rect**)-1LL;
2766 #else
2767         SDL_Rect **ENDRECT = (SDL_Rect**)-1;
2768 #endif
2769
2770         for(vidmodes = SDL_ListModes(NULL, SDL_FULLSCREEN|SDL_HWSURFACE); vidmodes && vidmodes != ENDRECT && *vidmodes; ++vidmodes)
2771         {
2772                 if(k >= maxcount)
2773                         break;
2774                 modes[k].width = (*vidmodes)->w;
2775                 modes[k].height = (*vidmodes)->h;
2776                 modes[k].bpp = bpp;
2777                 modes[k].refreshrate = 60; // no support for refresh rate in SDL
2778                 modes[k].pixelheight_num = 1;
2779                 modes[k].pixelheight_denom = 1; // SDL does not provide this
2780                 ++k;
2781         }
2782 #else
2783         int modenum;
2784         int nummodes = SDL_GetNumDisplayModes(0);
2785         SDL_DisplayMode mode;
2786         for (modenum = 0;modenum < nummodes;modenum++)
2787         {
2788                 if (k >= maxcount)
2789                         break;
2790                 if (SDL_GetDisplayMode(0, modenum, &mode))
2791                         continue;
2792                 modes[k].width = mode.w;
2793                 modes[k].height = mode.h;
2794                 // FIXME bpp?
2795                 modes[k].refreshrate = mode.refresh_rate;
2796                 modes[k].pixelheight_num = 1;
2797                 modes[k].pixelheight_denom = 1; // SDL does not provide this
2798                 k++;
2799         }
2800 #endif
2801         return k;
2802 }