src/video/SDL_surface.c
author Edgar Simo <bobbens@gmail.com>
Sun, 06 Jul 2008 17:06:37 +0000
branchgsoc2008_force_feedback
changeset 2498 ab567bd667bf
parent 2329 c1a390f6a819
child 2698 e1da92da346c
permissions -rw-r--r--
Fixed various mistakes in the doxygen.
     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         /* just here for debugging */
   546 /*         printf */
   547 /*             ("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", */
   548 /*              src, dst->flags, src->map->info.flags, dst, dst->flags, */
   549 /*              dst->map->info.flags, src->map->blit); */
   550     }
   551     return (src->map->blit(src, srcrect, dst, dstrect));
   552 }
   553 
   554 
   555 int
   556 SDL_UpperBlit(SDL_Surface * src, SDL_Rect * srcrect,
   557               SDL_Surface * dst, SDL_Rect * dstrect)
   558 {
   559     SDL_Rect fulldst;
   560     int srcx, srcy, w, h;
   561 
   562     /* Make sure the surfaces aren't locked */
   563     if (!src || !dst) {
   564         SDL_SetError("SDL_UpperBlit: passed a NULL surface");
   565         return (-1);
   566     }
   567     if (src->locked || dst->locked) {
   568         SDL_SetError("Surfaces must not be locked during blit");
   569         return (-1);
   570     }
   571 
   572     /* If the destination rectangle is NULL, use the entire dest surface */
   573     if (dstrect == NULL) {
   574         fulldst.x = fulldst.y = 0;
   575         dstrect = &fulldst;
   576     }
   577 
   578     /* clip the source rectangle to the source surface */
   579     if (srcrect) {
   580         int maxw, maxh;
   581 
   582         srcx = srcrect->x;
   583         w = srcrect->w;
   584         if (srcx < 0) {
   585             w += srcx;
   586             dstrect->x -= srcx;
   587             srcx = 0;
   588         }
   589         maxw = src->w - srcx;
   590         if (maxw < w)
   591             w = maxw;
   592 
   593         srcy = srcrect->y;
   594         h = srcrect->h;
   595         if (srcy < 0) {
   596             h += srcy;
   597             dstrect->y -= srcy;
   598             srcy = 0;
   599         }
   600         maxh = src->h - srcy;
   601         if (maxh < h)
   602             h = maxh;
   603 
   604     } else {
   605         srcx = srcy = 0;
   606         w = src->w;
   607         h = src->h;
   608     }
   609 
   610     /* clip the destination rectangle against the clip rectangle */
   611     {
   612         SDL_Rect *clip = &dst->clip_rect;
   613         int dx, dy;
   614 
   615         dx = clip->x - dstrect->x;
   616         if (dx > 0) {
   617             w -= dx;
   618             dstrect->x += dx;
   619             srcx += dx;
   620         }
   621         dx = dstrect->x + w - clip->x - clip->w;
   622         if (dx > 0)
   623             w -= dx;
   624 
   625         dy = clip->y - dstrect->y;
   626         if (dy > 0) {
   627             h -= dy;
   628             dstrect->y += dy;
   629             srcy += dy;
   630         }
   631         dy = dstrect->y + h - clip->y - clip->h;
   632         if (dy > 0)
   633             h -= dy;
   634     }
   635 
   636     if (w > 0 && h > 0) {
   637         SDL_Rect sr;
   638         sr.x = srcx;
   639         sr.y = srcy;
   640         sr.w = dstrect->w = w;
   641         sr.h = dstrect->h = h;
   642         return SDL_LowerBlit(src, &sr, dst, dstrect);
   643     }
   644     dstrect->w = dstrect->h = 0;
   645     return 0;
   646 }
   647 
   648 /*
   649  * Lock a surface to directly access the pixels
   650  */
   651 int
   652 SDL_LockSurface(SDL_Surface * surface)
   653 {
   654     if (!surface->locked) {
   655         /* Perform the lock */
   656         if (surface->flags & SDL_RLEACCEL) {
   657             SDL_UnRLESurface(surface, 1);
   658             surface->flags |= SDL_RLEACCEL;     /* save accel'd state */
   659         }
   660     }
   661 
   662     /* Increment the surface lock count, for recursive locks */
   663     ++surface->locked;
   664 
   665     /* Ready to go.. */
   666     return (0);
   667 }
   668 
   669 /*
   670  * Unlock a previously locked surface
   671  */
   672 void
   673 SDL_UnlockSurface(SDL_Surface * surface)
   674 {
   675     /* Only perform an unlock if we are locked */
   676     if (!surface->locked || (--surface->locked > 0)) {
   677         return;
   678     }
   679 
   680     /* Update RLE encoded surface with new data */
   681     if ((surface->flags & SDL_RLEACCEL) == SDL_RLEACCEL) {
   682         surface->flags &= ~SDL_RLEACCEL;        /* stop lying */
   683         SDL_RLESurface(surface);
   684     }
   685 }
   686 
   687 /* 
   688  * Convert a surface into the specified pixel format.
   689  */
   690 SDL_Surface *
   691 SDL_ConvertSurface(SDL_Surface * surface,
   692                    SDL_PixelFormat * format, Uint32 flags)
   693 {
   694     SDL_Surface *convert;
   695     Uint32 copy_flags;
   696     SDL_Rect bounds;
   697 
   698     /* Check for empty destination palette! (results in empty image) */
   699     if (format->palette != NULL) {
   700         int i;
   701         for (i = 0; i < format->palette->ncolors; ++i) {
   702             if ((format->palette->colors[i].r != 0xFF) ||
   703                 (format->palette->colors[i].g != 0xFF) ||
   704                 (format->palette->colors[i].b != 0xFF))
   705                 break;
   706         }
   707         if (i == format->palette->ncolors) {
   708             SDL_SetError("Empty destination palette");
   709             return (NULL);
   710         }
   711     }
   712 
   713     /* Create a new surface with the desired format */
   714     convert = SDL_CreateRGBSurface(0, surface->w, surface->h,
   715                                    format->BitsPerPixel, format->Rmask,
   716                                    format->Gmask, format->Bmask,
   717                                    format->Amask);
   718     if (convert == NULL) {
   719         return (NULL);
   720     }
   721 
   722     /* Copy the palette if any */
   723     if (format->palette && convert->format->palette) {
   724         SDL_memcpy(convert->format->palette->colors,
   725                    format->palette->colors,
   726                    format->palette->ncolors * sizeof(SDL_Color));
   727         convert->format->palette->ncolors = format->palette->ncolors;
   728     }
   729 
   730     /* Save the original copy flags */
   731     copy_flags = surface->map->info.flags;
   732     surface->map->info.flags = 0;
   733 
   734     /* Copy over the image data */
   735     bounds.x = 0;
   736     bounds.y = 0;
   737     bounds.w = surface->w;
   738     bounds.h = surface->h;
   739     SDL_LowerBlit(surface, &bounds, convert, &bounds);
   740 
   741     /* Clean up the original surface, and update converted surface */
   742     SDL_SetClipRect(convert, &surface->clip_rect);
   743     if (copy_flags & SDL_COPY_COLORKEY) {
   744         Uint8 keyR, keyG, keyB, keyA;
   745 
   746         SDL_GetRGBA(surface->map->info.colorkey, surface->format, &keyR,
   747                     &keyG, &keyB, &keyA);
   748         SDL_SetColorKey(convert, 1,
   749                         SDL_MapRGBA(convert->format, keyR, keyG, keyB, keyA));
   750     }
   751     convert->map->info.r = surface->map->info.r;
   752     convert->map->info.g = surface->map->info.g;
   753     convert->map->info.b = surface->map->info.b;
   754     convert->map->info.a = surface->map->info.a;
   755     convert->map->info.flags = copy_flags;
   756     surface->map->info.flags = copy_flags;
   757 
   758     /* Enable alpha blending by default if the new surface has an
   759      * alpha channel or alpha modulation */
   760     if (format->Amask || (copy_flags & SDL_COPY_MODULATE_ALPHA)) {
   761         SDL_SetSurfaceBlendMode(convert, SDL_TEXTUREBLENDMODE_BLEND);
   762     }
   763 
   764     /* We're ready to go! */
   765     return (convert);
   766 }
   767 
   768 /*
   769  * Free a surface created by the above function.
   770  */
   771 void
   772 SDL_FreeSurface(SDL_Surface * surface)
   773 {
   774     if (surface == NULL) {
   775         return;
   776     }
   777     if (--surface->refcount > 0) {
   778         return;
   779     }
   780     while (surface->locked > 0) {
   781         SDL_UnlockSurface(surface);
   782     }
   783     if (surface->flags & SDL_RLEACCEL) {
   784         SDL_UnRLESurface(surface, 0);
   785     }
   786     if (surface->format) {
   787         SDL_SetSurfacePalette(surface, NULL);
   788         SDL_FreeFormat(surface->format);
   789         surface->format = NULL;
   790     }
   791     if (surface->map != NULL) {
   792         SDL_FreeBlitMap(surface->map);
   793         surface->map = NULL;
   794     }
   795     if (surface->pixels && ((surface->flags & SDL_PREALLOC) != SDL_PREALLOC)) {
   796         SDL_free(surface->pixels);
   797     }
   798     SDL_free(surface);
   799 #ifdef CHECK_LEAKS
   800     --surfaces_allocated;
   801 #endif
   802 }
   803 
   804 /* vi: set ts=4 sw=4 expandtab: */