1 /*
2   Simple DirectMedia Layer
3   Copyright (C) 1997-2021 Sam Lantinga <slouken@libsdl.org>
4 
5   This software is provided 'as-is', without any express or implied
6   warranty.  In no event will the authors be held liable for any damages
7   arising from the use of this software.
8 
9   Permission is granted to anyone to use this software for any purpose,
10   including commercial applications, and to alter it and redistribute it
11   freely, subject to the following restrictions:
12 
13   1. The origin of this software must not be misrepresented; you must not
14      claim that you wrote the original software. If you use this software
15      in a product, an acknowledgment in the product documentation would be
16      appreciated but is not required.
17   2. Altered source versions must be plainly marked as such, and must not be
18      misrepresented as being the original software.
19   3. This notice may not be removed or altered from any source distribution.
20 */
21 
22 /* This file contains functions for backwards compatibility with SDL 1.2 */
23 
24 #include "SDL20_include_wrapper.h"
25 
26 /*
27  * We report the library version as 1.2.$(SDL12_COMPAT_VERSION). This number
28  *  should be way ahead of what SDL-1.2 Classic would report, so apps can
29  *  decide if they're running under the compat layer, if they really care.
30  */
31 #define SDL12_COMPAT_VERSION 50
32 
33 #include <stdarg.h>
34 #include <limits.h>
35 #include <stddef.h>
36 #if defined(_MSC_VER) && (_MSC_VER < 1600)
37 /* intptr_t already handled by stddef.h. */
38 #else
39 #include <stdint.h>
40 #endif
41 
42 #ifdef _WIN32
43 #ifndef WIN32_LEAN_AND_MEAN
44 #define WIN32_LEAN_AND_MEAN 1
45 #endif
46 #include <windows.h>
47 #else
48 #include <stdio.h> /* fprintf(), etc. */
49 #include <stdlib.h>    /* for abort() */
50 #include <string.h>
51 #endif
52 
53 /* mingw headers may define these ... */
54 #undef strtod
55 #undef strcasecmp
56 #undef strncasecmp
57 #undef snprintf
58 #undef vsnprintf
59 
60 #define SDL_BlitSurface SDL_UpperBlit
61 
62 #ifdef __cplusplus
63 extern "C" {
64 #endif
65 
66 #define ENABLE_FIXMES 1
67 #if ENABLE_FIXMES == -1  /* don't even allow a build to finish if there's a FIXME */
68     /* the goal with this nonsense is to make the compiler print an error that
69        broadcasts the problem _and the string literal_ from the actual FIXME line */
70     extern void YouCannotBuildUntilYouResolveThisFixme(char *x);
71     #define FIXME(x) YouCannotBuildUntilYouResolveThisFixme(-->)
72 #elif ENABLE_FIXMES == 0  /* compile out any FIXMEs entirely. */
73     #define FIXME(x) do {} while (0)
74 #elif ENABLE_FIXMES == 1  /* Log a warning the first time a FIXME is executed. */
75     static SDL_bool PrintFixmes = SDL_TRUE;
76     #define FIXME(x) \
77         do { \
78             if (PrintFixmes) { \
79                 static SDL_bool seen = SDL_FALSE; \
80                 if (!seen) { \
81                     SDL20_Log("FIXME: %s (%s:%d)\n", x, __FUNCTION__, __LINE__); \
82                     seen = SDL_TRUE; \
83                 } \
84             } \
85         } while (0)
86 #else
87     #error Please fix the ENABLE_FIXMES define.
88 #endif
89 
90 #define SDL20_SYM(rc,fn,params,args,ret) \
91     typedef rc (SDLCALL *SDL20_##fn##_t) params; \
92     static SDL20_##fn##_t SDL20_##fn = NULL;
93 #include "SDL20_syms.h"
94 
95 /* Things that _should_ be binary compatible pass right through... */
96 #define SDL20_SYM_PASSTHROUGH(rc,fn,params,args,ret) \
97     DECLSPEC rc SDLCALL SDL_##fn params { ret SDL20_##fn args; }
98 #include "SDL20_syms.h"
99 
100 
101 /* these are macros (etc) in the SDL headers, so make our own. */
102 #define SDL20_OutOfMemory() SDL20_Error(SDL_ENOMEM)
103 #define SDL20_Unsupported() SDL20_Error(SDL_UNSUPPORTED)
104 #define SDL20_InvalidParamError(param) SDL20_SetError("Parameter '%s' is invalid", (param))
105 #define SDL20_zero(x) SDL20_memset(&(x), 0, sizeof((x)))
106 #define SDL20_zerop(x) SDL20_memset((x), 0, sizeof(*(x)))
107 #define SDL_ReportAssertion SDL20_ReportAssertion
108 
109 /* From SDL2.0's SDL_bits.h: a force-inlined function. */
110 #if defined(__WATCOMC__) && defined(__386__)
111 extern __inline int _SDL20_bsr_watcom(Uint32);
112 #pragma aux _SDL20_bsr_watcom = \
113     "bsr eax, eax" \
114     parm [eax] nomemory \
115     value [eax] \
116     modify exact [eax] nomemory;
117 #endif
118 
119 SDL_FORCE_INLINE int
SDL20_MostSignificantBitIndex32(Uint32 x)120 SDL20_MostSignificantBitIndex32(Uint32 x)
121 {
122 #if defined(__GNUC__) && (__GNUC__ >= 4 || (__GNUC__ == 3 && __GNUC_MINOR__ >= 4))
123     /* Count Leading Zeroes builtin in GCC.
124      * http://gcc.gnu.org/onlinedocs/gcc-4.3.4/gcc/Other-Builtins.html
125      */
126     if (x == 0) {
127         return -1;
128     }
129     return 31 - __builtin_clz(x);
130 #elif defined(__WATCOMC__) && defined(__386__)
131     if (x == 0) {
132         return -1;
133     }
134     return _SDL20_bsr_watcom(x);
135 #elif defined(_MSC_VER)
136     unsigned long index;
137     if (_BitScanReverse(&index, x)) {
138         return index;
139     }
140     return -1;
141 #else
142     /* Based off of Bit Twiddling Hacks by Sean Eron Anderson
143      * <seander@cs.stanford.edu>, released in the public domain.
144      * http://graphics.stanford.edu/~seander/bithacks.html#IntegerLog
145      */
146     const Uint32 b[] = {0x2, 0xC, 0xF0, 0xFF00, 0xFFFF0000};
147     const int    S[] = {1, 2, 4, 8, 16};
148 
149     int msbIndex = 0;
150     int i;
151 
152     if (x == 0) {
153         return -1;
154     }
155 
156     for (i = 4; i >= 0; i--)
157     {
158         if (x & b[i])
159         {
160             x >>= S[i];
161             msbIndex |= S[i];
162         }
163     }
164 
165     return msbIndex;
166 #endif
167 }
168 
169 /* SDL_truncf needs SDL >=2.0.14, so copy it here. */
SDL20_truncf(float x)170 static float SDL20_truncf(float x)
171 {
172     return (x < 0.0f) ? (float)SDL20_ceil(x) : (float)SDL20_floor(x);
173 }
174 
175 #define SDL12_DEFAULT_REPEAT_DELAY 500
176 #define SDL12_DEFAULT_REPEAT_INTERVAL 30
177 
178 #define SDL12_INIT_TIMER       0x00000001
179 #define SDL12_INIT_AUDIO       0x00000010
180 #define SDL12_INIT_VIDEO       0x00000020
181 #define SDL12_INIT_CDROM       0x00000100
182 #define SDL12_INIT_JOYSTICK    0x00000200
183 #define SDL12_INIT_NOPARACHUTE 0x00100000
184 #define SDL12_INIT_EVENTTHREAD 0x01000000
185 #define SDL12_INIT_EVERYTHING  0x0000FFFF
186 
187 #define SDL12_LOGPAL 1
188 #define SDL12_PHYSPAL 2
189 
190 #ifndef SDL_SIMD_ALIGNED
191 #define SDL_SIMD_ALIGNED 0x00000008
192 #endif
193 
194 typedef struct SDL12_Rect
195 {
196     Sint16 x;
197     Sint16 y;
198     Uint16 w;
199     Uint16 h;
200 } SDL12_Rect;
201 
202 typedef struct SDL12_Palette
203 {
204     int       ncolors;
205     SDL_Color *colors;
206 } SDL12_Palette;
207 
208 typedef struct SDL12_PixelFormat
209 {
210     SDL12_Palette *palette;
211     Uint8 BitsPerPixel;
212     Uint8 BytesPerPixel;
213     Uint8 Rloss;
214     Uint8 Gloss;
215     Uint8 Bloss;
216     Uint8 Aloss;
217     Uint8 Rshift;
218     Uint8 Gshift;
219     Uint8 Bshift;
220     Uint8 Ashift;
221     Uint32 Rmask;
222     Uint32 Gmask;
223     Uint32 Bmask;
224     Uint32 Amask;
225     Uint32 colorkey;
226     Uint8 alpha;
227 } SDL12_PixelFormat;
228 
229 typedef struct SDL12_Surface
230 {
231     Uint32 flags;
232     SDL12_PixelFormat *format;
233     int w;
234     int h;
235     Uint16 pitch;
236     void *pixels;
237     int offset;
238     SDL_Surface *surface20; /* the real SDL 1.2 has an opaque pointer to a platform-specific thing here named "hwdata". */
239     SDL12_Rect clip_rect;
240     Uint32 unused1;
241     Uint32 locked;
242     void *blitmap;
243     unsigned int format_version;
244     int refcount;
245 } SDL12_Surface;
246 
247 #define SDL12_YV12_OVERLAY 0x32315659
248 #define SDL12_IYUV_OVERLAY 0x56555949
249 #define SDL12_YUY2_OVERLAY 0x32595559
250 #define SDL12_UYVY_OVERLAY 0x59565955
251 #define SDL12_YVYU_OVERLAY 0x55595659
252 
253 typedef struct SDL12_Overlay
254 {
255     Uint32 format;
256     int w;
257     int h;
258     int planes;
259     Uint16 *pitches;
260     Uint8 **pixels;
261     void *hwfuncs;
262     void *hwdata;
263     Uint32 hw_overlay :1;
264     Uint32 UnusedBits :31;
265 } SDL12_Overlay;
266 
267 typedef struct SDL12_YUVData  /* internal struct, not part of public SDL 1.2 API */
268 {
269     SDL_Texture *texture20;
270     SDL_bool dirty;
271     Uint8 *pixelbuf;
272     Uint8 *pixels[3];
273     Uint16 pitches[3];
274 } SDL12_YUVData;
275 
276 typedef struct
277 {
278     Uint32 hw_available :1;
279     Uint32 wm_available :1;
280     Uint32 UnusedBits1  :6;
281     Uint32 UnusedBits2  :1;
282     Uint32 blit_hw      :1;
283     Uint32 blit_hw_CC   :1;
284     Uint32 blit_hw_A    :1;
285     Uint32 blit_sw      :1;
286     Uint32 blit_sw_CC   :1;
287     Uint32 blit_sw_A    :1;
288     Uint32 blit_fill    :1;
289     Uint32 UnusedBits3  :16;
290     Uint32 video_mem;
291     SDL12_PixelFormat *vfmt;
292     int current_w;
293     int current_h;
294 } SDL12_VideoInfo;
295 
296 
297 #define SDL12_HWSURFACE 0x00000001
298 #define SDL12_ASYNCBLIT 0x00000004
299 #define SDL12_ANYFORMAT 0x10000000
300 #define SDL12_HWPALETTE 0x20000000
301 #define SDL12_DOUBLEBUF 0x40000000
302 #define SDL12_FULLSCREEN 0x80000000
303 #define SDL12_OPENGL 0x00000002
304 #define SDL12_OPENGLBLIT 0x0000000A
305 #define SDL12_RESIZABLE 0x00000010
306 #define SDL12_NOFRAME 0x00000020
307 #define SDL12_HWACCEL 0x00000100
308 #define SDL12_SRCCOLORKEY 0x00001000
309 #define SDL12_RLEACCELOK 0x00002000
310 #define SDL12_RLEACCEL 0x00004000
311 #define SDL12_SRCALPHA 0x00010000
312 #define SDL12_PREALLOC 0x01000000
313 
314 typedef enum
315 {
316     SDLK12_UNKNOWN = 0,
317     SDLK12_FIRST = 0,
318     SDLK12_BACKSPACE = 8,
319     SDLK12_TAB = 9,
320     SDLK12_CLEAR = 12,
321     SDLK12_RETURN = 13,
322     SDLK12_PAUSE = 19,
323     SDLK12_ESCAPE = 27,
324     SDLK12_SPACE = 32,
325     SDLK12_EXCLAIM = 33,
326     SDLK12_QUOTEDBL = 34,
327     SDLK12_HASH = 35,
328     SDLK12_DOLLAR = 36,
329     SDLK12_AMPERSAND = 38,
330     SDLK12_QUOTE = 39,
331     SDLK12_LEFTPAREN = 40,
332     SDLK12_RIGHTPAREN = 41,
333     SDLK12_ASTERISK = 42,
334     SDLK12_PLUS = 43,
335     SDLK12_COMMA = 44,
336     SDLK12_MINUS = 45,
337     SDLK12_PERIOD = 46,
338     SDLK12_SLASH = 47,
339     SDLK12_0 = 48,
340     SDLK12_1 = 49,
341     SDLK12_2 = 50,
342     SDLK12_3 = 51,
343     SDLK12_4 = 52,
344     SDLK12_5 = 53,
345     SDLK12_6 = 54,
346     SDLK12_7 = 55,
347     SDLK12_8 = 56,
348     SDLK12_9 = 57,
349     SDLK12_COLON = 58,
350     SDLK12_SEMICOLON = 59,
351     SDLK12_LESS = 60,
352     SDLK12_EQUALS = 61,
353     SDLK12_GREATER = 62,
354     SDLK12_QUESTION = 63,
355     SDLK12_AT = 64,
356     SDLK12_LEFTBRACKET = 91,
357     SDLK12_BACKSLASH = 92,
358     SDLK12_RIGHTBRACKET = 93,
359     SDLK12_CARET = 94,
360     SDLK12_UNDERSCORE = 95,
361     SDLK12_BACKQUOTE = 96,
362     SDLK12_a = 97,
363     SDLK12_b = 98,
364     SDLK12_c = 99,
365     SDLK12_d = 100,
366     SDLK12_e = 101,
367     SDLK12_f = 102,
368     SDLK12_g = 103,
369     SDLK12_h = 104,
370     SDLK12_i = 105,
371     SDLK12_j = 106,
372     SDLK12_k = 107,
373     SDLK12_l = 108,
374     SDLK12_m = 109,
375     SDLK12_n = 110,
376     SDLK12_o = 111,
377     SDLK12_p = 112,
378     SDLK12_q = 113,
379     SDLK12_r = 114,
380     SDLK12_s = 115,
381     SDLK12_t = 116,
382     SDLK12_u = 117,
383     SDLK12_v = 118,
384     SDLK12_w = 119,
385     SDLK12_x = 120,
386     SDLK12_y = 121,
387     SDLK12_z = 122,
388     SDLK12_DELETE = 127,
389     SDLK12_WORLD_0 = 160,
390     SDLK12_WORLD_1 = 161,
391     SDLK12_WORLD_2 = 162,
392     SDLK12_WORLD_3 = 163,
393     SDLK12_WORLD_4 = 164,
394     SDLK12_WORLD_5 = 165,
395     SDLK12_WORLD_6 = 166,
396     SDLK12_WORLD_7 = 167,
397     SDLK12_WORLD_8 = 168,
398     SDLK12_WORLD_9 = 169,
399     SDLK12_WORLD_10 = 170,
400     SDLK12_WORLD_11 = 171,
401     SDLK12_WORLD_12 = 172,
402     SDLK12_WORLD_13 = 173,
403     SDLK12_WORLD_14 = 174,
404     SDLK12_WORLD_15 = 175,
405     SDLK12_WORLD_16 = 176,
406     SDLK12_WORLD_17 = 177,
407     SDLK12_WORLD_18 = 178,
408     SDLK12_WORLD_19 = 179,
409     SDLK12_WORLD_20 = 180,
410     SDLK12_WORLD_21 = 181,
411     SDLK12_WORLD_22 = 182,
412     SDLK12_WORLD_23 = 183,
413     SDLK12_WORLD_24 = 184,
414     SDLK12_WORLD_25 = 185,
415     SDLK12_WORLD_26 = 186,
416     SDLK12_WORLD_27 = 187,
417     SDLK12_WORLD_28 = 188,
418     SDLK12_WORLD_29 = 189,
419     SDLK12_WORLD_30 = 190,
420     SDLK12_WORLD_31 = 191,
421     SDLK12_WORLD_32 = 192,
422     SDLK12_WORLD_33 = 193,
423     SDLK12_WORLD_34 = 194,
424     SDLK12_WORLD_35 = 195,
425     SDLK12_WORLD_36 = 196,
426     SDLK12_WORLD_37 = 197,
427     SDLK12_WORLD_38 = 198,
428     SDLK12_WORLD_39 = 199,
429     SDLK12_WORLD_40 = 200,
430     SDLK12_WORLD_41 = 201,
431     SDLK12_WORLD_42 = 202,
432     SDLK12_WORLD_43 = 203,
433     SDLK12_WORLD_44 = 204,
434     SDLK12_WORLD_45 = 205,
435     SDLK12_WORLD_46 = 206,
436     SDLK12_WORLD_47 = 207,
437     SDLK12_WORLD_48 = 208,
438     SDLK12_WORLD_49 = 209,
439     SDLK12_WORLD_50 = 210,
440     SDLK12_WORLD_51 = 211,
441     SDLK12_WORLD_52 = 212,
442     SDLK12_WORLD_53 = 213,
443     SDLK12_WORLD_54 = 214,
444     SDLK12_WORLD_55 = 215,
445     SDLK12_WORLD_56 = 216,
446     SDLK12_WORLD_57 = 217,
447     SDLK12_WORLD_58 = 218,
448     SDLK12_WORLD_59 = 219,
449     SDLK12_WORLD_60 = 220,
450     SDLK12_WORLD_61 = 221,
451     SDLK12_WORLD_62 = 222,
452     SDLK12_WORLD_63 = 223,
453     SDLK12_WORLD_64 = 224,
454     SDLK12_WORLD_65 = 225,
455     SDLK12_WORLD_66 = 226,
456     SDLK12_WORLD_67 = 227,
457     SDLK12_WORLD_68 = 228,
458     SDLK12_WORLD_69 = 229,
459     SDLK12_WORLD_70 = 230,
460     SDLK12_WORLD_71 = 231,
461     SDLK12_WORLD_72 = 232,
462     SDLK12_WORLD_73 = 233,
463     SDLK12_WORLD_74 = 234,
464     SDLK12_WORLD_75 = 235,
465     SDLK12_WORLD_76 = 236,
466     SDLK12_WORLD_77 = 237,
467     SDLK12_WORLD_78 = 238,
468     SDLK12_WORLD_79 = 239,
469     SDLK12_WORLD_80 = 240,
470     SDLK12_WORLD_81 = 241,
471     SDLK12_WORLD_82 = 242,
472     SDLK12_WORLD_83 = 243,
473     SDLK12_WORLD_84 = 244,
474     SDLK12_WORLD_85 = 245,
475     SDLK12_WORLD_86 = 246,
476     SDLK12_WORLD_87 = 247,
477     SDLK12_WORLD_88 = 248,
478     SDLK12_WORLD_89 = 249,
479     SDLK12_WORLD_90 = 250,
480     SDLK12_WORLD_91 = 251,
481     SDLK12_WORLD_92 = 252,
482     SDLK12_WORLD_93 = 253,
483     SDLK12_WORLD_94 = 254,
484     SDLK12_WORLD_95 = 255,
485     SDLK12_KP0 = 256,
486     SDLK12_KP1 = 257,
487     SDLK12_KP2 = 258,
488     SDLK12_KP3 = 259,
489     SDLK12_KP4 = 260,
490     SDLK12_KP5 = 261,
491     SDLK12_KP6 = 262,
492     SDLK12_KP7 = 263,
493     SDLK12_KP8 = 264,
494     SDLK12_KP9 = 265,
495     SDLK12_KP_PERIOD = 266,
496     SDLK12_KP_DIVIDE = 267,
497     SDLK12_KP_MULTIPLY = 268,
498     SDLK12_KP_MINUS = 269,
499     SDLK12_KP_PLUS = 270,
500     SDLK12_KP_ENTER = 271,
501     SDLK12_KP_EQUALS = 272,
502     SDLK12_UP = 273,
503     SDLK12_DOWN = 274,
504     SDLK12_RIGHT = 275,
505     SDLK12_LEFT = 276,
506     SDLK12_INSERT = 277,
507     SDLK12_HOME = 278,
508     SDLK12_END = 279,
509     SDLK12_PAGEUP = 280,
510     SDLK12_PAGEDOWN = 281,
511     SDLK12_F1 = 282,
512     SDLK12_F2 = 283,
513     SDLK12_F3 = 284,
514     SDLK12_F4 = 285,
515     SDLK12_F5 = 286,
516     SDLK12_F6 = 287,
517     SDLK12_F7 = 288,
518     SDLK12_F8 = 289,
519     SDLK12_F9 = 290,
520     SDLK12_F10 = 291,
521     SDLK12_F11 = 292,
522     SDLK12_F12 = 293,
523     SDLK12_F13 = 294,
524     SDLK12_F14 = 295,
525     SDLK12_F15 = 296,
526     SDLK12_NUMLOCK = 300,
527     SDLK12_CAPSLOCK = 301,
528     SDLK12_SCROLLOCK = 302,
529     SDLK12_RSHIFT = 303,
530     SDLK12_LSHIFT = 304,
531     SDLK12_RCTRL = 305,
532     SDLK12_LCTRL = 306,
533     SDLK12_RALT = 307,
534     SDLK12_LALT = 308,
535     SDLK12_RMETA = 309,
536     SDLK12_LMETA = 310,
537     SDLK12_LSUPER = 311,
538     SDLK12_RSUPER = 312,
539     SDLK12_MODE = 313,
540     SDLK12_COMPOSE = 314,
541     SDLK12_HELP = 315,
542     SDLK12_PRINT = 316,
543     SDLK12_SYSREQ = 317,
544     SDLK12_BREAK = 318,
545     SDLK12_MENU = 319,
546     SDLK12_POWER = 320,
547     SDLK12_EURO = 321,
548     SDLK12_UNDO = 322,
549     SDLK12_LAST
550 } SDL12Key;
551 
552 typedef enum
553 {
554     KMOD12_NONE  = 0x0000,
555     KMOD12_LSHIFT = 0x0001,
556     KMOD12_RSHIFT = 0x0002,
557     KMOD12_LCTRL = 0x0040,
558     KMOD12_RCTRL = 0x0080,
559     KMOD12_LALT = 0x0100,
560     KMOD12_RALT = 0x0200,
561     KMOD12_LMETA = 0x0400,
562     KMOD12_RMETA = 0x0800,
563     KMOD12_NUM = 0x1000,
564     KMOD12_CAPS = 0x2000,
565     KMOD12_MODE = 0x4000,
566     KMOD12_RESERVED = 0x8000
567 } SDL12Mod;
568 
569 typedef struct SDL12_keysym
570 {
571     Uint8 scancode;
572     SDL12Key sym;
573     unsigned int mod; /* SDL12Mod */
574     Uint16 unicode;
575 } SDL12_keysym;
576 
577 #define SDL12_RELEASED 0
578 #define SDL12_PRESSED  1
579 
580 #if defined(SDL_VIDEO_DRIVER_X11)  /* SDL_VIDEO_DRIVER_X11 refers to the SDL2 headers. */
581 typedef enum  /* this is only used for 1.2 X11 syswm */
582 {
583     SDL12_SYSWM_X11
584 } SDL12_SYSWM_TYPE;
585 #endif
586 
587 typedef struct SDL12_SysWMmsg
588 {
589     SDL_version version;
590 #if defined(_WIN32)
591     HWND hwnd;
592     UINT msg;
593     WPARAM wParam;
594     LPARAM lParam;
595 #elif defined(SDL_VIDEO_DRIVER_X11)
596     SDL12_SYSWM_TYPE subsystem;
597     union { XEvent xevent; } event;
598 #else
599     int data;  /* unused at the moment. */
600 #endif
601 } SDL12_SysWMmsg;
602 
603 typedef struct SDL12_SysWMinfo
604 {
605     SDL_version version;
606 #if defined(_WIN32)
607     HWND window;
608     HGLRC hglrc;
609 #elif defined(SDL_VIDEO_DRIVER_X11)
610     SDL12_SYSWM_TYPE subsystem;
611     union {
612         struct {
613             Display *display;
614             Window window;
615             void (*lock_func)(void);
616             void (*unlock_func)(void);
617             Window fswindow;
618             Window wmwindow;
619             Display *gfxdisplay;
620         } x11;
621     } info;
622 #else
623     int data;  /* unused at the moment. */
624 #endif
625 } SDL12_SysWMinfo;
626 
627 
628 typedef enum
629 {
630     SDL12_NOEVENT = 0,
631     SDL12_ACTIVEEVENT,
632     SDL12_KEYDOWN,
633     SDL12_KEYUP,
634     SDL12_MOUSEMOTION,
635     SDL12_MOUSEBUTTONDOWN,
636     SDL12_MOUSEBUTTONUP,
637     SDL12_JOYAXISMOTION,
638     SDL12_JOYBALLMOTION,
639     SDL12_JOYHATMOTION,
640     SDL12_JOYBUTTONDOWN,
641     SDL12_JOYBUTTONUP,
642     SDL12_QUIT,
643     SDL12_SYSWMEVENT,
644     SDL12_EVENT_RESERVEDA,
645     SDL12_EVENT_RESERVEDB,
646     SDL12_VIDEORESIZE,
647     SDL12_VIDEOEXPOSE,
648     SDL12_USEREVENT = 24,
649     SDL12_NUMEVENTS = 32
650 } SDL12_EventType;
651 
652 
653 #define SDL12_APPMOUSEFOCUS (1<<0)
654 #define SDL12_APPINPUTFOCUS (1<<1)
655 #define SDL12_APPACTIVE     (1<<2)
656 
657 typedef struct
658 {
659     Uint8 type;
660     Uint8 gain;
661     Uint8 state;
662 } SDL12_ActiveEvent;
663 
664 typedef struct
665 {
666     Uint8 type;
667     Uint8 which;
668     Uint8 state;
669     SDL12_keysym keysym;
670 } SDL12_KeyboardEvent;
671 
672 typedef struct
673 {
674     Uint8 type;
675     Uint8 which;
676     Uint8 state;
677     Uint16 x, y;
678     Sint16 xrel;
679     Sint16 yrel;
680 } SDL12_MouseMotionEvent;
681 
682 typedef struct
683 {
684     Uint8 type;
685     Uint8 which;
686     Uint8 button;
687     Uint8 state;
688     Uint16 x, y;
689 } SDL12_MouseButtonEvent;
690 
691 typedef struct
692 {
693     Uint8 type;
694     Uint8 which;
695     Uint8 axis;
696     Sint16 value;
697 } SDL12_JoyAxisEvent;
698 
699 typedef struct
700 {
701     Uint8 type;
702     Uint8 which;
703     Uint8 ball;
704     Sint16 xrel;
705     Sint16 yrel;
706 } SDL12_JoyBallEvent;
707 
708 typedef struct
709 {
710     Uint8 type;
711     Uint8 which;
712     Uint8 hat;
713     Uint8 value;
714 } SDL12_JoyHatEvent;
715 
716 typedef struct
717 {
718     Uint8 type;
719     Uint8 which;
720     Uint8 button;
721     Uint8 state;
722 } SDL12_JoyButtonEvent;
723 
724 typedef struct
725 {
726     Uint8 type;
727     int w;
728     int h;
729 } SDL12_ResizeEvent;
730 
731 typedef struct
732 {
733     Uint8 type;
734 } SDL12_ExposeEvent;
735 
736 typedef struct
737 {
738     Uint8 type;
739 } SDL12_QuitEvent;
740 
741 typedef struct
742 {
743     Uint8 type;
744     int code;
745     void *data1;
746     void *data2;
747 } SDL12_UserEvent;
748 
749 typedef struct
750 {
751     Uint8 type;
752     SDL12_SysWMmsg *msg;
753 } SDL12_SysWMEvent;
754 
755 typedef union
756 {
757     Uint8 type;
758     SDL12_ActiveEvent active;
759     SDL12_KeyboardEvent key;
760     SDL12_MouseMotionEvent motion;
761     SDL12_MouseButtonEvent button;
762     SDL12_JoyAxisEvent jaxis;
763     SDL12_JoyBallEvent jball;
764     SDL12_JoyHatEvent jhat;
765     SDL12_JoyButtonEvent jbutton;
766     SDL12_ResizeEvent resize;
767     SDL12_ExposeEvent expose;
768     SDL12_QuitEvent quit;
769     SDL12_UserEvent user;
770     SDL12_SysWMEvent syswm;
771 } SDL12_Event;
772 
773 typedef int (SDLCALL *SDL12_EventFilter)(const SDL12_Event *event12);
774 static int SDLCALL EventFilter20to12(void *data, SDL_Event *event20);
775 
776 typedef Uint32 (SDLCALL *SDL12_TimerCallback)(Uint32 interval);
777 typedef SDL_TimerCallback SDL12_NewTimerCallback;
778 
779 typedef struct
780 {
781     SDL12_Rect area;
782     Sint16 hot_x;
783     Sint16 hot_y;
784     Uint8 *data;
785     Uint8 *mask;
786     Uint8 *save[2];
787     SDL_Cursor *wm_cursor;  /* the real SDL 1.2 has an opaque pointer to a platform-specific cursor here. */
788 } SDL12_Cursor;
789 
790 typedef enum
791 {
792     SDL12_GRAB_QUERY = -1,
793     SDL12_GRAB_OFF = 0,
794     SDL12_GRAB_ON = 1
795 } SDL12_GrabMode;
796 
797 typedef enum
798 {
799     SDL12_GL_RED_SIZE,
800     SDL12_GL_GREEN_SIZE,
801     SDL12_GL_BLUE_SIZE,
802     SDL12_GL_ALPHA_SIZE,
803     SDL12_GL_BUFFER_SIZE,
804     SDL12_GL_DOUBLEBUFFER,
805     SDL12_GL_DEPTH_SIZE,
806     SDL12_GL_STENCIL_SIZE,
807     SDL12_GL_ACCUM_RED_SIZE,
808     SDL12_GL_ACCUM_GREEN_SIZE,
809     SDL12_GL_ACCUM_BLUE_SIZE,
810     SDL12_GL_ACCUM_ALPHA_SIZE,
811     SDL12_GL_STEREO,
812     SDL12_GL_MULTISAMPLEBUFFERS,
813     SDL12_GL_MULTISAMPLESAMPLES,
814     SDL12_GL_ACCELERATED_VISUAL,
815     SDL12_GL_SWAP_CONTROL,
816     SDL12_GL_MAX_ATTRIBUTE
817 } SDL12_GLattr;
818 
819 
820 typedef enum
821 {
822     SDL12_CD_TRAYEMPTY,
823     SDL12_CD_STOPPED,
824     SDL12_CD_PLAYING,
825     SDL12_CD_PAUSED,
826     SDL12_CD_ERROR = -1
827 } SDL12_CDstatus;
828 
829 typedef struct
830 {
831     Uint8 id;
832     Uint8 type;
833     Uint16 unused;
834     Uint32 length;
835     Uint32 offset;
836 } SDL12_CDtrack;
837 
838 typedef struct
839 {
840     int id;
841     SDL12_CDstatus status;
842     int numtracks;
843     int cur_track;
844     int cur_frame;
845     SDL12_CDtrack track[100];  /* in 1.2, this was SDL_MAX_TRACKS+1 */
846 } SDL12_CD;
847 
848 typedef struct
849 {
850     Uint32 format;
851     int nummodes;
852     SDL12_Rect *modeslist12;
853     SDL12_Rect **modes12;  /* ptrs to each item in modeslist, for SDL_ListModes() */
854 } VideoModeList;
855 
856 typedef struct
857 {
858     int device_index;
859     SDL_Joystick *joystick;
860 } JoystickOpenedItem;
861 
862 /* this is identical to SDL2, except SDL2 forced the structure packing in
863    some instances, so we can't passthrough without converting the struct. :( */
864 typedef struct
865 {
866     int needed;
867     Uint16 src_format;
868     Uint16 dst_format;
869     double rate_incr;
870     Uint8 *buf;
871     int len;
872     int len_cvt;
873     int len_mult;
874     double len_ratio;
875     void (SDLCALL *filters[10])(struct SDL_AudioCVT *cvt, Uint16 format);
876     int filter_index;
877 } SDL12_AudioCVT;
878 
879 #include "SDL_opengl.h"
880 #include "SDL_opengl_glext.h"
881 
882 
883 #define OPENGL_SYM(ext,rc,fn,params,args,ret) typedef rc (GLAPIENTRY *openglfn_##fn##_t) params;
884 #include "SDL20_syms.h"
885 
886 typedef struct OpenGLEntryPoints
887 {
888     SDL_bool SUPPORTS_Core;
889 
890     #define OPENGL_EXT(name) SDL_bool SUPPORTS_##name;
891     #include "SDL20_syms.h"
892     #define OPENGL_SYM(ext,rc,fn,params,args,ret) openglfn_##fn##_t fn;
893     #include "SDL20_syms.h"
894 } OpenGLEntryPoints;
895 
896 
897 /* !!! FIXME: grep for VideoWindow20 places that might care if it's NULL */
898 /* !!! FIXME: go through all of these. */
899 static Uint32 LinkedSDL2VersionInt = 0;
900 static SDL_bool IsDummyVideo = SDL_FALSE;
901 static VideoModeList *VideoModes = NULL;
902 static int VideoModesCount = 0;  /* this counts items in VideoModeList, not total video modes. */
903 static SDL12_VideoInfo VideoInfo12;
904 static SDL12_Palette VideoInfoPalette12;
905 static SDL12_PixelFormat VideoInfoVfmt12;
906 static SDL_PixelFormat *VideoInfoVfmt20 = NULL;
907 static SDL_bool VideoWindowGrabbed = SDL_FALSE;
908 static SDL_bool VideoCursorHidden = SDL_FALSE;
909 static SDL_Window *VideoWindow20 = NULL;
910 static SDL_Renderer *VideoRenderer20 = NULL;
911 static SDL_Texture *VideoTexture20 = NULL;
912 static SDL12_Surface *VideoSurface12 = NULL;
913 static SDL_Palette *VideoPhysicalPalette20 = NULL;
914 static Uint32 VideoSurfacePresentTicks = 0;
915 static Uint32 VideoSurfaceLastPresentTicks = 0;
916 static SDL_Surface *VideoConvertSurface20 = NULL;
917 static SDL_GLContext VideoGLContext20 = NULL;
918 static SDL12_Overlay *QueuedDisplayOverlay12 = NULL;
919 static SDL12_Rect QueuedDisplayOverlayDstRect12;
920 static char *WindowTitle = NULL;
921 static char *WindowIconTitle = NULL;
922 static SDL_Surface *VideoIcon20 = NULL;
923 static int EnabledUnicode = 0;
924 static SDL_bool EnabledKeyRepeat = SDL_TRUE;
925 /* Windows SDL1.2 never uses translated keyboard layouts for compatibility with
926 DirectInput, which didn't support them. Other platforms (MacOS, Linux) seem to,
927 but with varying levels of bugginess. So default to Translated Layouts on
928 all non-Windows platforms (but have an option to change this, as many apps are
929 buggy with non-US layouts, or provide their own keyboard layout translation,
930 such as DOSBox. */
931 #if !defined(_WIN32)
932 static SDL_bool TranslateKeyboardLayout = SDL_TRUE;
933 #else
934 static SDL_bool TranslateKeyboardLayout = SDL_FALSE;
935 #endif
936 static int VideoDisplayIndex = 0;
937 static SDL_bool SupportSysWM = SDL_FALSE;
938 static SDL_bool CDRomInit = SDL_FALSE;
939 static char *CDRomPath = NULL;
940 static SDL12_CD *CDRomDevice = NULL;
941 static SDL12_EventFilter EventFilter12 = NULL;
942 static SDL12_Cursor *CurrentCursor12 = NULL;
943 static Uint8 EventStates[SDL12_NUMEVENTS];
944 static int SwapInterval = 0;
945 static JoystickOpenedItem JoystickOpenList[16];
946 static Uint8 KeyState[SDLK12_LAST];
947 static SDL_bool MouseInputIsRelative = SDL_FALSE;
948 static SDL_Point MousePosition = { 0, 0 };
949 static struct { /* SDL_FPoint */
950     float x, y;
951 } MouseRelativeRemainder = { 0.f, 0.f };
952 static SDL_bool UseMouseRelativeScaling = SDL_FALSE;
953 static OpenGLEntryPoints OpenGLFuncs;
954 static int OpenGLBlitLockCount = 0;
955 static GLuint OpenGLBlitTexture = 0;
956 static int OpenGLLogicalScalingWidth = 0;
957 static int OpenGLLogicalScalingHeight = 0;
958 static GLuint OpenGLLogicalScalingFBO = 0;
959 static GLuint OpenGLLogicalScalingColor = 0;
960 static GLuint OpenGLLogicalScalingDepth = 0;
961 static int OpenGLLogicalScalingSamples = 0;
962 static GLuint OpenGLLogicalScalingMultisampleFBO = 0;
963 static GLuint OpenGLLogicalScalingMultisampleColor = 0;
964 static GLuint OpenGLLogicalScalingMultisampleDepth = 0;
965 static GLuint OpenGLCurrentReadFBO = 0;
966 static GLuint OpenGLCurrentDrawFBO = 0;
967 
968 /* !!! FIXME: need a mutex for the event queue. */
969 #define SDL12_MAXEVENTS 128
970 typedef struct EventQueueType
971 {
972     SDL12_SysWMmsg syswm_msg;  /* save space for a copy of this in case we use it. */
973     SDL12_Event event12;
974     struct EventQueueType *next;
975 } EventQueueType;
976 
977 static EventQueueType EventQueuePool[SDL12_MAXEVENTS];
978 static EventQueueType *EventQueueHead = NULL;
979 static EventQueueType *EventQueueTail = NULL;
980 static EventQueueType *EventQueueAvailable = NULL;
981 
982 /* This is a KEYDOWN event which is being held for a follow-up TEXTINPUT */
983 static SDL12_Event PendingKeydownEvent;
984 
985 /* SDL_atoi() before SDL2-2.0.17 is non-compliant */
986 static SDL_INLINE int SDLCALL
SDL20_atoi(const char * str)987 SDL20_atoi(const char *str)
988 {
989     return SDL20_strtol(str, NULL, 10);
990 }
991 
992 /* Obviously we can't use SDL_LoadObject() to load SDL2.  :)  */
993 static char loaderror[256];
994 #if defined(_WIN32)
995     #define DIRSEP "\\"
996     #define SDL20_LIBNAME "SDL2.dll"
997     /* require SDL2 >= 2.0.12 for SDL_CreateThread binary compatibility */
998     #define SDL20_REQUIRED_VER SDL_VERSIONNUM(2,0,12)
999     static HMODULE Loaded_SDL20 = NULL;
1000     #define LoadSDL20Library() ((Loaded_SDL20 = LoadLibraryA(SDL20_LIBNAME)) != NULL)
1001     #define LookupSDL20Sym(sym) (void *)GetProcAddress(Loaded_SDL20, sym)
1002     #define CloseSDL20Library() { if (Loaded_SDL20) { FreeLibrary(Loaded_SDL20); Loaded_SDL20 = NULL; } }
1003     #define strcpy_fn  lstrcpyA
1004     #define sprintf_fn wsprintfA
1005 #elif defined(__OS2__)
1006     #include <os2.h>
1007     #define DIRSEP "\\"
1008     #define SDL20_LIBNAME "SDL2.dll"
1009     #define SDL20_REQUIRED_VER SDL_VERSIONNUM(2,0,7)
1010     #define strcpy_fn  strcpy
1011     #define sprintf_fn sprintf
1012     static HMODULE Loaded_SDL20 = NULLHANDLE;
LoadSDL20Library(void)1013     static SDL_bool LoadSDL20Library(void) {
1014         char err[256];
1015         if (DosLoadModule(err, sizeof(err), SDL20_LIBNAME, &Loaded_SDL20) != 0) {
1016             return SDL_FALSE;
1017         }
1018         return SDL_TRUE;
1019     }
LookupSDL20Sym(const char * symname)1020     static void *LookupSDL20Sym (const char *symname) {
1021         PFN fp;
1022         if (DosQueryProcAddr(Loaded_SDL20, 0, symname, &fp) != 0) return NULL;
1023         return (void *)fp;
1024     }
CloseSDL20Library(void)1025     static void CloseSDL20Library(void) {
1026         if (Loaded_SDL20 != NULLHANDLE) {
1027             DosFreeModule(Loaded_SDL20);
1028             Loaded_SDL20 = NULLHANDLE;
1029         }
1030     }
1031 #elif defined(__APPLE__)
1032     #include <dlfcn.h>
1033     #include <pwd.h>
1034     #include <unistd.h>
1035     #define SDL20_LIBNAME "libSDL2-2.0.0.dylib"
1036     #define SDL20_FRAMEWORK "SDL2.framework/Versions/A/SDL2"
1037     #define SDL20_REQUIRED_VER SDL_VERSIONNUM(2,0,7)
1038     #define strcpy_fn  strcpy
1039     #define sprintf_fn sprintf
1040     static void *Loaded_SDL20 = NULL;
1041     #define LookupSDL20Sym(sym) dlsym(Loaded_SDL20, sym)
1042     #define CloseSDL20Library() { if (Loaded_SDL20) { dlclose(Loaded_SDL20); Loaded_SDL20 = NULL; } }
LoadSDL20Library(void)1043     static SDL_bool LoadSDL20Library(void) {
1044         /* I don't know if this is the _right_ order to try, but this seems reasonable */
1045         static const char * const dylib_locations[] = {
1046             "@loader_path/" SDL20_LIBNAME, /* MyApp.app/Contents/MacOS/libSDL2-2.0.0.dylib */
1047             "@loader_path/../Frameworks/" SDL20_FRAMEWORK, /* MyApp.app/Contents/Frameworks/SDL2.framework */
1048             "@executable_path/" SDL20_LIBNAME, /* MyApp.app/Contents/MacOS/libSDL2-2.0.0.dylib */
1049             "@executable_path/../Frameworks/" SDL20_FRAMEWORK, /* MyApp.app/Contents/Frameworks/SDL2.framework */
1050             NULL,  /* /Users/username/Library/Frameworks/SDL2.framework */
1051             "/Library/Frameworks" SDL20_FRAMEWORK, /* /Library/Frameworks/SDL2.framework */
1052             SDL20_LIBNAME  /* oh well, anywhere the system can see the .dylib (/usr/local/lib or whatever) */
1053         };
1054 
1055         int i;
1056         for (i = 0; i < SDL_arraysize(dylib_locations); i++) {
1057             const char *location = dylib_locations[i];
1058             if (location) {
1059                 Loaded_SDL20 = dlopen(location, RTLD_LOCAL|RTLD_NOW);
1060             } else { /* hack to mean "try homedir" */
1061                 const char *homedir = NULL;
1062                 struct passwd *pwent = getpwuid(getuid());
1063                 if (pwent) {
1064                     homedir = pwent->pw_dir;
1065                 }
1066                 if (!homedir) {
1067                     homedir = getenv("HOME");
1068                 }
1069                 if (homedir) {
1070                     char framework[512];
1071                     const int rc = snprintf(framework, sizeof (framework), "%s/Library/Frameworks/" SDL20_FRAMEWORK, homedir);
1072                     if ((rc > 0) && (rc < sizeof (framework))) {
1073                         Loaded_SDL20 = dlopen(framework, RTLD_LOCAL|RTLD_NOW);
1074                     }
1075                 }
1076             }
1077 
1078             if (Loaded_SDL20) {
1079                 return SDL_TRUE;
1080             }
1081         }
1082 
1083         return SDL_FALSE; /* didn't find it anywhere reasonable. :( */
1084     }
1085 #elif defined(__unix__)
1086     #include <dlfcn.h>
1087     #define SDL20_LIBNAME "libSDL2-2.0.so.0"
1088     #define SDL20_REQUIRED_VER SDL_VERSIONNUM(2,0,7)
1089     static void *Loaded_SDL20 = NULL;
1090     #define LoadSDL20Library() ((Loaded_SDL20 = dlopen(SDL20_LIBNAME, RTLD_LOCAL|RTLD_NOW)) != NULL)
1091     #define LookupSDL20Sym(sym) dlsym(Loaded_SDL20, sym)
1092     #define CloseSDL20Library() { if (Loaded_SDL20) { dlclose(Loaded_SDL20); Loaded_SDL20 = NULL; } }
1093     #define strcpy_fn  strcpy
1094     #define sprintf_fn sprintf
1095 #else
1096     #error Please define your platform.
1097 #endif
1098 
1099 #ifndef DIRSEP
1100 #define DIRSEP "/"
1101 #endif
1102 
1103 static void *
LoadSDL20Symbol(const char * fn,int * okay)1104 LoadSDL20Symbol(const char *fn, int *okay)
1105 {
1106     void *retval = NULL;
1107     if (*okay) { /* only bother trying if we haven't previously failed. */
1108         retval = LookupSDL20Sym(fn);
1109         if (retval == NULL) {
1110             sprintf_fn(loaderror, "%s missing in SDL2 library.", fn);
1111             *okay = 0;
1112         }
1113     }
1114     return retval;
1115 }
1116 
1117 static void
UnloadSDL20(void)1118 UnloadSDL20(void)
1119 {
1120     #define SDL20_SYM(rc,fn,params,args,ret) SDL20_##fn = NULL;
1121     #include "SDL20_syms.h"
1122     CloseSDL20Library();
1123 }
1124 
1125 static int
LoadSDL20(void)1126 LoadSDL20(void)
1127 {
1128     int okay = 1;
1129     if (!Loaded_SDL20) {
1130         okay = LoadSDL20Library();
1131         if (!okay) {
1132             strcpy_fn(loaderror, "Failed loading SDL2 library.");
1133         } else {
1134             #define SDL20_SYM(rc,fn,params,args,ret) SDL20_##fn = (SDL20_##fn##_t) LoadSDL20Symbol("SDL_" #fn, &okay);
1135             #include "SDL20_syms.h"
1136             if (okay) {
1137                 SDL_version v;
1138                 SDL20_GetVersion(&v);
1139                 LinkedSDL2VersionInt = SDL_VERSIONNUM(v.major, v.minor, v.patch);
1140                 okay = (LinkedSDL2VersionInt >= SDL20_REQUIRED_VER);
1141                 if (!okay) {
1142                     sprintf_fn(loaderror, "SDL2 %d.%d.%d library is too old.", v.major, v.minor, v.patch);
1143                 } else {
1144                     const char *envr = SDL20_getenv("SDL12COMPAT_DEBUG_LOGGING");
1145                     const SDL_bool debug_logging = (!envr || (SDL20_atoi(envr) == 0)) ? SDL_FALSE : SDL_TRUE;
1146                     #if ENABLE_FIXMES == 1
1147                     PrintFixmes = debug_logging;
1148                     #endif
1149                     if (debug_logging) {
1150                         #if defined(__DATE__) && defined(__TIME__)
1151                         SDL20_Log("sdl12-compat, built on " __DATE__ " at " __TIME__ ", talking to SDL2 %d.%d.%d", v.major, v.minor, v.patch);
1152                         #else
1153                         SDL20_Log("sdl12-compat, talking to SDL2 %d.%d.%d", v.major, v.minor, v.patch);
1154                         #endif
1155                     }
1156                 }
1157             }
1158             if (!okay) {
1159                 UnloadSDL20();
1160             }
1161         }
1162     }
1163     return okay;
1164 }
1165 
1166 #if defined(_WIN32)
error_dialog(const char * errorMsg)1167 static void error_dialog(const char *errorMsg)
1168 {
1169     MessageBoxA(NULL, errorMsg, "Error", MB_OK | MB_SETFOREGROUND | MB_ICONSTOP);
1170 }
1171 #elif defined(__APPLE__)
1172 extern void error_dialog(const char *errorMsg);
1173 #else
error_dialog(const char * errorMsg)1174 static void error_dialog(const char *errorMsg)
1175 {
1176     fprintf(stderr, "%s\n", errorMsg);
1177 }
1178 #endif
1179 
1180 #if defined(__GNUC__) && !defined(_WIN32)
1181 static void dllinit(void) __attribute__((constructor));
dllinit(void)1182 static void dllinit(void)
1183 {
1184     if (!LoadSDL20()) {
1185         error_dialog(loaderror);
1186         abort();
1187     }
1188 }
1189 static void dllquit(void) __attribute__((destructor));
dllquit(void)1190 static void dllquit(void)
1191 {
1192     UnloadSDL20();
1193 }
1194 
1195 #elif defined(_WIN32) && (defined(_MSC_VER) || defined(__MINGW32__) || defined(__WATCOMC__))
1196 #if defined(_MSC_VER) && !defined(__FLTUSED__)
1197 #define __FLTUSED__
1198 __declspec(selectany) int _fltused = 1;
1199 #endif
1200 #if defined(__MINGW32__)
1201 #define _DllMainCRTStartup DllMainCRTStartup
1202 #endif
1203 #if defined(__WATCOMC__)
1204 #define _DllMainCRTStartup LibMain
1205 #endif
_DllMainCRTStartup(HANDLE dllhandle,DWORD reason,LPVOID reserved)1206 BOOL WINAPI _DllMainCRTStartup(HANDLE dllhandle, DWORD reason, LPVOID reserved)
1207 {
1208     (void) dllhandle;
1209     (void) reserved;
1210     switch (reason) {
1211     case DLL_PROCESS_DETACH:
1212         UnloadSDL20();
1213         break;
1214 
1215     case DLL_PROCESS_ATTACH: /* init once for each new process */
1216         if (!LoadSDL20()) {
1217             error_dialog(loaderror);
1218             #if 0
1219             TerminateProcess(GetCurrentProcess(), 42);
1220             ExitProcess(42);
1221             #endif
1222             return FALSE;
1223         }
1224         break;
1225 
1226     case DLL_THREAD_ATTACH: /* thread-specific init. */
1227     case DLL_THREAD_DETACH: /* thread-specific cleanup */
1228         break;
1229     }
1230     return TRUE;
1231 }
1232 
1233 #elif defined(__WATCOMC__) && defined(__OS2__)
LibMain(unsigned hmod,unsigned termination)1234 unsigned _System LibMain(unsigned hmod, unsigned termination)
1235 {
1236     (void)hmod;
1237     if (termination) {
1238         UnloadSDL20();
1239     } else if (!LoadSDL20()) {
1240         error_dialog(loaderror);
1241         return 0;
1242     }
1243     return 1;
1244 }
1245 
1246 #else
1247     #error Please define an init procedure for your platform.
1248 #endif
1249 
1250 #ifdef _WIN32
1251 /* SDL_main functions:
1252  * SDL2 doesn't define SDL_MAIN_NEEDED for _WIN32,
1253  * therefore no need to call SDL_SetMainReady().
1254  */
1255 DECLSPEC void SDLCALL
SDL_SetModuleHandle(void * handle)1256 SDL_SetModuleHandle(void *handle)
1257 {
1258     (void) handle;/* handled internally by SDL2 - nothing to do.. */
1259 }
1260 #endif
1261 
1262 
1263 DECLSPEC const SDL_version * SDLCALL
SDL_Linked_Version(void)1264 SDL_Linked_Version(void)
1265 {
1266     static const SDL_version version = { 1, 2, SDL12_COMPAT_VERSION };
1267     return &version;
1268 }
1269 
1270 DECLSPEC int SDLCALL
SDL_sscanf(const char * text,const char * fmt,...)1271 SDL_sscanf(const char *text, const char *fmt, ...)
1272 {
1273     int retval;
1274     va_list ap;
1275     va_start(ap, fmt);
1276     retval = (int) SDL20_vsscanf(text, fmt, ap);
1277     va_end(ap);
1278     return retval;
1279 }
1280 
1281 DECLSPEC int SDLCALL
SDL_snprintf(char * text,size_t maxlen,const char * fmt,...)1282 SDL_snprintf(char *text, size_t maxlen, const char *fmt, ...)
1283 {
1284     int retval;
1285     va_list ap;
1286     va_start(ap, fmt);
1287     retval = (int) SDL20_vsnprintf(text, maxlen, fmt, ap);
1288     va_end(ap);
1289     return retval;
1290 }
1291 
1292 DECLSPEC void * SDLCALL
SDL_revcpy(void * _dst,const void * _src,size_t len)1293 SDL_revcpy(void *_dst, const void *_src, size_t len)
1294 {
1295     if (len > 0) {
1296         Uint8 *dst = (((Uint8 *) _dst) + len) - 1;
1297         const Uint8 *src = (((const Uint8 *) _src) + len) - 1;
1298         size_t i;
1299         for (i = 0; i < len; i++, src--, dst--) {
1300             *dst = *src;
1301         }
1302     }
1303     return _dst;
1304 }
1305 
1306 
1307 /* SDL2 doesn't have MMXExt / 3dNowExt. */
1308 #if defined(__GNUC__) && defined(__i386__)
1309 #define cpuid(func, a, b, c, d) \
1310     __asm__ __volatile__ ( \
1311 "        pushl %%ebx        \n" \
1312 "        xorl %%ecx,%%ecx   \n" \
1313 "        cpuid              \n" \
1314 "        movl %%ebx, %%esi  \n" \
1315 "        popl %%ebx         \n" : \
1316             "=a" (a), "=S" (b), "=c" (c), "=d" (d) : "a" (func))
1317 #elif defined(__GNUC__) && defined(__x86_64__)
1318 #define cpuid(func, a, b, c, d) \
1319     __asm__ __volatile__ ( \
1320 "        pushq %%rbx        \n" \
1321 "        xorq %%rcx,%%rcx   \n" \
1322 "        cpuid              \n" \
1323 "        movq %%rbx, %%rsi  \n" \
1324 "        popq %%rbx         \n" : \
1325             "=a" (a), "=S" (b), "=c" (c), "=d" (d) : "a" (func))
1326 #elif (defined(_MSC_VER) && defined(_M_IX86)) || defined(__WATCOMC__)
1327 #define cpuid(func, a, b, c, d) \
1328     __asm { \
1329         __asm mov eax, func \
1330         __asm xor ecx, ecx \
1331         __asm cpuid \
1332         __asm mov a, eax \
1333         __asm mov b, ebx \
1334         __asm mov c, ecx \
1335         __asm mov d, edx \
1336 }
1337 #elif defined(_MSC_VER) && defined(_M_X64)
1338 #include <intrin.h>
1339 #define cpuid(func, a, b, c, d) \
1340 { \
1341     int CPUInfo[4]; \
1342     __cpuid(CPUInfo, func); \
1343     a = CPUInfo[0]; \
1344     b = CPUInfo[1]; \
1345     c = CPUInfo[2]; \
1346     d = CPUInfo[3]; \
1347 }
1348 #else
1349 #define cpuid(func, a, b, c, d) \
1350     do { a = b = c = d = 0; (void) a; (void) b; (void) c; (void) d; } while (0)
1351 #endif
1352 
1353 static int cpu_ext_features = -1;
get_cpu_ext_features(void)1354 static int get_cpu_ext_features(void) {
1355     if (cpu_ext_features < 0) {
1356         cpu_ext_features = 0;
1357         if (SDL20_HasMMX()) {
1358             int a, b, c, d;
1359             cpuid(0x80000000, a, b, c, d);
1360             if (a >= 0x80000001) {
1361                 cpuid(0x80000001, a, b, c, d);
1362                 cpu_ext_features = d;
1363             }
1364         }
1365     }
1366     return cpu_ext_features;
1367 }
1368 
1369 DECLSPEC SDL_bool SDLCALL
SDL_HasMMXExt(void)1370 SDL_HasMMXExt(void)
1371 {
1372     return (get_cpu_ext_features() & 0x00400000)? SDL_TRUE : SDL_FALSE;
1373 }
1374 
1375 DECLSPEC SDL_bool SDLCALL
SDL_Has3DNowExt(void)1376 SDL_Has3DNowExt(void)
1377 {
1378     return (get_cpu_ext_features() & 0x40000000)? SDL_TRUE : SDL_FALSE;
1379 }
1380 
1381 DECLSPEC SDL_Joystick * SDLCALL
SDL_JoystickOpen(int device_index)1382 SDL_JoystickOpen(int device_index)
1383 {
1384     size_t i;
1385     SDL20_LockJoysticks();
1386     for (i = 0; i < SDL_arraysize(JoystickOpenList); i++) {
1387         if (JoystickOpenList[i].joystick == NULL) {
1388             break;
1389         }
1390     }
1391 
1392     if (i == SDL_arraysize(JoystickOpenList)) {
1393         SDL20_UnlockJoysticks();
1394         SDL20_SetError("Too many open joysticks");
1395         return NULL;
1396     }
1397 
1398     JoystickOpenList[i].joystick = SDL20_JoystickOpen(device_index);
1399     if (JoystickOpenList[i].joystick) {
1400         JoystickOpenList[i].device_index = device_index;
1401     }
1402 
1403     SDL20_UnlockJoysticks();
1404     return JoystickOpenList[i].joystick;
1405 }
1406 
1407 DECLSPEC void SDLCALL
SDL_JoystickClose(SDL_Joystick * joystick)1408 SDL_JoystickClose(SDL_Joystick *joystick)
1409 {
1410     size_t i;
1411     SDL20_LockJoysticks();
1412     for (i = 0; i < SDL_arraysize(JoystickOpenList); i++) {
1413         if (JoystickOpenList[i].joystick == joystick) {
1414             break;
1415         }
1416     }
1417 
1418     if (i < SDL_arraysize(JoystickOpenList)) {
1419         JoystickOpenList[i].joystick = NULL;
1420     }
1421 
1422     SDL20_UnlockJoysticks();
1423 
1424     SDL20_JoystickClose(joystick);
1425 }
1426 
1427 DECLSPEC const char * SDLCALL
SDL_JoystickName(int device_index)1428 SDL_JoystickName(int device_index)
1429 {
1430     return SDL20_JoystickNameForIndex(device_index);
1431 }
1432 
1433 DECLSPEC int SDLCALL
SDL_JoystickIndex(SDL_Joystick * joystick)1434 SDL_JoystickIndex(SDL_Joystick *joystick)
1435 {
1436     size_t i;
1437     SDL20_LockJoysticks();
1438     for (i = 0; i < SDL_arraysize(JoystickOpenList); i++) {
1439         if (JoystickOpenList[i].joystick == joystick) {
1440             break;
1441         }
1442     }
1443 
1444     if (i < SDL_arraysize(JoystickOpenList)) {
1445         SDL20_UnlockJoysticks();
1446         return JoystickOpenList[i].device_index;
1447     }
1448 
1449     SDL20_UnlockJoysticks();
1450     return SDL20_SetError("Can't find joystick");
1451 }
1452 
1453 DECLSPEC int SDLCALL
SDL_JoystickOpened(int device_index)1454 SDL_JoystickOpened(int device_index)
1455 {
1456     int retval = 0;
1457     size_t i;
1458     SDL20_LockJoysticks();
1459     for (i = 0; i < SDL_arraysize(JoystickOpenList); i++) {
1460         if ((JoystickOpenList[i].joystick) && (JoystickOpenList[i].device_index == device_index)) {
1461             retval = 1;
1462             break;
1463         }
1464     }
1465     SDL20_UnlockJoysticks();
1466     return retval;
1467 }
1468 
1469 static SDL_PixelFormat *
PixelFormat12to20(SDL_PixelFormat * format20,SDL_Palette * palette20,const SDL12_PixelFormat * format12)1470 PixelFormat12to20(SDL_PixelFormat *format20, SDL_Palette *palette20, const SDL12_PixelFormat *format12)
1471 {
1472     if (format12->palette) {
1473         palette20->ncolors = format12->palette->ncolors;
1474         palette20->colors = format12->palette->colors;
1475         palette20->version = 1;
1476         palette20->refcount = 1;
1477         format20->palette = palette20;
1478     } else {
1479         format20->palette = NULL;
1480     }
1481 
1482     format20->format = SDL20_MasksToPixelFormatEnum(format12->BitsPerPixel, format12->Rmask, format12->Gmask, format12->Bmask, format12->Amask);
1483     format20->BitsPerPixel = format12->BitsPerPixel;
1484     format20->BytesPerPixel = format12->BytesPerPixel;
1485 
1486     /* Paletted surfaces shouldn't have masks in SDL 2.0 */
1487     if (format12->palette) {
1488         format20->Rmask = 0;
1489         format20->Gmask = 0;
1490         format20->Bmask = 0;
1491         format20->Amask = 0;
1492         format20->Rloss = 8;
1493         format20->Gloss = 8;
1494         format20->Bloss = 8;
1495         format20->Aloss = 8;
1496         format20->Rshift = 0;
1497         format20->Gshift = 0;
1498         format20->Bshift = 0;
1499         format20->Ashift = 0;
1500     } else {
1501         format20->Rmask = format12->Rmask;
1502         format20->Gmask = format12->Gmask;
1503         format20->Bmask = format12->Bmask;
1504         format20->Amask = format12->Amask;
1505         format20->Rloss = format12->Rloss;
1506         format20->Gloss = format12->Gloss;
1507         format20->Bloss = format12->Bloss;
1508         format20->Aloss = format12->Aloss;
1509         format20->Rshift = format12->Rshift;
1510         format20->Gshift = format12->Gshift;
1511         format20->Bshift = format12->Bshift;
1512         format20->Ashift = format12->Ashift;
1513     }
1514     format20->refcount = 1;
1515     format20->next = NULL;
1516     return format20;
1517 }
1518 
1519 static SDL12_PixelFormat *
PixelFormat20to12(SDL12_PixelFormat * format12,SDL12_Palette * palette12,const SDL_PixelFormat * format20)1520 PixelFormat20to12(SDL12_PixelFormat *format12, SDL12_Palette *palette12, const SDL_PixelFormat *format20)
1521 {
1522     if (format20->palette) {
1523         palette12->ncolors = format20->palette->ncolors;
1524         palette12->colors = format20->palette->colors;
1525         format12->palette = palette12;
1526     } else {
1527         format12->palette = NULL;
1528     }
1529 
1530     format12->BitsPerPixel = format20->BitsPerPixel;
1531     format12->BytesPerPixel = format20->BytesPerPixel;
1532     format12->Rloss = format20->Rloss;
1533     format12->Gloss = format20->Gloss;
1534     format12->Bloss = format20->Bloss;
1535     format12->Aloss = format20->Aloss;
1536     format12->Rshift = format20->Rshift;
1537     format12->Gshift = format20->Gshift;
1538     format12->Bshift = format20->Bshift;
1539     format12->Ashift = format20->Ashift;
1540     format12->Rmask = format20->Rmask;
1541     format12->Gmask = format20->Gmask;
1542     format12->Bmask = format20->Bmask;
1543     format12->Amask = format20->Amask;
1544     format12->colorkey = 0; /* this is a surface, not pixelformat, properties in SDL2. */
1545     format12->alpha = 255;  /* this is a surface, not pixelformat, properties in SDL2. */
1546     return format12;
1547 }
1548 
1549 static int
GetVideoDisplay(void)1550 GetVideoDisplay(void)
1551 {
1552     const char *variable;
1553     variable = SDL20_getenv("SDL_VIDEO_FULLSCREEN_DISPLAY");
1554     if (!variable) {
1555         variable = SDL20_getenv("SDL_VIDEO_FULLSCREEN_HEAD");
1556     }
1557     if (variable) {
1558         int preferred_display = SDL20_atoi(variable);
1559 
1560         if (preferred_display < 0 || preferred_display >= SDL20_GetNumVideoDisplays()) {
1561             return 0;
1562         }
1563 
1564         return SDL20_atoi(variable);
1565     } else {
1566         return 0;
1567     }
1568 }
1569 
1570 /* returns true if mode1 should sort before mode2 */
1571 static int
VidModeSizeGreater(SDL12_Rect * mode1,SDL12_Rect * mode2)1572 VidModeSizeGreater(SDL12_Rect *mode1, SDL12_Rect *mode2)
1573 {
1574     if (mode1->w > mode2->w) {
1575         return 1;
1576     } else if (mode2->w > mode1->w) {
1577         return 0;
1578     } else {
1579         return (mode1->h > mode2->h);
1580     }
1581 }
1582 
1583 static int
AddVidModeToList(VideoModeList * vmode,SDL12_Rect * mode)1584 AddVidModeToList(VideoModeList *vmode, SDL12_Rect *mode)
1585 {
1586     void *ptr = NULL;
1587     int i;
1588 
1589     /* make sure we don't have this one already (with a different refresh rate, etc). */
1590     for (i = 0; i < vmode->nummodes; i++) {
1591         if ((vmode->modeslist12[i].w == mode->w) && (vmode->modeslist12[i].h == mode->h)) {
1592             break;
1593         }
1594     }
1595 
1596     if (i < vmode->nummodes) {
1597         return 0;  /* already have this one. */
1598     }
1599 
1600     ptr = SDL20_realloc(vmode->modeslist12, sizeof (SDL12_Rect) * (vmode->nummodes + 1));
1601     if (ptr == NULL) {
1602         return SDL20_OutOfMemory();
1603     }
1604     vmode->modeslist12 = (SDL12_Rect *) ptr;
1605 
1606     vmode->modeslist12[vmode->nummodes] = *mode;
1607 
1608     vmode->nummodes++;
1609 
1610     return 0;
1611 }
1612 
1613 /* A list of fake video modes which are included. */
1614 static SDL12_Rect fake_modes[] = {
1615     { 0, 0, 1920, 1080 },
1616     { 0, 0, 1280, 720 },
1617     { 0, 0, 1024, 768 },
1618     { 0, 0, 800, 600 },
1619     { 0, 0, 640, 480 }
1620 };
1621 
1622 /* This sets up VideoModes and VideoModesCount. You end up with arrays by pixel
1623     format, each with a value that 1.2's SDL_ListModes() can return. */
1624 static int
Init12VidModes(void)1625 Init12VidModes(void)
1626 {
1627     const int total = SDL20_GetNumDisplayModes(VideoDisplayIndex);
1628     VideoModeList *vmode = NULL;
1629     void *ptr = NULL;
1630     int i, j;
1631     SDL12_Rect prev_mode = { 0, 0, 0, 0 }, current_mode = { 0, 0, 0, 0 };
1632     /* We only want to enable fake modes if OpenGL Logical Scaling is enabled. */
1633     const char *env = SDL20_getenv("SDL12COMPAT_OPENGL_SCALING");
1634     SDL_bool use_fake_modes = (!env || SDL20_atoi(env)) ? SDL_TRUE : SDL_FALSE;
1635 
1636     if (VideoModesCount > 0) {
1637         return 0;  /* already did this. */
1638     }
1639 
1640     SDL_assert(VideoModes == NULL);
1641 
1642     for (i = 0; i < total; ++i) {
1643         SDL_DisplayMode mode;
1644 
1645         if (SDL20_GetDisplayMode(VideoDisplayIndex, i, &mode) < 0) {
1646             continue;
1647         }
1648 
1649         if ((mode.w == 0) && (mode.h == 0)) {
1650             /* SDL2 has a bug in its dummy driver before 2.0.16 that causes it to report a bogus video mode. */
1651             if (IsDummyVideo && (LinkedSDL2VersionInt <= SDL_VERSIONNUM(2, 0, 15))) {
1652                 mode.w = 1024;
1653                 mode.h = 768;
1654                 mode.format = SDL_PIXELFORMAT_RGB888;
1655             }
1656         }
1657 
1658         if ((mode.w <= 0) || (mode.h <= 0)) {
1659             continue;  /* bogus mode for whatever reason, ignore it. */
1660         }
1661 
1662         if (mode.w > 65535 || mode.h > 65535) {
1663             continue;  /* can't fit to 16-bits for SDL12_Rect */
1664         }
1665 
1666         if (!vmode || (mode.format != vmode->format)) {  /* SDL20_GetDisplayMode() sorts on bpp first. We know when to change arrays. */
1667             ptr = (VideoModeList *) SDL20_realloc(VideoModes, sizeof (VideoModeList) * (VideoModesCount+1));
1668             if (!ptr) {
1669                 return SDL20_OutOfMemory();
1670             }
1671             VideoModes = (VideoModeList *) ptr;
1672             vmode = &VideoModes[VideoModesCount];
1673             vmode->format = mode.format;
1674             vmode->nummodes = 0;
1675             vmode->modeslist12 = NULL;
1676             vmode->modes12 = NULL;
1677             VideoModesCount++;
1678         }
1679 
1680         current_mode.w = mode.w;
1681         current_mode.h = mode.h;
1682 
1683         /* Attempt to add all of the fake modes. */
1684         if (use_fake_modes) {
1685             for (j = 0; j < SDL_arraysize(fake_modes); ++j) {
1686                 if (VidModeSizeGreater(&prev_mode, &fake_modes[j]) && VidModeSizeGreater(&fake_modes[j], &current_mode)) {
1687                     if (AddVidModeToList(vmode, &fake_modes[j])) {
1688                         return SDL20_OutOfMemory();
1689                     }
1690                 }
1691             }
1692         }
1693 
1694         if (AddVidModeToList(vmode, &current_mode)) {
1695             return SDL20_OutOfMemory();
1696         }
1697 
1698         prev_mode.w = mode.w;
1699         prev_mode.h = mode.h;
1700     }
1701 
1702     /* we need to try to add fake modes to the end of the list once there are no more real modes */
1703     if (use_fake_modes) {
1704         for (i = 0; i < SDL_arraysize(fake_modes); ++i) {
1705             if (VidModeSizeGreater(&prev_mode, &fake_modes[i])) {
1706                 if (AddVidModeToList(vmode, &fake_modes[i])) {
1707                     return SDL20_OutOfMemory();
1708                 }
1709             }
1710         }
1711     }
1712 
1713     /* link up modes12 for SDL_ListModes()'s use... */
1714     for (i = 0, vmode = VideoModes; i < VideoModesCount; i++, vmode++) {
1715         const int nummodes = vmode->nummodes;
1716         vmode->modes12 = (SDL12_Rect **) SDL20_calloc(sizeof (SDL12_Rect *), nummodes + 1);
1717         if (vmode->modes12 == NULL) {
1718             return SDL20_OutOfMemory();
1719         }
1720         for (j = 0; j < nummodes; j++) {
1721             vmode->modes12[j] = &vmode->modeslist12[j];
1722         }
1723     }
1724 
1725     return 0;
1726 }
1727 
1728 /* we should have a default cursor */
1729 #include "default_cursor.h"
1730 DECLSPEC void SDLCALL SDL_FreeCursor(SDL12_Cursor *);
1731 
1732 static int
Init12Video(void)1733 Init12Video(void)
1734 {
1735     const char *driver = SDL20_GetCurrentVideoDriver();
1736     const char *layout_env = SDL20_getenv("SDL12COMPAT_USE_KEYBOARD_LAYOUT");
1737     SDL_DisplayMode mode;
1738     int i;
1739 
1740     /* Only override this if the env var is set, as the default is platform-specific. */
1741     if (layout_env) {
1742         TranslateKeyboardLayout = SDL20_atoi(layout_env) ? SDL_TRUE : SDL_FALSE;
1743     }
1744 
1745     IsDummyVideo = ((driver != NULL) && (SDL20_strcmp(driver, "dummy") == 0)) ? SDL_TRUE : SDL_FALSE;
1746 
1747     for (i = 0; i < SDL12_MAXEVENTS-1; i++)
1748         EventQueuePool[i].next = &EventQueuePool[i+1];
1749     EventQueuePool[SDL12_MAXEVENTS-1].next = NULL;
1750 
1751     EventQueueHead = EventQueueTail = NULL;
1752     EventQueueAvailable = EventQueuePool;
1753 
1754     SDL20_memset(&PendingKeydownEvent, 0, sizeof(SDL12_Event));
1755 
1756     SDL20_memset(EventStates, SDL_ENABLE, sizeof (EventStates)); /* on by default */
1757 
1758     EventStates[SDL12_SYSWMEVENT] = SDL_IGNORE;  /* off by default. */
1759     SDL20_EventState(SDL_SYSWMEVENT, SDL_IGNORE);
1760 
1761 #if defined(SDL_VIDEO_DRIVER_WINDOWS)
1762     SupportSysWM = (SDL20_strcmp(driver, "windows") == 0) ? SDL_TRUE : SDL_FALSE;
1763 #elif defined(SDL_VIDEO_DRIVER_X11)
1764     SupportSysWM = (SDL20_strcmp(driver, "x11") == 0) ? SDL_TRUE : SDL_FALSE;
1765 #else
1766     SupportSysWM = SDL_FALSE;
1767 #endif
1768 
1769     SDL20_DelEventWatch(EventFilter20to12, NULL);
1770     SDL20_AddEventWatch(EventFilter20to12, NULL);
1771 
1772     VideoDisplayIndex = GetVideoDisplay();
1773     SwapInterval = 0;
1774 
1775     VideoWindowGrabbed = SDL_FALSE;
1776     VideoCursorHidden = SDL_FALSE;
1777     SDL20_ShowCursor(1);
1778 
1779     if (Init12VidModes() < 0) {
1780         return -1;
1781     }
1782 
1783     SDL20_StopTextInput();
1784 
1785     if (SDL20_GetDesktopDisplayMode(VideoDisplayIndex, &mode) == 0) {
1786         VideoInfoVfmt20 = SDL20_AllocFormat(mode.format);
1787         VideoInfo12.vfmt = PixelFormat20to12(&VideoInfoVfmt12, &VideoInfoPalette12, VideoInfoVfmt20);
1788         VideoInfo12.current_w = mode.w;
1789         VideoInfo12.current_h = mode.h;
1790         VideoInfo12.wm_available = 1;  /* FIXME ? */
1791         VideoInfo12.video_mem = 1024 * 256;  /* good enough. */
1792     }
1793 
1794     return 0;
1795 }
1796 
1797 DECLSPEC int SDLCALL
SDL_VideoInit(const char * driver,Uint32 flags)1798 SDL_VideoInit(const char *driver, Uint32 flags)
1799 {
1800     int retval;
1801 
1802     (void) flags;  /* unused. */
1803 
1804     retval = SDL20_VideoInit(driver);
1805     if (retval != -1) {
1806         retval = Init12Video();
1807         if (retval == -1) {
1808             SDL20_VideoQuit();
1809         }
1810     }
1811     return retval;
1812 }
1813 
1814 
1815 static void InitializeCDSubsystem(void);
1816 static void QuitCDSubsystem(void);
1817 
1818 
1819 DECLSPEC int SDLCALL
SDL_InitSubSystem(Uint32 sdl12flags)1820 SDL_InitSubSystem(Uint32 sdl12flags)
1821 {
1822     Uint32 sdl20flags = 0;
1823     int rc;
1824 
1825 #ifdef __WINDOWS__
1826     /* DOSBox (and probably other things), try to force the "windib" video
1827        backend, but it doesn't exist in SDL2. Force to "windows" instead. */
1828     const char *origvidenv = NULL;
1829     const char *env = SDL20_getenv("SDL_VIDEODRIVER");
1830     if (env && (SDL20_strcmp(env, "windib") == 0)) {
1831         origvidenv = "windib";
1832         SDL20_setenv("SDL_VIDEODRIVER", "windows", 1);
1833     }
1834 #endif
1835 
1836 #ifdef __MACOSX__
1837     extern void sdl12_compat_macos_init(void);
1838     sdl12_compat_macos_init();
1839 #endif
1840 
1841     FIXME("support SDL_INIT_EVENTTHREAD where it makes sense?");
1842     #define SETFLAG(flag) if (sdl12flags & SDL12_INIT_##flag) sdl20flags |= SDL_INIT_##flag
1843     SETFLAG(TIMER);
1844     SETFLAG(AUDIO);
1845     SETFLAG(VIDEO);
1846     SETFLAG(JOYSTICK);
1847     SETFLAG(NOPARACHUTE);
1848     #undef SETFLAG
1849 
1850     /* There's no CDROM in 2.0, but we fake it. */
1851     if (sdl12flags & SDL12_INIT_CDROM) {
1852         /* this never reports failure, even if there's a legit problem. You just won't see any drives. */
1853         InitializeCDSubsystem();
1854     }
1855 
1856     rc = SDL20_Init(sdl20flags);
1857     if ((rc == 0) && (sdl20flags & SDL_INIT_VIDEO)) {
1858         if (Init12Video() < 0) {
1859             rc = -1;
1860         }
1861     }
1862 
1863 #ifdef __WINDOWS__
1864     if (origvidenv) {  /* set this back to minimize surprise state changes. */
1865         SDL20_setenv("SDL_VIDEODRIVER", origvidenv, 1);
1866     }
1867 #endif
1868 
1869     return rc;
1870 }
1871 
1872 DECLSPEC int SDLCALL
SDL_Init(Uint32 sdl12flags)1873 SDL_Init(Uint32 sdl12flags)
1874 {
1875     FIXME("there is never a parachute in SDL2, should we catch segfaults ourselves?");
1876     return SDL_InitSubSystem(sdl12flags);   /* there's no difference betwee Init and InitSubSystem in SDL2. */
1877 }
1878 
1879 
1880 static void
InitFlags12to20(const Uint32 flags12,Uint32 * _flags20,Uint32 * _extraflags)1881 InitFlags12to20(const Uint32 flags12, Uint32 *_flags20, Uint32 *_extraflags)
1882 {
1883     Uint32 flags20 = 0;
1884     Uint32 extraflags = 0;
1885 
1886     #define SETFLAG(flag) if (flags12 & SDL12_INIT_##flag) flags20 |= SDL_INIT_##flag
1887     SETFLAG(TIMER);
1888     SETFLAG(AUDIO);
1889     SETFLAG(VIDEO);
1890     SETFLAG(JOYSTICK);
1891     SETFLAG(NOPARACHUTE);
1892     #undef SETFLAG
1893 
1894     if ((flags12 & SDL12_INIT_CDROM) && (CDRomInit)) {
1895         extraflags |= SDL12_INIT_CDROM;
1896     }
1897 
1898     *_flags20 = flags20;
1899     *_extraflags = extraflags;
1900 }
1901 
1902 static Uint32
InitFlags20to12(const Uint32 flags20)1903 InitFlags20to12(const Uint32 flags20)
1904 {
1905     Uint32 flags12 = 0;
1906 
1907     #define SETFLAG(flag) if (flags20 & SDL_INIT_##flag) flags12 |= SDL12_INIT_##flag
1908     SETFLAG(TIMER);
1909     SETFLAG(AUDIO);
1910     SETFLAG(VIDEO);
1911     SETFLAG(JOYSTICK);
1912     SETFLAG(NOPARACHUTE);
1913     #undef SETFLAG
1914 
1915     return flags12;
1916 }
1917 
1918 
1919 DECLSPEC Uint32 SDLCALL
SDL_WasInit(Uint32 sdl12flags)1920 SDL_WasInit(Uint32 sdl12flags)
1921 {
1922     Uint32 sdl20flags, extraflags;
1923     InitFlags12to20(sdl12flags, &sdl20flags, &extraflags);
1924 
1925     return InitFlags20to12(SDL20_WasInit(sdl20flags)) | extraflags;
1926 }
1927 
1928 static SDL12_Surface *EndVidModeCreate(void);
1929 static void
Quit12Video(void)1930 Quit12Video(void)
1931 {
1932     int i;
1933 
1934     SDL20_FreeSurface(VideoIcon20);
1935     VideoIcon20 = NULL;
1936 
1937     EndVidModeCreate(); /* clean-up static data. */
1938 
1939     for (i = 0; i < VideoModesCount; i++) {
1940         SDL20_free(VideoModes[i].modeslist12);
1941         SDL20_free(VideoModes[i].modes12);
1942     }
1943     SDL20_free(VideoModes);
1944 
1945     SDL20_FreeFormat(VideoInfoVfmt20);
1946     SDL20_zero(VideoInfo12);
1947 
1948     VideoInfoVfmt20 = NULL;
1949     EventFilter12 = NULL;
1950     EventQueueAvailable = EventQueueHead = EventQueueTail = NULL;
1951     SDL_FreeCursor(CurrentCursor12);
1952     VideoModes = NULL;
1953     VideoModesCount = 0;
1954 }
1955 
1956 DECLSPEC void SDLCALL
SDL_QuitSubSystem(Uint32 sdl12flags)1957 SDL_QuitSubSystem(Uint32 sdl12flags)
1958 {
1959     Uint32 sdl20flags, extraflags;
1960     InitFlags12to20(sdl12flags, &sdl20flags, &extraflags);
1961 
1962     if (extraflags & SDL12_INIT_CDROM) {
1963         QuitCDSubsystem();
1964     }
1965 
1966     if (sdl12flags & SDL12_INIT_AUDIO) {
1967         SDL_CloseAudio();
1968     }
1969 
1970     if (sdl12flags & SDL12_INIT_VIDEO) {
1971         Quit12Video();
1972     }
1973 
1974     SDL20_QuitSubSystem(sdl20flags);
1975 
1976     if ((SDL20_WasInit(0) == 0) && (!CDRomInit)) {
1977         SDL20_Quit();
1978     }
1979 }
1980 
1981 DECLSPEC void SDLCALL
SDL_Quit(void)1982 SDL_Quit(void)
1983 {
1984     SDL_QuitSubSystem(SDL_WasInit(0) | SDL12_INIT_CDROM);
1985 }
1986 
1987 DECLSPEC void SDLCALL
SDL_Error(SDL_errorcode error)1988 SDL_Error(SDL_errorcode error)
1989 {
1990     SDL20_Error(error);
1991 }
1992 
1993 DECLSPEC void SDLCALL
SDL_SetError(const char * fmt,...)1994 SDL_SetError(const char *fmt, ...)
1995 {
1996     char ch;
1997     char *str = NULL;
1998     size_t len = 0;
1999     va_list ap;
2000 
2001     va_start(ap, fmt);
2002     len = SDL20_vsnprintf(&ch, 1, fmt, ap);
2003     va_end(ap);
2004 
2005     str = (char *) SDL20_malloc(len + 1);
2006     if (!str) {
2007         SDL20_OutOfMemory();
2008     } else {
2009         va_start(ap, fmt);
2010         SDL20_vsnprintf(str, len + 1, fmt, ap);
2011         va_end(ap);
2012         SDL20_SetError("%s", str);
2013         SDL20_free(str);
2014     }
2015 }
2016 
2017 DECLSPEC const char * SDLCALL
SDL_GetError(void)2018 SDL_GetError(void)
2019 {
2020     if (SDL20_GetError == NULL) {
2021         static const char noload_errstr[] = "SDL2 library isn't loaded.";
2022         return noload_errstr;
2023     }
2024     return SDL20_GetError();
2025 }
2026 
2027 
2028 static const char *
GetDriverName(const char * name,char * namebuf,int maxlen)2029 GetDriverName(const char *name, char *namebuf, int maxlen)
2030 {
2031     if (name) {
2032         if (namebuf) {
2033             SDL20_strlcpy(namebuf, name, maxlen);
2034             return namebuf;
2035         } else {
2036             return name;
2037         }
2038     }
2039     return NULL;
2040 }
2041 
2042 DECLSPEC const char * SDLCALL
SDL_AudioDriverName(char * namebuf,int maxlen)2043 SDL_AudioDriverName(char *namebuf, int maxlen)
2044 {
2045     return GetDriverName(SDL20_GetCurrentAudioDriver(), namebuf, maxlen);
2046 }
2047 
2048 DECLSPEC const char * SDLCALL
SDL_VideoDriverName(char * namebuf,int maxlen)2049 SDL_VideoDriverName(char *namebuf, int maxlen)
2050 {
2051     return GetDriverName(SDL20_GetCurrentVideoDriver(), namebuf, maxlen);
2052 }
2053 
2054 
2055 DECLSPEC int SDLCALL
SDL_PollEvent(SDL12_Event * event12)2056 SDL_PollEvent(SDL12_Event *event12)
2057 {
2058     EventQueueType *next;
2059 
2060     SDL_PumpEvents();  /* this will run our filter and build our 1.2 queue. */
2061 
2062     if (EventQueueHead == NULL) {
2063         return 0;  /* no events at the moment. */
2064     }
2065 
2066     if (event12 != NULL) {
2067         SDL20_memcpy(event12, &EventQueueHead->event12, sizeof (SDL12_Event));
2068         next = EventQueueHead->next;
2069         EventQueueHead->next = EventQueueAvailable;
2070         EventQueueAvailable = EventQueueHead;
2071         EventQueueHead = next;
2072         if (!next) {
2073             EventQueueTail = NULL;
2074         }
2075     }
2076 
2077     return 1;
2078 }
2079 
2080 DECLSPEC int SDLCALL
SDL_PushEvent(SDL12_Event * event12)2081 SDL_PushEvent(SDL12_Event *event12)
2082 {
2083     EventQueueType *item = EventQueueAvailable;
2084     if (item == NULL) {
2085         return -1;  /* no space available at the moment. */
2086     }
2087 
2088     EventQueueAvailable = item->next;
2089     if (EventQueueTail) {
2090         EventQueueTail->next = item;
2091         EventQueueTail = item;
2092     } else {
2093         EventQueueHead = EventQueueTail = item;
2094     }
2095     item->next = NULL;
2096 
2097     SDL20_memcpy(&item->event12, event12, sizeof (SDL12_Event));
2098 
2099     if (event12->type == SDL12_SYSWMEVENT) {  /* make a copy of the data here */
2100         SDL20_memcpy(&item->syswm_msg, event12->syswm.msg, sizeof (SDL12_SysWMmsg));
2101         item->event12.syswm.msg = &item->syswm_msg;
2102     }
2103 
2104     return 0;
2105 }
2106 
2107 DECLSPEC int SDLCALL
SDL_PeepEvents(SDL12_Event * events12,int numevents,SDL_eventaction action,Uint32 mask)2108 SDL_PeepEvents(SDL12_Event *events12, int numevents, SDL_eventaction action, Uint32 mask)
2109 {
2110     SDL12_Event dummy_event;
2111 
2112     if (action == SDL_ADDEVENT) {
2113         int i;
2114         for (i = 0; i < numevents; i++) {
2115             if (SDL_PushEvent(&events12[i]) < 0) {
2116                 break;  /* out of space for more events. */
2117             }
2118         }
2119         return i;
2120     }
2121 
2122     if (!events12) {
2123         action = SDL_PEEKEVENT;
2124         numevents = 1;
2125         events12 = &dummy_event;
2126     }
2127 
2128     if ((action == SDL_PEEKEVENT) || (action == SDL_GETEVENT)) {
2129         const SDL_bool is_get = (action == SDL_GETEVENT)? SDL_TRUE : SDL_FALSE;
2130         EventQueueType *prev = NULL;
2131         EventQueueType *item = EventQueueHead;
2132         EventQueueType *next = NULL;
2133         int chosen = 0;
2134         while (chosen < numevents) {
2135             EventQueueType *nextPrev = item;
2136             if (!item) {
2137                 break;  /* no more events at the moment. */
2138             }
2139 
2140             next = item->next;  /* copy, since we might overwrite item->next */
2141 
2142             if (mask & (1<<item->event12.type)) {
2143                 SDL20_memcpy(&events12[chosen++], &item->event12, sizeof (SDL12_Event));
2144                 if (is_get) { /* remove from list? */
2145                     if (prev != NULL) {
2146                         prev->next = next;
2147                     }
2148                     if (item == EventQueueHead) {
2149                         EventQueueHead = next;
2150                     }
2151                     if (item == EventQueueTail) {
2152                         EventQueueTail = prev;
2153                     }
2154 
2155                     /* put it back in the free pool. */
2156                     item->next = EventQueueAvailable;
2157                     EventQueueAvailable = item;
2158                     nextPrev = prev;  /* previous item doesn't change. */
2159                 }
2160             }
2161 
2162             item = next;
2163             prev = nextPrev;
2164         }
2165         return chosen;
2166     }
2167 
2168     return 0;
2169 }
2170 
2171 DECLSPEC int SDLCALL
SDL_WaitEvent(SDL12_Event * event12)2172 SDL_WaitEvent(SDL12_Event *event12)
2173 {
2174     FIXME("In 1.2, this only fails (-1) if you haven't SDL_Init()'d.");
2175     while (!SDL_PollEvent(event12)) {
2176         SDL20_Delay(10);
2177     }
2178     return 1;
2179 }
2180 
2181 static SDL_bool
PushEventIfNotFiltered(SDL12_Event * event12)2182 PushEventIfNotFiltered(SDL12_Event *event12)
2183 {
2184     if (event12->type != SDL12_NOEVENT) {
2185         if (EventStates[event12->type] != SDL_IGNORE) {
2186             if ((!EventFilter12) || (EventFilter12(event12))) {
2187                 return (SDL_PushEvent(event12) == 0)? SDL_TRUE : SDL_FALSE;
2188             }
2189         }
2190     }
2191     return SDL_FALSE;
2192 }
2193 
2194 DECLSPEC Uint8 SDLCALL
SDL_EventState(Uint8 type,int state)2195 SDL_EventState(Uint8 type, int state)
2196 {
2197     /* the values of "state" match between 1.2 and 2.0 */
2198     const Uint8 retval = EventStates[type];
2199     SDL12_Event e;
2200 
2201     if (state != SDL_QUERY) {
2202         EventStates[type] = state;
2203         if ((type == SDL12_SYSWMEVENT) && SupportSysWM) {  /* we only enable syswm in SDL2 if it makes sense. */
2204             SDL20_EventState(SDL_SYSWMEVENT, state);
2205         }
2206     }
2207     if (state == SDL_IGNORE) {  /* drop existing events of this type. */
2208         while (SDL_PeepEvents(&e, 1, SDL_GETEVENT, (1<<type))) {
2209           /* nothing */ ;
2210         }
2211     }
2212 
2213     return retval;
2214 }
2215 
2216 /* Calculates the Logical Scaling viewport based on a given window size.
2217    We pass the DPI-unscaled pixel size in when using this for rendering, and
2218    the DPI-scaled window size when using it to transform mouse coordinates. */
2219 static SDL_Rect
GetOpenGLLogicalScalingViewport(int physical_width,int physical_height)2220 GetOpenGLLogicalScalingViewport(int physical_width, int physical_height)
2221 {
2222     float want_aspect, real_aspect;
2223     SDL_Rect dstrect;
2224 
2225     want_aspect = ((float) OpenGLLogicalScalingWidth) / ((float) OpenGLLogicalScalingHeight);
2226     real_aspect = ((float) physical_width) / ((float) physical_height);
2227 
2228     if (SDL20_fabs(want_aspect-real_aspect) < 0.0001) {
2229         /* The aspect ratios are the same, just scale appropriately */
2230         dstrect.x = 0;
2231         dstrect.y = 0;
2232         dstrect.w = physical_width;
2233         dstrect.h = physical_height;
2234     } else if (want_aspect > real_aspect) {
2235         /* We want a wider aspect ratio than is available - letterbox it */
2236         const float scale = ((float) physical_width) / OpenGLLogicalScalingWidth;
2237         dstrect.x = 0;
2238         dstrect.w = physical_width;
2239         dstrect.h = (int)SDL20_floor(OpenGLLogicalScalingHeight * scale);
2240         dstrect.y = (physical_height - dstrect.h) / 2;
2241     } else {
2242         /* We want a narrower aspect ratio than is available - use side-bars */
2243         const float scale = ((float)physical_height) / OpenGLLogicalScalingHeight;
2244         dstrect.y = 0;
2245         dstrect.h = physical_height;
2246         dstrect.w = (int)SDL20_floor(OpenGLLogicalScalingWidth * scale);
2247         dstrect.x = (physical_width - dstrect.w) / 2;
2248     }
2249 
2250     return dstrect;
2251 }
2252 
2253 /* Scale a point (e.g. absolute mouse position) to the logical scaling size */
2254 static void
AdjustOpenGLLogicalScalingPoint(int * x,int * y)2255 AdjustOpenGLLogicalScalingPoint(int *x, int *y)
2256 {
2257     SDL_Rect viewport;
2258     int physical_w, physical_h;
2259     float scale_x, scale_y;
2260     int adjusted_x, adjusted_y;
2261 
2262     /* Don't adjust anything if we're not using Logical Scaling */
2263     if (!OpenGLLogicalScalingFBO) {
2264         return;
2265     }
2266 
2267     /* we want to scale based on the window size, which is dpi-scaled */
2268     SDL20_GetWindowSize(VideoWindow20, &physical_w, &physical_h);
2269     viewport = GetOpenGLLogicalScalingViewport(physical_w, physical_h);
2270 
2271     scale_x = (float)OpenGLLogicalScalingWidth / viewport.w;
2272     scale_y = (float)OpenGLLogicalScalingHeight / viewport.h;
2273 
2274     adjusted_x = (int) ((*x - viewport.x) * scale_x);
2275     adjusted_y = (int) ((*y - viewport.y) * scale_y);
2276 
2277     /* Clamp the result to the visible window */
2278     *x = SDL_max(SDL_min(adjusted_x, OpenGLLogicalScalingWidth), 0);
2279     *y = SDL_max(SDL_min(adjusted_y, OpenGLLogicalScalingHeight), 0);
2280 }
2281 
2282 /* Scale a vector (e.g. relative mouse movement) to the logical scaling size */
2283 static void
AdjustOpenGLLogicalScalingVector(int * x,int * y,float * rx,float * ry)2284 AdjustOpenGLLogicalScalingVector(int *x, int *y, float *rx, float *ry)
2285 {
2286     SDL_Rect viewport;
2287     int physical_w, physical_h;
2288     float scale_x, scale_y;
2289     float float_x, float_y;
2290     float trunc_x, trunc_y;
2291 
2292     /* Don't adjust anything if we're not using Logical Scaling */
2293     if (!OpenGLLogicalScalingFBO) {
2294         return;
2295     }
2296 
2297     /* we want to scale based on the window size, which is dpi-scaled */
2298     SDL20_GetWindowSize(VideoWindow20, &physical_w, &physical_h);
2299     viewport = GetOpenGLLogicalScalingViewport(physical_w, physical_h);
2300 
2301     scale_x = (float)OpenGLLogicalScalingWidth / viewport.w;
2302     scale_y = (float)OpenGLLogicalScalingHeight / viewport.h;
2303 
2304     float_x = *x * scale_x + (rx ? *rx : 0.f);
2305     float_y = *y * scale_y + (ry ? *ry : 0.f);
2306 
2307     trunc_x = SDL20_truncf(float_x);
2308     trunc_y = SDL20_truncf(float_y);
2309 
2310     *x = (int)trunc_x;
2311     *y = (int)trunc_y;
2312 
2313     if (rx) {
2314         *rx = float_x - trunc_x;
2315     }
2316     if (ry) {
2317         *ry = float_y - trunc_y;
2318     }
2319 }
2320 
MouseButtonState20to12(const Uint32 state20)2321 static Uint8 MouseButtonState20to12(const Uint32 state20)
2322 {
2323     Uint8 retval = (state20 & 0x7);  /* left, right, and middle will match. */
2324 
2325     /* the X[12] buttons are different in 1.2; mousewheel was in the way. */
2326     if (state20 & SDL_BUTTON(SDL_BUTTON_X1)) {
2327         retval |= (1<<5);
2328     }
2329     if (state20 & SDL_BUTTON(SDL_BUTTON_X2)) {
2330         retval |= (1<<6);
2331     }
2332 
2333     return retval;
2334 }
2335 
2336 DECLSPEC Uint8 SDLCALL
SDL_GetMouseState(int * x,int * y)2337 SDL_GetMouseState(int *x, int *y)
2338 {
2339     const Uint8 buttons = MouseButtonState20to12(SDL20_GetMouseState(x, y));
2340     if (x) { *x = MousePosition.x; }
2341     if (y) { *y = MousePosition.y; }
2342     return buttons;
2343 }
2344 
2345 DECLSPEC Uint8 SDLCALL
SDL_GetRelativeMouseState(int * x,int * y)2346 SDL_GetRelativeMouseState(int *x, int *y)
2347 {
2348     return MouseButtonState20to12(SDL20_GetRelativeMouseState(x, y));
2349 }
2350 
2351 DECLSPEC char * SDLCALL
SDL_GetKeyName(SDL12Key key)2352 SDL_GetKeyName(SDL12Key key)
2353 {
2354     switch (key) {
2355     #define CASESDLK12TONAME(k, n) case k: return (char *) n
2356     CASESDLK12TONAME(SDLK12_BACKSPACE, "backspace");
2357     CASESDLK12TONAME(SDLK12_TAB, "tab");
2358     CASESDLK12TONAME(SDLK12_CLEAR, "clear");
2359     CASESDLK12TONAME(SDLK12_RETURN, "return");
2360     CASESDLK12TONAME(SDLK12_PAUSE, "pause");
2361     CASESDLK12TONAME(SDLK12_ESCAPE, "escape");
2362     CASESDLK12TONAME(SDLK12_SPACE, "space");
2363     CASESDLK12TONAME(SDLK12_EXCLAIM, "!");
2364     CASESDLK12TONAME(SDLK12_QUOTEDBL, "\"");
2365     CASESDLK12TONAME(SDLK12_HASH, "#");
2366     CASESDLK12TONAME(SDLK12_DOLLAR, "$");
2367     CASESDLK12TONAME(SDLK12_AMPERSAND, "&");
2368     CASESDLK12TONAME(SDLK12_QUOTE, "'");
2369     CASESDLK12TONAME(SDLK12_LEFTPAREN, "(");
2370     CASESDLK12TONAME(SDLK12_RIGHTPAREN, ")");
2371     CASESDLK12TONAME(SDLK12_ASTERISK, "*");
2372     CASESDLK12TONAME(SDLK12_PLUS, "+");
2373     CASESDLK12TONAME(SDLK12_COMMA, ",");
2374     CASESDLK12TONAME(SDLK12_MINUS, "-");
2375     CASESDLK12TONAME(SDLK12_PERIOD, ".");
2376     CASESDLK12TONAME(SDLK12_SLASH, "/");
2377     CASESDLK12TONAME(SDLK12_0, "0");
2378     CASESDLK12TONAME(SDLK12_1, "1");
2379     CASESDLK12TONAME(SDLK12_2, "2");
2380     CASESDLK12TONAME(SDLK12_3, "3");
2381     CASESDLK12TONAME(SDLK12_4, "4");
2382     CASESDLK12TONAME(SDLK12_5, "5");
2383     CASESDLK12TONAME(SDLK12_6, "6");
2384     CASESDLK12TONAME(SDLK12_7, "7");
2385     CASESDLK12TONAME(SDLK12_8, "8");
2386     CASESDLK12TONAME(SDLK12_9, "9");
2387     CASESDLK12TONAME(SDLK12_COLON, ":");
2388     CASESDLK12TONAME(SDLK12_SEMICOLON, ");");
2389     CASESDLK12TONAME(SDLK12_LESS, "<");
2390     CASESDLK12TONAME(SDLK12_EQUALS, "=");
2391     CASESDLK12TONAME(SDLK12_GREATER, ">");
2392     CASESDLK12TONAME(SDLK12_QUESTION, "?");
2393     CASESDLK12TONAME(SDLK12_AT, "@");
2394     CASESDLK12TONAME(SDLK12_LEFTBRACKET, "[");
2395     CASESDLK12TONAME(SDLK12_BACKSLASH, "\\");
2396     CASESDLK12TONAME(SDLK12_RIGHTBRACKET, "]");
2397     CASESDLK12TONAME(SDLK12_CARET, "^");
2398     CASESDLK12TONAME(SDLK12_UNDERSCORE, "_");
2399     CASESDLK12TONAME(SDLK12_BACKQUOTE, "`");
2400     CASESDLK12TONAME(SDLK12_a, "a");
2401     CASESDLK12TONAME(SDLK12_b, "b");
2402     CASESDLK12TONAME(SDLK12_c, "c");
2403     CASESDLK12TONAME(SDLK12_d, "d");
2404     CASESDLK12TONAME(SDLK12_e, "e");
2405     CASESDLK12TONAME(SDLK12_f, "f");
2406     CASESDLK12TONAME(SDLK12_g, "g");
2407     CASESDLK12TONAME(SDLK12_h, "h");
2408     CASESDLK12TONAME(SDLK12_i, "i");
2409     CASESDLK12TONAME(SDLK12_j, "j");
2410     CASESDLK12TONAME(SDLK12_k, "k");
2411     CASESDLK12TONAME(SDLK12_l, "l");
2412     CASESDLK12TONAME(SDLK12_m, "m");
2413     CASESDLK12TONAME(SDLK12_n, "n");
2414     CASESDLK12TONAME(SDLK12_o, "o");
2415     CASESDLK12TONAME(SDLK12_p, "p");
2416     CASESDLK12TONAME(SDLK12_q, "q");
2417     CASESDLK12TONAME(SDLK12_r, "r");
2418     CASESDLK12TONAME(SDLK12_s, "s");
2419     CASESDLK12TONAME(SDLK12_t, "t");
2420     CASESDLK12TONAME(SDLK12_u, "u");
2421     CASESDLK12TONAME(SDLK12_v, "v");
2422     CASESDLK12TONAME(SDLK12_w, "w");
2423     CASESDLK12TONAME(SDLK12_x, "x");
2424     CASESDLK12TONAME(SDLK12_y, "y");
2425     CASESDLK12TONAME(SDLK12_z, "z");
2426     CASESDLK12TONAME(SDLK12_DELETE, "delete");
2427 
2428     CASESDLK12TONAME(SDLK12_WORLD_0, "world 0");
2429     CASESDLK12TONAME(SDLK12_WORLD_1, "world 1");
2430     CASESDLK12TONAME(SDLK12_WORLD_2, "world 2");
2431     CASESDLK12TONAME(SDLK12_WORLD_3, "world 3");
2432     CASESDLK12TONAME(SDLK12_WORLD_4, "world 4");
2433     CASESDLK12TONAME(SDLK12_WORLD_5, "world 5");
2434     CASESDLK12TONAME(SDLK12_WORLD_6, "world 6");
2435     CASESDLK12TONAME(SDLK12_WORLD_7, "world 7");
2436     CASESDLK12TONAME(SDLK12_WORLD_8, "world 8");
2437     CASESDLK12TONAME(SDLK12_WORLD_9, "world 9");
2438     CASESDLK12TONAME(SDLK12_WORLD_10, "world 10");
2439     CASESDLK12TONAME(SDLK12_WORLD_11, "world 11");
2440     CASESDLK12TONAME(SDLK12_WORLD_12, "world 12");
2441     CASESDLK12TONAME(SDLK12_WORLD_13, "world 13");
2442     CASESDLK12TONAME(SDLK12_WORLD_14, "world 14");
2443     CASESDLK12TONAME(SDLK12_WORLD_15, "world 15");
2444     CASESDLK12TONAME(SDLK12_WORLD_16, "world 16");
2445     CASESDLK12TONAME(SDLK12_WORLD_17, "world 17");
2446     CASESDLK12TONAME(SDLK12_WORLD_18, "world 18");
2447     CASESDLK12TONAME(SDLK12_WORLD_19, "world 19");
2448     CASESDLK12TONAME(SDLK12_WORLD_20, "world 20");
2449     CASESDLK12TONAME(SDLK12_WORLD_21, "world 21");
2450     CASESDLK12TONAME(SDLK12_WORLD_22, "world 22");
2451     CASESDLK12TONAME(SDLK12_WORLD_23, "world 23");
2452     CASESDLK12TONAME(SDLK12_WORLD_24, "world 24");
2453     CASESDLK12TONAME(SDLK12_WORLD_25, "world 25");
2454     CASESDLK12TONAME(SDLK12_WORLD_26, "world 26");
2455     CASESDLK12TONAME(SDLK12_WORLD_27, "world 27");
2456     CASESDLK12TONAME(SDLK12_WORLD_28, "world 28");
2457     CASESDLK12TONAME(SDLK12_WORLD_29, "world 29");
2458     CASESDLK12TONAME(SDLK12_WORLD_30, "world 30");
2459     CASESDLK12TONAME(SDLK12_WORLD_31, "world 31");
2460     CASESDLK12TONAME(SDLK12_WORLD_32, "world 32");
2461     CASESDLK12TONAME(SDLK12_WORLD_33, "world 33");
2462     CASESDLK12TONAME(SDLK12_WORLD_34, "world 34");
2463     CASESDLK12TONAME(SDLK12_WORLD_35, "world 35");
2464     CASESDLK12TONAME(SDLK12_WORLD_36, "world 36");
2465     CASESDLK12TONAME(SDLK12_WORLD_37, "world 37");
2466     CASESDLK12TONAME(SDLK12_WORLD_38, "world 38");
2467     CASESDLK12TONAME(SDLK12_WORLD_39, "world 39");
2468     CASESDLK12TONAME(SDLK12_WORLD_40, "world 40");
2469     CASESDLK12TONAME(SDLK12_WORLD_41, "world 41");
2470     CASESDLK12TONAME(SDLK12_WORLD_42, "world 42");
2471     CASESDLK12TONAME(SDLK12_WORLD_43, "world 43");
2472     CASESDLK12TONAME(SDLK12_WORLD_44, "world 44");
2473     CASESDLK12TONAME(SDLK12_WORLD_45, "world 45");
2474     CASESDLK12TONAME(SDLK12_WORLD_46, "world 46");
2475     CASESDLK12TONAME(SDLK12_WORLD_47, "world 47");
2476     CASESDLK12TONAME(SDLK12_WORLD_48, "world 48");
2477     CASESDLK12TONAME(SDLK12_WORLD_49, "world 49");
2478     CASESDLK12TONAME(SDLK12_WORLD_50, "world 50");
2479     CASESDLK12TONAME(SDLK12_WORLD_51, "world 51");
2480     CASESDLK12TONAME(SDLK12_WORLD_52, "world 52");
2481     CASESDLK12TONAME(SDLK12_WORLD_53, "world 53");
2482     CASESDLK12TONAME(SDLK12_WORLD_54, "world 54");
2483     CASESDLK12TONAME(SDLK12_WORLD_55, "world 55");
2484     CASESDLK12TONAME(SDLK12_WORLD_56, "world 56");
2485     CASESDLK12TONAME(SDLK12_WORLD_57, "world 57");
2486     CASESDLK12TONAME(SDLK12_WORLD_58, "world 58");
2487     CASESDLK12TONAME(SDLK12_WORLD_59, "world 59");
2488     CASESDLK12TONAME(SDLK12_WORLD_60, "world 60");
2489     CASESDLK12TONAME(SDLK12_WORLD_61, "world 61");
2490     CASESDLK12TONAME(SDLK12_WORLD_62, "world 62");
2491     CASESDLK12TONAME(SDLK12_WORLD_63, "world 63");
2492     CASESDLK12TONAME(SDLK12_WORLD_64, "world 64");
2493     CASESDLK12TONAME(SDLK12_WORLD_65, "world 65");
2494     CASESDLK12TONAME(SDLK12_WORLD_66, "world 66");
2495     CASESDLK12TONAME(SDLK12_WORLD_67, "world 67");
2496     CASESDLK12TONAME(SDLK12_WORLD_68, "world 68");
2497     CASESDLK12TONAME(SDLK12_WORLD_69, "world 69");
2498     CASESDLK12TONAME(SDLK12_WORLD_70, "world 70");
2499     CASESDLK12TONAME(SDLK12_WORLD_71, "world 71");
2500     CASESDLK12TONAME(SDLK12_WORLD_72, "world 72");
2501     CASESDLK12TONAME(SDLK12_WORLD_73, "world 73");
2502     CASESDLK12TONAME(SDLK12_WORLD_74, "world 74");
2503     CASESDLK12TONAME(SDLK12_WORLD_75, "world 75");
2504     CASESDLK12TONAME(SDLK12_WORLD_76, "world 76");
2505     CASESDLK12TONAME(SDLK12_WORLD_77, "world 77");
2506     CASESDLK12TONAME(SDLK12_WORLD_78, "world 78");
2507     CASESDLK12TONAME(SDLK12_WORLD_79, "world 79");
2508     CASESDLK12TONAME(SDLK12_WORLD_80, "world 80");
2509     CASESDLK12TONAME(SDLK12_WORLD_81, "world 81");
2510     CASESDLK12TONAME(SDLK12_WORLD_82, "world 82");
2511     CASESDLK12TONAME(SDLK12_WORLD_83, "world 83");
2512     CASESDLK12TONAME(SDLK12_WORLD_84, "world 84");
2513     CASESDLK12TONAME(SDLK12_WORLD_85, "world 85");
2514     CASESDLK12TONAME(SDLK12_WORLD_86, "world 86");
2515     CASESDLK12TONAME(SDLK12_WORLD_87, "world 87");
2516     CASESDLK12TONAME(SDLK12_WORLD_88, "world 88");
2517     CASESDLK12TONAME(SDLK12_WORLD_89, "world 89");
2518     CASESDLK12TONAME(SDLK12_WORLD_90, "world 90");
2519     CASESDLK12TONAME(SDLK12_WORLD_91, "world 91");
2520     CASESDLK12TONAME(SDLK12_WORLD_92, "world 92");
2521     CASESDLK12TONAME(SDLK12_WORLD_93, "world 93");
2522     CASESDLK12TONAME(SDLK12_WORLD_94, "world 94");
2523     CASESDLK12TONAME(SDLK12_WORLD_95, "world 95");
2524 
2525     CASESDLK12TONAME(SDLK12_KP0, "[0]");
2526     CASESDLK12TONAME(SDLK12_KP1, "[1]");
2527     CASESDLK12TONAME(SDLK12_KP2, "[2]");
2528     CASESDLK12TONAME(SDLK12_KP3, "[3]");
2529     CASESDLK12TONAME(SDLK12_KP4, "[4]");
2530     CASESDLK12TONAME(SDLK12_KP5, "[5]");
2531     CASESDLK12TONAME(SDLK12_KP6, "[6]");
2532     CASESDLK12TONAME(SDLK12_KP7, "[7]");
2533     CASESDLK12TONAME(SDLK12_KP8, "[8]");
2534     CASESDLK12TONAME(SDLK12_KP9, "[9]");
2535     CASESDLK12TONAME(SDLK12_KP_PERIOD, "[.]");
2536     CASESDLK12TONAME(SDLK12_KP_DIVIDE, "[/]");
2537     CASESDLK12TONAME(SDLK12_KP_MULTIPLY, "[*]");
2538     CASESDLK12TONAME(SDLK12_KP_MINUS, "[-]");
2539     CASESDLK12TONAME(SDLK12_KP_PLUS, "[+]");
2540     CASESDLK12TONAME(SDLK12_KP_ENTER, "enter");
2541     CASESDLK12TONAME(SDLK12_KP_EQUALS, "equals");
2542 
2543     CASESDLK12TONAME(SDLK12_UP, "up");
2544     CASESDLK12TONAME(SDLK12_DOWN, "down");
2545     CASESDLK12TONAME(SDLK12_RIGHT, "right");
2546     CASESDLK12TONAME(SDLK12_LEFT, "left");
2547     CASESDLK12TONAME(SDLK12_INSERT, "insert");
2548     CASESDLK12TONAME(SDLK12_HOME, "home");
2549     CASESDLK12TONAME(SDLK12_END, "end");
2550     CASESDLK12TONAME(SDLK12_PAGEUP, "page up");
2551     CASESDLK12TONAME(SDLK12_PAGEDOWN, "page down");
2552 
2553     CASESDLK12TONAME(SDLK12_F1, "f1");
2554     CASESDLK12TONAME(SDLK12_F2, "f2");
2555     CASESDLK12TONAME(SDLK12_F3, "f3");
2556     CASESDLK12TONAME(SDLK12_F4, "f4");
2557     CASESDLK12TONAME(SDLK12_F5, "f5");
2558     CASESDLK12TONAME(SDLK12_F6, "f6");
2559     CASESDLK12TONAME(SDLK12_F7, "f7");
2560     CASESDLK12TONAME(SDLK12_F8, "f8");
2561     CASESDLK12TONAME(SDLK12_F9, "f9");
2562     CASESDLK12TONAME(SDLK12_F10, "f10");
2563     CASESDLK12TONAME(SDLK12_F11, "f11");
2564     CASESDLK12TONAME(SDLK12_F12, "f12");
2565     CASESDLK12TONAME(SDLK12_F13, "f13");
2566     CASESDLK12TONAME(SDLK12_F14, "f14");
2567     CASESDLK12TONAME(SDLK12_F15, "f15");
2568 
2569     CASESDLK12TONAME(SDLK12_NUMLOCK, "numlock");
2570     CASESDLK12TONAME(SDLK12_CAPSLOCK, "caps lock");
2571     CASESDLK12TONAME(SDLK12_SCROLLOCK, "scroll lock");
2572     CASESDLK12TONAME(SDLK12_RSHIFT, "right shift");
2573     CASESDLK12TONAME(SDLK12_LSHIFT, "left shift");
2574     CASESDLK12TONAME(SDLK12_RCTRL, "right ctrl");
2575     CASESDLK12TONAME(SDLK12_LCTRL, "left ctrl");
2576     CASESDLK12TONAME(SDLK12_RALT, "right alt");
2577     CASESDLK12TONAME(SDLK12_LALT, "left alt");
2578     CASESDLK12TONAME(SDLK12_RMETA, "right meta");
2579     CASESDLK12TONAME(SDLK12_LMETA, "left meta");
2580     CASESDLK12TONAME(SDLK12_LSUPER, "left super"); /* "Windows" keys */
2581     CASESDLK12TONAME(SDLK12_RSUPER, "right super");
2582     CASESDLK12TONAME(SDLK12_MODE, "alt gr");
2583     CASESDLK12TONAME(SDLK12_COMPOSE, "compose");
2584 
2585     CASESDLK12TONAME(SDLK12_HELP, "help");
2586     CASESDLK12TONAME(SDLK12_PRINT, "print screen");
2587     CASESDLK12TONAME(SDLK12_SYSREQ, "sys req");
2588     CASESDLK12TONAME(SDLK12_BREAK, "break");
2589     CASESDLK12TONAME(SDLK12_MENU, "menu");
2590     CASESDLK12TONAME(SDLK12_POWER, "power");
2591     CASESDLK12TONAME(SDLK12_EURO, "euro");
2592     CASESDLK12TONAME(SDLK12_UNDO, "undo");
2593     #undef CASESDLK12TONAME
2594     default: break;
2595     }
2596 
2597     return (char *) "unknown key";
2598 }
2599 
2600 static SDL12Key
Keysym20to12(const SDL_Keycode keysym20)2601 Keysym20to12(const SDL_Keycode keysym20)
2602 {
2603     if (((int) keysym20) <= 255) {
2604         /* (most of) low-ASCII maps directly,
2605          * and so does the Latin-1 range (128-255) */
2606         if (keysym20 == SDLK_PAUSE) {
2607             return SDLK12_PAUSE;
2608         } else if (keysym20 == SDLK_CLEAR) {
2609             return SDLK12_CLEAR;
2610         }
2611         return (SDL12Key) keysym20;
2612     }
2613 
2614     switch (keysym20) {
2615     #define CASEKEYSYM20TO12(k20, k12) case SDLK_##k20: return SDLK12_##k12
2616     CASEKEYSYM20TO12(KP_0, KP0);
2617     CASEKEYSYM20TO12(KP_1, KP1);
2618     CASEKEYSYM20TO12(KP_2, KP2);
2619     CASEKEYSYM20TO12(KP_3, KP3);
2620     CASEKEYSYM20TO12(KP_4, KP4);
2621     CASEKEYSYM20TO12(KP_5, KP5);
2622     CASEKEYSYM20TO12(KP_6, KP6);
2623     CASEKEYSYM20TO12(KP_7, KP7);
2624     CASEKEYSYM20TO12(KP_8, KP8);
2625     CASEKEYSYM20TO12(KP_9, KP9);
2626     CASEKEYSYM20TO12(NUMLOCKCLEAR, NUMLOCK);
2627     CASEKEYSYM20TO12(SCROLLLOCK, SCROLLOCK);
2628     CASEKEYSYM20TO12(RGUI, RMETA);
2629     CASEKEYSYM20TO12(LGUI, LMETA);
2630     CASEKEYSYM20TO12(PRINTSCREEN, PRINT);
2631     #undef CASEKEYSYM20TO12
2632 
2633     #define CASEKEYSYM20TO12(k) case SDLK_##k: return SDLK12_##k
2634     CASEKEYSYM20TO12(CLEAR);
2635     CASEKEYSYM20TO12(PAUSE);
2636     CASEKEYSYM20TO12(KP_PERIOD);
2637     CASEKEYSYM20TO12(KP_DIVIDE);
2638     CASEKEYSYM20TO12(KP_MULTIPLY);
2639     CASEKEYSYM20TO12(KP_MINUS);
2640     CASEKEYSYM20TO12(KP_PLUS);
2641     CASEKEYSYM20TO12(KP_ENTER);
2642     CASEKEYSYM20TO12(KP_EQUALS);
2643     CASEKEYSYM20TO12(UP);
2644     CASEKEYSYM20TO12(DOWN);
2645     CASEKEYSYM20TO12(RIGHT);
2646     CASEKEYSYM20TO12(LEFT);
2647     CASEKEYSYM20TO12(INSERT);
2648     CASEKEYSYM20TO12(HOME);
2649     CASEKEYSYM20TO12(END);
2650     CASEKEYSYM20TO12(PAGEUP);
2651     CASEKEYSYM20TO12(PAGEDOWN);
2652     CASEKEYSYM20TO12(F1);
2653     CASEKEYSYM20TO12(F2);
2654     CASEKEYSYM20TO12(F3);
2655     CASEKEYSYM20TO12(F4);
2656     CASEKEYSYM20TO12(F5);
2657     CASEKEYSYM20TO12(F6);
2658     CASEKEYSYM20TO12(F7);
2659     CASEKEYSYM20TO12(F8);
2660     CASEKEYSYM20TO12(F9);
2661     CASEKEYSYM20TO12(F10);
2662     CASEKEYSYM20TO12(F11);
2663     CASEKEYSYM20TO12(F12);
2664     CASEKEYSYM20TO12(F13);
2665     CASEKEYSYM20TO12(F14);
2666     CASEKEYSYM20TO12(F15);
2667     CASEKEYSYM20TO12(CAPSLOCK);
2668     CASEKEYSYM20TO12(RSHIFT);
2669     CASEKEYSYM20TO12(LSHIFT);
2670     CASEKEYSYM20TO12(RCTRL);
2671     CASEKEYSYM20TO12(LCTRL);
2672     CASEKEYSYM20TO12(RALT);
2673     CASEKEYSYM20TO12(LALT);
2674     CASEKEYSYM20TO12(MODE);
2675     CASEKEYSYM20TO12(HELP);
2676     CASEKEYSYM20TO12(SYSREQ);
2677     CASEKEYSYM20TO12(MENU);
2678     CASEKEYSYM20TO12(POWER);
2679     CASEKEYSYM20TO12(UNDO);
2680     #undef CASEKEYSYM20TO12
2681 
2682     /* Map the "World Keys" (SDLK_WORLD_0 = 0xA0 to SDLK_WORLD_95 = 0xFF).
2683      * In SDL2 they're the UCS-4 (32bit unicode) code for the key,
2684      * in SDL1.2 (on X11 at least) they were the X11_KeySym & 0xFF,
2685      * if (X11_KeySym >> 8)) was either 0 to 8 or 0x0A or 0x0C or 0x0E
2686      * So map all those used UCS-4 codes to the corresponding SDLK12_WORLD_* codes
2687      * Note that the Latin-1 range (keysym20 <= 255) is already handled at the top of this function
2688      * Luckily X11's keysymdef.h lists both the values of the constants and their UCS4-value, like
2689      * #define XK_Aogonek                       0x01a1  / * U+0104 LATIN CAPITAL LETTER A WITH OGONEK * /
2690      * So I'm using that as a reference for our mappings, which only use
2691      * the lowest byte of the XK_* value, because of X11_KeySym & 0xFF in SDL1.2
2692      *
2693      * case UCS4_code: return (SDL12Key)lowest_byte_of_corresponding_X11_KeySym; */
2694 
2695     /* Latin-2 */
2696     case 0x0104: return (SDL12Key)0xa1;
2697     case 0x02D8: return (SDL12Key)0xa2;
2698     case 0x0141: return (SDL12Key)0xa3;
2699     case 0x013D: return (SDL12Key)0xa5;
2700     case 0x015A: return (SDL12Key)0xa6;
2701     case 0x0160: return (SDL12Key)0xa9;
2702     case 0x015E: return (SDL12Key)0xaa;
2703     case 0x0164: return (SDL12Key)0xab;
2704     case 0x0179: return (SDL12Key)0xac;
2705     case 0x017D: return (SDL12Key)0xae;
2706     case 0x017B: return (SDL12Key)0xaf;
2707     case 0x0105: return (SDL12Key)0xb1;
2708     case 0x02DB: return (SDL12Key)0xb2;
2709     case 0x0142: return (SDL12Key)0xb3;
2710     case 0x013E: return (SDL12Key)0xb5;
2711     case 0x015B: return (SDL12Key)0xb6;
2712     case 0x02C7: return (SDL12Key)0xb7;
2713     case 0x0161: return (SDL12Key)0xb9;
2714     case 0x015F: return (SDL12Key)0xba;
2715     case 0x0165: return (SDL12Key)0xbb;
2716     case 0x017A: return (SDL12Key)0xbc;
2717     case 0x02DD: return (SDL12Key)0xbd;
2718     case 0x017E: return (SDL12Key)0xbe;
2719     case 0x017C: return (SDL12Key)0xbf;
2720     case 0x0154: return (SDL12Key)0xc0;
2721     case 0x0102: return (SDL12Key)0xc3;
2722     case 0x0139: return (SDL12Key)0xc5;
2723     case 0x0106: return (SDL12Key)0xc6;
2724     case 0x010C: return (SDL12Key)0xc8;
2725     case 0x0118: return (SDL12Key)0xca;
2726     case 0x011A: return (SDL12Key)0xcc;
2727     case 0x010E: return (SDL12Key)0xcf;
2728     case 0x0110: return (SDL12Key)0xd0;
2729     case 0x0143: return (SDL12Key)0xd1;
2730     case 0x0147: return (SDL12Key)0xd2;
2731     case 0x0150: return (SDL12Key)0xd5;
2732     case 0x0158: return (SDL12Key)0xd8;
2733     case 0x016E: return (SDL12Key)0xd9;
2734     case 0x0170: return (SDL12Key)0xdb;
2735     case 0x0162: return (SDL12Key)0xde;
2736     case 0x0155: return (SDL12Key)0xe0;
2737     case 0x0103: return (SDL12Key)0xe3;
2738     case 0x013A: return (SDL12Key)0xe5;
2739     case 0x0107: return (SDL12Key)0xe6;
2740     case 0x010D: return (SDL12Key)0xe8;
2741     case 0x0119: return (SDL12Key)0xea;
2742     case 0x011B: return (SDL12Key)0xec;
2743     case 0x010F: return (SDL12Key)0xef;
2744     case 0x0111: return (SDL12Key)0xf0;
2745     case 0x0144: return (SDL12Key)0xf1;
2746     case 0x0148: return (SDL12Key)0xf2;
2747     case 0x0151: return (SDL12Key)0xf5;
2748     case 0x0159: return (SDL12Key)0xf8;
2749     case 0x016F: return (SDL12Key)0xf9;
2750     case 0x0171: return (SDL12Key)0xfb;
2751     case 0x0163: return (SDL12Key)0xfe;
2752     case 0x02D9: return (SDL12Key)0xff;
2753     /* Latin-3 */
2754     case 0x0126: return (SDL12Key)0xa1;
2755     case 0x0124: return (SDL12Key)0xa6;
2756     case 0x0130: return (SDL12Key)0xa9;
2757     case 0x011E: return (SDL12Key)0xab;
2758     case 0x0134: return (SDL12Key)0xac;
2759     case 0x0127: return (SDL12Key)0xb1;
2760     case 0x0125: return (SDL12Key)0xb6;
2761     case 0x0131: return (SDL12Key)0xb9;
2762     case 0x011F: return (SDL12Key)0xbb;
2763     case 0x0135: return (SDL12Key)0xbc;
2764     case 0x010A: return (SDL12Key)0xc5;
2765     case 0x0108: return (SDL12Key)0xc6;
2766     case 0x0120: return (SDL12Key)0xd5;
2767     case 0x011C: return (SDL12Key)0xd8;
2768     case 0x016C: return (SDL12Key)0xdd;
2769     case 0x015C: return (SDL12Key)0xde;
2770     case 0x010B: return (SDL12Key)0xe5;
2771     case 0x0109: return (SDL12Key)0xe6;
2772     case 0x0121: return (SDL12Key)0xf5;
2773     case 0x011D: return (SDL12Key)0xf8;
2774     case 0x016D: return (SDL12Key)0xfd;
2775     case 0x015D: return (SDL12Key)0xfe;
2776     /* Latin 4 */
2777     case 0x0138: return (SDL12Key)0xa2;
2778     case 0x0156: return (SDL12Key)0xa3;
2779     case 0x0128: return (SDL12Key)0xa5;
2780     case 0x013B: return (SDL12Key)0xa6;
2781     case 0x0112: return (SDL12Key)0xaa;
2782     case 0x0122: return (SDL12Key)0xab;
2783     case 0x0166: return (SDL12Key)0xac;
2784     case 0x0157: return (SDL12Key)0xb3;
2785     case 0x0129: return (SDL12Key)0xb5;
2786     case 0x013C: return (SDL12Key)0xb6;
2787     case 0x0113: return (SDL12Key)0xba;
2788     case 0x0123: return (SDL12Key)0xbb;
2789     case 0x0167: return (SDL12Key)0xbc;
2790     case 0x014A: return (SDL12Key)0xbd;
2791     case 0x014B: return (SDL12Key)0xbf;
2792     case 0x0100: return (SDL12Key)0xc0;
2793     case 0x012E: return (SDL12Key)0xc7;
2794     case 0x0116: return (SDL12Key)0xcc;
2795     case 0x012A: return (SDL12Key)0xcf;
2796     case 0x0145: return (SDL12Key)0xd1;
2797     case 0x014C: return (SDL12Key)0xd2;
2798     case 0x0136: return (SDL12Key)0xd3;
2799     case 0x0172: return (SDL12Key)0xd9;
2800     case 0x0168: return (SDL12Key)0xdd;
2801     case 0x016A: return (SDL12Key)0xde;
2802     case 0x0101: return (SDL12Key)0xe0;
2803     case 0x012F: return (SDL12Key)0xe7;
2804     case 0x0117: return (SDL12Key)0xec;
2805     case 0x012B: return (SDL12Key)0xef;
2806     case 0x0146: return (SDL12Key)0xf1;
2807     case 0x014D: return (SDL12Key)0xf2;
2808     case 0x0137: return (SDL12Key)0xf3;
2809     case 0x0173: return (SDL12Key)0xf9;
2810     case 0x0169: return (SDL12Key)0xfd;
2811     case 0x016B: return (SDL12Key)0xfe;
2812     /* Katakana */
2813     case 0x203E: return (SDL12Key)0x7e;
2814     case 0x3002: return (SDL12Key)0xa1;
2815     case 0x300C: return (SDL12Key)0xa2;
2816     case 0x300D: return (SDL12Key)0xa3;
2817     case 0x3001: return (SDL12Key)0xa4;
2818     case 0x30FB: return (SDL12Key)0xa5;
2819     case 0x30F2: return (SDL12Key)0xa6;
2820     case 0x30A1: return (SDL12Key)0xa7;
2821     case 0x30A3: return (SDL12Key)0xa8;
2822     case 0x30A5: return (SDL12Key)0xa9;
2823     case 0x30A7: return (SDL12Key)0xaa;
2824     case 0x30A9: return (SDL12Key)0xab;
2825     case 0x30E3: return (SDL12Key)0xac;
2826     case 0x30E5: return (SDL12Key)0xad;
2827     case 0x30E7: return (SDL12Key)0xae;
2828     case 0x30C3: return (SDL12Key)0xaf;
2829     case 0x30FC: return (SDL12Key)0xb0;
2830     case 0x30A2: return (SDL12Key)0xb1;
2831     case 0x30A4: return (SDL12Key)0xb2;
2832     case 0x30A6: return (SDL12Key)0xb3;
2833     case 0x30A8: return (SDL12Key)0xb4;
2834     case 0x30AA: return (SDL12Key)0xb5;
2835     case 0x30AB: return (SDL12Key)0xb6;
2836     case 0x30AD: return (SDL12Key)0xb7;
2837     case 0x30AF: return (SDL12Key)0xb8;
2838     case 0x30B1: return (SDL12Key)0xb9;
2839     case 0x30B3: return (SDL12Key)0xba;
2840     case 0x30B5: return (SDL12Key)0xbb;
2841     case 0x30B7: return (SDL12Key)0xbc;
2842     case 0x30B9: return (SDL12Key)0xbd;
2843     case 0x30BB: return (SDL12Key)0xbe;
2844     case 0x30BD: return (SDL12Key)0xbf;
2845     case 0x30BF: return (SDL12Key)0xc0;
2846     case 0x30C1: return (SDL12Key)0xc1;
2847     case 0x30C4: return (SDL12Key)0xc2;
2848     case 0x30C6: return (SDL12Key)0xc3;
2849     case 0x30C8: return (SDL12Key)0xc4;
2850     case 0x30CA: return (SDL12Key)0xc5;
2851     case 0x30CB: return (SDL12Key)0xc6;
2852     case 0x30CC: return (SDL12Key)0xc7;
2853     case 0x30CD: return (SDL12Key)0xc8;
2854     case 0x30CE: return (SDL12Key)0xc9;
2855     case 0x30CF: return (SDL12Key)0xca;
2856     case 0x30D2: return (SDL12Key)0xcb;
2857     case 0x30D5: return (SDL12Key)0xcc;
2858     case 0x30D8: return (SDL12Key)0xcd;
2859     case 0x30DB: return (SDL12Key)0xce;
2860     case 0x30DE: return (SDL12Key)0xcf;
2861     case 0x30DF: return (SDL12Key)0xd0;
2862     case 0x30E0: return (SDL12Key)0xd1;
2863     case 0x30E1: return (SDL12Key)0xd2;
2864     case 0x30E2: return (SDL12Key)0xd3;
2865     case 0x30E4: return (SDL12Key)0xd4;
2866     case 0x30E6: return (SDL12Key)0xd5;
2867     case 0x30E8: return (SDL12Key)0xd6;
2868     case 0x30E9: return (SDL12Key)0xd7;
2869     case 0x30EA: return (SDL12Key)0xd8;
2870     case 0x30EB: return (SDL12Key)0xd9;
2871     case 0x30EC: return (SDL12Key)0xda;
2872     case 0x30ED: return (SDL12Key)0xdb;
2873     case 0x30EF: return (SDL12Key)0xdc;
2874     case 0x30F3: return (SDL12Key)0xdd;
2875     case 0x309B: return (SDL12Key)0xde;
2876     case 0x309C: return (SDL12Key)0xdf;
2877     /* Arabic */
2878     case 0x060C: return (SDL12Key)0xac;
2879     case 0x061B: return (SDL12Key)0xbb;
2880     case 0x061F: return (SDL12Key)0xbf;
2881     case 0x0621: return (SDL12Key)0xc1;
2882     case 0x0622: return (SDL12Key)0xc2;
2883     case 0x0623: return (SDL12Key)0xc3;
2884     case 0x0624: return (SDL12Key)0xc4;
2885     case 0x0625: return (SDL12Key)0xc5;
2886     case 0x0626: return (SDL12Key)0xc6;
2887     case 0x0627: return (SDL12Key)0xc7;
2888     case 0x0628: return (SDL12Key)0xc8;
2889     case 0x0629: return (SDL12Key)0xc9;
2890     case 0x062A: return (SDL12Key)0xca;
2891     case 0x062B: return (SDL12Key)0xcb;
2892     case 0x062C: return (SDL12Key)0xcc;
2893     case 0x062D: return (SDL12Key)0xcd;
2894     case 0x062E: return (SDL12Key)0xce;
2895     case 0x062F: return (SDL12Key)0xcf;
2896     case 0x0630: return (SDL12Key)0xd0;
2897     case 0x0631: return (SDL12Key)0xd1;
2898     case 0x0632: return (SDL12Key)0xd2;
2899     case 0x0633: return (SDL12Key)0xd3;
2900     case 0x0634: return (SDL12Key)0xd4;
2901     case 0x0635: return (SDL12Key)0xd5;
2902     case 0x0636: return (SDL12Key)0xd6;
2903     case 0x0637: return (SDL12Key)0xd7;
2904     case 0x0638: return (SDL12Key)0xd8;
2905     case 0x0639: return (SDL12Key)0xd9;
2906     case 0x063A: return (SDL12Key)0xda;
2907     case 0x0640: return (SDL12Key)0xe0;
2908     case 0x0641: return (SDL12Key)0xe1;
2909     case 0x0642: return (SDL12Key)0xe2;
2910     case 0x0643: return (SDL12Key)0xe3;
2911     case 0x0644: return (SDL12Key)0xe4;
2912     case 0x0645: return (SDL12Key)0xe5;
2913     case 0x0646: return (SDL12Key)0xe6;
2914     case 0x0647: return (SDL12Key)0xe7;
2915     case 0x0648: return (SDL12Key)0xe8;
2916     case 0x0649: return (SDL12Key)0xe9;
2917     case 0x064A: return (SDL12Key)0xea;
2918     case 0x064B: return (SDL12Key)0xeb;
2919     case 0x064C: return (SDL12Key)0xec;
2920     case 0x064D: return (SDL12Key)0xed;
2921     case 0x064E: return (SDL12Key)0xee;
2922     case 0x064F: return (SDL12Key)0xef;
2923     case 0x0650: return (SDL12Key)0xf0;
2924     case 0x0651: return (SDL12Key)0xf1;
2925     case 0x0652: return (SDL12Key)0xf2;
2926     /* Cyrillic */
2927     case 0x0452: return (SDL12Key)0xa1;
2928     case 0x0453: return (SDL12Key)0xa2;
2929     case 0x0451: return (SDL12Key)0xa3;
2930     case 0x0454: return (SDL12Key)0xa4;
2931     case 0x0455: return (SDL12Key)0xa5;
2932     case 0x0456: return (SDL12Key)0xa6;
2933     case 0x0457: return (SDL12Key)0xa7;
2934     case 0x0458: return (SDL12Key)0xa8;
2935     case 0x0459: return (SDL12Key)0xa9;
2936     case 0x045A: return (SDL12Key)0xaa;
2937     case 0x045B: return (SDL12Key)0xab;
2938     case 0x045C: return (SDL12Key)0xac;
2939     case 0x0491: return (SDL12Key)0xad;
2940     case 0x045E: return (SDL12Key)0xae;
2941     case 0x045F: return (SDL12Key)0xaf;
2942     case 0x2116: return (SDL12Key)0xb0;
2943     case 0x0402: return (SDL12Key)0xb1;
2944     case 0x0403: return (SDL12Key)0xb2;
2945     case 0x0401: return (SDL12Key)0xb3;
2946     case 0x0404: return (SDL12Key)0xb4;
2947     case 0x0405: return (SDL12Key)0xb5;
2948     case 0x0406: return (SDL12Key)0xb6;
2949     case 0x0407: return (SDL12Key)0xb7;
2950     case 0x0408: return (SDL12Key)0xb8;
2951     case 0x0409: return (SDL12Key)0xb9;
2952     case 0x040A: return (SDL12Key)0xba;
2953     case 0x040B: return (SDL12Key)0xbb;
2954     case 0x040C: return (SDL12Key)0xbc;
2955     case 0x0490: return (SDL12Key)0xbd;
2956     case 0x040E: return (SDL12Key)0xbe;
2957     case 0x040F: return (SDL12Key)0xbf;
2958     case 0x044E: return (SDL12Key)0xc0;
2959     case 0x0430: return (SDL12Key)0xc1;
2960     case 0x0431: return (SDL12Key)0xc2;
2961     case 0x0446: return (SDL12Key)0xc3;
2962     case 0x0434: return (SDL12Key)0xc4;
2963     case 0x0435: return (SDL12Key)0xc5;
2964     case 0x0444: return (SDL12Key)0xc6;
2965     case 0x0433: return (SDL12Key)0xc7;
2966     case 0x0445: return (SDL12Key)0xc8;
2967     case 0x0438: return (SDL12Key)0xc9;
2968     case 0x0439: return (SDL12Key)0xca;
2969     case 0x043A: return (SDL12Key)0xcb;
2970     case 0x043B: return (SDL12Key)0xcc;
2971     case 0x043C: return (SDL12Key)0xcd;
2972     case 0x043D: return (SDL12Key)0xce;
2973     case 0x043E: return (SDL12Key)0xcf;
2974     case 0x043F: return (SDL12Key)0xd0;
2975     case 0x044F: return (SDL12Key)0xd1;
2976     case 0x0440: return (SDL12Key)0xd2;
2977     case 0x0441: return (SDL12Key)0xd3;
2978     case 0x0442: return (SDL12Key)0xd4;
2979     case 0x0443: return (SDL12Key)0xd5;
2980     case 0x0436: return (SDL12Key)0xd6;
2981     case 0x0432: return (SDL12Key)0xd7;
2982     case 0x044C: return (SDL12Key)0xd8;
2983     case 0x044B: return (SDL12Key)0xd9;
2984     case 0x0437: return (SDL12Key)0xda;
2985     case 0x0448: return (SDL12Key)0xdb;
2986     case 0x044D: return (SDL12Key)0xdc;
2987     case 0x0449: return (SDL12Key)0xdd;
2988     case 0x0447: return (SDL12Key)0xde;
2989     case 0x044A: return (SDL12Key)0xdf;
2990     case 0x042E: return (SDL12Key)0xe0;
2991     case 0x0410: return (SDL12Key)0xe1;
2992     case 0x0411: return (SDL12Key)0xe2;
2993     case 0x0426: return (SDL12Key)0xe3;
2994     case 0x0414: return (SDL12Key)0xe4;
2995     case 0x0415: return (SDL12Key)0xe5;
2996     case 0x0424: return (SDL12Key)0xe6;
2997     case 0x0413: return (SDL12Key)0xe7;
2998     case 0x0425: return (SDL12Key)0xe8;
2999     case 0x0418: return (SDL12Key)0xe9;
3000     case 0x0419: return (SDL12Key)0xea;
3001     case 0x041A: return (SDL12Key)0xeb;
3002     case 0x041B: return (SDL12Key)0xec;
3003     case 0x041C: return (SDL12Key)0xed;
3004     case 0x041D: return (SDL12Key)0xee;
3005     case 0x041E: return (SDL12Key)0xef;
3006     case 0x041F: return (SDL12Key)0xf0;
3007     case 0x042F: return (SDL12Key)0xf1;
3008     case 0x0420: return (SDL12Key)0xf2;
3009     case 0x0421: return (SDL12Key)0xf3;
3010     case 0x0422: return (SDL12Key)0xf4;
3011     case 0x0423: return (SDL12Key)0xf5;
3012     case 0x0416: return (SDL12Key)0xf6;
3013     case 0x0412: return (SDL12Key)0xf7;
3014     case 0x042C: return (SDL12Key)0xf8;
3015     case 0x042B: return (SDL12Key)0xf9;
3016     case 0x0417: return (SDL12Key)0xfa;
3017     case 0x0428: return (SDL12Key)0xfb;
3018     case 0x042D: return (SDL12Key)0xfc;
3019     case 0x0429: return (SDL12Key)0xfd;
3020     case 0x0427: return (SDL12Key)0xfe;
3021     case 0x042A: return (SDL12Key)0xff;
3022     /* Greek */
3023     case 0x0386: return (SDL12Key)0xa1;
3024     case 0x0388: return (SDL12Key)0xa2;
3025     case 0x0389: return (SDL12Key)0xa3;
3026     case 0x038A: return (SDL12Key)0xa4;
3027     case 0x03AA: return (SDL12Key)0xa5;
3028     case 0x038C: return (SDL12Key)0xa7;
3029     case 0x038E: return (SDL12Key)0xa8;
3030     case 0x03AB: return (SDL12Key)0xa9;
3031     case 0x038F: return (SDL12Key)0xab;
3032     case 0x0385: return (SDL12Key)0xae;
3033     case 0x2015: return (SDL12Key)0xaf;
3034     case 0x03AC: return (SDL12Key)0xb1;
3035     case 0x03AD: return (SDL12Key)0xb2;
3036     case 0x03AE: return (SDL12Key)0xb3;
3037     case 0x03AF: return (SDL12Key)0xb4;
3038     case 0x03CA: return (SDL12Key)0xb5;
3039     case 0x0390: return (SDL12Key)0xb6;
3040     case 0x03CC: return (SDL12Key)0xb7;
3041     case 0x03CD: return (SDL12Key)0xb8;
3042     case 0x03CB: return (SDL12Key)0xb9;
3043     case 0x03B0: return (SDL12Key)0xba;
3044     case 0x03CE: return (SDL12Key)0xbb;
3045     case 0x0391: return (SDL12Key)0xc1;
3046     case 0x0392: return (SDL12Key)0xc2;
3047     case 0x0393: return (SDL12Key)0xc3;
3048     case 0x0394: return (SDL12Key)0xc4;
3049     case 0x0395: return (SDL12Key)0xc5;
3050     case 0x0396: return (SDL12Key)0xc6;
3051     case 0x0397: return (SDL12Key)0xc7;
3052     case 0x0398: return (SDL12Key)0xc8;
3053     case 0x0399: return (SDL12Key)0xc9;
3054     case 0x039A: return (SDL12Key)0xca;
3055     case 0x039B: return (SDL12Key)0xcb;
3056     case 0x039C: return (SDL12Key)0xcc;
3057     case 0x039D: return (SDL12Key)0xcd;
3058     case 0x039E: return (SDL12Key)0xce;
3059     case 0x039F: return (SDL12Key)0xcf;
3060     case 0x03A0: return (SDL12Key)0xd0;
3061     case 0x03A1: return (SDL12Key)0xd1;
3062     case 0x03A3: return (SDL12Key)0xd2;
3063     case 0x03A4: return (SDL12Key)0xd4;
3064     case 0x03A5: return (SDL12Key)0xd5;
3065     case 0x03A6: return (SDL12Key)0xd6;
3066     case 0x03A7: return (SDL12Key)0xd7;
3067     case 0x03A8: return (SDL12Key)0xd8;
3068     case 0x03A9: return (SDL12Key)0xd9;
3069     case 0x03B1: return (SDL12Key)0xe1;
3070     case 0x03B2: return (SDL12Key)0xe2;
3071     case 0x03B3: return (SDL12Key)0xe3;
3072     case 0x03B4: return (SDL12Key)0xe4;
3073     case 0x03B5: return (SDL12Key)0xe5;
3074     case 0x03B6: return (SDL12Key)0xe6;
3075     case 0x03B7: return (SDL12Key)0xe7;
3076     case 0x03B8: return (SDL12Key)0xe8;
3077     case 0x03B9: return (SDL12Key)0xe9;
3078     case 0x03BA: return (SDL12Key)0xea;
3079     case 0x03BB: return (SDL12Key)0xeb;
3080     case 0x03BC: return (SDL12Key)0xec;
3081     case 0x03BD: return (SDL12Key)0xed;
3082     case 0x03BE: return (SDL12Key)0xee;
3083     case 0x03BF: return (SDL12Key)0xef;
3084     case 0x03C0: return (SDL12Key)0xf0;
3085     case 0x03C1: return (SDL12Key)0xf1;
3086     case 0x03C3: return (SDL12Key)0xf2;
3087     case 0x03C2: return (SDL12Key)0xf3;
3088     case 0x03C4: return (SDL12Key)0xf4;
3089     case 0x03C5: return (SDL12Key)0xf5;
3090     case 0x03C6: return (SDL12Key)0xf6;
3091     case 0x03C7: return (SDL12Key)0xf7;
3092     case 0x03C8: return (SDL12Key)0xf8;
3093     case 0x03C9: return (SDL12Key)0xf9;
3094     /* Technical */
3095     case 0x23B7: return (SDL12Key)0xa1;
3096     case 0x250C: return (SDL12Key)0xa2;
3097     case 0x2500: return (SDL12Key)0xa3;
3098     case 0x2320: return (SDL12Key)0xa4;
3099     case 0x2321: return (SDL12Key)0xa5;
3100     case 0x2502: return (SDL12Key)0xa6;
3101     case 0x23A1: return (SDL12Key)0xa7;
3102     case 0x23A3: return (SDL12Key)0xa8;
3103     case 0x23A4: return (SDL12Key)0xa9;
3104     case 0x23A6: return (SDL12Key)0xaa;
3105     case 0x239B: return (SDL12Key)0xab;
3106     case 0x239D: return (SDL12Key)0xac;
3107     case 0x239E: return (SDL12Key)0xad;
3108     case 0x23A0: return (SDL12Key)0xae;
3109     case 0x23A8: return (SDL12Key)0xaf;
3110     case 0x23AC: return (SDL12Key)0xb0;
3111     case 0x2264: return (SDL12Key)0xbc;
3112     case 0x2260: return (SDL12Key)0xbd;
3113     case 0x2265: return (SDL12Key)0xbe;
3114     case 0x222B: return (SDL12Key)0xbf;
3115     case 0x2234: return (SDL12Key)0xc0;
3116     case 0x221D: return (SDL12Key)0xc1;
3117     case 0x221E: return (SDL12Key)0xc2;
3118     case 0x2207: return (SDL12Key)0xc5;
3119     case 0x223C: return (SDL12Key)0xc8;
3120     case 0x2243: return (SDL12Key)0xc9;
3121     case 0x21D4: return (SDL12Key)0xcd;
3122     case 0x21D2: return (SDL12Key)0xce;
3123     case 0x2261: return (SDL12Key)0xcf;
3124     case 0x221A: return (SDL12Key)0xd6;
3125     case 0x2282: return (SDL12Key)0xda;
3126     case 0x2283: return (SDL12Key)0xdb;
3127     case 0x2229: return (SDL12Key)0xdc;
3128     case 0x222A: return (SDL12Key)0xdd;
3129     case 0x2227: return (SDL12Key)0xde;
3130     case 0x2228: return (SDL12Key)0xdf;
3131     case 0x2202: return (SDL12Key)0xef;
3132     case 0x0192: return (SDL12Key)0xf6;
3133     case 0x2190: return (SDL12Key)0xfb;
3134     case 0x2191: return (SDL12Key)0xfc;
3135     case 0x2192: return (SDL12Key)0xfd;
3136     case 0x2193: return (SDL12Key)0xfe;
3137     /* Publishing */
3138     case 0x2003: return (SDL12Key)0xa1;
3139     case 0x2002: return (SDL12Key)0xa2;
3140     case 0x2004: return (SDL12Key)0xa3;
3141     case 0x2005: return (SDL12Key)0xa4;
3142     case 0x2007: return (SDL12Key)0xa5;
3143     case 0x2008: return (SDL12Key)0xa6;
3144     case 0x2009: return (SDL12Key)0xa7;
3145     case 0x200A: return (SDL12Key)0xa8;
3146     case 0x2014: return (SDL12Key)0xa9;
3147     case 0x2013: return (SDL12Key)0xaa;
3148     case 0x2423: return (SDL12Key)0xac;
3149     case 0x2026: return (SDL12Key)0xae;
3150     case 0x2025: return (SDL12Key)0xaf;
3151     case 0x2153: return (SDL12Key)0xb0;
3152     case 0x2154: return (SDL12Key)0xb1;
3153     case 0x2155: return (SDL12Key)0xb2;
3154     case 0x2156: return (SDL12Key)0xb3;
3155     case 0x2157: return (SDL12Key)0xb4;
3156     case 0x2158: return (SDL12Key)0xb5;
3157     case 0x2159: return (SDL12Key)0xb6;
3158     case 0x215A: return (SDL12Key)0xb7;
3159     case 0x2105: return (SDL12Key)0xb8;
3160     case 0x2012: return (SDL12Key)0xbb;
3161     case 0x27E8: return (SDL12Key)0xbc;
3162     case 0x002E: return (SDL12Key)0xbd;
3163     case 0x27E9: return (SDL12Key)0xbe;
3164     case 0x215B: return (SDL12Key)0xc3;
3165     case 0x215C: return (SDL12Key)0xc4;
3166     case 0x215D: return (SDL12Key)0xc5;
3167     case 0x215E: return (SDL12Key)0xc6;
3168     case 0x2122: return (SDL12Key)0xc9;
3169     case 0x2613: return (SDL12Key)0xca;
3170     case 0x25C1: return (SDL12Key)0xcc;
3171     case 0x25B7: return (SDL12Key)0xcd;
3172     case 0x25CB: return (SDL12Key)0xce;
3173     case 0x25AF: return (SDL12Key)0xcf;
3174     case 0x2018: return (SDL12Key)0xd0;
3175     case 0x2019: return (SDL12Key)0xd1;
3176     case 0x201C: return (SDL12Key)0xd2;
3177     case 0x201D: return (SDL12Key)0xd3;
3178     case 0x211E: return (SDL12Key)0xd4;
3179     case 0x2030: return (SDL12Key)0xd5;
3180     case 0x2032: return (SDL12Key)0xd6;
3181     case 0x2033: return (SDL12Key)0xd7;
3182     case 0x271D: return (SDL12Key)0xd9;
3183     case 0x25AC: return (SDL12Key)0xdb;
3184     case 0x25C0: return (SDL12Key)0xdc;
3185     case 0x25B6: return (SDL12Key)0xdd;
3186     case 0x25CF: return (SDL12Key)0xde;
3187     case 0x25AE: return (SDL12Key)0xdf;
3188     case 0x25E6: return (SDL12Key)0xe0;
3189     case 0x25AB: return (SDL12Key)0xe1;
3190     case 0x25AD: return (SDL12Key)0xe2;
3191     case 0x25B3: return (SDL12Key)0xe3;
3192     case 0x25BD: return (SDL12Key)0xe4;
3193     case 0x2606: return (SDL12Key)0xe5;
3194     case 0x2022: return (SDL12Key)0xe6;
3195     case 0x25AA: return (SDL12Key)0xe7;
3196     case 0x25B2: return (SDL12Key)0xe8;
3197     case 0x25BC: return (SDL12Key)0xe9;
3198     case 0x261C: return (SDL12Key)0xea;
3199     case 0x261E: return (SDL12Key)0xeb;
3200     case 0x2663: return (SDL12Key)0xec;
3201     case 0x2666: return (SDL12Key)0xed;
3202     case 0x2665: return (SDL12Key)0xee;
3203     case 0x2720: return (SDL12Key)0xf0;
3204     case 0x2020: return (SDL12Key)0xf1;
3205     case 0x2021: return (SDL12Key)0xf2;
3206     case 0x2713: return (SDL12Key)0xf3;
3207     case 0x2717: return (SDL12Key)0xf4;
3208     case 0x266F: return (SDL12Key)0xf5;
3209     case 0x266D: return (SDL12Key)0xf6;
3210     case 0x2642: return (SDL12Key)0xf7;
3211     case 0x2640: return (SDL12Key)0xf8;
3212     case 0x260E: return (SDL12Key)0xf9;
3213     case 0x2315: return (SDL12Key)0xfa;
3214     case 0x2117: return (SDL12Key)0xfb;
3215     case 0x2038: return (SDL12Key)0xfc;
3216     case 0x201A: return (SDL12Key)0xfd;
3217     case 0x201E: return (SDL12Key)0xfe;
3218     /* Hebrew */
3219     case 0x2017: return (SDL12Key)0xdf;
3220     case 0x05D0: return (SDL12Key)0xe0;
3221     case 0x05D1: return (SDL12Key)0xe1;
3222     case 0x05D2: return (SDL12Key)0xe2;
3223     case 0x05D3: return (SDL12Key)0xe3;
3224     case 0x05D4: return (SDL12Key)0xe4;
3225     case 0x05D5: return (SDL12Key)0xe5;
3226     case 0x05D6: return (SDL12Key)0xe6;
3227     case 0x05D7: return (SDL12Key)0xe7;
3228     case 0x05D8: return (SDL12Key)0xe8;
3229     case 0x05D9: return (SDL12Key)0xe9;
3230     case 0x05DA: return (SDL12Key)0xea;
3231     case 0x05DB: return (SDL12Key)0xeb;
3232     case 0x05DC: return (SDL12Key)0xec;
3233     case 0x05DD: return (SDL12Key)0xed;
3234     case 0x05DE: return (SDL12Key)0xee;
3235     case 0x05DF: return (SDL12Key)0xef;
3236     case 0x05E0: return (SDL12Key)0xf0;
3237     case 0x05E1: return (SDL12Key)0xf1;
3238     case 0x05E2: return (SDL12Key)0xf2;
3239     case 0x05E3: return (SDL12Key)0xf3;
3240     case 0x05E4: return (SDL12Key)0xf4;
3241     case 0x05E5: return (SDL12Key)0xf5;
3242     case 0x05E6: return (SDL12Key)0xf6;
3243     case 0x05E7: return (SDL12Key)0xf7;
3244     case 0x05E8: return (SDL12Key)0xf8;
3245     case 0x05E9: return (SDL12Key)0xf9;
3246     case 0x05EA: return (SDL12Key)0xfa;
3247     /* Thai */
3248     case 0x0E01: return (SDL12Key)0xa1;
3249     case 0x0E02: return (SDL12Key)0xa2;
3250     case 0x0E03: return (SDL12Key)0xa3;
3251     case 0x0E04: return (SDL12Key)0xa4;
3252     case 0x0E05: return (SDL12Key)0xa5;
3253     case 0x0E06: return (SDL12Key)0xa6;
3254     case 0x0E07: return (SDL12Key)0xa7;
3255     case 0x0E08: return (SDL12Key)0xa8;
3256     case 0x0E09: return (SDL12Key)0xa9;
3257     case 0x0E0A: return (SDL12Key)0xaa;
3258     case 0x0E0B: return (SDL12Key)0xab;
3259     case 0x0E0C: return (SDL12Key)0xac;
3260     case 0x0E0D: return (SDL12Key)0xad;
3261     case 0x0E0E: return (SDL12Key)0xae;
3262     case 0x0E0F: return (SDL12Key)0xaf;
3263     case 0x0E10: return (SDL12Key)0xb0;
3264     case 0x0E11: return (SDL12Key)0xb1;
3265     case 0x0E12: return (SDL12Key)0xb2;
3266     case 0x0E13: return (SDL12Key)0xb3;
3267     case 0x0E14: return (SDL12Key)0xb4;
3268     case 0x0E15: return (SDL12Key)0xb5;
3269     case 0x0E16: return (SDL12Key)0xb6;
3270     case 0x0E17: return (SDL12Key)0xb7;
3271     case 0x0E18: return (SDL12Key)0xb8;
3272     case 0x0E19: return (SDL12Key)0xb9;
3273     case 0x0E1A: return (SDL12Key)0xba;
3274     case 0x0E1B: return (SDL12Key)0xbb;
3275     case 0x0E1C: return (SDL12Key)0xbc;
3276     case 0x0E1D: return (SDL12Key)0xbd;
3277     case 0x0E1E: return (SDL12Key)0xbe;
3278     case 0x0E1F: return (SDL12Key)0xbf;
3279     case 0x0E20: return (SDL12Key)0xc0;
3280     case 0x0E21: return (SDL12Key)0xc1;
3281     case 0x0E22: return (SDL12Key)0xc2;
3282     case 0x0E23: return (SDL12Key)0xc3;
3283     case 0x0E24: return (SDL12Key)0xc4;
3284     case 0x0E25: return (SDL12Key)0xc5;
3285     case 0x0E26: return (SDL12Key)0xc6;
3286     case 0x0E27: return (SDL12Key)0xc7;
3287     case 0x0E28: return (SDL12Key)0xc8;
3288     case 0x0E29: return (SDL12Key)0xc9;
3289     case 0x0E2A: return (SDL12Key)0xca;
3290     case 0x0E2B: return (SDL12Key)0xcb;
3291     case 0x0E2C: return (SDL12Key)0xcc;
3292     case 0x0E2D: return (SDL12Key)0xcd;
3293     case 0x0E2E: return (SDL12Key)0xce;
3294     case 0x0E2F: return (SDL12Key)0xcf;
3295     case 0x0E30: return (SDL12Key)0xd0;
3296     case 0x0E31: return (SDL12Key)0xd1;
3297     case 0x0E32: return (SDL12Key)0xd2;
3298     case 0x0E33: return (SDL12Key)0xd3;
3299     case 0x0E34: return (SDL12Key)0xd4;
3300     case 0x0E35: return (SDL12Key)0xd5;
3301     case 0x0E36: return (SDL12Key)0xd6;
3302     case 0x0E37: return (SDL12Key)0xd7;
3303     case 0x0E38: return (SDL12Key)0xd8;
3304     case 0x0E39: return (SDL12Key)0xd9;
3305     case 0x0E3A: return (SDL12Key)0xda;
3306     case 0x0E3F: return (SDL12Key)0xdf;
3307     case 0x0E40: return (SDL12Key)0xe0;
3308     case 0x0E41: return (SDL12Key)0xe1;
3309     case 0x0E42: return (SDL12Key)0xe2;
3310     case 0x0E43: return (SDL12Key)0xe3;
3311     case 0x0E44: return (SDL12Key)0xe4;
3312     case 0x0E45: return (SDL12Key)0xe5;
3313     case 0x0E46: return (SDL12Key)0xe6;
3314     case 0x0E47: return (SDL12Key)0xe7;
3315     case 0x0E48: return (SDL12Key)0xe8;
3316     case 0x0E49: return (SDL12Key)0xe9;
3317     case 0x0E4A: return (SDL12Key)0xea;
3318     case 0x0E4B: return (SDL12Key)0xeb;
3319     case 0x0E4C: return (SDL12Key)0xec;
3320     case 0x0E4D: return (SDL12Key)0xed;
3321     case 0x0E50: return (SDL12Key)0xf0;
3322     case 0x0E51: return (SDL12Key)0xf1;
3323     case 0x0E52: return (SDL12Key)0xf2;
3324     case 0x0E53: return (SDL12Key)0xf3;
3325     case 0x0E54: return (SDL12Key)0xf4;
3326     case 0x0E55: return (SDL12Key)0xf5;
3327     case 0x0E56: return (SDL12Key)0xf6;
3328     case 0x0E57: return (SDL12Key)0xf7;
3329     case 0x0E58: return (SDL12Key)0xf8;
3330     case 0x0E59: return (SDL12Key)0xf9;
3331     /* end of SDLK_WORLD_ keys based on Latin-* or similar High-ASCII charsets
3332      * and the low byte of their corresponding X11 XK_* KeySyms */
3333     default: break;
3334     }
3335 
3336     FIXME("nothing maps to SDLK12_COMPOSE, SDLK12_BREAK, or SDLK12_EURO ...?");
3337     return SDLK12_UNKNOWN;
3338 }
3339 static SDL12Key
Scancode20toKeysym12(const SDL_Scancode scancode20)3340 Scancode20toKeysym12(const SDL_Scancode scancode20)
3341 {
3342     switch (scancode20) {
3343     #define CASESCANCODE20TOKEY12(s20, k12) case SDL_SCANCODE_##s20: return SDLK12_##k12
3344     CASESCANCODE20TOKEY12(A,a);
3345     CASESCANCODE20TOKEY12(B,b);
3346     CASESCANCODE20TOKEY12(C,c);
3347     CASESCANCODE20TOKEY12(D,d);
3348     CASESCANCODE20TOKEY12(E,e);
3349     CASESCANCODE20TOKEY12(F,f);
3350     CASESCANCODE20TOKEY12(G,g);
3351     CASESCANCODE20TOKEY12(H,h);
3352     CASESCANCODE20TOKEY12(I,i);
3353     CASESCANCODE20TOKEY12(J,j);
3354     CASESCANCODE20TOKEY12(K,k);
3355     CASESCANCODE20TOKEY12(L,l);
3356     CASESCANCODE20TOKEY12(M,m);
3357     CASESCANCODE20TOKEY12(N,n);
3358     CASESCANCODE20TOKEY12(O,o);
3359     CASESCANCODE20TOKEY12(P,p);
3360     CASESCANCODE20TOKEY12(Q,q);
3361     CASESCANCODE20TOKEY12(R,r);
3362     CASESCANCODE20TOKEY12(S,s);
3363     CASESCANCODE20TOKEY12(T,t);
3364     CASESCANCODE20TOKEY12(U,u);
3365     CASESCANCODE20TOKEY12(V,v);
3366     CASESCANCODE20TOKEY12(W,w);
3367     CASESCANCODE20TOKEY12(X,x);
3368     CASESCANCODE20TOKEY12(Y,y);
3369     CASESCANCODE20TOKEY12(Z,z);
3370     CASESCANCODE20TOKEY12(1,1);
3371     CASESCANCODE20TOKEY12(2,2);
3372     CASESCANCODE20TOKEY12(3,3);
3373     CASESCANCODE20TOKEY12(4,4);
3374     CASESCANCODE20TOKEY12(5,5);
3375     CASESCANCODE20TOKEY12(6,6);
3376     CASESCANCODE20TOKEY12(7,7);
3377     CASESCANCODE20TOKEY12(8,8);
3378     CASESCANCODE20TOKEY12(9,9);
3379     CASESCANCODE20TOKEY12(0,0);
3380     CASESCANCODE20TOKEY12(RETURN,RETURN);
3381     CASESCANCODE20TOKEY12(ESCAPE,ESCAPE);
3382     CASESCANCODE20TOKEY12(BACKSPACE,BACKSPACE);
3383     CASESCANCODE20TOKEY12(TAB,TAB);
3384     CASESCANCODE20TOKEY12(SPACE,SPACE);
3385     CASESCANCODE20TOKEY12(MINUS,MINUS);
3386     CASESCANCODE20TOKEY12(EQUALS,EQUALS);
3387     CASESCANCODE20TOKEY12(LEFTBRACKET,LEFTBRACKET);
3388     CASESCANCODE20TOKEY12(RIGHTBRACKET,RIGHTBRACKET);
3389     CASESCANCODE20TOKEY12(BACKSLASH,BACKSLASH);
3390     CASESCANCODE20TOKEY12(NONUSHASH,HASH);
3391     CASESCANCODE20TOKEY12(SEMICOLON,SEMICOLON);
3392     CASESCANCODE20TOKEY12(APOSTROPHE,QUOTE);
3393     CASESCANCODE20TOKEY12(GRAVE,BACKQUOTE);
3394     CASESCANCODE20TOKEY12(COMMA,COMMA);
3395     CASESCANCODE20TOKEY12(PERIOD,PERIOD);
3396     CASESCANCODE20TOKEY12(SLASH,SLASH);
3397     CASESCANCODE20TOKEY12(CAPSLOCK,CAPSLOCK);
3398     CASESCANCODE20TOKEY12(F1,F1);
3399     CASESCANCODE20TOKEY12(F2,F2);
3400     CASESCANCODE20TOKEY12(F3,F3);
3401     CASESCANCODE20TOKEY12(F4,F4);
3402     CASESCANCODE20TOKEY12(F5,F5);
3403     CASESCANCODE20TOKEY12(F6,F6);
3404     CASESCANCODE20TOKEY12(F7,F7);
3405     CASESCANCODE20TOKEY12(F8,F8);
3406     CASESCANCODE20TOKEY12(F9,F9);
3407     CASESCANCODE20TOKEY12(F10,F10);
3408     CASESCANCODE20TOKEY12(F11,F11);
3409     CASESCANCODE20TOKEY12(F12,F12);
3410     CASESCANCODE20TOKEY12(PRINTSCREEN,PRINT);
3411     CASESCANCODE20TOKEY12(SCROLLLOCK,SCROLLOCK);
3412     CASESCANCODE20TOKEY12(PAUSE,PAUSE);
3413     CASESCANCODE20TOKEY12(INSERT,INSERT);
3414     CASESCANCODE20TOKEY12(HOME,HOME);
3415     CASESCANCODE20TOKEY12(PAGEUP,PAGEUP);
3416     CASESCANCODE20TOKEY12(DELETE,DELETE);
3417     CASESCANCODE20TOKEY12(END,END);
3418     CASESCANCODE20TOKEY12(PAGEDOWN,PAGEDOWN);
3419     CASESCANCODE20TOKEY12(RIGHT,RIGHT);
3420     CASESCANCODE20TOKEY12(LEFT,LEFT);
3421     CASESCANCODE20TOKEY12(DOWN,DOWN);
3422     CASESCANCODE20TOKEY12(UP,UP);
3423     CASESCANCODE20TOKEY12(NUMLOCKCLEAR,NUMLOCK);
3424 
3425     CASESCANCODE20TOKEY12(KP_DIVIDE,KP_DIVIDE);
3426     CASESCANCODE20TOKEY12(KP_MULTIPLY,KP_MULTIPLY);
3427     CASESCANCODE20TOKEY12(KP_MINUS,KP_MINUS);
3428     CASESCANCODE20TOKEY12(KP_PLUS,KP_PLUS);
3429     CASESCANCODE20TOKEY12(KP_ENTER,KP_ENTER);
3430     CASESCANCODE20TOKEY12(KP_1,KP1);
3431     CASESCANCODE20TOKEY12(KP_2,KP2);
3432     CASESCANCODE20TOKEY12(KP_3,KP3);
3433     CASESCANCODE20TOKEY12(KP_4,KP4);
3434     CASESCANCODE20TOKEY12(KP_5,KP5);
3435     CASESCANCODE20TOKEY12(KP_6,KP6);
3436     CASESCANCODE20TOKEY12(KP_7,KP7);
3437     CASESCANCODE20TOKEY12(KP_8,KP8);
3438     CASESCANCODE20TOKEY12(KP_9,KP9);
3439     CASESCANCODE20TOKEY12(KP_0,KP0);
3440 
3441     CASESCANCODE20TOKEY12(NONUSBACKSLASH,BACKSLASH);
3442     /* In theory, this could be MENU, or COMPOSE, or neither, but on my machine, it's MENU. */
3443     CASESCANCODE20TOKEY12(APPLICATION,MENU);
3444     CASESCANCODE20TOKEY12(POWER,POWER);
3445     CASESCANCODE20TOKEY12(F13,F13);
3446     CASESCANCODE20TOKEY12(F14,F14);
3447     CASESCANCODE20TOKEY12(F15,F15);
3448     CASESCANCODE20TOKEY12(KP_EQUALS,KP_EQUALS);
3449     /* SDL 1.2 doesn't support F16..F21 */
3450     /* Nor SDL_SCANCODE_EXECUTE */
3451     CASESCANCODE20TOKEY12(HELP,HELP);
3452     CASESCANCODE20TOKEY12(MENU,MENU);
3453     /* The next several scancodes don't have equivalents, until... */
3454     CASESCANCODE20TOKEY12(SYSREQ,SYSREQ);
3455     CASESCANCODE20TOKEY12(CLEAR,CLEAR);
3456     /* Skip some more... */
3457     CASESCANCODE20TOKEY12(LCTRL,LCTRL);
3458     CASESCANCODE20TOKEY12(LSHIFT,LSHIFT);
3459     CASESCANCODE20TOKEY12(LALT,LALT);
3460 #ifdef __MACOSX__
3461     CASESCANCODE20TOKEY12(LGUI,LMETA);
3462 #else
3463     CASESCANCODE20TOKEY12(LGUI,LSUPER);
3464 #endif
3465     CASESCANCODE20TOKEY12(RCTRL,RCTRL);
3466     CASESCANCODE20TOKEY12(RSHIFT,RSHIFT);
3467     CASESCANCODE20TOKEY12(RALT,RALT);
3468 #ifdef __MACOSX__
3469     CASESCANCODE20TOKEY12(RGUI,RMETA);
3470 #else
3471     CASESCANCODE20TOKEY12(RGUI,RSUPER);
3472 #endif
3473 
3474     CASESCANCODE20TOKEY12(MODE,MODE);
3475     #undef CASESCANCODE20TOKEY12
3476     default: break;
3477     }
3478 
3479     FIXME("nothing maps to SDLK12_BREAK, or SDLK12_EURO ...?");
3480     FIXME("map some of the SDLK12_WORLD keys");
3481     return SDLK12_UNKNOWN;
3482 }
3483 
3484 static Uint8
Scancode20to12(SDL_Scancode sc)3485 Scancode20to12(SDL_Scancode sc)
3486 {
3487     /* SDL 1.2 scancodes are the actual raw scancodes (for the most part), and
3488        so differ wildly between different systems. Fortunately, this means
3489        they're rarely used, and often have fallbacks. Here, we support them
3490        for three systems: Win32, Mac OS X, and a synthesized pseudo-Linux that
3491        should work.
3492        Windows scancodes are bascially just Linux ones - 8. OS X has a totally
3493        different set of scancodes from everyone else. Linux's scancodes change
3494        depending on what driver you're using, but only really for a few keys.
3495        Since there are applications (DOSBox) which look this up and behave
3496        accordingly, but have fallbacks, those keys have scancodes of 0 here,
3497        to trigger the fallbacks. */
3498     switch(sc) {
3499 #if defined(_WIN32)
3500 #define CASESCANCODE20TO12(sc20, sc12, sc12mac) case SDL_SCANCODE_##sc20: return (sc12 ? (sc12 - 8) : 0)
3501 #elif defined(__MACOSX__)
3502 #define CASESCANCODE20TO12(sc20, sc12, sc12mac) case SDL_SCANCODE_##sc20: return sc12mac
3503 #else
3504 #define CASESCANCODE20TO12(sc20, sc12, sc12mac) case SDL_SCANCODE_##sc20: return sc12
3505 #endif
3506     CASESCANCODE20TO12(0, 0x13, 0x1D);
3507     CASESCANCODE20TO12(1, 0x0A, 0x12);
3508     CASESCANCODE20TO12(2, 0x0B, 0x13);
3509     CASESCANCODE20TO12(3, 0x0C, 0x14);
3510     CASESCANCODE20TO12(4, 0x0D, 0x15);
3511     CASESCANCODE20TO12(5, 0x0E, 0x17);
3512     CASESCANCODE20TO12(6, 0x0F, 0x16);
3513     CASESCANCODE20TO12(7, 0x10, 0x1A);
3514     CASESCANCODE20TO12(8, 0x11, 0x1C);
3515     CASESCANCODE20TO12(9, 0x12, 0x19);
3516     CASESCANCODE20TO12(A, 0x26, 0x00);
3517     CASESCANCODE20TO12(APOSTROPHE, 0x30, 0x27);
3518     CASESCANCODE20TO12(B, 0x38, 0x0B);
3519     CASESCANCODE20TO12(BACKSLASH, 0x33, 0x2A);
3520     CASESCANCODE20TO12(BACKSPACE, 0x16, 0x33);
3521     CASESCANCODE20TO12(C, 0x36, 0x08);
3522     CASESCANCODE20TO12(CAPSLOCK, 0x42, 0x00);
3523     CASESCANCODE20TO12(COMMA, 0x3B, 0x2B);
3524     CASESCANCODE20TO12(D, 0x28, 0x02);
3525     CASESCANCODE20TO12(DELETE, 0x00, 0x75);
3526     CASESCANCODE20TO12(DOWN, 0x00, 0x7D);
3527     CASESCANCODE20TO12(E, 0x1A, 0x0E);
3528     CASESCANCODE20TO12(END, 0x00, 0x77);
3529     CASESCANCODE20TO12(EQUALS, 0x15, 0x18);
3530     CASESCANCODE20TO12(ESCAPE, 0x09, 0x35);
3531     CASESCANCODE20TO12(F, 0x29, 0x03);
3532     CASESCANCODE20TO12(F1, 0x43, 0x7A);
3533     CASESCANCODE20TO12(F10, 0x4C, 0x6E);
3534     CASESCANCODE20TO12(F11, 0x5F, 0x67);
3535     CASESCANCODE20TO12(F12, 0x60, 0x6F);
3536     CASESCANCODE20TO12(F2, 0x44, 0x78);
3537     CASESCANCODE20TO12(F3, 0x45, 0x63);
3538     CASESCANCODE20TO12(F4, 0x46, 0x76);
3539     CASESCANCODE20TO12(F5, 0x47, 0x60);
3540     CASESCANCODE20TO12(F6, 0x48, 0x61);
3541     CASESCANCODE20TO12(F7, 0x49, 0x62);
3542     CASESCANCODE20TO12(F8, 0x4A, 0x64);
3543     CASESCANCODE20TO12(F9, 0x4B, 0x65);
3544     CASESCANCODE20TO12(G, 0x2A, 0x05);
3545     CASESCANCODE20TO12(GRAVE, 0x31, 0x32); /* Note: the mac scancode might not be 100% correct, see below */
3546     CASESCANCODE20TO12(H, 0x2B, 0x04);
3547     CASESCANCODE20TO12(HOME, 0x00, 0x73);
3548     CASESCANCODE20TO12(I, 0x1F, 0x22);
3549     CASESCANCODE20TO12(INSERT, 0x00, 0x72);
3550     CASESCANCODE20TO12(J, 0x2C, 0x26);
3551     CASESCANCODE20TO12(K, 0x2D, 0x28);
3552     CASESCANCODE20TO12(KP_0, 0x5A, 0x52);
3553     CASESCANCODE20TO12(KP_1, 0x57, 0x53);
3554     CASESCANCODE20TO12(KP_2, 0x58, 0x54);
3555     CASESCANCODE20TO12(KP_3, 0x59, 0x55);
3556     CASESCANCODE20TO12(KP_4, 0x53, 0x56);
3557     CASESCANCODE20TO12(KP_5, 0x54, 0x57);
3558     CASESCANCODE20TO12(KP_6, 0x55, 0x58);
3559     CASESCANCODE20TO12(KP_7, 0x4F, 0x59);
3560     CASESCANCODE20TO12(KP_8, 0x50, 0x5B);
3561     CASESCANCODE20TO12(KP_9, 0x51, 0x5C);
3562     CASESCANCODE20TO12(KP_DIVIDE, 0x00, 0x4B);
3563     CASESCANCODE20TO12(KP_ENTER, 0x00, 0x4C);
3564     CASESCANCODE20TO12(KP_EQUALS, 0x00, 0x51);
3565     CASESCANCODE20TO12(KP_MINUS, 0x52, 0x4E);
3566     CASESCANCODE20TO12(KP_MULTIPLY, 0x3F, 0x43);
3567     CASESCANCODE20TO12(KP_PERIOD, 0x5B, 0x41);
3568     CASESCANCODE20TO12(KP_PLUS, 0x56, 0x45);
3569     CASESCANCODE20TO12(L, 0x2E, 0x25);
3570     CASESCANCODE20TO12(LALT, 0x40, 0x00);
3571     CASESCANCODE20TO12(LCTRL, 0x25, 0x00);
3572     CASESCANCODE20TO12(LEFT, 0x00, 0x7B);
3573     CASESCANCODE20TO12(LEFTBRACKET, 0x22, 0x21);
3574     CASESCANCODE20TO12(LGUI, 0x85, 0x00);
3575     CASESCANCODE20TO12(LSHIFT, 0x32, 0x00);
3576     CASESCANCODE20TO12(M, 0x3A, 0x2E);
3577     CASESCANCODE20TO12(MINUS, 0x14, 0x1B);
3578     CASESCANCODE20TO12(N, 0x39, 0x2D);
3579     /* On Macs with ANSI layout, 0x32 is SDL_SCANCODE_GRAVE and _NONUSBACKSLASH doesn't exist.
3580      * On Macs with ISO layout, 0x32 is _NONUSBACKSLASH and 0x0A is the key at the position of _GRAVE..
3581      * Probably it's best to keep _GRAVE at 0x32 and use 0x0A for _NONUSBACKSLASH instead,
3582      * so at least it has a unique scancode at all. */
3583     CASESCANCODE20TO12(NONUSBACKSLASH, 0x5E, 0x0A);
3584     CASESCANCODE20TO12(NUMLOCKCLEAR, 0x4D, 0x47);
3585     CASESCANCODE20TO12(O, 0x20, 0x1F);
3586     CASESCANCODE20TO12(P, 0x21, 0x23);
3587     CASESCANCODE20TO12(PAGEDOWN, 0x00, 0x79);
3588     CASESCANCODE20TO12(PAGEUP, 0x00, 0x74);
3589     CASESCANCODE20TO12(PERIOD, 0x3C, 0x2F);
3590     CASESCANCODE20TO12(PRINTSCREEN, 0x6B, 0x6B);
3591     CASESCANCODE20TO12(Q, 0x18, 0x0C);
3592     CASESCANCODE20TO12(R, 0x1B, 0x0F);
3593     CASESCANCODE20TO12(RETURN, 0x24, 0x24);
3594     CASESCANCODE20TO12(RGUI, 0x86, 0x00);
3595     CASESCANCODE20TO12(RIGHT, 0x00, 0x7C);
3596     CASESCANCODE20TO12(RIGHTBRACKET, 0x23, 0x1E);
3597     CASESCANCODE20TO12(RSHIFT, 0x3E, 0x00);
3598     CASESCANCODE20TO12(S, 0x27, 0x01);
3599     CASESCANCODE20TO12(SCROLLLOCK, 0x4E, 0x71);
3600     CASESCANCODE20TO12(SEMICOLON, 0x2F, 0x29);
3601     CASESCANCODE20TO12(SLASH, 0x3D, 0x2C);
3602     CASESCANCODE20TO12(SPACE, 0x41, 0x31);
3603     CASESCANCODE20TO12(T, 0x1C, 0x11);
3604     CASESCANCODE20TO12(TAB, 0x17, 0x30);
3605     CASESCANCODE20TO12(U, 0x1E, 0x20);
3606     CASESCANCODE20TO12(UP, 0x00, 0x7E);
3607     CASESCANCODE20TO12(V, 0x37, 0x09);
3608     CASESCANCODE20TO12(W, 0x19, 0x0D);
3609     CASESCANCODE20TO12(X, 0x35, 0x07);
3610     CASESCANCODE20TO12(Y, 0x1D, 0x10);
3611     CASESCANCODE20TO12(Z, 0x34, 0x06);
3612 #undef CASESCANCODE20TO12
3613     default:
3614         /* If we don't know it, return 0, which is "unknown".
3615            It's also "a" on Mac OS X, but SDL 1.2 uses it as "unknown", too. */
3616         return 0;
3617     }
3618 }
3619 
3620 DECLSPEC Uint8 * SDLCALL
SDL_GetKeyState(int * numkeys)3621 SDL_GetKeyState(int *numkeys)
3622 {
3623     if (numkeys) {
3624         *numkeys = (int) SDL_arraysize(KeyState);
3625     }
3626     return KeyState;
3627 }
3628 
DecodeUTF8Char(char ** ptr)3629 static int DecodeUTF8Char(char **ptr)
3630 {
3631     Uint32 first_c = **(unsigned char **)ptr;
3632     int num_bytes = (first_c) ? (31 - SDL20_MostSignificantBitIndex32(~(first_c << 24))) : 0;
3633     Uint32 value = first_c & ((1 << (8 - num_bytes)) - 1);
3634     int i;
3635 
3636     (*ptr)++;
3637     for (i = 1; i < num_bytes; ++i) {
3638         value = (value << 6) | (**(unsigned char **)ptr & 0x3f);
3639         (*ptr)++;
3640     }
3641     return value;
3642 }
3643 
3644 /* Add the pending KEYDOWN event to the EventQueue, possibly with 'unicode' set
3645  * Returns 1 if there was a pending event. */
FlushPendingKeydownEvent(Uint32 unicode)3646 static int FlushPendingKeydownEvent(Uint32 unicode)
3647 {
3648     if (PendingKeydownEvent.type != SDL12_KEYDOWN) {
3649         return 0;
3650     }
3651 
3652     PendingKeydownEvent.key.keysym.unicode = unicode;
3653     PushEventIfNotFiltered(&PendingKeydownEvent);
3654     /* Reset the event. */
3655     SDL20_memset(&PendingKeydownEvent, 0, sizeof(SDL12_Event));
3656 
3657     return 1;
3658 }
3659 
3660 static int SDLCALL
EventFilter20to12(void * data,SDL_Event * event20)3661 EventFilter20to12(void *data, SDL_Event *event20)
3662 {
3663     SDL12_Event event12;
3664     SDL12_SysWMmsg msg;
3665 
3666     SDL_assert(data == NULL);  /* currently unused. */
3667 
3668     SDL20_zero(event12);
3669 
3670     switch (event20->type) {
3671         case SDL_QUIT:
3672             event12.type = SDL12_QUIT;
3673             break;
3674 
3675         case SDL_WINDOWEVENT:
3676             switch (event20->window.event) {
3677                 /* don't send an SDL12_QUIT event for SDL_WINDOWEVENT_CLOSE;
3678                    we only ever have a single window, so an SDL_QUIT will be
3679                    coming from SDL2 next anyhow, so just send that on. */
3680 
3681                 case SDL_WINDOWEVENT_SHOWN:
3682                 case SDL_WINDOWEVENT_EXPOSED:
3683                     event12.type = SDL12_VIDEOEXPOSE;
3684                     break;
3685 
3686                 case SDL_WINDOWEVENT_RESIZED:
3687                     /* don't generate a VIDEORESIZE event based on SIZE_CHANGED
3688                        events: the recommended way to handle VIDEORESIZE is
3689                        with a new SDL_SetVideoMode() call, and creating a new
3690                        window generates a SIZE_CHANGED event, which leads to an
3691                        infinite loop. */
3692 
3693                     /* don't report VIDEORESIZE if we're fullscreen-desktop;
3694                        we're doing logical scaling and as far as the app is
3695                        concerned the window doesn't change. */
3696                     if (!VideoWindow20) {
3697                         FIXME("we should probably drop a lot of these events.");
3698                         break;  /* there's no window? Drop this event. */
3699                     } else {
3700                         const Uint32 flags = SDL20_GetWindowFlags(VideoWindow20);
3701                         if ((flags & SDL_WINDOW_FULLSCREEN_DESKTOP) == SDL_WINDOW_FULLSCREEN_DESKTOP) {
3702                             break;
3703                         }
3704                     }
3705 
3706                     event12.type = SDL12_VIDEORESIZE;
3707                     event12.resize.w = event20->window.data1;
3708                     event12.resize.h = event20->window.data2;
3709                     break;
3710 
3711                 case SDL_WINDOWEVENT_MINIMIZED:
3712                     event12.type = SDL12_ACTIVEEVENT;
3713                     event12.active.gain = 0;
3714                     event12.active.state = SDL12_APPACTIVE;
3715                     break;
3716 
3717                 case SDL_WINDOWEVENT_RESTORED:
3718                     event12.type = SDL12_ACTIVEEVENT;
3719                     event12.active.gain = 1;
3720                     event12.active.state = SDL12_APPACTIVE;
3721                     break;
3722 
3723                 case SDL_WINDOWEVENT_ENTER:
3724                     event12.type = SDL12_ACTIVEEVENT;
3725                     event12.active.gain = 1;
3726                     event12.active.state = SDL12_APPMOUSEFOCUS;
3727                     break;
3728 
3729                 case SDL_WINDOWEVENT_LEAVE:
3730                     event12.type = SDL12_ACTIVEEVENT;
3731                     event12.active.gain = 0;
3732                     event12.active.state = SDL12_APPMOUSEFOCUS;
3733                     break;
3734 
3735                 case SDL_WINDOWEVENT_FOCUS_GAINED:
3736                     event12.type = SDL12_ACTIVEEVENT;
3737                     event12.active.gain = 1;
3738                     event12.active.state = SDL12_APPINPUTFOCUS;
3739                     break;
3740 
3741                 case SDL_WINDOWEVENT_FOCUS_LOST:
3742                     event12.type = SDL12_ACTIVEEVENT;
3743                     event12.active.gain = 0;
3744                     event12.active.state = SDL12_APPINPUTFOCUS;
3745                     break;
3746             }
3747             break;
3748 
3749         case SDL_SYSWMEVENT:
3750             if (!SupportSysWM) {
3751                 return 1;
3752             }
3753 
3754             #if defined(SDL_VIDEO_DRIVER_WINDOWS)
3755                 SDL_assert(event20->syswm.msg->subsystem == SDL_SYSWM_WINDOWS);
3756                 msg.hwnd = event20->syswm.msg->msg.win.hwnd;
3757                 msg.msg = event20->syswm.msg->msg.win.msg;
3758                 msg.wParam = event20->syswm.msg->msg.win.wParam;
3759                 msg.lParam = event20->syswm.msg->msg.win.lParam;
3760             #elif defined(SDL_VIDEO_DRIVER_X11)
3761                 SDL_assert(event20->syswm.msg->subsystem == SDL_SYSWM_X11);
3762                 msg.subsystem = SDL12_SYSWM_X11;
3763                 SDL20_memcpy(&msg.event.xevent, &event20->syswm.msg->msg.x11.event, sizeof (XEvent));
3764             #else
3765                 SDL_assert(!"should have been caught by !SupportsSysWM test");
3766             #endif
3767 
3768             SDL20_memcpy(&msg.version, SDL_Linked_Version(), sizeof (msg.version));
3769             event12.type = SDL12_SYSWMEVENT;
3770             event12.syswm.msg = &msg;  /* this is stack-allocated, but we copy and update the pointer later. */
3771             break;
3772 
3773         case SDL_KEYUP:
3774             if (event20->key.repeat) {
3775                 return 1;  /* ignore 2.0-style key repeat events */
3776             }
3777 
3778             if (TranslateKeyboardLayout) {
3779                 event12.key.keysym.sym = Keysym20to12(event20->key.keysym.sym);
3780             } else {
3781                 event12.key.keysym.sym = Scancode20toKeysym12(event20->key.keysym.scancode);
3782             }
3783 
3784             KeyState[event12.key.keysym.sym] = event20->key.state;
3785 
3786             event12.type = (event20->type == SDL_KEYDOWN) ? SDL12_KEYDOWN : SDL12_KEYUP;
3787             event12.key.which = 0;
3788             event12.key.state = event20->key.state;
3789             /* turns out that some apps actually made use of the hardware scancodes (checking for platform beforehand) */
3790             event12.key.keysym.scancode = Scancode20to12(event20->key.keysym.scancode);
3791             event12.key.keysym.mod = event20->key.keysym.mod;  /* these match up between 1.2 and 2.0! */
3792             event12.key.keysym.unicode = 0;
3793 
3794             /* If there's a pending KEYDOWN event, flush it on KEYUP. */
3795             FlushPendingKeydownEvent(0);
3796             break;
3797 
3798         case SDL_KEYDOWN:
3799             FlushPendingKeydownEvent(0);
3800             if (event20->key.repeat && !EnabledKeyRepeat) {
3801                 return 1;  /* ignore 2.0-style key repeat events */
3802             }
3803 
3804             if (TranslateKeyboardLayout) {
3805                 PendingKeydownEvent.key.keysym.sym = Keysym20to12(event20->key.keysym.sym);
3806             } else {
3807                 PendingKeydownEvent.key.keysym.sym = Scancode20toKeysym12(event20->key.keysym.scancode);
3808             }
3809 
3810             KeyState[PendingKeydownEvent.key.keysym.sym] = event20->key.state;
3811 
3812             PendingKeydownEvent.type = (event20->type == SDL_KEYDOWN) ? SDL12_KEYDOWN : SDL12_KEYUP;
3813             PendingKeydownEvent.key.which = 0;
3814             PendingKeydownEvent.key.state = event20->key.state;
3815             /* turns out that some apps actually made use of the hardware scancodes (checking for platform beforehand) */
3816             PendingKeydownEvent.key.keysym.scancode = Scancode20to12(event20->key.keysym.scancode);
3817             PendingKeydownEvent.key.keysym.mod = event20->key.keysym.mod;  /* these match up between 1.2 and 2.0! */
3818             PendingKeydownEvent.key.keysym.unicode = 0;
3819 
3820             /* If Unicode is not enabled, flush all KEYDOWN events immediately. */
3821             if (!EnabledUnicode) {
3822                 FlushPendingKeydownEvent(0);
3823                 return 1;
3824             }
3825 
3826             /* some programs rely on unicode values for these control characters */
3827             switch (PendingKeydownEvent.key.keysym.sym)
3828             {
3829                 case SDLK12_BACKSPACE:
3830                     FlushPendingKeydownEvent('\b');
3831                     break;
3832                 case SDLK12_TAB:
3833                     FlushPendingKeydownEvent('\t');
3834                     break;
3835                 case SDLK12_RETURN:
3836                 case SDLK12_KP_ENTER:
3837                     /* Enter: \r, Shift+Enter: \n */
3838                     if (PendingKeydownEvent.key.keysym.mod & KMOD_SHIFT)
3839                         FlushPendingKeydownEvent('\n');
3840                     else
3841                         FlushPendingKeydownEvent('\r');
3842                     break;
3843                 case SDLK12_ESCAPE:
3844                     FlushPendingKeydownEvent(0x1B); /* '\e' */
3845                     break;
3846                 default:
3847                     /* not a supported control character */
3848                     break;
3849             }
3850 
3851             return 1;
3852 
3853         case SDL_TEXTEDITING: return 1;
3854         case SDL_TEXTINPUT: {
3855             char *text = event20->text.text;
3856             int codePoint;
3857             while ((codePoint = DecodeUTF8Char(&text)) != 0) {
3858                 if (codePoint > 0xFFFF) {
3859                     /* We need to send a UTF-16 surrogate pair. */
3860                     Uint16 firstChar = ((codePoint - 0x10000) >> 10) + 0xD800;
3861                     Uint16 secondChar = ((codePoint - 0x10000) & 0x3FF) + 0xDC00;
3862                     event12.type = SDL12_KEYDOWN;
3863                     event12.key.state = SDL12_PRESSED;
3864                     event12.key.keysym.scancode = 0;
3865                     event12.key.keysym.sym = SDLK12_UNKNOWN;
3866                     event12.key.keysym.unicode = firstChar;
3867                     if (!FlushPendingKeydownEvent(firstChar)) {
3868                          PushEventIfNotFiltered(&event12);
3869                     }
3870                     event12.key.keysym.unicode = secondChar;
3871                     PushEventIfNotFiltered(&event12);
3872                 } else {
3873                     if (!FlushPendingKeydownEvent(codePoint)) {
3874                         event12.type = SDL12_KEYDOWN;
3875                         event12.key.state = SDL12_PRESSED;
3876                         event12.key.keysym.scancode = 0;
3877                         event12.key.keysym.sym = SDLK12_UNKNOWN;
3878                         event12.key.keysym.unicode = codePoint;
3879                         PushEventIfNotFiltered(&event12);
3880                     }
3881                 }
3882             }
3883           }
3884           return 1;
3885 
3886         case SDL_MOUSEMOTION:
3887             event12.type = SDL12_MOUSEMOTION;
3888             event12.motion.which = (Uint8) event20->motion.which;
3889             event12.motion.state = event20->motion.state;
3890             AdjustOpenGLLogicalScalingPoint(&event20->motion.x, &event20->motion.y);
3891             event12.motion.x = (Uint16) event20->motion.x;
3892             event12.motion.y = (Uint16) event20->motion.y;
3893             if (UseMouseRelativeScaling) {
3894                 AdjustOpenGLLogicalScalingVector(&event20->motion.xrel,
3895                                                  &event20->motion.yrel,
3896                                                  &MouseRelativeRemainder.x,
3897                                                  &MouseRelativeRemainder.y);
3898             }
3899             event12.motion.xrel = (Sint16) event20->motion.xrel;
3900             event12.motion.yrel = (Sint16) event20->motion.yrel;
3901             if (MouseInputIsRelative) {
3902                 /* in relative mode, clamp fake absolute position to the window dimensions. */
3903                 #define ADJUST_RELATIVE(axis, rel, dim) { \
3904                     MousePosition.axis += event20->motion.rel; \
3905                     if (MousePosition.axis <= 0) { \
3906                         MousePosition.axis = 0; \
3907                     } else if (MousePosition.axis >= VideoSurface12->dim) { \
3908                         MousePosition.axis = (VideoSurface12->dim - 1); \
3909                     } \
3910                     event12.motion.axis = MousePosition.axis; \
3911                 }
3912                 ADJUST_RELATIVE(x, xrel, w);
3913                 ADJUST_RELATIVE(y, yrel, h);
3914                 #undef ADJUST_RELATIVE
3915             } else {
3916                 MousePosition.x = event12.motion.x;
3917                 MousePosition.y = event12.motion.y;
3918             }
3919             break;
3920 
3921         case SDL_MOUSEBUTTONDOWN:
3922             event12.type = SDL12_MOUSEBUTTONDOWN;
3923             event12.button.which = (Uint8) event20->button.which;
3924             event12.button.button = event20->button.button;
3925             if (event12.button.button > 3) {
3926                 event12.button.button += 2; /* SDL_BUTTON_X1/2 */
3927             }
3928             event12.button.state = event20->button.state;
3929             if (MouseInputIsRelative) {
3930                 /* If we're using relative mouse input, we need to use our "fake" position. */
3931                 event12.button.x = MousePosition.x;
3932                 event12.button.y = MousePosition.y;
3933             } else {
3934                 AdjustOpenGLLogicalScalingPoint(&event20->button.x, &event20->button.y);
3935                 event12.button.x = (Uint16) event20->button.x;
3936                 event12.button.y = (Uint16) event20->button.y;
3937             }
3938             break;
3939 
3940         case SDL_MOUSEBUTTONUP:
3941             event12.type = SDL12_MOUSEBUTTONUP;
3942             event12.button.which = (Uint8) event20->button.which;
3943             event12.button.button = event20->button.button;
3944             if (event12.button.button > 3) {
3945                 event12.button.button += 2; /* SDL_BUTTON_X1/2 */
3946             }
3947             event12.button.state = event20->button.state;
3948             if (MouseInputIsRelative) {
3949                 /* If we're using relative mouse input, we need to use our "fake" position. */
3950                 event12.button.x = MousePosition.x;
3951                 event12.button.y = MousePosition.y;
3952             } else {
3953                 AdjustOpenGLLogicalScalingPoint(&event20->button.x, &event20->button.y);
3954                 event12.button.x = (Uint16) event20->button.x;
3955                 event12.button.y = (Uint16) event20->button.y;
3956             }
3957             break;
3958 
3959         case SDL_MOUSEWHEEL:
3960             if (event20->wheel.y == 0) {
3961                 break;  /* don't support horizontal wheels in 1.2. */
3962             }
3963             event12.type = SDL12_MOUSEBUTTONDOWN;
3964             event12.button.which = (Uint8) event20->wheel.which;
3965             event12.button.button = (event20->wheel.y > 0) ? 4 : 5;  /* wheelup is 4, down is 5. */
3966             event12.button.state = SDL_PRESSED;
3967             event12.button.x = 0;
3968             event12.button.y = 0;
3969             PushEventIfNotFiltered(&event12);
3970 
3971             event12.type = SDL12_MOUSEBUTTONUP;  /* immediately release mouse "button" at the end of this switch. */
3972             event12.button.state = SDL_RELEASED;
3973             break;
3974 
3975         case SDL_JOYAXISMOTION:
3976             event12.type = SDL12_JOYAXISMOTION;
3977             event12.jaxis.which = (Uint8) event20->jaxis.which;
3978             event12.jaxis.axis = event20->jaxis.axis;
3979             event12.jaxis.value = event20->jaxis.value;
3980             break;
3981 
3982         case SDL_JOYBALLMOTION:
3983             event12.type = SDL12_JOYBALLMOTION;
3984             event12.jball.which = (Uint8) event20->jball.which;
3985             event12.jball.ball = event20->jball.ball;
3986             event12.jball.xrel = event20->jball.xrel;
3987             event12.jball.yrel = event20->jball.yrel;
3988             break;
3989 
3990         case SDL_JOYHATMOTION:
3991             event12.type = SDL12_JOYHATMOTION;
3992             event12.jhat.which = (Uint8) event20->jhat.which;
3993             event12.jhat.hat = event20->jhat.hat;
3994             event12.jhat.value = event20->jhat.value;
3995             break;
3996 
3997         case SDL_JOYBUTTONDOWN:
3998             event12.type = SDL12_JOYBUTTONDOWN;
3999             event12.jbutton.which = (Uint8) event20->jbutton.which;
4000             event12.jbutton.button = event20->jbutton.button;
4001             event12.jbutton.state = event20->jbutton.state;
4002             break;
4003 
4004         case SDL_JOYBUTTONUP:
4005             event12.type = SDL12_JOYBUTTONUP;
4006             event12.jbutton.which = (Uint8) event20->jbutton.which;
4007             event12.jbutton.button = event20->jbutton.button;
4008             event12.jbutton.state = event20->jbutton.state;
4009             break;
4010 
4011         /*
4012         case SDL_JOYDEVICEADDED:
4013         case SDL_JOYDEVICEREMOVED:
4014         case SDL_CONTROLLERAXISMOTION:
4015         case SDL_CONTROLLERBUTTONDOWN:
4016         case SDL_CONTROLLERBUTTONUP:
4017         case SDL_CONTROLLERDEVICEADDED:
4018         case SDL_CONTROLLERDEVICEREMOVED:
4019         case SDL_CONTROLLERDEVICEREMAPPED:
4020         case SDL_FINGERDOWN:
4021         case SDL_FINGERUP:
4022         case SDL_FINGERMOTION:
4023         case SDL_DOLLARGESTURE:
4024         case SDL_DOLLARRECORD:
4025         case SDL_MULTIGESTURE:
4026         case SDL_CLIPBOARDUPDATE:
4027         case SDL_DROPFILE:
4028         */
4029 
4030         default:
4031             return 1;  /* drop everything else. */
4032     }
4033 
4034     PushEventIfNotFiltered(&event12);
4035 
4036     /* always pass it to the 2.0 event queue, as internal watchers (like the render API)
4037        might need to see these events to deal with logical scaling, etc. We've already
4038        copied it to the separate 1.2 event queue, and run the app's 1.2 event filter.
4039        Next time we call 1.2's SDL_PollEvent or SDL_PumpEvents(), we'll throw away the
4040        entire SDL2 event queue, as everything that cares about those will have then
4041        had a chance to examine it. */
4042     return 1;
4043 }
4044 
4045 DECLSPEC void SDLCALL
SDL_SetEventFilter(SDL12_EventFilter filter12)4046 SDL_SetEventFilter(SDL12_EventFilter filter12)
4047 {
4048     /* We always have a filter installed, but will call the app's too. */
4049     EventFilter12 = filter12;
4050 }
4051 
4052 DECLSPEC SDL12_EventFilter SDLCALL
SDL_GetEventFilter(void)4053 SDL_GetEventFilter(void)
4054 {
4055     return EventFilter12;
4056 }
4057 
4058 
4059 static SDL12_Rect *
Rect20to12(const SDL_Rect * rect20,SDL12_Rect * rect12)4060 Rect20to12(const SDL_Rect *rect20, SDL12_Rect *rect12)
4061 {
4062     rect12->x = (Sint16) rect20->x;
4063     rect12->y = (Sint16) rect20->y;
4064     rect12->w = (Uint16) ((rect20->w <= 0) ? 0 : rect20->w);
4065     rect12->h = (Uint16) ((rect20->h <= 0) ? 0 : rect20->h);
4066     return rect12;
4067 }
4068 
4069 static SDL_Rect *
Rect12to20(const SDL12_Rect * rect12,SDL_Rect * rect20)4070 Rect12to20(const SDL12_Rect *rect12, SDL_Rect *rect20)
4071 {
4072     rect20->x = (int) rect12->x;
4073     rect20->y = (int) rect12->y;
4074     rect20->w = (int) rect12->w;
4075     rect20->h = (int) rect12->h;
4076     return rect20;
4077 }
4078 
4079 static SDL12_Surface *
Surface20to12(SDL_Surface * surface20)4080 Surface20to12(SDL_Surface *surface20)
4081 {
4082     SDL_BlendMode blendmode = SDL_BLENDMODE_NONE;
4083     SDL12_Surface *surface12 = NULL;
4084     SDL12_Palette *palette12 = NULL;
4085     SDL12_PixelFormat *format12 = NULL;
4086     Uint32 flags = 0;
4087 
4088     if (!surface20) {
4089         return NULL;
4090     } else if (surface20->pitch > 65535) {
4091         SDL20_SetError("Pitch is too large");  /* can't fit to 16-bits */
4092         return NULL;
4093     }
4094 
4095     surface12 = (SDL12_Surface *) SDL20_malloc(sizeof (SDL12_Surface));
4096     if (!surface12) {
4097         goto failed;
4098     }
4099 
4100     if (surface20->format->palette) {
4101         palette12 = (SDL12_Palette *) SDL20_malloc(sizeof (SDL12_Palette));
4102         if (!palette12) {
4103             goto failed;
4104         }
4105     }
4106 
4107     format12 = (SDL12_PixelFormat *) SDL20_malloc(sizeof (SDL12_PixelFormat));
4108     if (!format12) {
4109         goto failed;
4110     }
4111 
4112     if (palette12) {
4113         SDL20_zerop(palette12);
4114         SDL_assert(surface20->format->palette);
4115         palette12->ncolors = surface20->format->palette->ncolors;
4116         palette12->colors = surface20->format->palette->colors;
4117     }
4118 
4119     SDL20_zerop(format12);
4120     format12->palette = palette12;
4121     format12->BitsPerPixel = surface20->format->BitsPerPixel;
4122     format12->BytesPerPixel = surface20->format->BytesPerPixel;
4123     format12->Rloss = surface20->format->Rloss;
4124     format12->Gloss = surface20->format->Gloss;
4125     format12->Bloss = surface20->format->Bloss;
4126     format12->Aloss = surface20->format->Aloss;
4127     format12->Rshift = surface20->format->Rshift;
4128     format12->Gshift = surface20->format->Gshift;
4129     format12->Bshift = surface20->format->Bshift;
4130     format12->Ashift = surface20->format->Ashift;
4131     format12->Rmask = surface20->format->Rmask;
4132     format12->Gmask = surface20->format->Gmask;
4133     format12->Bmask = surface20->format->Bmask;
4134     format12->Amask = surface20->format->Amask;
4135 
4136     if (SDL20_GetColorKey(surface20, &format12->colorkey) < 0) {
4137         format12->colorkey = 0;
4138     } else {
4139         surface12->flags |= SDL12_SRCCOLORKEY;
4140     }
4141 
4142     if (SDL20_GetSurfaceAlphaMod(surface20, &format12->alpha) < 0) {
4143         format12->alpha = 255;
4144     }
4145 
4146     SDL20_zerop(surface12);
4147     flags = surface20->flags;
4148     flags &= ~SDL_SIMD_ALIGNED;  /* we don't need to map this to 1.2 */
4149     #define MAPSURFACEFLAGS(fl) { if (surface20->flags & SDL_##fl) { surface12->flags |= SDL12_##fl; flags &= ~SDL_##fl; } }
4150     MAPSURFACEFLAGS(PREALLOC);
4151     MAPSURFACEFLAGS(RLEACCEL);
4152     /*MAPSURFACEFLAGS(DONTFREE);*/
4153     #undef MAPSURFACEFLAGS
4154     SDL_assert(flags == 0);  /* non-zero if there's a flag we didn't map. */
4155 
4156     if ((SDL20_GetSurfaceBlendMode(surface20, &blendmode) == 0) && (blendmode == SDL_BLENDMODE_BLEND)) {
4157         surface12->flags |= SDL12_SRCALPHA;
4158     }
4159 
4160     surface12->format = format12;
4161     surface12->w = surface20->w;
4162     surface12->h = surface20->h;
4163     surface12->pitch = (Uint16) surface20->pitch;
4164     surface12->pixels = surface20->pixels;
4165     surface12->offset = 0;
4166     surface12->surface20 = surface20;
4167     Rect20to12(&surface20->clip_rect, &surface12->clip_rect);
4168     surface12->refcount = surface20->refcount;
4169 
4170     return surface12;
4171 
4172 failed:
4173     SDL20_free(surface12);
4174     SDL20_free(palette12);
4175     SDL20_free(format12);
4176     return NULL;
4177 }
4178 
4179 static void
SetPalette12ForMasks(SDL12_Surface * surface12,const Uint32 Rmask,const Uint32 Gmask,const Uint32 Bmask)4180 SetPalette12ForMasks(SDL12_Surface *surface12, const Uint32 Rmask, const Uint32 Gmask, const Uint32 Bmask)
4181 {
4182     SDL12_PixelFormat *format12;
4183     SDL_Color *color;
4184     int i, ncolors;
4185 
4186     format12 = surface12->format;
4187     if (format12->palette && (Rmask || Bmask || Gmask)) {
4188         int Rw, Rm, Gw, Gm, Bw, Bm;
4189         #define LOSSMASKSHIFTSETUP(t) { \
4190             format12->t##shift = 0; \
4191             format12->t##loss = 8; \
4192             if (t##mask) { \
4193                 Uint32 mask; \
4194                 for (mask = t##mask; !(mask & 1); mask >>= 1) { \
4195                     format12->t##shift++; \
4196                 } \
4197                 while (mask & 1) { \
4198                     format12->t##loss--; \
4199                     mask >>= 1; \
4200                 } \
4201             } \
4202             format12->t##mask = t##mask; \
4203         }
4204         LOSSMASKSHIFTSETUP(R);
4205         LOSSMASKSHIFTSETUP(G);
4206         LOSSMASKSHIFTSETUP(B);
4207         #undef LOSSMASKSHIFTSETUP
4208         format12->Amask = 0;
4209         format12->Ashift = 0;
4210         format12->Aloss = 8;
4211 
4212         #define MASKSETUP(t) { \
4213             t##w = 0, t##m = 0; \
4214             if (t##mask) { \
4215                 t##w = 8 - format12->t##loss; \
4216                 for (i = format12->t##loss; i > 0; i -= t##w) { \
4217                     t##m |= 1 << i; \
4218                 } \
4219             } \
4220         }
4221         MASKSETUP(R);
4222         MASKSETUP(G);
4223         MASKSETUP(B);
4224         #undef MASKSETUP
4225 
4226         ncolors = format12->palette->ncolors;
4227         color = format12->palette->colors;
4228         for (i = 0; i < ncolors; i++, color++) {
4229             #define SETCOLOR(T, t) { \
4230                 const int x = (i & T##mask) >> format12->T##shift; \
4231                 color->t = (x << format12->T##loss) | ((x * T##m) >> T##w); \
4232             }
4233             SETCOLOR(R, r);
4234             SETCOLOR(G, g);
4235             SETCOLOR(B, b);
4236             #undef SETCOLOR
4237             color->a = 255;
4238         }
4239 
4240     }
4241 }
4242 
4243 DECLSPEC SDL12_Surface * SDLCALL
SDL_CreateRGBSurface(Uint32 flags12,int width,int height,int depth,Uint32 Rmask,Uint32 Gmask,Uint32 Bmask,Uint32 Amask)4244 SDL_CreateRGBSurface(Uint32 flags12, int width, int height, int depth, Uint32 Rmask, Uint32 Gmask, Uint32 Bmask, Uint32 Amask)
4245 {
4246     SDL_Surface *surface20;
4247     SDL12_Surface *surface12;
4248 
4249     /* SDL 1.2 checks this. */
4250     if ((width >= 16384) || (height >= 65536)) {
4251         SDL20_SetError("Width or height is too large");
4252         return NULL;
4253     }
4254 
4255     if (depth == 8) {  /* don't pass masks to SDL2 for 8-bit surfaces, it'll cause problems. */
4256         surface20 = SDL20_CreateRGBSurface(0, width, height, depth, 0, 0, 0, 0);
4257     } else {
4258         surface20 = SDL20_CreateRGBSurface(0, width, height, depth, Rmask, Gmask, Bmask, Amask);
4259     }
4260 
4261     /* SDL 1.2 would make a surface from almost any masks, even if it doesn't
4262        make sense; specifically, it will make a surface if a color mask is
4263        bogus. Sometimes this even worked because it would eventually land in
4264        a generic blitter that just copied data blindly. SDL2 wants more strict
4265        pixel formats, so try to detect this case and try again with a standard
4266        format. */
4267     if ((surface20 == NULL) && (depth >= 24) && (SDL20_MasksToPixelFormatEnum(depth, Rmask, Gmask, Bmask, Amask) == SDL_PIXELFORMAT_UNKNOWN)) {
4268         /* I have no illusions this is correct, it just works for the known problem cases so far. */
4269         Rmask = SDL_SwapLE32(0x000000FF);
4270         Gmask = SDL_SwapLE32(0x0000FF00);
4271         Bmask = SDL_SwapLE32(0x00FF0000);
4272         Amask = SDL_SwapLE32(Amask ? 0xFF000000 : 0x00000000);
4273         surface20 = SDL20_CreateRGBSurface(0, width, height, depth, Rmask, Gmask, Bmask, Amask);
4274     }
4275 
4276     surface12 = Surface20to12(surface20);
4277     if (!surface12) {
4278         SDL20_FreeSurface(surface20);
4279         return NULL;
4280     }
4281 
4282     SDL_assert((surface12->flags & ~(SDL12_SRCCOLORKEY|SDL12_SRCALPHA)) == 0);  /* shouldn't have prealloc, rleaccel, or dontfree. */
4283 
4284     SetPalette12ForMasks(surface12, Rmask, Gmask, Bmask);
4285 
4286     if (flags12 & SDL12_SRCALPHA) {
4287         surface12->flags |= SDL12_SRCALPHA;
4288         SDL20_SetSurfaceBlendMode(surface20, SDL_BLENDMODE_BLEND);
4289     }
4290 
4291     return surface12;
4292 }
4293 
4294 DECLSPEC SDL12_Surface * SDLCALL
SDL_CreateRGBSurfaceFrom(void * pixels,int width,int height,int depth,int pitch,Uint32 Rmask,Uint32 Gmask,Uint32 Bmask,Uint32 Amask)4295 SDL_CreateRGBSurfaceFrom(void *pixels, int width, int height, int depth, int pitch, Uint32 Rmask, Uint32 Gmask, Uint32 Bmask, Uint32 Amask)
4296 {
4297     SDL_Surface *surface20;
4298     SDL12_Surface *surface12;
4299 
4300     if ((width >= 16384) || (height >= 65536)) {
4301         SDL20_SetError("Width or height is too large");
4302         return NULL;
4303     }
4304 
4305     if (depth == 8) {  /* don't pass masks to SDL2 for 8-bit surfaces, it'll cause problems. */
4306         surface20 = SDL20_CreateRGBSurfaceFrom(pixels, width, height, depth, pitch, 0, 0, 0, 0);
4307     } else {
4308         surface20 = SDL20_CreateRGBSurfaceFrom(pixels, width, height, depth, pitch, Rmask, Gmask, Bmask, Amask);
4309     }
4310 
4311     surface12 = Surface20to12(surface20);
4312     if (!surface12) {
4313         SDL20_FreeSurface(surface20);
4314         return NULL;
4315     }
4316 
4317     SDL_assert((surface12->flags & ~(SDL12_SRCCOLORKEY|SDL12_SRCALPHA)) == SDL12_PREALLOC);  /* should _only_ have prealloc. */
4318 
4319     SetPalette12ForMasks(surface12, Rmask, Gmask, Bmask);
4320 
4321     return surface12;
4322 }
4323 
4324 DECLSPEC void SDLCALL
SDL_FreeSurface(SDL12_Surface * surface12)4325 SDL_FreeSurface(SDL12_Surface *surface12)
4326 {
4327     if (surface12 && (surface12 != VideoSurface12)) {
4328         SDL20_FreeSurface(surface12->surface20);
4329         if (surface12->format) {
4330             SDL20_free(surface12->format->palette);
4331             SDL20_free(surface12->format);
4332         }
4333         SDL20_free(surface12);
4334     }
4335 }
4336 
4337 DECLSPEC void SDLCALL
SDL_GetClipRect(SDL12_Surface * surface12,SDL12_Rect * rect)4338 SDL_GetClipRect(SDL12_Surface *surface12, SDL12_Rect *rect)
4339 {
4340     if (surface12 && rect) {
4341         SDL20_memcpy(rect, &surface12->clip_rect, sizeof (SDL12_Rect));
4342     }
4343 }
4344 
4345 DECLSPEC SDL_bool SDLCALL
SDL_SetClipRect(SDL12_Surface * surface12,const SDL12_Rect * rect12)4346 SDL_SetClipRect(SDL12_Surface *surface12, const SDL12_Rect *rect12)
4347 {
4348     SDL_bool retval = SDL_FALSE;
4349     if (surface12) {
4350         SDL_Rect rect20;
4351         retval = SDL20_SetClipRect(surface12->surface20, rect12 ? Rect12to20(rect12, &rect20) : NULL);
4352         SDL20_GetClipRect(surface12->surface20, &rect20);
4353         Rect20to12(&rect20, &surface12->clip_rect);
4354     }
4355     return retval;
4356 }
4357 
4358 DECLSPEC int SDLCALL
SDL_FillRect(SDL12_Surface * dst,SDL12_Rect * dstrect12,Uint32 color)4359 SDL_FillRect(SDL12_Surface *dst, SDL12_Rect *dstrect12, Uint32 color)
4360 {
4361     SDL_Rect dstrect20;
4362     const int retval = SDL20_FillRect(dst->surface20, dstrect12 ? Rect12to20(dstrect12, &dstrect20) : NULL, color);
4363     if (retval == 0) {
4364         if (dstrect12) {  /* 1.2 stores the clip intersection in dstrect */
4365             SDL_Rect intersected20;
4366             SDL20_IntersectRect(&dstrect20, &dst->surface20->clip_rect, &intersected20);
4367             Rect20to12(&intersected20, dstrect12);
4368         }
4369     }
4370     return retval;
4371 }
4372 
4373 DECLSPEC Uint32 SDLCALL
SDL_MapRGB(const SDL12_PixelFormat * format12,Uint8 r,Uint8 g,Uint8 b)4374 SDL_MapRGB(const SDL12_PixelFormat *format12, Uint8 r, Uint8 g, Uint8 b)
4375 {
4376     /* This is probably way slower than apps expect. */
4377     SDL_PixelFormat format20;
4378     SDL_Palette palette20;
4379     return SDL20_MapRGB(PixelFormat12to20(&format20, &palette20, format12), r, g, b);
4380 }
4381 
4382 DECLSPEC Uint32 SDLCALL
SDL_MapRGBA(const SDL12_PixelFormat * format12,Uint8 r,Uint8 g,Uint8 b,Uint8 a)4383 SDL_MapRGBA(const SDL12_PixelFormat *format12, Uint8 r, Uint8 g, Uint8 b, Uint8 a)
4384 {
4385     /* This is probably way slower than apps expect. */
4386     SDL_PixelFormat format20;
4387     SDL_Palette palette20;
4388     return SDL20_MapRGBA(PixelFormat12to20(&format20, &palette20, format12), r, g, b, a);
4389 }
4390 
4391 DECLSPEC void SDLCALL
SDL_GetRGB(Uint32 pixel,const SDL12_PixelFormat * format12,Uint8 * r,Uint8 * g,Uint8 * b)4392 SDL_GetRGB(Uint32 pixel, const SDL12_PixelFormat *format12, Uint8 *r, Uint8 *g, Uint8 *b)
4393 {
4394     /* This is probably way slower than apps expect. */
4395     SDL_PixelFormat format20;
4396     SDL_Palette palette20;
4397     SDL20_GetRGB(pixel, PixelFormat12to20(&format20, &palette20, format12), r, g, b);
4398 }
4399 
4400 DECLSPEC void SDLCALL
SDL_GetRGBA(Uint32 pixel,const SDL12_PixelFormat * format12,Uint8 * r,Uint8 * g,Uint8 * b,Uint8 * a)4401 SDL_GetRGBA(Uint32 pixel, const SDL12_PixelFormat *format12, Uint8 *r, Uint8 *g, Uint8 *b, Uint8 *a)
4402 {
4403     /* This is probably way slower than apps expect. */
4404     SDL_PixelFormat format20;
4405     SDL_Palette palette20;
4406     SDL20_GetRGBA(pixel, PixelFormat12to20(&format20, &palette20, format12), r, g, b, a);
4407 }
4408 
4409 DECLSPEC const SDL12_VideoInfo * SDLCALL
SDL_GetVideoInfo(void)4410 SDL_GetVideoInfo(void)
4411 {
4412     return VideoInfo12.vfmt ? &VideoInfo12 : NULL;
4413 }
4414 
4415 DECLSPEC int SDLCALL
SDL_VideoModeOK(int width,int height,int bpp,Uint32 sdl12flags)4416 SDL_VideoModeOK(int width, int height, int bpp, Uint32 sdl12flags)
4417 {
4418     int i, j, actual_bpp = 0;
4419 
4420     if (!SDL20_WasInit(SDL_INIT_VIDEO)) {
4421         return 0;
4422     }
4423 
4424     if (!(sdl12flags & SDL12_FULLSCREEN)) {
4425         SDL_DisplayMode mode;
4426         SDL20_GetDesktopDisplayMode(VideoDisplayIndex, &mode);
4427         actual_bpp = SDL_BITSPERPIXEL(mode.format);
4428     } else {
4429         for (i = 0; i < VideoModesCount; ++i) {
4430             VideoModeList *vmode = &VideoModes[i];
4431             for (j = 0; j < vmode->nummodes; ++j) {
4432                 if (vmode->modeslist12[j].w == width && vmode->modeslist12[j].h == height)
4433                 {
4434                     if (!vmode->format) {
4435                         return bpp;
4436                     }
4437                     if (SDL_BITSPERPIXEL(vmode->format) == 24 && bpp == 32) {
4438                         actual_bpp = 32;
4439                     } else if (SDL_BITSPERPIXEL(vmode->format) >= (Uint32) bpp) {
4440                         actual_bpp = SDL_BITSPERPIXEL(vmode->format);
4441                     }
4442                 }
4443             }
4444         }
4445     }
4446 
4447     return (actual_bpp == 24) ? 32 : actual_bpp;
4448 }
4449 
4450 DECLSPEC SDL12_Rect ** SDLCALL
SDL_ListModes(const SDL12_PixelFormat * format12,Uint32 flags)4451 SDL_ListModes(const SDL12_PixelFormat *format12, Uint32 flags)
4452 {
4453     VideoModeList *best_modes = NULL;
4454     Uint32 bpp;
4455     int i;
4456 
4457     if (!SDL20_WasInit(SDL_INIT_VIDEO)) {
4458         SDL20_SetError("Video subsystem not initialized");
4459         return NULL;
4460     }
4461 
4462     if ((!format12) && (!VideoInfo12.vfmt)) {
4463         SDL20_SetError("No pixel format specified");
4464         return NULL;
4465     }
4466 
4467     if (IsDummyVideo) {
4468         return (SDL12_Rect **) -1;  /* 1.2's dummy driver always returns -1, and it's useful to special-case that. */
4469     }
4470 
4471     if (!(flags & SDL12_FULLSCREEN)) {
4472         return (SDL12_Rect **) -1;  /* any resolution is fine. */
4473     }
4474 
4475     if (format12 && (format12 != VideoInfo12.vfmt)) {
4476         bpp = (Uint32) format12->BitsPerPixel;
4477     } else {
4478         bpp = SDL_BITSPERPIXEL(VideoInfoVfmt20->format);
4479     }
4480 
4481     for (i = 0; i < VideoModesCount; i++) {
4482         VideoModeList *modes = &VideoModes[i];
4483         if (SDL_BITSPERPIXEL(modes->format) == bpp) {
4484             return modes->modes12;
4485         } else if (SDL_BITSPERPIXEL(modes->format) == 24 && bpp == 32) {
4486             best_modes = modes;
4487         } else if (SDL_BITSPERPIXEL(modes->format) > bpp) {
4488             if (!best_modes || SDL_BITSPERPIXEL(modes->format) > SDL_BITSPERPIXEL(best_modes->format)) {
4489                 best_modes = modes;
4490             }
4491         }
4492     }
4493 
4494     if (!best_modes) {
4495         SDL20_SetError("No modes support requested pixel format");
4496         return NULL;
4497     }
4498     return best_modes->modes12;
4499 }
4500 
4501 DECLSPEC void SDLCALL
SDL_FreeCursor(SDL12_Cursor * cursor12)4502 SDL_FreeCursor(SDL12_Cursor *cursor12)
4503 {
4504     if (cursor12 == CurrentCursor12) {
4505         CurrentCursor12 = NULL;
4506     }
4507     if (cursor12) {
4508         if (cursor12->wm_cursor) {
4509             SDL20_FreeCursor(cursor12->wm_cursor);
4510         }
4511         SDL20_free(cursor12->data);
4512         SDL20_free(cursor12->mask);
4513         SDL20_free(cursor12);
4514     }
4515 }
4516 
4517 DECLSPEC SDL12_Cursor * SDLCALL
SDL_CreateCursor(Uint8 * data,Uint8 * mask,int w,int h,int hot_x,int hot_y)4518 SDL_CreateCursor(Uint8 *data, Uint8 *mask, int w, int h, int hot_x, int hot_y)
4519 {
4520     const size_t datasize = h * (w / 8);
4521     SDL_Cursor *cursor20 = NULL;
4522     SDL12_Cursor *retval = NULL;
4523 
4524     retval = (SDL12_Cursor *) SDL20_malloc(sizeof (SDL12_Cursor));
4525     if (!retval) {
4526         goto outofmem;
4527     }
4528 
4529     SDL20_zerop(retval);
4530 
4531     retval->data = (Uint8 *) SDL20_malloc(datasize);
4532     if (!retval->data) {
4533         goto outofmem;
4534     }
4535 
4536     retval->mask = (Uint8 *) SDL20_malloc(datasize);
4537     if (!retval->mask) {
4538         goto outofmem;
4539     }
4540 
4541     cursor20 = SDL20_CreateCursor(data, mask, w, h, hot_x, hot_y);
4542     if (!cursor20) {
4543         goto failed;
4544     }
4545 
4546     retval->area.w = w;
4547     retval->area.h = h;
4548     retval->hot_x = hot_x;
4549     retval->hot_y = hot_y;
4550     retval->wm_cursor = cursor20;
4551     /* we always leave retval->save as null pointers. */
4552 
4553     SDL20_memcpy(retval->data, data, datasize);
4554     SDL20_memcpy(retval->mask, mask, datasize);
4555 
4556     return retval;
4557 
4558 outofmem:
4559     SDL20_OutOfMemory();
4560 
4561 failed:
4562     SDL_FreeCursor(retval);
4563     return NULL;
4564 }
4565 
4566 DECLSPEC void SDLCALL
SDL_SetCursor(SDL12_Cursor * cursor)4567 SDL_SetCursor(SDL12_Cursor *cursor)
4568 {
4569     CurrentCursor12 = cursor;
4570     SDL20_SetCursor(cursor ? cursor->wm_cursor : NULL);
4571 }
4572 
4573 DECLSPEC SDL12_Cursor * SDLCALL
SDL_GetCursor(void)4574 SDL_GetCursor(void)
4575 {
4576     if (!CurrentCursor12) {
4577         CurrentCursor12 = SDL_CreateCursor(default_cdata, default_cmask,
4578                             DEFAULT_CWIDTH, DEFAULT_CHEIGHT, DEFAULT_CHOTX, DEFAULT_CHOTY);
4579     }
4580     return CurrentCursor12;
4581 }
4582 
4583 static void
GetEnvironmentWindowPosition(int * x,int * y)4584 GetEnvironmentWindowPosition(int *x, int *y)
4585 {
4586     int display = VideoDisplayIndex;
4587     const char *window = SDL20_getenv("SDL_VIDEO_WINDOW_POS");
4588     const char *center = SDL20_getenv("SDL_VIDEO_CENTERED");
4589     if (window) {
4590         if (SDL20_strcmp(window, "center") == 0) {
4591             center = window;
4592         } else if (SDL20_sscanf(window, "%d,%d", x, y) == 2) {
4593             return;
4594         }
4595     }
4596 
4597     if (center) {
4598         *x = SDL_WINDOWPOS_CENTERED_DISPLAY(display);
4599         *y = SDL_WINDOWPOS_CENTERED_DISPLAY(display);
4600     } else {
4601         *x = SDL_WINDOWPOS_UNDEFINED_DISPLAY(display);
4602         *y = SDL_WINDOWPOS_UNDEFINED_DISPLAY(display);
4603     }
4604 }
4605 
4606 static SDL12_Surface *
EndVidModeCreate(void)4607 EndVidModeCreate(void)
4608 {
4609     if (OpenGLBlitTexture) {
4610         OpenGLFuncs.glDeleteTextures(1, &OpenGLBlitTexture);
4611         OpenGLBlitTexture = 0;
4612     }
4613     if (VideoTexture20) {
4614         SDL20_DestroyTexture(VideoTexture20);
4615         VideoTexture20 = NULL;
4616     }
4617     if (VideoRenderer20) {
4618         SDL20_DestroyRenderer(VideoRenderer20);
4619         VideoRenderer20 = NULL;
4620     }
4621     if (VideoGLContext20) {
4622         SDL20_GL_MakeCurrent(NULL, NULL);
4623         SDL20_GL_DeleteContext(VideoGLContext20);
4624         VideoGLContext20 = NULL;
4625     }
4626     if (VideoWindow20) {
4627         SDL20_DestroyWindow(VideoWindow20);
4628         VideoWindow20 = NULL;
4629     }
4630     if (VideoPhysicalPalette20) {
4631         SDL20_FreePalette(VideoPhysicalPalette20);
4632         VideoPhysicalPalette20 = NULL;
4633     }
4634     if (VideoSurface12) {
4635         SDL20_free(VideoSurface12->pixels);
4636         VideoSurface12->pixels = NULL;
4637         SDL_FreeSurface(VideoSurface12);
4638         VideoSurface12 = NULL;
4639     }
4640     if (VideoConvertSurface20) {
4641         SDL20_FreeSurface(VideoConvertSurface20);
4642         VideoConvertSurface20 = NULL;
4643     }
4644 
4645     SDL_zero(OpenGLFuncs);
4646     OpenGLBlitLockCount = 0;
4647     OpenGLLogicalScalingWidth = 0;
4648     OpenGLLogicalScalingHeight = 0;
4649     OpenGLLogicalScalingFBO = 0;
4650     OpenGLLogicalScalingColor = 0;
4651     OpenGLLogicalScalingDepth = 0;
4652 
4653     MouseInputIsRelative = SDL_FALSE;
4654     MousePosition.x = 0;
4655     MousePosition.y = 0;
4656 
4657     return NULL;
4658 }
4659 
4660 
4661 static SDL12_Surface *
CreateSurface12WithFormat(const int w,const int h,const Uint32 fmt)4662 CreateSurface12WithFormat(const int w, const int h, const Uint32 fmt)
4663 {
4664     Uint32 rmask, gmask, bmask, amask;
4665     int bpp;
4666     if (!SDL20_PixelFormatEnumToMasks(fmt, &bpp, &rmask, &gmask, &bmask, &amask)) {
4667         return NULL;
4668     }
4669     return SDL_CreateRGBSurface(0, w, h, bpp, rmask, gmask, bmask, amask);
4670 }
4671 
4672 static SDL_Surface *
CreateNullPixelSurface20(const int width,const int height,const Uint32 fmt)4673 CreateNullPixelSurface20(const int width, const int height, const Uint32 fmt)
4674 {
4675     SDL_Surface *surface20 = SDL20_CreateRGBSurfaceWithFormat(0, 0, 0, SDL_BITSPERPIXEL(fmt), fmt);
4676     if (surface20) {
4677         surface20->flags |= SDL_PREALLOC;
4678         surface20->pixels = NULL;
4679         surface20->w = width;
4680         surface20->h = height;
4681         surface20->pitch = 0;
4682         SDL20_SetClipRect(surface20, NULL);
4683     }
4684     return surface20;
4685 }
4686 
4687 static void
LoadOpenGLFunctions(void)4688 LoadOpenGLFunctions(void)
4689 {
4690     const char *version;
4691     int major = 0, minor = 0;
4692 
4693     /* load core functions so we can guess about a few other things. */
4694     SDL_zero(OpenGLFuncs);
4695     OpenGLFuncs.SUPPORTS_Core = SDL_TRUE;
4696     #define OPENGL_SYM(ext,rc,fn,params,args,ret) OpenGLFuncs.fn = \
4697            (OpenGLFuncs.SUPPORTS_##ext)? (openglfn_##fn##_t)SDL20_GL_GetProcAddress(#fn) : NULL;
4698     #include "SDL20_syms.h"
4699 
4700     version = (const char *) OpenGLFuncs.glGetString(GL_VERSION);
4701     if (!version || (SDL20_sscanf(version, "%d.%d", &major, &minor) != 2)) {
4702         major = minor = 0;
4703     }
4704 
4705     /* Lookup reported extensions. */
4706     #define OPENGL_EXT(name) OpenGLFuncs.SUPPORTS_##name = SDL20_GL_ExtensionSupported(#name);
4707     #include "SDL20_syms.h"
4708 
4709     /* GL_ARB_framebuffer_object is in core OpenGL 3.0+ with the same entry point names as the extension version. */
4710     if (major >= 3) {
4711         OpenGLFuncs.SUPPORTS_GL_ARB_framebuffer_object = SDL_TRUE;
4712     }
4713 
4714     if (major >= 2) {
4715         OpenGLFuncs.SUPPORTS_GL_ARB_texture_non_power_of_two = SDL_TRUE;  /* core since 2.0 */
4716     }
4717 
4718     /* load everything we can. */
4719     #define OPENGL_SYM(ext,rc,fn,params,args,ret) OpenGLFuncs.fn = \
4720            (OpenGLFuncs.SUPPORTS_##ext)? (openglfn_##fn##_t)SDL20_GL_GetProcAddress(#fn) : NULL;
4721     #include "SDL20_syms.h"
4722 }
4723 
4724 static void
ResolveFauxBackbufferMSAA()4725 ResolveFauxBackbufferMSAA()
4726 {
4727     const GLboolean has_scissor = OpenGLFuncs.glIsEnabled(GL_SCISSOR_TEST);
4728 
4729     if (has_scissor) {
4730         OpenGLFuncs.glDisable(GL_SCISSOR_TEST);  /* scissor test affects framebuffer_blit */
4731     }
4732 
4733     OpenGLFuncs.glBindFramebuffer(GL_READ_FRAMEBUFFER, OpenGLLogicalScalingFBO);
4734     OpenGLFuncs.glBindFramebuffer(GL_DRAW_FRAMEBUFFER, OpenGLLogicalScalingMultisampleFBO);
4735     OpenGLFuncs.glBlitFramebuffer(0, 0, OpenGLLogicalScalingWidth, OpenGLLogicalScalingHeight,
4736                                   0, 0, OpenGLLogicalScalingWidth, OpenGLLogicalScalingHeight,
4737                                   GL_COLOR_BUFFER_BIT, GL_NEAREST);
4738 
4739     if (has_scissor) {
4740         OpenGLFuncs.glEnable(GL_SCISSOR_TEST);
4741     }
4742     OpenGLFuncs.glBindFramebuffer(GL_READ_FRAMEBUFFER, OpenGLCurrentReadFBO);
4743     OpenGLFuncs.glBindFramebuffer(GL_DRAW_FRAMEBUFFER, OpenGLCurrentDrawFBO);
4744 }
4745 
4746 /* if the app binds its own framebuffer objects, it'll try to bind the window framebuffer
4747    (always zero) to draw to the screen, but if we're using a framebuffer object to handle
4748    scaling, we need to catch those binds and make sure rendering intended for the window
4749    framebuffer is redirected to our scaling FBO, so we have SDL_GL_GetProcAddress() hand out
4750    a shim for glBindFramebuffer to catch this. */
4751 static void GLAPIENTRY
glBindFramebuffer_shim_for_scaling(GLenum target,GLuint name)4752 glBindFramebuffer_shim_for_scaling(GLenum target, GLuint name)
4753 {
4754     /* OpenGLLogicalScaling{Multisample,}FBO will be zero if we aren't scaling, making this use the default. */
4755 
4756     /* We always cache the current framebuffer when it's changed here, so we don't have
4757        to repeatedly ask OpenGL what the current framebuffer is, and so we can only force
4758        resolves if the currently bound read FBO is the default. */
4759     if ((target == GL_READ_FRAMEBUFFER) || (target == GL_FRAMEBUFFER)) {
4760         if (OpenGLLogicalScalingMultisampleFBO) {
4761             /* We need to read from a resolves FBO if multisampling is enabled. */
4762             OpenGLCurrentReadFBO = (name == 0) ? OpenGLLogicalScalingMultisampleFBO : name;
4763         } else {
4764             OpenGLCurrentReadFBO = (name == 0) ? OpenGLLogicalScalingFBO : name;
4765         }
4766     }
4767 
4768     if ((target == GL_DRAW_FRAMEBUFFER) || (target == GL_FRAMEBUFFER)) {
4769         OpenGLCurrentDrawFBO = (name == 0) ? OpenGLLogicalScalingFBO : name;
4770     }
4771 
4772     /* If multisampling is enabled, and we're trying using the default framebuffer, do a multisample resolve. */
4773     if (OpenGLLogicalScalingMultisampleFBO && (OpenGLCurrentReadFBO == OpenGLLogicalScalingMultisampleFBO)) {
4774         ResolveFauxBackbufferMSAA();
4775     } else {
4776         /* ResolveFauxBackbufferMSAA() will bind the framebuffers, otherwise we have to do it manually */
4777         OpenGLFuncs.glBindFramebuffer(GL_READ_FRAMEBUFFER, OpenGLCurrentReadFBO);
4778         OpenGLFuncs.glBindFramebuffer(GL_DRAW_FRAMEBUFFER, OpenGLCurrentDrawFBO);
4779     }
4780 
4781 }
4782 
4783 static void GLAPIENTRY
glReadPixels_shim_for_scaling(GLint x,GLint y,GLsizei width,GLsizei height,GLenum format,GLenum type,void * data)4784 glReadPixels_shim_for_scaling(GLint x, GLint y, GLsizei width, GLsizei height, GLenum format, GLenum type, void *data)
4785 {
4786     if (OpenGLLogicalScalingMultisampleFBO && (OpenGLCurrentReadFBO == OpenGLLogicalScalingMultisampleFBO))
4787         ResolveFauxBackbufferMSAA();
4788     OpenGLFuncs.glReadPixels(x, y, width, height, format, type, data);
4789 }
4790 
4791 static void GLAPIENTRY
glCopyPixels_shim_for_scaling(GLint x,GLint y,GLsizei width,GLsizei height,GLenum type)4792 glCopyPixels_shim_for_scaling(GLint x, GLint y, GLsizei width, GLsizei height, GLenum type)
4793 {
4794     if (OpenGLLogicalScalingMultisampleFBO && (OpenGLCurrentReadFBO == OpenGLLogicalScalingMultisampleFBO))
4795         ResolveFauxBackbufferMSAA();
4796     OpenGLFuncs.glCopyPixels(x, y, width, height, type);
4797 }
4798 
4799 static void GLAPIENTRY
glCopyTexImage1D_shim_for_scaling(GLenum target,GLint level,GLenum internalformat,GLint x,GLint y,GLsizei width,GLint border)4800 glCopyTexImage1D_shim_for_scaling(GLenum target, GLint level, GLenum internalformat, GLint x, GLint y, GLsizei width, GLint border)
4801 {
4802     if (OpenGLLogicalScalingMultisampleFBO && (OpenGLCurrentReadFBO == OpenGLLogicalScalingMultisampleFBO))
4803         ResolveFauxBackbufferMSAA();
4804     OpenGLFuncs.glCopyTexImage1D(target, level, internalformat, x, y, width, border);
4805 }
4806 
4807 static void GLAPIENTRY
glCopyTexSubImage1D_shim_for_scaling(GLenum target,GLint level,GLint xoffset,GLint x,GLint y,GLsizei width)4808 glCopyTexSubImage1D_shim_for_scaling(GLenum target, GLint level, GLint xoffset, GLint x, GLint y, GLsizei width)
4809 {
4810     if (OpenGLLogicalScalingMultisampleFBO && (OpenGLCurrentReadFBO == OpenGLLogicalScalingMultisampleFBO))
4811         ResolveFauxBackbufferMSAA();
4812     OpenGLFuncs.glCopyTexSubImage1D(target, level, xoffset, x, y, width);
4813 }
4814 
4815 static void GLAPIENTRY
glCopyTexImage2D_shim_for_scaling(GLenum target,GLint level,GLenum internalformat,GLint x,GLint y,GLsizei width,GLsizei height,GLint border)4816 glCopyTexImage2D_shim_for_scaling(GLenum target, GLint level, GLenum internalformat, GLint x, GLint y, GLsizei width, GLsizei height, GLint border)
4817 {
4818     if (OpenGLLogicalScalingMultisampleFBO && (OpenGLCurrentReadFBO == OpenGLLogicalScalingMultisampleFBO))
4819         ResolveFauxBackbufferMSAA();
4820     OpenGLFuncs.glCopyTexImage2D(target, level, internalformat, x, y, width, height, border);
4821 }
4822 
4823 static void GLAPIENTRY
glCopyTexSubImage2D_shim_for_scaling(GLenum target,GLint level,GLint xoffset,GLint yoffset,GLint x,GLint y,GLsizei width,GLsizei height)4824 glCopyTexSubImage2D_shim_for_scaling(GLenum target, GLint level, GLint xoffset, GLint yoffset, GLint x, GLint y, GLsizei width, GLsizei height)
4825 {
4826     if (OpenGLLogicalScalingMultisampleFBO && (OpenGLCurrentReadFBO == OpenGLLogicalScalingMultisampleFBO))
4827         ResolveFauxBackbufferMSAA();
4828     OpenGLFuncs.glCopyTexSubImage2D(target, level, xoffset, yoffset, x, y, width, height);
4829 }
4830 
4831 static void GLAPIENTRY
glCopyTexSubImage3D_shim_for_scaling(GLenum target,GLint level,GLint xoffset,GLint yoffset,GLint zoffset,GLint x,GLint y,GLsizei width,GLsizei height)4832 glCopyTexSubImage3D_shim_for_scaling(GLenum target, GLint level, GLint xoffset, GLint yoffset, GLint zoffset, GLint x, GLint y, GLsizei width, GLsizei height)
4833 {
4834     if (OpenGLLogicalScalingMultisampleFBO && (OpenGLCurrentReadFBO == OpenGLLogicalScalingMultisampleFBO))
4835         ResolveFauxBackbufferMSAA();
4836     OpenGLFuncs.glCopyTexSubImage3D(target, level, xoffset, yoffset, zoffset, x, y, width, height);
4837 }
4838 
4839 static SDL_bool
InitializeOpenGLScaling(const int w,const int h)4840 InitializeOpenGLScaling(const int w, const int h)
4841 {
4842     const char *env;
4843     int alpha_size = 0;
4844 
4845     /* Support the MOUSE_RELATIVE_SCALING hint from SDL 2.0 for OpenGL scaling. */
4846     env = SDL20_getenv("SDL_MOUSE_RELATIVE_SCALING");
4847     UseMouseRelativeScaling = (!env || SDL20_atoi(env)) ? SDL_TRUE : SDL_FALSE;
4848 
4849     if (!OpenGLFuncs.SUPPORTS_GL_ARB_framebuffer_object) {
4850         return SDL_FALSE;  /* no FBOs, no scaling. */
4851     }
4852 
4853     OpenGLFuncs.glBindFramebuffer(GL_FRAMEBUFFER, 0);
4854     OpenGLFuncs.glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
4855     SDL20_GL_SwapWindow(VideoWindow20);
4856 
4857     FIXME("This should check if app requested a depth buffer, etc, too.");
4858     SDL20_GL_GetAttribute(SDL_GL_ALPHA_SIZE, &alpha_size);
4859 
4860     if (!OpenGLLogicalScalingFBO) {
4861         OpenGLFuncs.glGenFramebuffers(1, &OpenGLLogicalScalingFBO);
4862     }
4863 
4864     if (!OpenGLLogicalScalingColor) {
4865         OpenGLFuncs.glGenRenderbuffers(1, &OpenGLLogicalScalingColor);
4866     }
4867 
4868     if (!OpenGLLogicalScalingDepth) {
4869         OpenGLFuncs.glGenRenderbuffers(1, &OpenGLLogicalScalingDepth);
4870     }
4871 
4872     OpenGLFuncs.glBindFramebuffer(GL_FRAMEBUFFER, OpenGLLogicalScalingFBO);
4873     OpenGLFuncs.glBindRenderbuffer(GL_RENDERBUFFER, OpenGLLogicalScalingColor);
4874     OpenGLFuncs.glRenderbufferStorageMultisample(GL_RENDERBUFFER, OpenGLLogicalScalingSamples, (alpha_size > 0) ? GL_RGBA8 : GL_RGB8, w, h);
4875     OpenGLFuncs.glFramebufferRenderbuffer(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_RENDERBUFFER, OpenGLLogicalScalingColor);
4876     OpenGLFuncs.glBindRenderbuffer(GL_RENDERBUFFER, OpenGLLogicalScalingDepth);
4877     OpenGLFuncs.glRenderbufferStorageMultisample(GL_RENDERBUFFER, OpenGLLogicalScalingSamples, GL_DEPTH24_STENCIL8, w, h);
4878     OpenGLFuncs.glFramebufferRenderbuffer(GL_FRAMEBUFFER, GL_DEPTH_ATTACHMENT, GL_RENDERBUFFER, OpenGLLogicalScalingDepth);
4879     OpenGLFuncs.glFramebufferRenderbuffer(GL_FRAMEBUFFER, GL_STENCIL_ATTACHMENT, GL_RENDERBUFFER, OpenGLLogicalScalingDepth);
4880     OpenGLFuncs.glBindRenderbuffer(GL_RENDERBUFFER, 0);
4881 
4882     if ( (OpenGLFuncs.glCheckFramebufferStatus(GL_FRAMEBUFFER) != GL_FRAMEBUFFER_COMPLETE) || OpenGLFuncs.glGetError() ) {
4883         OpenGLFuncs.glBindFramebuffer(GL_FRAMEBUFFER, 0);
4884         OpenGLFuncs.glDeleteRenderbuffers(1, &OpenGLLogicalScalingColor);
4885         OpenGLFuncs.glDeleteRenderbuffers(1, &OpenGLLogicalScalingDepth);
4886         OpenGLFuncs.glDeleteFramebuffers(1, &OpenGLLogicalScalingFBO);
4887         OpenGLLogicalScalingFBO = OpenGLLogicalScalingColor = OpenGLLogicalScalingDepth = 0;
4888         return SDL_FALSE;
4889     }
4890 
4891     if (OpenGLLogicalScalingSamples) {
4892         if (!OpenGLLogicalScalingMultisampleFBO) {
4893             OpenGLFuncs.glGenFramebuffers(1, &OpenGLLogicalScalingMultisampleFBO);
4894         }
4895         if (!OpenGLLogicalScalingMultisampleColor) {
4896             OpenGLFuncs.glGenRenderbuffers(1, &OpenGLLogicalScalingMultisampleColor);
4897         }
4898         if (!OpenGLLogicalScalingMultisampleDepth) {
4899             OpenGLFuncs.glGenRenderbuffers(1, &OpenGLLogicalScalingMultisampleDepth);
4900         }
4901 
4902         OpenGLFuncs.glBindFramebuffer(GL_FRAMEBUFFER, OpenGLLogicalScalingMultisampleFBO);
4903         OpenGLFuncs.glBindRenderbuffer(GL_RENDERBUFFER, OpenGLLogicalScalingMultisampleColor);
4904         OpenGLFuncs.glRenderbufferStorage(GL_RENDERBUFFER, (alpha_size > 0) ? GL_RGBA8 : GL_RGB8, w, h);
4905         OpenGLFuncs.glFramebufferRenderbuffer(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_RENDERBUFFER, OpenGLLogicalScalingMultisampleColor);
4906         OpenGLFuncs.glBindRenderbuffer(GL_RENDERBUFFER, OpenGLLogicalScalingMultisampleDepth);
4907         OpenGLFuncs.glRenderbufferStorage(GL_RENDERBUFFER, GL_DEPTH24_STENCIL8, w, h);
4908         OpenGLFuncs.glFramebufferRenderbuffer(GL_FRAMEBUFFER, GL_DEPTH_ATTACHMENT, GL_RENDERBUFFER, OpenGLLogicalScalingMultisampleDepth);
4909         OpenGLFuncs.glFramebufferRenderbuffer(GL_FRAMEBUFFER, GL_STENCIL_ATTACHMENT, GL_RENDERBUFFER, OpenGLLogicalScalingMultisampleDepth);
4910         OpenGLFuncs.glBindRenderbuffer(GL_RENDERBUFFER, 0);
4911 
4912         if ( (OpenGLFuncs.glCheckFramebufferStatus(GL_FRAMEBUFFER) != GL_FRAMEBUFFER_COMPLETE) || OpenGLFuncs.glGetError() ) {
4913             OpenGLFuncs.glBindFramebuffer(GL_FRAMEBUFFER, 0);
4914             OpenGLFuncs.glDeleteRenderbuffers(1, &OpenGLLogicalScalingMultisampleColor);
4915             OpenGLFuncs.glDeleteRenderbuffers(1, &OpenGLLogicalScalingMultisampleDepth);
4916             OpenGLFuncs.glDeleteFramebuffers(1, &OpenGLLogicalScalingMultisampleFBO);
4917             OpenGLLogicalScalingMultisampleFBO = OpenGLLogicalScalingMultisampleColor = OpenGLLogicalScalingMultisampleDepth = 0;
4918         }
4919         OpenGLFuncs.glBindFramebuffer(GL_DRAW_FRAMEBUFFER, OpenGLLogicalScalingFBO);
4920         OpenGLFuncs.glBindFramebuffer(GL_READ_FRAMEBUFFER, OpenGLLogicalScalingMultisampleFBO);
4921     }
4922 
4923     /* initialise the cached current FBO bindings properly */
4924     OpenGLCurrentReadFBO = OpenGLLogicalScalingMultisampleFBO ? OpenGLLogicalScalingMultisampleFBO : OpenGLLogicalScalingFBO;
4925     OpenGLCurrentDrawFBO = OpenGLLogicalScalingFBO;
4926 
4927     OpenGLFuncs.glViewport(0, 0, w, h);
4928     OpenGLFuncs.glScissor(0, 0, w, h);
4929     OpenGLLogicalScalingWidth = w;
4930     OpenGLLogicalScalingHeight = h;
4931 
4932     OpenGLFuncs.glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
4933     return SDL_TRUE;
4934 }
4935 
4936 
4937 static void HandleInputGrab(SDL12_GrabMode mode);
4938 
4939 DECLSPEC SDL12_Surface * SDLCALL
SDL_SetVideoMode(int width,int height,int bpp,Uint32 flags12)4940 SDL_SetVideoMode(int width, int height, int bpp, Uint32 flags12)
4941 {
4942     SDL_DisplayMode dmode;
4943     Uint32 fullscreen_flags20 = 0;
4944     Uint32 appfmt;
4945     SDL_bool use_gl_scaling = SDL_FALSE;
4946     const char *env;
4947     SDL_bool use_highdpi = SDL_TRUE;
4948 
4949     FIXME("Should we offer scaling for windowed modes, too?");
4950     if (flags12 & SDL12_OPENGL) {
4951         /* !!! FIXME: the reason we have a toggle to prevent this is because an app might use
4952            FBOs directly, and will cause this to break if they bind Framebuffer 0 instead
4953            of our render target. If we can fool them into calling a fake glBindFramebuffer
4954            that binds our logical FBO instead of the window framebuffer, we can probably
4955            work with these apps, too. That's easy from SDL_GL_GetProcAddress, but we
4956            maybe need to export the symbol from here too, for those that link against
4957            OpenGL directly. UT2004 is known to use FBOs with SDL 1.2, and I assume
4958            idTech 4 games (Doom 3, Quake 4, Prey) do as well. */
4959         env = SDL20_getenv("SDL12COMPAT_OPENGL_SCALING");
4960 
4961         /* for now we default GL scaling to ENABLED. If an app breaks or is linked directly
4962            to glBindFramebuffer, they'll need to turn it off with this environment variable */
4963         use_gl_scaling = (!env || SDL20_atoi(env)) ? SDL_TRUE : SDL_FALSE;
4964 
4965         /* default use_highdpi to false for OpenGL windows when not using
4966            OpenGL scaling as legacy OpenGL applications are unlikely to support
4967            high-DPI setups properly. (They often use the window size to determine
4968            the resolute in some or all parts of their code.) Because OpenGL scaling
4969            is never used for windows, it is always false there. */
4970         use_highdpi = (flags12 & SDL12_FULLSCREEN) ? use_gl_scaling : SDL_FALSE;
4971     }
4972 
4973     env = SDL20_getenv("SDL12COMPAT_HIGHDPI");
4974     if (env) {
4975         use_highdpi = SDL20_atoi(env) ? SDL_TRUE : SDL_FALSE;
4976     }
4977 
4978     FIXME("currently ignores SDL_WINDOWID, which we could use with SDL_CreateWindowFrom ...?");
4979 
4980     flags12 &= ~SDL12_HWACCEL; /* just in case - https://github.com/libsdl-org/SDL-1.2/issues/817 */
4981 
4982     /* SDL_SetVideoMode() implicitly inits if necessary. */
4983     if (SDL20_WasInit(SDL_INIT_VIDEO) == 0) {
4984         if (SDL20_Init(SDL_INIT_VIDEO) < 0) {
4985             return NULL;
4986         }
4987         if (Init12Video() < 0) {
4988             return NULL;
4989         }
4990     }
4991 
4992     FIXME("handle SDL_ANYFORMAT");
4993 
4994     if ((width < 0) || (height < 0)) {
4995         SDL20_SetError("Invalid width or height");
4996         return NULL;
4997     }
4998 
4999     if (SDL20_GetCurrentDisplayMode(VideoDisplayIndex, &dmode) < 0) {
5000         return NULL;
5001     }
5002 
5003     if (width == 0) {
5004         width = dmode.w;
5005     }
5006 
5007     if (height == 0) {
5008         height = dmode.h;
5009     }
5010 
5011     if (bpp == 0) {
5012         bpp = SDL_BITSPERPIXEL(dmode.format);
5013     }
5014 
5015     #if !SDL_VERSION_ATLEAST(2,0,14)
5016     #define SDL_PIXELFORMAT_XRGB8888 SDL_PIXELFORMAT_RGB888
5017     #endif
5018     switch (bpp) {
5019         case  8: appfmt = SDL_PIXELFORMAT_INDEX8; break;
5020         case 16: appfmt = SDL_PIXELFORMAT_RGB565; FIXME("bgr instead of rgb?"); break;
5021         case 24: appfmt = SDL_PIXELFORMAT_RGB24; FIXME("bgr instead of rgb?"); break;
5022         case 32: appfmt = SDL_PIXELFORMAT_XRGB8888; FIXME("bgr instead of rgb?"); break;
5023         default: SDL20_SetError("Unsupported bits-per-pixel"); return NULL;
5024     }
5025 
5026     SDL_assert((VideoSurface12 != NULL) == (VideoWindow20 != NULL));
5027 
5028     FIXME("don't do anything if the window's dimensions, etc haven't changed.");
5029     FIXME("we need to preserve VideoSurface12 (but not its pixels), I think...");
5030 
5031     if (VideoSurface12 && ((VideoSurface12->flags & SDL12_OPENGL) != (flags12 & SDL12_OPENGL)) ) {
5032         EndVidModeCreate();  /* rebuild the window if moving to/from a GL context */
5033     } else if (VideoSurface12 && (VideoSurface12->surface20->format->format != appfmt)) {
5034         EndVidModeCreate();  /* rebuild the window if changing pixel format */
5035     } else if (VideoGLContext20) {
5036         /* SDL 1.2 (infuriatingly!) destroys the GL context on each resize in some cases, on various platforms. Try to match that. */
5037         #ifdef __WINDOWS__
5038             /* The windx5 driver _always_ destroyed the GL context, unconditionally, but the default (windib) did not, so match windib.
5039              *  windib: keep if:
5040              *   - window already exists
5041              *   - BitsPerPixel hasn't changed
5042              *   - none of the window flags (except SDL_ANYFORMAT) have changed
5043              *   - window is already SDL_OPENGL.
5044              *   - window is not a fullscreen window.
5045              */
5046             const SDL_bool destroy_gl_context = (
5047                 ((VideoSurface12->flags & ~SDL12_ANYFORMAT) != (flags12 & ~SDL12_ANYFORMAT)) ||
5048                 (VideoSurface12->format->BitsPerPixel != bpp) ||
5049                 ((flags12 & SDL12_OPENGL) != SDL12_OPENGL) ||
5050                 ((flags12 & SDL12_FULLSCREEN) == SDL12_FULLSCREEN)
5051             ) ? SDL_TRUE : SDL_FALSE;
5052         #elif defined(__APPLE__)
5053             const SDL_bool destroy_gl_context = SDL_TRUE; /* macOS ("quartz" backend) unconditionally destroys the GL context */
5054         #elif defined(__HAIKU__)
5055             const SDL_bool destroy_gl_context = SDL_FALSE; /* BeOS and Haiku ("bwindow" backend) unconditionally keeps the GL context */
5056         #elif defined(__LINUX__) || defined(unix) || defined(__unix__) || defined(__FreeBSD__) || defined(__NetBSD__) || defined(__OpenBSD__) || defined(sun)
5057             /* The x11 backend does in _some_ cases, and since Linux software depends on that, even though Wayland and
5058              *   such wasn't a thing at the time, we treat everything that looks a little like Unix this way.
5059              *  x11: keep if:
5060              *   - window already exists
5061              *   - window is already SDL_OPENGL.
5062              *   - new flags also want SDL_OPENGL.
5063              *   - BitsPerPixel hasn't changed
5064              *   - SDL_NOFRAME hasn't changed
5065              */
5066             const SDL_bool destroy_gl_context = (
5067                 ((VideoSurface12->flags & SDL12_OPENGL) != (flags12 & SDL12_OPENGL)) ||
5068                 ((flags12 & SDL12_OPENGL) != SDL12_OPENGL) ||
5069                 (VideoSurface12->format->BitsPerPixel != bpp) ||
5070                 ((VideoSurface12->flags & SDL12_NOFRAME) != (flags12 & SDL12_NOFRAME))
5071             ) ? SDL_TRUE : SDL_FALSE;
5072         #else
5073             const SDL_bool destroy_gl_context = SDL_TRUE;  /* everywhere else: nuke it from orbit. Oh well. */
5074         #endif
5075 
5076         if (destroy_gl_context) {
5077             SDL20_GL_MakeCurrent(NULL, NULL);
5078             SDL20_GL_DeleteContext(VideoGLContext20);
5079             VideoGLContext20 = NULL;
5080             SDL_zero(OpenGLFuncs);
5081             OpenGLBlitTexture = 0;
5082             OpenGLBlitLockCount = 0;
5083             OpenGLLogicalScalingWidth = 0;
5084             OpenGLLogicalScalingHeight = 0;
5085             OpenGLLogicalScalingFBO = 0;
5086             OpenGLLogicalScalingColor = 0;
5087             OpenGLLogicalScalingDepth = 0;
5088             OpenGLLogicalScalingMultisampleFBO = 0;
5089             OpenGLLogicalScalingMultisampleColor = 0;
5090             OpenGLLogicalScalingMultisampleDepth = 0;
5091         }
5092     }
5093 
5094     if (flags12 & SDL12_FULLSCREEN) {
5095         /* For software rendering, we're just going to push it off onto the
5096             GPU, so use FULLSCREEN_DESKTOP and logical scaling there.
5097             If possible, we'll do this with OpenGL, too, but we might not be
5098             able to. */
5099         if (use_gl_scaling || ((flags12 & SDL12_OPENGL) == 0) || ((dmode.w == width) && (dmode.h == height))) {
5100             fullscreen_flags20 |= SDL_WINDOW_FULLSCREEN_DESKTOP;
5101         } else {
5102             fullscreen_flags20 |= SDL_WINDOW_FULLSCREEN;
5103         }
5104     }
5105 
5106     if (!VideoWindow20) {  /* create it */
5107         int x = SDL_WINDOWPOS_UNDEFINED, y = SDL_WINDOWPOS_UNDEFINED;
5108         Uint32 flags20 = fullscreen_flags20;
5109         if (flags12 & SDL12_OPENGL) { flags20 |= SDL_WINDOW_OPENGL; }
5110         if (flags12 & SDL12_RESIZABLE) { flags20 |= SDL_WINDOW_RESIZABLE; }
5111         if (flags12 & SDL12_NOFRAME) { flags20 |= SDL_WINDOW_BORDERLESS; }
5112         if (use_highdpi) { flags20 |= SDL_WINDOW_ALLOW_HIGHDPI; }
5113 
5114         /* most platforms didn't check these environment variables, but the major
5115            ones did (x11, windib, quartz), so we'll just offer it everywhere. */
5116         GetEnvironmentWindowPosition(&x, &y);
5117 
5118         /* If GL scaling is disabled, and a multisampled buffer is requested, do it. */
5119         if (!use_gl_scaling && (flags12 & SDL12_OPENGL) && OpenGLLogicalScalingSamples) {
5120             SDL20_GL_SetAttribute(SDL_GL_MULTISAMPLEBUFFERS, 1);
5121             SDL20_GL_SetAttribute(SDL_GL_MULTISAMPLESAMPLES, OpenGLLogicalScalingSamples);
5122         }
5123 
5124         VideoWindow20 = SDL20_CreateWindow(WindowTitle, x, y, width, height, flags20);
5125         if (!VideoWindow20) {
5126             return EndVidModeCreate();
5127         }
5128         if (VideoIcon20) {
5129             SDL20_SetWindowIcon(VideoWindow20, VideoIcon20);
5130         }
5131     } else {  /* resize it */
5132         SDL20_SetWindowSize(VideoWindow20, width, height);
5133         SDL20_SetWindowFullscreen(VideoWindow20, fullscreen_flags20);
5134         /* This second SetWindowSize is a workaround for an SDL2 bug, see https://github.com/libsdl-org/sdl12-compat/issues/148 */
5135         SDL20_SetWindowSize(VideoWindow20, width, height);
5136         SDL20_SetWindowBordered(VideoWindow20, (flags12 & SDL12_NOFRAME) ? SDL_FALSE : SDL_TRUE);
5137         SDL20_SetWindowResizable(VideoWindow20, (flags12 & SDL12_RESIZABLE) ? SDL_TRUE : SDL_FALSE);
5138     }
5139 
5140     if (VideoSurface12) {
5141         SDL20_free(VideoSurface12->pixels);
5142     } else {
5143         VideoSurface12 = CreateSurface12WithFormat(0, 0, appfmt);
5144         if (!VideoSurface12) {
5145             return EndVidModeCreate();
5146         }
5147     }
5148 
5149     VideoSurface12->surface20->flags |= SDL_PREALLOC;
5150     VideoSurface12->flags |= SDL12_PREALLOC;
5151     VideoSurface12->pixels = VideoSurface12->surface20->pixels = NULL;
5152     VideoSurface12->w = VideoSurface12->surface20->w = width;
5153     VideoSurface12->h = VideoSurface12->surface20->h = height;
5154     VideoSurface12->pitch = VideoSurface12->surface20->pitch = width * SDL_BYTESPERPIXEL(appfmt);
5155     SDL_SetClipRect(VideoSurface12, NULL);
5156 
5157     if (flags12 & SDL12_FULLSCREEN) {
5158         VideoSurface12->flags |= SDL12_FULLSCREEN;
5159     } else {
5160         VideoSurface12->flags &= ~SDL12_FULLSCREEN;
5161     }
5162 
5163     if (flags12 & SDL12_OPENGL) {
5164         const char *vsync_env = SDL20_getenv("SDL12COMPAT_SYNC_TO_VBLANK");
5165         SDL_assert(!VideoTexture20);  /* either a new window or we destroyed all this */
5166         SDL_assert(!VideoRenderer20);
5167 
5168         FIXME("If we're using logical scaling, we can turn off depth buffer, alpha, etc, since we'll make our own and only need an RGB color buffer for the window.");
5169 
5170         if (!VideoGLContext20) {
5171             VideoGLContext20 = SDL20_GL_CreateContext(VideoWindow20);
5172             if (!VideoGLContext20) {
5173                 return EndVidModeCreate();
5174             }
5175             LoadOpenGLFunctions();
5176         }
5177 
5178         VideoSurface12->flags |= SDL12_OPENGL;
5179 
5180         /* Try to set up a logical scaling */
5181         if (use_gl_scaling) {
5182             if (!InitializeOpenGLScaling(width, height)) {
5183                 use_gl_scaling = SDL_FALSE;
5184                 fullscreen_flags20 &= ~SDL_WINDOW_FULLSCREEN_DESKTOP;
5185                 SDL20_SetWindowFullscreen(VideoWindow20, fullscreen_flags20);
5186                 SDL20_SetWindowSize(VideoWindow20, width, height);
5187                 fullscreen_flags20 |= SDL_WINDOW_FULLSCREEN;
5188                 SDL20_SetWindowFullscreen(VideoWindow20, fullscreen_flags20);
5189             }
5190         }
5191 
5192         if ((flags12 & SDL12_OPENGLBLIT) == SDL12_OPENGLBLIT) {
5193             const int pixsize = VideoSurface12->format->BytesPerPixel;
5194             const GLenum glfmt = (pixsize == 4) ? GL_RGBA : GL_RGB;
5195             const GLenum gltype = (pixsize == 4) ? GL_UNSIGNED_BYTE : GL_UNSIGNED_SHORT_5_6_5;
5196 
5197             if (!OpenGLFuncs.SUPPORTS_GL_ARB_texture_non_power_of_two) {
5198                 SDL20_SetError("Your OpenGL drivers don't support NPOT textures for SDL_OPENGLBLIT; please upgrade.");
5199                 return EndVidModeCreate();
5200             }
5201 
5202             if (!OpenGLBlitTexture) {
5203                 OpenGLFuncs.glGenTextures(1, &OpenGLBlitTexture);
5204             }
5205             OpenGLFuncs.glBindTexture(GL_TEXTURE_2D, OpenGLBlitTexture);
5206             OpenGLFuncs.glTexImage2D(GL_TEXTURE_2D, 0, (pixsize == 4) ? GL_RGBA : GL_RGB, VideoSurface12->w, VideoSurface12->h, 0, glfmt, gltype, NULL);
5207 
5208             VideoSurface12->surface20->pixels = SDL20_malloc(height * VideoSurface12->pitch);
5209             VideoSurface12->pixels = VideoSurface12->surface20->pixels;
5210             if (!VideoSurface12->pixels) {
5211                 SDL20_OutOfMemory();
5212                 return EndVidModeCreate();
5213             }
5214             SDL20_memset(VideoSurface12->pixels, 0xFF, height * VideoSurface12->pitch);  /* SDL 1.2 default OPENGLBLIT surface to full intensity */
5215             VideoSurface12->flags |= SDL12_OPENGLBLIT;
5216         }
5217 
5218         if (vsync_env) {
5219             SDL20_GL_SetSwapInterval(SDL20_atoi(vsync_env));
5220         } else {
5221             SDL20_GL_SetSwapInterval(SwapInterval);
5222         }
5223 
5224     } else {
5225         /* always use a renderer for non-OpenGL windows. */
5226         const char *vsync_env = SDL20_getenv("SDL12COMPAT_SYNC_TO_VBLANK");
5227         const char *old_scale_quality = SDL20_GetHint(SDL_HINT_RENDER_SCALE_QUALITY);
5228         const char *scale_method_env = SDL20_getenv("SDL12COMPAT_SCALE_METHOD");
5229         const SDL_bool want_vsync = (vsync_env && SDL20_atoi(vsync_env)) ? SDL_TRUE : SDL_FALSE;
5230         const SDL_bool want_nearest = (scale_method_env && !SDL20_strcmp(scale_method_env, "nearest"))? SDL_TRUE : SDL_FALSE;
5231         SDL_RendererInfo rinfo;
5232         SDL_assert(!VideoGLContext20);  /* either a new window or we destroyed all this */
5233         if (!VideoRenderer20 && want_vsync) {
5234             VideoRenderer20 = SDL20_CreateRenderer(VideoWindow20, -1, SDL_RENDERER_ACCELERATED|SDL_RENDERER_PRESENTVSYNC);
5235         }
5236         if (!VideoRenderer20) {
5237             VideoRenderer20 = SDL20_CreateRenderer(VideoWindow20, -1, SDL_RENDERER_ACCELERATED);
5238         }
5239         if (!VideoRenderer20) {
5240             VideoRenderer20 = SDL20_CreateRenderer(VideoWindow20, -1, 0);
5241         }
5242         if (!VideoRenderer20) {
5243             return EndVidModeCreate();
5244         }
5245 
5246         SDL20_RenderSetLogicalSize(VideoRenderer20, width, height);
5247 
5248         /* we need to make sure we're at the back of the Event Watch queue */
5249         SDL20_DelEventWatch(EventFilter20to12, NULL);
5250         SDL20_AddEventWatch(EventFilter20to12, NULL);
5251 
5252         SDL20_SetRenderDrawColor(VideoRenderer20, 0, 0, 0, 255);  /* leave this black always, we only use it to clear the framebuffer. */
5253         SDL20_RenderClear(VideoRenderer20);
5254         SDL20_RenderPresent(VideoRenderer20);
5255 
5256         if (SDL20_GetRendererInfo(VideoRenderer20, &rinfo) < 0) {
5257             return EndVidModeCreate();
5258         }
5259 
5260         if (VideoTexture20) {
5261             SDL20_DestroyTexture(VideoTexture20);
5262         }
5263 
5264         if (VideoConvertSurface20) {
5265             SDL20_FreeSurface(VideoConvertSurface20);
5266             VideoConvertSurface20 = NULL;
5267         }
5268 
5269         SDL20_SetHint(SDL_HINT_RENDER_SCALE_QUALITY, want_nearest?"0":"1");
5270         VideoTexture20 = SDL20_CreateTexture(VideoRenderer20, rinfo.texture_formats[0], SDL_TEXTUREACCESS_STREAMING, width, height);
5271         SDL20_SetHint(SDL_HINT_RENDER_SCALE_QUALITY, old_scale_quality);
5272         if (!VideoTexture20) {
5273             return EndVidModeCreate();
5274         }
5275 
5276         if (rinfo.texture_formats[0] != appfmt) {
5277             /* need to convert between app's format and texture format */
5278             VideoConvertSurface20 = CreateNullPixelSurface20(width, height, rinfo.texture_formats[0]);
5279             if (!VideoConvertSurface20) {
5280                 return EndVidModeCreate();
5281             }
5282         }
5283 
5284         VideoSurface12->flags &= ~SDL12_OPENGL;
5285         VideoSurface12->surface20->pixels = SDL20_malloc(height * VideoSurface12->pitch);
5286         VideoSurface12->pixels = VideoSurface12->surface20->pixels;
5287         if (!VideoSurface12->pixels) {
5288             SDL20_OutOfMemory();
5289             return EndVidModeCreate();
5290         }
5291 
5292         /* fill in the same default palette that SDL 1.2 does... */
5293         if (VideoSurface12->format->BitsPerPixel == 8) {
5294             int i;
5295             SDL_Color *color = VideoSurface12->format->palette->colors;
5296             for (i = 0; i < 256; i++, color++) {
5297                 { const int x = i & 0xe0; color->r = x | x >> 3 | x >> 6; }
5298                 { const int x = (i << 3) & 0xe0; color->g = x | x >> 3 | x >> 6; }
5299                 { const int x = (i & 0x3) | ((i & 0x3) << 2); color->b = x | x << 4; }
5300                 color->a = 255;
5301             }
5302             if (!VideoPhysicalPalette20) {
5303                 VideoPhysicalPalette20 = SDL20_AllocPalette(256);
5304                 if (!VideoPhysicalPalette20) {
5305                     return EndVidModeCreate();
5306                 }
5307             }
5308             SDL20_SetPaletteColors(VideoPhysicalPalette20, VideoSurface12->format->palette->colors, 0, 256);
5309         }
5310     }
5311 
5312     SDL20_RaiseWindow(VideoWindow20);
5313 
5314     /* SDL 1.2 always grabbed input if the video mode was fullscreen. */
5315     if (VideoSurface12->flags & SDL12_FULLSCREEN) {
5316         HandleInputGrab(SDL12_GRAB_ON);
5317     }
5318 
5319     VideoSurfacePresentTicks = 0;
5320     VideoSurfaceLastPresentTicks = 0;
5321 
5322     return VideoSurface12;
5323 }
5324 
5325 DECLSPEC SDL12_Surface * SDLCALL
SDL_GetVideoSurface(void)5326 SDL_GetVideoSurface(void)
5327 {
5328     return VideoSurface12;
5329 }
5330 
5331 static int
SaveDestAlpha(SDL12_Surface * src12,SDL12_Surface * dst12,Uint8 ** retval)5332 SaveDestAlpha(SDL12_Surface *src12, SDL12_Surface *dst12, Uint8 **retval)
5333 {
5334     /* The 1.2 docs say this:
5335      * RGBA->RGBA:
5336      *     SDL_SRCALPHA set:
5337      * 	alpha-blend (using the source alpha channel) the RGB values;
5338      * 	leave destination alpha untouched. [Note: is this correct?]
5339      *
5340      * In SDL2, we change the destination alpha. We have to save it off in this case, which sucks.
5341      */
5342     Uint8 *dstalpha = NULL;
5343     const SDL_bool save_dstalpha = ((src12->flags & SDL12_SRCALPHA) && dst12->format->Amask && ((src12->format->alpha != 255) || src12->format->Amask)) ? SDL_TRUE : SDL_FALSE;
5344 
5345     FIXME("This should only save the dst rect in use");
5346 
5347     if (save_dstalpha) {
5348         Uint8 *dptr;
5349         int x, y;
5350 
5351         const int w = dst12->w;
5352         const int h = dst12->h;
5353 
5354         const Uint32 amask = dst12->format->Amask;
5355         const Uint32 ashift = dst12->format->Ashift;
5356         const Uint16 pitch = dst12->pitch;
5357 
5358         dstalpha = (Uint8 *) SDL20_malloc(w * h);
5359         if (!dstalpha) {
5360             *retval = NULL;
5361             return SDL20_OutOfMemory();
5362         }
5363         dptr = dstalpha;
5364 
5365         if ((amask == 0xFF) || (amask == 0xFF00) || (amask == 0xFF0000) ||(amask == 0xFF000000)) {
5366             FIXME("this could be SIMD'd");
5367         }
5368         if (dst12->format->BytesPerPixel == 2) {
5369             const Uint16 *sptr = (const Uint16 *) dst12->pixels;
5370             for (y = 0; y < h; y++) {
5371                 for (x = 0; x < w; x++) {
5372                     *(dptr++) = (Uint8) ((sptr[x] & amask) >> ashift);
5373                 }
5374                 sptr = (Uint16 *) (((Uint8 *) sptr) + pitch);
5375             }
5376         } else if (dst12->format->BytesPerPixel == 4) {
5377             const Uint32 *sptr = (const Uint32 *) dst12->pixels;
5378             for (y = 0; y < h; y++) {
5379                 for (x = 0; x < w; x++) {
5380                     *(dptr++) = (Uint8) ((sptr[x] & amask) >> ashift);
5381                 }
5382                 sptr = (Uint32 *) (((Uint8 *) sptr) + pitch);
5383             }
5384         } else {
5385             FIXME("Unhandled dest alpha");
5386         }
5387     }
5388 
5389     *retval = dstalpha;
5390     return 0;
5391 }
5392 
5393 static void
RestoreDestAlpha(SDL12_Surface * dst12,Uint8 * dstalpha)5394 RestoreDestAlpha(SDL12_Surface *dst12, Uint8 *dstalpha)
5395 {
5396     if (dstalpha) {
5397         int x, y;
5398 
5399         const int w = dst12->w;
5400         const int h = dst12->h;
5401         const Uint8 *sptr = dstalpha;
5402         const Uint32 amask = dst12->format->Amask;
5403         const Uint32 ashift = dst12->format->Ashift;
5404         const Uint16 pitch = dst12->pitch;
5405 
5406         if ((amask == 0xFF) || (amask == 0xFF00) || (amask == 0xFF0000) ||(amask == 0xFF000000)) {
5407             FIXME("this could be SIMD'd");
5408         }
5409         if (dst12->format->BytesPerPixel == 2) {
5410             Uint16 *dptr = (Uint16 *) dst12->pixels;
5411             for (y = 0; y < h; y++) {
5412                 for (x = 0; x < w; x++) {
5413                     dptr[x] = (Uint16) ((dptr[x] & ~amask) | ((((Uint16) *(sptr++)) << ashift) & amask));
5414                 }
5415                 dptr = (Uint16 *) (((Uint8 *) dptr) + pitch);
5416             }
5417         } else if (dst12->format->BytesPerPixel == 4) {
5418             Uint32 *dptr = (Uint32 *) dst12->pixels;
5419             for (y = 0; y < h; y++) {
5420                 for (x = 0; x < w; x++) {
5421                     dptr[x] = (dptr[x] & ~amask) | ((((Uint32) *(sptr++)) << ashift) & amask);
5422                 }
5423                 dptr = (Uint32 *) (((Uint8 *) dptr) + pitch);
5424             }
5425         } else {
5426             FIXME("Unhandled dest alpha");
5427         }
5428         SDL20_free(dstalpha);
5429     }
5430 }
5431 
5432 DECLSPEC int SDLCALL
SDL_UpperBlit(SDL12_Surface * src12,SDL12_Rect * srcrect12,SDL12_Surface * dst12,SDL12_Rect * dstrect12)5433 SDL_UpperBlit(SDL12_Surface *src12, SDL12_Rect *srcrect12, SDL12_Surface *dst12, SDL12_Rect *dstrect12)
5434 {
5435     Uint8 *dstalpha;
5436     SDL_Rect srcrect20, dstrect20;
5437     int retval;
5438 
5439     if ((src12 == NULL) || (dst12 == NULL)) {
5440         return SDL20_SetError("SDL_UpperBlit: passed a NULL surface");
5441     } else if (SaveDestAlpha(src12, dst12, &dstalpha) < 0) {
5442         return -1;
5443     }
5444 
5445     retval = SDL20_UpperBlit(src12->surface20,
5446                              srcrect12 ? Rect12to20(srcrect12, &srcrect20) : NULL,
5447                              dst12->surface20,
5448                              dstrect12 ? Rect12to20(dstrect12, &dstrect20) : NULL);
5449 
5450     RestoreDestAlpha(dst12, dstalpha);
5451 
5452     if (dstrect12) {
5453         Rect20to12(&dstrect20, dstrect12);
5454     }
5455 
5456     return retval;
5457 }
5458 
5459 DECLSPEC int SDLCALL
SDL_LowerBlit(SDL12_Surface * src12,SDL12_Rect * srcrect12,SDL12_Surface * dst12,SDL12_Rect * dstrect12)5460 SDL_LowerBlit(SDL12_Surface *src12, SDL12_Rect *srcrect12, SDL12_Surface *dst12, SDL12_Rect *dstrect12)
5461 {
5462     Uint8 *dstalpha;
5463     SDL_Rect srcrect20, dstrect20;
5464     int retval;
5465 
5466     if (SaveDestAlpha(src12, dst12, &dstalpha) < 0) {
5467         return -1;
5468     }
5469 
5470     retval = SDL20_LowerBlit(src12->surface20,
5471                              srcrect12 ? Rect12to20(srcrect12, &srcrect20) : NULL,
5472                              dst12->surface20,
5473                              dstrect12 ? Rect12to20(dstrect12, &dstrect20) : NULL);
5474 
5475     RestoreDestAlpha(dst12, dstalpha);
5476 
5477     if (srcrect12) {
5478         Rect20to12(&srcrect20, srcrect12);
5479     }
5480 
5481     if (dstrect12) {
5482         Rect20to12(&dstrect20, dstrect12);
5483     }
5484 
5485     return retval;
5486 }
5487 
5488 DECLSPEC int SDLCALL
SDL_SoftStretch(SDL12_Surface * src12,SDL12_Rect * srcrect12,SDL12_Surface * dst12,SDL12_Rect * dstrect12)5489 SDL_SoftStretch(SDL12_Surface *src12, SDL12_Rect *srcrect12, SDL12_Surface *dst12, SDL12_Rect *dstrect12)
5490 {
5491     SDL_Rect srcrect20, dstrect20;
5492     return SDL20_SoftStretch(src12->surface20,
5493                              srcrect12 ? Rect12to20(srcrect12, &srcrect20) : NULL,
5494                              dst12->surface20,
5495                              dstrect12 ? Rect12to20(dstrect12, &dstrect20) : NULL);
5496 }
5497 
5498 DECLSPEC int SDLCALL
SDL_SetAlpha(SDL12_Surface * surface12,Uint32 flags12,Uint8 value)5499 SDL_SetAlpha(SDL12_Surface *surface12, Uint32 flags12, Uint8 value)
5500 {
5501     /* note that SDL 1.2 does not check if surface12 is NULL before dereferencing it either */
5502     const SDL_bool addkey = (flags12 & SDL12_SRCALPHA) ? SDL_TRUE : SDL_FALSE;
5503     int retval = 0;
5504 
5505     if (addkey) {
5506         if (!surface12->format->Amask) {  /* whole-surface alpha is ignored if surface has an alpha channel. */
5507             retval = SDL20_SetSurfaceAlphaMod(surface12->surface20, value);
5508             if (SDL20_GetSurfaceAlphaMod(surface12->surface20, &surface12->format->alpha) < 0) {
5509                 surface12->format->alpha = 255;
5510             }
5511         }
5512         surface12->flags |= SDL12_SRCALPHA;
5513         SDL20_SetSurfaceBlendMode(surface12->surface20, SDL_BLENDMODE_BLEND);
5514     } else {
5515         if (!surface12->format->Amask) {  /* whole-surface alpha is ignored if surface has an alpha channel. */
5516             retval = SDL20_SetSurfaceAlphaMod(surface12->surface20, 255);
5517             if (SDL20_GetSurfaceAlphaMod(surface12->surface20, &surface12->format->alpha) < 0) {
5518                 surface12->format->alpha = 255;
5519             }
5520         }
5521         surface12->flags &= ~SDL12_SRCALPHA;
5522         SDL20_SetSurfaceBlendMode(surface12->surface20, SDL_BLENDMODE_NONE);
5523     }
5524 
5525     return retval;
5526 }
5527 
5528 DECLSPEC int SDLCALL
SDL_LockSurface(SDL12_Surface * surface12)5529 SDL_LockSurface(SDL12_Surface *surface12)
5530 {
5531     const int retval = SDL20_LockSurface(surface12->surface20);
5532     surface12->pixels = surface12->surface20->pixels;
5533     surface12->pitch = surface12->surface20->pitch;
5534     return retval;
5535 }
5536 
5537 DECLSPEC void SDLCALL
SDL_UnlockSurface(SDL12_Surface * surface12)5538 SDL_UnlockSurface(SDL12_Surface *surface12)
5539 {
5540     SDL20_UnlockSurface(surface12->surface20);
5541     surface12->pixels = surface12->surface20->pixels;
5542     surface12->pitch = surface12->surface20->pitch;
5543 }
5544 
5545 DECLSPEC SDL12_Surface * SDLCALL
SDL_ConvertSurface(SDL12_Surface * src12,const SDL12_PixelFormat * format12,Uint32 flags12)5546 SDL_ConvertSurface(SDL12_Surface *src12, const SDL12_PixelFormat *format12, Uint32 flags12)
5547 {
5548     Uint32 flags20 = 0;
5549     SDL_PixelFormat format20;
5550     SDL_Palette palette20;
5551     SDL_Surface *surface20;
5552     SDL12_Surface *retval = NULL;
5553 
5554     if (flags12 & SDL12_PREALLOC) flags20 |= SDL_PREALLOC;
5555     if (flags12 & SDL12_RLEACCEL) flags20 |= SDL_RLEACCEL;
5556 
5557     surface20 = SDL20_ConvertSurface(src12->surface20, PixelFormat12to20(&format20, &palette20, format12), flags20);
5558     if (surface20) {
5559         retval = Surface20to12(surface20);
5560         if (!retval) {
5561             SDL20_FreeSurface(surface20);
5562         } else {
5563             if (flags12 & SDL12_SRCALPHA) {
5564                 SDL20_SetSurfaceBlendMode(surface20, SDL_BLENDMODE_BLEND);
5565                 retval->flags |= SDL12_SRCALPHA;
5566             }
5567         }
5568     }
5569     return retval;
5570 }
5571 
5572 DECLSPEC SDL12_Surface * SDLCALL
SDL_DisplayFormat(SDL12_Surface * surface12)5573 SDL_DisplayFormat(SDL12_Surface *surface12)
5574 {
5575     const Uint32 flags = surface12->flags & (SDL12_SRCCOLORKEY|SDL12_SRCALPHA|SDL12_RLEACCELOK);
5576     if (!VideoSurface12) {
5577         SDL20_SetError("No video mode has been set");
5578         return NULL;
5579     }
5580 
5581     return SDL_ConvertSurface(surface12, VideoSurface12->format, flags);
5582 }
5583 
5584 DECLSPEC SDL12_Surface * SDLCALL
SDL_DisplayFormatAlpha(SDL12_Surface * surface12)5585 SDL_DisplayFormatAlpha(SDL12_Surface *surface12)
5586 {
5587     const Uint32 flags = surface12->flags & (SDL12_SRCALPHA|SDL12_RLEACCELOK);
5588     SDL12_Surface *retval = NULL;
5589     SDL_PixelFormat *fmt20 = NULL;
5590     SDL12_PixelFormat fmt12;
5591 
5592     if (!VideoSurface12) {
5593         SDL20_SetError("No video mode has been set");
5594         return NULL;
5595     }
5596 
5597     /* we only allow a few formats for the screen surface, and this is the appropriate alpha format for all of them. */
5598     fmt20 = SDL20_AllocFormat(SDL_PIXELFORMAT_ARGB8888); FIXME("bgr instead of rgb?");
5599     if (!fmt20) {
5600         return NULL;
5601     }
5602 
5603     retval = SDL_ConvertSurface(surface12, PixelFormat20to12(&fmt12, NULL, fmt20), flags);
5604     SDL20_FreeFormat(fmt20);
5605     return retval;
5606 }
5607 
5608 static void
PresentScreen(void)5609 PresentScreen(void)
5610 {
5611     SDL20_RenderClear(VideoRenderer20);
5612     SDL20_RenderCopy(VideoRenderer20, VideoTexture20, NULL, NULL);
5613 
5614     /* Render any pending YUV overlay over the surface texture. */
5615     if (QueuedDisplayOverlay12) {
5616         SDL12_YUVData *hwdata = (SDL12_YUVData *) QueuedDisplayOverlay12->hwdata;
5617         SDL_Rect dstrect20;
5618         SDL20_RenderCopy(VideoRenderer20, hwdata->texture20, NULL, Rect12to20(&QueuedDisplayOverlayDstRect12, &dstrect20));
5619         QueuedDisplayOverlay12 = NULL;
5620     }
5621 
5622     SDL20_RenderPresent(VideoRenderer20);
5623     VideoSurfaceLastPresentTicks = SDL20_GetTicks();
5624     VideoSurfacePresentTicks = 0;
5625 }
5626 
5627 static void
UpdateRect12to20(SDL12_Surface * surface12,const SDL12_Rect * rect12,SDL_Rect * rect20,SDL_bool * whole_screen)5628 UpdateRect12to20(SDL12_Surface *surface12, const SDL12_Rect *rect12, SDL_Rect *rect20, SDL_bool *whole_screen)
5629 {
5630     Rect12to20(rect12, rect20);
5631     if (!rect20->x && !rect20->y && !rect20->w && !rect20->h) {
5632         *whole_screen = SDL_TRUE;
5633         rect20->w = surface12->w;
5634         rect20->h = surface12->h;
5635     } else {
5636         SDL_Rect surfacerect20;
5637         surfacerect20.x = surfacerect20.y = 0;
5638         surfacerect20.w = surface12->w;
5639         surfacerect20.h = surface12->h;
5640         Rect12to20(rect12, rect20);
5641         SDL20_IntersectRect(&surfacerect20, rect20, rect20);
5642         if ((rect20->x == 0) && (rect20->y == 0) && (rect20->w == surface12->w) && (rect20->h == surface12->h)) {
5643             *whole_screen = SDL_TRUE;
5644         }
5645     }
5646 }
5647 
5648 /* For manual throttling of screen updates. */
5649 static int
GetDesiredMillisecondsPerFrame()5650 GetDesiredMillisecondsPerFrame()
5651 {
5652     SDL_DisplayMode mode;
5653     if (VideoSurface12->flags & SDL12_FULLSCREEN) {
5654        if (SDL20_GetWindowDisplayMode(VideoWindow20, &mode) == 0) {
5655            if (mode.refresh_rate) {
5656                return 1000 / mode.refresh_rate;
5657            }
5658        }
5659     } else if (SDL20_GetCurrentDisplayMode(VideoDisplayIndex, &mode) == 0) {
5660         /* If we're windowed, assume we're on the default screen. */
5661         if (mode.refresh_rate) {
5662             return 1000 / mode.refresh_rate;
5663         }
5664     }
5665     return 15;
5666 }
5667 
5668 /* SDL_OPENGLBLIT support APIs. https://discourse.libsdl.org/t/ogl-and-sdl/2775/3 */
5669 DECLSPEC void SDLCALL
SDL_GL_Lock(void)5670 SDL_GL_Lock(void)
5671 {
5672     if (!OpenGLBlitTexture) {
5673         return;
5674     }
5675 
5676     if (++OpenGLBlitLockCount == 1) {
5677         OpenGLFuncs.glPushAttrib(GL_ALL_ATTRIB_BITS);
5678         OpenGLFuncs.glPushClientAttrib(GL_CLIENT_PIXEL_STORE_BIT);
5679         OpenGLFuncs.glEnable(GL_TEXTURE_2D);
5680         OpenGLFuncs.glEnable(GL_BLEND);
5681         OpenGLFuncs.glDisable(GL_FOG);
5682         OpenGLFuncs.glDisable(GL_ALPHA_TEST);
5683         OpenGLFuncs.glDisable(GL_DEPTH_TEST);
5684         OpenGLFuncs.glDisable(GL_SCISSOR_TEST);
5685         OpenGLFuncs.glDisable(GL_STENCIL_TEST);
5686         OpenGLFuncs.glDisable(GL_CULL_FACE);
5687 
5688         OpenGLFuncs.glBindTexture(GL_TEXTURE_2D, OpenGLBlitTexture);
5689         OpenGLFuncs.glTexEnvf(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_MODULATE);
5690         OpenGLFuncs.glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
5691         OpenGLFuncs.glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
5692         OpenGLFuncs.glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_REPEAT);
5693         OpenGLFuncs.glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_REPEAT);
5694 
5695         OpenGLFuncs.glPixelStorei(GL_UNPACK_ROW_LENGTH, VideoSurface12->pitch / VideoSurface12->format->BytesPerPixel);
5696         OpenGLFuncs.glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
5697         OpenGLFuncs.glColor4f(1.0f, 1.0f, 1.0f, 1.0f);
5698 
5699         OpenGLFuncs.glViewport(0, 0, VideoSurface12->w, VideoSurface12->h);
5700         OpenGLFuncs.glMatrixMode(GL_PROJECTION);
5701         OpenGLFuncs.glPushMatrix();
5702         OpenGLFuncs.glLoadIdentity();
5703 
5704         OpenGLFuncs.glOrtho(0.0, (GLdouble) VideoSurface12->w, (GLdouble) VideoSurface12->h, 0.0, 0.0, 1.0);
5705 
5706         OpenGLFuncs.glMatrixMode(GL_MODELVIEW);
5707         OpenGLFuncs.glPushMatrix();
5708         OpenGLFuncs.glLoadIdentity();
5709     }
5710 }
5711 
5712 DECLSPEC void SDLCALL
SDL_GL_UpdateRects(int numrects,SDL12_Rect * rects12)5713 SDL_GL_UpdateRects(int numrects, SDL12_Rect *rects12)
5714 {
5715     if (OpenGLBlitTexture) {
5716         const int srcpitch = VideoSurface12->pitch;
5717         const int pixsize = VideoSurface12->format->BytesPerPixel;
5718         const GLenum glfmt = (pixsize == 4) ? GL_RGBA : GL_RGB;
5719         const GLenum gltype = (pixsize == 4) ? GL_UNSIGNED_BYTE : GL_UNSIGNED_SHORT_5_6_5;
5720         SDL_Rect surfacerect20;
5721         int i;
5722 
5723         surfacerect20.x = surfacerect20.y = 0;
5724         surfacerect20.w = VideoSurface12->w;
5725         surfacerect20.h = VideoSurface12->h;
5726 
5727         for (i = 0; i < numrects; i++) {
5728             SDL_Rect rect20;
5729             SDL_Rect intersected20;
5730             Uint8 *src;
5731 
5732             SDL20_IntersectRect(Rect12to20(&rects12[i], &rect20), &surfacerect20, &intersected20);
5733 
5734             src = (((Uint8 *) VideoSurface12->pixels) + (intersected20.y * srcpitch)) + (intersected20.x * pixsize);
5735             OpenGLFuncs.glTexSubImage2D(GL_TEXTURE_2D, 0, intersected20.x, intersected20.y, intersected20.w, intersected20.h, glfmt, gltype, src);
5736 
5737             OpenGLFuncs.glBegin(GL_TRIANGLE_STRIP);
5738             {
5739                 const GLfloat tex_x1 = ((GLfloat) intersected20.x) / ((GLfloat) VideoSurface12->w);
5740                 const GLfloat tex_y1 = ((GLfloat) intersected20.y) / ((GLfloat) VideoSurface12->h);
5741                 const GLfloat tex_x2 = tex_x1 + ((GLfloat) intersected20.w) / ((GLfloat) VideoSurface12->w);
5742                 const GLfloat tex_y2 = tex_y1 + ((GLfloat) intersected20.h) / ((GLfloat) VideoSurface12->h);
5743                 const GLint vert_x1 = (GLint) intersected20.x;
5744                 const GLint vert_y1 = (GLint) intersected20.y;
5745                 const GLint vert_x2 = vert_x1 + (GLint) intersected20.w;
5746                 const GLint vert_y2 = vert_y1 + (GLint) intersected20.h;
5747                 OpenGLFuncs.glTexCoord2f(tex_x1, tex_y1);
5748                 OpenGLFuncs.glVertex2i(vert_x1, vert_y1);
5749                 OpenGLFuncs.glTexCoord2f(tex_x2, tex_y1);
5750                 OpenGLFuncs.glVertex2i(vert_x2, vert_y1);
5751                 OpenGLFuncs.glTexCoord2f(tex_x1, tex_y2);
5752                 OpenGLFuncs.glVertex2i(vert_x1, vert_y2);
5753                 OpenGLFuncs.glTexCoord2f(tex_x2, tex_y2);
5754                 OpenGLFuncs.glVertex2i(vert_x2, vert_y2);
5755             }
5756             OpenGLFuncs.glEnd();
5757         }
5758     }
5759 }
5760 
5761 
5762 DECLSPEC void SDLCALL
SDL_GL_Unlock(void)5763 SDL_GL_Unlock(void)
5764 {
5765     if (OpenGLBlitTexture) {
5766         if (OpenGLBlitLockCount > 0) {
5767             if (--OpenGLBlitLockCount == 0) {
5768                 OpenGLFuncs.glPopMatrix();
5769                 OpenGLFuncs.glMatrixMode(GL_PROJECTION);
5770                 OpenGLFuncs.glPopMatrix();
5771                 OpenGLFuncs.glPopClientAttrib();
5772                 OpenGLFuncs.glPopAttrib();
5773             }
5774         }
5775     }
5776 }
5777 
5778 
5779 DECLSPEC void SDLCALL
SDL_UpdateRects(SDL12_Surface * surface12,int numrects,SDL12_Rect * rects12)5780 SDL_UpdateRects(SDL12_Surface *surface12, int numrects, SDL12_Rect *rects12)
5781 {
5782     /* strangely, SDL 1.2 doesn't check if surface12 is NULL before touching it */
5783     /* (UpdateRect, singular, does...) */
5784 
5785     if ((surface12 == VideoSurface12) && ((surface12->flags & SDL12_OPENGLBLIT) == SDL12_OPENGLBLIT)) {
5786         SDL_GL_Lock();
5787         SDL_GL_UpdateRects(numrects, rects12);
5788         SDL_GL_Unlock();
5789         return;
5790     }
5791 
5792     if (surface12->flags & SDL12_OPENGL) {
5793         SDL20_SetError("Use SDL_GL_SwapBuffers() on OpenGL surfaces");
5794         return;
5795     }
5796 
5797     /* everything else is marked SDL12_DOUBLEBUF and SHOULD BE a no-op here,
5798      *  but in practice most apps never got a double-buffered surface and
5799      *  don't handle it correctly, so we have to work around it. */
5800     if (surface12 == VideoSurface12) {
5801         SDL_Palette *logicalPal = surface12->surface20->format->palette;
5802         const int pixsize = surface12->format->BytesPerPixel;
5803         const int srcpitch = surface12->pitch;
5804         SDL_bool whole_screen = SDL_FALSE;
5805         void *pixels = NULL;
5806         SDL_Rect rect20;
5807         int pitch = 0;
5808         int i, j;
5809 
5810         for (i = 0; i < numrects; i++) {
5811             UpdateRect12to20(surface12, &rects12[i], &rect20, &whole_screen);
5812             if (!rect20.w || !rect20.h) {
5813                 continue;
5814             } else if (SDL20_LockTexture(VideoTexture20, &rect20, &pixels, &pitch) < 0) {
5815                 continue;  /* oh well */
5816             }
5817 
5818             if (VideoConvertSurface20) {
5819                 SDL_Rect dstrect20;  /* pretend that the subregion is just the top left of the convert surface. */
5820                 dstrect20.x = dstrect20.y = 0;
5821                 dstrect20.w = rect20.w;
5822                 dstrect20.h = rect20.h;
5823                 surface12->surface20->format->palette = VideoPhysicalPalette20;
5824                 VideoConvertSurface20->pixels = pixels;
5825                 VideoConvertSurface20->pitch = pitch;
5826                 VideoConvertSurface20->w = rect20.w;
5827                 VideoConvertSurface20->h = rect20.h;
5828                 SDL20_UpperBlit(VideoSurface12->surface20, &rect20, VideoConvertSurface20, &dstrect20);
5829             } else {
5830                 const int cpy = rect20.w * pixsize;
5831                 char *dst = (char *) pixels;
5832                 const Uint8 *src = (((Uint8 *) surface12->pixels) + (rect20.y * srcpitch)) + (rect20.x * pixsize);
5833                 for (j = 0; j < rect20.h; j++) {
5834                     SDL20_memcpy(dst, src, cpy);
5835                     src += srcpitch;
5836                     dst += pitch;
5837                 }
5838             }
5839 
5840             SDL20_UnlockTexture(VideoTexture20);
5841         }
5842 
5843         if (VideoConvertSurface20) {  /* reset some state we messed with */
5844             surface12->surface20->format->palette = logicalPal;
5845             VideoConvertSurface20->pixels = NULL;
5846             VideoConvertSurface20->pitch = 0;
5847             VideoConvertSurface20->w = VideoSurface12->w;
5848             VideoConvertSurface20->h = VideoSurface12->h;
5849         }
5850 
5851         if (whole_screen) {
5852             PresentScreen();  /* flip it now. */
5853         } else {
5854             VideoSurfacePresentTicks = VideoSurfaceLastPresentTicks + GetDesiredMillisecondsPerFrame();  /* flip it later. */
5855         }
5856     }
5857 }
5858 
5859 DECLSPEC void SDLCALL
SDL_UpdateRect(SDL12_Surface * screen12,Sint32 x,Sint32 y,Uint32 w,Uint32 h)5860 SDL_UpdateRect(SDL12_Surface *screen12, Sint32 x, Sint32 y, Uint32 w, Uint32 h)
5861 {
5862     if (screen12) {
5863         SDL12_Rect rect12;
5864         rect12.x = (Sint16) x;
5865         rect12.y = (Sint16) y;
5866         rect12.w = (Uint16) (w ? w : screen12->w);
5867         rect12.h = (Uint16) (h ? h : screen12->h);
5868         SDL_UpdateRects(screen12, 1, &rect12);
5869     }
5870 }
5871 
5872 DECLSPEC int SDLCALL
SDL_Flip(SDL12_Surface * surface12)5873 SDL_Flip(SDL12_Surface *surface12)
5874 {
5875     if (surface12->flags & SDL12_OPENGL) {
5876         return SDL20_SetError("Use SDL_GL_SwapBuffers() on OpenGL surfaces");
5877     }
5878 
5879     if (surface12 == VideoSurface12) {
5880         SDL_UpdateRect(surface12, 0, 0, 0, 0);  /* update the whole screen and present now. */
5881     }
5882 
5883     return 0;
5884 }
5885 
5886 DECLSPEC void SDLCALL
SDL_PumpEvents(void)5887 SDL_PumpEvents(void)
5888 {
5889     SDL_Event e;
5890 
5891     /* If the app is doing dirty rectangles, we set a flag and present the
5892      *  screen surface when they pump for new events if we're close to 60Hz,
5893      *  which we consider a sign that they are done rendering for the current
5894      *  frame and it would make sense to send it to the screen. */
5895     if (VideoSurfacePresentTicks && SDL_TICKS_PASSED(SDL20_GetTicks(), VideoSurfacePresentTicks)) {
5896         PresentScreen();
5897     }
5898     while (SDL20_PollEvent(&e)) {  /* spin to drain the SDL2 event queue. */ }
5899 
5900     /* If there's a pending KEYDOWN event, and we haven't got a TEXTINPUT
5901      * event which matches it, then let it through now. */
5902     if (PendingKeydownEvent.type == SDL12_KEYDOWN) {
5903         FlushPendingKeydownEvent(0);
5904     }
5905 }
5906 
5907 DECLSPEC void SDLCALL
SDL_WM_SetCaption(const char * title,const char * icon)5908 SDL_WM_SetCaption(const char *title, const char *icon)
5909 {
5910     if (WindowTitle) {
5911         SDL20_free(WindowTitle);
5912     }
5913     if (WindowIconTitle) {
5914         SDL20_free(WindowIconTitle);
5915     }
5916     WindowTitle = title ? SDL20_strdup(title) : NULL;
5917     WindowIconTitle = icon ? SDL20_strdup(icon) : NULL;
5918     if (VideoWindow20) {
5919         SDL20_SetWindowTitle(VideoWindow20, WindowTitle);
5920     }
5921 }
5922 
5923 DECLSPEC void SDLCALL
SDL_WM_GetCaption(const char ** title,const char ** icon)5924 SDL_WM_GetCaption(const char **title, const char **icon)
5925 {
5926     if (title) {
5927         *title = WindowTitle;
5928     }
5929     if (icon) {
5930         *icon = WindowIconTitle;
5931     }
5932 }
5933 
5934 DECLSPEC void SDLCALL
SDL_WM_SetIcon(SDL12_Surface * icon12,Uint8 * mask)5935 SDL_WM_SetIcon(SDL12_Surface *icon12, Uint8 *mask)
5936 {
5937     SDL_BlendMode oldmode;
5938     Uint32 rmask, gmask, bmask, amask;
5939     SDL_Surface *icon20;
5940     int bpp;
5941     int ret;
5942 
5943     if (VideoWindow20) {
5944         SDL20_SetWindowIcon(VideoWindow20, icon12->surface20);
5945         return;
5946     }
5947 
5948     /* take the mask and zero out those alpha values. */
5949     oldmode = SDL_BLENDMODE_NONE;
5950     if (SDL20_GetSurfaceBlendMode(icon12->surface20, &oldmode) < 0) {
5951         return; /* oh well. */
5952     }
5953     if (!SDL20_PixelFormatEnumToMasks(SDL_PIXELFORMAT_ARGB8888, &bpp, &rmask, &gmask, &bmask, &amask)) {
5954         return; /* oh well. */
5955     }
5956     icon20 = SDL20_CreateRGBSurface(0, icon12->w, icon12->h, bpp, rmask, gmask, bmask, amask);
5957     if (!icon20) {
5958         return; /* oh well. */
5959     }
5960 
5961     SDL20_SetSurfaceBlendMode(icon12->surface20, SDL_BLENDMODE_NONE);
5962     ret = SDL20_UpperBlit(icon12->surface20, NULL, icon20, NULL);
5963     SDL20_SetSurfaceBlendMode(icon12->surface20, oldmode);
5964     if (ret == 0) {
5965         if (mask) {
5966             const int w = icon12->w;
5967             const int h = icon12->h;
5968             const int mpitch = (w + 7) / 8;
5969             Uint32 *ptr = (Uint32 *) icon20->pixels;
5970 
5971             int x, y;
5972 
5973             SDL_assert(icon20->format->BytesPerPixel == 4);
5974             SDL_assert(icon20->pitch == icon20->w * 4);
5975 
5976             for (y = 0; y < h; y++) {
5977                 for (x = 0; x < w; x++, ptr++) {
5978                     if (!(mask[y*mpitch + x/8] & (128 >> (x % 8)))) {
5979                         *ptr &= ~amask;
5980                     } else {
5981                         *ptr |= amask;
5982                     }
5983                 }
5984             }
5985         }
5986 
5987         if (VideoWindow20) {
5988             SDL20_SetWindowIcon(VideoWindow20, icon20);
5989         }
5990         SDL20_FreeSurface(VideoIcon20);
5991         VideoIcon20 = icon20;
5992     }
5993 }
5994 
5995 DECLSPEC int SDLCALL
SDL_WM_IconifyWindow(void)5996 SDL_WM_IconifyWindow(void)
5997 {
5998     SDL20_MinimizeWindow(VideoWindow20);
5999     return 0;
6000 }
6001 
6002 DECLSPEC int SDLCALL
SDL_WM_ToggleFullScreen(SDL12_Surface * surface)6003 SDL_WM_ToggleFullScreen(SDL12_Surface *surface)
6004 {
6005     int retval = 0;
6006     if (surface == VideoSurface12) {
6007         Uint32 flags20;
6008         SDL_assert(VideoWindow20);
6009         flags20 = SDL20_GetWindowFlags(VideoWindow20);
6010         if (flags20 & SDL_WINDOW_FULLSCREEN) {
6011             SDL_assert(VideoSurface12->flags & SDL12_FULLSCREEN);
6012             retval = (SDL20_SetWindowFullscreen(VideoWindow20, 0) == 0);
6013             if (retval) {
6014                 VideoSurface12->flags &= ~SDL12_FULLSCREEN;
6015             }
6016         } else {
6017             Uint32 newflags20;
6018             SDL_assert((VideoSurface12->flags & SDL12_FULLSCREEN) == 0);
6019             newflags20 = (((VideoSurface12->flags & SDL12_OPENGL) == 0) || (OpenGLLogicalScalingFBO != 0)) ? SDL_WINDOW_FULLSCREEN_DESKTOP : SDL_WINDOW_FULLSCREEN;
6020             retval = (SDL20_SetWindowFullscreen(VideoWindow20, newflags20) == 0);
6021             if (retval) {
6022                 VideoSurface12->flags |= SDL12_FULLSCREEN;
6023             }
6024         }
6025         if (retval && VideoRenderer20) {
6026             SDL20_RenderSetLogicalSize(VideoRenderer20, VideoSurface12->w, VideoSurface12->h);
6027         }
6028     }
6029     return retval;
6030 }
6031 
6032 static void
UpdateRelativeMouseMode(void)6033 UpdateRelativeMouseMode(void)
6034 {
6035     /* in SDL 1.2, hiding+grabbing the cursor was like SDL2's relative mouse mode. */
6036     if (VideoWindow20) {
6037         const SDL_bool enable = (VideoWindowGrabbed && VideoCursorHidden) ? SDL_TRUE : SDL_FALSE;
6038         if (MouseInputIsRelative != enable) {
6039             MouseInputIsRelative = enable;
6040             if (MouseInputIsRelative) {
6041                 /* reset position, we'll have to track it ourselves in SDL_MOUSEMOTION events, since 1.2
6042                  *  would give you window coordinates, even in relative mode. */
6043                 SDL20_GetMouseState(&MousePosition.x, &MousePosition.y);
6044                 AdjustOpenGLLogicalScalingPoint(&MousePosition.x, &MousePosition.y);
6045             }
6046             SDL20_SetRelativeMouseMode(MouseInputIsRelative);
6047         }
6048     }
6049 }
6050 
6051 DECLSPEC int SDLCALL
SDL_ShowCursor(int toggle)6052 SDL_ShowCursor(int toggle)
6053 {
6054     const int retval = VideoCursorHidden ? 0 : 1;
6055 
6056     if (toggle >= 0) {
6057         const SDL_bool wanthide = (toggle == 0) ? SDL_TRUE : SDL_FALSE;
6058         if (VideoCursorHidden != wanthide) {
6059             SDL20_ShowCursor(wanthide ? 0 : 1);
6060             VideoCursorHidden = wanthide;
6061             UpdateRelativeMouseMode();
6062         }
6063     }
6064     return retval;
6065 }
6066 
6067 static void
HandleInputGrab(SDL12_GrabMode mode)6068 HandleInputGrab(SDL12_GrabMode mode)
6069 {
6070     /* SDL 1.2 always grabbed input if the video mode was fullscreen. */
6071     const SDL_bool isfullscreen = (VideoSurface12 && (VideoSurface12->flags & SDL12_FULLSCREEN)) ? SDL_TRUE : SDL_FALSE;
6072     const SDL_bool wantgrab = (isfullscreen || (mode == SDL12_GRAB_ON)) ? SDL_TRUE : SDL_FALSE;
6073     if (VideoWindowGrabbed != wantgrab) {
6074         SDL20_SetWindowGrab(VideoWindow20, wantgrab);
6075         VideoWindowGrabbed = wantgrab;
6076         UpdateRelativeMouseMode();
6077     }
6078 }
6079 
6080 DECLSPEC SDL12_GrabMode SDLCALL
SDL_WM_GrabInput(SDL12_GrabMode mode)6081 SDL_WM_GrabInput(SDL12_GrabMode mode)
6082 {
6083     if (mode != SDL12_GRAB_QUERY) {
6084         HandleInputGrab(mode);
6085     }
6086     return VideoWindowGrabbed ? SDL12_GRAB_ON : SDL12_GRAB_OFF;
6087 }
6088 
6089 DECLSPEC void SDLCALL
SDL_WarpMouse(Uint16 x,Uint16 y)6090 SDL_WarpMouse(Uint16 x, Uint16 y)
6091 {
6092     if (MouseInputIsRelative) {  /* we have to track this ourselves, in case app calls SDL_GetMouseState(). */
6093         MousePosition.x = (int) x;
6094         MousePosition.y = (int) y;
6095     } else {
6096         SDL20_WarpMouseInWindow(VideoWindow20, x, y);
6097     }
6098 }
6099 
6100 DECLSPEC Uint8 SDLCALL
SDL_GetAppState(void)6101 SDL_GetAppState(void)
6102 {
6103     Uint8 state12 = 0;
6104     Uint32 flags20 = 0;
6105 
6106     flags20 = SDL20_GetWindowFlags(VideoWindow20);
6107     if ((flags20 & SDL_WINDOW_SHOWN) && !(flags20 & SDL_WINDOW_MINIMIZED)) {
6108         state12 |= SDL12_APPACTIVE;
6109     }
6110     if (flags20 & SDL_WINDOW_INPUT_FOCUS) {
6111         state12 |= SDL12_APPINPUTFOCUS;
6112     }
6113     if (flags20 & SDL_WINDOW_MOUSE_FOCUS) {
6114         state12 |= SDL12_APPMOUSEFOCUS;
6115     }
6116     return state12;
6117 }
6118 
6119 DECLSPEC int SDLCALL
SDL_SetColorKey(SDL12_Surface * surface12,Uint32 flag12,Uint32 key)6120 SDL_SetColorKey(SDL12_Surface *surface12, Uint32 flag12, Uint32 key)
6121 {
6122     const SDL_bool addkey = (flag12 & SDL12_SRCCOLORKEY) ? SDL_TRUE : SDL_FALSE;
6123     const int retval = SDL20_SetColorKey(surface12->surface20, addkey, key);
6124     if (SDL20_GetColorKey(surface12->surface20, &surface12->format->colorkey) < 0) {
6125         surface12->format->colorkey = 0;
6126     }
6127 
6128     if (addkey) {
6129         surface12->flags |= SDL12_SRCCOLORKEY;
6130     } else {
6131         surface12->flags &= ~SDL12_SRCCOLORKEY;
6132     }
6133 
6134     return retval;
6135 }
6136 
6137 DECLSPEC int SDLCALL
SDL_SetPalette(SDL12_Surface * surface12,int flags,const SDL_Color * colors,int firstcolor,int ncolors)6138 SDL_SetPalette(SDL12_Surface *surface12, int flags, const SDL_Color *colors,
6139                int firstcolor, int ncolors)
6140 {
6141     SDL12_Palette *palette12;
6142     SDL_Palette *palette20;
6143     SDL_Color *opaquecolors;
6144     int i, retval;
6145 
6146     if (!surface12) {
6147         return 0;  /* not an error, a no-op. */
6148     }
6149 
6150     if ((flags & (SDL12_LOGPAL | SDL12_PHYSPAL)) == 0) {
6151         return 0;  /* nothing to do. */
6152     }
6153 
6154     palette12 = surface12->format->palette;
6155     if (!palette12) {
6156         return 0;  /* not an error, a no-op. */
6157     }
6158 
6159     palette20 = surface12->surface20->format->palette;
6160     SDL_assert(palette20 != NULL);
6161 
6162     /* we need to force the "unused" field to 255, since it's "alpha" in SDL2. */
6163     opaquecolors = (SDL_Color *) SDL20_malloc(sizeof (SDL_Color) * ncolors);
6164     if (!opaquecolors) {
6165         return SDL20_OutOfMemory();
6166     }
6167 
6168     /* don't SDL_memcpy in case the 'a' field is uninitialized and upsets
6169      *  memory tools like Valgrind. */
6170     for (i = 0; i < ncolors; i++) {
6171         opaquecolors[i].r = colors[i].r;
6172         opaquecolors[i].g = colors[i].g;
6173         opaquecolors[i].b = colors[i].b;
6174         opaquecolors[i].a = 255;
6175     }
6176 
6177     retval = 0;
6178 
6179     if (flags & SDL12_LOGPAL) {
6180         if (SDL20_SetPaletteColors(palette20, opaquecolors, firstcolor, ncolors) < 0) {
6181             retval = -1;
6182         }
6183     }
6184 
6185     if ((flags & SDL12_PHYSPAL) && (surface12 == VideoSurface12) && VideoPhysicalPalette20) {
6186         if (SDL20_SetPaletteColors(VideoPhysicalPalette20, opaquecolors, firstcolor, ncolors) < 0) {
6187             retval = -1;
6188         }
6189     }
6190 
6191     SDL20_free(opaquecolors);
6192 
6193     /* in case this pointer changed... */
6194     palette12->colors = palette20->colors;
6195 
6196     if ((surface12 == VideoSurface12) && (flags & SDL12_PHYSPAL)) {
6197         SDL_UpdateRect(surface12, 0, 0, 0, 0);   /* force screen to reblit with new palette. */
6198     }
6199 
6200     return retval;
6201 }
6202 
6203 DECLSPEC int SDLCALL
SDL_SetColors(SDL12_Surface * surface12,const SDL_Color * colors,int firstcolor,int ncolors)6204 SDL_SetColors(SDL12_Surface *surface12, const SDL_Color * colors, int firstcolor,
6205               int ncolors)
6206 {
6207     return SDL_SetPalette(surface12, SDL12_LOGPAL | SDL12_PHYSPAL, colors, firstcolor, ncolors);
6208 }
6209 
6210 
6211 #if defined(SDL_VIDEO_DRIVER_X11)
6212 /* In 1.2, these would lock the event thread (if you _used_ the event thread), and call XSync(SDL_Display, False) before unlocking */
x11_lock_display(void)6213 static void x11_lock_display(void) {}
x11_unlock_display(void)6214 static void x11_unlock_display(void) {}
6215 #endif
6216 
6217 DECLSPEC int SDLCALL
SDL_GetWMInfo(SDL12_SysWMinfo * info12)6218 SDL_GetWMInfo(SDL12_SysWMinfo *info12)
6219 {
6220     SDL_SysWMinfo info20;
6221 
6222     if (info12->version.major > 1) {
6223         SDL20_SetError("Requested version is unsupported");
6224         return 0;  /* some programs only test against 0, not -1 */
6225     } else if (!SupportSysWM) {
6226         SDL20_SetError("No SysWM support available");
6227         return 0;  /* some programs only test against 0, not -1 */
6228     }
6229 
6230     SDL_zero(info20);
6231     SDL_VERSION(&info20.version);
6232     if (!SDL20_GetWindowWMInfo(VideoWindow20, &info20)) {
6233         return 0;  /* some programs only test against 0, not -1 */
6234     }
6235 
6236 #if defined(SDL_VIDEO_DRIVER_WINDOWS)
6237     SDL_assert(info20.subsystem == SDL_SYSWM_WINDOWS);
6238     info12->window = info20.info.win.window;
6239     if (SDL_VERSIONNUM(info12->version.major, info12->version.minor, info12->version.patch) >= SDL_VERSIONNUM(1, 2, 5)) {
6240         info12->hglrc = (HGLRC) VideoGLContext20;
6241     }
6242 #elif defined(SDL_VIDEO_DRIVER_X11)
6243     SDL_assert(info20.subsystem == SDL_SYSWM_X11);
6244     info12->subsystem = SDL12_SYSWM_X11;
6245     info12->info.x11.display = info20.info.x11.display;
6246     info12->info.x11.window = info20.info.x11.window;
6247     if (SDL_VERSIONNUM(info12->version.major, info12->version.minor, info12->version.patch) >= SDL_VERSIONNUM(1, 0, 2)) {
6248         info12->info.x11.fswindow = 0;  /* these don't exist in SDL2. */
6249         info12->info.x11.wmwindow = 0;
6250     }
6251     if (SDL_VERSIONNUM(info12->version.major, info12->version.minor, info12->version.patch) >= SDL_VERSIONNUM(1, 2, 12)) {
6252         info12->info.x11.gfxdisplay = info20.info.x11.display;  /* shrug */
6253     }
6254     info12->info.x11.lock_func = x11_lock_display;  /* just no-ops for now */
6255     info12->info.x11.unlock_func = x11_unlock_display;
6256 #else
6257     info12->data = 0;  /* shrug */
6258 #endif
6259 
6260     return 1;
6261 }
6262 
6263 DECLSPEC SDL12_Overlay * SDLCALL
SDL_CreateYUVOverlay(int w,int h,Uint32 format12,SDL12_Surface * display12)6264 SDL_CreateYUVOverlay(int w, int h, Uint32 format12, SDL12_Surface *display12)
6265 {
6266     /* SDL 1.2 has you pass the screen surface in here, but it doesn't check that it's _actually_ the screen surface,
6267        which implies you should be able to blit YUV overlays to other surfaces too...but then SDL_DisplayYUVOverlay
6268        always uses the screen surface unconditionally. As such, and because overlays were sort of hostile to software
6269        rendering anyhow, we always make an SDL_Texture in here and draw over the screen pixels, in hopes that the GPU
6270        gives us a boost here. */
6271 
6272     SDL12_Overlay *retval = NULL;
6273     SDL12_YUVData *hwdata = NULL;
6274     Uint32 format20 = 0;
6275 
6276     if (display12 != VideoSurface12) {  /* SDL 1.2 doesn't check this, but it seems irresponsible not to. */
6277         SDL20_SetError("YUV overlays are only supported on the screen surface");
6278         return NULL;
6279     }
6280 
6281     if (display12->flags & SDL12_OPENGL) {
6282         SDL20_SetError("YUV overlays are not supported in OpenGL mode");
6283         return NULL;
6284     }
6285 
6286     SDL_assert(VideoRenderer20 != NULL);
6287 
6288     switch (format12) {
6289         #define SUPPORTED_YUV_FORMAT(x) case SDL12_##x##_OVERLAY: format20 = SDL_PIXELFORMAT_##x; break
6290         SUPPORTED_YUV_FORMAT(YV12);
6291         SUPPORTED_YUV_FORMAT(IYUV);
6292         SUPPORTED_YUV_FORMAT(YUY2);
6293         SUPPORTED_YUV_FORMAT(UYVY);
6294         SUPPORTED_YUV_FORMAT(YVYU);
6295         #undef SUPPORTED_YUV_FORMAT
6296         default: SDL20_SetError("Unsupported YUV format"); return NULL;
6297     }
6298 
6299     retval = (SDL12_Overlay *) SDL20_calloc(1, sizeof (SDL12_Overlay) + sizeof (SDL12_YUVData));
6300     if (!retval) {
6301         SDL20_OutOfMemory();
6302         return NULL;
6303     }
6304 
6305     hwdata = (SDL12_YUVData *) (retval + 1);
6306     hwdata->pixelbuf = (Uint8 *) SDL20_calloc(1, (w * 2) * h);
6307     if (!hwdata->pixelbuf) {
6308         SDL20_free(retval);
6309         SDL20_OutOfMemory();
6310         return NULL;
6311     }
6312 
6313     hwdata->pixels[0] = hwdata->pixelbuf;
6314     if ((format12 == SDL12_YV12_OVERLAY) || (format12 == SDL12_IYUV_OVERLAY)) {
6315         retval->planes = 3;
6316         hwdata->pitches[0] = w;
6317         hwdata->pitches[1] = hwdata->pitches[2] = w / 2;
6318         hwdata->pixels[1] = hwdata->pixels[0] + (w * h);
6319         hwdata->pixels[2] = hwdata->pixels[1] + ((w / 2) * h);
6320     } else {
6321         retval->planes = 1;
6322         hwdata->pitches[0] = w * 2;
6323     }
6324 
6325     hwdata->texture20 = SDL20_CreateTexture(VideoRenderer20, format20, SDL_TEXTUREACCESS_STREAMING, w, h);
6326     if (!hwdata->texture20) {
6327         SDL20_free(hwdata->pixelbuf);
6328         SDL20_free(retval);
6329         return NULL;
6330     }
6331 
6332     retval->format = format12;
6333     retval->w = w;
6334     retval->h = h;
6335     retval->hwfuncs = (void *) 0x1;  /* in case it's important for this to be non-NULL. */
6336     retval->hwdata = hwdata;
6337     retval->hw_overlay = 1;
6338     retval->pitches = hwdata->pitches;
6339 
6340     return retval;
6341 }
6342 
6343 DECLSPEC int SDLCALL
SDL_LockYUVOverlay(SDL12_Overlay * overlay12)6344 SDL_LockYUVOverlay(SDL12_Overlay *overlay12)
6345 {
6346     SDL12_YUVData *hwdata;
6347 
6348     if (!overlay12) {
6349         return SDL20_InvalidParamError("overlay");
6350     }
6351 
6352     /* SMPEG locks the YUV overlay, calls SDL_DisplayYUVOverlay() on it,
6353        copies data to it then unlocks it, in that order, which _seems_ like an
6354        app bug, but it works in 1.2. Most of SDL 1.2's yuv lock/unlock
6355        implementations are just no-ops anyhow, so we upload during display,
6356        if the overlay has been locked since last time (and even
6357        if it is still locked), to accomodate this usage pattern. */
6358 
6359     hwdata = (SDL12_YUVData *) overlay12->hwdata;
6360     hwdata->dirty = SDL_TRUE;  /* assume the contents will change and we must upload */
6361     overlay12->pixels = hwdata->pixels;
6362 
6363     return 0;  /* success */
6364 }
6365 
6366 DECLSPEC int SDLCALL
SDL_DisplayYUVOverlay(SDL12_Overlay * overlay12,SDL12_Rect * dstrect12)6367 SDL_DisplayYUVOverlay(SDL12_Overlay *overlay12, SDL12_Rect *dstrect12)
6368 {
6369     SDL12_YUVData *hwdata;
6370 
6371     if (!overlay12) {
6372         return SDL20_InvalidParamError("overlay");
6373     } else if (!dstrect12) {
6374         return SDL20_InvalidParamError("dstrect");
6375     } else if (!VideoRenderer20) {
6376         return SDL20_SetError("No software screen surface available");
6377     }
6378 
6379     hwdata = (SDL12_YUVData *) overlay12->hwdata;
6380 
6381     /* Upload contents if we've been locked, even if we're _still_ locked, to
6382        work around an SMPEG quirk. */
6383     if (hwdata->dirty) {
6384         SDL_Rect rect20;
6385         rect20.x = rect20.y = 0;
6386         rect20.w = overlay12->w;
6387         rect20.h = overlay12->h;
6388         if (overlay12->format == SDL12_IYUV_OVERLAY) {
6389             SDL20_UpdateYUVTexture(hwdata->texture20, &rect20,
6390                                  hwdata->pixels[0], hwdata->pitches[0],
6391                                  hwdata->pixels[1], hwdata->pitches[1],
6392                                  hwdata->pixels[2], hwdata->pitches[2]);
6393         } else if (overlay12->format == SDL12_YV12_OVERLAY) {
6394             SDL20_UpdateYUVTexture(hwdata->texture20, &rect20,
6395                                  hwdata->pixels[0], hwdata->pitches[0],
6396                                  hwdata->pixels[2], hwdata->pitches[2],
6397                                  hwdata->pixels[1], hwdata->pitches[1]);
6398         } else {
6399             SDL20_UpdateTexture(hwdata->texture20, &rect20, hwdata->pixels[0], hwdata->pitches[0]);
6400         }
6401 
6402         if (overlay12->pixels == NULL) {  /* must leave it marked as dirty if still locked! */
6403             hwdata->dirty = SDL_FALSE;
6404         }
6405     }
6406 
6407     /* The app may or may not SDL_Flip() after this...queue this to render on the next present,
6408        and start a timer going to force a present, in case they don't. */
6409     FIXME("is it legal to display multiple yuv overlays?");  /* if so, this will need to be a list instead of a single pointer. */
6410     QueuedDisplayOverlay12 = overlay12;
6411     SDL20_memcpy(&QueuedDisplayOverlayDstRect12, dstrect12, sizeof (SDL12_Rect));
6412     VideoSurfacePresentTicks = VideoSurfaceLastPresentTicks + GetDesiredMillisecondsPerFrame();  /* flip it later. */
6413 
6414     return 0;
6415 }
6416 
6417 DECLSPEC void SDLCALL
SDL_UnlockYUVOverlay(SDL12_Overlay * overlay12)6418 SDL_UnlockYUVOverlay(SDL12_Overlay *overlay12)
6419 {
6420     if (overlay12) {
6421         overlay12->pixels = NULL;
6422     }
6423 }
6424 
6425 DECLSPEC void SDLCALL
SDL_FreeYUVOverlay(SDL12_Overlay * overlay12)6426 SDL_FreeYUVOverlay(SDL12_Overlay *overlay12)
6427 {
6428     if (overlay12) {
6429         SDL12_YUVData *hwdata = (SDL12_YUVData *) overlay12->hwdata;
6430         SDL20_DestroyTexture(hwdata->texture20);
6431         SDL20_free(hwdata->pixelbuf);
6432         SDL20_free(overlay12);
6433     }
6434 }
6435 
6436 DECLSPEC void * SDLCALL
SDL_GL_GetProcAddress(const char * sym)6437 SDL_GL_GetProcAddress(const char *sym)
6438 {
6439     /* see comments on glBindFramebuffer_shim_for_scaling for explanation */
6440     if ((SDL20_strcmp(sym, "glBindFramebuffer") == 0) || (SDL20_strcmp(sym, "glBindFramebufferEXT") == 0)) {
6441         return (void *) glBindFramebuffer_shim_for_scaling;
6442     }
6443 
6444     /* these functions all need to have an MSAA resolve inserted before use */
6445     if ((SDL20_strcmp(sym, "glReadPixels") == 0)) {
6446         return (void *) glReadPixels_shim_for_scaling;
6447     }
6448     if ((SDL20_strcmp(sym, "glCopyPixels") == 0)) {
6449         return (void *) glCopyPixels_shim_for_scaling;
6450     }
6451     if ((SDL20_strcmp(sym, "glCopyTexImage1D") == 0)) {
6452         return (void *) glCopyTexImage1D_shim_for_scaling;
6453     }
6454     if ((SDL20_strcmp(sym, "glCopyTexSubImage1D") == 0)) {
6455         return (void *) glCopyTexSubImage1D_shim_for_scaling;
6456     }
6457     if ((SDL20_strcmp(sym, "glCopyTexImage2D") == 0)) {
6458         return (void *) glCopyTexImage2D_shim_for_scaling;
6459     }
6460     if ((SDL20_strcmp(sym, "glCopyTexSubImage2D") == 0)) {
6461         return (void *) glCopyTexSubImage2D_shim_for_scaling;
6462     }
6463     if ((SDL20_strcmp(sym, "glCopyTexSubImage3D") == 0)) {
6464         return (void *) glCopyTexSubImage3D_shim_for_scaling;
6465     }
6466     return SDL20_GL_GetProcAddress(sym);
6467 }
6468 
6469 DECLSPEC int SDLCALL
SDL_GL_LoadLibrary(const char * libname)6470 SDL_GL_LoadLibrary(const char *libname)
6471 {
6472     /* SDL 1.2 would unload the previous library if one was loaded. SDL2
6473        reports an error if one is already loaded, and sometimes loads it
6474        internally for some video targets, so unloading it probably isn't safe.
6475        There really isn't a good reason to be using anything other than the
6476        system OpenGL in 2019, so we ignore the error in this case to match 1.2
6477        behavior, even if you were going to load a different library this time.
6478        Oh well. */
6479     const int rc = SDL20_GL_LoadLibrary(libname);
6480     if (rc < 0) {
6481         const char *err = SDL20_GetError();
6482         char *dup;
6483 
6484         if (SDL20_strcmp(err, "OpenGL library already loaded") == 0) {
6485             return 0;
6486         }
6487         /* reset the actual error. */
6488         dup = SDL20_strdup(err);
6489         if (!dup) {
6490             SDL20_OutOfMemory();
6491         } else {
6492             SDL20_SetError(dup);
6493             SDL20_free(dup);
6494         }
6495     }
6496     return rc;
6497 }
6498 
6499 
6500 DECLSPEC int SDLCALL
SDL_GL_SetAttribute(SDL12_GLattr attr,int value)6501 SDL_GL_SetAttribute(SDL12_GLattr attr, int value)
6502 {
6503     if (attr >= SDL12_GL_MAX_ATTRIBUTE) {
6504         return SDL20_SetError("Unknown GL attribute");
6505     }
6506 
6507     /* swap control was moved out of this API, everything else lines up. */
6508     if (attr == SDL12_GL_SWAP_CONTROL) {
6509         SwapInterval = value;
6510         return 0;
6511     }
6512     else if (attr == SDL12_GL_MULTISAMPLESAMPLES) {
6513         OpenGLLogicalScalingSamples = value;
6514         return 0;
6515     }
6516     else if (attr == SDL12_GL_MULTISAMPLEBUFFERS) {
6517         return 0;
6518     }
6519     return SDL20_GL_SetAttribute((SDL_GLattr) attr, value);
6520 }
6521 
6522 DECLSPEC int SDLCALL
SDL_GL_GetAttribute(SDL12_GLattr attr,int * value)6523 SDL_GL_GetAttribute(SDL12_GLattr attr, int* value)
6524 {
6525     int retval;
6526 
6527     if (attr >= SDL12_GL_MAX_ATTRIBUTE) {
6528         return SDL20_SetError("Unknown GL attribute");
6529     }
6530     /* swap control was moved out of this API, everything else lines up. */
6531     if (attr == SDL12_GL_SWAP_CONTROL) {
6532         *value = SDL20_GL_GetSwapInterval();
6533         return 0;
6534     }
6535     else if (attr == SDL12_GL_MULTISAMPLESAMPLES) {
6536         *value = OpenGLLogicalScalingSamples;
6537         return 0;
6538     }
6539     else if (attr == SDL12_GL_MULTISAMPLEBUFFERS) {
6540         *value = (OpenGLLogicalScalingSamples) ? 1 : 0;
6541         return 0;
6542     }
6543 
6544     /* SDL2 has a bug where FBO 0 must be bound or SDL20_GL_GetAttribute gives incorrect information.
6545        See https://github.com/libsdl-org/sdl12-compat/issues/150 */
6546     if (OpenGLCurrentDrawFBO == 0) {
6547         retval = SDL20_GL_GetAttribute((SDL_GLattr) attr, value);
6548     } else {
6549         SDL_assert(OpenGLFuncs.glBindFramebuffer != NULL);
6550         OpenGLFuncs.glBindFramebuffer(GL_DRAW_FRAMEBUFFER, 0);
6551         retval = SDL20_GL_GetAttribute((SDL_GLattr) attr, value);
6552         OpenGLFuncs.glBindFramebuffer(GL_DRAW_FRAMEBUFFER, OpenGLCurrentDrawFBO);
6553     }
6554 
6555     return retval;
6556 }
6557 
6558 
6559 DECLSPEC void SDLCALL
SDL_GL_SwapBuffers(void)6560 SDL_GL_SwapBuffers(void)
6561 {
6562     if (VideoWindow20) {
6563         if (OpenGLLogicalScalingFBO != 0) {
6564             const GLboolean has_scissor = OpenGLFuncs.glIsEnabled(GL_SCISSOR_TEST);
6565             const char *scale_method_env = SDL20_getenv("SDL12COMPAT_SCALE_METHOD");
6566             const SDL_bool want_nearest = (scale_method_env && !SDL20_strcmp(scale_method_env, "nearest"))? SDL_TRUE : SDL_FALSE;
6567             int physical_w, physical_h;
6568             GLfloat clearcolor[4];
6569             SDL_Rect dstrect;
6570 
6571             /* use the drawable size, which is != window size for HIGHDPI systems */
6572             SDL20_GL_GetDrawableSize(VideoWindow20, &physical_w, &physical_h);
6573             dstrect = GetOpenGLLogicalScalingViewport(physical_w, physical_h);
6574 
6575             OpenGLFuncs.glGetFloatv(GL_COLOR_CLEAR_VALUE, clearcolor);
6576 
6577             if (has_scissor) {
6578                 OpenGLFuncs.glDisable(GL_SCISSOR_TEST);  /* scissor test affects framebuffer_blit */
6579             }
6580 
6581             OpenGLFuncs.glBindFramebuffer(GL_READ_FRAMEBUFFER, OpenGLLogicalScalingFBO);
6582 
6583             /* Resolve the multisample framebuffer if required. */
6584             if (OpenGLLogicalScalingMultisampleFBO) {
6585                 OpenGLFuncs.glBindFramebuffer(GL_DRAW_FRAMEBUFFER, OpenGLLogicalScalingMultisampleFBO);
6586                 OpenGLFuncs.glBlitFramebuffer(0, 0, OpenGLLogicalScalingWidth, OpenGLLogicalScalingHeight,
6587                                               0, 0, OpenGLLogicalScalingWidth, OpenGLLogicalScalingHeight,
6588                                               GL_COLOR_BUFFER_BIT, GL_NEAREST);
6589                 OpenGLFuncs.glBindFramebuffer(GL_READ_FRAMEBUFFER, OpenGLLogicalScalingMultisampleFBO);
6590             }
6591 
6592             OpenGLFuncs.glBindFramebuffer(GL_DRAW_FRAMEBUFFER, 0);
6593             OpenGLFuncs.glClearColor(0.0f, 0.0f, 0.0f, 1.0f);
6594             OpenGLFuncs.glClear(GL_COLOR_BUFFER_BIT);
6595             OpenGLFuncs.glBlitFramebuffer(0, 0, OpenGLLogicalScalingWidth, OpenGLLogicalScalingHeight,
6596                                           dstrect.x, dstrect.y, dstrect.x + dstrect.w, dstrect.y + dstrect.h,
6597                                           GL_COLOR_BUFFER_BIT, want_nearest?GL_NEAREST:GL_LINEAR);
6598             OpenGLFuncs.glBindFramebuffer(GL_FRAMEBUFFER, 0);
6599             SDL20_GL_SwapWindow(VideoWindow20);
6600             OpenGLFuncs.glClearColor(clearcolor[0], clearcolor[1], clearcolor[2], clearcolor[3]);
6601             if (has_scissor) {
6602                 OpenGLFuncs.glEnable(GL_SCISSOR_TEST);
6603             }
6604             OpenGLFuncs.glBindFramebuffer(GL_READ_FRAMEBUFFER, OpenGLCurrentReadFBO);
6605             OpenGLFuncs.glBindFramebuffer(GL_DRAW_FRAMEBUFFER, OpenGLCurrentDrawFBO);
6606         } else {
6607             SDL20_GL_SwapWindow(VideoWindow20);
6608         }
6609     }
6610 }
6611 
6612 DECLSPEC int SDLCALL
SDL_SetGamma(float red,float green,float blue)6613 SDL_SetGamma(float red, float green, float blue)
6614 {
6615     Uint16 red_ramp[256];
6616     Uint16 green_ramp[256];
6617     Uint16 blue_ramp[256];
6618 
6619     SDL20_CalculateGammaRamp(red, red_ramp);
6620     if (green == red) {
6621         SDL20_memcpy(green_ramp, red_ramp, sizeof(red_ramp));
6622     } else {
6623         SDL20_CalculateGammaRamp(green, green_ramp);
6624     }
6625     if (blue == red) {
6626         SDL20_memcpy(blue_ramp, red_ramp, sizeof(red_ramp));
6627     } else if (blue == green) {
6628         SDL20_memcpy(blue_ramp, green_ramp, sizeof(green_ramp));
6629     } else {
6630         SDL20_CalculateGammaRamp(blue, blue_ramp);
6631     }
6632     return SDL20_SetWindowGammaRamp(VideoWindow20, red_ramp, green_ramp, blue_ramp);
6633 }
6634 
6635 DECLSPEC int SDLCALL
SDL_SetGammaRamp(const Uint16 * red,const Uint16 * green,const Uint16 * blue)6636 SDL_SetGammaRamp(const Uint16 *red, const Uint16 *green, const Uint16 *blue)
6637 {
6638     return SDL20_SetWindowGammaRamp(VideoWindow20, red, green, blue);
6639 }
6640 
6641 DECLSPEC int SDLCALL
SDL_GetGammaRamp(Uint16 * red,Uint16 * green,Uint16 * blue)6642 SDL_GetGammaRamp(Uint16 *red, Uint16 *green, Uint16 *blue)
6643 {
6644     return SDL20_GetWindowGammaRamp(VideoWindow20, red, green, blue);
6645 }
6646 
6647 DECLSPEC int SDLCALL
SDL_EnableKeyRepeat(int delay,int interval)6648 SDL_EnableKeyRepeat(int delay, int interval)
6649 {
6650     FIXME("Support non-default delay and interval for Key Repeat");
6651     (void) interval;
6652 
6653     EnabledKeyRepeat = (delay != 0) ? SDL_TRUE : SDL_FALSE;
6654 
6655     return 0;
6656 }
6657 
6658 DECLSPEC void SDLCALL
SDL_GetKeyRepeat(int * delay,int * interval)6659 SDL_GetKeyRepeat(int *delay, int *interval)
6660 {
6661     if (delay) {
6662         *delay = EnabledKeyRepeat ? SDL12_DEFAULT_REPEAT_DELAY : 0;
6663     }
6664     if (interval) {
6665         *interval = EnabledKeyRepeat ? SDL12_DEFAULT_REPEAT_INTERVAL : 0;
6666     }
6667 }
6668 
6669 DECLSPEC int SDLCALL
SDL_EnableUNICODE(int enable)6670 SDL_EnableUNICODE(int enable)
6671 {
6672     const int old = EnabledUnicode;
6673     if (enable >= 0) {
6674         EnabledUnicode = enable;
6675         if (enable) {
6676             SDL20_StartTextInput();
6677         } else {
6678             SDL20_StopTextInput();
6679         }
6680     }
6681     return old;
6682 }
6683 
6684 /* SDL 1.2 limited timers to a 10ms resolution. SDL 2.0 doesn't, so we might
6685    have to round. This is the equation 1.2 uses: */
RoundTimerTo12Resolution(const Uint32 ms)6686 static Uint32 RoundTimerTo12Resolution(const Uint32 ms)
6687 {
6688     return (((ms + 10) - 1) / 10) * 10;
6689 }
6690 
6691 
6692 static Uint32 SDLCALL
SetTimerCallback12(Uint32 interval,void * param)6693 SetTimerCallback12(Uint32 interval, void* param)
6694 {
6695     return RoundTimerTo12Resolution(((SDL12_TimerCallback)param)(interval));
6696 }
6697 
6698 DECLSPEC int SDLCALL
SDL_SetTimer(Uint32 interval,SDL12_TimerCallback callback)6699 SDL_SetTimer(Uint32 interval, SDL12_TimerCallback callback)
6700 {
6701     static SDL_TimerID compat_timer;
6702 
6703     if (compat_timer) {
6704         SDL20_RemoveTimer(compat_timer);
6705         compat_timer = 0;
6706     }
6707 
6708     if (interval && callback) {
6709         interval = RoundTimerTo12Resolution(interval);
6710         compat_timer = SDL20_AddTimer(interval, SetTimerCallback12, (void*)callback);
6711         if (!compat_timer) {
6712             return -1;
6713         }
6714     }
6715     return 0;
6716 }
6717 
6718 DECLSPEC int SDLCALL
SDL_putenv(const char * _var)6719 SDL_putenv(const char *_var)
6720 {
6721     char *ptr = NULL;
6722     char *var = SDL20_strdup(_var);
6723     if (var == NULL) {
6724         return -1;  /* we don't set errno. */
6725     }
6726 
6727     ptr = SDL20_strchr(var, '=');
6728     if (ptr == NULL) {
6729         SDL20_free(var);
6730         return -1;
6731     }
6732 
6733     *ptr = '\0';  /* split the string into name and value. */
6734     SDL20_setenv(var, ptr + 1, 1);
6735     SDL20_free(var);
6736     return 0;
6737 }
6738 
6739 
6740 #if (defined(_WIN32) || defined(__OS2__)) && !defined(SDL_PASSED_BEGINTHREAD_ENDTHREAD)
6741 #error SDL_PASSED_BEGINTHREAD_ENDTHREAD not defined
6742 #endif
6743 #ifdef SDL_PASSED_BEGINTHREAD_ENDTHREAD
6744 #ifdef _WIN32
6745 /* Official Windows versions of SDL-1.2 >= 1.2.10 were always built
6746  * with HAVE_LIBC, i.e.: *without* SDL_PASSED_BEGINTHREAD_ENDTHREAD
6747  * defined, in order to keep binary compatibility with SDL <= 1.2.9.
6748  *
6749  * On the other hand SDL2 >= 2.0.12, as we dictate for Windows does
6750  * always define SDL_PASSED_BEGINTHREAD_ENDTHREAD, in order to keep
6751  * SDL2 versions built with and without libc binary compatible with
6752  * each other.
6753  *
6754  * Therefore, we have to do the following trick below. */
6755 DECLSPEC SDL_Thread * SDLCALL
SDL_CreateThread(int (SDLCALL * fn)(void *),void * data)6756 SDL_CreateThread(int (SDLCALL *fn)(void *), void *data)
6757 {
6758     return SDL20_CreateThread(fn, NULL, data, NULL, NULL);
6759 }
6760 #else
6761 DECLSPEC SDL_Thread * SDLCALL
SDL_CreateThread(int (SDLCALL * fn)(void *),void * data,pfnSDL_CurrentBeginThread pfnBeginThread,pfnSDL_CurrentEndThread pfnEndThread)6762 SDL_CreateThread(int (SDLCALL *fn)(void *), void *data, pfnSDL_CurrentBeginThread pfnBeginThread, pfnSDL_CurrentEndThread pfnEndThread)
6763 {
6764     return SDL20_CreateThread(fn, NULL, data, pfnBeginThread, pfnEndThread);
6765 }
6766 #endif
6767 #else
6768 DECLSPEC SDL_Thread * SDLCALL
SDL_CreateThread(int (SDLCALL * fn)(void *),void * data)6769 SDL_CreateThread(int (SDLCALL *fn)(void *), void *data)
6770 {
6771     return SDL20_CreateThread(fn, NULL, data);
6772 }
6773 #endif
6774 
6775 /* These two will truncate the returned value on LP64 systems,
6776  * a shortcoming of SDL-1.2. */
SDL_ThreadID(void)6777 DECLSPEC Uint32 SDLCALL SDL_ThreadID(void)
6778 {
6779     return SDL20_ThreadID();
6780 }
SDL_GetThreadID(SDL_Thread * thread)6781 DECLSPEC Uint32 SDLCALL SDL_GetThreadID(SDL_Thread *thread)
6782 {
6783     return SDL20_GetThreadID(thread);
6784 }
6785 
6786 DECLSPEC int SDLCALL
SDL_mutexP(SDL_mutex * mutex)6787 SDL_mutexP(SDL_mutex *mutex)
6788 {
6789     return SDL20_LockMutex(mutex);
6790 }
6791 
6792 DECLSPEC int SDLCALL
SDL_mutexV(SDL_mutex * mutex)6793 SDL_mutexV(SDL_mutex *mutex)
6794 {
6795     return SDL20_UnlockMutex(mutex);
6796 }
6797 
6798 DECLSPEC void SDLCALL
SDL_KillThread(SDL_Thread * thread)6799 SDL_KillThread(SDL_Thread *thread)
6800 {
6801     (void)thread;
6802     SDL20_Log("WARNING: this app used SDL_KillThread(), an unforgivable curse.\n"
6803               "This program should be fixed. No thread was actually harmed.\n");
6804 }
6805 
6806 typedef struct SDL12_TimerID_Data
6807 {
6808     SDL_TimerID timer_id;
6809     SDL12_NewTimerCallback callback;
6810     void *param;
6811 } SDL12_TimerID_Data;
6812 
6813 /* This changed from an opaque pointer to an int in 2.0. */
6814 typedef SDL12_TimerID_Data *SDL12_TimerID;
6815 SDL_COMPILE_TIME_ASSERT(timer, sizeof(SDL12_TimerID) >= sizeof(SDL_TimerID));
6816 
6817 
6818 static Uint32 SDLCALL
AddTimerCallback12(Uint32 interval,void * param)6819 AddTimerCallback12(Uint32 interval, void *param)
6820 {
6821     SDL12_TimerID data = (SDL12_TimerID) param;
6822     return RoundTimerTo12Resolution(data->callback(interval, data->param));
6823 }
6824 
6825 DECLSPEC SDL12_TimerID SDLCALL
SDL_AddTimer(Uint32 interval,SDL12_NewTimerCallback callback,void * param)6826 SDL_AddTimer(Uint32 interval, SDL12_NewTimerCallback callback, void *param)
6827 {
6828     SDL12_TimerID data = (SDL12_TimerID) SDL20_malloc(sizeof (SDL12_TimerID_Data));
6829     if (!data) {
6830         SDL20_OutOfMemory();
6831         return NULL;
6832     }
6833 
6834     interval = RoundTimerTo12Resolution(interval);
6835     data->callback = callback;
6836     data->param = param;
6837     data->timer_id = SDL20_AddTimer(interval, AddTimerCallback12, data);
6838 
6839     if (!data->timer_id) {
6840         SDL20_free(data);
6841         return NULL;
6842     }
6843 
6844     return data;
6845 }
6846 
6847 DECLSPEC SDL_bool SDLCALL
SDL_RemoveTimer(SDL12_TimerID data)6848 SDL_RemoveTimer(SDL12_TimerID data)
6849 {
6850     /* !!! FIXME:  1.2 will safely return SDL_FALSE if this is a
6851      * bogus timer. This code will dereference a bogus pointer. */
6852     const SDL_bool retval = SDL20_RemoveTimer(data->timer_id);
6853     if (retval) {
6854         SDL20_free(data);
6855     }
6856     return retval;
6857 }
6858 
6859 
6860 typedef struct SDL12_RWops {
6861     int (SDLCALL *seek)(struct SDL12_RWops *context, int offset, int whence);
6862     int (SDLCALL *read)(struct SDL12_RWops *context, void *ptr, int size, int maxnum);
6863     int (SDLCALL *write)(struct SDL12_RWops *context, const void *ptr, int size, int num);
6864     int (SDLCALL *close)(struct SDL12_RWops *context);
6865     Uint32 type;
6866     void *padding[8];
6867     SDL_RWops *rwops20;
6868 } SDL12_RWops;
6869 
6870 
6871 DECLSPEC SDL12_RWops * SDLCALL
SDL_AllocRW(void)6872 SDL_AllocRW(void)
6873 {
6874     SDL12_RWops *rwops = (SDL12_RWops *) SDL20_malloc(sizeof (SDL12_RWops));
6875     if (!rwops) {
6876         SDL20_OutOfMemory();
6877     }
6878     return rwops;
6879 }
6880 
6881 DECLSPEC void SDLCALL
SDL_FreeRW(SDL12_RWops * rwops12)6882 SDL_FreeRW(SDL12_RWops *rwops12)
6883 {
6884     SDL20_free(rwops12);
6885 }
6886 
6887 static int SDLCALL
RWops20to12_seek(struct SDL12_RWops * rwops12,int offset,int whence)6888 RWops20to12_seek(struct SDL12_RWops *rwops12, int offset, int whence)
6889 {
6890     return (int)rwops12->rwops20->seek(rwops12->rwops20, offset, whence);
6891 }
6892 
6893 static int SDLCALL
RWops20to12_read(struct SDL12_RWops * rwops12,void * ptr,int size,int maxnum)6894 RWops20to12_read(struct SDL12_RWops *rwops12, void *ptr, int size, int maxnum)
6895 {
6896     return (int)rwops12->rwops20->read(rwops12->rwops20, ptr, size, maxnum);
6897 }
6898 
6899 static int SDLCALL
RWops20to12_write(struct SDL12_RWops * rwops12,const void * ptr,int size,int num)6900 RWops20to12_write(struct SDL12_RWops *rwops12, const void *ptr, int size, int num)
6901 {
6902     return (int)rwops12->rwops20->write(rwops12->rwops20, ptr, size, num);
6903 }
6904 
6905 static int SDLCALL
RWops20to12_close(struct SDL12_RWops * rwops12)6906 RWops20to12_close(struct SDL12_RWops *rwops12)
6907 {
6908     int rc = 0;
6909     if (rwops12) {
6910         rc = rwops12->rwops20->close(rwops12->rwops20);
6911         if (rc == 0) {
6912             SDL_FreeRW(rwops12);
6913         }
6914     }
6915     return rc;
6916 }
6917 
6918 static SDL12_RWops *
RWops20to12(SDL_RWops * rwops20)6919 RWops20to12(SDL_RWops *rwops20)
6920 {
6921     SDL12_RWops *rwops12;
6922 
6923     if (!rwops20) {
6924         return NULL;
6925     }
6926 
6927     rwops12 = SDL_AllocRW();
6928     if (!rwops12) {
6929         return NULL;
6930     }
6931 
6932     SDL20_zerop(rwops12);
6933     rwops12->type = rwops20->type;
6934     rwops12->rwops20 = rwops20;
6935     rwops12->seek = RWops20to12_seek;
6936     rwops12->read = RWops20to12_read;
6937     rwops12->write = RWops20to12_write;
6938     rwops12->close = RWops20to12_close;
6939 
6940     return rwops12;
6941 }
6942 
6943 DECLSPEC SDL12_RWops * SDLCALL
SDL_RWFromFile(const char * file,const char * mode)6944 SDL_RWFromFile(const char *file, const char *mode)
6945 {
6946     if (!file || !*file || !mode || !*mode) {
6947         SDL20_SetError("SDL_RWFromFile(): No file or no mode specified");
6948         return NULL;
6949     }
6950     return RWops20to12(SDL20_RWFromFile(file, mode));
6951 }
6952 
6953 DECLSPEC SDL12_RWops * SDLCALL
SDL_RWFromFP(void * io,int autoclose)6954 SDL_RWFromFP(void *io, int autoclose)
6955 {
6956     return RWops20to12(SDL20_RWFromFP(io, autoclose));
6957 }
6958 
6959 DECLSPEC SDL12_RWops * SDLCALL
SDL_RWFromMem(void * mem,int size)6960 SDL_RWFromMem(void *mem, int size)
6961 {
6962     return RWops20to12(SDL20_RWFromMem(mem, size));
6963 }
6964 
6965 DECLSPEC SDL12_RWops * SDLCALL
SDL_RWFromConstMem(const void * mem,int size)6966 SDL_RWFromConstMem(const void *mem, int size)
6967 {
6968     return RWops20to12(SDL20_RWFromConstMem(mem, size));
6969 }
6970 
6971 #define READ_AND_BYTESWAP(endian, bits) \
6972     DECLSPEC Uint##bits SDLCALL SDL_Read##endian##bits(SDL12_RWops *rwops12) { \
6973         Uint##bits val; rwops12->read(rwops12, &val, sizeof (val), 1); \
6974         return SDL_Swap##endian##bits(val); \
6975     }
6976 
6977 READ_AND_BYTESWAP(LE,16)
6978 READ_AND_BYTESWAP(BE,16)
6979 READ_AND_BYTESWAP(LE,32)
6980 READ_AND_BYTESWAP(BE,32)
6981 READ_AND_BYTESWAP(LE,64)
6982 READ_AND_BYTESWAP(BE,64)
6983 #undef READ_AND_BYTESWAP
6984 
6985 #define BYTESWAP_AND_WRITE(endian, bits) \
6986     DECLSPEC int SDLCALL SDL_Write##endian##bits(SDL12_RWops *rwops12, Uint##bits val) { \
6987         val = SDL_Swap##endian##bits(val); \
6988         return rwops12->write(rwops12, &val, sizeof (val), 1); \
6989     }
6990 BYTESWAP_AND_WRITE(LE,16)
6991 BYTESWAP_AND_WRITE(BE,16)
6992 BYTESWAP_AND_WRITE(LE,32)
6993 BYTESWAP_AND_WRITE(BE,32)
6994 BYTESWAP_AND_WRITE(LE,64)
6995 BYTESWAP_AND_WRITE(BE,64)
6996 #undef BYTESWAP_AND_WRITE
6997 
6998 
6999 static Sint64 SDLCALL
RWops12to20_size(struct SDL_RWops * rwops20)7000 RWops12to20_size(struct SDL_RWops *rwops20)
7001 {
7002     SDL12_RWops *rwops12 = (SDL12_RWops *) rwops20->hidden.unknown.data1;
7003     int size = (int) ((intptr_t) rwops20->hidden.unknown.data2);
7004     int pos;
7005 
7006     if (size != -1) {
7007         return size;
7008     }
7009 
7010     pos = rwops12->seek(rwops12, 0, RW_SEEK_CUR);
7011     if (pos == -1) {
7012         return SDL20_Error(SDL_EFSEEK);
7013     }
7014     size = rwops12->seek(rwops12, 0, RW_SEEK_END);
7015     rwops12->seek(rwops12, pos, RW_SEEK_SET);
7016     rwops20->hidden.unknown.data2 = (void *) ((intptr_t) size);
7017     return size;
7018 }
7019 
7020 static Sint64 SDLCALL
RWops12to20_seek(struct SDL_RWops * rwops20,Sint64 offset,int whence)7021 RWops12to20_seek(struct SDL_RWops *rwops20, Sint64 offset, int whence)
7022 {
7023     SDL12_RWops *rwops12 = (SDL12_RWops *) rwops20->hidden.unknown.data1;
7024     if (offset < INT_MIN || offset > INT_MAX) {
7025         return SDL20_InvalidParamError("offset");
7026     }
7027     return (Sint64) rwops12->seek(rwops12, (int) offset, whence);
7028 }
7029 
7030 static size_t SDLCALL
RWops12to20_read(struct SDL_RWops * rwops20,void * ptr,size_t size,size_t maxnum)7031 RWops12to20_read(struct SDL_RWops *rwops20, void *ptr, size_t size, size_t maxnum)
7032 {
7033     SDL12_RWops *rwops12 = (SDL12_RWops *) rwops20->hidden.unknown.data1;
7034     if (size > INT_MAX || maxnum > INT_MAX) {
7035         SDL20_InvalidParamError("size' or 'num");
7036         return 0;
7037     }
7038     return (size_t) rwops12->read(rwops12, ptr, (int) size, (int) maxnum);
7039 }
7040 
7041 static size_t SDLCALL
RWops12to20_write(struct SDL_RWops * rwops20,const void * ptr,size_t size,size_t num)7042 RWops12to20_write(struct SDL_RWops *rwops20, const void *ptr, size_t size, size_t num)
7043 {
7044     SDL12_RWops *rwops12 = (SDL12_RWops *) rwops20->hidden.unknown.data1;
7045     if (size > INT_MAX || num > INT_MAX) {
7046         SDL20_InvalidParamError("size' or 'num");
7047         return 0;
7048     }
7049     return (size_t) rwops12->write(rwops12, ptr, (int) size, (int) num);
7050 }
7051 
7052 static int SDLCALL
RWops12to20_close(struct SDL_RWops * rwops20)7053 RWops12to20_close(struct SDL_RWops *rwops20)
7054 {
7055     int rc = 0;
7056     if (rwops20) {
7057         SDL12_RWops *rwops12 = (SDL12_RWops *) rwops20->hidden.unknown.data1;
7058         rc = rwops12->close(rwops12);
7059         SDL20_FreeRW(rwops20);
7060     }
7061     return rc;
7062 }
7063 
7064 static SDL_RWops *
RWops12to20(SDL12_RWops * rwops12)7065 RWops12to20(SDL12_RWops *rwops12)
7066 {
7067     SDL_RWops *rwops20;
7068 
7069     if (!rwops12) {
7070         return NULL;
7071     }
7072 
7073     rwops20 = SDL20_AllocRW();
7074     if (!rwops20) {
7075         return NULL;
7076     }
7077 
7078     SDL20_zerop(rwops20);
7079     rwops20->type = rwops12->type;
7080     rwops20->hidden.unknown.data1 = rwops12;
7081     rwops20->hidden.unknown.data2 = (void *) ((intptr_t) -1);   /* cached size of stream */
7082     rwops20->size = RWops12to20_size;
7083     rwops20->seek = RWops12to20_seek;
7084     rwops20->read = RWops12to20_read;
7085     rwops20->write = RWops12to20_write;
7086     rwops20->close = RWops12to20_close;
7087     return rwops20;
7088 }
7089 
7090 DECLSPEC SDL12_Surface * SDLCALL
SDL_LoadBMP_RW(SDL12_RWops * rwops12,int freerwops12)7091 SDL_LoadBMP_RW(SDL12_RWops *rwops12, int freerwops12)
7092 {
7093     SDL_RWops *rwops20 = RWops12to20(rwops12);
7094     SDL_Surface *surface20 = SDL20_LoadBMP_RW(rwops20, freerwops12);
7095     SDL12_Surface *surface12 = Surface20to12(surface20);
7096     if (!freerwops12) { /* free our wrapper if SDL2 didn't close it. */
7097         SDL20_FreeRW(rwops20);
7098     }
7099     if ((!surface12) && (surface20)) {
7100         SDL20_FreeSurface(surface20);
7101     }
7102     return surface12;
7103 }
7104 
7105 DECLSPEC int SDLCALL
SDL_SaveBMP_RW(SDL12_Surface * surface12,SDL12_RWops * rwops12,int freerwops12)7106 SDL_SaveBMP_RW(SDL12_Surface *surface12, SDL12_RWops *rwops12, int freerwops12)
7107 {
7108     SDL_RWops *rwops20 = RWops12to20(rwops12);
7109     const int retval = SDL20_SaveBMP_RW(surface12->surface20, rwops20, freerwops12);
7110     if (!freerwops12) {  /* free our wrapper if SDL2 didn't close it. */
7111         SDL20_FreeRW(rwops20);
7112     }
7113     return retval;
7114 }
7115 
7116 DECLSPEC SDL_AudioSpec * SDLCALL
SDL_LoadWAV_RW(SDL12_RWops * rwops12,int freerwops12,SDL_AudioSpec * spec,Uint8 ** buf,Uint32 * len)7117 SDL_LoadWAV_RW(SDL12_RWops *rwops12, int freerwops12,
7118                SDL_AudioSpec *spec, Uint8 **buf, Uint32 *len)
7119 {
7120     SDL_RWops *rwops20 = RWops12to20(rwops12);
7121     SDL_AudioSpec *retval = SDL20_LoadWAV_RW(rwops20, freerwops12, spec, buf, len);
7122     if (retval && retval->format & 0x20) {
7123         SDL20_SetError("Unsupported 32-bit PCM data format");
7124         SDL20_FreeWAV(*buf);
7125         *buf = NULL;
7126         retval = NULL;
7127     }
7128     if (!freerwops12) {  /* free our wrapper if SDL2 didn't close it. */
7129         SDL20_FreeRW(rwops20);
7130     }
7131     return retval;
7132 }
7133 
7134 
7135 /* CD-ROM API!
7136    We don't support physical CD drives in sdl12-compat. In modern times, it's
7137    hard to find discs at all, let alone discs with audio tracks. Drives are
7138    also getting scarce, and ones that are plugged into the sound output
7139    hardware moreso. With this in mind, sdl12-compat can be instructed to
7140    point to a filesystem directory full .mp3 files, and will pretend this is
7141    an audio CD-ROM, and will decode these files and mix them into an audio
7142    stream as if they were playing from a disc. */
7143 
7144 #if defined(_MSC_VER) && defined(_M_IX86)
7145 #include "x86_msvc.h"
7146 #endif
7147 
7148 #define CDAUDIO_FPS 75  /* CD audio frames per second. */
7149 
7150 /* public domain, single-header MP3 decoder for fake CD-ROM audio support! */
7151 #define DR_MP3_IMPLEMENTATION
7152 #if defined(__GNUC__) && (__GNUC__ >= 4) && \
7153   !(defined(_WIN32) || defined(__EMX__))
7154 #define DRMP3_API __attribute__((visibility("hidden")))
7155 #elif defined(__APPLE__)
7156 #define DRMP3_API __private_extern__
7157 #else
7158 #define DRMP3_API /* just in case */
7159 #endif
7160 #define DR_MP3_NO_STDIO 1
7161 #define DR_MP3_NO_S16 1
7162 #define DR_MP3_FLOAT_OUTPUT 1
7163 #define DR_MP3_NO_FULL_READ 1
7164 #define DRMP3_ASSERT(x) SDL_assert((x))
7165 #define DRMP3_MALLOC(sz) SDL20_malloc((sz))
7166 #define DRMP3_REALLOC(p, sz) SDL20_realloc((p), (sz))
7167 #define DRMP3_FREE(p) SDL20_free((p))
7168 #define DRMP3_COPY_MEMORY(dst, src, sz) SDL20_memcpy((dst), (src), (sz))
7169 #define DRMP3_MOVE_MEMORY(dst, src, sz) SDL20_memmove((dst), (src), (sz))
7170 #define DRMP3_ZERO_MEMORY(p, sz) SDL20_memset((p), 0, (sz))
7171 
7172 #include "dr_mp3.h"
7173 
SDL20_RWseek(SDL_RWops * ctx,Sint64 ofs,int whence)7174 static SDL_INLINE Sint64 SDLCALL SDL20_RWseek(SDL_RWops *ctx, Sint64 ofs, int whence) {
7175     return ctx->seek(ctx, ofs, whence);
7176 }
SDL20_RWread(SDL_RWops * ctx,void * ptr,size_t size,size_t n)7177 static SDL_INLINE size_t SDLCALL SDL20_RWread(SDL_RWops *ctx, void *ptr, size_t size, size_t n) {
7178     return ctx->read(ctx, ptr, size, n);
7179 }
SDL20_RWclose(SDL_RWops * ctx)7180 static SDL_INLINE int SDLCALL SDL20_RWclose(SDL_RWops *ctx) {
7181     return ctx->close(ctx);
7182 }
7183 
7184 static size_t
mp3_sdlrwops_read(void * data,void * buf,size_t bytesToRead)7185 mp3_sdlrwops_read(void *data, void *buf, size_t bytesToRead)
7186 {
7187     return SDL20_RWread((SDL_RWops *) data, buf, 1, bytesToRead);
7188 }
7189 
7190 static drmp3_bool32
mp3_sdlrwops_seek(void * data,int offset,drmp3_seek_origin origin)7191 mp3_sdlrwops_seek(void *data, int offset, drmp3_seek_origin origin)
7192 {
7193     const int whence = (origin == drmp3_seek_origin_start) ? RW_SEEK_SET : RW_SEEK_CUR;
7194     SDL_assert((origin == drmp3_seek_origin_start) || (origin == drmp3_seek_origin_current));
7195     return (SDL20_RWseek((SDL_RWops *) data, offset, whence) == -1) ? DRMP3_FALSE : DRMP3_TRUE;
7196 }
7197 
7198 
7199 static int OpenSDL2AudioDevice(SDL_AudioSpec *);
7200 static void CloseSDL2AudioDevice(void);
7201 static SDL_bool ResetAudioStream(SDL_AudioStream **_stream, SDL_AudioSpec *spec, const SDL_AudioSpec *to, const SDL_AudioFormat fromfmt, const Uint8 fromchannels, const int fromfreq);
7202 
7203 typedef struct
7204 {
7205     SDL_AudioSpec device_format;
7206 
7207     SDL_bool app_callback_opened;
7208     SDL_AudioSpec app_callback_format;
7209     SDL_AudioStream *app_callback_stream;
7210 
7211     SDL_bool cdrom_opened;
7212     SDL_AudioSpec cdrom_format;
7213     SDL_AudioStream *cdrom_stream;
7214 
7215     SDL12_CDstatus cdrom_status;
7216     int cdrom_pcm_frames_written;
7217     int cdrom_cur_track;
7218     int cdrom_cur_frame;
7219     int cdrom_stop_ntracks;
7220     int cdrom_stop_nframes;
7221     drmp3 cdrom_mp3;
7222 
7223     Uint8 *mix_buffer;
7224     size_t mixbuflen;
7225 } AudioCallbackWrapperData;
7226 
7227 static AudioCallbackWrapperData *audio_cbdata = NULL;
7228 static SDL_atomic_t audio_callback_paused;
7229 
7230 
7231 static void
FreeMp3(drmp3 * mp3)7232 FreeMp3(drmp3 *mp3)
7233 {
7234     SDL_RWops *rw = (SDL_RWops *) mp3->pUserData;
7235     if (rw) {
7236         drmp3_uninit(mp3);
7237         mp3->pUserData = NULL;
7238         SDL20_RWclose(rw);
7239     }
7240 }
7241 
7242 
7243 static SDL_bool
CDSubsystemIsInitialized(void)7244 CDSubsystemIsInitialized(void)
7245 {
7246     if (!CDRomInit) {
7247         SDL20_SetError("CD-ROM subsystem not initialized");
7248         return SDL_FALSE;
7249     }
7250     return SDL_TRUE;
7251 }
7252 
7253 /* This never reports failure; if there's a problem, we report zero drives found. */
7254 static void
InitializeCDSubsystem(void)7255 InitializeCDSubsystem(void)
7256 {
7257     const char *cdpath;
7258 
7259     FIXME("Is subsystem init reference counted in SDL 1.2?");  /* it is in SDL2, but I don't know for 1.2. */
7260     if (CDRomInit) {
7261         return;
7262     }
7263 
7264     cdpath = SDL20_getenv("SDL12COMPAT_FAKE_CDROM_PATH");
7265     if (cdpath) {
7266         CDRomPath = SDL_strdup(cdpath);
7267     }
7268 
7269     CDRomInit = SDL_TRUE;
7270 }
7271 
7272 static void
QuitCDSubsystem(void)7273 QuitCDSubsystem(void)
7274 {
7275     if (!CDRomInit) {
7276         return;
7277     }
7278     SDL_free(CDRomPath);
7279     CDRomPath = NULL;
7280     CDRomInit = SDL_FALSE;
7281 }
7282 
7283 DECLSPEC int SDLCALL
SDL_CDNumDrives(void)7284 SDL_CDNumDrives(void)
7285 {
7286     if (!CDSubsystemIsInitialized()) {
7287         return -1;
7288     }
7289 
7290     if (!CDRomPath) {
7291         static SDL_bool warned_once = SDL_FALSE;
7292         if (!warned_once) {
7293             warned_once = SDL_TRUE;
7294             SDL20_Log("This app is looking for CD-ROM drives, but no path was specified");
7295             SDL20_Log("Set the SDL12COMPAT_FAKE_CDROM_PATH environment variable to a directory");
7296             SDL20_Log("of MP3 files named trackXX.mp3 where XX is a track number in two digits");
7297             SDL20_Log("from 01 to 99");
7298         }
7299     }
7300 
7301     return CDRomPath ? 1 : 0;
7302 }
7303 
7304 static SDL_bool
ValidCDDriveIndex(const int drive)7305 ValidCDDriveIndex(const int drive)
7306 {
7307     if (!CDSubsystemIsInitialized()) {
7308         return SDL_FALSE;
7309     }
7310 
7311     if (!CDRomPath || (drive != 0)) {
7312         SDL20_SetError("Invalid CD-ROM drive index");
7313         return SDL_FALSE;
7314     }
7315 
7316     return SDL_TRUE;
7317 }
7318 
7319 DECLSPEC const char * SDLCALL
SDL_CDName(int drive)7320 SDL_CDName(int drive)
7321 {
7322     return ValidCDDriveIndex(drive) ? CDRomPath : NULL;
7323 }
7324 
7325 DECLSPEC SDL12_CD * SDLCALL
SDL_CDOpen(int drive)7326 SDL_CDOpen(int drive)
7327 {
7328     SDL12_CD *retval;
7329     size_t alloclen;
7330     char *fullpath;
7331     drmp3 *mp3 = NULL;
7332     Uint32 total_track_offset = 0;
7333 
7334     if (!ValidCDDriveIndex(drive)) {
7335         return NULL;
7336     }
7337 
7338     retval = (SDL12_CD *) SDL20_calloc(1, sizeof(SDL12_CD));
7339     if (!retval) {
7340         SDL20_OutOfMemory();
7341         return NULL;
7342     }
7343 
7344     alloclen = SDL20_strlen(CDRomPath) + 32;
7345     fullpath = (char *) SDL20_malloc(alloclen);
7346     if (fullpath == NULL) {
7347         SDL20_free(retval);
7348         SDL20_OutOfMemory();
7349         return NULL;
7350     }
7351 
7352     mp3 = (drmp3 *) SDL20_malloc(sizeof (drmp3));
7353     if (!mp3) {
7354         SDL20_free(fullpath);
7355         SDL20_free(retval);
7356         SDL20_OutOfMemory();
7357         return NULL;
7358     }
7359 
7360     /* We should probably do a proper enumeration of this directory,
7361        but that needs platform-specific code that SDL2 doesn't offer.
7362        readdir() is surprisingly hard to do without a bunch of different
7363        platform backends! We just open files until we fail to do so,
7364        and then stop. */
7365     FIXME("Can we do something more robust than this for directory enumeration?");
7366     for (;;) {
7367         SDL_RWops *rw;
7368         drmp3_uint64 pcmframes;
7369         drmp3_uint32 samplerate;
7370         SDL12_CDtrack *track;
7371         int c;   char c0, c1;
7372 
7373         /* we only report audio tracks, starting at 1... */
7374         FIXME("Let there be fake data tracks");
7375         c = retval->numtracks + 1;
7376         c0 = c / 10 + '0';
7377         c1 = c % 10 + '0';
7378         SDL20_snprintf(fullpath, alloclen, "%s%strack%c%c.mp3", CDRomPath, DIRSEP, c0, c1);
7379         rw = SDL20_RWFromFile(fullpath, "rb");
7380         if (!rw && c > 1) {
7381             break;  /* ok, we're done looking for more. */
7382         }
7383 
7384         track = &retval->track[retval->numtracks];
7385         if (!rw) {
7386             track->type = 4; /* data track. E.g.: quake's audio starts at track 2. */
7387         } else {
7388             if (!drmp3_init(mp3, mp3_sdlrwops_read, mp3_sdlrwops_seek, rw, NULL)) {
7389                 SDL20_RWclose(rw);
7390                 break;  /* ok, we're done looking for more. */
7391             }
7392             pcmframes = drmp3_get_pcm_frame_count(mp3);
7393             samplerate = mp3->sampleRate;
7394             FreeMp3(mp3);
7395 
7396             track->id = retval->numtracks;
7397             track->type = 0;  /* audio track. Data tracks are 4. */
7398             track->length = (Uint32) ((((double) pcmframes) / ((double) samplerate)) * CDAUDIO_FPS);
7399             track->offset = total_track_offset;
7400             total_track_offset += track->length;
7401         }
7402 
7403         retval->numtracks++;
7404 
7405         if (retval->numtracks == 99) {
7406             break;  /* max tracks you can have on an audio CD. */
7407         }
7408     }
7409     if (retval->numtracks == 1 && retval->track[0].type != 0) {
7410         retval->numtracks = 0; /* data-only */
7411     }
7412     SDL20_free(mp3);
7413     SDL20_free(fullpath);
7414 
7415     retval->id = 1;  /* just to be non-zero, I guess. */
7416     retval->status = (retval->numtracks > 0) ? SDL12_CD_STOPPED : SDL12_CD_TRAYEMPTY;
7417 
7418     if (retval->numtracks > 0) {
7419         SDL_AudioSpec want;
7420         SDL_zero(want);
7421         want.freq = 44100;
7422         want.format = AUDIO_F32SYS;
7423         want.channels = 2;
7424         want.samples = 4096;
7425 
7426         if (!OpenSDL2AudioDevice(&want)) {
7427             retval->numtracks = 0;
7428             retval->status = SDL12_CD_TRAYEMPTY;
7429         } else {
7430             /* Device is locked now, even if was opened and playing before. Set up some things. */
7431             SDL20_memcpy(&audio_cbdata->cdrom_format, &want, sizeof (SDL_AudioSpec));
7432             audio_cbdata->cdrom_opened = SDL_TRUE;
7433             audio_cbdata->cdrom_status = SDL12_CD_STOPPED;
7434             audio_cbdata->cdrom_pcm_frames_written = 0;
7435             audio_cbdata->cdrom_cur_track = 0;
7436             audio_cbdata->cdrom_cur_frame = 0;
7437             SDL20_UnlockAudio();
7438         }
7439     }
7440 
7441     CDRomDevice = retval;  /* NULL API args use the last opened device. */
7442 
7443     return retval;
7444 }
7445 
7446 static SDL12_CD *
ValidCDDevice(SDL12_CD * cdrom)7447 ValidCDDevice(SDL12_CD *cdrom)
7448 {
7449     if (!CDSubsystemIsInitialized()) {
7450         return NULL;
7451     } else if (!cdrom) {
7452         if (!CDRomDevice) {
7453             SDL20_SetError("CD-ROM not opened");
7454         } else {
7455             cdrom = CDRomDevice;
7456         }
7457     }
7458     return cdrom;
7459 }
7460 
7461 
7462 DECLSPEC SDL12_CDstatus SDLCALL
SDL_CDStatus(SDL12_CD * cdrom)7463 SDL_CDStatus(SDL12_CD *cdrom)
7464 {
7465     SDL12_CDstatus retval;
7466 
7467     if ((cdrom = ValidCDDevice(cdrom)) == NULL) {
7468         return SDL12_CD_ERROR;
7469     }
7470 
7471     SDL20_LockAudio();  /* we update this during the audio callback. */
7472     if (audio_cbdata) {
7473         cdrom->status = audio_cbdata->cdrom_status;
7474         cdrom->cur_track = audio_cbdata->cdrom_cur_track;
7475         cdrom->cur_frame = audio_cbdata->cdrom_cur_frame;
7476     }
7477     retval = cdrom->status;
7478     SDL20_UnlockAudio();
7479 
7480     return retval;
7481 }
7482 
7483 static SDL_bool
LoadCDTrack(const int tracknum,drmp3 * mp3)7484 LoadCDTrack(const int tracknum, drmp3 *mp3)
7485 {
7486     const SDL_AudioSpec *have = &audio_cbdata->device_format;
7487     SDL_RWops *rw = NULL;
7488     const size_t alloclen = SDL20_strlen(CDRomPath) + 32;
7489     char *fullpath = (char *) SDL_malloc(alloclen);
7490     const int c = tracknum + 1;
7491     char c0, c1;
7492 
7493     if (!fullpath) {
7494         return SDL_FALSE;
7495     }
7496 
7497     c0 = c / 10 + '0';
7498     c1 = c % 10 + '0';
7499     SDL20_snprintf(fullpath, alloclen, "%s%strack%c%c.mp3", CDRomPath, DIRSEP, c0, c1);
7500     rw = SDL20_RWFromFile(fullpath, "rb");
7501     SDL20_free(fullpath);
7502 
7503     if (!rw) {
7504         return SDL_FALSE;
7505     }
7506 
7507     if (!drmp3_init(mp3, mp3_sdlrwops_read, mp3_sdlrwops_seek, rw, NULL)) {
7508         SDL20_RWclose(rw);
7509         return SDL_FALSE;
7510     }
7511 
7512     if (!ResetAudioStream(&audio_cbdata->cdrom_stream, &audio_cbdata->cdrom_format, have, AUDIO_F32SYS, mp3->channels, mp3->sampleRate)) {
7513         FreeMp3(mp3);
7514         return SDL_FALSE;
7515     }
7516 
7517     return SDL_TRUE;
7518 }
7519 
7520 static int
StartCDAudioPlaying(SDL12_CD * cdrom,const int start_track,const int start_frame,const int ntracks,const int nframes)7521 StartCDAudioPlaying(SDL12_CD *cdrom, const int start_track, const int start_frame, const int ntracks, const int nframes)
7522 {
7523     drmp3 *mp3 = (drmp3 *) SDL20_malloc(sizeof (drmp3));
7524     const SDL_bool loaded = mp3 ? LoadCDTrack(start_track, mp3) : SDL_FALSE;
7525     const SDL_bool seeking = (loaded && (start_frame > 0))? SDL_TRUE : SDL_FALSE;
7526     const drmp3_uint64 pcm_frame = seeking ? ((drmp3_uint64) ((start_frame / 75.0) * mp3->sampleRate)) : 0;
7527 
7528     if (!mp3) {
7529         return SDL20_OutOfMemory();
7530     }
7531 
7532     if (seeking) {   /* do seeking before handing off to the audio thread. */
7533         drmp3_seek_to_pcm_frame(mp3, pcm_frame);
7534     }
7535 
7536     SDL20_LockAudio();
7537     if (audio_cbdata) {
7538         cdrom->status = audio_cbdata->cdrom_status = loaded ? SDL12_CD_PLAYING : SDL12_CD_TRAYEMPTY;
7539         audio_cbdata->cdrom_pcm_frames_written = (int) pcm_frame;
7540         audio_cbdata->cdrom_cur_track = start_track;
7541         audio_cbdata->cdrom_cur_frame = start_frame;
7542         audio_cbdata->cdrom_stop_ntracks = ntracks;
7543         audio_cbdata->cdrom_stop_nframes = nframes;
7544         FreeMp3(&audio_cbdata->cdrom_mp3);
7545         if (loaded) {
7546             SDL20_memcpy(&audio_cbdata->cdrom_mp3, mp3, sizeof (drmp3));
7547         }
7548     }
7549     SDL20_UnlockAudio();
7550 
7551     SDL20_free(mp3);
7552 
7553     return loaded ? 0 : SDL20_SetError("Failed to start CD track");
7554 }
7555 
7556 
7557 DECLSPEC int SDLCALL
SDL_CDPlayTracks(SDL12_CD * cdrom,int start_track,int start_frame,int ntracks,int nframes)7558 SDL_CDPlayTracks(SDL12_CD *cdrom, int start_track, int start_frame, int ntracks, int nframes)
7559 {
7560     if ((cdrom = ValidCDDevice(cdrom)) == NULL) {
7561         return -1;
7562     } else if (cdrom->status == SDL12_CD_TRAYEMPTY) {
7563         return SDL20_SetError("Tray empty");
7564     } else if ((start_track < 0) || (start_track >= cdrom->numtracks)) {
7565         return SDL20_SetError("Invalid start track");
7566     } else if ((start_frame < 0) || (((Uint32) start_frame) >= cdrom->track[start_track].length)) {
7567         return SDL20_SetError("Invalid start frame");
7568     } else if ((ntracks < 0) || ((start_track + ntracks) >= cdrom->numtracks)) {
7569         return SDL20_SetError("Invalid number of tracks");
7570     } else if ((nframes < 0) || (((Uint32) nframes) >= cdrom->track[start_track + ntracks].length)) {
7571         return SDL20_SetError("Invalid number of frames");
7572     }
7573 
7574     if (!ntracks && !nframes) {
7575         ntracks = cdrom->numtracks - start_track;
7576         nframes = cdrom->track[cdrom->numtracks - 1].length;
7577     }
7578 
7579     return StartCDAudioPlaying(cdrom, start_track, start_frame, ntracks, nframes);
7580 }
7581 
7582 DECLSPEC int SDLCALL
SDL_CDPlay(SDL12_CD * cdrom,int start,int length)7583 SDL_CDPlay(SDL12_CD *cdrom, int start, int length)
7584 {
7585     const Uint32 ui32start = (Uint32) start;
7586     Uint32 remain = (Uint32) length;
7587     int start_track = -1;
7588     int start_frame = -1;
7589     int ntracks = -1;
7590     int nframes = -1;
7591     int i;
7592 
7593     if ((cdrom = ValidCDDevice(cdrom)) == NULL) {
7594         return -1;
7595     } else if (cdrom->status == SDL12_CD_TRAYEMPTY) {
7596         return SDL20_SetError("Tray empty");
7597     } else if (start < 0) {
7598         return SDL20_SetError("Invalid start");
7599     } else if (length < 0) {
7600         return SDL20_SetError("Invalid length");
7601     }
7602 
7603     for (i = 0; i < cdrom->numtracks; i++) {
7604         if ((ui32start >= cdrom->track[i].offset) && (ui32start < (cdrom->track[i].offset + cdrom->track[i].length))) {
7605             start_track = i;
7606             break;
7607         }
7608     }
7609 
7610     if (start_track == -1) {
7611         return SDL20_SetError("Invalid start");
7612     }
7613 
7614     start_frame = start - cdrom->track[start_track].offset;
7615 
7616     if (remain < (cdrom->track[start_frame].length - start_frame)) {
7617         ntracks = 0;
7618         nframes = remain;
7619         remain = 0;
7620     } else {
7621         remain -= (cdrom->track[start_frame].length - start_frame);
7622         for (i = start_track + 1; i < cdrom->numtracks; i++) {
7623             if (remain < cdrom->track[i].length) {
7624                 ntracks = i - start_track;
7625                 nframes = remain;
7626                 remain = 0;
7627                 break;
7628             }
7629             remain -= cdrom->track[i].length;
7630         }
7631     }
7632 
7633     if (remain) {
7634         ntracks = (cdrom->numtracks - start_track) - 1;
7635         nframes = cdrom->track[cdrom->numtracks - 1].length;
7636     }
7637 
7638     return StartCDAudioPlaying(cdrom, start_track, start_frame, ntracks, nframes);
7639 }
7640 
7641 DECLSPEC int SDLCALL
SDL_CDPause(SDL12_CD * cdrom)7642 SDL_CDPause(SDL12_CD *cdrom)
7643 {
7644     if ((cdrom = ValidCDDevice(cdrom)) == NULL) {
7645         return -1;
7646     } else if (cdrom->status == SDL12_CD_TRAYEMPTY) {
7647         return SDL20_SetError("Tray empty");
7648     }
7649 
7650     SDL20_LockAudio();
7651     if (audio_cbdata) {
7652         if (audio_cbdata->cdrom_status == SDL12_CD_PLAYING) {
7653             audio_cbdata->cdrom_status = SDL12_CD_PAUSED;
7654         }
7655         cdrom->status = audio_cbdata->cdrom_status;
7656     }
7657     SDL20_UnlockAudio();
7658     return 0;
7659 }
7660 
7661 DECLSPEC int SDLCALL
SDL_CDResume(SDL12_CD * cdrom)7662 SDL_CDResume(SDL12_CD *cdrom)
7663 {
7664     if ((cdrom = ValidCDDevice(cdrom)) == NULL) {
7665         return -1;
7666     } else if (cdrom->status == SDL12_CD_TRAYEMPTY) {
7667         return SDL20_SetError("Tray empty");
7668     }
7669 
7670     SDL20_LockAudio();
7671     if (audio_cbdata) {
7672         if (audio_cbdata->cdrom_status == SDL12_CD_PAUSED) {
7673             audio_cbdata->cdrom_status = SDL12_CD_PLAYING;
7674         }
7675         cdrom->status = audio_cbdata->cdrom_status;
7676     }
7677     SDL20_UnlockAudio();
7678     return 0;
7679 }
7680 
7681 
7682 DECLSPEC int SDLCALL
SDL_CDStop(SDL12_CD * cdrom)7683 SDL_CDStop(SDL12_CD *cdrom)
7684 {
7685     SDL_RWops *oldrw = NULL;
7686 
7687     if ((cdrom = ValidCDDevice(cdrom)) == NULL) {
7688         return -1;
7689     }
7690 
7691     SDL20_LockAudio();
7692     if (audio_cbdata) {
7693         if ((audio_cbdata->cdrom_status == SDL12_CD_PLAYING) || (audio_cbdata->cdrom_status == SDL12_CD_PAUSED)) {
7694             audio_cbdata->cdrom_status = SDL12_CD_STOPPED;
7695             FreeMp3(&audio_cbdata->cdrom_mp3);
7696         }
7697         cdrom->status = audio_cbdata->cdrom_status;
7698     }
7699     SDL20_UnlockAudio();
7700 
7701     if (oldrw) {
7702         SDL20_RWclose(oldrw);
7703     }
7704     return 0;
7705 }
7706 
7707 DECLSPEC int SDLCALL
SDL_CDEject(SDL12_CD * cdrom)7708 SDL_CDEject(SDL12_CD *cdrom)
7709 {
7710     if ((cdrom = ValidCDDevice(cdrom)) == NULL) {
7711         return -1;
7712     }
7713 
7714     SDL20_LockAudio();
7715     if (audio_cbdata) {
7716         audio_cbdata->cdrom_status = SDL12_CD_TRAYEMPTY;
7717         FreeMp3(&audio_cbdata->cdrom_mp3);
7718     }
7719     cdrom->status = SDL12_CD_TRAYEMPTY;
7720     SDL20_UnlockAudio();
7721     return 0;
7722 }
7723 
7724 DECLSPEC void SDLCALL
SDL_CDClose(SDL12_CD * cdrom)7725 SDL_CDClose(SDL12_CD *cdrom)
7726 {
7727     if ((cdrom = ValidCDDevice(cdrom)) == NULL) {
7728         return;
7729     }
7730 
7731     SDL20_LockAudio();
7732     if (audio_cbdata) {
7733         audio_cbdata->cdrom_status = SDL12_CD_STOPPED;
7734         audio_cbdata->cdrom_opened = SDL_FALSE;
7735     }
7736     SDL20_UnlockAudio();
7737 
7738     if (audio_cbdata) {
7739         FreeMp3(&audio_cbdata->cdrom_mp3);
7740         SDL20_FreeAudioStream(audio_cbdata->cdrom_stream);
7741         audio_cbdata->cdrom_stream = NULL;
7742     }
7743 
7744     CloseSDL2AudioDevice();
7745 
7746     if (cdrom == CDRomDevice) {
7747         CDRomDevice = NULL;
7748     }
7749     SDL20_free(cdrom);
7750 }
7751 
7752 
7753 static void
FakeCdRomAudioCallback(AudioCallbackWrapperData * data,Uint8 * stream,int len,const SDL_bool must_mix)7754 FakeCdRomAudioCallback(AudioCallbackWrapperData *data, Uint8 *stream, int len, const SDL_bool must_mix)
7755 {
7756     Uint32 total_available, available = 0;
7757     Uint32 channels, want_frames;
7758 
7759     if (data->cdrom_status != SDL12_CD_PLAYING) {
7760         if (!must_mix) {
7761             SDL20_memset(stream, data->device_format.silence, len);
7762         }
7763         return;
7764     }
7765 
7766     SDL_assert((data->cdrom_status == SDL12_CD_PLAYING) && (data->cdrom_mp3.pUserData != NULL));
7767 
7768     channels = data->cdrom_format.channels;
7769     want_frames = data->cdrom_format.samples / channels;
7770 
7771     while ((!data->cdrom_mp3.atEnd) && (SDL20_AudioStreamAvailable(data->cdrom_stream) < len)) {
7772         const Uint32 frames_read = (Uint32) drmp3_read_pcm_frames_f32(&data->cdrom_mp3, want_frames, (float *) data->mix_buffer);
7773         const Uint32 bytes_read = frames_read * channels * sizeof (float);
7774         SDL_assert(bytes_read <= data->cdrom_format.size);
7775         if ((!bytes_read) || (SDL20_AudioStreamPut(data->cdrom_stream, data->mix_buffer, bytes_read) == -1)) {  /* probably out of memory if failed */
7776             data->cdrom_mp3.atEnd = DRMP3_TRUE;  /* force this to fail from now on */
7777             SDL20_AudioStreamFlush(data->cdrom_stream);  /* make sure all we've put is available to get. */
7778             break;
7779         }
7780     }
7781 
7782     total_available = SDL20_AudioStreamAvailable(data->cdrom_stream);
7783     available = total_available;
7784     if (((Uint32) len) < available) {
7785         available = (Uint32) len;
7786     }
7787 
7788     if (available > 0) {
7789         if (!must_mix) {
7790             SDL20_AudioStreamGet(data->cdrom_stream, stream, available);
7791         } else {
7792             SDL20_AudioStreamGet(data->cdrom_stream, data->mix_buffer, available);
7793             SDL20_MixAudio(stream, data->mix_buffer, available, SDL_MIX_MAXVOLUME);
7794         }
7795 
7796         data->cdrom_pcm_frames_written += (int) ((available / ((double) SDL_AUDIO_BITSIZE(data->device_format.format) / 8.0)) / data->device_format.channels);
7797         data->cdrom_cur_frame = (int) ((((double)data->cdrom_pcm_frames_written) / ((double)data->device_format.freq)) * CDAUDIO_FPS);
7798         if (data->cdrom_stop_ntracks == 0) {
7799             if (data->cdrom_cur_frame >= data->cdrom_stop_nframes) {
7800                 data->cdrom_mp3.atEnd = DRMP3_TRUE;  /* played all that was requested! */
7801             }
7802         }
7803     }
7804 
7805     if ((total_available == 0) && (data->cdrom_mp3.atEnd)) {  /* mp3 is done for whatever reason */
7806         SDL_bool silence = ((!must_mix) && (available < ((Uint32) len))) ? SDL_TRUE : SDL_FALSE;  /* silence any section we couldn't provide */
7807 
7808         FreeMp3(&data->cdrom_mp3);
7809 
7810         if (data->cdrom_stop_ntracks > 0) {
7811             data->cdrom_stop_ntracks--;
7812             data->cdrom_pcm_frames_written = 0;
7813             data->cdrom_cur_frame = 0;
7814 
7815             if (data->cdrom_status == SDL12_CD_PLAYING) {  /* go on to next track? */
7816                 const SDL_bool loaded = LoadCDTrack(++data->cdrom_cur_track, &data->cdrom_mp3);
7817                 if (!loaded) {
7818                     data->cdrom_status = SDL12_CD_TRAYEMPTY;  FIXME("Maybe just mark it stopped?");
7819                 } else {  /* let new track fill out rest of callback. */
7820                     if (available < ((Uint32) len)) {
7821                         FakeCdRomAudioCallback(data, stream + available, len - available, must_mix);
7822                         silence = SDL_FALSE;
7823                     }
7824                 }
7825             }
7826         } else {
7827             data->cdrom_status = SDL12_CD_STOPPED;  /* played all that was requested! */
7828         }
7829 
7830         if (silence) {
7831             SDL20_memset(stream + available, data->device_format.silence, len - available);
7832         }
7833     }
7834 }
7835 
7836 
7837 static void SDLCALL
AudioCallbackWrapper(void * userdata,Uint8 * stream,int len)7838 AudioCallbackWrapper(void *userdata, Uint8 *stream, int len)
7839 {
7840     AudioCallbackWrapperData *data = (AudioCallbackWrapperData *) userdata;
7841     SDL_bool must_mix = SDL_FALSE;
7842 
7843     if (data->app_callback_opened && !SDL20_AtomicGet(&audio_callback_paused)) {
7844         while (SDL20_AudioStreamAvailable(data->app_callback_stream) < len) {
7845             SDL20_memset(data->mix_buffer, data->app_callback_format.silence, data->app_callback_format.size);  /* SDL2 doesn't clear the stream before calling in here, but 1.2 expects it. */
7846             data->app_callback_format.callback(data->app_callback_format.userdata, data->mix_buffer, data->app_callback_format.size);
7847             if (SDL20_AudioStreamPut(data->app_callback_stream, data->mix_buffer, data->app_callback_format.size) == -1) {  /* probably out of memory if failed */
7848                 break;  /* this will make the AudioStreamGet call fail. */
7849             }
7850         }
7851         if (SDL20_AudioStreamGet(data->app_callback_stream, stream, len) != len) {
7852             SDL20_memset(stream, data->device_format.silence, len);
7853         } else {
7854             must_mix = SDL_TRUE;
7855         }
7856     }
7857 
7858     FakeCdRomAudioCallback(data, stream, len, must_mix);
7859 }
7860 
7861 
7862 static SDL_bool
ResetAudioStream(SDL_AudioStream ** _stream,SDL_AudioSpec * spec,const SDL_AudioSpec * to,const SDL_AudioFormat fromfmt,const Uint8 fromchannels,const int fromfreq)7863 ResetAudioStream(SDL_AudioStream **_stream, SDL_AudioSpec *spec, const SDL_AudioSpec *to, const SDL_AudioFormat fromfmt, const Uint8 fromchannels, const int fromfreq)
7864 {
7865     if ((!*_stream) || (spec->channels != fromchannels) || (spec->format != fromfmt) || (spec->freq != fromfreq)) {
7866         SDL20_FreeAudioStream(*_stream);
7867         *_stream = SDL20_NewAudioStream(fromfmt, fromchannels, fromfreq, to->format, to->channels, to->freq);
7868         if (!*_stream) {
7869             return SDL_FALSE;
7870         }
7871 
7872         spec->channels = fromchannels;
7873         spec->format = fromfmt;
7874         spec->freq = fromfreq;
7875         spec->size = spec->samples * spec->channels * (SDL_AUDIO_BITSIZE(spec->format) / 8);
7876 
7877         if (audio_cbdata->mixbuflen < spec->size) {
7878             void *ptr = SDL20_realloc(audio_cbdata->mix_buffer, spec->size);
7879             if (!ptr) {
7880                 SDL20_FreeAudioStream(*_stream);
7881                 *_stream = NULL;
7882                 SDL20_OutOfMemory();
7883                 return SDL_FALSE;
7884             }
7885             audio_cbdata->mixbuflen = spec->size;
7886             audio_cbdata->mix_buffer = (Uint8 *) ptr;
7887         }
7888     }
7889     return SDL_TRUE;
7890 }
7891 
7892 static SDL_bool
ResetAudioStreamForDeviceChange(SDL_AudioStream ** _stream,SDL_AudioSpec * spec)7893 ResetAudioStreamForDeviceChange(SDL_AudioStream **_stream, SDL_AudioSpec *spec)
7894 {
7895     if (*_stream == NULL) {
7896         return SDL_TRUE;  /* no stream, no need to reset it. */
7897     }
7898     SDL20_FreeAudioStream(*_stream);  /* force it to rebuild because destination format changed. */
7899     *_stream = NULL;
7900     return ResetAudioStream(_stream, spec, &audio_cbdata->device_format, spec->format, spec->channels, spec->freq);
7901 }
7902 
7903 static int
OpenSDL2AudioDevice(SDL_AudioSpec * want)7904 OpenSDL2AudioDevice(SDL_AudioSpec *want)
7905 {
7906     void (SDLCALL *orig_callback)(void *userdata, Uint8 *stream, int len) = want->callback;
7907     void *orig_userdata = want->userdata;
7908     int retval;
7909 
7910     /* Two things use the audio device: the app, through 1.2's SDL_OpenAudio,
7911        and the fake CD-ROM device. Either can open the device, and both write
7912        to SDL_AudioStreams to buffer and convert data. We try to open the device
7913        in a format that accommodates both inputs, but we might close the device
7914        and reopen it if we need more channels, etc. */
7915     if (audio_cbdata != NULL) {  /* device is already open. */
7916         SDL_AudioSpec *have = &audio_cbdata->device_format;
7917         if ( (want->freq > have->freq) ||
7918              (want->channels > have->channels) ||
7919              (want->samples > have->samples) ||
7920              ( (SDL_AUDIO_ISFLOAT(want->format)) && (!SDL_AUDIO_ISFLOAT(have->format)) ) ||
7921              ( SDL_AUDIO_BITSIZE(want->format) > SDL_AUDIO_BITSIZE(have->format) ) ) {
7922             SDL20_CloseAudio();
7923         } else {
7924             SDL20_LockAudio();  /* Device is already at acceptable parameters, just pause it for further setup by caller. */
7925             return SDL_TRUE;
7926         }
7927     } else {
7928         audio_cbdata = (AudioCallbackWrapperData *) SDL20_calloc(1, sizeof (AudioCallbackWrapperData));
7929         if (!audio_cbdata) {
7930             SDL20_OutOfMemory();
7931             return SDL_FALSE;
7932         }
7933     }
7934 
7935     FIXME("if this fails, we need to deal with app callback or cd-rom no longer working");
7936     want->callback = AudioCallbackWrapper;
7937     want->userdata = audio_cbdata;
7938     retval = (SDL20_OpenAudio(want, &audio_cbdata->device_format) == 0);
7939     want->callback = orig_callback;
7940     want->userdata = orig_userdata;
7941     want->size = want->samples * want->channels * (SDL_AUDIO_BITSIZE(want->format) / 8);
7942 
7943     /* note that 0x80 isn't perfect silence for U16 formats, but we only have one byte that is used for memset() calls, so it has to do. SDL2 has the same bug. */
7944     want->silence = SDL_AUDIO_ISSIGNED(want->format) ? 0x00 : 0x80;
7945 
7946     /* reset audiostreams if device format changed. */
7947     FIXME("deal with failure in here");
7948     ResetAudioStreamForDeviceChange(&audio_cbdata->app_callback_stream, &audio_cbdata->app_callback_format);
7949     ResetAudioStreamForDeviceChange(&audio_cbdata->cdrom_stream, &audio_cbdata->cdrom_format);
7950 
7951     SDL20_LockAudio();
7952     SDL20_PauseAudio(0);  /* always unpause, but caller will unlock after finalizing setup. */
7953 
7954     return retval;
7955 }
7956 
7957 static void
CloseSDL2AudioDevice(void)7958 CloseSDL2AudioDevice(void)
7959 {
7960     int close_sdl2_device;
7961 
7962     SDL20_LockAudio();
7963     close_sdl2_device = (audio_cbdata && !audio_cbdata->app_callback_opened && !audio_cbdata->cdrom_opened);
7964     SDL20_UnlockAudio();
7965 
7966     if (close_sdl2_device) {
7967         SDL20_CloseAudio();
7968         SDL20_FreeAudioStream(audio_cbdata->app_callback_stream);
7969         SDL20_FreeAudioStream(audio_cbdata->cdrom_stream);
7970         SDL20_free(audio_cbdata->mix_buffer);
7971         SDL20_free(audio_cbdata);
7972         audio_cbdata = NULL;
7973     }
7974 }
7975 
7976 
7977 DECLSPEC int SDLCALL
SDL_OpenAudio(SDL_AudioSpec * want,SDL_AudioSpec * obtained)7978 SDL_OpenAudio(SDL_AudioSpec *want, SDL_AudioSpec *obtained)
7979 {
7980     int already_opened;
7981 
7982     /* SDL2 uses a NULL callback to mean "we plan to use SDL_QueueAudio()" */
7983     if (want && (want->callback == NULL)) {
7984         return SDL20_SetError("Callback can't be NULL");
7985     }
7986 
7987     SDL20_LockAudio();
7988     already_opened = audio_cbdata && audio_cbdata->app_callback_opened;
7989     SDL20_UnlockAudio();
7990     if (already_opened) {
7991         return SDL20_SetError("Audio device already opened");
7992     }
7993 
7994     FIXME("Respect 1.2 environment variables for defining format here.");
7995     if (!want->format) {
7996         want->format = AUDIO_S16SYS;
7997     }
7998     if (!want->freq) {
7999         want->freq = 22050;
8000         want->samples = 0;
8001     }
8002     if (!want->channels) {
8003         want->channels = 2;
8004     }
8005     if (!want->samples) {
8006         Uint32 samp = (want->freq / 1000) * 46;  /* ~46 ms */
8007         Uint32 pow2 = 1;
8008         while (pow2 < samp) pow2 <<= 1;
8009         want->samples = pow2;
8010     }
8011 
8012     /* the app always passes callback data through an SDL_AudioStream, since it
8013        has to share with the fake CD-ROM support. This also avoids the risk of
8014        getting an incompatible device configuration from SDL2. As such,
8015        the app always gets the format it requests. */
8016     if (!OpenSDL2AudioDevice(want)) {
8017         return -1;
8018     }
8019 
8020     /* Device is locked now, unconditionally. Set up some things. */
8021 
8022     if (obtained) {  /* the app always gets the format it requests */
8023         SDL20_memcpy(obtained, want, sizeof (SDL_AudioSpec));
8024     }
8025 
8026     SDL20_memcpy(&audio_cbdata->app_callback_format, want, sizeof (SDL_AudioSpec));
8027     audio_cbdata->app_callback_opened = SDL_TRUE;
8028     SDL20_AtomicSet(&audio_callback_paused, SDL_TRUE);  /* app callback always starts paused after open. */
8029 
8030     FIXME("Cleanup from failures in here");
8031     SDL_assert(audio_cbdata->app_callback_stream == NULL);
8032 
8033     if (!ResetAudioStream(&audio_cbdata->app_callback_stream, &audio_cbdata->app_callback_format, &audio_cbdata->device_format, want->format, want->channels, want->freq)) {
8034         FIXME("Close audio device if nothing else was using it");
8035         return -1;
8036     }
8037 
8038     SDL20_UnlockAudio();  /* we're off and going. */
8039 
8040     return 0;
8041 }
8042 
8043 DECLSPEC void SDLCALL
SDL_PauseAudio(int pause_on)8044 SDL_PauseAudio(int pause_on)
8045 {
8046     SDL20_AtomicSet(&audio_callback_paused, pause_on ? SDL_TRUE : SDL_FALSE);
8047 }
8048 
8049 DECLSPEC SDL_AudioStatus SDLCALL
SDL_GetAudioStatus(void)8050 SDL_GetAudioStatus(void)
8051 {
8052     SDL_AudioStatus retval = SDL_AUDIO_STOPPED;
8053     SDL20_LockAudio();
8054     if (audio_cbdata && audio_cbdata->app_callback_opened) {
8055         retval = SDL20_AtomicGet(&audio_callback_paused) ? SDL_AUDIO_PAUSED : SDL_AUDIO_PLAYING;
8056     }
8057     SDL20_UnlockAudio();
8058     return retval;
8059 }
8060 
8061 DECLSPEC void SDLCALL
SDL_CloseAudio(void)8062 SDL_CloseAudio(void)
8063 {
8064     SDL20_LockAudio();
8065     if (audio_cbdata) {
8066         audio_cbdata->app_callback_opened = SDL_FALSE;
8067         SDL20_FreeAudioStream(audio_cbdata->app_callback_stream);
8068         audio_cbdata->app_callback_stream = NULL;
8069     }
8070     SDL20_UnlockAudio();
8071 
8072     CloseSDL2AudioDevice();
8073 }
8074 
8075 
8076 static SDL_AudioCVT *
AudioCVT12to20(const SDL12_AudioCVT * cvt12,SDL_AudioCVT * cvt20)8077 AudioCVT12to20(const SDL12_AudioCVT *cvt12, SDL_AudioCVT *cvt20)
8078 {
8079     SDL_zerop(cvt20);
8080     cvt20->needed = cvt12->needed;
8081     cvt20->src_format = cvt12->src_format;
8082     cvt20->dst_format = cvt12->dst_format;
8083     cvt20->rate_incr = cvt12->rate_incr;
8084     cvt20->buf = cvt12->buf;
8085     cvt20->len = cvt12->len;
8086     cvt20->len_cvt = cvt12->len_cvt;
8087     cvt20->len_mult = cvt12->len_mult;
8088     cvt20->len_ratio = cvt12->len_ratio;
8089     SDL20_memcpy(cvt20->filters, cvt12->filters, sizeof (cvt12->filters));
8090     cvt20->filter_index = cvt12->filter_index;
8091     return cvt20;
8092 }
8093 
8094 static SDL12_AudioCVT *
AudioCVT20to12(const SDL_AudioCVT * cvt20,SDL12_AudioCVT * cvt12)8095 AudioCVT20to12(const SDL_AudioCVT *cvt20, SDL12_AudioCVT *cvt12)
8096 {
8097     SDL_zerop(cvt12);
8098     cvt12->needed = cvt20->needed;
8099     cvt12->src_format = cvt20->src_format;
8100     cvt12->dst_format = cvt20->dst_format;
8101     cvt12->rate_incr = cvt20->rate_incr;
8102     cvt12->buf = cvt20->buf;
8103     cvt12->len = cvt20->len;
8104     cvt12->len_cvt = cvt20->len_cvt;
8105     cvt12->len_mult = cvt20->len_mult;
8106     cvt12->len_ratio = cvt20->len_ratio;
8107     SDL20_memcpy(cvt12->filters, cvt20->filters, sizeof (cvt20->filters));
8108     cvt12->filter_index = cvt20->filter_index;
8109     return cvt12;
8110 }
8111 
8112 DECLSPEC int SDLCALL
SDL_BuildAudioCVT(SDL12_AudioCVT * cvt12,Uint16 src_format,Uint8 src_channels,int src_rate,Uint16 dst_format,Uint8 dst_channels,int dst_rate)8113 SDL_BuildAudioCVT(SDL12_AudioCVT *cvt12, Uint16 src_format, Uint8 src_channels, int src_rate, Uint16 dst_format, Uint8 dst_channels, int dst_rate)
8114 {
8115     SDL_AudioCVT cvt20;
8116     const int retval = SDL20_BuildAudioCVT(&cvt20, src_format, src_channels, src_rate, dst_format, dst_channels, dst_rate);
8117     AudioCVT20to12(&cvt20, cvt12);  /* SDL 1.2 derefences cvt12 without checking for NULL */
8118     return retval;
8119 }
8120 
8121 DECLSPEC int SDLCALL
SDL_ConvertAudio(SDL12_AudioCVT * cvt12)8122 SDL_ConvertAudio(SDL12_AudioCVT *cvt12)
8123 {
8124     /* neither SDL 1.2 nor 2.0 makes sure cvt12 isn't NULL here.  :/  */
8125     SDL_AudioCVT cvt20;
8126     const int retval = SDL20_ConvertAudio(AudioCVT12to20(cvt12, &cvt20));
8127     AudioCVT20to12(&cvt20, cvt12);
8128     return retval;
8129 }
8130 
8131 
8132 /* SDL_GL_DisableContext and SDL_GL_EnableContext_Thread are not real SDL 1.2
8133    APIs, but some idTech4 games shipped with a custom SDL 1.2 build that added
8134    these functions, to let them make a GL context current on a background thread,
8135    so we supply them as well to be binary compatible for those games. */
8136 
8137 DECLSPEC void SDLCALL
SDL_GL_DisableContext(void)8138 SDL_GL_DisableContext(void)
8139 {
8140     SDL20_GL_MakeCurrent(NULL, NULL);
8141 }
8142 
8143 DECLSPEC void SDLCALL
SDL_GL_EnableContext_Thread(void)8144 SDL_GL_EnableContext_Thread(void)
8145 {
8146     const SDL_bool enable = (VideoGLContext20 && VideoWindow20)? SDL_TRUE : SDL_FALSE;
8147     SDL20_GL_MakeCurrent(enable ? VideoWindow20 : NULL, enable ? VideoGLContext20 : NULL);
8148 }
8149 
8150 
8151 /* X11_KeyToUnicode is an internal function in the SDL 1.2 x11 backend that some Linux
8152    software (older versions of the Torque Engine, for example) would call directly, so
8153    we're supplying an extremely naive implementation here. Apps using this should be
8154    fixed if possible, and this implementation is generally incorrect but hopefully
8155    enough to get apps to limp along.
8156    As this isn't X11-specific, we supply it globally, so x11 binaries can transition
8157    to Wayland, and if there's some wildly-misbuilt win32 software, they can call it
8158    too. :) */
8159 #if !(defined(_WIN32) || defined(__OS2__)) /* #if defined(__unix__) || defined(__APPLE__) ?? */
8160 DECLSPEC Uint16 SDLCALL
X11_KeyToUnicode(SDL12Key key,SDL12Mod mod)8161 X11_KeyToUnicode(SDL12Key key, SDL12Mod mod)
8162 {
8163     if (((int) key) >= 127) {
8164         return 0;
8165     }
8166     if ((key >= SDLK12_a) && (key <= SDLK12_z)) {
8167         const int shifted = ((mod & (KMOD12_LSHIFT|KMOD12_RSHIFT)) != 0) ? 1 : 0;
8168         int capital = ((mod & KMOD12_CAPS) != 0) ? 1 : 0;
8169         if (shifted) {
8170             capital = !capital;
8171         }
8172         return (Uint16) ((capital ? 'A' : 'a') + (key - SDLK12_a));
8173     }
8174 
8175     return (Uint16) key;
8176 }
8177 #endif
8178 
8179 #ifdef __cplusplus
8180 }
8181 #endif
8182 
8183 /* vi: set ts=4 sw=4 expandtab: */
8184