src/video/SDL_surface.c
author Bob Pendleton <bob@pendleton.com>
Fri, 09 Jan 2009 20:43:30 +0000
changeset 3011 8f4ed5ec2b06
parent 2884 9dde605c7540
child 3013 8cc00819c8d6
permissions -rw-r--r--
I ran a global "make indent" it modified the following files.
     1 /*
     2     SDL - Simple DirectMedia Layer
     3     Copyright (C) 1997-2009 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     /* The flags are no longer used, make the compiler happy */
    45     flags;
    46 
    47     /* Allocate the surface */
    48     surface = (SDL_Surface *) SDL_calloc(1, sizeof(*surface));
    49     if (surface == NULL) {
    50         SDL_OutOfMemory();
    51         return NULL;
    52     }
    53 
    54     surface->format = SDL_AllocFormat(depth, Rmask, Gmask, Bmask, Amask);
    55     if (!surface->format) {
    56         SDL_FreeSurface(surface);
    57         return NULL;
    58     }
    59     surface->w = width;
    60     surface->h = height;
    61     surface->pitch = SDL_CalculatePitch(surface);
    62     SDL_SetClipRect(surface, NULL);
    63 
    64     if (surface->format->BitsPerPixel <= 8) {
    65         SDL_Palette *palette =
    66             SDL_AllocPalette((1 << surface->format->BitsPerPixel));
    67         if (!palette) {
    68             SDL_FreeSurface(surface);
    69             return NULL;
    70         }
    71         if (Rmask || Bmask || Gmask) {
    72             const SDL_PixelFormat *format = surface->format;
    73 
    74             /* create palette according to masks */
    75             int i;
    76             int Rm = 0, Gm = 0, Bm = 0;
    77             int Rw = 0, Gw = 0, Bw = 0;
    78 
    79             if (Rmask) {
    80                 Rw = 8 - format->Rloss;
    81                 for (i = format->Rloss; i > 0; i -= Rw)
    82                     Rm |= 1 << i;
    83             }
    84             if (Gmask) {
    85                 Gw = 8 - format->Gloss;
    86                 for (i = format->Gloss; i > 0; i -= Gw)
    87                     Gm |= 1 << i;
    88             }
    89             if (Bmask) {
    90                 Bw = 8 - format->Bloss;
    91                 for (i = format->Bloss; i > 0; i -= Bw)
    92                     Bm |= 1 << i;
    93             }
    94             for (i = 0; i < palette->ncolors; ++i) {
    95                 int r, g, b;
    96                 r = (i & Rmask) >> format->Rshift;
    97                 r = (r << format->Rloss) | ((r * Rm) >> Rw);
    98                 palette->colors[i].r = r;
    99 
   100                 g = (i & Gmask) >> format->Gshift;
   101                 g = (g << format->Gloss) | ((g * Gm) >> Gw);
   102                 palette->colors[i].g = g;
   103 
   104                 b = (i & Bmask) >> format->Bshift;
   105                 b = (b << format->Bloss) | ((b * Bm) >> Bw);
   106                 palette->colors[i].b = b;
   107             }
   108         } else if (palette->ncolors == 2) {
   109             /* Create a black and white bitmap palette */
   110             palette->colors[0].r = 0xFF;
   111             palette->colors[0].g = 0xFF;
   112             palette->colors[0].b = 0xFF;
   113             palette->colors[1].r = 0x00;
   114             palette->colors[1].g = 0x00;
   115             palette->colors[1].b = 0x00;
   116         }
   117         SDL_SetSurfacePalette(surface, palette);
   118         SDL_FreePalette(palette);
   119     }
   120 
   121     /* Get the pixels */
   122     if (surface->w && surface->h) {
   123         surface->pixels = SDL_malloc(surface->h * surface->pitch);
   124         if (!surface->pixels) {
   125             SDL_FreeSurface(surface);
   126             SDL_OutOfMemory();
   127             return NULL;
   128         }
   129         /* This is important for bitmaps */
   130         SDL_memset(surface->pixels, 0, surface->h * surface->pitch);
   131     }
   132 
   133     /* Allocate an empty mapping */
   134     surface->map = SDL_AllocBlitMap();
   135     if (!surface->map) {
   136         SDL_FreeSurface(surface);
   137         return NULL;
   138     }
   139     SDL_FormatChanged(surface);
   140 
   141     /* By default surface with an alpha mask are set up for blending */
   142     if (Amask) {
   143         SDL_SetSurfaceBlendMode(surface, SDL_BLENDMODE_BLEND);
   144     }
   145 
   146     /* The surface is ready to go */
   147     surface->refcount = 1;
   148 #ifdef CHECK_LEAKS
   149     ++surfaces_allocated;
   150 #endif
   151     return surface;
   152 }
   153 
   154 /*
   155  * Create an RGB surface from an existing memory buffer
   156  */
   157 SDL_Surface *
   158 SDL_CreateRGBSurfaceFrom(void *pixels,
   159                          int width, int height, int depth, int pitch,
   160                          Uint32 Rmask, Uint32 Gmask, Uint32 Bmask,
   161                          Uint32 Amask)
   162 {
   163     SDL_Surface *surface;
   164 
   165     surface =
   166         SDL_CreateRGBSurface(0, 0, 0, depth, Rmask, Gmask, Bmask, Amask);
   167     if (surface != NULL) {
   168         surface->flags |= SDL_PREALLOC;
   169         surface->pixels = pixels;
   170         surface->w = width;
   171         surface->h = height;
   172         surface->pitch = pitch;
   173         SDL_SetClipRect(surface, NULL);
   174     }
   175     return surface;
   176 }
   177 
   178 static int
   179 SDL_SurfacePaletteChanged(void *userdata, SDL_Palette * palette)
   180 {
   181     SDL_Surface *surface = (SDL_Surface *) userdata;
   182 
   183     SDL_FormatChanged(surface);
   184 
   185     return 0;
   186 }
   187 
   188 int
   189 SDL_SetSurfacePalette(SDL_Surface * surface, SDL_Palette * palette)
   190 {
   191     if (!surface || !surface->format) {
   192         SDL_SetError("SDL_SetSurfacePalette() passed a NULL surface");
   193         return -1;
   194     }
   195 
   196     if (palette && palette->ncolors != (1 << surface->format->BitsPerPixel)) {
   197         SDL_SetError
   198             ("SDL_SetSurfacePalette() passed a palette that doesn't match the surface format");
   199         return -1;
   200     }
   201 
   202     if (surface->format->palette == palette) {
   203         return 0;
   204     }
   205 
   206     if (surface->format->palette) {
   207         SDL_DelPaletteWatch(surface->format->palette,
   208                             SDL_SurfacePaletteChanged, surface);
   209     }
   210 
   211     surface->format->palette = palette;
   212 
   213     if (surface->format->palette) {
   214         SDL_AddPaletteWatch(surface->format->palette,
   215                             SDL_SurfacePaletteChanged, surface);
   216     }
   217     return 0;
   218 }
   219 
   220 int
   221 SDL_SetSurfaceRLE(SDL_Surface * surface, int flag)
   222 {
   223     int flags;
   224 
   225     if (!surface) {
   226         return -1;
   227     }
   228 
   229     flags = surface->map->info.flags;
   230     if (flag) {
   231         surface->map->info.flags |= SDL_COPY_RLE_DESIRED;
   232     } else {
   233         surface->map->info.flags &= ~SDL_COPY_RLE_DESIRED;
   234     }
   235     if (surface->map->info.flags != flags) {
   236         SDL_InvalidateMap(surface->map);
   237     }
   238     return 0;
   239 }
   240 
   241 int
   242 SDL_SetColorKey(SDL_Surface * surface, Uint32 flag, Uint32 key)
   243 {
   244     int flags;
   245 
   246     if (!surface) {
   247         return -1;
   248     }
   249 
   250     if (flag & SDL_RLEACCEL) {
   251         SDL_SetSurfaceRLE(surface, 1);
   252     }
   253 
   254     flags = surface->map->info.flags;
   255     if (flag) {
   256         surface->map->info.flags |= SDL_COPY_COLORKEY;
   257         surface->map->info.colorkey = key;
   258     } else {
   259         surface->map->info.flags &= ~SDL_COPY_COLORKEY;
   260     }
   261     if (surface->map->info.flags != flags) {
   262         SDL_InvalidateMap(surface->map);
   263     }
   264 
   265     /* Compatibility mode */
   266     if (surface->map->info.flags & SDL_COPY_COLORKEY) {
   267         surface->flags |= SDL_SRCCOLORKEY;
   268     } else {
   269         surface->flags &= ~SDL_SRCCOLORKEY;
   270     }
   271 
   272     return 0;
   273 }
   274 
   275 /* This is a fairly slow function to switch from colorkey to alpha */
   276 static void
   277 SDL_ConvertColorkeyToAlpha(SDL_Surface * surface)
   278 {
   279     int x, y;
   280 
   281     if (!surface) {
   282         return;
   283     }
   284 
   285     if (!(surface->map->info.flags & SDL_COPY_COLORKEY) ||
   286         !surface->format->Amask) {
   287         return;
   288     }
   289 
   290     SDL_LockSurface(surface);
   291 
   292     switch (surface->format->BytesPerPixel) {
   293     case 2:
   294         {
   295             Uint16 *row, *spot;
   296             Uint16 ckey = (Uint16) surface->map->info.colorkey;
   297             Uint16 mask = (Uint16) (~surface->format->Amask);
   298 
   299             row = (Uint16 *) surface->pixels;
   300             for (y = surface->h; y--;) {
   301                 spot = row;
   302                 for (x = surface->w; x--;) {
   303                     if (*spot == ckey) {
   304                         *spot &= mask;
   305                     }
   306                     ++spot;
   307                 }
   308                 row += surface->pitch / 2;
   309             }
   310         }
   311         break;
   312     case 3:
   313         /* FIXME */
   314         break;
   315     case 4:
   316         {
   317             Uint32 *row, *spot;
   318             Uint32 ckey = surface->map->info.colorkey;
   319             Uint32 mask = ~surface->format->Amask;
   320 
   321             row = (Uint32 *) surface->pixels;
   322             for (y = surface->h; y--;) {
   323                 spot = row;
   324                 for (x = surface->w; x--;) {
   325                     if (*spot == ckey) {
   326                         *spot &= mask;
   327                     }
   328                     ++spot;
   329                 }
   330                 row += surface->pitch / 4;
   331             }
   332         }
   333         break;
   334     }
   335 
   336     SDL_UnlockSurface(surface);
   337 
   338     SDL_SetColorKey(surface, 0, 0);
   339     SDL_SetSurfaceBlendMode(surface, SDL_BLENDMODE_BLEND);
   340 }
   341 
   342 int
   343 SDL_SetSurfaceColorMod(SDL_Surface * surface, Uint8 r, Uint8 g, Uint8 b)
   344 {
   345     int flags;
   346 
   347     if (!surface) {
   348         return -1;
   349     }
   350 
   351     surface->map->info.r = r;
   352     surface->map->info.g = g;
   353     surface->map->info.b = b;
   354 
   355     flags = surface->map->info.flags;
   356     if (r != 0xFF || g != 0xFF || b != 0xFF) {
   357         surface->map->info.flags |= SDL_COPY_MODULATE_COLOR;
   358     } else {
   359         surface->map->info.flags &= ~SDL_COPY_MODULATE_COLOR;
   360     }
   361     if (surface->map->info.flags != flags) {
   362         SDL_InvalidateMap(surface->map);
   363     }
   364     return 0;
   365 }
   366 
   367 
   368 int
   369 SDL_GetSurfaceColorMod(SDL_Surface * surface, Uint8 * r, Uint8 * g, Uint8 * b)
   370 {
   371     if (!surface) {
   372         return -1;
   373     }
   374 
   375     if (r) {
   376         *r = surface->map->info.r;
   377     }
   378     if (g) {
   379         *g = surface->map->info.g;
   380     }
   381     if (b) {
   382         *b = surface->map->info.b;
   383     }
   384     return 0;
   385 }
   386 
   387 int
   388 SDL_SetSurfaceAlphaMod(SDL_Surface * surface, Uint8 alpha)
   389 {
   390     int flags;
   391 
   392     if (!surface) {
   393         return -1;
   394     }
   395 
   396     surface->map->info.a = alpha;
   397 
   398     flags = surface->map->info.flags;
   399     if (alpha != 0xFF) {
   400         surface->map->info.flags |= SDL_COPY_MODULATE_ALPHA;
   401     } else {
   402         surface->map->info.flags &= ~SDL_COPY_MODULATE_ALPHA;
   403     }
   404     if (surface->map->info.flags != flags) {
   405         SDL_InvalidateMap(surface->map);
   406     }
   407     return 0;
   408 }
   409 
   410 int
   411 SDL_GetSurfaceAlphaMod(SDL_Surface * surface, Uint8 * alpha)
   412 {
   413     if (!surface) {
   414         return -1;
   415     }
   416 
   417     if (alpha) {
   418         *alpha = surface->map->info.a;
   419     }
   420     return 0;
   421 }
   422 
   423 int
   424 SDL_SetSurfaceBlendMode(SDL_Surface * surface, int blendMode)
   425 {
   426     int flags, status;
   427 
   428     if (!surface) {
   429         return -1;
   430     }
   431 
   432     status = 0;
   433     flags = surface->map->info.flags;
   434     surface->map->info.flags &=
   435         ~(SDL_COPY_MASK | SDL_COPY_BLEND | SDL_COPY_ADD | SDL_COPY_MOD);
   436     switch (blendMode) {
   437     case SDL_BLENDMODE_NONE:
   438         break;
   439     case SDL_BLENDMODE_MASK:
   440         surface->map->info.flags |= SDL_COPY_MASK;
   441         break;
   442     case SDL_BLENDMODE_BLEND:
   443         surface->map->info.flags |= SDL_COPY_BLEND;
   444         break;
   445     case SDL_BLENDMODE_ADD:
   446         surface->map->info.flags |= SDL_COPY_ADD;
   447         break;
   448     case SDL_BLENDMODE_MOD:
   449         surface->map->info.flags |= SDL_COPY_MOD;
   450         break;
   451     default:
   452         SDL_Unsupported();
   453         status = -1;
   454         break;
   455     }
   456 
   457     if (surface->map->info.flags != flags) {
   458         SDL_InvalidateMap(surface->map);
   459     }
   460 
   461     /* Compatibility mode */
   462     if (surface->map->info.flags & SDL_COPY_BLEND) {
   463         surface->flags |= SDL_SRCALPHA;
   464     } else {
   465         surface->flags &= ~SDL_SRCALPHA;
   466     }
   467 
   468     return status;
   469 }
   470 
   471 int
   472 SDL_GetSurfaceBlendMode(SDL_Surface * surface, int *blendMode)
   473 {
   474     if (!surface) {
   475         return -1;
   476     }
   477 
   478     if (!blendMode) {
   479         return 0;
   480     }
   481 
   482     switch (surface->map->info.
   483             flags & (SDL_COPY_MASK | SDL_COPY_BLEND | SDL_COPY_ADD |
   484                      SDL_COPY_MOD)) {
   485     case SDL_COPY_MASK:
   486         *blendMode = SDL_BLENDMODE_MASK;
   487         break;
   488     case SDL_COPY_BLEND:
   489         *blendMode = SDL_BLENDMODE_BLEND;
   490         break;
   491     case SDL_COPY_ADD:
   492         *blendMode = SDL_BLENDMODE_ADD;
   493         break;
   494     case SDL_COPY_MOD:
   495         *blendMode = SDL_BLENDMODE_MOD;
   496         break;
   497     default:
   498         *blendMode = SDL_BLENDMODE_NONE;
   499         break;
   500     }
   501     return 0;
   502 }
   503 
   504 int
   505 SDL_SetSurfaceScaleMode(SDL_Surface * surface, int scaleMode)
   506 {
   507     int flags, status;
   508 
   509     if (!surface) {
   510         return -1;
   511     }
   512 
   513     status = 0;
   514     flags = surface->map->info.flags;
   515     surface->map->info.flags &= ~(SDL_COPY_NEAREST);
   516     switch (scaleMode) {
   517     case SDL_TEXTURESCALEMODE_NONE:
   518         break;
   519     case SDL_TEXTURESCALEMODE_FAST:
   520         surface->map->info.flags |= SDL_COPY_NEAREST;
   521         break;
   522     case SDL_TEXTURESCALEMODE_SLOW:
   523     case SDL_TEXTURESCALEMODE_BEST:
   524         SDL_Unsupported();
   525         surface->map->info.flags |= SDL_COPY_NEAREST;
   526         status = -1;
   527         break;
   528     default:
   529         SDL_Unsupported();
   530         status = -1;
   531         break;
   532     }
   533 
   534     if (surface->map->info.flags != flags) {
   535         SDL_InvalidateMap(surface->map);
   536     }
   537     return status;
   538 }
   539 
   540 int
   541 SDL_GetSurfaceScaleMode(SDL_Surface * surface, int *scaleMode)
   542 {
   543     if (!surface) {
   544         return -1;
   545     }
   546 
   547     if (!scaleMode) {
   548         return 0;
   549     }
   550 
   551     switch (surface->map->info.flags & SDL_COPY_NEAREST) {
   552     case SDL_COPY_NEAREST:
   553         *scaleMode = SDL_TEXTURESCALEMODE_FAST;
   554         break;
   555     default:
   556         *scaleMode = SDL_TEXTURESCALEMODE_NONE;
   557         break;
   558     }
   559     return 0;
   560 }
   561 
   562 SDL_bool
   563 SDL_SetClipRect(SDL_Surface * surface, const SDL_Rect * rect)
   564 {
   565     SDL_Rect full_rect;
   566 
   567     /* Don't do anything if there's no surface to act on */
   568     if (!surface) {
   569         return SDL_FALSE;
   570     }
   571 
   572     /* Set up the full surface rectangle */
   573     full_rect.x = 0;
   574     full_rect.y = 0;
   575     full_rect.w = surface->w;
   576     full_rect.h = surface->h;
   577 
   578     /* Set the clipping rectangle */
   579     if (!rect) {
   580         surface->clip_rect = full_rect;
   581         return 1;
   582     }
   583     return SDL_IntersectRect(rect, &full_rect, &surface->clip_rect);
   584 }
   585 
   586 void
   587 SDL_GetClipRect(SDL_Surface * surface, SDL_Rect * rect)
   588 {
   589     if (surface && rect) {
   590         *rect = surface->clip_rect;
   591     }
   592 }
   593 
   594 /* 
   595  * Set up a blit between two surfaces -- split into three parts:
   596  * The upper part, SDL_UpperBlit(), performs clipping and rectangle 
   597  * verification.  The lower part is a pointer to a low level
   598  * accelerated blitting function.
   599  *
   600  * These parts are separated out and each used internally by this 
   601  * library in the optimimum places.  They are exported so that if
   602  * you know exactly what you are doing, you can optimize your code
   603  * by calling the one(s) you need.
   604  */
   605 int
   606 SDL_LowerBlit(SDL_Surface * src, SDL_Rect * srcrect,
   607               SDL_Surface * dst, SDL_Rect * dstrect)
   608 {
   609     /* Check to make sure the blit mapping is valid */
   610     if ((src->map->dst != dst) ||
   611         (src->map->dst->format_version != src->map->format_version)) {
   612         if (SDL_MapSurface(src, dst) < 0) {
   613             return (-1);
   614         }
   615         /* just here for debugging */
   616 /*         printf */
   617 /*             ("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", */
   618 /*              src, dst->flags, src->map->info.flags, dst, dst->flags, */
   619 /*              dst->map->info.flags, src->map->blit); */
   620     }
   621     return (src->map->blit(src, srcrect, dst, dstrect));
   622 }
   623 
   624 
   625 int
   626 SDL_UpperBlit(SDL_Surface * src, SDL_Rect * srcrect,
   627               SDL_Surface * dst, SDL_Rect * dstrect)
   628 {
   629     SDL_Rect fulldst;
   630     int srcx, srcy, w, h;
   631 
   632     /* Make sure the surfaces aren't locked */
   633     if (!src || !dst) {
   634         SDL_SetError("SDL_UpperBlit: passed a NULL surface");
   635         return (-1);
   636     }
   637     if (src->locked || dst->locked) {
   638         SDL_SetError("Surfaces must not be locked during blit");
   639         return (-1);
   640     }
   641 
   642     /* If the destination rectangle is NULL, use the entire dest surface */
   643     if (dstrect == NULL) {
   644         fulldst.x = fulldst.y = 0;
   645         dstrect = &fulldst;
   646     }
   647 
   648     /* clip the source rectangle to the source surface */
   649     if (srcrect) {
   650         int maxw, maxh;
   651 
   652         srcx = srcrect->x;
   653         w = srcrect->w;
   654         if (srcx < 0) {
   655             w += srcx;
   656             dstrect->x -= srcx;
   657             srcx = 0;
   658         }
   659         maxw = src->w - srcx;
   660         if (maxw < w)
   661             w = maxw;
   662 
   663         srcy = srcrect->y;
   664         h = srcrect->h;
   665         if (srcy < 0) {
   666             h += srcy;
   667             dstrect->y -= srcy;
   668             srcy = 0;
   669         }
   670         maxh = src->h - srcy;
   671         if (maxh < h)
   672             h = maxh;
   673 
   674     } else {
   675         srcx = srcy = 0;
   676         w = src->w;
   677         h = src->h;
   678     }
   679 
   680     /* clip the destination rectangle against the clip rectangle */
   681     {
   682         SDL_Rect *clip = &dst->clip_rect;
   683         int dx, dy;
   684 
   685         dx = clip->x - dstrect->x;
   686         if (dx > 0) {
   687             w -= dx;
   688             dstrect->x += dx;
   689             srcx += dx;
   690         }
   691         dx = dstrect->x + w - clip->x - clip->w;
   692         if (dx > 0)
   693             w -= dx;
   694 
   695         dy = clip->y - dstrect->y;
   696         if (dy > 0) {
   697             h -= dy;
   698             dstrect->y += dy;
   699             srcy += dy;
   700         }
   701         dy = dstrect->y + h - clip->y - clip->h;
   702         if (dy > 0)
   703             h -= dy;
   704     }
   705 
   706     if (w > 0 && h > 0) {
   707         SDL_Rect sr;
   708         sr.x = srcx;
   709         sr.y = srcy;
   710         sr.w = dstrect->w = w;
   711         sr.h = dstrect->h = h;
   712         return SDL_LowerBlit(src, &sr, dst, dstrect);
   713     }
   714     dstrect->w = dstrect->h = 0;
   715     return 0;
   716 }
   717 
   718 /*
   719  * Lock a surface to directly access the pixels
   720  */
   721 int
   722 SDL_LockSurface(SDL_Surface * surface)
   723 {
   724     if (!surface->locked) {
   725         /* Perform the lock */
   726         if (surface->flags & SDL_RLEACCEL) {
   727             SDL_UnRLESurface(surface, 1);
   728             surface->flags |= SDL_RLEACCEL;     /* save accel'd state */
   729         }
   730     }
   731 
   732     /* Increment the surface lock count, for recursive locks */
   733     ++surface->locked;
   734 
   735     /* Ready to go.. */
   736     return (0);
   737 }
   738 
   739 /*
   740  * Unlock a previously locked surface
   741  */
   742 void
   743 SDL_UnlockSurface(SDL_Surface * surface)
   744 {
   745     /* Only perform an unlock if we are locked */
   746     if (!surface->locked || (--surface->locked > 0)) {
   747         return;
   748     }
   749 
   750     /* Update RLE encoded surface with new data */
   751     if ((surface->flags & SDL_RLEACCEL) == SDL_RLEACCEL) {
   752         surface->flags &= ~SDL_RLEACCEL;        /* stop lying */
   753         SDL_RLESurface(surface);
   754     }
   755 }
   756 
   757 /* 
   758  * Convert a surface into the specified pixel format.
   759  */
   760 SDL_Surface *
   761 SDL_ConvertSurface(SDL_Surface * surface, SDL_PixelFormat * format,
   762                    Uint32 flags)
   763 {
   764     SDL_Surface *convert;
   765     Uint32 copy_flags;
   766     SDL_Rect bounds;
   767 
   768     /* Check for empty destination palette! (results in empty image) */
   769     if (format->palette != NULL) {
   770         int i;
   771         for (i = 0; i < format->palette->ncolors; ++i) {
   772             if ((format->palette->colors[i].r != 0xFF) ||
   773                 (format->palette->colors[i].g != 0xFF) ||
   774                 (format->palette->colors[i].b != 0xFF))
   775                 break;
   776         }
   777         if (i == format->palette->ncolors) {
   778             SDL_SetError("Empty destination palette");
   779             return (NULL);
   780         }
   781     }
   782 
   783     /* Create a new surface with the desired format */
   784     convert = SDL_CreateRGBSurface(flags, surface->w, surface->h,
   785                                    format->BitsPerPixel, format->Rmask,
   786                                    format->Gmask, format->Bmask,
   787                                    format->Amask);
   788     if (convert == NULL) {
   789         return (NULL);
   790     }
   791 
   792     /* Copy the palette if any */
   793     if (format->palette && convert->format->palette) {
   794         SDL_memcpy(convert->format->palette->colors,
   795                    format->palette->colors,
   796                    format->palette->ncolors * sizeof(SDL_Color));
   797         convert->format->palette->ncolors = format->palette->ncolors;
   798     }
   799 
   800     /* Save the original copy flags */
   801     copy_flags = surface->map->info.flags;
   802     surface->map->info.flags = 0;
   803 
   804     /* Copy over the image data */
   805     bounds.x = 0;
   806     bounds.y = 0;
   807     bounds.w = surface->w;
   808     bounds.h = surface->h;
   809     SDL_LowerBlit(surface, &bounds, convert, &bounds);
   810 
   811     /* Clean up the original surface, and update converted surface */
   812     convert->map->info.r = surface->map->info.r;
   813     convert->map->info.g = surface->map->info.g;
   814     convert->map->info.b = surface->map->info.b;
   815     convert->map->info.a = surface->map->info.a;
   816     convert->map->info.flags =
   817         (copy_flags &
   818          ~(SDL_COPY_COLORKEY | SDL_COPY_BLEND
   819            | SDL_COPY_RLE_DESIRED | SDL_COPY_RLE_COLORKEY |
   820            SDL_COPY_RLE_ALPHAKEY));
   821     surface->map->info.flags = copy_flags;
   822     if (copy_flags & SDL_COPY_COLORKEY) {
   823         Uint8 keyR, keyG, keyB, keyA;
   824 
   825         SDL_GetRGBA(surface->map->info.colorkey, surface->format, &keyR,
   826                     &keyG, &keyB, &keyA);
   827         SDL_SetColorKey(convert, 1,
   828                         SDL_MapRGBA(convert->format, keyR, keyG, keyB, keyA));
   829         /* This is needed when converting for 3D texture upload */
   830         SDL_ConvertColorkeyToAlpha(convert);
   831     }
   832     SDL_SetClipRect(convert, &surface->clip_rect);
   833 
   834     /* Enable alpha blending by default if the new surface has an
   835      * alpha channel or alpha modulation */
   836     if ((surface->format->Amask && format->Amask) ||
   837         (copy_flags & SDL_COPY_MODULATE_ALPHA)) {
   838         SDL_SetSurfaceBlendMode(convert, SDL_BLENDMODE_BLEND);
   839     }
   840     if ((copy_flags & SDL_COPY_RLE_DESIRED) || (flags & SDL_RLEACCEL)) {
   841         SDL_SetSurfaceRLE(convert, SDL_RLEACCEL);
   842     }
   843 
   844     /* We're ready to go! */
   845     return (convert);
   846 }
   847 
   848 /*
   849  * Free a surface created by the above function.
   850  */
   851 void
   852 SDL_FreeSurface(SDL_Surface * surface)
   853 {
   854     if (surface == NULL) {
   855         return;
   856     }
   857     if (--surface->refcount > 0) {
   858         return;
   859     }
   860     while (surface->locked > 0) {
   861         SDL_UnlockSurface(surface);
   862     }
   863     if (surface->flags & SDL_RLEACCEL) {
   864         SDL_UnRLESurface(surface, 0);
   865     }
   866     if (surface->format) {
   867         SDL_SetSurfacePalette(surface, NULL);
   868         SDL_FreeFormat(surface->format);
   869         surface->format = NULL;
   870     }
   871     if (surface->map != NULL) {
   872         SDL_FreeBlitMap(surface->map);
   873         surface->map = NULL;
   874     }
   875     if (surface->pixels && ((surface->flags & SDL_PREALLOC) != SDL_PREALLOC)) {
   876         SDL_free(surface->pixels);
   877     }
   878     SDL_free(surface);
   879 #ifdef CHECK_LEAKS
   880     --surfaces_allocated;
   881 #endif
   882 }
   883 
   884 /* vi: set ts=4 sw=4 expandtab: */