src/video/SDL_surface.c
author Sam Lantinga <slouken@libsdl.org>
Tue, 25 Nov 2008 05:29:14 +0000
changeset 2787 93764fe8601a
parent 2786 6bacfecbf27e
child 2807 365fe1a2aad5
permissions -rw-r--r--
It turns out both the software and the OpenGL renderer had the same problem.
According to the spec, when SDL_SRCALPHA is set, the colorkey is ignored, so
we just need to convert the colorkey into the alpha channel.
     1 /*
     2     SDL - Simple DirectMedia Layer
     3     Copyright (C) 1997-2006 Sam Lantinga
     4 
     5     This library is free software; you can redistribute it and/or
     6     modify it under the terms of the GNU Lesser General Public
     7     License as published by the Free Software Foundation; either
     8     version 2.1 of the License, or (at your option) any later version.
     9 
    10     This library is distributed in the hope that it will be useful,
    11     but WITHOUT ANY WARRANTY; without even the implied warranty of
    12     MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
    13     Lesser General Public License for more details.
    14 
    15     You should have received a copy of the GNU Lesser General Public
    16     License along with this library; if not, write to the Free Software
    17     Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
    18 
    19     Sam Lantinga
    20     slouken@libsdl.org
    21 */
    22 #include "SDL_config.h"
    23 
    24 #include "SDL_video.h"
    25 #include "SDL_compat.h"
    26 #include "SDL_sysvideo.h"
    27 #include "SDL_blit.h"
    28 #include "SDL_RLEaccel_c.h"
    29 #include "SDL_pixels_c.h"
    30 #include "SDL_leaks.h"
    31 
    32 
    33 /* Public routines */
    34 /*
    35  * Create an empty RGB surface of the appropriate depth
    36  */
    37 SDL_Surface *
    38 SDL_CreateRGBSurface(Uint32 flags,
    39                      int width, int height, int depth,
    40                      Uint32 Rmask, Uint32 Gmask, Uint32 Bmask, Uint32 Amask)
    41 {
    42     SDL_Surface *surface;
    43 
    44     /* Allocate the surface */
    45     surface = (SDL_Surface *) SDL_calloc(1, sizeof(*surface));
    46     if (surface == NULL) {
    47         SDL_OutOfMemory();
    48         return NULL;
    49     }
    50 
    51     surface->format = SDL_AllocFormat(depth, Rmask, Gmask, Bmask, Amask);
    52     if (!surface->format) {
    53         SDL_FreeSurface(surface);
    54         return NULL;
    55     }
    56     surface->w = width;
    57     surface->h = height;
    58     surface->pitch = SDL_CalculatePitch(surface);
    59     SDL_SetClipRect(surface, NULL);
    60 
    61     if (surface->format->BitsPerPixel <= 8) {
    62         SDL_Palette *palette =
    63             SDL_AllocPalette((1 << surface->format->BitsPerPixel));
    64         if (!palette) {
    65             SDL_FreeSurface(surface);
    66             return NULL;
    67         }
    68         if (Rmask || Bmask || Gmask) {
    69             const SDL_PixelFormat *format = surface->format;
    70 
    71             /* create palette according to masks */
    72             int i;
    73             int Rm = 0, Gm = 0, Bm = 0;
    74             int Rw = 0, Gw = 0, Bw = 0;
    75 
    76             if (Rmask) {
    77                 Rw = 8 - format->Rloss;
    78                 for (i = format->Rloss; i > 0; i -= Rw)
    79                     Rm |= 1 << i;
    80             }
    81             if (Gmask) {
    82                 Gw = 8 - format->Gloss;
    83                 for (i = format->Gloss; i > 0; i -= Gw)
    84                     Gm |= 1 << i;
    85             }
    86             if (Bmask) {
    87                 Bw = 8 - format->Bloss;
    88                 for (i = format->Bloss; i > 0; i -= Bw)
    89                     Bm |= 1 << i;
    90             }
    91             for (i = 0; i < palette->ncolors; ++i) {
    92                 int r, g, b;
    93                 r = (i & Rmask) >> format->Rshift;
    94                 r = (r << format->Rloss) | ((r * Rm) >> Rw);
    95                 palette->colors[i].r = r;
    96 
    97                 g = (i & Gmask) >> format->Gshift;
    98                 g = (g << format->Gloss) | ((g * Gm) >> Gw);
    99                 palette->colors[i].g = g;
   100 
   101                 b = (i & Bmask) >> format->Bshift;
   102                 b = (b << format->Bloss) | ((b * Bm) >> Bw);
   103                 palette->colors[i].b = b;
   104             }
   105         } else if (palette->ncolors == 2) {
   106             /* Create a black and white bitmap palette */
   107             palette->colors[0].r = 0xFF;
   108             palette->colors[0].g = 0xFF;
   109             palette->colors[0].b = 0xFF;
   110             palette->colors[1].r = 0x00;
   111             palette->colors[1].g = 0x00;
   112             palette->colors[1].b = 0x00;
   113         }
   114         SDL_SetSurfacePalette(surface, palette);
   115         SDL_FreePalette(palette);
   116     }
   117 
   118     /* Get the pixels */
   119     if (surface->w && surface->h) {
   120         surface->pixels = SDL_malloc(surface->h * surface->pitch);
   121         if (!surface->pixels) {
   122             SDL_FreeSurface(surface);
   123             SDL_OutOfMemory();
   124             return NULL;
   125         }
   126         /* This is important for bitmaps */
   127         SDL_memset(surface->pixels, 0, surface->h * surface->pitch);
   128     }
   129 
   130     /* Allocate an empty mapping */
   131     surface->map = SDL_AllocBlitMap();
   132     if (!surface->map) {
   133         SDL_FreeSurface(surface);
   134         return NULL;
   135     }
   136     SDL_FormatChanged(surface);
   137 
   138     /* By default surface with an alpha mask are set up for blending */
   139     if (Amask) {
   140         SDL_SetSurfaceBlendMode(surface, SDL_TEXTUREBLENDMODE_BLEND);
   141     }
   142 
   143     /* The surface is ready to go */
   144     surface->refcount = 1;
   145 #ifdef CHECK_LEAKS
   146     ++surfaces_allocated;
   147 #endif
   148     return surface;
   149 }
   150 
   151 /*
   152  * Create an RGB surface from an existing memory buffer
   153  */
   154 SDL_Surface *
   155 SDL_CreateRGBSurfaceFrom(void *pixels,
   156                          int width, int height, int depth, int pitch,
   157                          Uint32 Rmask, Uint32 Gmask, Uint32 Bmask,
   158                          Uint32 Amask)
   159 {
   160     SDL_Surface *surface;
   161 
   162     surface =
   163         SDL_CreateRGBSurface(0, 0, 0, depth, Rmask, Gmask, Bmask, Amask);
   164     if (surface != NULL) {
   165         surface->flags |= SDL_PREALLOC;
   166         surface->pixels = pixels;
   167         surface->w = width;
   168         surface->h = height;
   169         surface->pitch = pitch;
   170         SDL_SetClipRect(surface, NULL);
   171     }
   172     return surface;
   173 }
   174 
   175 static int
   176 SDL_SurfacePaletteChanged(void *userdata, SDL_Palette * palette)
   177 {
   178     SDL_Surface *surface = (SDL_Surface *) userdata;
   179 
   180     SDL_FormatChanged(surface);
   181 
   182     return 0;
   183 }
   184 
   185 int
   186 SDL_SetSurfacePalette(SDL_Surface * surface, SDL_Palette * palette)
   187 {
   188     if (!surface || !surface->format) {
   189         SDL_SetError("SDL_SetSurfacePalette() passed a NULL surface");
   190         return -1;
   191     }
   192 
   193     if (palette && palette->ncolors != (1 << surface->format->BitsPerPixel)) {
   194         SDL_SetError
   195             ("SDL_SetSurfacePalette() passed a palette that doesn't match the surface format");
   196         return -1;
   197     }
   198 
   199     if (surface->format->palette == palette) {
   200         return 0;
   201     }
   202 
   203     if (surface->format->palette) {
   204         SDL_DelPaletteWatch(surface->format->palette,
   205                             SDL_SurfacePaletteChanged, surface);
   206     }
   207 
   208     surface->format->palette = palette;
   209 
   210     if (surface->format->palette) {
   211         SDL_AddPaletteWatch(surface->format->palette,
   212                             SDL_SurfacePaletteChanged, surface);
   213     }
   214     return 0;
   215 }
   216 
   217 int
   218 SDL_SetSurfaceRLE(SDL_Surface * surface, int flag)
   219 {
   220     int flags;
   221 
   222     if (!surface) {
   223         return -1;
   224     }
   225 
   226     flags = surface->map->info.flags;
   227     if (flag) {
   228         surface->map->info.flags |= SDL_COPY_RLE_DESIRED;
   229     } else {
   230         surface->map->info.flags &= ~SDL_COPY_RLE_DESIRED;
   231     }
   232     if (surface->map->info.flags != flags) {
   233         SDL_InvalidateMap(surface->map);
   234     }
   235     return 0;
   236 }
   237 
   238 int
   239 SDL_SetColorKey(SDL_Surface * surface, Uint32 flag, Uint32 key)
   240 {
   241     int flags;
   242 
   243     if (!surface) {
   244         return -1;
   245     }
   246 
   247     if (flag & SDL_RLEACCEL) {
   248         SDL_SetSurfaceRLE(surface, 1);
   249     }
   250 
   251     flags = surface->map->info.flags;
   252     if (flag) {
   253         surface->map->info.flags |= SDL_COPY_COLORKEY;
   254         surface->map->info.colorkey = key;
   255     } else {
   256         surface->map->info.flags &= ~SDL_COPY_COLORKEY;
   257     }
   258     if (surface->map->info.flags != flags) {
   259         SDL_InvalidateMap(surface->map);
   260     }
   261 
   262     /* Compatibility mode */
   263     if (surface->map->info.flags & SDL_COPY_COLORKEY) {
   264         surface->flags |= SDL_SRCCOLORKEY;
   265     } else {
   266         surface->flags &= ~SDL_SRCCOLORKEY;
   267     }
   268 
   269     return 0;
   270 }
   271 
   272 /* This is a fairly slow function to switch from colorkey to alpha */
   273 static void
   274 SDL_ConvertColorkeyToAlpha(SDL_Surface * surface)
   275 {
   276     int x, y;
   277 
   278     if (!surface) {
   279         return;
   280     }
   281 
   282     if (!(surface->map->info.flags & SDL_COPY_COLORKEY) ||
   283         !surface->format->Amask) {
   284         return;
   285     }
   286 
   287     SDL_LockSurface(surface);
   288 
   289     switch (surface->format->BytesPerPixel) {
   290     case 2:
   291         {
   292             Uint16 *row, *spot;
   293             Uint16 ckey = (Uint16) surface->map->info.colorkey;
   294             Uint16 mask = (Uint16) (~surface->format->Amask);
   295 
   296             row = (Uint16 *) surface->pixels;
   297             for (y = surface->h; y--;) {
   298                 spot = row;
   299                 for (x = surface->w; x--;) {
   300                     if (*spot == ckey) {
   301                         *spot &= mask;
   302                     }
   303                     ++spot;
   304                 }
   305                 row += surface->pitch / 2;
   306             }
   307         }
   308         break;
   309     case 3:
   310         /* FIXME */
   311         break;
   312     case 4:
   313         {
   314             Uint32 *row, *spot;
   315             Uint32 ckey = surface->map->info.colorkey;
   316             Uint32 mask = ~surface->format->Amask;
   317 
   318             row = (Uint32 *) surface->pixels;
   319             for (y = surface->h; y--;) {
   320                 spot = row;
   321                 for (x = surface->w; x--;) {
   322                     if (*spot == ckey) {
   323                         *spot &= mask;
   324                     }
   325                     ++spot;
   326                 }
   327                 row += surface->pitch / 4;
   328             }
   329         }
   330         break;
   331     }
   332 
   333     SDL_UnlockSurface(surface);
   334 
   335     SDL_SetColorKey(surface, 0, 0);
   336 }
   337 
   338 int
   339 SDL_SetSurfaceColorMod(SDL_Surface * surface, Uint8 r, Uint8 g, Uint8 b)
   340 {
   341     int flags;
   342 
   343     if (!surface) {
   344         return -1;
   345     }
   346 
   347     surface->map->info.r = r;
   348     surface->map->info.g = g;
   349     surface->map->info.b = b;
   350 
   351     flags = surface->map->info.flags;
   352     if (r != 0xFF || g != 0xFF || b != 0xFF) {
   353         surface->map->info.flags |= SDL_COPY_MODULATE_COLOR;
   354     } else {
   355         surface->map->info.flags &= ~SDL_COPY_MODULATE_COLOR;
   356     }
   357     if (surface->map->info.flags != flags) {
   358         SDL_InvalidateMap(surface->map);
   359     }
   360     return 0;
   361 }
   362 
   363 
   364 int
   365 SDL_GetSurfaceColorMod(SDL_Surface * surface, Uint8 * r, Uint8 * g, Uint8 * b)
   366 {
   367     if (!surface) {
   368         return -1;
   369     }
   370 
   371     if (r) {
   372         *r = surface->map->info.r;
   373     }
   374     if (g) {
   375         *g = surface->map->info.g;
   376     }
   377     if (b) {
   378         *b = surface->map->info.b;
   379     }
   380     return 0;
   381 }
   382 
   383 int
   384 SDL_SetSurfaceAlphaMod(SDL_Surface * surface, Uint8 alpha)
   385 {
   386     int flags;
   387 
   388     if (!surface) {
   389         return -1;
   390     }
   391 
   392     surface->map->info.a = alpha;
   393 
   394     flags = surface->map->info.flags;
   395     if (alpha != 0xFF) {
   396         surface->map->info.flags |= SDL_COPY_MODULATE_ALPHA;
   397     } else {
   398         surface->map->info.flags &= ~SDL_COPY_MODULATE_ALPHA;
   399     }
   400     if (surface->map->info.flags != flags) {
   401         SDL_InvalidateMap(surface->map);
   402     }
   403     return 0;
   404 }
   405 
   406 int
   407 SDL_GetSurfaceAlphaMod(SDL_Surface * surface, Uint8 * alpha)
   408 {
   409     if (!surface) {
   410         return -1;
   411     }
   412 
   413     if (alpha) {
   414         *alpha = surface->map->info.a;
   415     }
   416     return 0;
   417 }
   418 
   419 int
   420 SDL_SetSurfaceBlendMode(SDL_Surface * surface, int blendMode)
   421 {
   422     int flags, status;
   423 
   424     if (!surface) {
   425         return -1;
   426     }
   427 
   428     status = 0;
   429     flags = surface->map->info.flags;
   430     surface->map->info.flags &=
   431         ~(SDL_COPY_MASK | SDL_COPY_BLEND | SDL_COPY_ADD | SDL_COPY_MOD);
   432     switch (blendMode) {
   433     case SDL_TEXTUREBLENDMODE_NONE:
   434         break;
   435     case SDL_TEXTUREBLENDMODE_MASK:
   436         surface->map->info.flags |= SDL_COPY_MASK;
   437         break;
   438     case SDL_TEXTUREBLENDMODE_BLEND:
   439         surface->map->info.flags |= SDL_COPY_BLEND;
   440         break;
   441     case SDL_TEXTUREBLENDMODE_ADD:
   442         surface->map->info.flags |= SDL_COPY_ADD;
   443         break;
   444     case SDL_TEXTUREBLENDMODE_MOD:
   445         surface->map->info.flags |= SDL_COPY_MOD;
   446         break;
   447     default:
   448         SDL_Unsupported();
   449         status = -1;
   450         break;
   451     }
   452 
   453     if (surface->map->info.flags != flags) {
   454         SDL_InvalidateMap(surface->map);
   455     }
   456 
   457     /* Compatibility mode */
   458     if (surface->map->info.flags & SDL_COPY_BLEND) {
   459         surface->flags |= SDL_SRCALPHA;
   460     } else {
   461         surface->flags &= ~SDL_SRCALPHA;
   462     }
   463 
   464     return status;
   465 }
   466 
   467 int
   468 SDL_GetSurfaceBlendMode(SDL_Surface * surface, int *blendMode)
   469 {
   470     if (!surface) {
   471         return -1;
   472     }
   473 
   474     if (!blendMode) {
   475         return 0;
   476     }
   477 
   478     switch (surface->map->
   479             info.flags & (SDL_COPY_MASK | SDL_COPY_BLEND | SDL_COPY_ADD |
   480                           SDL_COPY_MOD)) {
   481     case SDL_COPY_MASK:
   482         *blendMode = SDL_TEXTUREBLENDMODE_MASK;
   483         break;
   484     case SDL_COPY_BLEND:
   485         *blendMode = SDL_TEXTUREBLENDMODE_BLEND;
   486         break;
   487     case SDL_COPY_ADD:
   488         *blendMode = SDL_TEXTUREBLENDMODE_ADD;
   489         break;
   490     case SDL_COPY_MOD:
   491         *blendMode = SDL_TEXTUREBLENDMODE_MOD;
   492         break;
   493     default:
   494         *blendMode = SDL_TEXTUREBLENDMODE_NONE;
   495         break;
   496     }
   497     return 0;
   498 }
   499 
   500 int
   501 SDL_SetSurfaceScaleMode(SDL_Surface * surface, int scaleMode)
   502 {
   503     int flags, status;
   504 
   505     if (!surface) {
   506         return -1;
   507     }
   508 
   509     status = 0;
   510     flags = surface->map->info.flags;
   511     surface->map->info.flags &= ~(SDL_COPY_NEAREST);
   512     switch (scaleMode) {
   513     case SDL_TEXTURESCALEMODE_NONE:
   514         break;
   515     case SDL_TEXTURESCALEMODE_FAST:
   516         surface->map->info.flags |= SDL_COPY_NEAREST;
   517         break;
   518     case SDL_TEXTURESCALEMODE_SLOW:
   519     case SDL_TEXTURESCALEMODE_BEST:
   520         SDL_Unsupported();
   521         surface->map->info.flags |= SDL_COPY_NEAREST;
   522         status = -1;
   523         break;
   524     default:
   525         SDL_Unsupported();
   526         status = -1;
   527         break;
   528     }
   529 
   530     if (surface->map->info.flags != flags) {
   531         SDL_InvalidateMap(surface->map);
   532     }
   533     return status;
   534 }
   535 
   536 int
   537 SDL_GetSurfaceScaleMode(SDL_Surface * surface, int *scaleMode)
   538 {
   539     if (!surface) {
   540         return -1;
   541     }
   542 
   543     if (!scaleMode) {
   544         return 0;
   545     }
   546 
   547     switch (surface->map->info.flags & (SDL_COPY_NEAREST)) {
   548     case SDL_COPY_NEAREST:
   549         *scaleMode = SDL_TEXTURESCALEMODE_FAST;
   550         break;
   551     default:
   552         *scaleMode = SDL_TEXTURESCALEMODE_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 1;
   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         (src->map->dst->format_version != src->map->format_version)) {
   608         if (SDL_MapSurface(src, dst) < 0) {
   609             return (-1);
   610         }
   611         /* just here for debugging */
   612 /*         printf */
   613 /*             ("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", */
   614 /*              src, dst->flags, src->map->info.flags, dst, dst->flags, */
   615 /*              dst->map->info.flags, src->map->blit); */
   616     }
   617     return (src->map->blit(src, srcrect, dst, dstrect));
   618 }
   619 
   620 
   621 int
   622 SDL_UpperBlit(SDL_Surface * src, SDL_Rect * srcrect,
   623               SDL_Surface * dst, SDL_Rect * dstrect)
   624 {
   625     SDL_Rect fulldst;
   626     int srcx, srcy, w, h;
   627 
   628     /* Make sure the surfaces aren't locked */
   629     if (!src || !dst) {
   630         SDL_SetError("SDL_UpperBlit: passed a NULL surface");
   631         return (-1);
   632     }
   633     if (src->locked || dst->locked) {
   634         SDL_SetError("Surfaces must not be locked during blit");
   635         return (-1);
   636     }
   637 
   638     /* If the destination rectangle is NULL, use the entire dest surface */
   639     if (dstrect == NULL) {
   640         fulldst.x = fulldst.y = 0;
   641         dstrect = &fulldst;
   642     }
   643 
   644     /* clip the source rectangle to the source surface */
   645     if (srcrect) {
   646         int maxw, maxh;
   647 
   648         srcx = srcrect->x;
   649         w = srcrect->w;
   650         if (srcx < 0) {
   651             w += srcx;
   652             dstrect->x -= srcx;
   653             srcx = 0;
   654         }
   655         maxw = src->w - srcx;
   656         if (maxw < w)
   657             w = maxw;
   658 
   659         srcy = srcrect->y;
   660         h = srcrect->h;
   661         if (srcy < 0) {
   662             h += srcy;
   663             dstrect->y -= srcy;
   664             srcy = 0;
   665         }
   666         maxh = src->h - srcy;
   667         if (maxh < h)
   668             h = maxh;
   669 
   670     } else {
   671         srcx = srcy = 0;
   672         w = src->w;
   673         h = src->h;
   674     }
   675 
   676     /* clip the destination rectangle against the clip rectangle */
   677     {
   678         SDL_Rect *clip = &dst->clip_rect;
   679         int dx, dy;
   680 
   681         dx = clip->x - dstrect->x;
   682         if (dx > 0) {
   683             w -= dx;
   684             dstrect->x += dx;
   685             srcx += dx;
   686         }
   687         dx = dstrect->x + w - clip->x - clip->w;
   688         if (dx > 0)
   689             w -= dx;
   690 
   691         dy = clip->y - dstrect->y;
   692         if (dy > 0) {
   693             h -= dy;
   694             dstrect->y += dy;
   695             srcy += dy;
   696         }
   697         dy = dstrect->y + h - clip->y - clip->h;
   698         if (dy > 0)
   699             h -= dy;
   700     }
   701 
   702     if (w > 0 && h > 0) {
   703         SDL_Rect sr;
   704         sr.x = srcx;
   705         sr.y = srcy;
   706         sr.w = dstrect->w = w;
   707         sr.h = dstrect->h = h;
   708         return SDL_LowerBlit(src, &sr, dst, dstrect);
   709     }
   710     dstrect->w = dstrect->h = 0;
   711     return 0;
   712 }
   713 
   714 /*
   715  * Lock a surface to directly access the pixels
   716  */
   717 int
   718 SDL_LockSurface(SDL_Surface * surface)
   719 {
   720     if (!surface->locked) {
   721         /* Perform the lock */
   722         if (surface->flags & SDL_RLEACCEL) {
   723             SDL_UnRLESurface(surface, 1);
   724             surface->flags |= SDL_RLEACCEL;     /* save accel'd state */
   725         }
   726     }
   727 
   728     /* Increment the surface lock count, for recursive locks */
   729     ++surface->locked;
   730 
   731     /* Ready to go.. */
   732     return (0);
   733 }
   734 
   735 /*
   736  * Unlock a previously locked surface
   737  */
   738 void
   739 SDL_UnlockSurface(SDL_Surface * surface)
   740 {
   741     /* Only perform an unlock if we are locked */
   742     if (!surface->locked || (--surface->locked > 0)) {
   743         return;
   744     }
   745 
   746     /* Update RLE encoded surface with new data */
   747     if ((surface->flags & SDL_RLEACCEL) == SDL_RLEACCEL) {
   748         surface->flags &= ~SDL_RLEACCEL;        /* stop lying */
   749         SDL_RLESurface(surface);
   750     }
   751 }
   752 
   753 /* 
   754  * Convert a surface into the specified pixel format.
   755  */
   756 SDL_Surface *
   757 SDL_ConvertSurface(SDL_Surface * surface,
   758                    SDL_PixelFormat * format, Uint32 flags)
   759 {
   760     SDL_Surface *convert;
   761     Uint32 copy_flags;
   762     SDL_Rect bounds;
   763 
   764     /* Check for empty destination palette! (results in empty image) */
   765     if (format->palette != NULL) {
   766         int i;
   767         for (i = 0; i < format->palette->ncolors; ++i) {
   768             if ((format->palette->colors[i].r != 0xFF) ||
   769                 (format->palette->colors[i].g != 0xFF) ||
   770                 (format->palette->colors[i].b != 0xFF))
   771                 break;
   772         }
   773         if (i == format->palette->ncolors) {
   774             SDL_SetError("Empty destination palette");
   775             return (NULL);
   776         }
   777     }
   778 
   779     /* Create a new surface with the desired format */
   780     convert = SDL_CreateRGBSurface(0, surface->w, surface->h,
   781                                    format->BitsPerPixel, format->Rmask,
   782                                    format->Gmask, format->Bmask,
   783                                    format->Amask);
   784     if (convert == NULL) {
   785         return (NULL);
   786     }
   787 
   788     /* Copy the palette if any */
   789     if (format->palette && convert->format->palette) {
   790         SDL_memcpy(convert->format->palette->colors,
   791                    format->palette->colors,
   792                    format->palette->ncolors * sizeof(SDL_Color));
   793         convert->format->palette->ncolors = format->palette->ncolors;
   794     }
   795 
   796     /* Save the original copy flags */
   797     copy_flags = surface->map->info.flags;
   798     surface->map->info.flags = 0;
   799 
   800     /* Copy over the image data */
   801     bounds.x = 0;
   802     bounds.y = 0;
   803     bounds.w = surface->w;
   804     bounds.h = surface->h;
   805     SDL_LowerBlit(surface, &bounds, convert, &bounds);
   806 
   807     /* Clean up the original surface, and update converted surface */
   808     SDL_SetClipRect(convert, &surface->clip_rect);
   809     if (copy_flags & SDL_COPY_COLORKEY) {
   810         Uint8 keyR, keyG, keyB, keyA;
   811 
   812         SDL_GetRGBA(surface->map->info.colorkey, surface->format, &keyR,
   813                     &keyG, &keyB, &keyA);
   814         SDL_SetColorKey(convert, 1,
   815                         SDL_MapRGBA(convert->format, keyR, keyG, keyB, keyA));
   816         SDL_ConvertColorkeyToAlpha(convert);
   817     }
   818     convert->map->info.r = surface->map->info.r;
   819     convert->map->info.g = surface->map->info.g;
   820     convert->map->info.b = surface->map->info.b;
   821     convert->map->info.a = surface->map->info.a;
   822     convert->map->info.flags = copy_flags;
   823     surface->map->info.flags = copy_flags;
   824 
   825     /* Enable alpha blending by default if the new surface has an
   826      * alpha channel or alpha modulation */
   827     if (format->Amask || (copy_flags & SDL_COPY_MODULATE_ALPHA)) {
   828         SDL_SetSurfaceBlendMode(convert, SDL_TEXTUREBLENDMODE_BLEND);
   829     }
   830 
   831     /* We're ready to go! */
   832     return (convert);
   833 }
   834 
   835 /*
   836  * Free a surface created by the above function.
   837  */
   838 void
   839 SDL_FreeSurface(SDL_Surface * surface)
   840 {
   841     if (surface == NULL) {
   842         return;
   843     }
   844     if (--surface->refcount > 0) {
   845         return;
   846     }
   847     while (surface->locked > 0) {
   848         SDL_UnlockSurface(surface);
   849     }
   850     if (surface->flags & SDL_RLEACCEL) {
   851         SDL_UnRLESurface(surface, 0);
   852     }
   853     if (surface->format) {
   854         SDL_SetSurfacePalette(surface, NULL);
   855         SDL_FreeFormat(surface->format);
   856         surface->format = NULL;
   857     }
   858     if (surface->map != NULL) {
   859         SDL_FreeBlitMap(surface->map);
   860         surface->map = NULL;
   861     }
   862     if (surface->pixels && ((surface->flags & SDL_PREALLOC) != SDL_PREALLOC)) {
   863         SDL_free(surface->pixels);
   864     }
   865     SDL_free(surface);
   866 #ifdef CHECK_LEAKS
   867     --surfaces_allocated;
   868 #endif
   869 }
   870 
   871 /* vi: set ts=4 sw=4 expandtab: */