src/SDL_compat.c
author Sam Lantinga <slouken@libsdl.org>
Wed, 12 Jul 2006 06:39:26 +0000
changeset 1897 c2a27da60b18
parent 1895 c121d94672cb
child 1907 06c27a737b7a
permissions -rw-r--r--
Solved the performance problems by introducing the concept of a single-buffered
display, which is a fast path used for the whole-surface SDL 1.2 API.
Solved the flicker problems by implementing a backbuffer in the GDI renderer.

Unfortunately, now using the GDI renderer with a backbuffer and HBITMAPs is
significantly slower than SDL's surface code. *sigh*
     1 /*
     2     SDL - Simple DirectMedia Layer
     3     Copyright (C) 1997-2006 Sam Lantinga
     4 
     5     This library is free software; you can redistribute it and/or
     6     modify it under the terms of the GNU Lesser General Public
     7     License as published by the Free Software Foundation; either
     8     version 2.1 of the License, or (at your option) any later version.
     9 
    10     This library is distributed in the hope that it will be useful,
    11     but WITHOUT ANY WARRANTY; without even the implied warranty of
    12     MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
    13     Lesser General Public License for more details.
    14 
    15     You should have received a copy of the GNU Lesser General Public
    16     License along with this library; if not, write to the Free Software
    17     Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
    18 
    19     Sam Lantinga
    20     slouken@libsdl.org
    21 */
    22 #include "SDL_config.h"
    23 
    24 /* This file contains functions for backwards compatibility with SDL 1.2 */
    25 
    26 #include "SDL.h"
    27 #include "SDL_syswm.h"
    28 
    29 #include "video/SDL_sysvideo.h"
    30 #include "video/SDL_pixels_c.h"
    31 
    32 
    33 static SDL_WindowID SDL_VideoWindow;
    34 static SDL_TextureID SDL_VideoTexture;
    35 static SDL_Surface *SDL_VideoSurface;
    36 static SDL_Surface *SDL_ShadowSurface;
    37 static SDL_Surface *SDL_PublicSurface;
    38 static char *wm_title;
    39 
    40 char *
    41 SDL_AudioDriverName(char *namebuf, int maxlen)
    42 {
    43     const char *name = SDL_GetCurrentAudioDriver();
    44     if (name) {
    45         SDL_strlcpy(namebuf, name, maxlen);
    46         return namebuf;
    47     }
    48     return NULL;
    49 }
    50 
    51 char *
    52 SDL_VideoDriverName(char *namebuf, int maxlen)
    53 {
    54     const char *name = SDL_GetCurrentVideoDriver();
    55     if (name) {
    56         SDL_strlcpy(namebuf, name, maxlen);
    57         return namebuf;
    58     }
    59     return NULL;
    60 }
    61 
    62 const SDL_VideoInfo *
    63 SDL_GetVideoInfo(void)
    64 {
    65     static SDL_VideoInfo info;
    66 
    67     /* Memory leak, compatibility code, who cares? */
    68     if (!info.vfmt && SDL_GetDesktopDisplayMode()) {
    69         int bpp;
    70         Uint32 Rmask, Gmask, Bmask, Amask;
    71 
    72         SDL_PixelFormatEnumToMasks(SDL_GetDesktopDisplayMode()->format, &bpp,
    73                                    &Rmask, &Gmask, &Bmask, &Amask);
    74         info.vfmt = SDL_AllocFormat(bpp, Rmask, Gmask, Bmask, Amask);
    75     }
    76     return &info;
    77 }
    78 
    79 int
    80 SDL_VideoModeOK(int width, int height, int bpp, Uint32 flags)
    81 {
    82     int i, actual_bpp = 0;
    83 
    84     if (!SDL_GetVideoDevice()) {
    85         return 0;
    86     }
    87 
    88     if (!(flags & SDL_FULLSCREEN)) {
    89         return SDL_BITSPERPIXEL(SDL_GetDesktopDisplayMode()->format);
    90     }
    91 
    92     for (i = 0; i < SDL_GetNumDisplayModes(); ++i) {
    93         const SDL_DisplayMode *mode = SDL_GetDisplayMode(i);
    94         if (!mode->w || !mode->h || (width == mode->w && height == mode->h)) {
    95             if (!mode->format) {
    96                 return bpp;
    97             }
    98             if (SDL_BITSPERPIXEL(mode->format) >= (Uint32) bpp) {
    99                 actual_bpp = SDL_BITSPERPIXEL(mode->format);
   100             }
   101         }
   102     }
   103     return actual_bpp;
   104 }
   105 
   106 SDL_Rect **
   107 SDL_ListModes(SDL_PixelFormat * format, Uint32 flags)
   108 {
   109     int i, nmodes;
   110     SDL_Rect **modes;
   111 
   112     if (!SDL_GetVideoDevice()) {
   113         return NULL;
   114     }
   115 
   116     if (!(flags & SDL_FULLSCREEN)) {
   117         return (SDL_Rect **) (-1);
   118     }
   119 
   120     /* Memory leak, but this is a compatibility function, who cares? */
   121     nmodes = 0;
   122     modes = NULL;
   123     for (i = 0; i < SDL_GetNumDisplayModes(); ++i) {
   124         const SDL_DisplayMode *mode = SDL_GetDisplayMode(i);
   125         if (!mode->w || !mode->h) {
   126             return (SDL_Rect **) (-1);
   127         }
   128         if (SDL_BITSPERPIXEL(mode->format) != format->BitsPerPixel) {
   129             continue;
   130         }
   131         if (nmodes > 0 && modes[nmodes - 1]->w == mode->w
   132             && modes[nmodes - 1]->h == mode->h) {
   133             continue;
   134         }
   135 
   136         modes = SDL_realloc(modes, (nmodes + 2) * sizeof(*modes));
   137         if (!modes) {
   138             return NULL;
   139         }
   140         modes[nmodes] = (SDL_Rect *) SDL_malloc(sizeof(SDL_Rect));
   141         if (!modes[nmodes]) {
   142             return NULL;
   143         }
   144         modes[nmodes]->x = 0;
   145         modes[nmodes]->y = 0;
   146         modes[nmodes]->w = mode->w;
   147         modes[nmodes]->h = mode->h;
   148         ++nmodes;
   149     }
   150     if (modes) {
   151         modes[nmodes] = NULL;
   152     }
   153     return modes;
   154 }
   155 
   156 static int
   157 SDL_CompatEventFilter(void *userdata, SDL_Event * event)
   158 {
   159     SDL_Event fake;
   160 
   161     switch (event->type) {
   162     case SDL_WINDOWEVENT:
   163         switch (event->window.event) {
   164         case SDL_WINDOWEVENT_EXPOSED:
   165             if (!SDL_HasEvent(SDL_VIDEOEXPOSEMASK)) {
   166                 fake.type = SDL_VIDEOEXPOSE;
   167                 SDL_PushEvent(&fake);
   168             }
   169             break;
   170         case SDL_WINDOWEVENT_RESIZED:
   171             fake.type = SDL_VIDEORESIZE;
   172             fake.resize.w = event->window.data1;
   173             fake.resize.h = event->window.data2;
   174             SDL_PushEvent(&fake);
   175             break;
   176         case SDL_WINDOWEVENT_MINIMIZED:
   177             fake.type = SDL_ACTIVEEVENT;
   178             fake.active.gain = 0;
   179             fake.active.state = SDL_APPACTIVE;
   180             SDL_PushEvent(&fake);
   181             break;
   182         case SDL_WINDOWEVENT_RESTORED:
   183             fake.type = SDL_ACTIVEEVENT;
   184             fake.active.gain = 1;
   185             fake.active.state = SDL_APPACTIVE;
   186             SDL_PushEvent(&fake);
   187             break;
   188         case SDL_WINDOWEVENT_ENTER:
   189             fake.type = SDL_ACTIVEEVENT;
   190             fake.active.gain = 1;
   191             fake.active.state = SDL_APPMOUSEFOCUS;
   192             SDL_PushEvent(&fake);
   193             break;
   194         case SDL_WINDOWEVENT_LEAVE:
   195             fake.type = SDL_ACTIVEEVENT;
   196             fake.active.gain = 0;
   197             fake.active.state = SDL_APPMOUSEFOCUS;
   198             SDL_PushEvent(&fake);
   199             break;
   200         case SDL_WINDOWEVENT_FOCUS_GAINED:
   201             fake.type = SDL_ACTIVEEVENT;
   202             fake.active.gain = 1;
   203             fake.active.state = SDL_APPINPUTFOCUS;
   204             SDL_PushEvent(&fake);
   205             break;
   206         case SDL_WINDOWEVENT_FOCUS_LOST:
   207             fake.type = SDL_ACTIVEEVENT;
   208             fake.active.gain = 1;
   209             fake.active.state = SDL_APPINPUTFOCUS;
   210             SDL_PushEvent(&fake);
   211             break;
   212         case SDL_WINDOWEVENT_CLOSE:
   213             fake.type = SDL_QUIT;
   214             SDL_PushEvent(&fake);
   215             break;
   216         }
   217     case SDL_KEYDOWN:
   218     case SDL_KEYUP:
   219         {
   220             Uint32 unicode = 0;
   221             if (event->key.type == SDL_KEYDOWN && event->key.keysym.sym < 256) {
   222                 unicode = event->key.keysym.sym;
   223                 if (unicode >= 'a' && unicode <= 'z') {
   224                     int shifted = !!(event->key.keysym.mod & KMOD_SHIFT);
   225                     int capslock = !!(event->key.keysym.mod & KMOD_CAPS);
   226                     if ((shifted ^ capslock) != 0) {
   227                         unicode = SDL_toupper(unicode);
   228                     }
   229                 }
   230             }
   231             if (unicode) {
   232                 event->key.keysym.unicode = unicode;
   233             }
   234             break;
   235         }
   236     case SDL_MOUSEWHEEL:
   237         {
   238             Uint8 button;
   239             int selected;
   240             int x, y;
   241 
   242             selected = SDL_SelectMouse(event->wheel.which);
   243             SDL_GetMouseState(&x, &y);
   244             SDL_SelectMouse(selected);
   245 
   246             if (event->wheel.motion > 0) {
   247                 button = SDL_BUTTON_WHEELUP;
   248             } else {
   249                 button = SDL_BUTTON_WHEELDOWN;
   250             }
   251 
   252             fake.button.which = event->wheel.windowID;
   253             fake.button.button = button;
   254             fake.button.x = x;
   255             fake.button.y = y;
   256             fake.button.windowID = event->wheel.windowID;
   257 
   258             fake.type = SDL_MOUSEBUTTONDOWN;
   259             fake.button.state = SDL_PRESSED;
   260             SDL_PushEvent(&fake);
   261 
   262             fake.type = SDL_MOUSEBUTTONUP;
   263             fake.button.state = SDL_RELEASED;
   264             SDL_PushEvent(&fake);
   265             break;
   266         }
   267 
   268     }
   269     return 1;
   270 }
   271 
   272 static int
   273 SDL_VideoPaletteChanged(void *userdata, SDL_Palette * palette)
   274 {
   275     if (userdata == SDL_ShadowSurface) {
   276         /* If the shadow palette changed, make the changes visible */
   277         if (!SDL_VideoSurface->format->palette) {
   278             SDL_UpdateRect(SDL_ShadowSurface, 0, 0, 0, 0);
   279         }
   280     }
   281     if (userdata == SDL_VideoSurface) {
   282         return SDL_SetDisplayPalette(palette->colors, 0, palette->ncolors);
   283     }
   284     return 0;
   285 }
   286 
   287 static void
   288 GetEnvironmentWindowPosition(int w, int h, int *x, int *y)
   289 {
   290     const char *window = SDL_getenv("SDL_VIDEO_WINDOW_POS");
   291     const char *center = SDL_getenv("SDL_VIDEO_CENTERED");
   292     if (window) {
   293         if (SDL_sscanf(window, "%d,%d", x, y) == 2) {
   294             return;
   295         }
   296         if (SDL_strcmp(window, "center") == 0) {
   297             center = window;
   298         }
   299     }
   300     if (center) {
   301         const SDL_DisplayMode *current = SDL_GetDesktopDisplayMode();
   302         *x = (current->w - w) / 2;
   303         *y = (current->h - h) / 2;
   304     }
   305 }
   306 
   307 SDL_Surface *
   308 SDL_SetVideoMode(int width, int height, int bpp, Uint32 flags)
   309 {
   310     const SDL_DisplayMode *desktop_mode;
   311     SDL_DisplayMode mode;
   312     int window_x = SDL_WINDOWPOS_UNDEFINED;
   313     int window_y = SDL_WINDOWPOS_UNDEFINED;
   314     Uint32 window_flags;
   315     Uint32 desktop_format;
   316     Uint32 desired_format;
   317     Uint32 surface_flags;
   318 
   319     if (!SDL_GetVideoDevice()) {
   320         if (SDL_Init(SDL_INIT_VIDEO | SDL_INIT_NOPARACHUTE) < 0) {
   321             return NULL;
   322         }
   323     }
   324 
   325     /* Destroy existing window */
   326     SDL_PublicSurface = NULL;
   327     if (SDL_ShadowSurface) {
   328         SDL_FreeSurface(SDL_ShadowSurface);
   329         SDL_ShadowSurface = NULL;
   330     }
   331     if (SDL_VideoSurface) {
   332         SDL_DelPaletteWatch(SDL_VideoSurface->format->palette,
   333                             SDL_VideoPaletteChanged, NULL);
   334         SDL_FreeSurface(SDL_VideoSurface);
   335         SDL_VideoSurface = NULL;
   336     }
   337     if (SDL_VideoWindow) {
   338         SDL_GetWindowPosition(SDL_VideoWindow, &window_x, &window_y);
   339     }
   340     SDL_DestroyWindow(SDL_VideoWindow);
   341 
   342     /* Set up the event filter */
   343     if (!SDL_GetEventFilter(NULL, NULL)) {
   344         SDL_SetEventFilter(SDL_CompatEventFilter, NULL);
   345     }
   346 
   347     /* Create a new window */
   348     window_flags = SDL_WINDOW_SHOWN;
   349     if (flags & SDL_FULLSCREEN) {
   350         window_flags |= SDL_WINDOW_FULLSCREEN;
   351     }
   352     if (flags & SDL_OPENGL) {
   353         window_flags |= SDL_WINDOW_OPENGL;
   354     }
   355     if (flags & SDL_RESIZABLE) {
   356         window_flags |= SDL_WINDOW_RESIZABLE;
   357     }
   358     if (flags & SDL_NOFRAME) {
   359         window_flags |= SDL_WINDOW_BORDERLESS;
   360     }
   361     GetEnvironmentWindowPosition(width, height, &window_x, &window_y);
   362     SDL_SetFullscreenDisplayMode(NULL);
   363     SDL_VideoWindow =
   364         SDL_CreateWindow(wm_title, window_x, window_y, width, height,
   365                          window_flags);
   366     if (!SDL_VideoWindow) {
   367         return NULL;
   368     }
   369 
   370     window_flags = SDL_GetWindowFlags(SDL_VideoWindow);
   371     surface_flags = 0;
   372     if (window_flags & SDL_WINDOW_FULLSCREEN) {
   373         surface_flags |= SDL_FULLSCREEN;
   374     }
   375     if (window_flags & SDL_WINDOW_OPENGL) {
   376         surface_flags |= SDL_OPENGL;
   377     }
   378     if (window_flags & SDL_WINDOW_RESIZABLE) {
   379         surface_flags |= SDL_RESIZABLE;
   380     }
   381     if (window_flags & SDL_WINDOW_BORDERLESS) {
   382         surface_flags |= SDL_NOFRAME;
   383     }
   384 
   385     /* Set up the desired display mode */
   386     desktop_mode = SDL_GetDesktopDisplayMode();
   387     desktop_format = desktop_mode->format;
   388     if (desktop_format && ((flags & SDL_ANYFORMAT)
   389                            || (bpp == SDL_BITSPERPIXEL(desktop_format)))) {
   390         desired_format = desktop_format;
   391     } else {
   392         switch (bpp) {
   393         case 0:
   394             if (desktop_format) {
   395                 desired_format = desktop_format;
   396             } else {
   397                 desired_format = SDL_PixelFormat_RGB888;
   398             }
   399             break;
   400         case 8:
   401             desired_format = SDL_PixelFormat_Index8;
   402             break;
   403         case 15:
   404             desired_format = SDL_PixelFormat_RGB555;
   405             break;
   406         case 16:
   407             desired_format = SDL_PixelFormat_RGB565;
   408             break;
   409         case 24:
   410             desired_format = SDL_PixelFormat_RGB24;
   411             break;
   412         case 32:
   413             desired_format = SDL_PixelFormat_RGB888;
   414             break;
   415         default:
   416             SDL_SetError("Unsupported bpp in SDL_SetVideoMode()");
   417             return NULL;
   418         }
   419     }
   420     mode.format = desired_format;
   421     mode.w = width;
   422     mode.h = height;
   423     mode.refresh_rate = 0;
   424 
   425     /* Set the desired display mode */
   426     if (flags & SDL_FULLSCREEN) {
   427         if (SDL_SetFullscreenDisplayMode(&mode) < 0) {
   428             return NULL;
   429         }
   430     }
   431 
   432     /* If we're in OpenGL mode, just create a stub surface and we're done! */
   433     if (flags & SDL_OPENGL) {
   434         SDL_VideoSurface =
   435             SDL_CreateRGBSurfaceFrom(NULL, width, height, bpp, 0, 0, 0, 0, 0);
   436         if (!SDL_VideoSurface) {
   437             return NULL;
   438         }
   439         SDL_VideoSurface->flags |= surface_flags;
   440         SDL_PublicSurface = SDL_VideoSurface;
   441         return SDL_PublicSurface;
   442     }
   443 
   444     /* Create a renderer for the window */
   445     if (SDL_CreateRenderer(SDL_VideoWindow, -1, SDL_Renderer_SingleBuffer) <
   446         0) {
   447         return NULL;
   448     }
   449 
   450     /* Create a texture for the screen surface */
   451     SDL_VideoTexture =
   452         SDL_CreateTexture(desired_format, SDL_TextureAccess_Local, width,
   453                           height);
   454     if (!SDL_VideoTexture) {
   455         SDL_VideoTexture =
   456             SDL_CreateTexture(0, SDL_TextureAccess_Local, width, height);
   457     }
   458     if (!SDL_VideoTexture) {
   459         return NULL;
   460     }
   461 
   462     /* Create the screen surface */
   463     SDL_VideoSurface = SDL_CreateRGBSurfaceFromTexture(SDL_VideoTexture);
   464     if (!SDL_VideoSurface) {
   465         return NULL;
   466     }
   467     SDL_VideoSurface->flags |= surface_flags;
   468 
   469     /* Set a default screen palette */
   470     if (SDL_VideoSurface->format->palette) {
   471         SDL_VideoSurface->flags |= SDL_HWPALETTE;
   472         SDL_DitherColors(SDL_VideoSurface->format->palette->colors,
   473                          SDL_VideoSurface->format->BitsPerPixel);
   474         SDL_AddPaletteWatch(SDL_VideoSurface->format->palette,
   475                             SDL_VideoPaletteChanged, NULL);
   476         SDL_SetPaletteColors(SDL_VideoSurface->format->palette,
   477                              SDL_VideoSurface->format->palette->colors, 0,
   478                              SDL_VideoSurface->format->palette->ncolors);
   479     }
   480 
   481     /* Create a shadow surface if necessary */
   482     if (((bpp != SDL_VideoSurface->format->BitsPerPixel)
   483          && !(flags & SDL_ANYFORMAT))
   484         || ((SDL_VideoSurface->flags & SDL_HWSURFACE)
   485             && !(flags & SDL_HWSURFACE))) {
   486         if ((bpp == SDL_VideoSurface->format->BitsPerPixel)
   487             || (flags & SDL_ANYFORMAT)) {
   488             SDL_ShadowSurface =
   489                 SDL_CreateRGBSurface(0, width, height,
   490                                      SDL_VideoSurface->format->BitsPerPixel,
   491                                      SDL_VideoSurface->format->Rmask,
   492                                      SDL_VideoSurface->format->Gmask,
   493                                      SDL_VideoSurface->format->Bmask,
   494                                      SDL_VideoSurface->format->Amask);
   495         } else {
   496             SDL_ShadowSurface =
   497                 SDL_CreateRGBSurface(0, width, height, bpp, 0, 0, 0, 0);
   498         }
   499         if (!SDL_ShadowSurface) {
   500             return NULL;
   501         }
   502         SDL_ShadowSurface->flags |= surface_flags;
   503 
   504         /* 8-bit SDL_ShadowSurface surfaces report that they have exclusive palette */
   505         if (SDL_ShadowSurface->format->palette) {
   506             SDL_ShadowSurface->flags |= SDL_HWPALETTE;
   507             if (SDL_VideoSurface->format->palette) {
   508                 SDL_SetSurfacePalette(SDL_ShadowSurface,
   509                                       SDL_VideoSurface->format->palette);
   510             } else {
   511                 SDL_DitherColors(SDL_ShadowSurface->format->palette->colors,
   512                                  SDL_ShadowSurface->format->BitsPerPixel);
   513             }
   514         }
   515     }
   516     SDL_PublicSurface =
   517         (SDL_ShadowSurface ? SDL_ShadowSurface : SDL_VideoSurface);
   518 
   519     /* Clear the surface for display */
   520     SDL_FillRect(SDL_PublicSurface, NULL, 0);
   521     SDL_UpdateRect(SDL_PublicSurface, 0, 0, 0, 0);
   522 
   523     /* We're finally done! */
   524     return SDL_PublicSurface;
   525 }
   526 
   527 SDL_Surface *
   528 SDL_GetVideoSurface(void)
   529 {
   530     return SDL_PublicSurface;
   531 }
   532 
   533 SDL_Surface *
   534 SDL_DisplayFormat(SDL_Surface * surface)
   535 {
   536     Uint32 flags;
   537 
   538     if (!SDL_PublicSurface) {
   539         SDL_SetError("No video mode has been set");
   540         return NULL;
   541     }
   542 
   543     /* Set the flags appropriate for copying to display surface */
   544     flags = SDL_SWSURFACE;
   545 #ifdef AUTORLE_DISPLAYFORMAT
   546     flags |= (surface->flags & (SDL_SRCCOLORKEY | SDL_SRCALPHA));
   547     flags |= SDL_RLEACCELOK;
   548 #else
   549     flags |=
   550         surface->flags & (SDL_SRCCOLORKEY | SDL_SRCALPHA | SDL_RLEACCELOK);
   551 #endif
   552     return SDL_ConvertSurface(surface, SDL_PublicSurface->format, flags);
   553 }
   554 
   555 SDL_Surface *
   556 SDL_DisplayFormatAlpha(SDL_Surface * surface)
   557 {
   558     SDL_PixelFormat *vf;
   559     SDL_PixelFormat *format;
   560     SDL_Surface *converted;
   561     Uint32 flags;
   562     /* default to ARGB8888 */
   563     Uint32 amask = 0xff000000;
   564     Uint32 rmask = 0x00ff0000;
   565     Uint32 gmask = 0x0000ff00;
   566     Uint32 bmask = 0x000000ff;
   567 
   568     if (!SDL_PublicSurface) {
   569         SDL_SetError("No video mode has been set");
   570         return NULL;
   571     }
   572     vf = SDL_PublicSurface->format;
   573 
   574     switch (vf->BytesPerPixel) {
   575     case 2:
   576         /* For XGY5[56]5, use, AXGY8888, where {X, Y} = {R, B}.
   577            For anything else (like ARGB4444) it doesn't matter
   578            since we have no special code for it anyway */
   579         if ((vf->Rmask == 0x1f) &&
   580             (vf->Bmask == 0xf800 || vf->Bmask == 0x7c00)) {
   581             rmask = 0xff;
   582             bmask = 0xff0000;
   583         }
   584         break;
   585 
   586     case 3:
   587     case 4:
   588         /* Keep the video format, as long as the high 8 bits are
   589            unused or alpha */
   590         if ((vf->Rmask == 0xff) && (vf->Bmask == 0xff0000)) {
   591             rmask = 0xff;
   592             bmask = 0xff0000;
   593         }
   594         break;
   595 
   596     default:
   597         /* We have no other optimised formats right now. When/if a new
   598            optimised alpha format is written, add the converter here */
   599         break;
   600     }
   601     format = SDL_AllocFormat(32, rmask, gmask, bmask, amask);
   602     flags = SDL_PublicSurface->flags & SDL_HWSURFACE;
   603     flags |= surface->flags & (SDL_SRCALPHA | SDL_RLEACCELOK);
   604     converted = SDL_ConvertSurface(surface, format, flags);
   605     SDL_FreeFormat(format);
   606     return converted;
   607 }
   608 
   609 int
   610 SDL_Flip(SDL_Surface * screen)
   611 {
   612     SDL_UpdateRect(screen, 0, 0, 0, 0);
   613     return 0;
   614 }
   615 
   616 void
   617 SDL_UpdateRect(SDL_Surface * screen, Sint32 x, Sint32 y, Uint32 w, Uint32 h)
   618 {
   619     if (screen) {
   620         SDL_Rect rect;
   621 
   622         /* Fill the rectangle */
   623         rect.x = (int) x;
   624         rect.y = (int) y;
   625         rect.w = (int) (w ? w : screen->w);
   626         rect.h = (int) (h ? h : screen->h);
   627         SDL_UpdateRects(screen, 1, &rect);
   628     }
   629 }
   630 void
   631 SDL_UpdateRects(SDL_Surface * screen, int numrects, SDL_Rect * rects)
   632 {
   633     int i;
   634 
   635     if (screen == SDL_ShadowSurface) {
   636         for (i = 0; i < numrects; ++i) {
   637             SDL_LowerBlit(SDL_ShadowSurface, &rects[i], SDL_VideoSurface,
   638                           &rects[i]);
   639         }
   640 
   641         /* Fall through to video surface update */
   642         screen = SDL_VideoSurface;
   643     }
   644     if (screen == SDL_VideoSurface) {
   645         for (i = 0; i < numrects; ++i) {
   646             SDL_RenderCopy(SDL_VideoTexture, &rects[i], &rects[i],
   647                            SDL_TextureBlendMode_None,
   648                            SDL_TextureScaleMode_None);
   649         }
   650         SDL_RenderPresent();
   651     }
   652 }
   653 
   654 void
   655 SDL_WM_SetCaption(const char *title, const char *icon)
   656 {
   657     if (wm_title) {
   658         SDL_free(wm_title);
   659     } else {
   660         wm_title = SDL_strdup(title);
   661     }
   662     SDL_SetWindowTitle(SDL_VideoWindow, wm_title);
   663 }
   664 
   665 void
   666 SDL_WM_GetCaption(char **title, char **icon)
   667 {
   668     if (title) {
   669         *title = wm_title;
   670     }
   671     if (icon) {
   672         *icon = "";
   673     }
   674 }
   675 
   676 void
   677 SDL_WM_SetIcon(SDL_Surface * icon, Uint8 * mask)
   678 {
   679     /* FIXME */
   680 }
   681 
   682 int
   683 SDL_WM_IconifyWindow(void)
   684 {
   685     SDL_MinimizeWindow(SDL_VideoWindow);
   686     return 0;
   687 }
   688 
   689 int
   690 SDL_WM_ToggleFullScreen(SDL_Surface * surface)
   691 {
   692     if (SDL_GetWindowFlags(SDL_VideoWindow) & SDL_WINDOW_FULLSCREEN) {
   693         if (SDL_SetWindowFullscreen(SDL_VideoWindow, 0) < 0) {
   694             return 0;
   695         }
   696         SDL_PublicSurface->flags &= ~SDL_FULLSCREEN;
   697     } else {
   698         if (SDL_SetWindowFullscreen(SDL_VideoWindow, 1) < 0) {
   699             return 0;
   700         }
   701         SDL_PublicSurface->flags |= SDL_FULLSCREEN;
   702     }
   703     return 1;
   704 }
   705 
   706 SDL_GrabMode
   707 SDL_WM_GrabInput(SDL_GrabMode mode)
   708 {
   709     if (mode != SDL_GRAB_QUERY) {
   710         SDL_SetWindowGrab(SDL_VideoWindow, mode);
   711     }
   712     return (SDL_GrabMode) SDL_GetWindowGrab(SDL_VideoWindow);
   713 }
   714 
   715 void
   716 SDL_WarpMouse(Uint16 x, Uint16 y)
   717 {
   718     SDL_WarpMouseInWindow(SDL_VideoWindow, x, y);
   719 }
   720 
   721 Uint8
   722 SDL_GetAppState(void)
   723 {
   724     Uint8 state = 0;
   725     Uint32 flags = 0;
   726 
   727     flags = SDL_GetWindowFlags(SDL_VideoWindow);
   728     if ((flags & SDL_WINDOW_SHOWN) && !(flags & SDL_WINDOW_MINIMIZED)) {
   729         state |= SDL_APPACTIVE;
   730     }
   731     if (flags & SDL_WINDOW_INPUT_FOCUS) {
   732         state |= SDL_APPINPUTFOCUS;
   733     }
   734     if (flags & SDL_WINDOW_MOUSE_FOCUS) {
   735         state |= SDL_APPMOUSEFOCUS;
   736     }
   737     return state;
   738 }
   739 
   740 const SDL_version *
   741 SDL_Linked_Version(void)
   742 {
   743     static SDL_version version;
   744     SDL_VERSION(&version);
   745     return &version;
   746 }
   747 
   748 int
   749 SDL_SetPalette(SDL_Surface * surface, int flags, const SDL_Color * colors,
   750                int firstcolor, int ncolors)
   751 {
   752     return SDL_SetColors(surface, colors, firstcolor, ncolors);
   753 }
   754 
   755 int
   756 SDL_SetColors(SDL_Surface * surface, const SDL_Color * colors, int firstcolor,
   757               int ncolors)
   758 {
   759     if (SDL_SetPaletteColors
   760         (surface->format->palette, colors, firstcolor, ncolors) == 0) {
   761         return 1;
   762     } else {
   763         return 0;
   764     }
   765 }
   766 
   767 int
   768 SDL_GetWMInfo(SDL_SysWMinfo * info)
   769 {
   770     return SDL_GetWindowWMInfo(SDL_VideoWindow, info);
   771 }
   772 
   773 #if 0
   774 void
   775 SDL_MoveCursor(int x, int y)
   776 {
   777     SDL_VideoDevice *_this = SDL_GetVideoDevice();
   778 
   779     /* Erase and update the current mouse position */
   780     if (SHOULD_DRAWCURSOR(SDL_cursorstate)) {
   781         /* Erase and redraw mouse cursor in new position */
   782         SDL_LockCursor();
   783         SDL_EraseCursor(SDL_VideoSurface);
   784         SDL_cursor->area.x = (x - SDL_cursor->hot_x);
   785         SDL_cursor->area.y = (y - SDL_cursor->hot_y);
   786         SDL_DrawCursor(SDL_VideoSurface);
   787         SDL_UnlockCursor();
   788     } else if (_this->MoveWMCursor) {
   789         _this->MoveWMCursor(_this, x, y);
   790     }
   791 }
   792 
   793 /* Keep track of the current cursor colors */
   794 static int palette_changed = 1;
   795 static Uint8 pixels8[2];
   796 
   797 void
   798 SDL_CursorPaletteChanged(void)
   799 {
   800     palette_changed = 1;
   801 }
   802 
   803 void
   804 SDL_MouseRect(SDL_Rect * area)
   805 {
   806     SDL_VideoDevice *_this = SDL_GetVideoDevice();
   807     int clip_diff;
   808 
   809     *area = SDL_cursor->area;
   810     if (area->x < 0) {
   811         area->w += area->x;
   812         area->x = 0;
   813     }
   814     if (area->y < 0) {
   815         area->h += area->y;
   816         area->y = 0;
   817     }
   818     clip_diff = (area->x + area->w) - SDL_VideoSurface->w;
   819     if (clip_diff > 0) {
   820         area->w = area->w < clip_diff ? 0 : area->w - clip_diff;
   821     }
   822     clip_diff = (area->y + area->h) - SDL_VideoSurface->h;
   823     if (clip_diff > 0) {
   824         area->h = area->h < clip_diff ? 0 : area->h - clip_diff;
   825     }
   826 }
   827 
   828 static void
   829 SDL_DrawCursorFast(SDL_Surface * screen, SDL_Rect * area)
   830 {
   831     const Uint32 pixels[2] = { 0xFFFFFFFF, 0x00000000 };
   832     int i, w, h;
   833     Uint8 *data, datab;
   834     Uint8 *mask, maskb;
   835 
   836     data = SDL_cursor->data + area->y * SDL_cursor->area.w / 8;
   837     mask = SDL_cursor->mask + area->y * SDL_cursor->area.w / 8;
   838     switch (screen->format->BytesPerPixel) {
   839 
   840     case 1:
   841         {
   842             Uint8 *dst;
   843             int dstskip;
   844 
   845             if (palette_changed) {
   846                 pixels8[0] =
   847                     (Uint8) SDL_MapRGB(screen->format, 255, 255, 255);
   848                 pixels8[1] = (Uint8) SDL_MapRGB(screen->format, 0, 0, 0);
   849                 palette_changed = 0;
   850             }
   851             dst = (Uint8 *) screen->pixels +
   852                 (SDL_cursor->area.y + area->y) * screen->pitch +
   853                 SDL_cursor->area.x;
   854             dstskip = screen->pitch - area->w;
   855 
   856             for (h = area->h; h; h--) {
   857                 for (w = area->w / 8; w; w--) {
   858                     maskb = *mask++;
   859                     datab = *data++;
   860                     for (i = 0; i < 8; ++i) {
   861                         if (maskb & 0x80) {
   862                             *dst = pixels8[datab >> 7];
   863                         }
   864                         maskb <<= 1;
   865                         datab <<= 1;
   866                         dst++;
   867                     }
   868                 }
   869                 dst += dstskip;
   870             }
   871         }
   872         break;
   873 
   874     case 2:
   875         {
   876             Uint16 *dst;
   877             int dstskip;
   878 
   879             dst = (Uint16 *) screen->pixels +
   880                 (SDL_cursor->area.y + area->y) * screen->pitch / 2 +
   881                 SDL_cursor->area.x;
   882             dstskip = (screen->pitch / 2) - area->w;
   883 
   884             for (h = area->h; h; h--) {
   885                 for (w = area->w / 8; w; w--) {
   886                     maskb = *mask++;
   887                     datab = *data++;
   888                     for (i = 0; i < 8; ++i) {
   889                         if (maskb & 0x80) {
   890                             *dst = (Uint16) pixels[datab >> 7];
   891                         }
   892                         maskb <<= 1;
   893                         datab <<= 1;
   894                         dst++;
   895                     }
   896                 }
   897                 dst += dstskip;
   898             }
   899         }
   900         break;
   901 
   902     case 3:
   903         {
   904             Uint8 *dst;
   905             int dstskip;
   906 
   907             dst = (Uint8 *) screen->pixels +
   908                 (SDL_cursor->area.y + area->y) * screen->pitch +
   909                 SDL_cursor->area.x * 3;
   910             dstskip = screen->pitch - area->w * 3;
   911 
   912             for (h = area->h; h; h--) {
   913                 for (w = area->w / 8; w; w--) {
   914                     maskb = *mask++;
   915                     datab = *data++;
   916                     for (i = 0; i < 8; ++i) {
   917                         if (maskb & 0x80) {
   918                             SDL_memset(dst, pixels[datab >> 7], 3);
   919                         }
   920                         maskb <<= 1;
   921                         datab <<= 1;
   922                         dst += 3;
   923                     }
   924                 }
   925                 dst += dstskip;
   926             }
   927         }
   928         break;
   929 
   930     case 4:
   931         {
   932             Uint32 *dst;
   933             int dstskip;
   934 
   935             dst = (Uint32 *) screen->pixels +
   936                 (SDL_cursor->area.y + area->y) * screen->pitch / 4 +
   937                 SDL_cursor->area.x;
   938             dstskip = (screen->pitch / 4) - area->w;
   939 
   940             for (h = area->h; h; h--) {
   941                 for (w = area->w / 8; w; w--) {
   942                     maskb = *mask++;
   943                     datab = *data++;
   944                     for (i = 0; i < 8; ++i) {
   945                         if (maskb & 0x80) {
   946                             *dst = pixels[datab >> 7];
   947                         }
   948                         maskb <<= 1;
   949                         datab <<= 1;
   950                         dst++;
   951                     }
   952                 }
   953                 dst += dstskip;
   954             }
   955         }
   956         break;
   957     }
   958 }
   959 
   960 static void
   961 SDL_DrawCursorSlow(SDL_Surface * screen, SDL_Rect * area)
   962 {
   963     const Uint32 pixels[2] = { 0xFFFFFF, 0x000000 };
   964     int h;
   965     int x, minx, maxx;
   966     Uint8 *data, datab = 0;
   967     Uint8 *mask, maskb = 0;
   968     Uint8 *dst;
   969     int dstbpp, dstskip;
   970 
   971     data = SDL_cursor->data + area->y * SDL_cursor->area.w / 8;
   972     mask = SDL_cursor->mask + area->y * SDL_cursor->area.w / 8;
   973     dstbpp = screen->format->BytesPerPixel;
   974     dst = (Uint8 *) screen->pixels +
   975         (SDL_cursor->area.y + area->y) * screen->pitch +
   976         SDL_cursor->area.x * dstbpp;
   977     dstskip = screen->pitch - SDL_cursor->area.w * dstbpp;
   978 
   979     minx = area->x;
   980     maxx = area->x + area->w;
   981     if (screen->format->BytesPerPixel == 1) {
   982         if (palette_changed) {
   983             pixels8[0] = (Uint8) SDL_MapRGB(screen->format, 255, 255, 255);
   984             pixels8[1] = (Uint8) SDL_MapRGB(screen->format, 0, 0, 0);
   985             palette_changed = 0;
   986         }
   987         for (h = area->h; h; h--) {
   988             for (x = 0; x < SDL_cursor->area.w; ++x) {
   989                 if ((x % 8) == 0) {
   990                     maskb = *mask++;
   991                     datab = *data++;
   992                 }
   993                 if ((x >= minx) && (x < maxx)) {
   994                     if (maskb & 0x80) {
   995                         SDL_memset(dst, pixels8[datab >> 7], dstbpp);
   996                     }
   997                 }
   998                 maskb <<= 1;
   999                 datab <<= 1;
  1000                 dst += dstbpp;
  1001             }
  1002             dst += dstskip;
  1003         }
  1004     } else {
  1005         for (h = area->h; h; h--) {
  1006             for (x = 0; x < SDL_cursor->area.w; ++x) {
  1007                 if ((x % 8) == 0) {
  1008                     maskb = *mask++;
  1009                     datab = *data++;
  1010                 }
  1011                 if ((x >= minx) && (x < maxx)) {
  1012                     if (maskb & 0x80) {
  1013                         SDL_memset(dst, pixels[datab >> 7], dstbpp);
  1014                     }
  1015                 }
  1016                 maskb <<= 1;
  1017                 datab <<= 1;
  1018                 dst += dstbpp;
  1019             }
  1020             dst += dstskip;
  1021         }
  1022     }
  1023 }
  1024 
  1025 /* This handles the ugly work of converting the saved cursor background from
  1026    the pixel format of the shadow surface to that of the video surface.
  1027    This is only necessary when blitting from a shadow surface of a different
  1028    pixel format than the video surface, and using a software rendered cursor.
  1029 */
  1030 static void
  1031 SDL_ConvertCursorSave(SDL_Surface * screen, int w, int h)
  1032 {
  1033     SDL_VideoDevice *_this = SDL_GetVideoDevice();
  1034     SDL_BlitInfo info;
  1035     SDL_loblit RunBlit;
  1036 
  1037     /* Make sure we can steal the blit mapping */
  1038     if (screen->map->dst != SDL_VideoSurface) {
  1039         return;
  1040     }
  1041 
  1042     /* Set up the blit information */
  1043     info.s_pixels = SDL_cursor->save[1];
  1044     info.s_width = w;
  1045     info.s_height = h;
  1046     info.s_skip = 0;
  1047     info.d_pixels = SDL_cursor->save[0];
  1048     info.d_width = w;
  1049     info.d_height = h;
  1050     info.d_skip = 0;
  1051     info.aux_data = screen->map->sw_data->aux_data;
  1052     info.src = screen->format;
  1053     info.table = screen->map->table;
  1054     info.dst = SDL_VideoSurface->format;
  1055     RunBlit = screen->map->sw_data->blit;
  1056 
  1057     /* Run the actual software blit */
  1058     RunBlit(&info);
  1059 }
  1060 
  1061 void
  1062 SDL_DrawCursorNoLock(SDL_Surface * screen)
  1063 {
  1064     SDL_VideoDevice *_this = SDL_GetVideoDevice();
  1065     SDL_Rect area;
  1066 
  1067     /* Get the mouse rectangle, clipped to the screen */
  1068     SDL_MouseRect(&area);
  1069     if ((area.w == 0) || (area.h == 0)) {
  1070         return;
  1071     }
  1072 
  1073     /* Copy mouse background */
  1074     {
  1075         int w, h, screenbpp;
  1076         Uint8 *src, *dst;
  1077 
  1078         /* Set up the copy pointers */
  1079         screenbpp = screen->format->BytesPerPixel;
  1080         if ((screen == SDL_VideoSurface) ||
  1081             FORMAT_EQUAL(screen->format, SDL_VideoSurface->format)) {
  1082             dst = SDL_cursor->save[0];
  1083         } else {
  1084             dst = SDL_cursor->save[1];
  1085         }
  1086         src = (Uint8 *) screen->pixels + area.y * screen->pitch +
  1087             area.x * screenbpp;
  1088 
  1089         /* Perform the copy */
  1090         w = area.w * screenbpp;
  1091         h = area.h;
  1092         while (h--) {
  1093             SDL_memcpy(dst, src, w);
  1094             dst += w;
  1095             src += screen->pitch;
  1096         }
  1097     }
  1098 
  1099     /* Draw the mouse cursor */
  1100     area.x -= SDL_cursor->area.x;
  1101     area.y -= SDL_cursor->area.y;
  1102     if ((area.x == 0) && (area.w == SDL_cursor->area.w)) {
  1103         SDL_DrawCursorFast(screen, &area);
  1104     } else {
  1105         SDL_DrawCursorSlow(screen, &area);
  1106     }
  1107 }
  1108 
  1109 void
  1110 SDL_DrawCursor(SDL_Surface * screen)
  1111 {
  1112     /* Lock the screen if necessary */
  1113     if (screen == NULL) {
  1114         return;
  1115     }
  1116     if (SDL_MUSTLOCK(screen)) {
  1117         if (SDL_LockSurface(screen) < 0) {
  1118             return;
  1119         }
  1120     }
  1121 
  1122     SDL_DrawCursorNoLock(screen);
  1123 
  1124     /* Unlock the screen and update if necessary */
  1125     if (SDL_MUSTLOCK(screen)) {
  1126         SDL_UnlockSurface(screen);
  1127     }
  1128     if ((screen->flags & SDL_SCREEN_SURFACE) &&
  1129         !(screen->flags & SDL_HWSURFACE)) {
  1130         SDL_VideoDevice *_this = SDL_GetVideoDevice();
  1131         SDL_Window *window;
  1132         SDL_Rect area;
  1133 
  1134         window = SDL_GetWindowFromSurface(screen);
  1135         if (!window) {
  1136             return;
  1137         }
  1138 
  1139         SDL_MouseRect(&area);
  1140 
  1141         if (_this->UpdateWindowSurface) {
  1142             _this->UpdateWindowSurface(_this, window, 1, &area);
  1143         }
  1144     }
  1145 }
  1146 
  1147 void
  1148 SDL_EraseCursorNoLock(SDL_Surface * screen)
  1149 {
  1150     SDL_VideoDevice *_this = SDL_GetVideoDevice();
  1151     SDL_Window *window;
  1152     SDL_Rect area;
  1153 
  1154     /* Get the window associated with the surface */
  1155     window = SDL_GetWindowFromSurface(screen);
  1156     if (!window || !window->surface) {
  1157         return;
  1158     }
  1159 
  1160     /* Get the mouse rectangle, clipped to the screen */
  1161     SDL_MouseRect(&area);
  1162     if ((area.w == 0) || (area.h == 0)) {
  1163         return;
  1164     }
  1165 
  1166     /* Copy mouse background */
  1167     {
  1168         int w, h, screenbpp;
  1169         Uint8 *src, *dst;
  1170 
  1171         /* Set up the copy pointers */
  1172         screenbpp = screen->format->BytesPerPixel;
  1173         if ((screen->flags & SDL_SCREEN_SURFACE) ||
  1174             FORMAT_EQUAL(screen->format, window->surface->format)) {
  1175             src = SDL_cursor->save[0];
  1176         } else {
  1177             src = SDL_cursor->save[1];
  1178         }
  1179         dst = (Uint8 *) screen->pixels + area.y * screen->pitch +
  1180             area.x * screenbpp;
  1181 
  1182         /* Perform the copy */
  1183         w = area.w * screenbpp;
  1184         h = area.h;
  1185         while (h--) {
  1186             SDL_memcpy(dst, src, w);
  1187             src += w;
  1188             dst += screen->pitch;
  1189         }
  1190 
  1191         /* Perform pixel conversion on cursor background */
  1192         if (src > SDL_cursor->save[1]) {
  1193             SDL_ConvertCursorSave(screen, area.w, area.h);
  1194         }
  1195     }
  1196 }
  1197 
  1198 void
  1199 SDL_EraseCursor(SDL_Surface * screen)
  1200 {
  1201     /* Lock the screen if necessary */
  1202     if (screen == NULL) {
  1203         return;
  1204     }
  1205     if (SDL_MUSTLOCK(screen)) {
  1206         if (SDL_LockSurface(screen) < 0) {
  1207             return;
  1208         }
  1209     }
  1210 
  1211     SDL_EraseCursorNoLock(screen);
  1212 
  1213     /* Unlock the screen and update if necessary */
  1214     if (SDL_MUSTLOCK(screen)) {
  1215         SDL_UnlockSurface(screen);
  1216     }
  1217     if ((screen->flags & SDL_SCREEN_SURFACE) &&
  1218         !(screen->flags & SDL_HWSURFACE)) {
  1219         SDL_VideoDevice *_this = SDL_GetVideoDevice();
  1220         SDL_Window *window;
  1221         SDL_Rect area;
  1222 
  1223         window = SDL_GetWindowFromSurface(screen);
  1224         if (!window) {
  1225             return;
  1226         }
  1227 
  1228         SDL_MouseRect(&area);
  1229 
  1230         if (_this->UpdateWindowSurface) {
  1231             _this->UpdateWindowSurface(_this, window, 1, &area);
  1232         }
  1233     }
  1234 }
  1235 
  1236 /* Reset the cursor on video mode change
  1237    FIXME:  Keep track of all cursors, and reset them all.
  1238  */
  1239 void
  1240 SDL_ResetCursor(void)
  1241 {
  1242     int savelen;
  1243 
  1244     if (SDL_cursor) {
  1245         savelen = SDL_cursor->area.w * 4 * SDL_cursor->area.h;
  1246         SDL_cursor->area.x = 0;
  1247         SDL_cursor->area.y = 0;
  1248         SDL_memset(SDL_cursor->save[0], 0, savelen);
  1249     }
  1250 }
  1251 #endif
  1252 
  1253 struct private_yuvhwdata
  1254 {
  1255     Uint16 pitches[3];
  1256     Uint8 *planes[3];
  1257 
  1258     SDL_TextureID textureID;
  1259 };
  1260 
  1261 SDL_Overlay *
  1262 SDL_CreateYUVOverlay(int w, int h, Uint32 format, SDL_Surface * display)
  1263 {
  1264     SDL_Overlay *overlay;
  1265     Uint32 texture_format;
  1266 
  1267     if ((display->flags & SDL_OPENGL) == SDL_OPENGL) {
  1268         SDL_SetError("YUV overlays are not supported in OpenGL mode");
  1269         return NULL;
  1270     }
  1271 
  1272     if (display != SDL_PublicSurface) {
  1273         SDL_SetError("YUV display is only supported on the screen surface");
  1274         return NULL;
  1275     }
  1276 
  1277     switch (format) {
  1278     case SDL_YV12_OVERLAY:
  1279         texture_format = SDL_PixelFormat_YV12;
  1280         break;
  1281     case SDL_IYUV_OVERLAY:
  1282         texture_format = SDL_PixelFormat_IYUV;
  1283         break;
  1284     case SDL_YUY2_OVERLAY:
  1285         texture_format = SDL_PixelFormat_YUY2;
  1286         break;
  1287     case SDL_UYVY_OVERLAY:
  1288         texture_format = SDL_PixelFormat_UYVY;
  1289         break;
  1290     case SDL_YVYU_OVERLAY:
  1291         texture_format = SDL_PixelFormat_YVYU;
  1292         break;
  1293     default:
  1294         SDL_SetError("Unknown YUV format");
  1295         return NULL;
  1296     }
  1297 
  1298     overlay = (SDL_Overlay *) SDL_malloc(sizeof(*overlay));
  1299     if (!overlay) {
  1300         SDL_OutOfMemory();
  1301         return NULL;
  1302     }
  1303     SDL_zerop(overlay);
  1304 
  1305     overlay->hwdata =
  1306         (struct private_yuvhwdata *) SDL_malloc(sizeof(*overlay->hwdata));
  1307     if (!overlay->hwdata) {
  1308         SDL_free(overlay);
  1309         SDL_OutOfMemory();
  1310         return NULL;
  1311     }
  1312 
  1313     overlay->format = format;
  1314     overlay->w = w;
  1315     overlay->h = h;
  1316     if (format == SDL_YV12_OVERLAY || format == SDL_IYUV_OVERLAY) {
  1317         overlay->planes = 3;
  1318     } else {
  1319         overlay->planes = 1;
  1320     }
  1321     overlay->pitches = overlay->hwdata->pitches;
  1322     overlay->pixels = overlay->hwdata->planes;
  1323 
  1324     switch (format) {
  1325     case SDL_YV12_OVERLAY:
  1326     case SDL_IYUV_OVERLAY:
  1327         overlay->pitches[0] = overlay->w;
  1328         overlay->pitches[1] = overlay->w / 2;
  1329         overlay->pitches[2] = overlay->w / 2;
  1330         break;
  1331     case SDL_YUY2_OVERLAY:
  1332     case SDL_UYVY_OVERLAY:
  1333     case SDL_YVYU_OVERLAY:
  1334         overlay->pitches[0] = overlay->w * 2;
  1335         break;
  1336     }
  1337 
  1338     overlay->hwdata->textureID =
  1339         SDL_CreateTexture(texture_format, SDL_TextureAccess_Local, w, h);
  1340     if (!overlay->hwdata->textureID) {
  1341         SDL_FreeYUVOverlay(overlay);
  1342         return NULL;
  1343     }
  1344 
  1345     return overlay;
  1346 }
  1347 
  1348 int
  1349 SDL_LockYUVOverlay(SDL_Overlay * overlay)
  1350 {
  1351     void *pixels;
  1352     int pitch;
  1353     if (SDL_LockTexture(overlay->hwdata->textureID, NULL, 1, &pixels, &pitch)
  1354         < 0) {
  1355         return -1;
  1356     }
  1357     switch (overlay->format) {
  1358     case SDL_YV12_OVERLAY:
  1359     case SDL_IYUV_OVERLAY:
  1360         overlay->pixels[0] = (Uint8 *) pixels;
  1361         overlay->pixels[1] =
  1362             overlay->pixels[0] + overlay->pitches[0] * overlay->h;
  1363         overlay->pixels[2] =
  1364             overlay->pixels[1] + overlay->pitches[1] * overlay->h;
  1365         break;
  1366     case SDL_YUY2_OVERLAY:
  1367     case SDL_UYVY_OVERLAY:
  1368     case SDL_YVYU_OVERLAY:
  1369         overlay->pixels[0] = (Uint8 *) pixels;
  1370         break;
  1371     }
  1372     return 0;
  1373 }
  1374 
  1375 void
  1376 SDL_UnlockYUVOverlay(SDL_Overlay * overlay)
  1377 {
  1378     SDL_UnlockTexture(overlay->hwdata->textureID);
  1379 }
  1380 
  1381 int
  1382 SDL_DisplayYUVOverlay(SDL_Overlay * overlay, SDL_Rect * dstrect)
  1383 {
  1384     if (SDL_RenderCopy(overlay->hwdata->textureID, NULL, dstrect,
  1385                        SDL_TextureBlendMode_None,
  1386                        SDL_TextureScaleMode_Fast) < 0) {
  1387         return -1;
  1388     }
  1389     SDL_RenderPresent();
  1390     return 0;
  1391 }
  1392 
  1393 void
  1394 SDL_FreeYUVOverlay(SDL_Overlay * overlay)
  1395 {
  1396     if (overlay) {
  1397         if (overlay->hwdata) {
  1398             if (overlay->hwdata->textureID) {
  1399                 SDL_DestroyTexture(overlay->hwdata->textureID);
  1400             }
  1401             SDL_free(overlay->hwdata);
  1402         }
  1403         SDL_free(overlay);
  1404     }
  1405 }
  1406 
  1407 /* vi: set ts=4 sw=4 expandtab: */