src/SDL12_compat.c
author Ryan C. Gordon <icculus@icculus.org>
Wed, 13 Feb 2019 20:55:29 -0500
changeset 59 39067b54d1b0
parent 58 75a93435ce44
child 60 76cf0dc4bce4
permissions -rw-r--r--
Reimplemented SDL_SetVideoMode, with SDL_Render for 2D surfaces!
     1 /*
     2   Simple DirectMedia Layer
     3   Copyright (C) 1997-2019 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 // !!! FIXME: clean up code conventions
    25 // !!! FIXME: grep for VideoWindow20 places that might care if it's NULL
    26 
    27 #include "SDL20_include_wrapper.h"
    28 
    29 #if !SDL_VERSION_ATLEAST(2,0,0)
    30 #error You need to compile against SDL 2.0 headers.
    31 #endif
    32 
    33 /*
    34  * We report the library version as 1.2.$(SDL12_COMPAT_VERSION). This number
    35  *  should be way ahead of what SDL-1.2 Classic would report, so apps can
    36  *  decide if they're running under the compat layer, if they really care.
    37  */
    38 #define SDL12_COMPAT_VERSION 50
    39 
    40 #include <stdarg.h>
    41 
    42 // !!! IMPLEMENT_ME SDL_CDClose
    43 // !!! IMPLEMENT_ME SDL_CDEject
    44 // !!! IMPLEMENT_ME SDL_CDName
    45 // !!! IMPLEMENT_ME SDL_CDNumDrives
    46 // !!! IMPLEMENT_ME SDL_CDOpen
    47 // !!! IMPLEMENT_ME SDL_CDPause
    48 // !!! IMPLEMENT_ME SDL_CDPlay
    49 // !!! IMPLEMENT_ME SDL_CDPlayTracks
    50 // !!! IMPLEMENT_ME SDL_CDResume
    51 // !!! IMPLEMENT_ME SDL_CDStatus
    52 // !!! IMPLEMENT_ME SDL_CDStop
    53 // !!! IMPLEMENT_ME SDL_ConvertSurface
    54 // !!! IMPLEMENT_ME SDL_CreateYUVOverlay
    55 
    56 // !!! IMPLEMENT_ME SDL_DisplayFormat
    57 // !!! IMPLEMENT_ME SDL_DisplayFormatAlpha
    58 // !!! IMPLEMENT_ME SDL_DisplayYUVOverlay
    59 // !!! IMPLEMENT_ME SDL_EnableKeyRepeat
    60 // !!! IMPLEMENT_ME SDL_EnableUNICODE
    61 // !!! IMPLEMENT_ME SDL_FreeYUVOverlay
    62 
    63 // !!! IMPLEMENT_ME SDL_GL_Lock
    64 // !!! IMPLEMENT_ME SDL_GL_Unlock
    65 // !!! IMPLEMENT_ME SDL_GL_UpdateRects
    66 
    67 // !!! IMPLEMENT_ME SDL_GetKeyName
    68 // !!! IMPLEMENT_ME SDL_GetKeyState
    69 // !!! IMPLEMENT_ME SDL_GetModState
    70 // !!! IMPLEMENT_ME SDL_GetRelativeMouseState
    71 
    72 // !!! IMPLEMENT_ME SDL_GetVideoSurface
    73 // !!! IMPLEMENT_ME SDL_GetWMInfo
    74 
    75 // !!! IMPLEMENT_ME SDL_LockSurface
    76 // !!! IMPLEMENT_ME SDL_LockYUVOverlay
    77 // !!! IMPLEMENT_ME SDL_LowerBlit
    78 
    79 // !!! IMPLEMENT_ME SDL_SetAlpha
    80 // !!! IMPLEMENT_ME SDL_SetColorKey
    81 // !!! IMPLEMENT_ME SDL_SetColors
    82 
    83 // !!! IMPLEMENT_ME SDL_SetModState
    84 // !!! IMPLEMENT_ME SDL_SetPalette
    85 // !!! IMPLEMENT_ME SDL_SetVideoMode
    86 // !!! IMPLEMENT_ME SDL_SoftStretch
    87 // !!! IMPLEMENT_ME SDL_UnlockSurface
    88 // !!! IMPLEMENT_ME SDL_UnlockYUVOverlay
    89 // !!! IMPLEMENT_ME SDL_UpdateRects
    90 // !!! IMPLEMENT_ME SDL_UpperBlit
    91 
    92 // !!! FIXME: should SDL_VideoInit really be a passthrough?
    93 // !!! FIXME: should SDL_VideoQuit really be a passthrough?
    94 
    95 // !!! IMPLEMENT_ME SDL_WM_SetIcon
    96 // !!! IMPLEMENT_ME SDL_WM_ToggleFullScreen
    97 
    98 // !!! IMPLEMENT_ME X11_KeyToUnicode
    99 
   100 
   101 #if 0
   102 #define FIXME(x) do {} while (0)
   103 #else
   104 #define FIXME(x) \
   105     do { \
   106         static SDL_bool seen = SDL_FALSE; \
   107         if (!seen) { \
   108             fprintf(stderr, "FIXME: %s (%s:%d)\n", x, __FILE__, __LINE__); \
   109             seen = SDL_TRUE; \
   110         } \
   111     } while (0)
   112 #endif
   113 
   114 #define SDL20_SYM(rc,fn,params,args,ret) \
   115     typedef rc (SDLCALL *SDL20_##fn##_t) params; \
   116     static SDL20_##fn##_t SDL20_##fn = NULL;
   117 #include "SDL20_syms.h"
   118 
   119 /* Things that _should_ be binary compatible pass right through... */
   120 #define SDL20_SYM_PASSTHROUGH(rc,fn,params,args,ret) \
   121     DECLSPEC rc SDLCALL SDL_##fn params { ret SDL20_##fn args; }
   122 #include "SDL20_syms.h"
   123 
   124 
   125 /* these are macros (etc) in the SDL headers, so make our own. */
   126 #define SDL20_OutOfMemory() SDL20_Error(SDL_ENOMEM)
   127 #define SDL20_Unsupported() SDL20_Error(SDL_UNSUPPORTED)
   128 #define SDL20_InvalidParamError(param) SDL20_SetError("Parameter '%s' is invalid", (param))
   129 #define SDL20_zero(x) SDL20_memset(&(x), 0, sizeof((x)))
   130 #define SDL20_zerop(x) SDL20_memset((x), 0, sizeof(*(x)))
   131 #define SDL_ReportAssertion SDL20_ReportAssertion
   132 
   133 #define SDL12_DEFAULT_REPEAT_DELAY 500
   134 #define SDL12_DEFAULT_REPEAT_INTERVAL 30
   135 
   136 #define SDL12_INIT_TIMER       0x00000001
   137 #define SDL12_INIT_AUDIO       0x00000010
   138 #define SDL12_INIT_VIDEO       0x00000020
   139 #define SDL12_INIT_CDROM       0x00000100
   140 #define SDL12_INIT_JOYSTICK    0x00000200
   141 #define SDL12_INIT_NOPARACHUTE 0x00100000
   142 #define SDL12_INIT_EVENTTHREAD 0x01000000
   143 #define SDL12_INIT_EVERYTHING  0x0000FFFF
   144 
   145 typedef struct SDL12_Palette
   146 {
   147     int       ncolors;
   148     SDL_Color *colors;
   149 } SDL12_Palette;
   150 
   151 typedef struct SDL12_PixelFormat
   152 {
   153     SDL12_Palette *palette;
   154     Uint8 BitsPerPixel;
   155     Uint8 BytesPerPixel;
   156     Uint8 Rloss;
   157     Uint8 Gloss;
   158     Uint8 Bloss;
   159     Uint8 Aloss;
   160     Uint8 Rshift;
   161     Uint8 Gshift;
   162     Uint8 Bshift;
   163     Uint8 Ashift;
   164     Uint32 Rmask;
   165     Uint32 Gmask;
   166     Uint32 Bmask;
   167     Uint32 Amask;
   168     Uint32 colorkey;
   169     Uint8 alpha;
   170 } SDL12_PixelFormat;
   171 
   172 typedef struct SDL12_Surface
   173 {
   174     Uint32 flags;
   175     SDL12_PixelFormat *format;
   176     int w;
   177     int h;
   178     Uint16 pitch;
   179     void *pixels;
   180     int offset;
   181     SDL_Surface *surface20; /* the real SDL 1.2 has an opaque pointer to a platform-specific thing here named "hwdata". */
   182     SDL_Rect clip_rect;
   183     Uint32 unused1;
   184     Uint32 locked;
   185     void *blitmap;
   186     unsigned int format_version;
   187     int refcount;
   188 } SDL12_Surface;
   189 
   190 typedef struct SDL12_Overlay
   191 {
   192     Uint32 format;
   193     int w;
   194     int h;
   195     int planes;
   196     Uint16 *pitches;
   197     Uint8 **pixels;
   198     void *hwfuncs;
   199     void *hwdata;
   200     Uint32 hw_overlay :1;
   201     Uint32 UnusedBits :31;
   202 } SDL12_Overlay;
   203 
   204 typedef struct
   205 {
   206     Uint32 hw_available :1;
   207     Uint32 wm_available :1;
   208     Uint32 UnusedBits1  :6;
   209     Uint32 UnusedBits2  :1;
   210     Uint32 blit_hw      :1;
   211     Uint32 blit_hw_CC   :1;
   212     Uint32 blit_hw_A    :1;
   213     Uint32 blit_sw      :1;
   214     Uint32 blit_sw_CC   :1;
   215     Uint32 blit_sw_A    :1;
   216     Uint32 blit_fill    :1;
   217     Uint32 UnusedBits3  :16;
   218     Uint32 video_mem;
   219     SDL_PixelFormat *vfmt;
   220     int current_w;
   221     int current_h;
   222 } SDL12_VideoInfo;
   223 
   224 
   225 #define SDL12_HWSURFACE 0x00000001
   226 #define SDL12_ASYNCBLIT 0x00000004
   227 #define SDL12_ANYFORMAT 0x10000000
   228 #define SDL12_HWPALETTE 0x20000000
   229 #define SDL12_DOUBLEBUF 0x40000000
   230 #define SDL12_FULLSCREEN 0x80000000
   231 #define SDL12_OPENGL 0x00000002
   232 #define SDL12_OPENGLBLIT 0x0000000A
   233 #define SDL12_RESIZABLE 0x00000010
   234 #define SDL12_NOFRAME 0x00000020
   235 #define SDL12_HWACCEL 0x00000100
   236 #define SDL12_SRCCOLORKEY 0x00001000
   237 #define SDL12_RLEACCELOK 0x00002000
   238 #define SDL12_RLEACCEL 0x00004000
   239 #define SDL12_SRCALPHA 0x00010000
   240 #define SDL12_PREALLOC 0x01000000
   241 
   242 typedef enum
   243 {
   244     SDL12_NOEVENT = 0,
   245     SDL12_ACTIVEEVENT,
   246     SDL12_KEYDOWN,
   247     SDL12_KEYUP,
   248     SDL12_MOUSEMOTION,
   249     SDL12_MOUSEBUTTONDOWN,
   250     SDL12_MOUSEBUTTONUP,
   251     SDL12_JOYAXISMOTION,
   252     SDL12_JOYBALLMOTION,
   253     SDL12_JOYHATMOTION,
   254     SDL12_JOYBUTTONDOWN,
   255     SDL12_JOYBUTTONUP,
   256     SDL12_QUIT,
   257     SDL12_SYSWMEVENT,
   258     SDL12_EVENT_RESERVEDA,
   259     SDL12_EVENT_RESERVEDB,
   260     SDL12_VIDEORESIZE,
   261     SDL12_VIDEOEXPOSE,
   262     SDL12_USEREVENT = 24,
   263     SDL12_NUMEVENTS = 32
   264 } SDL12_EventType;
   265 
   266 
   267 #define SDL12_APPMOUSEFOCUS (1<<0)
   268 #define SDL12_APPINPUTFOCUS (1<<1)
   269 #define SDL12_APPACTIVE     (1<<2)
   270 
   271 typedef struct
   272 {
   273     Uint8 type;
   274     Uint8 gain;
   275     Uint8 state;
   276 } SDL12_ActiveEvent;
   277 
   278 typedef struct
   279 {
   280     Uint8 type;
   281     Uint8 which;
   282     Uint8 state;
   283     //FIXME: SDL12_keysym keysym;
   284 } SDL12_KeyboardEvent;
   285 
   286 typedef struct
   287 {
   288     Uint8 type;
   289     Uint8 which;
   290     Uint8 state;
   291     Uint16 x, y;
   292     Sint16 xrel;
   293     Sint16 yrel;
   294 } SDL12_MouseMotionEvent;
   295 
   296 typedef struct
   297 {
   298     Uint8 type;
   299     Uint8 which;
   300     Uint8 button;
   301     Uint8 state;
   302     Uint16 x, y;
   303 } SDL12_MouseButtonEvent;
   304 
   305 typedef struct
   306 {
   307     Uint8 type;
   308     Uint8 which;
   309     Uint8 axis;
   310     Sint16 value;
   311 } SDL12_JoyAxisEvent;
   312 
   313 typedef struct
   314 {
   315     Uint8 type;
   316     Uint8 which;
   317     Uint8 ball;
   318     Sint16 xrel;
   319     Sint16 yrel;
   320 } SDL12_JoyBallEvent;
   321 
   322 typedef struct
   323 {
   324     Uint8 type;
   325     Uint8 which;
   326     Uint8 hat;
   327     Uint8 value;
   328 } SDL12_JoyHatEvent;
   329 
   330 typedef struct
   331 {
   332     Uint8 type;
   333     Uint8 which;
   334     Uint8 button;
   335     Uint8 state;
   336 } SDL12_JoyButtonEvent;
   337 
   338 typedef struct
   339 {
   340     Uint8 type;
   341     int w;
   342     int h;
   343 } SDL12_ResizeEvent;
   344 
   345 typedef struct
   346 {
   347     Uint8 type;
   348 } SDL12_ExposeEvent;
   349 
   350 typedef struct
   351 {
   352     Uint8 type;
   353 } SDL12_QuitEvent;
   354 
   355 typedef struct
   356 {
   357     Uint8 type;
   358     int code;
   359     void *data1;
   360     void *data2;
   361 } SDL12_UserEvent;
   362 
   363 typedef struct
   364 {
   365     Uint8 type;
   366     void *msg;
   367 } SDL12_SysWMEvent;
   368 
   369 typedef union
   370 {
   371     Uint8 type;
   372     SDL12_ActiveEvent active;
   373     SDL12_KeyboardEvent key;
   374     SDL12_MouseMotionEvent motion;
   375     SDL12_MouseButtonEvent button;
   376     SDL12_JoyAxisEvent jaxis;
   377     SDL12_JoyBallEvent jball;
   378     SDL12_JoyHatEvent jhat;
   379     SDL12_JoyButtonEvent jbutton;
   380     SDL12_ResizeEvent resize;
   381     SDL12_ExposeEvent expose;
   382     SDL12_QuitEvent quit;
   383     SDL12_UserEvent user;
   384     SDL12_SysWMEvent syswm;
   385 } SDL12_Event;
   386 
   387 typedef int (SDLCALL *SDL12_EventFilter)(const SDL12_Event *event12);
   388 static int EventFilter20to12(void *data, SDL_Event *event20);
   389 
   390 typedef Uint32 (SDLCALL *SDL12_TimerCallback)(Uint32 interval);
   391 typedef SDL_TimerCallback SDL12_NewTimerCallback;
   392 
   393 typedef struct
   394 {
   395     SDL_Rect area;
   396     Sint16 hot_x;
   397     Sint16 hot_y;
   398     Uint8 *data;
   399     Uint8 *mask;
   400     Uint8 *save[2];
   401     SDL_Cursor *wm_cursor;  /* the real SDL 1.2 has an opaque pointer to a platform-specific cursor here. */
   402 } SDL12_Cursor;
   403 
   404 typedef enum
   405 {
   406     SDL12_GL_RED_SIZE,
   407     SDL12_GL_GREEN_SIZE,
   408     SDL12_GL_BLUE_SIZE,
   409     SDL12_GL_ALPHA_SIZE,
   410     SDL12_GL_BUFFER_SIZE,
   411     SDL12_GL_DOUBLEBUFFER,
   412     SDL12_GL_DEPTH_SIZE,
   413     SDL12_GL_STENCIL_SIZE,
   414     SDL12_GL_ACCUM_RED_SIZE,
   415     SDL12_GL_ACCUM_GREEN_SIZE,
   416     SDL12_GL_ACCUM_BLUE_SIZE,
   417     SDL12_GL_ACCUM_ALPHA_SIZE,
   418     SDL12_GL_STEREO,
   419     SDL12_GL_MULTISAMPLEBUFFERS,
   420     SDL12_GL_MULTISAMPLESAMPLES,
   421     SDL12_GL_ACCELERATED_VISUAL,
   422     SDL12_GL_SWAP_CONTROL,
   423     SDL12_GL_MAX_ATTRIBUTE
   424 } SDL12_GLattr;
   425 
   426 
   427 typedef struct
   428 {
   429     Uint32 format;
   430     SDL_Rect *modeslist;
   431     SDL_Rect **modes;  /* ptrs to each item in modeslist, for SDL_ListModes() */
   432 } VideoModeList;
   433 
   434 // !!! FIXME: go through all of these.
   435 static VideoModeList *VideoModes = NULL;
   436 static int VideoModesCount = 0;
   437 static SDL12_VideoInfo VideoInfo12;
   438 static SDL_Window *VideoWindow20 = NULL;
   439 static SDL_Renderer *VideoRenderer20 = NULL;
   440 static SDL_Texture *VideoTexture20 = NULL;
   441 static SDL12_Surface *VideoSurface12 = NULL;
   442 static SDL_Surface *VideoConvertSurface20 = NULL;
   443 static SDL_GLContext *VideoGLContext20 = NULL;
   444 static char *WindowTitle = NULL;
   445 static char *WindowIconTitle = NULL;
   446 static SDL12_Surface *VideoIcon12;
   447 static int EnabledUnicode = 0;
   448 static int VideoDisplayIndex = 0;
   449 static int CDRomInit = 0;
   450 static SDL12_EventFilter EventFilter12 = NULL;
   451 static SDL12_Cursor *CurrentCursor12 = NULL;
   452 static Uint8 EventStates[SDL12_NUMEVENTS];
   453 static int SwapInterval = 0;
   454 
   455 // !!! FIXME: need a mutex for the event queue.
   456 #define SDL12_MAXEVENTS 128
   457 typedef struct EventQueueType
   458 {
   459     SDL12_Event event12;
   460     struct EventQueueType *next;
   461 } EventQueueType;
   462 
   463 static EventQueueType EventQueuePool[SDL12_MAXEVENTS];
   464 static EventQueueType *EventQueueHead = NULL;
   465 static EventQueueType *EventQueueTail = NULL;
   466 static EventQueueType *EventQueueAvailable = NULL;
   467 
   468 
   469 /* Obviously we can't use SDL_LoadObject() to load SDL2.  :)  */
   470 #if defined(_WINDOWS)
   471     #define WIN32_LEAN_AND_MEAN 1
   472     #include <windows.h>
   473     #define SDL20_LIBNAME "SDL2.dll"
   474     static HANDLE Loaded_SDL20 = NULL;
   475     #define LoadSDL20Library() ((Loaded_SDL20 = LoadLibraryA(SDL20_LIBNAME)) != NULL)
   476     #define LookupSDL20Sym(sym) GetProcAddress(Loaded_SDL20, sym)
   477     #define CloseSDL20Library() { { if (Loaded_SDL20) { FreeLibrary(Loaded_SDL20); Loaded_SDL20 = NULL; } }
   478 #elif defined(unix) || defined(__APPLE__)
   479     #include <dlfcn.h>
   480     #ifdef __APPLE__
   481     #define SDL20_LIBNAME "libSDL2.dylib"
   482     #else
   483     #define SDL20_LIBNAME "libSDL2-2.0.so.0"
   484     #endif
   485     static void *Loaded_SDL20 = NULL;
   486     #define LoadSDL20Library() ((Loaded_SDL20 = dlopen(SDL20_LIBNAME, RTLD_LOCAL)) != NULL)
   487     #define LookupSDL20Sym(sym) dlsym(Loaded_SDL20, sym)
   488     #define CloseSDL20Library() { if (Loaded_SDL20) { dlclose(Loaded_SDL20); Loaded_SDL20 = NULL; } }
   489 #else
   490     #error Please define your platform.
   491 #endif
   492 
   493 static void *
   494 LoadSDL20Symbol(const char *fn, int *okay)
   495 {
   496     void *retval = NULL;
   497     if (*okay)  /* only bother trying if we haven't previously failed. */
   498     {
   499         retval = LookupSDL20Sym(fn);
   500 if (!retval) { fprintf(stderr, "WARNING: LOAD FAILED: %s\n", fn); }
   501 //        if (retval == NULL)
   502 //            *okay = 0;
   503     }
   504     return retval;
   505 }
   506 
   507 static void
   508 UnloadSDL20(void)
   509 {
   510     #define SDL20_SYM(rc,fn,params,args,ret) SDL20_##fn = NULL;
   511     #include "SDL20_syms.h"
   512     CloseSDL20Library();
   513 }
   514 
   515 static int
   516 LoadSDL20(void)
   517 {
   518     int okay = 1;
   519     if (!Loaded_SDL20)
   520     {
   521         okay = LoadSDL20Library();
   522         #define SDL20_SYM(rc,fn,params,args,ret) SDL20_##fn = (SDL20_##fn##_t) LoadSDL20Symbol("SDL_" #fn, &okay);
   523         #include "SDL20_syms.h"
   524         if (!okay)
   525             UnloadSDL20();
   526     }
   527     return okay;
   528 }
   529 
   530 DECLSPEC const SDL_version * SDLCALL
   531 SDL_Linked_Version(void)
   532 {
   533     static const SDL_version version = { 1, 2, SDL12_COMPAT_VERSION };
   534     return &version;
   535 }
   536 
   537 static int
   538 GetVideoDisplay()
   539 {
   540     FIXME("cache this value during SDL_Init() so it doesn't change.");
   541     const char *variable = SDL20_getenv("SDL_VIDEO_FULLSCREEN_DISPLAY");
   542     if ( !variable ) {
   543         variable = SDL20_getenv("SDL_VIDEO_FULLSCREEN_HEAD");
   544     }
   545     if ( variable ) {
   546         return SDL20_atoi(variable);
   547     } else {
   548         return 0;
   549     }
   550 }
   551 
   552 /* This sets up VideoModes and VideoModesCount. You end up with arrays by pixel
   553     format, each with a value that 1.2's SDL_ListModes() can return. */
   554 static int
   555 Init12VidModes(void)
   556 {
   557     const int total = SDL20_GetNumDisplayModes(VideoDisplayIndex);
   558     VideoModeList *vmode = NULL;
   559     int num_modes = 0;
   560     void *ptr = NULL;
   561     int i, j;
   562 
   563     SDL_assert(VideoModes == NULL);
   564     SDL_assert(VideoModesCount == 0);
   565 
   566     for (i = 0; i < total; ++i) {
   567         SDL_DisplayMode mode;
   568 
   569         if (SDL20_GetDisplayMode(VideoDisplayIndex, i, &mode) == -1) {
   570             continue;
   571         } else if (!mode.w || !mode.h) {
   572             SDL_assert(0 && "Can this actually happen?");
   573             continue;
   574         }
   575 
   576         if (!vmode || (mode.format != vmode->format)) {  // SDL20_GetDisplayMode() sorts on bpp first. We know when to change arrays.
   577             if (VideoModesCount > 0) {
   578                 VideoModes[VideoModesCount-1].modes[num_modes] = NULL;
   579             }
   580             ptr = (VideoModeList *) SDL20_realloc(VideoModes, sizeof (VideoModeList) * (VideoModesCount+1));
   581             if (!ptr) {
   582                 return SDL20_OutOfMemory();
   583             }
   584             VideoModes = (VideoModeList *) ptr;
   585             vmode = &VideoModes[VideoModesCount];
   586             vmode->format = mode.format;
   587             vmode->modeslist = NULL;
   588             vmode->modes = NULL;
   589             VideoModesCount++;
   590             num_modes = 0;
   591         }
   592 
   593         /* make sure we don't have this one already (with a different refresh rate, etc). */
   594         for (j = 0; j < num_modes; j++) {
   595             if ((vmode->modeslist[j].w == mode.w) && (vmode->modeslist[j].h == mode.h)) {
   596                 break;
   597             }
   598         }
   599 
   600         if (j < num_modes) {
   601             continue;  /* already have this one. */
   602         }
   603 
   604         ptr = SDL20_realloc(vmode->modes, sizeof (SDL_Rect *) * (num_modes + 2));
   605         if (ptr == NULL) {
   606             return SDL20_OutOfMemory();
   607         }
   608         vmode->modes = (SDL_Rect **) ptr;
   609 
   610         ptr = SDL20_realloc(vmode->modeslist, sizeof (SDL_Rect) * (num_modes + 1));
   611         if (ptr == NULL) {
   612             return SDL20_OutOfMemory();
   613         }
   614         vmode->modeslist = (SDL_Rect *) ptr;
   615 
   616         vmode->modeslist[num_modes].x = 0;
   617         vmode->modeslist[num_modes].y = 0;
   618         vmode->modeslist[num_modes].w = mode.w;
   619         vmode->modeslist[num_modes].h = mode.h;
   620 
   621         vmode->modes[num_modes] = &vmode->modeslist[num_modes];
   622 
   623         num_modes++;
   624     }
   625 
   626     if (VideoModesCount > 0) {
   627         VideoModes[VideoModesCount-1].modes[num_modes] = NULL;
   628     }
   629 
   630     return 0;
   631 }
   632 
   633 static int
   634 Init12Video(void)
   635 {
   636     int i;
   637 
   638     for (i = 0; i < SDL12_MAXEVENTS-1; i++)
   639         EventQueuePool[i].next = &EventQueuePool[i+1];
   640     EventQueuePool[SDL12_MAXEVENTS-1].next = NULL;
   641 
   642     EventQueueHead = EventQueueTail = NULL;
   643     EventQueueAvailable = EventQueuePool;
   644 
   645     SDL_memset(EventStates, SDL_ENABLE, sizeof (EventStates)); /* on by default */
   646     EventStates[SDL12_SYSWMEVENT] = SDL_IGNORE;  /* off by default. */
   647 
   648     SDL20_SetEventFilter(EventFilter20to12, NULL);
   649 
   650     VideoDisplayIndex = GetVideoDisplay();
   651     SwapInterval = 0;
   652 
   653     if (Init12VidModes() == -1) {
   654         return -1;
   655     }
   656 
   657     return 0;
   658 }
   659 
   660 
   661 DECLSPEC int SDLCALL
   662 SDL_InitSubSystem(Uint32 sdl12flags)
   663 {
   664     FIXME("there is never a parachute in SDL2, should we catch segfaults ourselves?");
   665 
   666     FIXME("support event thread where it makes sense to do so?");
   667 
   668 	if ( (sdl12flags & SDL12_INIT_EVENTTHREAD) == SDL12_INIT_EVENTTHREAD ) {
   669 		return SDL20_SetError("OS doesn't support threaded events");
   670 	}
   671 
   672     Uint32 sdl20flags = 0;
   673     int rc;
   674 
   675     if (!LoadSDL20())
   676         return -1;
   677 
   678     #define SETFLAG(flag) if (sdl12flags & SDL12_INIT_##flag) sdl20flags |= SDL_INIT_##flag
   679     SETFLAG(TIMER);
   680     SETFLAG(AUDIO);
   681     SETFLAG(VIDEO);
   682     SETFLAG(JOYSTICK);
   683     SETFLAG(NOPARACHUTE);
   684     #undef SETFLAG
   685 
   686     // There's no CDROM in 2.0, but we'll just pretend it succeeded.
   687     if (sdl12flags & SDL12_INIT_CDROM)
   688         CDRomInit = 1;
   689 
   690     FIXME("do something about SDL12_INIT_EVENTTHREAD");
   691 
   692     rc = SDL20_Init(sdl20flags);
   693     if ((rc == 0) && (sdl20flags & SDL_INIT_VIDEO)) {
   694         if (Init12Video() == -1) {
   695             FIXME("should we deinit other subsystems?");
   696             return -1;
   697         }
   698     }
   699 
   700     return rc;
   701 }
   702 
   703 DECLSPEC int SDLCALL
   704 SDL_Init(Uint32 sdl12flags)
   705 {
   706     FIXME("what was different in 1.2?");
   707     return SDL_InitSubSystem(sdl12flags);   /* there's no difference betwee Init and InitSubSystem in SDL2. */
   708 }
   709 
   710 
   711 static void
   712 InitFlags12To20(const Uint32 flags12, Uint32 *_flags20, Uint32 *_extraflags)
   713 {
   714     Uint32 flags20 = 0;
   715     Uint32 extraflags = 0;
   716 
   717     #define SETFLAG(flag) if (flags12 & SDL12_INIT_##flag) flags20 |= SDL_INIT_##flag
   718     SETFLAG(TIMER);
   719     SETFLAG(AUDIO);
   720     SETFLAG(VIDEO);
   721     SETFLAG(JOYSTICK);
   722     SETFLAG(NOPARACHUTE);
   723     #undef SETFLAG
   724 
   725     if ((flags12 & SDL12_INIT_CDROM) && (CDRomInit)) {
   726         extraflags |= SDL12_INIT_CDROM;
   727     }
   728 
   729     FIXME("do something about SDL12_INIT_EVENTTHREAD");
   730 
   731     *_flags20 = flags20;
   732     *_extraflags = extraflags;
   733 }
   734 
   735 static Uint32
   736 InitFlags20to12(const Uint32 flags20)
   737 {
   738     Uint32 flags12 = 0;
   739 
   740     #define SETFLAG(flag) if (flags20 & SDL_INIT_##flag) flags12 |= SDL12_INIT_##flag
   741     SETFLAG(TIMER);
   742     SETFLAG(AUDIO);
   743     SETFLAG(VIDEO);
   744     SETFLAG(JOYSTICK);
   745     SETFLAG(NOPARACHUTE);
   746     #undef SETFLAG
   747 
   748     return flags12;
   749 }
   750 
   751 
   752 DECLSPEC Uint32 SDLCALL
   753 SDL_WasInit(Uint32 sdl12flags)
   754 {
   755     Uint32 sdl20flags, extraflags;
   756     InitFlags12To20(sdl12flags, &sdl20flags, &extraflags);
   757 
   758     return InitFlags20to12(SDL20_WasInit(sdl20flags)) | extraflags;
   759 }
   760 
   761 static void
   762 Quit12Video(void)
   763 {
   764     int i;
   765 
   766     for (i = 0; i < VideoModesCount; i++) {
   767         SDL20_free(VideoModes[i].modeslist);
   768         SDL20_free(VideoModes[i].modes);
   769     }
   770     SDL20_free(VideoModes);
   771 
   772     SDL20_FreeFormat(VideoInfo12.vfmt);
   773     SDL20_zero(VideoInfo12);
   774 
   775     EventFilter12 = NULL;
   776     EventQueueAvailable = EventQueueHead = EventQueueTail = NULL;
   777     CurrentCursor12 = NULL;
   778     VideoModes = NULL;
   779     VideoModesCount = 0;
   780 }
   781 
   782 DECLSPEC void SDLCALL
   783 SDL_QuitSubSystem(Uint32 sdl12flags)
   784 {
   785     Uint32 sdl20flags, extraflags;
   786     InitFlags12To20(sdl12flags, &sdl20flags, &extraflags);
   787 
   788     if (extraflags & SDL12_INIT_CDROM) {
   789         CDRomInit = 0;
   790     }
   791 
   792     FIXME("reset a bunch of other global variables too.");
   793     if (sdl12flags & SDL12_INIT_VIDEO) {
   794         Quit12Video();
   795     }
   796 
   797     FIXME("do something about SDL12_INIT_EVENTTHREAD");
   798     SDL20_QuitSubSystem(sdl20flags);
   799 
   800     if ((SDL20_WasInit(0) == 0) && (!CDRomInit)) {
   801         SDL20_Quit();
   802         UnloadSDL20();
   803     }
   804 }
   805 
   806 DECLSPEC void SDLCALL
   807 SDL_Quit(void)
   808 {
   809     SDL_QuitSubSystem(SDL_WasInit(0) | SDL12_INIT_CDROM);
   810 }
   811 
   812 DECLSPEC void SDLCALL
   813 SDL_SetError(const char *fmt, ...)
   814 {
   815     char ch;
   816     char *str = NULL;
   817     size_t len = 0;
   818     va_list ap;
   819     va_start(ap, fmt);
   820     len = SDL20_vsnprintf(&ch, 1, fmt, ap);
   821     va_end(ap);
   822 
   823     str = (char *) SDL20_malloc(len + 1);
   824     if (!str)
   825         SDL20_OutOfMemory();
   826     else
   827     {
   828         va_start(ap, fmt);
   829         SDL20_vsnprintf(str, len + 1, fmt, ap);
   830         va_end(ap);
   831         SDL20_SetError("%s", str);
   832         SDL20_free(str);
   833     }
   834 }
   835 
   836 DECLSPEC const char * SDLCALL
   837 SDL_GetError(void)
   838 {
   839     if (!Loaded_SDL20)
   840     {
   841         static const char noload_errstr[] = "Failed to load SDL 2.0 shared library";
   842         return noload_errstr;
   843     }
   844     return SDL20_GetError();
   845 }
   846 
   847 
   848 static const char *
   849 GetDriverName(const char *name, char *namebuf, int maxlen)
   850 {
   851     if (name) {
   852         if (namebuf) {
   853             SDL20_strlcpy(namebuf, name, maxlen);
   854             return namebuf;
   855         } else {
   856             return name;
   857         }
   858     }
   859     return NULL;
   860 }
   861 
   862 DECLSPEC const char * SDLCALL
   863 SDL_AudioDriverName(char *namebuf, int maxlen)
   864 {
   865     return GetDriverName(SDL20_GetCurrentAudioDriver(), namebuf, maxlen);
   866 }
   867 
   868 DECLSPEC const char * SDLCALL
   869 SDL_VideoDriverName(char *namebuf, int maxlen)
   870 {
   871     return GetDriverName(SDL20_GetCurrentVideoDriver(), namebuf, maxlen);
   872 }
   873 
   874 DECLSPEC int SDLCALL
   875 SDL_PollEvent(SDL12_Event *event12)
   876 {
   877     EventQueueType *next;
   878 
   879     SDL20_PumpEvents();  /* this will run our filter and build our 1.2 queue. */
   880 
   881     if (EventQueueHead == NULL)
   882         return 0;  /* no events at the moment. */
   883 
   884     SDL_memcpy(event12, &EventQueueHead->event12, sizeof (SDL12_Event));
   885     next = EventQueueHead->next;
   886     EventQueueHead->next = EventQueueAvailable;
   887     EventQueueAvailable = EventQueueHead;
   888     EventQueueHead = next;
   889     return 1;
   890 }
   891 
   892 DECLSPEC int SDLCALL
   893 SDL_PushEvent(SDL12_Event *event12)
   894 {
   895     EventQueueType *item = EventQueueAvailable;
   896     if (item == NULL)
   897         return -1;  /* no space available at the moment. */
   898 
   899     EventQueueAvailable = item->next;
   900     if (EventQueueTail)
   901         EventQueueTail->next = item;
   902     else
   903         EventQueueHead = EventQueueTail = item;
   904     item->next = NULL;
   905 
   906     SDL_memcpy(&item->event12, event12, sizeof (SDL12_Event));
   907     return 0;
   908 }
   909 
   910 DECLSPEC int SDLCALL
   911 SDL_PeepEvents(SDL12_Event *events12, int numevents, SDL_eventaction action, Uint32 mask)
   912 {
   913     if (action == SDL_ADDEVENT)
   914     {
   915         int i;
   916         for (i = 0; i < numevents; i++)
   917         {
   918             if (SDL_PushEvent(&events12[i]) == -1)
   919                 break;  /* out of space for more events. */
   920         }
   921         return i;
   922     }
   923     else if ((action == SDL_PEEKEVENT) || (action == SDL_GETEVENT))
   924     {
   925         const SDL_bool isGet = (action == SDL_GETEVENT);
   926         EventQueueType *prev = NULL;
   927         EventQueueType *item = EventQueueHead;
   928         EventQueueType *next = NULL;
   929         int chosen = 0;
   930         while (chosen < numevents)
   931         {
   932             EventQueueType *nextPrev = item;
   933             if (!item)
   934                 break;  /* no more events at the moment. */
   935 
   936             next = item->next;  /* copy, since we might overwrite item->next */
   937 
   938             if (mask & (1<<item->event12.type))
   939             {
   940                 SDL_memcpy(&events12[chosen++], &item->event12, sizeof (SDL12_Event));
   941                 if (isGet)  /* remove from list? */
   942                 {
   943                     if (prev != NULL)
   944                         prev->next = next;
   945                     if (item == EventQueueHead)
   946                         EventQueueHead = next;
   947                     if (item == EventQueueTail)
   948                         EventQueueTail = prev;
   949 
   950                     /* put it back in the free pool. */
   951                     item->next = EventQueueAvailable;
   952                     EventQueueAvailable = item;
   953                     nextPrev = prev;  /* previous item doesn't change. */
   954                 }
   955             }
   956 
   957             item = next;
   958             prev = nextPrev;
   959         }
   960         return chosen;
   961     }
   962 
   963     return 0;
   964 }
   965 
   966 DECLSPEC int SDLCALL
   967 SDL_WaitEvent(SDL12_Event *event12)
   968 {
   969     FIXME("In 1.2, this only fails (-1) if you haven't SDL_Init()'d.");
   970     while (!SDL_PollEvent(event12))
   971         SDL20_Delay(10);
   972     return 1;
   973 }
   974 
   975 static SDL_bool
   976 PushEventIfNotFiltered(SDL12_Event *event12)
   977 {
   978     if (event12->type != SDL12_NOEVENT)
   979     {
   980         if (EventStates[event12->type] != SDL_IGNORE)
   981         {
   982             if ((!EventFilter12) || (EventFilter12(event12)))
   983                 return (SDL_PushEvent(event12) == 0);
   984         }
   985     }
   986     return SDL_FALSE;
   987 }
   988 
   989 DECLSPEC Uint8 SDLCALL
   990 SDL_EventState(Uint8 type, int state)
   991 {
   992     /* the values of "state" match between 1.2 and 2.0 */
   993     const Uint8 retval = EventStates[type];
   994     SDL12_Event e;
   995 
   996     if (state != SDL_QUERY)
   997         EventStates[type] = state;
   998     if (state == SDL_IGNORE)  /* drop existing events of this type. */
   999         while (SDL_PeepEvents(&e, 1, SDL_GETEVENT, (1<<type))) {}
  1000 
  1001     return retval;
  1002 }
  1003 
  1004 DECLSPEC Uint8 SDLCALL
  1005 SDL_GetMouseState(int *x, int *y)
  1006 {
  1007     const Uint32 state20 = SDL20_GetMouseState(x, y);
  1008     Uint8 retval = (state20 & 0x7);  /* left, right, and middle will match. */
  1009 
  1010     /* the X[12] buttons are different in 1.2; mousewheel was in the way. */
  1011     if (state20 & SDL_BUTTON(SDL_BUTTON_X1))
  1012         retval |= (1<<5);
  1013     if (state20 & SDL_BUTTON(SDL_BUTTON_X2))
  1014         retval |= (1<<6);
  1015 
  1016     return retval;
  1017 }
  1018 
  1019 static int
  1020 EventFilter20to12(void *data, SDL_Event *event20)
  1021 {
  1022     //const int maxUserEvents12 = SDL12_NUMEVENTS - SDL12_USEREVENT;
  1023     SDL12_Event event12;
  1024     int x, y;
  1025 
  1026     SDL_assert(data == NULL);  /* currently unused. */
  1027 
  1028     SDL20_zero(event12);
  1029 
  1030     switch (event20->type)
  1031     {
  1032         case SDL_QUIT:
  1033             event12.type = SDL12_QUIT;
  1034             break;
  1035 
  1036         case SDL_WINDOWEVENT:
  1037             switch (event20->window.event)
  1038             {
  1039                 case SDL_WINDOWEVENT_CLOSE:
  1040                     event12.type = SDL12_QUIT;
  1041                     break;
  1042 
  1043                 case SDL_WINDOWEVENT_SHOWN:
  1044                 case SDL_WINDOWEVENT_EXPOSED:
  1045                     event12.type = SDL12_VIDEOEXPOSE;
  1046                     break;
  1047 
  1048                 case SDL_WINDOWEVENT_RESIZED:
  1049                 case SDL_WINDOWEVENT_SIZE_CHANGED:
  1050                     FIXME("what's the difference between RESIZED and SIZE_CHANGED?");
  1051                     event12.type = SDL12_VIDEORESIZE;
  1052                     event12.resize.w = event20->window.data1;
  1053                     event12.resize.h = event20->window.data2;
  1054                     break;
  1055 
  1056                 case SDL_WINDOWEVENT_MINIMIZED:
  1057                     event12.type = SDL12_ACTIVEEVENT;
  1058                     event12.active.gain = 0;
  1059                     event12.active.state = SDL12_APPACTIVE;
  1060                     break;
  1061 
  1062                 case SDL_WINDOWEVENT_RESTORED:
  1063                     event12.type = SDL12_ACTIVEEVENT;
  1064                     event12.active.gain = 1;
  1065                     event12.active.state = SDL12_APPACTIVE;
  1066                     break;
  1067 
  1068                 case SDL_WINDOWEVENT_ENTER:
  1069                     event12.type = SDL12_ACTIVEEVENT;
  1070                     event12.active.gain = 1;
  1071                     event12.active.state = SDL12_APPMOUSEFOCUS;
  1072                     break;
  1073 
  1074                 case SDL_WINDOWEVENT_LEAVE:
  1075                     event12.type = SDL12_ACTIVEEVENT;
  1076                     event12.active.gain = 0;
  1077                     event12.active.state = SDL12_APPMOUSEFOCUS;
  1078                     break;
  1079 
  1080                 case SDL_WINDOWEVENT_FOCUS_GAINED:
  1081                     event12.type = SDL12_ACTIVEEVENT;
  1082                     event12.active.gain = 1;
  1083                     event12.active.state = SDL12_APPINPUTFOCUS;
  1084                     break;
  1085 
  1086                 case SDL_WINDOWEVENT_FOCUS_LOST:
  1087                     event12.type = SDL12_ACTIVEEVENT;
  1088                     event12.active.gain = 0;
  1089                     event12.active.state = SDL12_APPINPUTFOCUS;
  1090                     break;
  1091             }
  1092             break;
  1093 
  1094         // !!! FIXME: this is sort of a mess to convert.
  1095         //case SDL_SYSWMEVENT:
  1096 
  1097         case SDL_KEYDOWN: FIXME("write me"); return 0;
  1098         case SDL_KEYUP: FIXME("write me"); return 0;
  1099 
  1100         case SDL_TEXTEDITING: FIXME("write me"); return 0;
  1101         case SDL_TEXTINPUT: FIXME("write me"); return 0;
  1102 
  1103         case SDL_MOUSEMOTION:
  1104         	event12.type = SDL12_MOUSEMOTION;
  1105             event12.motion.which = (Uint8) event20->motion.which;
  1106             event12.motion.state = event20->motion.state;
  1107             event12.motion.x = (Uint16) event20->motion.x;
  1108             event12.motion.y = (Uint16) event20->motion.y;
  1109             event12.motion.xrel = (Sint16) event20->motion.xrel;
  1110             event12.motion.yrel = (Sint16) event20->motion.yrel;
  1111             break;
  1112 
  1113         case SDL_MOUSEBUTTONDOWN:
  1114         	event12.type = SDL12_MOUSEBUTTONDOWN;
  1115             event12.button.which = (Uint8) event20->button.which;
  1116             event12.button.button = event20->button.button;
  1117             event12.button.state = event20->button.state;
  1118             event12.button.x = (Uint16) event20->button.x;
  1119             event12.button.y = (Uint16) event20->button.y;
  1120             break;
  1121 
  1122         case SDL_MOUSEBUTTONUP:
  1123         	event12.type = SDL12_MOUSEBUTTONUP;
  1124             event12.button.which = (Uint8) event20->button.which;
  1125             event12.button.button = event20->button.button;
  1126             event12.button.state = event20->button.state;
  1127             event12.button.x = (Uint16) event20->button.x;
  1128             event12.button.y = (Uint16) event20->button.y;
  1129             break;
  1130 
  1131         case SDL_MOUSEWHEEL:
  1132             if (event20->wheel.y == 0)
  1133                 break;  /* don't support horizontal wheels in 1.2. */
  1134 
  1135             event12.type = SDL12_MOUSEBUTTONDOWN;
  1136             event12.button.which = (Uint8) event20->wheel.which;
  1137             event12.button.button = (event20->wheel.y > 0) ? 4 : 5;  /* wheelup is 4, down is 5. */
  1138             event12.button.state = SDL_GetMouseState(&x, &y);
  1139             event12.button.x = (Uint16) x;
  1140             event12.button.y = (Uint16) y;
  1141             PushEventIfNotFiltered(&event12);
  1142 
  1143             event12.type = SDL12_MOUSEBUTTONUP;  /* immediately release mouse "button" at the end of this switch. */
  1144             break;
  1145 
  1146         case SDL_JOYAXISMOTION:
  1147             event12.type = SDL12_JOYAXISMOTION;
  1148             event12.jaxis.which = (Uint8) event20->jaxis.which;
  1149             event12.jaxis.axis = event20->jaxis.axis;
  1150             event12.jaxis.value = event20->jaxis.value;
  1151             break;
  1152 
  1153         case SDL_JOYBALLMOTION:
  1154             event12.type = SDL12_JOYBALLMOTION;
  1155             event12.jball.which = (Uint8) event20->jball.which;
  1156             event12.jball.ball = event20->jball.ball;
  1157             event12.jball.xrel = event20->jball.xrel;
  1158             event12.jball.yrel = event20->jball.yrel;
  1159             break;
  1160 
  1161         case SDL_JOYHATMOTION:
  1162             event12.type = SDL12_JOYHATMOTION;
  1163             event12.jhat.which = (Uint8) event20->jhat.which;
  1164             event12.jhat.hat = event20->jhat.hat;
  1165             event12.jhat.value = event20->jhat.value;
  1166             break;
  1167 
  1168         case SDL_JOYBUTTONDOWN:
  1169             event12.type = SDL12_JOYBUTTONDOWN;
  1170             event12.jbutton.which = (Uint8) event20->jbutton.which;
  1171             event12.jbutton.button = event20->jbutton.button;
  1172             event12.jbutton.state = event20->jbutton.state;
  1173             break;
  1174 
  1175         case SDL_JOYBUTTONUP:
  1176             event12.type = SDL12_JOYBUTTONUP;
  1177             event12.jbutton.which = (Uint8) event20->jbutton.which;
  1178             event12.jbutton.button = event20->jbutton.button;
  1179             event12.jbutton.state = event20->jbutton.state;
  1180             break;
  1181 
  1182         //case SDL_JOYDEVICEADDED:
  1183         //case SDL_JOYDEVICEREMOVED:
  1184 	    //case SDL_CONTROLLERAXISMOTION:
  1185 	    //case SDL_CONTROLLERBUTTONDOWN:
  1186 	    //case SDL_CONTROLLERBUTTONUP:
  1187 	    //case SDL_CONTROLLERDEVICEADDED:
  1188 	    //case SDL_CONTROLLERDEVICEREMOVED:
  1189 	    //case SDL_CONTROLLERDEVICEREMAPPED:
  1190         //case SDL_FINGERDOWN:
  1191         //case SDL_FINGERUP:
  1192         //case SDL_FINGERMOTION:
  1193         //case SDL_DOLLARGESTURE:
  1194         //case SDL_DOLLARRECORD:
  1195         //case SDL_MULTIGESTURE:
  1196         //case SDL_CLIPBOARDUPDATE:
  1197         //case SDL_DROPFILE:
  1198 
  1199         default:
  1200             return 0;  /* drop everything else. */
  1201     }
  1202 
  1203     PushEventIfNotFiltered(&event12);
  1204 
  1205     return 0;  /* always drop it from the 2.0 event queue. */
  1206 }
  1207 
  1208 DECLSPEC void SDLCALL
  1209 SDL_SetEventFilter(SDL12_EventFilter filter12)
  1210 {
  1211     /* We always have a filter installed, but will call the app's too. */
  1212     EventFilter12 = filter12;
  1213 }
  1214 
  1215 DECLSPEC SDL12_EventFilter SDLCALL
  1216 SDL_GetEventFilter(void)
  1217 {
  1218     return EventFilter12;
  1219 }
  1220 
  1221 
  1222 static SDL12_Surface *
  1223 Surface20to12(SDL_Surface *surface20)
  1224 {
  1225     SDL12_Surface *surface12 = NULL;
  1226     SDL12_Palette *palette12 = NULL;
  1227     SDL12_PixelFormat *format12 = NULL;
  1228     Uint32 flags = 0;
  1229 
  1230     if (!surface20)
  1231         return NULL;
  1232 
  1233     surface12 = (SDL12_Surface *) SDL20_malloc(sizeof (SDL12_Surface));
  1234     if (!surface12)
  1235         goto failed;
  1236 
  1237     palette12 = (SDL12_Palette *) SDL20_malloc(sizeof (SDL12_Palette));
  1238     if (!palette12)
  1239         goto failed;
  1240 
  1241     format12 = (SDL12_PixelFormat *) SDL20_malloc(sizeof (SDL12_PixelFormat));
  1242     if (!format12)
  1243         goto failed;
  1244 
  1245     SDL20_zerop(palette12);
  1246     palette12->ncolors = surface20->format->palette->ncolors;
  1247     palette12->colors = surface20->format->palette->colors;
  1248 
  1249     SDL20_zerop(format12);
  1250     format12->palette = palette12;
  1251     format12->BitsPerPixel = surface20->format->BitsPerPixel;
  1252     format12->BytesPerPixel = surface20->format->BytesPerPixel;
  1253     format12->Rloss = surface20->format->Rloss;
  1254     format12->Gloss = surface20->format->Gloss;
  1255     format12->Bloss = surface20->format->Bloss;
  1256     format12->Aloss = surface20->format->Aloss;
  1257     format12->Rshift = surface20->format->Rshift;
  1258     format12->Gshift = surface20->format->Gshift;
  1259     format12->Bshift = surface20->format->Bshift;
  1260     format12->Ashift = surface20->format->Ashift;
  1261     format12->Rmask = surface20->format->Rmask;
  1262     format12->Gmask = surface20->format->Gmask;
  1263     format12->Bmask = surface20->format->Bmask;
  1264     format12->Amask = surface20->format->Amask;
  1265     FIXME("format12->colorkey");
  1266     FIXME("format12->alpha");
  1267 
  1268     SDL20_zerop(surface12);
  1269     flags = surface20->flags;
  1270     #define MAPSURFACEFLAGS(fl) { if (surface20->flags & SDL_##fl) { surface12->flags |= SDL12_##fl; flags &= ~SDL_##fl; } }
  1271     MAPSURFACEFLAGS(PREALLOC);
  1272     MAPSURFACEFLAGS(RLEACCEL);
  1273     /*MAPSURFACEFLAGS(DONTFREE);*/
  1274     #undef MAPSURFACEFLAGS
  1275     SDL_assert(flags == 0);  /* non-zero if there's a flag we didn't map. */
  1276 
  1277     surface12->format = format12;
  1278     surface12->w = surface20->w;
  1279     surface12->h = surface20->h;
  1280     surface12->pitch = (Uint16) surface20->pitch;  FIXME("make sure this fits in a Uint16");
  1281     surface12->pixels = surface20->pixels;
  1282     surface12->offset = 0;
  1283     surface12->surface20 = surface20;
  1284     SDL20_memcpy(&surface12->clip_rect, &surface20->clip_rect, sizeof (SDL_Rect));
  1285     surface12->refcount = surface20->refcount;
  1286 
  1287     return surface12;
  1288 
  1289 failed:
  1290     SDL20_free(surface12);
  1291     SDL20_free(palette12);
  1292     SDL20_free(format12);
  1293     return NULL;
  1294 }
  1295 
  1296 DECLSPEC SDL12_Surface * SDLCALL
  1297 SDL_CreateRGBSurface(Uint32 sdl12flags, int width, int height, int depth, Uint32 Rmask, Uint32 Gmask, Uint32 Bmask, Uint32 Amask)
  1298 {
  1299     SDL_Surface *surface20 = SDL20_CreateRGBSurface(0, width, height, depth, Rmask, Gmask, Bmask, Amask);
  1300     SDL12_Surface *surface12 = Surface20to12(surface20);
  1301     if (!surface12) {
  1302         SDL20_FreeSurface(surface20);
  1303         return NULL;
  1304     }
  1305 
  1306     SDL_assert(surface12->flags == 0);  // shouldn't have prealloc, rleaccel, or dontfree.
  1307     return surface12;
  1308 }
  1309 
  1310 DECLSPEC SDL12_Surface * SDLCALL
  1311 SDL_CreateRGBSurfaceFrom(void *pixels, int width, int height, int depth, int pitch, Uint32 Rmask, Uint32 Gmask, Uint32 Bmask, Uint32 Amask)
  1312 {
  1313     SDL_Surface *surface20 = SDL20_CreateRGBSurfaceFrom(pixels, width, height, depth, pitch, Rmask, Gmask, Bmask, Amask);
  1314     SDL12_Surface *surface12 = Surface20to12(surface20);
  1315     if (!surface12) {
  1316         SDL20_FreeSurface(surface20);
  1317         return NULL;
  1318     }
  1319 
  1320     SDL_assert(surface12->flags == SDL12_PREALLOC);  // should _only_ have prealloc.
  1321     return surface12;
  1322 }
  1323 
  1324 DECLSPEC void SDLCALL
  1325 SDL_FreeSurface(SDL12_Surface *surface12)
  1326 {
  1327     if (surface12) {
  1328         SDL20_FreeSurface(surface12->surface20);
  1329         if (surface12->format) {
  1330             SDL20_free(surface12->format->palette);
  1331             SDL20_free(surface12->format);
  1332         }
  1333         SDL20_free(surface12);
  1334     }
  1335 }
  1336 
  1337 DECLSPEC void SDLCALL
  1338 SDL_GetClipRect(SDL12_Surface *surface12, SDL_Rect *rect)
  1339 {
  1340     if (surface12 && rect)
  1341 	    SDL_memcpy(rect, &surface12->clip_rect, sizeof (SDL_Rect));
  1342 }
  1343 
  1344 DECLSPEC SDL_bool SDLCALL
  1345 SDL_SetClipRect(SDL12_Surface *surface12, const SDL_Rect *rect)
  1346 {
  1347     SDL_bool retval = SDL_FALSE;
  1348     if (surface12)
  1349     {
  1350         retval = SDL20_SetClipRect(surface12->surface20, rect);
  1351         SDL20_GetClipRect(surface12->surface20, &surface12->clip_rect);
  1352     }
  1353     return retval;
  1354 }
  1355 
  1356 DECLSPEC int SDLCALL
  1357 SDL_FillRect(SDL12_Surface *dst, SDL_Rect *dstrect, Uint32 color)
  1358 {
  1359     const SDL_Rect orig_dstrect = *dstrect;
  1360     const int retval = SDL20_FillRect(dst->surface20, &orig_dstrect, color);
  1361     if (retval != -1)
  1362     {
  1363         if (dstrect)  /* 1.2 stores the clip intersection in dstrect */
  1364             SDL20_IntersectRect(&orig_dstrect, &dst->clip_rect, dstrect);
  1365     }
  1366     return retval;
  1367 }
  1368 
  1369 
  1370 static SDL_PixelFormat *
  1371 PixelFormat12to20(SDL_PixelFormat *format20, SDL_Palette *palette20, const SDL12_PixelFormat *format12)
  1372 {
  1373     palette20->ncolors = format12->palette->ncolors;
  1374     palette20->colors = format12->palette->colors;
  1375     palette20->version = 1;
  1376     palette20->refcount = 1;
  1377     format20->format = SDL20_MasksToPixelFormatEnum(format12->BitsPerPixel, format12->Rmask, format12->Gmask, format12->Bmask, format12->Amask);
  1378     format20->palette = palette20;
  1379     format20->BitsPerPixel = format12->BitsPerPixel;
  1380     format20->BytesPerPixel = format12->BytesPerPixel;
  1381     format20->Rmask = format12->Rmask;
  1382     format20->Gmask = format12->Gmask;
  1383     format20->Bmask = format12->Bmask;
  1384     format20->Amask = format12->Amask;
  1385     format20->Rloss = format12->Rloss;
  1386     format20->Gloss = format12->Gloss;
  1387     format20->Bloss = format12->Bloss;
  1388     format20->Aloss = format12->Aloss;
  1389     format20->Rshift = format12->Rshift;
  1390     format20->Gshift = format12->Gshift;
  1391     format20->Bshift = format12->Bshift;
  1392     format20->Ashift = format12->Ashift;
  1393     format20->refcount = 1;
  1394     format20->next = NULL;
  1395     return format20;
  1396 }
  1397 
  1398 DECLSPEC Uint32 SDLCALL
  1399 SDL_MapRGB(const SDL12_PixelFormat *format12, Uint8 r, Uint8 g, Uint8 b)
  1400 {
  1401     /* This is probably way slower than apps expect. */
  1402     SDL_PixelFormat format20;
  1403     SDL_Palette palette20;
  1404     return SDL20_MapRGB(PixelFormat12to20(&format20, &palette20, format12), r, g, b);
  1405 }
  1406 
  1407 DECLSPEC Uint32 SDLCALL
  1408 SDL_MapRGBA(const SDL12_PixelFormat *format12, Uint8 r, Uint8 g, Uint8 b, Uint8 a)
  1409 {
  1410     /* This is probably way slower than apps expect. */
  1411     SDL_PixelFormat format20;
  1412     SDL_Palette palette20;
  1413     return SDL20_MapRGBA(PixelFormat12to20(&format20, &palette20, format12), r, g, b, a);
  1414 }
  1415 
  1416 DECLSPEC void SDLCALL
  1417 SDL_GetRGB(Uint32 pixel, const SDL12_PixelFormat *format12, Uint8 *r, Uint8 *g, Uint8 *b)
  1418 {
  1419     /* This is probably way slower than apps expect. */
  1420     SDL_PixelFormat format20;
  1421     SDL_Palette palette20;
  1422     return SDL20_GetRGB(pixel, PixelFormat12to20(&format20, &palette20, format12), r, g, b);
  1423 }
  1424 
  1425 DECLSPEC void SDLCALL
  1426 SDL_GetRGBA(Uint32 pixel, const SDL12_PixelFormat *format12, Uint8 *r, Uint8 *g, Uint8 *b, Uint8 *a)
  1427 {
  1428     /* This is probably way slower than apps expect. */
  1429     SDL_PixelFormat format20;
  1430     SDL_Palette palette20;
  1431     return SDL20_GetRGBA(pixel, PixelFormat12to20(&format20, &palette20, format12), r, g, b, a);
  1432 }
  1433 
  1434 DECLSPEC const SDL12_VideoInfo * SDLCALL
  1435 SDL_GetVideoInfo(void)
  1436 {
  1437     SDL_DisplayMode mode;
  1438 
  1439     FIXME("calculate this in Init12Video(), then this just does: return VideoInfo.vfmt ? &VideoInfo : NULL;");
  1440 
  1441     if (!VideoInfo12.vfmt && SDL20_GetDesktopDisplayMode(VideoDisplayIndex, &mode) == 0) {
  1442         VideoInfo12.vfmt = SDL20_AllocFormat(mode.format);
  1443         VideoInfo12.current_w = mode.w;
  1444         VideoInfo12.current_h = mode.h;
  1445         FIXME("vidinfo details commented out");
  1446         //VideoInfo12.wm_available = 1;
  1447         //VideoInfo12.video_mem = 1024 * 256;
  1448     }
  1449     return &VideoInfo12;
  1450 }
  1451 
  1452 DECLSPEC int SDLCALL
  1453 SDL_VideoModeOK(int width, int height, int bpp, Uint32 sdl12flags)
  1454 {
  1455     int i, nummodes, actual_bpp = 0;
  1456 
  1457     if (!SDL20_WasInit(SDL_INIT_VIDEO)) {
  1458         return 0;
  1459     }
  1460 
  1461     if (!(sdl12flags & SDL12_FULLSCREEN)) {
  1462         SDL_DisplayMode mode;
  1463         SDL20_GetDesktopDisplayMode(VideoDisplayIndex, &mode);
  1464         return SDL_BITSPERPIXEL(mode.format);
  1465     }
  1466 
  1467     nummodes = SDL20_GetNumDisplayModes(VideoDisplayIndex);
  1468     for (i = 0; i < nummodes; ++i) {
  1469         SDL_DisplayMode mode;
  1470         SDL20_GetDisplayMode(VideoDisplayIndex, i, &mode);
  1471         if (!mode.w || !mode.h || (width == mode.w && height == mode.h)) {
  1472             if (!mode.format) {
  1473                 return bpp;
  1474             }
  1475             if (SDL_BITSPERPIXEL(mode.format) >= (Uint32) bpp) {
  1476                 actual_bpp = SDL_BITSPERPIXEL(mode.format);
  1477             }
  1478         }
  1479     }
  1480     return actual_bpp;
  1481 }
  1482 
  1483 DECLSPEC SDL_Rect ** SDLCALL
  1484 SDL_ListModes(const SDL12_PixelFormat *format12, Uint32 flags)
  1485 {
  1486     Uint32 fmt;
  1487     int i;
  1488 
  1489     if (!SDL20_WasInit(SDL_INIT_VIDEO)) {
  1490         return NULL;
  1491     }
  1492 
  1493     if ((!format12) && (!VideoInfo12.vfmt)) {
  1494         SDL20_SetError("No pixel format specified");
  1495         return NULL;
  1496     }
  1497 
  1498     if (!(flags & SDL12_FULLSCREEN)) {
  1499         return (SDL_Rect **) (-1);  /* any resolution is fine. */
  1500     }
  1501 
  1502     if (format12) {
  1503         fmt = SDL20_MasksToPixelFormatEnum(format12->BitsPerPixel, format12->Rmask, format12->Gmask, format12->Bmask, format12->Amask);
  1504     } else {
  1505         fmt = VideoInfo12.vfmt->format;
  1506     }
  1507 
  1508     for (i = 0; i < VideoModesCount; i++) {
  1509         VideoModeList *modes = &VideoModes[i];
  1510         if (modes->format == fmt) {
  1511             return modes->modes;
  1512         }
  1513     }
  1514 
  1515     SDL20_SetError("No modes support requested pixel format");
  1516     return NULL;
  1517 }
  1518 
  1519 DECLSPEC void SDLCALL
  1520 SDL_FreeCursor(SDL12_Cursor *cursor12)
  1521 {
  1522     if (cursor12) {
  1523         if (cursor12->wm_cursor)
  1524             SDL20_FreeCursor(cursor12->wm_cursor);
  1525         SDL20_free(cursor12->data);
  1526         SDL20_free(cursor12->mask);
  1527         SDL20_free(cursor12);
  1528     }
  1529 }
  1530 
  1531 DECLSPEC SDL12_Cursor * SDLCALL
  1532 SDL_CreateCursor(Uint8 *data, Uint8 *mask, int w, int h, int hot_x, int hot_y)
  1533 {
  1534     const size_t datasize = h * (w / 8);
  1535     SDL_Cursor *cursor20 = NULL;
  1536     SDL12_Cursor *retval = NULL;
  1537 
  1538     retval = (SDL12_Cursor *) SDL20_malloc(sizeof (SDL12_Cursor));
  1539     if (!retval)
  1540         goto outofmem;
  1541 
  1542     SDL20_zerop(retval);
  1543 
  1544     retval->data = (Uint8 *) SDL20_malloc(datasize);
  1545     if (!retval->data)
  1546         goto outofmem;
  1547 
  1548     retval->mask = (Uint8 *) SDL20_malloc(datasize);
  1549     if (!retval->mask)
  1550         goto outofmem;
  1551 
  1552     cursor20 = SDL20_CreateCursor(data, mask, w, h, hot_x, hot_y);
  1553     if (!cursor20)
  1554         goto failed;
  1555 
  1556     retval->area.w = w;
  1557     retval->area.h = h;
  1558     retval->hot_x = hot_x;
  1559     retval->hot_y = hot_y;
  1560     retval->wm_cursor = cursor20;
  1561     /* we always leave retval->save as null pointers. */
  1562 
  1563     SDL20_memcpy(retval->data, data, datasize);
  1564     SDL20_memcpy(retval->mask, mask, datasize);
  1565 
  1566     return retval;
  1567 
  1568 outofmem:
  1569     SDL20_OutOfMemory();
  1570 
  1571 failed:
  1572     SDL_FreeCursor(retval);
  1573     return NULL;
  1574 }
  1575 
  1576 DECLSPEC void SDLCALL
  1577 SDL_SetCursor(SDL12_Cursor *cursor)
  1578 {
  1579     CurrentCursor12 = cursor;
  1580     SDL20_SetCursor(cursor ? cursor->wm_cursor : NULL);
  1581 }
  1582 
  1583 DECLSPEC SDL12_Cursor * SDLCALL
  1584 SDL_GetCursor(void)
  1585 {
  1586     return CurrentCursor12;
  1587 }
  1588 
  1589 static void
  1590 GetEnvironmentWindowPosition(int *x, int *y)
  1591 {
  1592     int display = VideoDisplayIndex;
  1593     const char *window = SDL20_getenv("SDL_VIDEO_WINDOW_POS");
  1594     const char *center = SDL20_getenv("SDL_VIDEO_CENTERED");
  1595     if (window) {
  1596         if (SDL20_strcmp(window, "center") == 0) {
  1597             center = window;
  1598         } else if (SDL20_sscanf(window, "%d,%d", x, y) == 2) {
  1599             return;
  1600         }
  1601     }
  1602 
  1603     if (center) {
  1604         *x = SDL_WINDOWPOS_CENTERED_DISPLAY(display);
  1605         *y = SDL_WINDOWPOS_CENTERED_DISPLAY(display);
  1606     }
  1607 }
  1608 
  1609 static void
  1610 SetupScreenSaver(const int flags12)
  1611 {
  1612     const char *env;
  1613     SDL_bool allow_screensaver;
  1614 
  1615     /* Allow environment override of screensaver disable */
  1616     env = SDL20_getenv("SDL_VIDEO_ALLOW_SCREENSAVER");
  1617     if (env) {
  1618         allow_screensaver = SDL20_atoi(env) ? SDL_TRUE : SDL_FALSE;
  1619     } else if (flags12 & SDL12_FULLSCREEN) {
  1620         allow_screensaver = SDL_FALSE;
  1621     } else {
  1622         allow_screensaver = SDL_TRUE;
  1623     }
  1624     if (allow_screensaver) {
  1625         SDL20_EnableScreenSaver();
  1626     } else {
  1627         SDL20_DisableScreenSaver();
  1628     }
  1629 }
  1630 
  1631 
  1632 static SDL12_Surface *
  1633 EndVidModeCreate(void)
  1634 {
  1635     if (VideoTexture20) {
  1636         SDL20_DestroyTexture(VideoTexture20);
  1637         VideoTexture20 = NULL;
  1638     }
  1639     if (VideoRenderer20) {
  1640         SDL20_DestroyRenderer(VideoRenderer20);
  1641         VideoRenderer20 = NULL;
  1642     }
  1643     if (VideoGLContext20) {
  1644         SDL20_GL_MakeCurrent(NULL, NULL);
  1645         SDL20_GL_DeleteContext(VideoGLContext20);
  1646         VideoGLContext20 = NULL;
  1647     }
  1648     if (VideoWindow20) {
  1649         SDL20_DestroyWindow(VideoWindow20);
  1650         VideoWindow20 = NULL;
  1651     }
  1652     if (VideoSurface12) {
  1653         SDL20_free(VideoSurface12->pixels);
  1654         VideoSurface12->pixels = NULL;
  1655         SDL_FreeSurface(VideoSurface12);
  1656         VideoSurface12 = NULL;
  1657     }
  1658     if (VideoConvertSurface20) {
  1659         SDL20_FreeSurface(VideoConvertSurface20);
  1660         VideoConvertSurface20 = NULL;
  1661     }
  1662     return NULL;
  1663 }
  1664 
  1665 
  1666 static SDL12_Surface *
  1667 CreateSurface12WithFormat(const int w, const int h, const Uint32 fmt)
  1668 {
  1669     Uint32 rmask, gmask, bmask, amask;
  1670     int bpp;
  1671     if (!SDL20_PixelFormatEnumToMasks(fmt, &bpp, &rmask, &gmask, &bmask, &amask)) {
  1672         return NULL;
  1673     }
  1674     return SDL_CreateRGBSurface(0, w, h, bpp, rmask, gmask, bmask, amask);
  1675 }
  1676 
  1677 static SDL_Surface *
  1678 CreateNullPixelSurface20(const int width, const int height, const Uint32 fmt)
  1679 {
  1680     SDL_Surface *surface20 = SDL20_CreateRGBSurfaceWithFormat(0, 0, 0, SDL_BITSPERPIXEL(fmt), fmt);
  1681     if (surface20) {
  1682         surface20->flags |= SDL_PREALLOC;
  1683         surface20->pixels = NULL;
  1684         surface20->w = width;
  1685         surface20->h = height;
  1686         surface20->pitch = 0;
  1687         SDL20_SetClipRect(surface20, NULL);
  1688     }
  1689     return surface20;
  1690 }
  1691 
  1692 
  1693 DECLSPEC SDL12_Surface * SDLCALL
  1694 SDL_SetVideoMode(int width, int height, int bpp, Uint32 flags12)
  1695 {
  1696     FIXME("currently ignores SDL_WINDOWID, which we could use with SDL_CreateWindowFrom ...?");
  1697     SDL_DisplayMode dmode;
  1698     Uint32 fullscreen_flags20 = 0;
  1699     Uint32 appfmt;
  1700 
  1701     /* SDL_SetVideoMode() implicitly inits if necessary. */
  1702     if (SDL20_WasInit(SDL_INIT_VIDEO) == 0) {
  1703         if (SDL20_Init(SDL_INIT_VIDEO) < 0) {
  1704             return NULL;
  1705         }
  1706     }
  1707 
  1708     if ((flags12 & SDL12_OPENGLBLIT) == SDL12_OPENGLBLIT) {
  1709         FIXME("No OPENGLBLIT support at the moment");
  1710         SDL20_SetError("SDL_OPENGLBLIT is (currently) unsupported");
  1711         return NULL;
  1712     }
  1713 
  1714     FIXME("handle SDL_ANYFORMAT");
  1715 
  1716     if ((width < 0) || (height < 0)) {
  1717         SDL20_SetError("Invalid width or height");
  1718         return NULL;
  1719     }
  1720 
  1721     FIXME("There's an environment variable to choose a display");
  1722     if (SDL20_GetCurrentDisplayMode(0, &dmode) < 0) {
  1723         return NULL;
  1724     }
  1725 
  1726     if (width == 0) {
  1727         width = dmode.w;
  1728     }
  1729 
  1730     if (height == 0) {
  1731         height = dmode.h;
  1732     }
  1733 
  1734     if (bpp == 0) {
  1735         bpp = SDL_BITSPERPIXEL(dmode.format);
  1736     }
  1737 
  1738     switch (bpp) {
  1739         case  8: appfmt = SDL_PIXELFORMAT_INDEX8; break;
  1740         case 16: appfmt = SDL_PIXELFORMAT_RGB565; FIXME("bgr instead of rgb?"); break;
  1741         case 24: appfmt = SDL_PIXELFORMAT_RGB24; FIXME("bgr instead of rgb?"); break;
  1742         case 32: appfmt = SDL_PIXELFORMAT_ARGB8888; FIXME("bgr instead of rgb?"); break;
  1743         default: SDL20_SetError("Unsupported bits-per-pixel"); return NULL;
  1744     }
  1745 
  1746     SDL_assert((VideoSurface12 != NULL) == (VideoWindow20 != NULL));
  1747 
  1748     FIXME("don't do anything if the window's dimensions, etc haven't changed.");
  1749     FIXME("we need to preserve VideoSurface12 (but not its pixels), I think...");
  1750 
  1751     if ( VideoSurface12 && ((VideoSurface12->flags & SDL12_OPENGL) != (flags12 & SDL12_OPENGL)) ) {
  1752         EndVidModeCreate();  /* rebuild the window if moving to/from a GL context */
  1753     } else if ( VideoSurface12 && (VideoSurface12->surface20->format->format != appfmt)) {
  1754         EndVidModeCreate();  /* rebuild the window if changing pixel format */
  1755     } else if (VideoGLContext20) {
  1756         /* SDL 1.2 (infuriatingly!) destroys the GL context on each resize, so we will too */
  1757         SDL20_GL_MakeCurrent(NULL, NULL);
  1758         SDL20_GL_DeleteContext(VideoGLContext20);
  1759         VideoGLContext20 = NULL;
  1760     }
  1761 
  1762     if (flags12 & SDL12_FULLSCREEN) {
  1763         // OpenGL tries to force the real resolution requested, but for
  1764         //  software rendering, we're just going to push it off onto the
  1765         //  GPU, so use FULLSCREEN_DESKTOP and logical scaling there.
  1766         FIXME("OpenGL will still expect letterboxing and centering if it didn't get an exact resolution match.");
  1767         if (flags12 & SDL12_OPENGL) {
  1768             fullscreen_flags20 |= SDL_WINDOW_FULLSCREEN;
  1769         } else {
  1770             fullscreen_flags20 |= SDL_WINDOW_FULLSCREEN_DESKTOP;
  1771         }
  1772     }
  1773 
  1774     if (!VideoWindow20) {  /* create it */
  1775         int x = SDL_WINDOWPOS_UNDEFINED, y = SDL_WINDOWPOS_UNDEFINED;
  1776         Uint32 flags20 = fullscreen_flags20;
  1777         if (flags12 & SDL12_OPENGL) { flags20 |= SDL_WINDOW_OPENGL; }
  1778         if (flags12 & SDL12_RESIZABLE) { flags20 |= SDL_WINDOW_RESIZABLE; }
  1779         if (flags12 & SDL12_NOFRAME) { flags20 |= SDL_WINDOW_BORDERLESS; }
  1780 
  1781         /* most platforms didn't check these environment variables, but the major
  1782            ones did (x11, windib, quartz), so we'll just offer it everywhere. */
  1783         GetEnvironmentWindowPosition(&x, &y);
  1784 
  1785         VideoWindow20 = SDL20_CreateWindow(WindowTitle, x, y, width, height, flags20);
  1786         if (!VideoWindow20) {
  1787             return EndVidModeCreate();
  1788         }
  1789     } else {  /* resize it */
  1790         SDL20_SetWindowSize(VideoWindow20, width, height);
  1791         SDL20_SetWindowFullscreen(VideoWindow20, fullscreen_flags20);
  1792         SDL20_SetWindowBordered(VideoWindow20, (flags12 & SDL12_NOFRAME) ? SDL_FALSE : SDL_TRUE);
  1793         SDL20_SetWindowResizable(VideoWindow20, (flags12 & SDL12_RESIZABLE) ? SDL_TRUE : SDL_FALSE);
  1794     }
  1795 
  1796     if (VideoSurface12) {
  1797         SDL20_free(VideoSurface12->pixels);
  1798     } else {
  1799         VideoSurface12 = CreateSurface12WithFormat(0, 0, appfmt);
  1800         if (!VideoSurface12) {
  1801             return EndVidModeCreate();
  1802         }
  1803     }
  1804 
  1805     VideoSurface12->surface20->flags |= SDL_PREALLOC;
  1806     VideoSurface12->flags |= SDL12_PREALLOC;
  1807     VideoSurface12->pixels = VideoSurface12->surface20->pixels = NULL;
  1808     VideoSurface12->w = VideoSurface12->surface20->w = width;
  1809     VideoSurface12->h = VideoSurface12->surface20->h = height;
  1810     VideoSurface12->pitch = VideoSurface12->surface20->pitch = width * SDL_BYTESPERPIXEL(appfmt);
  1811     SDL_SetClipRect(VideoSurface12, NULL);
  1812 
  1813     if (flags12 & SDL12_OPENGL) {
  1814         SDL_assert(!VideoTexture20);  /* either a new window or we destroyed all this */
  1815         SDL_assert(!VideoRenderer20);
  1816         VideoGLContext20 = SDL20_GL_CreateContext(VideoWindow20);
  1817         if (!VideoGLContext20) {
  1818             return EndVidModeCreate();
  1819         }
  1820 
  1821         VideoSurface12->flags |= SDL12_OPENGL;
  1822     } else {
  1823         /* always use a renderer for non-OpenGL windows. */
  1824         SDL_RendererInfo rinfo;
  1825         SDL_assert(!VideoGLContext20);  /* either a new window or we destroyed all this */
  1826         if (!VideoRenderer20) {
  1827             VideoRenderer20 = SDL20_CreateRenderer(VideoWindow20, -1, 0);
  1828             if (!VideoRenderer20) {
  1829                 return EndVidModeCreate();
  1830             }
  1831         }
  1832 
  1833         SDL20_RenderSetLogicalSize(VideoRenderer20, width, height);
  1834         SDL20_SetRenderDrawColor(VideoRenderer20, 0, 0, 0, 255);
  1835         SDL20_RenderClear(VideoRenderer20);
  1836         SDL20_RenderPresent(VideoRenderer20);
  1837         SDL20_SetRenderDrawColor(VideoRenderer20, 255, 255, 255, 255);
  1838 
  1839         if (SDL20_GetRendererInfo(VideoRenderer20, &rinfo) < 0) {
  1840             return EndVidModeCreate();
  1841         }
  1842 
  1843         if (VideoTexture20) {
  1844             SDL20_DestroyTexture(VideoTexture20);
  1845         }
  1846 
  1847         if (VideoConvertSurface20) {
  1848             SDL20_FreeSurface(VideoConvertSurface20);
  1849             VideoConvertSurface20 = NULL;
  1850         }
  1851 
  1852         VideoTexture20 = SDL20_CreateTexture(VideoRenderer20, rinfo.texture_formats[0], SDL_TEXTUREACCESS_STREAMING, width, height);
  1853         if (!VideoTexture20) {
  1854             return EndVidModeCreate();
  1855         }
  1856 
  1857         if (rinfo.texture_formats[0] != appfmt) {
  1858             /* need to convert between app's format and texture format */
  1859             VideoConvertSurface20 = CreateNullPixelSurface20(width, height, rinfo.texture_formats[0]);
  1860             if (!VideoConvertSurface20) {
  1861                 return EndVidModeCreate();
  1862             }
  1863         }
  1864 
  1865         VideoSurface12->flags &= ~SDL12_OPENGL;
  1866         VideoSurface12->surface20->pixels = SDL20_malloc(height * VideoSurface12->pitch);
  1867         VideoSurface12->pixels = VideoSurface12->surface20->pixels;
  1868         if (!VideoSurface12->pixels) {
  1869             SDL20_OutOfMemory();
  1870             return EndVidModeCreate();
  1871         }
  1872     }
  1873 
  1874     FIXME("setup screen saver");
  1875 
  1876     return VideoSurface12;
  1877 }
  1878 
  1879 DECLSPEC SDL12_Surface * SDLCALL
  1880 SDL_GetVideoSurface(void)
  1881 {
  1882     return VideoSurface12;
  1883 }
  1884 
  1885 DECLSPEC int SDLCALL
  1886 SDL_SetAlpha(SDL12_Surface * surface, Uint32 flag, Uint8 value)
  1887 {
  1888     FIXME("write me");
  1889     return SDL20_Unsupported();
  1890 }
  1891 
  1892 DECLSPEC SDL12_Surface * SDLCALL
  1893 SDL_DisplayFormat(SDL12_Surface *surface12)
  1894 {
  1895     FIXME("write me");
  1896     SDL20_Unsupported();
  1897     return NULL;
  1898 }
  1899 
  1900 DECLSPEC SDL12_Surface * SDLCALL
  1901 SDL_DisplayFormatAlpha(SDL12_Surface *surface)
  1902 {
  1903     FIXME("write me");
  1904     SDL20_Unsupported();
  1905     return NULL;
  1906 }
  1907 
  1908 DECLSPEC void SDLCALL
  1909 SDL_UpdateRects(SDL12_Surface * screen12, int numrects, SDL_Rect * rects)
  1910 {
  1911     FIXME("write me");
  1912     SDL20_Unsupported();
  1913 }
  1914 
  1915 DECLSPEC void SDLCALL
  1916 SDL_UpdateRect(SDL12_Surface *screen12, Sint32 x, Sint32 y, Uint32 w, Uint32 h)
  1917 {
  1918     if (screen12) {
  1919         SDL_Rect rect;
  1920         rect.x = (int) x;
  1921         rect.y = (int) y;
  1922         rect.w = (int) (w ? w : screen12->w);
  1923         rect.h = (int) (h ? h : screen12->h);
  1924         SDL_UpdateRects(screen12, 1, &rect);
  1925     }
  1926 }
  1927 
  1928 DECLSPEC int SDLCALL
  1929 SDL_Flip(SDL12_Surface *screen12)
  1930 {
  1931     SDL_UpdateRect(screen12, 0, 0, 0, 0);
  1932     return 0;
  1933 }
  1934 
  1935 DECLSPEC void SDLCALL
  1936 SDL_WM_SetCaption(const char *title, const char *icon)
  1937 {
  1938     if (WindowTitle) {
  1939         SDL20_free(WindowTitle);
  1940     }
  1941     if (WindowIconTitle) {
  1942         SDL20_free(WindowIconTitle);
  1943     }
  1944     WindowTitle = title ? SDL_strdup(title) : NULL;
  1945     WindowIconTitle = icon ? SDL_strdup(icon) : NULL;
  1946     if (VideoWindow20) {
  1947         SDL20_SetWindowTitle(VideoWindow20, WindowTitle);
  1948     }
  1949 }
  1950 
  1951 DECLSPEC void SDLCALL
  1952 SDL_WM_GetCaption(const char **title, const char **icon)
  1953 {
  1954     if (title) {
  1955         *title = WindowTitle;
  1956     }
  1957     if (icon) {
  1958         *icon = WindowIconTitle;
  1959     }
  1960 }
  1961 
  1962 DECLSPEC void SDLCALL
  1963 SDL_WM_SetIcon(SDL_Surface *icon, Uint8 *mask)
  1964 {
  1965     FIXME("write me");
  1966     SDL20_Unsupported();
  1967 }
  1968 
  1969 DECLSPEC int SDLCALL
  1970 SDL_WM_IconifyWindow(void)
  1971 {
  1972     SDL20_MinimizeWindow(VideoWindow20);
  1973     return 0;
  1974 }
  1975 
  1976 DECLSPEC int SDLCALL
  1977 SDL_WM_ToggleFullScreen(SDL12_Surface *surface)
  1978 {
  1979     FIXME("write me");
  1980     return SDL20_Unsupported();
  1981 }
  1982 
  1983 typedef enum
  1984 {
  1985     SDL12_GRAB_QUERY = -1,
  1986     SDL12_GRAB_OFF = 0,
  1987     SDL12_GRAB_ON = 1
  1988 } SDL12_GrabMode;
  1989 
  1990 DECLSPEC SDL12_GrabMode SDLCALL
  1991 SDL_WM_GrabInput(SDL12_GrabMode mode)
  1992 {
  1993     if (mode != SDL12_GRAB_QUERY) {
  1994         SDL20_SetWindowGrab(VideoWindow20, (mode == SDL12_GRAB_ON));
  1995     }
  1996     return SDL20_GetWindowGrab(VideoWindow20) ? SDL12_GRAB_ON : SDL12_GRAB_OFF;
  1997 }
  1998 
  1999 DECLSPEC void SDLCALL
  2000 SDL_WarpMouse(Uint16 x, Uint16 y)
  2001 {
  2002     SDL20_WarpMouseInWindow(VideoWindow20, x, y);
  2003 }
  2004 
  2005 DECLSPEC Uint8 SDLCALL
  2006 SDL_GetAppState(void)
  2007 {
  2008     Uint8 state12 = 0;
  2009     Uint32 flags20 = 0;
  2010 
  2011     flags20 = SDL20_GetWindowFlags(VideoWindow20);
  2012     if ((flags20 & SDL_WINDOW_SHOWN) && !(flags20 & SDL_WINDOW_MINIMIZED)) {
  2013         state12 |= SDL12_APPACTIVE;
  2014     }
  2015     if (flags20 & SDL_WINDOW_INPUT_FOCUS) {
  2016         state12 |= SDL12_APPINPUTFOCUS;
  2017     }
  2018     if (flags20 & SDL_WINDOW_MOUSE_FOCUS) {
  2019         state12 |= SDL12_APPMOUSEFOCUS;
  2020     }
  2021     return state12;
  2022 }
  2023 
  2024 DECLSPEC int SDLCALL
  2025 SDL_SetPalette(SDL12_Surface *surface12, int flags, const SDL_Color *colors,
  2026                int firstcolor, int ncolors)
  2027 {
  2028     FIXME("write me");
  2029     return SDL20_Unsupported();
  2030 }
  2031 
  2032 DECLSPEC int SDLCALL
  2033 SDL_SetColors(SDL12_Surface *surface12, const SDL_Color * colors, int firstcolor,
  2034               int ncolors)
  2035 {
  2036     FIXME("write me");
  2037     return SDL20_Unsupported();
  2038 }
  2039 
  2040 DECLSPEC int SDLCALL
  2041 SDL_GetWMInfo(SDL_SysWMinfo * info)
  2042 {
  2043     FIXME("write me");
  2044     //return SDL20_GetWindowWMInfo(VideoWindow20, info);
  2045     return SDL20_Unsupported();
  2046 }
  2047 
  2048 DECLSPEC SDL12_Overlay * SDLCALL
  2049 SDL_CreateYUVOverlay(int w, int h, Uint32 format, SDL12_Surface *display)
  2050 {
  2051     FIXME("write me");
  2052     SDL20_Unsupported();
  2053     return NULL;
  2054 }
  2055 
  2056 DECLSPEC int SDLCALL
  2057 SDL_LockYUVOverlay(SDL12_Overlay * overlay)
  2058 {
  2059     FIXME("write me");
  2060     return SDL20_Unsupported();
  2061 }
  2062 
  2063 DECLSPEC void SDLCALL
  2064 SDL_UnlockYUVOverlay(SDL12_Overlay * overlay)
  2065 {
  2066     FIXME("write me");
  2067 }
  2068 
  2069 DECLSPEC int SDLCALL
  2070 SDL_DisplayYUVOverlay(SDL12_Overlay * overlay, SDL_Rect * dstrect)
  2071 {
  2072     FIXME("write me");
  2073     return SDL20_Unsupported();
  2074 }
  2075 
  2076 DECLSPEC void SDLCALL
  2077 SDL_FreeYUVOverlay(SDL12_Overlay * overlay)
  2078 {
  2079     FIXME("write me");
  2080 }
  2081 
  2082 DECLSPEC int SDLCALL
  2083 SDL_GL_SetAttribute(SDL12_GLattr attr, int value)
  2084 {
  2085     if (attr >= SDL12_GL_MAX_ATTRIBUTE)
  2086         return SDL20_SetError("Unknown GL attribute");
  2087 
  2088     /* swap control was moved out of this API, everything else lines up. */
  2089     if (attr == SDL12_GL_SWAP_CONTROL)
  2090     {
  2091         SwapInterval = value;
  2092         FIXME("Actually set swap interval somewhere");
  2093         return 0;
  2094     }
  2095 
  2096     return SDL20_GL_SetAttribute((SDL_GLattr) attr, value);
  2097 }
  2098 
  2099 DECLSPEC int SDLCALL
  2100 SDL_GL_GetAttribute(SDL12_GLattr attr, int* value)
  2101 {
  2102     if (attr >= SDL12_GL_MAX_ATTRIBUTE)
  2103         return SDL20_SetError("Unknown GL attribute");
  2104 
  2105     /* swap control was moved out of this API, everything else lines up. */
  2106     if (attr == SDL12_GL_SWAP_CONTROL)
  2107     {
  2108         *value = SDL20_GL_GetSwapInterval();
  2109         return 0;
  2110     }
  2111 
  2112     return SDL20_GL_GetAttribute((SDL_GLattr) attr, value);
  2113 }
  2114 
  2115 
  2116 DECLSPEC void SDLCALL
  2117 SDL_GL_SwapBuffers(void)
  2118 {
  2119     if (VideoWindow20)
  2120         SDL20_GL_SwapWindow(VideoWindow20);
  2121 }
  2122 
  2123 DECLSPEC int SDLCALL
  2124 SDL_SetGamma(float red, float green, float blue)
  2125 {
  2126     Uint16 red_ramp[256];
  2127     Uint16 green_ramp[256];
  2128     Uint16 blue_ramp[256];
  2129 
  2130     SDL20_CalculateGammaRamp(red, red_ramp);
  2131     if (green == red) {
  2132         SDL20_memcpy(green_ramp, red_ramp, sizeof(red_ramp));
  2133     } else {
  2134         SDL20_CalculateGammaRamp(green, green_ramp);
  2135     }
  2136     if (blue == red) {
  2137         SDL20_memcpy(blue_ramp, red_ramp, sizeof(red_ramp));
  2138     } else if (blue == green) {
  2139         SDL20_memcpy(blue_ramp, green_ramp, sizeof(green_ramp));
  2140     } else {
  2141         SDL20_CalculateGammaRamp(blue, blue_ramp);
  2142     }
  2143     return SDL20_SetWindowGammaRamp(VideoWindow20, red_ramp, green_ramp, blue_ramp);
  2144 }
  2145 
  2146 DECLSPEC int SDLCALL
  2147 SDL_SetGammaRamp(const Uint16 *red, const Uint16 *green, const Uint16 *blue)
  2148 {
  2149     return SDL20_SetWindowGammaRamp(VideoWindow20, red, green, blue);
  2150 }
  2151 
  2152 DECLSPEC int SDLCALL
  2153 SDL_GetGammaRamp(Uint16 *red, Uint16 *green, Uint16 *blue)
  2154 {
  2155     return SDL20_GetWindowGammaRamp(VideoWindow20, red, green, blue);
  2156 }
  2157 
  2158 DECLSPEC int SDLCALL
  2159 SDL_EnableKeyRepeat(int delay, int interval)
  2160 {
  2161     return 0;
  2162 }
  2163 
  2164 DECLSPEC void SDLCALL
  2165 SDL_GetKeyRepeat(int *delay, int *interval)
  2166 {
  2167     if (delay) {
  2168         *delay = SDL12_DEFAULT_REPEAT_DELAY;
  2169     }
  2170     if (interval) {
  2171         *interval = SDL12_DEFAULT_REPEAT_INTERVAL;
  2172     }
  2173 }
  2174 
  2175 DECLSPEC int SDLCALL
  2176 SDL_EnableUNICODE(int enable)
  2177 {
  2178     FIXME("write me");
  2179     return SDL20_Unsupported();
  2180 }
  2181 
  2182 static Uint32
  2183 SetTimerOld_Callback(Uint32 interval, void* param)
  2184 {
  2185     return ((SDL12_TimerCallback)param)(interval);
  2186 }
  2187 
  2188 DECLSPEC int SDLCALL
  2189 SDL_SetTimer(Uint32 interval, SDL12_TimerCallback callback)
  2190 {
  2191     static SDL_TimerID compat_timer;
  2192 
  2193     if (compat_timer) {
  2194         SDL20_RemoveTimer(compat_timer);
  2195         compat_timer = 0;
  2196     }
  2197 
  2198     if (interval && callback) {
  2199         compat_timer = SDL20_AddTimer(interval, SetTimerOld_Callback, callback);
  2200         if (!compat_timer) {
  2201             return -1;
  2202         }
  2203     }
  2204     return 0;
  2205 }
  2206 
  2207 DECLSPEC int SDLCALL
  2208 SDL_putenv(const char *_var)
  2209 {
  2210     char *ptr = NULL;
  2211     char *var = SDL20_strdup(_var);
  2212     if (var == NULL) {
  2213         return -1;  /* we don't set errno. */
  2214     }
  2215 
  2216     ptr = SDL20_strchr(var, '=');
  2217     if (ptr == NULL) {
  2218         SDL20_free(var);
  2219         return -1;
  2220     }
  2221 
  2222     *ptr = '\0';  /* split the string into name and value. */
  2223     SDL20_setenv(var, ptr + 1, 1);
  2224     SDL20_free(var);
  2225     return 0;
  2226 }
  2227 
  2228 
  2229 
  2230 /* CD-ROM support is gone from SDL 2.0, so just have stubs that fail. */
  2231 
  2232 typedef void *SDL12_CD;  /* close enough.  :) */
  2233 typedef int SDL12_CDstatus;  /* close enough.  :) */
  2234 
  2235 DECLSPEC int SDLCALL
  2236 SDL_CDNumDrives(void)
  2237 {
  2238     FIXME("should return -1 without SDL_INIT_CDROM");
  2239     return 0;
  2240 }
  2241 
  2242 DECLSPEC const char *SDLCALL SDL_CDName(int drive) { SDL20_Unsupported(); return NULL; }
  2243 DECLSPEC SDL12_CD *SDLCALL SDL_CDOpen(int drive) { SDL20_Unsupported(); return NULL; }
  2244 DECLSPEC SDL12_CDstatus SDLCALL SDL_CDStatus(SDL12_CD *cdrom) { return SDL20_Unsupported(); }
  2245 DECLSPEC int SDLCALL SDL_CDPlayTracks(SDL12_CD *cdrom, int start_track, int start_frame, int ntracks, int nframes) { return SDL20_Unsupported(); }
  2246 DECLSPEC int SDLCALL SDL_CDPlay(SDL12_CD *cdrom, int start, int length) { return SDL20_Unsupported(); }
  2247 DECLSPEC int SDLCALL SDL_CDPause(SDL12_CD *cdrom) { return SDL20_Unsupported(); }
  2248 DECLSPEC int SDLCALL SDL_CDResume(SDL12_CD *cdrom) { return SDL20_Unsupported(); }
  2249 DECLSPEC int SDLCALL SDL_CDStop(SDL12_CD *cdrom) { return SDL20_Unsupported(); }
  2250 DECLSPEC int SDLCALL SDL_CDEject(SDL12_CD *cdrom) { return SDL20_Unsupported(); }
  2251 DECLSPEC void SDLCALL SDL_CDClose(SDL12_CD *cdrom) {}
  2252 
  2253 
  2254 #ifdef SDL_PASSED_BEGINTHREAD_ENDTHREAD
  2255 DECLSPEC SDL_Thread * SDLCALL
  2256 SDL_CreateThread(int (SDLCALL *fn)(void *), void *data, pfnSDL_CurrentBeginThread pfnBeginThread, pfnSDL_CurrentEndThread pfnEndThread)
  2257 {
  2258     return SDL20_CreateThread(fn, NULL, data, pfnBeginThread, pfnEndThread);
  2259 }
  2260 #else
  2261 DECLSPEC SDL_Thread * SDLCALL
  2262 SDL_CreateThread(int (SDLCALL *fn)(void *), void *data)
  2263 {
  2264     return SDL20_CreateThread(fn, NULL, data);
  2265 }
  2266 #endif
  2267 
  2268 DECLSPEC int SDLCALL
  2269 SDL_mutexP(SDL_mutex *mutex)
  2270 {
  2271     return SDL20_LockMutex(mutex);
  2272 }
  2273 
  2274 DECLSPEC int SDLCALL
  2275 SDL_mutexV(SDL_mutex *mutex)
  2276 {
  2277     return SDL20_UnlockMutex(mutex);
  2278 }
  2279 
  2280 DECLSPEC void SDLCALL SDL_KillThread(SDL_Thread *thread)
  2281 {
  2282     FIXME("Removed from 2.0; do nothing. We can't even report failure.");
  2283     fprintf(stderr,
  2284         "WARNING: this app used SDL_KillThread(), an unforgivable curse.\n"
  2285         "This program should be fixed. No thread was actually harmed.\n");
  2286 }
  2287 
  2288 /* This changed from an opaque pointer to an int in 2.0. */
  2289 typedef struct _SDL12_TimerID *SDL12_TimerID;
  2290 SDL_COMPILE_TIME_ASSERT(timer, sizeof(SDL12_TimerID) >= sizeof(SDL_TimerID));
  2291 
  2292 
  2293 DECLSPEC SDL12_TimerID SDLCALL
  2294 SDL_AddTimer(Uint32 interval, SDL12_NewTimerCallback callback, void *param)
  2295 {
  2296     return (SDL12_TimerID) ((size_t) SDL20_AddTimer(interval, callback, param));
  2297 }
  2298 
  2299 DECLSPEC SDL_bool SDLCALL
  2300 SDL_RemoveTimer(SDL12_TimerID id)
  2301 {
  2302     return SDL20_RemoveTimer((SDL_TimerID) ((size_t)id));
  2303 }
  2304 
  2305 
  2306 typedef struct SDL12_RWops {
  2307     int (SDLCALL *seek)(struct SDL12_RWops *context, int offset, int whence);
  2308     int (SDLCALL *read)(struct SDL12_RWops *context, void *ptr, int size, int maxnum);
  2309     int (SDLCALL *write)(struct SDL12_RWops *context, const void *ptr, int size, int num);
  2310     int (SDLCALL *close)(struct SDL12_RWops *context);
  2311     Uint32 type;
  2312     void *padding[8];
  2313     SDL_RWops *rwops20;
  2314 } SDL12_RWops;
  2315 
  2316 
  2317 DECLSPEC SDL12_RWops * SDLCALL
  2318 SDL_AllocRW(void)
  2319 {
  2320     SDL12_RWops *rwops = (SDL12_RWops *) SDL20_malloc(sizeof (SDL12_RWops));
  2321     if (!rwops)
  2322         SDL20_OutOfMemory();
  2323     return rwops;
  2324 }
  2325 
  2326 DECLSPEC void SDLCALL
  2327 SDL_FreeRW(SDL12_RWops *rwops12)
  2328 {
  2329     SDL20_free(rwops12);
  2330 }
  2331 
  2332 static int SDLCALL
  2333 RWops20to12_seek(struct SDL12_RWops *rwops12, int offset, int whence)
  2334 {
  2335     return rwops12->rwops20->seek(rwops12->rwops20, offset, whence);
  2336 }
  2337 
  2338 static int SDLCALL
  2339 RWops20to12_read(struct SDL12_RWops *rwops12, void *ptr, int size, int maxnum)
  2340 {
  2341     return rwops12->rwops20->read(rwops12->rwops20, ptr, size, maxnum);
  2342 }
  2343 
  2344 static int SDLCALL
  2345 RWops20to12_write(struct SDL12_RWops *rwops12, const void *ptr, int size, int num)
  2346 {
  2347     return rwops12->rwops20->write(rwops12->rwops20, ptr, size, num);
  2348 }
  2349 
  2350 static int SDLCALL
  2351 RWops20to12_close(struct SDL12_RWops *rwops12)
  2352 {
  2353     int rc = 0;
  2354     if (rwops12)
  2355     {
  2356         rc = rwops12->rwops20->close(rwops12->rwops20);
  2357         if (rc == 0)
  2358             SDL_FreeRW(rwops12);
  2359     }
  2360     return rc;
  2361 }
  2362 
  2363 static SDL12_RWops *
  2364 RWops20to12(SDL_RWops *rwops20)
  2365 {
  2366     SDL12_RWops *rwops12;
  2367 
  2368     if (!rwops20)
  2369         return NULL;
  2370 
  2371     rwops12 = SDL_AllocRW();
  2372     if (!rwops12)
  2373         return NULL;
  2374 
  2375     SDL20_zerop(rwops12);
  2376     rwops12->type = rwops20->type;
  2377     rwops12->rwops20 = rwops20;
  2378     rwops12->seek = RWops20to12_seek;
  2379     rwops12->read = RWops20to12_read;
  2380     rwops12->write = RWops20to12_write;
  2381     rwops12->close = RWops20to12_close;
  2382 
  2383     return rwops12;
  2384 }
  2385 
  2386 DECLSPEC SDL12_RWops * SDLCALL
  2387 SDL_RWFromFile(const char *file, const char *mode)
  2388 {
  2389     return RWops20to12(SDL20_RWFromFile(file, mode));
  2390 }
  2391 
  2392 DECLSPEC SDL12_RWops * SDLCALL
  2393 SDL_RWFromFP(FILE *io, int autoclose)
  2394 {
  2395     return RWops20to12(SDL20_RWFromFP(io, autoclose));
  2396 }
  2397 
  2398 DECLSPEC SDL12_RWops * SDLCALL
  2399 SDL_RWFromMem(void *mem, int size)
  2400 {
  2401     return RWops20to12(SDL20_RWFromMem(mem, size));
  2402 }
  2403 
  2404 DECLSPEC SDL12_RWops * SDLCALL
  2405 SDL_RWFromConstMem(const void *mem, int size)
  2406 {
  2407     return RWops20to12(SDL20_RWFromConstMem(mem, size));
  2408 }
  2409 
  2410 #define READ_AND_BYTESWAP(endian, bits) \
  2411     DECLSPEC Uint##bits SDLCALL SDL_Read##endian##bits(SDL12_RWops *rwops12) { \
  2412         Uint##bits val; rwops12->read(rwops12, &val, sizeof (val), 1); \
  2413         return SDL_Swap##endian##bits(val); \
  2414     }
  2415 
  2416 READ_AND_BYTESWAP(LE,16)
  2417 READ_AND_BYTESWAP(BE,16)
  2418 READ_AND_BYTESWAP(LE,32)
  2419 READ_AND_BYTESWAP(BE,32)
  2420 READ_AND_BYTESWAP(LE,64)
  2421 READ_AND_BYTESWAP(BE,64)
  2422 #undef READ_AND_BYTESWAP
  2423 
  2424 #define BYTESWAP_AND_WRITE(endian, bits) \
  2425     DECLSPEC int SDLCALL SDL_Write##endian##bits(SDL12_RWops *rwops12, Uint##bits val) { \
  2426         val = SDL_Swap##endian##bits(val); \
  2427         return rwops12->write(rwops12, &val, sizeof (val), 1); \
  2428     }
  2429 BYTESWAP_AND_WRITE(LE,16)
  2430 BYTESWAP_AND_WRITE(BE,16)
  2431 BYTESWAP_AND_WRITE(LE,32)
  2432 BYTESWAP_AND_WRITE(BE,32)
  2433 BYTESWAP_AND_WRITE(LE,64)
  2434 BYTESWAP_AND_WRITE(BE,64)
  2435 #undef BYTESWAP_AND_WRITE
  2436 
  2437 
  2438 static Sint64 SDLCALL
  2439 RWops12to20_size(struct SDL_RWops *rwops20)
  2440 {
  2441     SDL12_RWops *rwops12 = (SDL12_RWops *) rwops20->hidden.unknown.data1;
  2442     int size = rwops20->hidden.unknown.data2;
  2443     int pos;
  2444 
  2445     if (size != -1)
  2446         return size;
  2447 
  2448     pos = rwops12->seek(rwops12, 0, SEEK_CUR);
  2449     if (pos == -1)
  2450         return -1;
  2451 
  2452     size = (Sint64) rwops12->seek(rwops12, 0, SEEK_END);
  2453     if (size == -1)
  2454         return -1;
  2455 
  2456     rwops12->seek(rwops12, pos, SEEK_SET);  /* !!! FIXME: and if this fails? */
  2457     rwops20->hidden.unknown.data2 = size;
  2458     return size;
  2459 }
  2460 
  2461 static Sint64 SDLCALL
  2462 RWops12to20_seek(struct SDL_RWops *rwops20, Sint64 offset, int whence)
  2463 {
  2464     FIXME("fail if (offset) is too big");
  2465     SDL12_RWops *rwops12 = (SDL12_RWops *) rwops20->hidden.unknown.data1;
  2466     return (Sint64) rwops12->seek(rwops12, (int) offset, whence);
  2467 }
  2468 
  2469 static size_t SDLCALL
  2470 RWops12to20_read(struct SDL_RWops *rwops20, void *ptr, size_t size, size_t maxnum)
  2471 {
  2472     FIXME("fail if (size) or (maxnum) is too big");
  2473     SDL12_RWops *rwops12 = (SDL12_RWops *) rwops20->hidden.unknown.data1;
  2474     return (size_t) rwops12->read(rwops12, ptr, (int) size, (int) maxnum);
  2475 }
  2476 
  2477 static size_t SDLCALL
  2478 RWops12to20_write(struct SDL_RWops *rwops20, const void *ptr, size_t size, size_t num)
  2479 {
  2480     FIXME("fail if (size) or (maxnum) is too big");
  2481     SDL12_RWops *rwops12 = (SDL12_RWops *) rwops20->hidden.unknown.data1;
  2482     return (size_t) rwops12->write(rwops12, ptr, (int) size, (int) num);
  2483 }
  2484 
  2485 static int SDLCALL
  2486 RWops12to20_close(struct SDL_RWops *rwops20)
  2487 {
  2488     int rc = 0;
  2489     if (rwops20)
  2490     {
  2491         SDL12_RWops *rwops12 = (SDL12_RWops *) rwops20->hidden.unknown.data1;
  2492         rc = rwops12->close(rwops12);
  2493         if (rc == 0)
  2494             SDL20_FreeRW(rwops20);
  2495     }
  2496     return rc;
  2497 }
  2498 
  2499 static SDL_RWops *
  2500 RWops12to20(SDL12_RWops *rwops12)
  2501 {
  2502     SDL_RWops *rwops20;
  2503 
  2504     if (!rwops12)
  2505         return NULL;
  2506 
  2507     rwops20 = SDL20_AllocRW();
  2508     if (!rwops20)
  2509         return NULL;
  2510 
  2511     SDL20_zerop(rwops20);
  2512     rwops20->type = rwops12->type;
  2513     rwops20->hidden.unknown.data1 = rwops12;
  2514     rwops20->hidden.unknown.data2 = -1;  /* cached size of stream */
  2515     rwops20->size = RWops12to20_size;
  2516     rwops20->seek = RWops12to20_seek;
  2517     rwops20->read = RWops12to20_read;
  2518     rwops20->write = RWops12to20_write;
  2519     rwops20->close = RWops12to20_close;
  2520     return rwops20;
  2521 }
  2522 
  2523 DECLSPEC SDL12_Surface * SDLCALL
  2524 SDL_LoadBMP_RW(SDL12_RWops *rwops12, int freerwops12)
  2525 {
  2526     SDL_RWops *rwops20 = RWops12to20(rwops12);
  2527     SDL_Surface *surface20 = SDL20_LoadBMP_RW(rwops20, freerwops12);
  2528     SDL12_Surface *surface12 = Surface20to12(surface20);
  2529     if (!freerwops12)  /* free our wrapper if SDL2 didn't close it. */
  2530         SDL20_FreeRW(rwops20);
  2531     if ((!surface12) && (surface20))
  2532         SDL20_FreeSurface(surface20);
  2533     return surface12;
  2534 }
  2535 
  2536 DECLSPEC int SDLCALL
  2537 SDL_SaveBMP_RW(SDL12_Surface *surface12, SDL12_RWops *rwops12, int freerwops12)
  2538 {
  2539     FIXME("wrap surface");
  2540     SDL_RWops *rwops20 = RWops12to20(rwops12);
  2541     const int retval = SDL20_SaveBMP_RW(surface12->surface20, rwops20, freerwops12);
  2542     if (!freerwops12)  /* free our wrapper if SDL2 didn't close it. */
  2543         SDL20_FreeRW(rwops20);
  2544     return retval;
  2545 }
  2546 
  2547 DECLSPEC SDL_AudioSpec * SDLCALL
  2548 SDL_LoadWAV_RW(SDL12_RWops *rwops12, int freerwops12,
  2549                SDL_AudioSpec *spec, Uint8 **buf, Uint32 *len)
  2550 {
  2551     SDL_RWops *rwops20 = RWops12to20(rwops12);
  2552     SDL_AudioSpec *retval = SDL20_LoadWAV_RW(rwops20, freerwops12, spec, buf, len);
  2553     FIXME("deal with non-1.2 formats, like float32");
  2554     if (!freerwops12)  /* free our wrapper if SDL2 didn't close it. */
  2555         SDL20_FreeRW(rwops20);
  2556     return retval;
  2557 }
  2558 
  2559 /* vi: set ts=4 sw=4 expandtab: */