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