src/video/SDL_surface.c
author stfx <stfx@hotmail.de>
Wed, 08 Jul 2020 17:28:34 +0200
changeset 13944 b8c8ce11efc7
parent 13916 ed0e044e308c
permissions -rw-r--r--
cmake: Fix building with -DSDL_HAPTIC=Off
     1 /*
     2   Simple DirectMedia Layer
     3   Copyright (C) 1997-2020 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 #include "../SDL_internal.h"
    22 
    23 #include "SDL_video.h"
    24 #include "SDL_sysvideo.h"
    25 #include "SDL_blit.h"
    26 #include "SDL_RLEaccel_c.h"
    27 #include "SDL_pixels_c.h"
    28 #include "SDL_yuv_c.h"
    29 
    30 
    31 /* Check to make sure we can safely check multiplication of surface w and pitch and it won't overflow size_t */
    32 SDL_COMPILE_TIME_ASSERT(surface_size_assumptions,
    33     sizeof(int) == sizeof(Sint32) && sizeof(size_t) >= sizeof(Sint32));
    34 
    35 /* Public routines */
    36 
    37 /*
    38  * Calculate the pad-aligned scanline width of a surface
    39  */
    40 static Sint64
    41 SDL_CalculatePitch(Uint32 format, int width)
    42 {
    43     Sint64 pitch;
    44 
    45     if (SDL_ISPIXELFORMAT_FOURCC(format) || SDL_BITSPERPIXEL(format) >= 8) {
    46         pitch = ((Sint64)width * SDL_BYTESPERPIXEL(format));
    47     } else {
    48         pitch = (((Sint64)width * SDL_BITSPERPIXEL(format)) + 7) / 8;
    49     }
    50     pitch = (pitch + 3) & ~3;   /* 4-byte aligning for speed */
    51     return pitch;
    52 }
    53 
    54 /*
    55  * Create an empty RGB surface of the appropriate depth using the given
    56  * enum SDL_PIXELFORMAT_* format
    57  */
    58 SDL_Surface *
    59 SDL_CreateRGBSurfaceWithFormat(Uint32 flags, int width, int height, int depth,
    60                                Uint32 format)
    61 {
    62     Sint64 pitch;
    63     SDL_Surface *surface;
    64 
    65     /* The flags are no longer used, make the compiler happy */
    66     (void)flags;
    67 
    68     pitch = SDL_CalculatePitch(format, width);
    69     if (pitch < 0 || pitch > SDL_MAX_SINT32) {
    70         /* Overflow... */
    71         SDL_OutOfMemory();
    72         return NULL;
    73     }
    74 
    75     /* Allocate the surface */
    76     surface = (SDL_Surface *) SDL_calloc(1, sizeof(*surface));
    77     if (surface == NULL) {
    78         SDL_OutOfMemory();
    79         return NULL;
    80     }
    81 
    82     surface->format = SDL_AllocFormat(format);
    83     if (!surface->format) {
    84         SDL_FreeSurface(surface);
    85         return NULL;
    86     }
    87     surface->w = width;
    88     surface->h = height;
    89     surface->pitch = (int)pitch;
    90     SDL_SetClipRect(surface, NULL);
    91 
    92     if (SDL_ISPIXELFORMAT_INDEXED(surface->format->format)) {
    93         SDL_Palette *palette =
    94             SDL_AllocPalette((1 << surface->format->BitsPerPixel));
    95         if (!palette) {
    96             SDL_FreeSurface(surface);
    97             return NULL;
    98         }
    99         if (palette->ncolors == 2) {
   100             /* Create a black and white bitmap palette */
   101             palette->colors[0].r = 0xFF;
   102             palette->colors[0].g = 0xFF;
   103             palette->colors[0].b = 0xFF;
   104             palette->colors[1].r = 0x00;
   105             palette->colors[1].g = 0x00;
   106             palette->colors[1].b = 0x00;
   107         }
   108         SDL_SetSurfacePalette(surface, palette);
   109         SDL_FreePalette(palette);
   110     }
   111 
   112     /* Get the pixels */
   113     if (surface->w && surface->h) {
   114         /* Assumptions checked in surface_size_assumptions assert above */
   115         Sint64 size = ((Sint64)surface->h * surface->pitch);
   116         if (size < 0 || size > SDL_MAX_SINT32) {
   117             /* Overflow... */
   118             SDL_FreeSurface(surface);
   119             SDL_OutOfMemory();
   120             return NULL;
   121         }
   122 
   123         surface->pixels = SDL_SIMDAlloc((size_t)size);
   124         if (!surface->pixels) {
   125             SDL_FreeSurface(surface);
   126             SDL_OutOfMemory();
   127             return NULL;
   128         }
   129         surface->flags |= SDL_SIMD_ALIGNED;
   130         /* This is important for bitmaps */
   131         SDL_memset(surface->pixels, 0, surface->h * surface->pitch);
   132     }
   133 
   134     /* Allocate an empty mapping */
   135     surface->map = SDL_AllocBlitMap();
   136     if (!surface->map) {
   137         SDL_FreeSurface(surface);
   138         return NULL;
   139     }
   140 
   141     /* By default surface with an alpha mask are set up for blending */
   142     if (surface->format->Amask) {
   143         SDL_SetSurfaceBlendMode(surface, SDL_BLENDMODE_BLEND);
   144     }
   145 
   146     /* The surface is ready to go */
   147     surface->refcount = 1;
   148     return surface;
   149 }
   150 
   151 /*
   152  * Create an empty RGB surface of the appropriate depth
   153  */
   154 SDL_Surface *
   155 SDL_CreateRGBSurface(Uint32 flags,
   156                      int width, int height, int depth,
   157                      Uint32 Rmask, Uint32 Gmask, Uint32 Bmask, Uint32 Amask)
   158 {
   159     Uint32 format;
   160 
   161     /* Get the pixel format */
   162     format = SDL_MasksToPixelFormatEnum(depth, Rmask, Gmask, Bmask, Amask);
   163     if (format == SDL_PIXELFORMAT_UNKNOWN) {
   164         SDL_SetError("Unknown pixel format");
   165         return NULL;
   166     }
   167 
   168     return SDL_CreateRGBSurfaceWithFormat(flags, width, height, depth, format);
   169 }
   170 
   171 /*
   172  * Create an RGB surface from an existing memory buffer
   173  */
   174 SDL_Surface *
   175 SDL_CreateRGBSurfaceFrom(void *pixels,
   176                          int width, int height, int depth, int pitch,
   177                          Uint32 Rmask, Uint32 Gmask, Uint32 Bmask,
   178                          Uint32 Amask)
   179 {
   180     SDL_Surface *surface;
   181 
   182     surface = SDL_CreateRGBSurface(0, 0, 0, depth, Rmask, Gmask, Bmask, Amask);
   183     if (surface != NULL) {
   184         surface->flags |= SDL_PREALLOC;
   185         surface->pixels = pixels;
   186         surface->w = width;
   187         surface->h = height;
   188         surface->pitch = pitch;
   189         SDL_SetClipRect(surface, NULL);
   190     }
   191     return surface;
   192 }
   193 
   194 /*
   195  * Create an RGB surface from an existing memory buffer using the given given
   196  * enum SDL_PIXELFORMAT_* format
   197  */
   198 SDL_Surface *
   199 SDL_CreateRGBSurfaceWithFormatFrom(void *pixels,
   200                          int width, int height, int depth, int pitch,
   201                          Uint32 format)
   202 {
   203     SDL_Surface *surface;
   204 
   205     surface = SDL_CreateRGBSurfaceWithFormat(0, 0, 0, depth, format);
   206     if (surface != NULL) {
   207         surface->flags |= SDL_PREALLOC;
   208         surface->pixels = pixels;
   209         surface->w = width;
   210         surface->h = height;
   211         surface->pitch = pitch;
   212         SDL_SetClipRect(surface, NULL);
   213     }
   214     return surface;
   215 }
   216 
   217 int
   218 SDL_SetSurfacePalette(SDL_Surface * surface, SDL_Palette * palette)
   219 {
   220     if (!surface) {
   221         return SDL_SetError("SDL_SetSurfacePalette() passed a NULL surface");
   222     }
   223     if (SDL_SetPixelFormatPalette(surface->format, palette) < 0) {
   224         return -1;
   225     }
   226     SDL_InvalidateMap(surface->map);
   227 
   228     return 0;
   229 }
   230 
   231 int
   232 SDL_SetSurfaceRLE(SDL_Surface * surface, int flag)
   233 {
   234     int flags;
   235 
   236     if (!surface) {
   237         return -1;
   238     }
   239 
   240     flags = surface->map->info.flags;
   241     if (flag) {
   242         surface->map->info.flags |= SDL_COPY_RLE_DESIRED;
   243     } else {
   244         surface->map->info.flags &= ~SDL_COPY_RLE_DESIRED;
   245     }
   246     if (surface->map->info.flags != flags) {
   247         SDL_InvalidateMap(surface->map);
   248     }
   249     return 0;
   250 }
   251 
   252 int
   253 SDL_SetColorKey(SDL_Surface * surface, int flag, Uint32 key)
   254 {
   255     int flags;
   256 
   257     if (!surface) {
   258         return SDL_InvalidParamError("surface");
   259     }
   260 
   261     if (surface->format->palette && key >= ((Uint32) surface->format->palette->ncolors)) {
   262         return SDL_InvalidParamError("key");
   263     }
   264 
   265     if (flag & SDL_RLEACCEL) {
   266         SDL_SetSurfaceRLE(surface, 1);
   267     }
   268 
   269     flags = surface->map->info.flags;
   270     if (flag) {
   271         surface->map->info.flags |= SDL_COPY_COLORKEY;
   272         surface->map->info.colorkey = key;
   273     } else {
   274         surface->map->info.flags &= ~SDL_COPY_COLORKEY;
   275     }
   276     if (surface->map->info.flags != flags) {
   277         SDL_InvalidateMap(surface->map);
   278     }
   279 
   280     return 0;
   281 }
   282 
   283 SDL_bool
   284 SDL_HasColorKey(SDL_Surface * surface)
   285 {
   286     if (!surface) {
   287         return SDL_FALSE;
   288     }
   289 
   290     if (!(surface->map->info.flags & SDL_COPY_COLORKEY)) {
   291         return SDL_FALSE;
   292     }
   293 
   294     return SDL_TRUE;
   295 }
   296 
   297 int
   298 SDL_GetColorKey(SDL_Surface * surface, Uint32 * key)
   299 {
   300     if (!surface) {
   301         return SDL_InvalidParamError("surface");
   302     }
   303 
   304     if (!(surface->map->info.flags & SDL_COPY_COLORKEY)) {
   305         return SDL_SetError("Surface doesn't have a colorkey");
   306     }
   307 
   308     if (key) {
   309         *key = surface->map->info.colorkey;
   310     }
   311     return 0;
   312 }
   313 
   314 /* This is a fairly slow function to switch from colorkey to alpha */
   315 static void
   316 SDL_ConvertColorkeyToAlpha(SDL_Surface * surface, SDL_bool ignore_alpha)
   317 {
   318     int x, y;
   319 
   320     if (!surface) {
   321         return;
   322     }
   323 
   324     if (!(surface->map->info.flags & SDL_COPY_COLORKEY) ||
   325         !surface->format->Amask) {
   326         return;
   327     }
   328 
   329     SDL_LockSurface(surface);
   330 
   331     switch (surface->format->BytesPerPixel) {
   332     case 2:
   333         {
   334             Uint16 *row, *spot;
   335             Uint16 ckey = (Uint16) surface->map->info.colorkey;
   336             Uint16 mask = (Uint16) (~surface->format->Amask);
   337 
   338             /* Ignore, or not, alpha in colorkey comparison */
   339             if (ignore_alpha) {
   340                 ckey &= mask;
   341                 row = (Uint16 *) surface->pixels;
   342                 for (y = surface->h; y--;) {
   343                     spot = row;
   344                     for (x = surface->w; x--;) {
   345                         if ((*spot & mask) == ckey) {
   346                             *spot &= mask;
   347                         }
   348                         ++spot;
   349                     }
   350                     row += surface->pitch / 2;
   351                 }
   352             } else {
   353                 row = (Uint16 *) surface->pixels;
   354                 for (y = surface->h; y--;) {
   355                     spot = row;
   356                     for (x = surface->w; x--;) {
   357                         if (*spot == ckey) {
   358                             *spot &= mask;
   359                         }
   360                         ++spot;
   361                     }
   362                     row += surface->pitch / 2;
   363                 }
   364             }
   365         }
   366         break;
   367     case 3:
   368         /* FIXME */
   369         break;
   370     case 4:
   371         {
   372             Uint32 *row, *spot;
   373             Uint32 ckey = surface->map->info.colorkey;
   374             Uint32 mask = ~surface->format->Amask;
   375 
   376             /* Ignore, or not, alpha in colorkey comparison */
   377             if (ignore_alpha) {
   378                 ckey &= mask;
   379                 row = (Uint32 *) surface->pixels;
   380                 for (y = surface->h; y--;) {
   381                     spot = row;
   382                     for (x = surface->w; x--;) {
   383                         if ((*spot & mask) == ckey) {
   384                             *spot &= mask;
   385                         }
   386                         ++spot;
   387                     }
   388                     row += surface->pitch / 4;
   389                 }
   390             } else {
   391                 row = (Uint32 *) surface->pixels;
   392                 for (y = surface->h; y--;) {
   393                     spot = row;
   394                     for (x = surface->w; x--;) {
   395                         if (*spot == ckey) {
   396                             *spot &= mask;
   397                         }
   398                         ++spot;
   399                     }
   400                     row += surface->pitch / 4;
   401                 }
   402             }
   403         }
   404         break;
   405     }
   406 
   407     SDL_UnlockSurface(surface);
   408 
   409     SDL_SetColorKey(surface, 0, 0);
   410     SDL_SetSurfaceBlendMode(surface, SDL_BLENDMODE_BLEND);
   411 }
   412 
   413 int
   414 SDL_SetSurfaceColorMod(SDL_Surface * surface, Uint8 r, Uint8 g, Uint8 b)
   415 {
   416     int flags;
   417 
   418     if (!surface) {
   419         return -1;
   420     }
   421 
   422     surface->map->info.r = r;
   423     surface->map->info.g = g;
   424     surface->map->info.b = b;
   425 
   426     flags = surface->map->info.flags;
   427     if (r != 0xFF || g != 0xFF || b != 0xFF) {
   428         surface->map->info.flags |= SDL_COPY_MODULATE_COLOR;
   429     } else {
   430         surface->map->info.flags &= ~SDL_COPY_MODULATE_COLOR;
   431     }
   432     if (surface->map->info.flags != flags) {
   433         SDL_InvalidateMap(surface->map);
   434     }
   435     return 0;
   436 }
   437 
   438 
   439 int
   440 SDL_GetSurfaceColorMod(SDL_Surface * surface, Uint8 * r, Uint8 * g, Uint8 * b)
   441 {
   442     if (!surface) {
   443         return -1;
   444     }
   445 
   446     if (r) {
   447         *r = surface->map->info.r;
   448     }
   449     if (g) {
   450         *g = surface->map->info.g;
   451     }
   452     if (b) {
   453         *b = surface->map->info.b;
   454     }
   455     return 0;
   456 }
   457 
   458 int
   459 SDL_SetSurfaceAlphaMod(SDL_Surface * surface, Uint8 alpha)
   460 {
   461     int flags;
   462 
   463     if (!surface) {
   464         return -1;
   465     }
   466 
   467     surface->map->info.a = alpha;
   468 
   469     flags = surface->map->info.flags;
   470     if (alpha != 0xFF) {
   471         surface->map->info.flags |= SDL_COPY_MODULATE_ALPHA;
   472     } else {
   473         surface->map->info.flags &= ~SDL_COPY_MODULATE_ALPHA;
   474     }
   475     if (surface->map->info.flags != flags) {
   476         SDL_InvalidateMap(surface->map);
   477     }
   478     return 0;
   479 }
   480 
   481 int
   482 SDL_GetSurfaceAlphaMod(SDL_Surface * surface, Uint8 * alpha)
   483 {
   484     if (!surface) {
   485         return -1;
   486     }
   487 
   488     if (alpha) {
   489         *alpha = surface->map->info.a;
   490     }
   491     return 0;
   492 }
   493 
   494 int
   495 SDL_SetSurfaceBlendMode(SDL_Surface * surface, SDL_BlendMode blendMode)
   496 {
   497     int flags, status;
   498 
   499     if (!surface) {
   500         return -1;
   501     }
   502 
   503     status = 0;
   504     flags = surface->map->info.flags;
   505     surface->map->info.flags &=
   506         ~(SDL_COPY_BLEND | SDL_COPY_ADD | SDL_COPY_MOD | SDL_COPY_MUL);
   507     switch (blendMode) {
   508     case SDL_BLENDMODE_NONE:
   509         break;
   510     case SDL_BLENDMODE_BLEND:
   511         surface->map->info.flags |= SDL_COPY_BLEND;
   512         break;
   513     case SDL_BLENDMODE_ADD:
   514         surface->map->info.flags |= SDL_COPY_ADD;
   515         break;
   516     case SDL_BLENDMODE_MOD:
   517         surface->map->info.flags |= SDL_COPY_MOD;
   518         break;
   519     case SDL_BLENDMODE_MUL:
   520         surface->map->info.flags |= SDL_COPY_MUL;
   521         break;
   522     default:
   523         status = SDL_Unsupported();
   524         break;
   525     }
   526 
   527     if (surface->map->info.flags != flags) {
   528         SDL_InvalidateMap(surface->map);
   529     }
   530 
   531     return status;
   532 }
   533 
   534 int
   535 SDL_GetSurfaceBlendMode(SDL_Surface * surface, SDL_BlendMode *blendMode)
   536 {
   537     if (!surface) {
   538         return -1;
   539     }
   540 
   541     if (!blendMode) {
   542         return 0;
   543     }
   544 
   545     switch (surface->map->
   546             info.flags & (SDL_COPY_BLEND | SDL_COPY_ADD | SDL_COPY_MOD | SDL_COPY_MUL)) {
   547     case SDL_COPY_BLEND:
   548         *blendMode = SDL_BLENDMODE_BLEND;
   549         break;
   550     case SDL_COPY_ADD:
   551         *blendMode = SDL_BLENDMODE_ADD;
   552         break;
   553     case SDL_COPY_MOD:
   554         *blendMode = SDL_BLENDMODE_MOD;
   555         break;
   556     case SDL_COPY_MUL:
   557         *blendMode = SDL_BLENDMODE_MUL;
   558         break;
   559     default:
   560         *blendMode = SDL_BLENDMODE_NONE;
   561         break;
   562     }
   563     return 0;
   564 }
   565 
   566 SDL_bool
   567 SDL_SetClipRect(SDL_Surface * surface, const SDL_Rect * rect)
   568 {
   569     SDL_Rect full_rect;
   570 
   571     /* Don't do anything if there's no surface to act on */
   572     if (!surface) {
   573         return SDL_FALSE;
   574     }
   575 
   576     /* Set up the full surface rectangle */
   577     full_rect.x = 0;
   578     full_rect.y = 0;
   579     full_rect.w = surface->w;
   580     full_rect.h = surface->h;
   581 
   582     /* Set the clipping rectangle */
   583     if (!rect) {
   584         surface->clip_rect = full_rect;
   585         return SDL_TRUE;
   586     }
   587     return SDL_IntersectRect(rect, &full_rect, &surface->clip_rect);
   588 }
   589 
   590 void
   591 SDL_GetClipRect(SDL_Surface * surface, SDL_Rect * rect)
   592 {
   593     if (surface && rect) {
   594         *rect = surface->clip_rect;
   595     }
   596 }
   597 
   598 /*
   599  * Set up a blit between two surfaces -- split into three parts:
   600  * The upper part, SDL_UpperBlit(), performs clipping and rectangle
   601  * verification.  The lower part is a pointer to a low level
   602  * accelerated blitting function.
   603  *
   604  * These parts are separated out and each used internally by this
   605  * library in the optimimum places.  They are exported so that if
   606  * you know exactly what you are doing, you can optimize your code
   607  * by calling the one(s) you need.
   608  */
   609 int
   610 SDL_LowerBlit(SDL_Surface * src, SDL_Rect * srcrect,
   611               SDL_Surface * dst, SDL_Rect * dstrect)
   612 {
   613     /* Check to make sure the blit mapping is valid */
   614     if ((src->map->dst != dst) ||
   615         (dst->format->palette &&
   616          src->map->dst_palette_version != dst->format->palette->version) ||
   617         (src->format->palette &&
   618          src->map->src_palette_version != src->format->palette->version)) {
   619         if (SDL_MapSurface(src, dst) < 0) {
   620             return (-1);
   621         }
   622         /* just here for debugging */
   623 /*         printf */
   624 /*             ("src = 0x%08X src->flags = %08X src->map->info.flags = %08x\ndst = 0x%08X dst->flags = %08X dst->map->info.flags = %08X\nsrc->map->blit = 0x%08x\n", */
   625 /*              src, dst->flags, src->map->info.flags, dst, dst->flags, */
   626 /*              dst->map->info.flags, src->map->blit); */
   627     }
   628     return (src->map->blit(src, srcrect, dst, dstrect));
   629 }
   630 
   631 
   632 int
   633 SDL_UpperBlit(SDL_Surface * src, const SDL_Rect * srcrect,
   634               SDL_Surface * dst, SDL_Rect * dstrect)
   635 {
   636     SDL_Rect fulldst;
   637     int srcx, srcy, w, h;
   638 
   639     /* Make sure the surfaces aren't locked */
   640     if (!src || !dst) {
   641         return SDL_SetError("SDL_UpperBlit: passed a NULL surface");
   642     }
   643     if (src->locked || dst->locked) {
   644         return SDL_SetError("Surfaces must not be locked during blit");
   645     }
   646 
   647     /* If the destination rectangle is NULL, use the entire dest surface */
   648     if (dstrect == NULL) {
   649         fulldst.x = fulldst.y = 0;
   650         fulldst.w = dst->w;
   651         fulldst.h = dst->h;
   652         dstrect = &fulldst;
   653     }
   654 
   655     /* clip the source rectangle to the source surface */
   656     if (srcrect) {
   657         int maxw, maxh;
   658 
   659         srcx = srcrect->x;
   660         w = srcrect->w;
   661         if (srcx < 0) {
   662             w += srcx;
   663             dstrect->x -= srcx;
   664             srcx = 0;
   665         }
   666         maxw = src->w - srcx;
   667         if (maxw < w)
   668             w = maxw;
   669 
   670         srcy = srcrect->y;
   671         h = srcrect->h;
   672         if (srcy < 0) {
   673             h += srcy;
   674             dstrect->y -= srcy;
   675             srcy = 0;
   676         }
   677         maxh = src->h - srcy;
   678         if (maxh < h)
   679             h = maxh;
   680 
   681     } else {
   682         srcx = srcy = 0;
   683         w = src->w;
   684         h = src->h;
   685     }
   686 
   687     /* clip the destination rectangle against the clip rectangle */
   688     {
   689         SDL_Rect *clip = &dst->clip_rect;
   690         int dx, dy;
   691 
   692         dx = clip->x - dstrect->x;
   693         if (dx > 0) {
   694             w -= dx;
   695             dstrect->x += dx;
   696             srcx += dx;
   697         }
   698         dx = dstrect->x + w - clip->x - clip->w;
   699         if (dx > 0)
   700             w -= dx;
   701 
   702         dy = clip->y - dstrect->y;
   703         if (dy > 0) {
   704             h -= dy;
   705             dstrect->y += dy;
   706             srcy += dy;
   707         }
   708         dy = dstrect->y + h - clip->y - clip->h;
   709         if (dy > 0)
   710             h -= dy;
   711     }
   712 
   713     /* Switch back to a fast blit if we were previously stretching */
   714     if (src->map->info.flags & SDL_COPY_NEAREST) {
   715         src->map->info.flags &= ~SDL_COPY_NEAREST;
   716         SDL_InvalidateMap(src->map);
   717     }
   718 
   719     if (w > 0 && h > 0) {
   720         SDL_Rect sr;
   721         sr.x = srcx;
   722         sr.y = srcy;
   723         sr.w = dstrect->w = w;
   724         sr.h = dstrect->h = h;
   725         return SDL_LowerBlit(src, &sr, dst, dstrect);
   726     }
   727     dstrect->w = dstrect->h = 0;
   728     return 0;
   729 }
   730 
   731 int
   732 SDL_UpperBlitScaled(SDL_Surface * src, const SDL_Rect * srcrect,
   733               SDL_Surface * dst, SDL_Rect * dstrect)
   734 {
   735     double src_x0, src_y0, src_x1, src_y1;
   736     double dst_x0, dst_y0, dst_x1, dst_y1;
   737     SDL_Rect final_src, final_dst;
   738     double scaling_w, scaling_h;
   739     int src_w, src_h;
   740     int dst_w, dst_h;
   741 
   742     /* Make sure the surfaces aren't locked */
   743     if (!src || !dst) {
   744         return SDL_SetError("SDL_UpperBlitScaled: passed a NULL surface");
   745     }
   746     if (src->locked || dst->locked) {
   747         return SDL_SetError("Surfaces must not be locked during blit");
   748     }
   749 
   750     if (NULL == srcrect) {
   751         src_w = src->w;
   752         src_h = src->h;
   753     } else {
   754         src_w = srcrect->w;
   755         src_h = srcrect->h;
   756     }
   757 
   758     if (NULL == dstrect) {
   759         dst_w = dst->w;
   760         dst_h = dst->h;
   761     } else {
   762         dst_w = dstrect->w;
   763         dst_h = dstrect->h;
   764     }
   765 
   766     if (dst_w == src_w && dst_h == src_h) {
   767         /* No scaling, defer to regular blit */
   768         return SDL_BlitSurface(src, srcrect, dst, dstrect);
   769     }
   770 
   771     scaling_w = (double)dst_w / src_w;
   772     scaling_h = (double)dst_h / src_h;
   773 
   774     if (NULL == dstrect) {
   775         dst_x0 = 0;
   776         dst_y0 = 0;
   777         dst_x1 = dst_w - 1;
   778         dst_y1 = dst_h - 1;
   779     } else {
   780         dst_x0 = dstrect->x;
   781         dst_y0 = dstrect->y;
   782         dst_x1 = dst_x0 + dst_w - 1;
   783         dst_y1 = dst_y0 + dst_h - 1;
   784     }
   785 
   786     if (NULL == srcrect) {
   787         src_x0 = 0;
   788         src_y0 = 0;
   789         src_x1 = src_w - 1;
   790         src_y1 = src_h - 1;
   791     } else {
   792         src_x0 = srcrect->x;
   793         src_y0 = srcrect->y;
   794         src_x1 = src_x0 + src_w - 1;
   795         src_y1 = src_y0 + src_h - 1;
   796 
   797         /* Clip source rectangle to the source surface */
   798 
   799         if (src_x0 < 0) {
   800             dst_x0 -= src_x0 * scaling_w;
   801             src_x0 = 0;
   802         }
   803 
   804         if (src_x1 >= src->w) {
   805             dst_x1 -= (src_x1 - src->w + 1) * scaling_w;
   806             src_x1 = src->w - 1;
   807         }
   808 
   809         if (src_y0 < 0) {
   810             dst_y0 -= src_y0 * scaling_h;
   811             src_y0 = 0;
   812         }
   813 
   814         if (src_y1 >= src->h) {
   815             dst_y1 -= (src_y1 - src->h + 1) * scaling_h;
   816             src_y1 = src->h - 1;
   817         }
   818     }
   819 
   820     /* Clip destination rectangle to the clip rectangle */
   821 
   822     /* Translate to clip space for easier calculations */
   823     dst_x0 -= dst->clip_rect.x;
   824     dst_x1 -= dst->clip_rect.x;
   825     dst_y0 -= dst->clip_rect.y;
   826     dst_y1 -= dst->clip_rect.y;
   827 
   828     if (dst_x0 < 0) {
   829         src_x0 -= dst_x0 / scaling_w;
   830         dst_x0 = 0;
   831     }
   832 
   833     if (dst_x1 >= dst->clip_rect.w) {
   834         src_x1 -= (dst_x1 - dst->clip_rect.w + 1) / scaling_w;
   835         dst_x1 = dst->clip_rect.w - 1;
   836     }
   837 
   838     if (dst_y0 < 0) {
   839         src_y0 -= dst_y0 / scaling_h;
   840         dst_y0 = 0;
   841     }
   842 
   843     if (dst_y1 >= dst->clip_rect.h) {
   844         src_y1 -= (dst_y1 - dst->clip_rect.h + 1) / scaling_h;
   845         dst_y1 = dst->clip_rect.h - 1;
   846     }
   847 
   848     /* Translate back to surface coordinates */
   849     dst_x0 += dst->clip_rect.x;
   850     dst_x1 += dst->clip_rect.x;
   851     dst_y0 += dst->clip_rect.y;
   852     dst_y1 += dst->clip_rect.y;
   853 
   854     final_src.x = (int)SDL_floor(src_x0 + 0.5);
   855     final_src.y = (int)SDL_floor(src_y0 + 0.5);
   856     final_src.w = (int)SDL_floor(src_x1 + 1 + 0.5) - (int)SDL_floor(src_x0 + 0.5);
   857     final_src.h = (int)SDL_floor(src_y1 + 1 + 0.5) - (int)SDL_floor(src_y0 + 0.5);
   858 
   859     final_dst.x = (int)SDL_floor(dst_x0 + 0.5);
   860     final_dst.y = (int)SDL_floor(dst_y0 + 0.5);
   861     final_dst.w = (int)SDL_floor(dst_x1 - dst_x0 + 1.5);
   862     final_dst.h = (int)SDL_floor(dst_y1 - dst_y0 + 1.5);
   863 
   864     if (final_dst.w < 0)
   865         final_dst.w = 0;
   866     if (final_dst.h < 0)
   867         final_dst.h = 0;
   868 
   869     if (dstrect)
   870         *dstrect = final_dst;
   871 
   872     if (final_dst.w == 0 || final_dst.h == 0 ||
   873         final_src.w <= 0 || final_src.h <= 0) {
   874         /* No-op. */
   875         return 0;
   876     }
   877 
   878     return SDL_LowerBlitScaled(src, &final_src, dst, &final_dst);
   879 }
   880 
   881 /**
   882  *  This is a semi-private blit function and it performs low-level surface
   883  *  scaled blitting only.
   884  */
   885 int
   886 SDL_LowerBlitScaled(SDL_Surface * src, SDL_Rect * srcrect,
   887                 SDL_Surface * dst, SDL_Rect * dstrect)
   888 {
   889     static const Uint32 complex_copy_flags = (
   890         SDL_COPY_MODULATE_COLOR | SDL_COPY_MODULATE_ALPHA |
   891         SDL_COPY_BLEND | SDL_COPY_ADD | SDL_COPY_MOD | SDL_COPY_MUL |
   892         SDL_COPY_COLORKEY
   893     );
   894 
   895     if (!(src->map->info.flags & SDL_COPY_NEAREST)) {
   896         src->map->info.flags |= SDL_COPY_NEAREST;
   897         SDL_InvalidateMap(src->map);
   898     }
   899 
   900     if ( !(src->map->info.flags & complex_copy_flags) &&
   901          src->format->format == dst->format->format &&
   902          !SDL_ISPIXELFORMAT_INDEXED(src->format->format) ) {
   903         return SDL_SoftStretch( src, srcrect, dst, dstrect );
   904     } else {
   905         return SDL_LowerBlit( src, srcrect, dst, dstrect );
   906     }
   907 }
   908 
   909 /*
   910  * Lock a surface to directly access the pixels
   911  */
   912 int
   913 SDL_LockSurface(SDL_Surface * surface)
   914 {
   915     if (!surface->locked) {
   916 #if SDL_HAVE_RLE
   917         /* Perform the lock */
   918         if (surface->flags & SDL_RLEACCEL) {
   919             SDL_UnRLESurface(surface, 1);
   920             surface->flags |= SDL_RLEACCEL;     /* save accel'd state */
   921         }
   922 #endif
   923     }
   924 
   925     /* Increment the surface lock count, for recursive locks */
   926     ++surface->locked;
   927 
   928     /* Ready to go.. */
   929     return (0);
   930 }
   931 
   932 /*
   933  * Unlock a previously locked surface
   934  */
   935 void
   936 SDL_UnlockSurface(SDL_Surface * surface)
   937 {
   938     /* Only perform an unlock if we are locked */
   939     if (!surface->locked || (--surface->locked > 0)) {
   940         return;
   941     }
   942 
   943 #if SDL_HAVE_RLE
   944     /* Update RLE encoded surface with new data */
   945     if ((surface->flags & SDL_RLEACCEL) == SDL_RLEACCEL) {
   946         surface->flags &= ~SDL_RLEACCEL;        /* stop lying */
   947         SDL_RLESurface(surface);
   948     }
   949 #endif
   950 }
   951 
   952 /*
   953  * Creates a new surface identical to the existing surface
   954  */
   955 SDL_Surface *
   956 SDL_DuplicateSurface(SDL_Surface * surface)
   957 {
   958     return SDL_ConvertSurface(surface, surface->format, surface->flags);
   959 }
   960 
   961 /*
   962  * Convert a surface into the specified pixel format.
   963  */
   964 SDL_Surface *
   965 SDL_ConvertSurface(SDL_Surface * surface, const SDL_PixelFormat * format,
   966                    Uint32 flags)
   967 {
   968     SDL_Surface *convert;
   969     Uint32 copy_flags;
   970     SDL_Color copy_color;
   971     SDL_Rect bounds;
   972     int ret;
   973     SDL_bool palette_ck_transform = SDL_FALSE;
   974     int palette_ck_value = 0;
   975     SDL_bool palette_has_alpha = SDL_FALSE;
   976     Uint8 *palette_saved_alpha = NULL;
   977 
   978     if (!surface) {
   979         SDL_InvalidParamError("surface");
   980         return NULL;
   981     }
   982     if (!format) {
   983         SDL_InvalidParamError("format");
   984         return NULL;
   985     }
   986 
   987     /* Check for empty destination palette! (results in empty image) */
   988     if (format->palette != NULL) {
   989         int i;
   990         for (i = 0; i < format->palette->ncolors; ++i) {
   991             if ((format->palette->colors[i].r != 0xFF) ||
   992                 (format->palette->colors[i].g != 0xFF) ||
   993                 (format->palette->colors[i].b != 0xFF))
   994                 break;
   995         }
   996         if (i == format->palette->ncolors) {
   997             SDL_SetError("Empty destination palette");
   998             return (NULL);
   999         }
  1000     }
  1001 
  1002     /* Create a new surface with the desired format */
  1003     convert = SDL_CreateRGBSurface(flags, surface->w, surface->h,
  1004                                    format->BitsPerPixel, format->Rmask,
  1005                                    format->Gmask, format->Bmask,
  1006                                    format->Amask);
  1007     if (convert == NULL) {
  1008         return (NULL);
  1009     }
  1010 
  1011     /* Copy the palette if any */
  1012     if (format->palette && convert->format->palette) {
  1013         SDL_memcpy(convert->format->palette->colors,
  1014                    format->palette->colors,
  1015                    format->palette->ncolors * sizeof(SDL_Color));
  1016         convert->format->palette->ncolors = format->palette->ncolors;
  1017     }
  1018 
  1019     /* Save the original copy flags */
  1020     copy_flags = surface->map->info.flags;
  1021     copy_color.r = surface->map->info.r;
  1022     copy_color.g = surface->map->info.g;
  1023     copy_color.b = surface->map->info.b;
  1024     copy_color.a = surface->map->info.a;
  1025     surface->map->info.r = 0xFF;
  1026     surface->map->info.g = 0xFF;
  1027     surface->map->info.b = 0xFF;
  1028     surface->map->info.a = 0xFF;
  1029     surface->map->info.flags = 0;
  1030     SDL_InvalidateMap(surface->map);
  1031 
  1032     /* Copy over the image data */
  1033     bounds.x = 0;
  1034     bounds.y = 0;
  1035     bounds.w = surface->w;
  1036     bounds.h = surface->h;
  1037 
  1038     /* Source surface has a palette with no real alpha (0 or OPAQUE).
  1039      * Destination format has alpha.
  1040      * -> set alpha channel to be opaque */
  1041     if (surface->format->palette && format->Amask) {
  1042         SDL_bool set_opaque = SDL_FALSE;
  1043 
  1044         SDL_bool is_opaque, has_alpha_channel;
  1045         SDL_DetectPalette(surface->format->palette, &is_opaque, &has_alpha_channel);
  1046 
  1047         if (is_opaque) {
  1048             if (!has_alpha_channel) {
  1049                 set_opaque = SDL_TRUE;
  1050             }
  1051         } else {
  1052             palette_has_alpha = SDL_TRUE;
  1053         }
  1054 
  1055         /* Set opaque and backup palette alpha values */
  1056         if (set_opaque) {
  1057             int i;
  1058             palette_saved_alpha = SDL_stack_alloc(Uint8, surface->format->palette->ncolors);
  1059             for (i = 0; i < surface->format->palette->ncolors; i++) {
  1060                 palette_saved_alpha[i] = surface->format->palette->colors[i].a;
  1061                 surface->format->palette->colors[i].a = SDL_ALPHA_OPAQUE;
  1062             }
  1063         }
  1064     }
  1065 
  1066     /* Transform colorkey to alpha. for cases where source palette has duplicate values, and colorkey is one of them */
  1067     if (copy_flags & SDL_COPY_COLORKEY) {
  1068         if (surface->format->palette && !format->palette) {
  1069             palette_ck_transform = SDL_TRUE;
  1070             palette_has_alpha = SDL_TRUE;
  1071             palette_ck_value = surface->format->palette->colors[surface->map->info.colorkey].a;
  1072             surface->format->palette->colors[surface->map->info.colorkey].a = SDL_ALPHA_TRANSPARENT;
  1073         }
  1074     }
  1075 
  1076     ret = SDL_LowerBlit(surface, &bounds, convert, &bounds);
  1077 
  1078     /* Restore colorkey alpha value */
  1079     if (palette_ck_transform) {
  1080         surface->format->palette->colors[surface->map->info.colorkey].a = palette_ck_value;
  1081     }
  1082 
  1083     /* Restore palette alpha values */
  1084     if (palette_saved_alpha) {
  1085         int i;
  1086         for (i = 0; i < surface->format->palette->ncolors; i++) {
  1087             surface->format->palette->colors[i].a = palette_saved_alpha[i];
  1088         }
  1089         SDL_stack_free(palette_saved_alpha);
  1090     }
  1091 
  1092     /* Clean up the original surface, and update converted surface */
  1093     convert->map->info.r = copy_color.r;
  1094     convert->map->info.g = copy_color.g;
  1095     convert->map->info.b = copy_color.b;
  1096     convert->map->info.a = copy_color.a;
  1097     convert->map->info.flags =
  1098         (copy_flags &
  1099          ~(SDL_COPY_COLORKEY | SDL_COPY_BLEND
  1100            | SDL_COPY_RLE_DESIRED | SDL_COPY_RLE_COLORKEY |
  1101            SDL_COPY_RLE_ALPHAKEY));
  1102     surface->map->info.r = copy_color.r;
  1103     surface->map->info.g = copy_color.g;
  1104     surface->map->info.b = copy_color.b;
  1105     surface->map->info.a = copy_color.a;
  1106     surface->map->info.flags = copy_flags;
  1107     SDL_InvalidateMap(surface->map);
  1108 
  1109     /* SDL_LowerBlit failed, and so the conversion */
  1110     if (ret < 0) {
  1111         SDL_FreeSurface(convert);
  1112         return NULL;
  1113     }
  1114 
  1115     if (copy_flags & SDL_COPY_COLORKEY) {
  1116         SDL_bool set_colorkey_by_color = SDL_FALSE;
  1117         SDL_bool convert_colorkey = SDL_TRUE;
  1118 
  1119         if (surface->format->palette) {
  1120             if (format->palette &&
  1121                 surface->format->palette->ncolors <= format->palette->ncolors &&
  1122                 (SDL_memcmp(surface->format->palette->colors, format->palette->colors,
  1123                   surface->format->palette->ncolors * sizeof(SDL_Color)) == 0)) {
  1124                 /* The palette is identical, just set the same colorkey */
  1125                 SDL_SetColorKey(convert, 1, surface->map->info.colorkey);
  1126             } else if (!format->palette) {
  1127                 if (format->Amask) {
  1128                     /* No need to add the colorkey, transparency is in the alpha channel*/
  1129                 } else {
  1130                     /* Only set the colorkey information */
  1131                     set_colorkey_by_color = SDL_TRUE;
  1132                     convert_colorkey = SDL_FALSE;
  1133                 }
  1134             } else {
  1135                 set_colorkey_by_color = SDL_TRUE;
  1136             }
  1137         } else {
  1138             set_colorkey_by_color = SDL_TRUE;
  1139         }
  1140 
  1141         if (set_colorkey_by_color) {
  1142             SDL_Surface *tmp;
  1143             SDL_Surface *tmp2;
  1144             int converted_colorkey = 0;
  1145 
  1146             /* Create a dummy surface to get the colorkey converted */
  1147             tmp = SDL_CreateRGBSurface(0, 1, 1,
  1148                                    surface->format->BitsPerPixel, surface->format->Rmask,
  1149                                    surface->format->Gmask, surface->format->Bmask,
  1150                                    surface->format->Amask);
  1151 
  1152             /* Share the palette, if any */
  1153             if (surface->format->palette) {
  1154                 SDL_SetSurfacePalette(tmp, surface->format->palette);
  1155             }
  1156 
  1157             SDL_FillRect(tmp, NULL, surface->map->info.colorkey);
  1158 
  1159             tmp->map->info.flags &= ~SDL_COPY_COLORKEY;
  1160 
  1161             /* Convertion of the colorkey */
  1162             tmp2 = SDL_ConvertSurface(tmp, format, 0);
  1163 
  1164             /* Get the converted colorkey */
  1165             SDL_memcpy(&converted_colorkey, tmp2->pixels, tmp2->format->BytesPerPixel);
  1166 
  1167             SDL_FreeSurface(tmp);
  1168             SDL_FreeSurface(tmp2);
  1169 
  1170             /* Set the converted colorkey on the new surface */
  1171             SDL_SetColorKey(convert, 1, converted_colorkey);
  1172 
  1173             /* This is needed when converting for 3D texture upload */
  1174             if (convert_colorkey) {
  1175                 SDL_ConvertColorkeyToAlpha(convert, SDL_TRUE);
  1176             }
  1177         }
  1178     }
  1179     SDL_SetClipRect(convert, &surface->clip_rect);
  1180 
  1181     /* Enable alpha blending by default if the new surface has an
  1182      * alpha channel or alpha modulation */
  1183     if ((surface->format->Amask && format->Amask) ||
  1184         (palette_has_alpha && format->Amask) ||
  1185         (copy_flags & SDL_COPY_MODULATE_ALPHA)) {
  1186         SDL_SetSurfaceBlendMode(convert, SDL_BLENDMODE_BLEND);
  1187     }
  1188     if ((copy_flags & SDL_COPY_RLE_DESIRED) || (flags & SDL_RLEACCEL)) {
  1189         SDL_SetSurfaceRLE(convert, SDL_RLEACCEL);
  1190     }
  1191 
  1192     /* We're ready to go! */
  1193     return (convert);
  1194 }
  1195 
  1196 SDL_Surface *
  1197 SDL_ConvertSurfaceFormat(SDL_Surface * surface, Uint32 pixel_format,
  1198                          Uint32 flags)
  1199 {
  1200     SDL_PixelFormat *fmt;
  1201     SDL_Surface *convert = NULL;
  1202 
  1203     fmt = SDL_AllocFormat(pixel_format);
  1204     if (fmt) {
  1205         convert = SDL_ConvertSurface(surface, fmt, flags);
  1206         SDL_FreeFormat(fmt);
  1207     }
  1208     return convert;
  1209 }
  1210 
  1211 /*
  1212  * Create a surface on the stack for quick blit operations
  1213  */
  1214 static SDL_INLINE SDL_bool
  1215 SDL_CreateSurfaceOnStack(int width, int height, Uint32 pixel_format,
  1216                          void * pixels, int pitch, SDL_Surface * surface,
  1217                          SDL_PixelFormat * format, SDL_BlitMap * blitmap)
  1218 {
  1219     if (SDL_ISPIXELFORMAT_INDEXED(pixel_format)) {
  1220         SDL_SetError("Indexed pixel formats not supported");
  1221         return SDL_FALSE;
  1222     }
  1223     if (SDL_InitFormat(format, pixel_format) < 0) {
  1224         return SDL_FALSE;
  1225     }
  1226 
  1227     SDL_zerop(surface);
  1228     surface->flags = SDL_PREALLOC;
  1229     surface->format = format;
  1230     surface->pixels = pixels;
  1231     surface->w = width;
  1232     surface->h = height;
  1233     surface->pitch = pitch;
  1234     /* We don't actually need to set up the clip rect for our purposes */
  1235     /* SDL_SetClipRect(surface, NULL); */
  1236 
  1237     /* Allocate an empty mapping */
  1238     SDL_zerop(blitmap);
  1239     blitmap->info.r = 0xFF;
  1240     blitmap->info.g = 0xFF;
  1241     blitmap->info.b = 0xFF;
  1242     blitmap->info.a = 0xFF;
  1243     surface->map = blitmap;
  1244 
  1245     /* The surface is ready to go */
  1246     surface->refcount = 1;
  1247     return SDL_TRUE;
  1248 }
  1249 
  1250 /*
  1251  * Copy a block of pixels of one format to another format
  1252  */
  1253 int SDL_ConvertPixels(int width, int height,
  1254                       Uint32 src_format, const void * src, int src_pitch,
  1255                       Uint32 dst_format, void * dst, int dst_pitch)
  1256 {
  1257     SDL_Surface src_surface, dst_surface;
  1258     SDL_PixelFormat src_fmt, dst_fmt;
  1259     SDL_BlitMap src_blitmap, dst_blitmap;
  1260     SDL_Rect rect;
  1261     void *nonconst_src = (void *) src;
  1262 
  1263     /* Check to make sure we are blitting somewhere, so we don't crash */
  1264     if (!dst) {
  1265         return SDL_InvalidParamError("dst");
  1266     }
  1267     if (!dst_pitch) {
  1268         return SDL_InvalidParamError("dst_pitch");
  1269     }
  1270 
  1271 #if SDL_HAVE_YUV
  1272     if (SDL_ISPIXELFORMAT_FOURCC(src_format) && SDL_ISPIXELFORMAT_FOURCC(dst_format)) {
  1273         return SDL_ConvertPixels_YUV_to_YUV(width, height, src_format, src, src_pitch, dst_format, dst, dst_pitch);
  1274     } else if (SDL_ISPIXELFORMAT_FOURCC(src_format)) {
  1275         return SDL_ConvertPixels_YUV_to_RGB(width, height, src_format, src, src_pitch, dst_format, dst, dst_pitch);
  1276     } else if (SDL_ISPIXELFORMAT_FOURCC(dst_format)) {
  1277         return SDL_ConvertPixels_RGB_to_YUV(width, height, src_format, src, src_pitch, dst_format, dst, dst_pitch);
  1278     }
  1279 #else
  1280     if (SDL_ISPIXELFORMAT_FOURCC(src_format) || SDL_ISPIXELFORMAT_FOURCC(dst_format)) {
  1281         SDL_SetError("SDL not built with YUV support");
  1282         return -1;
  1283     }
  1284 #endif
  1285 
  1286     /* Fast path for same format copy */
  1287     if (src_format == dst_format) {
  1288         int i;
  1289         const int bpp = SDL_BYTESPERPIXEL(src_format);
  1290         width *= bpp;
  1291         for (i = height; i--;) {
  1292             SDL_memcpy(dst, src, width);
  1293             src = (const Uint8*)src + src_pitch;
  1294             dst = (Uint8*)dst + dst_pitch;
  1295         }
  1296         return 0;
  1297     }
  1298 
  1299     if (!SDL_CreateSurfaceOnStack(width, height, src_format, nonconst_src,
  1300                                   src_pitch,
  1301                                   &src_surface, &src_fmt, &src_blitmap)) {
  1302         return -1;
  1303     }
  1304     if (!SDL_CreateSurfaceOnStack(width, height, dst_format, dst, dst_pitch,
  1305                                   &dst_surface, &dst_fmt, &dst_blitmap)) {
  1306         return -1;
  1307     }
  1308 
  1309     /* Set up the rect and go! */
  1310     rect.x = 0;
  1311     rect.y = 0;
  1312     rect.w = width;
  1313     rect.h = height;
  1314     return SDL_LowerBlit(&src_surface, &rect, &dst_surface, &rect);
  1315 }
  1316 
  1317 /*
  1318  * Free a surface created by the above function.
  1319  */
  1320 void
  1321 SDL_FreeSurface(SDL_Surface * surface)
  1322 {
  1323     if (surface == NULL) {
  1324         return;
  1325     }
  1326     if (surface->flags & SDL_DONTFREE) {
  1327         return;
  1328     }
  1329     SDL_InvalidateMap(surface->map);
  1330 
  1331     if (--surface->refcount > 0) {
  1332         return;
  1333     }
  1334     while (surface->locked > 0) {
  1335         SDL_UnlockSurface(surface);
  1336     }
  1337 #if SDL_HAVE_RLE
  1338     if (surface->flags & SDL_RLEACCEL) {
  1339         SDL_UnRLESurface(surface, 0);
  1340     }
  1341 #endif
  1342     if (surface->format) {
  1343         SDL_SetSurfacePalette(surface, NULL);
  1344         SDL_FreeFormat(surface->format);
  1345         surface->format = NULL;
  1346     }
  1347     if (surface->flags & SDL_PREALLOC) {
  1348         /* Don't free */
  1349     } else if (surface->flags & SDL_SIMD_ALIGNED) {
  1350         /* Free aligned */
  1351         SDL_SIMDFree(surface->pixels);
  1352     } else {
  1353         /* Normal */
  1354         SDL_free(surface->pixels);
  1355     }
  1356     if (surface->map) {
  1357         SDL_FreeBlitMap(surface->map);
  1358     }
  1359     SDL_free(surface);
  1360 }
  1361 
  1362 /* vi: set ts=4 sw=4 expandtab: */