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