src/video/SDL_surface.c
author Sam Lantinga <slouken@libsdl.org>
Sat, 18 Aug 2007 05:39:09 +0000
changeset 2267 c785543d1843
parent 2266 e61ad15a205f
child 2328 91e601d9df8b
permissions -rw-r--r--
Okay, still some bugs, but everything builds again...
     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 int
   273 SDL_SetSurfaceColorMod(SDL_Surface * surface, Uint8 r, Uint8 g, Uint8 b)
   274 {
   275     int flags;
   276 
   277     if (!surface) {
   278         return -1;
   279     }
   280 
   281     surface->map->info.r = r;
   282     surface->map->info.g = g;
   283     surface->map->info.b = b;
   284 
   285     flags = surface->map->info.flags;
   286     if (r != 0xFF || g != 0xFF || b != 0xFF) {
   287         surface->map->info.flags |= SDL_COPY_MODULATE_COLOR;
   288     } else {
   289         surface->map->info.flags &= ~SDL_COPY_MODULATE_COLOR;
   290     }
   291     if (surface->map->info.flags != flags) {
   292         SDL_InvalidateMap(surface->map);
   293     }
   294     return 0;
   295 }
   296 
   297 
   298 int
   299 SDL_GetSurfaceColorMod(SDL_Surface * surface, Uint8 * r, Uint8 * g, Uint8 * b)
   300 {
   301     if (!surface) {
   302         return -1;
   303     }
   304 
   305     if (r) {
   306         *r = surface->map->info.r;
   307     }
   308     if (g) {
   309         *g = surface->map->info.g;
   310     }
   311     if (b) {
   312         *b = surface->map->info.b;
   313     }
   314     return 0;
   315 }
   316 
   317 int
   318 SDL_SetSurfaceAlphaMod(SDL_Surface * surface, Uint8 alpha)
   319 {
   320     int flags;
   321 
   322     if (!surface) {
   323         return -1;
   324     }
   325 
   326     surface->map->info.a = alpha;
   327 
   328     flags = surface->map->info.flags;
   329     if (alpha != 0xFF) {
   330         surface->map->info.flags |= SDL_COPY_MODULATE_ALPHA;
   331     } else {
   332         surface->map->info.flags &= ~SDL_COPY_MODULATE_ALPHA;
   333     }
   334     if (surface->map->info.flags != flags) {
   335         SDL_InvalidateMap(surface->map);
   336     }
   337     return 0;
   338 }
   339 
   340 int
   341 SDL_GetSurfaceAlphaMod(SDL_Surface * surface, Uint8 * alpha)
   342 {
   343     if (!surface) {
   344         return -1;
   345     }
   346 
   347     if (alpha) {
   348         *alpha = surface->map->info.a;
   349     }
   350     return 0;
   351 }
   352 
   353 int
   354 SDL_SetSurfaceBlendMode(SDL_Surface * surface, int blendMode)
   355 {
   356     int flags, status;
   357 
   358     if (!surface) {
   359         return -1;
   360     }
   361 
   362     status = 0;
   363     flags = surface->map->info.flags;
   364     surface->map->info.flags &=
   365         ~(SDL_COPY_MASK | SDL_COPY_BLEND | SDL_COPY_ADD | SDL_COPY_MOD);
   366     switch (blendMode) {
   367     case SDL_TEXTUREBLENDMODE_NONE:
   368         break;
   369     case SDL_TEXTUREBLENDMODE_MASK:
   370         surface->map->info.flags |= SDL_COPY_MASK;
   371         break;
   372     case SDL_TEXTUREBLENDMODE_BLEND:
   373         surface->map->info.flags |= SDL_COPY_BLEND;
   374         break;
   375     case SDL_TEXTUREBLENDMODE_ADD:
   376         surface->map->info.flags |= SDL_COPY_ADD;
   377         break;
   378     case SDL_TEXTUREBLENDMODE_MOD:
   379         surface->map->info.flags |= SDL_COPY_MOD;
   380         break;
   381     default:
   382         SDL_Unsupported();
   383         status = -1;
   384         break;
   385     }
   386 
   387     if (surface->map->info.flags != flags) {
   388         SDL_InvalidateMap(surface->map);
   389     }
   390 
   391     /* Compatibility mode */
   392     if (surface->map->info.flags & SDL_COPY_BLEND) {
   393         surface->flags |= SDL_SRCALPHA;
   394     } else {
   395         surface->flags &= ~SDL_SRCALPHA;
   396     }
   397 
   398     return status;
   399 }
   400 
   401 int
   402 SDL_GetSurfaceBlendMode(SDL_Surface * surface, int *blendMode)
   403 {
   404     if (!surface) {
   405         return -1;
   406     }
   407 
   408     if (!blendMode) {
   409         return 0;
   410     }
   411 
   412     switch (surface->map->info.
   413             flags & (SDL_COPY_MASK | SDL_COPY_BLEND | SDL_COPY_ADD |
   414                      SDL_COPY_MOD)) {
   415     case SDL_COPY_MASK:
   416         *blendMode = SDL_TEXTUREBLENDMODE_MASK;
   417         break;
   418     case SDL_COPY_BLEND:
   419         *blendMode = SDL_TEXTUREBLENDMODE_BLEND;
   420         break;
   421     case SDL_COPY_ADD:
   422         *blendMode = SDL_TEXTUREBLENDMODE_ADD;
   423         break;
   424     case SDL_COPY_MOD:
   425         *blendMode = SDL_TEXTUREBLENDMODE_MOD;
   426         break;
   427     default:
   428         *blendMode = SDL_TEXTUREBLENDMODE_NONE;
   429         break;
   430     }
   431     return 0;
   432 }
   433 
   434 int
   435 SDL_SetSurfaceScaleMode(SDL_Surface * surface, int scaleMode)
   436 {
   437     int flags, status;
   438 
   439     if (!surface) {
   440         return -1;
   441     }
   442 
   443     status = 0;
   444     flags = surface->map->info.flags;
   445     surface->map->info.flags &= ~(SDL_COPY_NEAREST);
   446     switch (scaleMode) {
   447     case SDL_TEXTURESCALEMODE_NONE:
   448         break;
   449     case SDL_TEXTURESCALEMODE_FAST:
   450         surface->map->info.flags |= SDL_COPY_NEAREST;
   451         break;
   452     case SDL_TEXTURESCALEMODE_SLOW:
   453     case SDL_TEXTURESCALEMODE_BEST:
   454         SDL_Unsupported();
   455         surface->map->info.flags |= SDL_COPY_NEAREST;
   456         status = -1;
   457         break;
   458     default:
   459         SDL_Unsupported();
   460         status = -1;
   461         break;
   462     }
   463 
   464     if (surface->map->info.flags != flags) {
   465         SDL_InvalidateMap(surface->map);
   466     }
   467     return status;
   468 }
   469 
   470 int
   471 SDL_GetSurfaceScaleMode(SDL_Surface * surface, int *scaleMode)
   472 {
   473     if (!surface) {
   474         return -1;
   475     }
   476 
   477     if (!scaleMode) {
   478         return 0;
   479     }
   480 
   481     switch (surface->map->info.flags & (SDL_COPY_NEAREST)) {
   482     case SDL_COPY_NEAREST:
   483         *scaleMode = SDL_TEXTURESCALEMODE_FAST;
   484         break;
   485     default:
   486         *scaleMode = SDL_TEXTURESCALEMODE_NONE;
   487         break;
   488     }
   489     return 0;
   490 }
   491 
   492 SDL_bool
   493 SDL_SetClipRect(SDL_Surface * surface, const SDL_Rect * rect)
   494 {
   495     SDL_Rect full_rect;
   496 
   497     /* Don't do anything if there's no surface to act on */
   498     if (!surface) {
   499         return SDL_FALSE;
   500     }
   501 
   502     /* Set up the full surface rectangle */
   503     full_rect.x = 0;
   504     full_rect.y = 0;
   505     full_rect.w = surface->w;
   506     full_rect.h = surface->h;
   507 
   508     /* Set the clipping rectangle */
   509     if (!rect) {
   510         surface->clip_rect = full_rect;
   511         return 1;
   512     }
   513     return SDL_IntersectRect(rect, &full_rect, &surface->clip_rect);
   514 }
   515 
   516 void
   517 SDL_GetClipRect(SDL_Surface * surface, SDL_Rect * rect)
   518 {
   519     if (surface && rect) {
   520         *rect = surface->clip_rect;
   521     }
   522 }
   523 
   524 /* 
   525  * Set up a blit between two surfaces -- split into three parts:
   526  * The upper part, SDL_UpperBlit(), performs clipping and rectangle 
   527  * verification.  The lower part is a pointer to a low level
   528  * accelerated blitting function.
   529  *
   530  * These parts are separated out and each used internally by this 
   531  * library in the optimimum places.  They are exported so that if
   532  * you know exactly what you are doing, you can optimize your code
   533  * by calling the one(s) you need.
   534  */
   535 int
   536 SDL_LowerBlit(SDL_Surface * src, SDL_Rect * srcrect,
   537               SDL_Surface * dst, SDL_Rect * dstrect)
   538 {
   539     /* Check to make sure the blit mapping is valid */
   540     if ((src->map->dst != dst) ||
   541         (src->map->dst->format_version != src->map->format_version)) {
   542         if (SDL_MapSurface(src, dst) < 0) {
   543             return (-1);
   544         }
   545     }
   546     return (src->map->blit(src, srcrect, dst, dstrect));
   547 }
   548 
   549 
   550 int
   551 SDL_UpperBlit(SDL_Surface * src, SDL_Rect * srcrect,
   552               SDL_Surface * dst, SDL_Rect * dstrect)
   553 {
   554     SDL_Rect fulldst;
   555     int srcx, srcy, w, h;
   556 
   557     /* Make sure the surfaces aren't locked */
   558     if (!src || !dst) {
   559         SDL_SetError("SDL_UpperBlit: passed a NULL surface");
   560         return (-1);
   561     }
   562     if (src->locked || dst->locked) {
   563         SDL_SetError("Surfaces must not be locked during blit");
   564         return (-1);
   565     }
   566 
   567     /* If the destination rectangle is NULL, use the entire dest surface */
   568     if (dstrect == NULL) {
   569         fulldst.x = fulldst.y = 0;
   570         dstrect = &fulldst;
   571     }
   572 
   573     /* clip the source rectangle to the source surface */
   574     if (srcrect) {
   575         int maxw, maxh;
   576 
   577         srcx = srcrect->x;
   578         w = srcrect->w;
   579         if (srcx < 0) {
   580             w += srcx;
   581             dstrect->x -= srcx;
   582             srcx = 0;
   583         }
   584         maxw = src->w - srcx;
   585         if (maxw < w)
   586             w = maxw;
   587 
   588         srcy = srcrect->y;
   589         h = srcrect->h;
   590         if (srcy < 0) {
   591             h += srcy;
   592             dstrect->y -= srcy;
   593             srcy = 0;
   594         }
   595         maxh = src->h - srcy;
   596         if (maxh < h)
   597             h = maxh;
   598 
   599     } else {
   600         srcx = srcy = 0;
   601         w = src->w;
   602         h = src->h;
   603     }
   604 
   605     /* clip the destination rectangle against the clip rectangle */
   606     {
   607         SDL_Rect *clip = &dst->clip_rect;
   608         int dx, dy;
   609 
   610         dx = clip->x - dstrect->x;
   611         if (dx > 0) {
   612             w -= dx;
   613             dstrect->x += dx;
   614             srcx += dx;
   615         }
   616         dx = dstrect->x + w - clip->x - clip->w;
   617         if (dx > 0)
   618             w -= dx;
   619 
   620         dy = clip->y - dstrect->y;
   621         if (dy > 0) {
   622             h -= dy;
   623             dstrect->y += dy;
   624             srcy += dy;
   625         }
   626         dy = dstrect->y + h - clip->y - clip->h;
   627         if (dy > 0)
   628             h -= dy;
   629     }
   630 
   631     if (w > 0 && h > 0) {
   632         SDL_Rect sr;
   633         sr.x = srcx;
   634         sr.y = srcy;
   635         sr.w = dstrect->w = w;
   636         sr.h = dstrect->h = h;
   637         return SDL_LowerBlit(src, &sr, dst, dstrect);
   638     }
   639     dstrect->w = dstrect->h = 0;
   640     return 0;
   641 }
   642 
   643 /*
   644  * Lock a surface to directly access the pixels
   645  */
   646 int
   647 SDL_LockSurface(SDL_Surface * surface)
   648 {
   649     if (!surface->locked) {
   650         /* Perform the lock */
   651         if (surface->flags & SDL_RLEACCEL) {
   652             SDL_UnRLESurface(surface, 1);
   653             surface->flags |= SDL_RLEACCEL;     /* save accel'd state */
   654         }
   655     }
   656 
   657     /* Increment the surface lock count, for recursive locks */
   658     ++surface->locked;
   659 
   660     /* Ready to go.. */
   661     return (0);
   662 }
   663 
   664 /*
   665  * Unlock a previously locked surface
   666  */
   667 void
   668 SDL_UnlockSurface(SDL_Surface * surface)
   669 {
   670     /* Only perform an unlock if we are locked */
   671     if (!surface->locked || (--surface->locked > 0)) {
   672         return;
   673     }
   674 
   675     /* Update RLE encoded surface with new data */
   676     if ((surface->flags & SDL_RLEACCEL) == SDL_RLEACCEL) {
   677         surface->flags &= ~SDL_RLEACCEL;        /* stop lying */
   678         SDL_RLESurface(surface);
   679     }
   680 }
   681 
   682 /* 
   683  * Convert a surface into the specified pixel format.
   684  */
   685 SDL_Surface *
   686 SDL_ConvertSurface(SDL_Surface * surface,
   687                    SDL_PixelFormat * format, Uint32 flags)
   688 {
   689     SDL_Surface *convert;
   690     Uint32 copy_flags;
   691     SDL_Rect bounds;
   692 
   693     /* Check for empty destination palette! (results in empty image) */
   694     if (format->palette != NULL) {
   695         int i;
   696         for (i = 0; i < format->palette->ncolors; ++i) {
   697             if ((format->palette->colors[i].r != 0xFF) ||
   698                 (format->palette->colors[i].g != 0xFF) ||
   699                 (format->palette->colors[i].b != 0xFF))
   700                 break;
   701         }
   702         if (i == format->palette->ncolors) {
   703             SDL_SetError("Empty destination palette");
   704             return (NULL);
   705         }
   706     }
   707 
   708     /* Create a new surface with the desired format */
   709     convert = SDL_CreateRGBSurface(0, surface->w, surface->h,
   710                                    format->BitsPerPixel, format->Rmask,
   711                                    format->Gmask, format->Bmask,
   712                                    format->Amask);
   713     if (convert == NULL) {
   714         return (NULL);
   715     }
   716 
   717     /* Copy the palette if any */
   718     if (format->palette && convert->format->palette) {
   719         SDL_memcpy(convert->format->palette->colors,
   720                    format->palette->colors,
   721                    format->palette->ncolors * sizeof(SDL_Color));
   722         convert->format->palette->ncolors = format->palette->ncolors;
   723     }
   724 
   725     /* Save the original copy flags */
   726     copy_flags = surface->map->info.flags;
   727     surface->map->info.flags = 0;
   728 
   729     /* Copy over the image data */
   730     bounds.x = 0;
   731     bounds.y = 0;
   732     bounds.w = surface->w;
   733     bounds.h = surface->h;
   734     SDL_LowerBlit(surface, &bounds, convert, &bounds);
   735 
   736     /* Clean up the original surface, and update converted surface */
   737     SDL_SetClipRect(convert, &surface->clip_rect);
   738     if (copy_flags & SDL_COPY_COLORKEY) {
   739         Uint8 keyR, keyG, keyB, keyA;
   740 
   741         SDL_GetRGBA(surface->map->info.colorkey, surface->format, &keyR,
   742                     &keyG, &keyB, &keyA);
   743         SDL_SetColorKey(convert, 1,
   744                         SDL_MapRGBA(convert->format, keyR, keyG, keyB, keyA));
   745     }
   746     convert->map->info.r = surface->map->info.r;
   747     convert->map->info.g = surface->map->info.g;
   748     convert->map->info.b = surface->map->info.b;
   749     convert->map->info.a = surface->map->info.a;
   750     convert->map->info.flags = copy_flags;
   751     surface->map->info.flags = copy_flags;
   752 
   753     /* Enable alpha blending by default if the new surface has an
   754      * alpha channel or alpha modulation */
   755     if (format->Amask || (copy_flags & SDL_COPY_MODULATE_ALPHA)) {
   756         SDL_SetSurfaceBlendMode(convert, SDL_TEXTUREBLENDMODE_BLEND);
   757     }
   758 
   759     /* We're ready to go! */
   760     return (convert);
   761 }
   762 
   763 /*
   764  * Free a surface created by the above function.
   765  */
   766 void
   767 SDL_FreeSurface(SDL_Surface * surface)
   768 {
   769     if (surface == NULL) {
   770         return;
   771     }
   772     if (--surface->refcount > 0) {
   773         return;
   774     }
   775     while (surface->locked > 0) {
   776         SDL_UnlockSurface(surface);
   777     }
   778     if (surface->flags & SDL_RLEACCEL) {
   779         SDL_UnRLESurface(surface, 0);
   780     }
   781     if (surface->format) {
   782         SDL_SetSurfacePalette(surface, NULL);
   783         SDL_FreeFormat(surface->format);
   784         surface->format = NULL;
   785     }
   786     if (surface->map != NULL) {
   787         SDL_FreeBlitMap(surface->map);
   788         surface->map = NULL;
   789     }
   790     if (surface->pixels && ((surface->flags & SDL_PREALLOC) != SDL_PREALLOC)) {
   791         SDL_free(surface->pixels);
   792     }
   793     SDL_free(surface);
   794 #ifdef CHECK_LEAKS
   795     --surfaces_allocated;
   796 #endif
   797 }
   798 
   799 /* vi: set ts=4 sw=4 expandtab: */