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], ¤t_mode)) {
1687 if (AddVidModeToList(vmode, &fake_modes[j])) {
1688 return SDL20_OutOfMemory();
1689 }
1690 }
1691 }
1692 }
1693
1694 if (AddVidModeToList(vmode, ¤t_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