src/video/SDL_surface.c
author Sam Lantinga <slouken@libsdl.org>
Fri, 11 Feb 2011 14:23:22 -0800
changeset 5256 bbdf9250ee8b
parent 5184 d976b67150c5
child 5258 f26314c20071
permissions -rw-r--r--
Removed unused leak detection code.
     1 /*
     2     SDL - Simple DirectMedia Layer
     3     Copyright (C) 1997-2010 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     (void)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     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, int 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_GetColorKey(SDL_Surface * surface, Uint32 * key)
   274 {
   275     if (!surface) {
   276         return -1;
   277     }
   278 
   279     if (!(surface->map->info.flags & SDL_COPY_COLORKEY)) {
   280         return -1;
   281     }
   282 
   283     if (key) {
   284         *key = surface->map->info.colorkey;
   285     }
   286     return 0;
   287 }
   288 
   289 /* This is a fairly slow function to switch from colorkey to alpha */
   290 static void
   291 SDL_ConvertColorkeyToAlpha(SDL_Surface * surface)
   292 {
   293     int x, y;
   294 
   295     if (!surface) {
   296         return;
   297     }
   298 
   299     if (!(surface->map->info.flags & SDL_COPY_COLORKEY) ||
   300         !surface->format->Amask) {
   301         return;
   302     }
   303 
   304     SDL_LockSurface(surface);
   305 
   306     switch (surface->format->BytesPerPixel) {
   307     case 2:
   308         {
   309             Uint16 *row, *spot;
   310             Uint16 ckey = (Uint16) surface->map->info.colorkey;
   311             Uint16 mask = (Uint16) (~surface->format->Amask);
   312 
   313             row = (Uint16 *) surface->pixels;
   314             for (y = surface->h; y--;) {
   315                 spot = row;
   316                 for (x = surface->w; x--;) {
   317                     if (*spot == ckey) {
   318                         *spot &= mask;
   319                     }
   320                     ++spot;
   321                 }
   322                 row += surface->pitch / 2;
   323             }
   324         }
   325         break;
   326     case 3:
   327         /* FIXME */
   328         break;
   329     case 4:
   330         {
   331             Uint32 *row, *spot;
   332             Uint32 ckey = surface->map->info.colorkey;
   333             Uint32 mask = ~surface->format->Amask;
   334 
   335             row = (Uint32 *) surface->pixels;
   336             for (y = surface->h; y--;) {
   337                 spot = row;
   338                 for (x = surface->w; x--;) {
   339                     if (*spot == ckey) {
   340                         *spot &= mask;
   341                     }
   342                     ++spot;
   343                 }
   344                 row += surface->pitch / 4;
   345             }
   346         }
   347         break;
   348     }
   349 
   350     SDL_UnlockSurface(surface);
   351 
   352     SDL_SetColorKey(surface, 0, 0);
   353     SDL_SetSurfaceBlendMode(surface, SDL_BLENDMODE_BLEND);
   354 }
   355 
   356 int
   357 SDL_SetSurfaceColorMod(SDL_Surface * surface, Uint8 r, Uint8 g, Uint8 b)
   358 {
   359     int flags;
   360 
   361     if (!surface) {
   362         return -1;
   363     }
   364 
   365     surface->map->info.r = r;
   366     surface->map->info.g = g;
   367     surface->map->info.b = b;
   368 
   369     flags = surface->map->info.flags;
   370     if (r != 0xFF || g != 0xFF || b != 0xFF) {
   371         surface->map->info.flags |= SDL_COPY_MODULATE_COLOR;
   372     } else {
   373         surface->map->info.flags &= ~SDL_COPY_MODULATE_COLOR;
   374     }
   375     if (surface->map->info.flags != flags) {
   376         SDL_InvalidateMap(surface->map);
   377     }
   378     return 0;
   379 }
   380 
   381 
   382 int
   383 SDL_GetSurfaceColorMod(SDL_Surface * surface, Uint8 * r, Uint8 * g, Uint8 * b)
   384 {
   385     if (!surface) {
   386         return -1;
   387     }
   388 
   389     if (r) {
   390         *r = surface->map->info.r;
   391     }
   392     if (g) {
   393         *g = surface->map->info.g;
   394     }
   395     if (b) {
   396         *b = surface->map->info.b;
   397     }
   398     return 0;
   399 }
   400 
   401 int
   402 SDL_SetSurfaceAlphaMod(SDL_Surface * surface, Uint8 alpha)
   403 {
   404     int flags;
   405 
   406     if (!surface) {
   407         return -1;
   408     }
   409 
   410     surface->map->info.a = alpha;
   411 
   412     flags = surface->map->info.flags;
   413     if (alpha != 0xFF) {
   414         surface->map->info.flags |= SDL_COPY_MODULATE_ALPHA;
   415     } else {
   416         surface->map->info.flags &= ~SDL_COPY_MODULATE_ALPHA;
   417     }
   418     if (surface->map->info.flags != flags) {
   419         SDL_InvalidateMap(surface->map);
   420     }
   421     return 0;
   422 }
   423 
   424 int
   425 SDL_GetSurfaceAlphaMod(SDL_Surface * surface, Uint8 * alpha)
   426 {
   427     if (!surface) {
   428         return -1;
   429     }
   430 
   431     if (alpha) {
   432         *alpha = surface->map->info.a;
   433     }
   434     return 0;
   435 }
   436 
   437 int
   438 SDL_SetSurfaceBlendMode(SDL_Surface * surface, SDL_BlendMode blendMode)
   439 {
   440     int flags, status;
   441 
   442     if (!surface) {
   443         return -1;
   444     }
   445 
   446     status = 0;
   447     flags = surface->map->info.flags;
   448     surface->map->info.flags &=
   449         ~(SDL_COPY_BLEND | SDL_COPY_ADD | SDL_COPY_MOD);
   450     switch (blendMode) {
   451     case SDL_BLENDMODE_NONE:
   452         break;
   453     case SDL_BLENDMODE_BLEND:
   454         surface->map->info.flags |= SDL_COPY_BLEND;
   455         break;
   456     case SDL_BLENDMODE_ADD:
   457         surface->map->info.flags |= SDL_COPY_ADD;
   458         break;
   459     case SDL_BLENDMODE_MOD:
   460         surface->map->info.flags |= SDL_COPY_MOD;
   461         break;
   462     default:
   463         SDL_Unsupported();
   464         status = -1;
   465         break;
   466     }
   467 
   468     if (surface->map->info.flags != flags) {
   469         SDL_InvalidateMap(surface->map);
   470     }
   471 
   472     /* Compatibility mode */
   473     if (surface->map->info.flags & SDL_COPY_BLEND) {
   474         surface->flags |= SDL_SRCALPHA;
   475     } else {
   476         surface->flags &= ~SDL_SRCALPHA;
   477     }
   478 
   479     return status;
   480 }
   481 
   482 int
   483 SDL_GetSurfaceBlendMode(SDL_Surface * surface, SDL_BlendMode *blendMode)
   484 {
   485     if (!surface) {
   486         return -1;
   487     }
   488 
   489     if (!blendMode) {
   490         return 0;
   491     }
   492 
   493     switch (surface->map->
   494             info.flags & (SDL_COPY_BLEND | SDL_COPY_ADD | SDL_COPY_MOD)) {
   495     case SDL_COPY_BLEND:
   496         *blendMode = SDL_BLENDMODE_BLEND;
   497         break;
   498     case SDL_COPY_ADD:
   499         *blendMode = SDL_BLENDMODE_ADD;
   500         break;
   501     case SDL_COPY_MOD:
   502         *blendMode = SDL_BLENDMODE_MOD;
   503         break;
   504     default:
   505         *blendMode = SDL_BLENDMODE_NONE;
   506         break;
   507     }
   508     return 0;
   509 }
   510 
   511 SDL_bool
   512 SDL_SetClipRect(SDL_Surface * surface, const SDL_Rect * rect)
   513 {
   514     SDL_Rect full_rect;
   515 
   516     /* Don't do anything if there's no surface to act on */
   517     if (!surface) {
   518         return SDL_FALSE;
   519     }
   520 
   521     /* Set up the full surface rectangle */
   522     full_rect.x = 0;
   523     full_rect.y = 0;
   524     full_rect.w = surface->w;
   525     full_rect.h = surface->h;
   526 
   527     /* Set the clipping rectangle */
   528     if (!rect) {
   529         surface->clip_rect = full_rect;
   530         return SDL_TRUE;
   531     }
   532     return SDL_IntersectRect(rect, &full_rect, &surface->clip_rect);
   533 }
   534 
   535 void
   536 SDL_GetClipRect(SDL_Surface * surface, SDL_Rect * rect)
   537 {
   538     if (surface && rect) {
   539         *rect = surface->clip_rect;
   540     }
   541 }
   542 
   543 /* 
   544  * Set up a blit between two surfaces -- split into three parts:
   545  * The upper part, SDL_UpperBlit(), performs clipping and rectangle 
   546  * verification.  The lower part is a pointer to a low level
   547  * accelerated blitting function.
   548  *
   549  * These parts are separated out and each used internally by this 
   550  * library in the optimimum places.  They are exported so that if
   551  * you know exactly what you are doing, you can optimize your code
   552  * by calling the one(s) you need.
   553  */
   554 int
   555 SDL_LowerBlit(SDL_Surface * src, SDL_Rect * srcrect,
   556               SDL_Surface * dst, SDL_Rect * dstrect)
   557 {
   558     /* Check to make sure the blit mapping is valid */
   559     if ((src->map->dst != dst) ||
   560         (src->map->dst->format_version != src->map->format_version)) {
   561         if (SDL_MapSurface(src, dst) < 0) {
   562             return (-1);
   563         }
   564         /* just here for debugging */
   565 /*         printf */
   566 /*             ("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", */
   567 /*              src, dst->flags, src->map->info.flags, dst, dst->flags, */
   568 /*              dst->map->info.flags, src->map->blit); */
   569     }
   570     return (src->map->blit(src, srcrect, dst, dstrect));
   571 }
   572 
   573 
   574 int
   575 SDL_UpperBlit(SDL_Surface * src, const SDL_Rect * srcrect,
   576               SDL_Surface * dst, SDL_Rect * dstrect)
   577 {
   578     SDL_Rect fulldst;
   579     int srcx, srcy, w, h;
   580 
   581     /* Make sure the surfaces aren't locked */
   582     if (!src || !dst) {
   583         SDL_SetError("SDL_UpperBlit: passed a NULL surface");
   584         return (-1);
   585     }
   586     if (src->locked || dst->locked) {
   587         SDL_SetError("Surfaces must not be locked during blit");
   588         return (-1);
   589     }
   590 
   591     /* If the destination rectangle is NULL, use the entire dest surface */
   592     if (dstrect == NULL) {
   593         fulldst.x = fulldst.y = 0;
   594         dstrect = &fulldst;
   595     }
   596 
   597     /* clip the source rectangle to the source surface */
   598     if (srcrect) {
   599         int maxw, maxh;
   600 
   601         srcx = srcrect->x;
   602         w = srcrect->w;
   603         if (srcx < 0) {
   604             w += srcx;
   605             dstrect->x -= srcx;
   606             srcx = 0;
   607         }
   608         maxw = src->w - srcx;
   609         if (maxw < w)
   610             w = maxw;
   611 
   612         srcy = srcrect->y;
   613         h = srcrect->h;
   614         if (srcy < 0) {
   615             h += srcy;
   616             dstrect->y -= srcy;
   617             srcy = 0;
   618         }
   619         maxh = src->h - srcy;
   620         if (maxh < h)
   621             h = maxh;
   622 
   623     } else {
   624         srcx = srcy = 0;
   625         w = src->w;
   626         h = src->h;
   627     }
   628 
   629     /* clip the destination rectangle against the clip rectangle */
   630     {
   631         SDL_Rect *clip = &dst->clip_rect;
   632         int dx, dy;
   633 
   634         dx = clip->x - dstrect->x;
   635         if (dx > 0) {
   636             w -= dx;
   637             dstrect->x += dx;
   638             srcx += dx;
   639         }
   640         dx = dstrect->x + w - clip->x - clip->w;
   641         if (dx > 0)
   642             w -= dx;
   643 
   644         dy = clip->y - dstrect->y;
   645         if (dy > 0) {
   646             h -= dy;
   647             dstrect->y += dy;
   648             srcy += dy;
   649         }
   650         dy = dstrect->y + h - clip->y - clip->h;
   651         if (dy > 0)
   652             h -= dy;
   653     }
   654 
   655     if (w > 0 && h > 0) {
   656         SDL_Rect sr;
   657         sr.x = srcx;
   658         sr.y = srcy;
   659         sr.w = dstrect->w = w;
   660         sr.h = dstrect->h = h;
   661         return SDL_LowerBlit(src, &sr, dst, dstrect);
   662     }
   663     dstrect->w = dstrect->h = 0;
   664     return 0;
   665 }
   666 
   667 /*
   668  * Lock a surface to directly access the pixels
   669  */
   670 int
   671 SDL_LockSurface(SDL_Surface * surface)
   672 {
   673     if (!surface->locked) {
   674         /* Perform the lock */
   675         if (surface->flags & SDL_RLEACCEL) {
   676             SDL_UnRLESurface(surface, 1);
   677             surface->flags |= SDL_RLEACCEL;     /* save accel'd state */
   678         }
   679     }
   680 
   681     /* Increment the surface lock count, for recursive locks */
   682     ++surface->locked;
   683 
   684     /* Ready to go.. */
   685     return (0);
   686 }
   687 
   688 /*
   689  * Unlock a previously locked surface
   690  */
   691 void
   692 SDL_UnlockSurface(SDL_Surface * surface)
   693 {
   694     /* Only perform an unlock if we are locked */
   695     if (!surface->locked || (--surface->locked > 0)) {
   696         return;
   697     }
   698 
   699     /* Update RLE encoded surface with new data */
   700     if ((surface->flags & SDL_RLEACCEL) == SDL_RLEACCEL) {
   701         surface->flags &= ~SDL_RLEACCEL;        /* stop lying */
   702         SDL_RLESurface(surface);
   703     }
   704 }
   705 
   706 /* 
   707  * Convert a surface into the specified pixel format.
   708  */
   709 SDL_Surface *
   710 SDL_ConvertSurface(SDL_Surface * surface, SDL_PixelFormat * format,
   711                    Uint32 flags)
   712 {
   713     SDL_Surface *convert;
   714     Uint32 copy_flags;
   715     SDL_Rect bounds;
   716 
   717     /* Check for empty destination palette! (results in empty image) */
   718     if (format->palette != NULL) {
   719         int i;
   720         for (i = 0; i < format->palette->ncolors; ++i) {
   721             if ((format->palette->colors[i].r != 0xFF) ||
   722                 (format->palette->colors[i].g != 0xFF) ||
   723                 (format->palette->colors[i].b != 0xFF))
   724                 break;
   725         }
   726         if (i == format->palette->ncolors) {
   727             SDL_SetError("Empty destination palette");
   728             return (NULL);
   729         }
   730     }
   731 
   732     /* Create a new surface with the desired format */
   733     convert = SDL_CreateRGBSurface(flags, surface->w, surface->h,
   734                                    format->BitsPerPixel, format->Rmask,
   735                                    format->Gmask, format->Bmask,
   736                                    format->Amask);
   737     if (convert == NULL) {
   738         return (NULL);
   739     }
   740 
   741     /* Copy the palette if any */
   742     if (format->palette && convert->format->palette) {
   743         SDL_memcpy(convert->format->palette->colors,
   744                    format->palette->colors,
   745                    format->palette->ncolors * sizeof(SDL_Color));
   746         convert->format->palette->ncolors = format->palette->ncolors;
   747     }
   748 
   749     /* Save the original copy flags */
   750     copy_flags = surface->map->info.flags;
   751     surface->map->info.flags = 0;
   752 
   753     /* Copy over the image data */
   754     bounds.x = 0;
   755     bounds.y = 0;
   756     bounds.w = surface->w;
   757     bounds.h = surface->h;
   758     SDL_LowerBlit(surface, &bounds, convert, &bounds);
   759 
   760     /* Clean up the original surface, and update converted surface */
   761     convert->map->info.r = surface->map->info.r;
   762     convert->map->info.g = surface->map->info.g;
   763     convert->map->info.b = surface->map->info.b;
   764     convert->map->info.a = surface->map->info.a;
   765     convert->map->info.flags =
   766         (copy_flags &
   767          ~(SDL_COPY_COLORKEY | SDL_COPY_BLEND
   768            | SDL_COPY_RLE_DESIRED | SDL_COPY_RLE_COLORKEY |
   769            SDL_COPY_RLE_ALPHAKEY));
   770     surface->map->info.flags = copy_flags;
   771     if (copy_flags & SDL_COPY_COLORKEY) {
   772         Uint8 keyR, keyG, keyB, keyA;
   773 
   774         SDL_GetRGBA(surface->map->info.colorkey, surface->format, &keyR,
   775                     &keyG, &keyB, &keyA);
   776         SDL_SetColorKey(convert, 1,
   777                         SDL_MapRGBA(convert->format, keyR, keyG, keyB, keyA));
   778         /* This is needed when converting for 3D texture upload */
   779         SDL_ConvertColorkeyToAlpha(convert);
   780     }
   781     SDL_SetClipRect(convert, &surface->clip_rect);
   782 
   783     /* Enable alpha blending by default if the new surface has an
   784      * alpha channel or alpha modulation */
   785     if ((surface->format->Amask && format->Amask) ||
   786         (copy_flags & (SDL_COPY_COLORKEY|SDL_COPY_MODULATE_ALPHA))) {
   787         SDL_SetSurfaceBlendMode(convert, SDL_BLENDMODE_BLEND);
   788     }
   789     if ((copy_flags & SDL_COPY_RLE_DESIRED) || (flags & SDL_RLEACCEL)) {
   790         SDL_SetSurfaceRLE(convert, SDL_RLEACCEL);
   791     }
   792 
   793     /* We're ready to go! */
   794     return (convert);
   795 }
   796 
   797 /*
   798  * Create a surface on the stack for quick blit operations
   799  */
   800 static __inline__ SDL_bool
   801 SDL_CreateSurfaceOnStack(int width, int height, Uint32 pixel_format,
   802                          void * pixels, int pitch, SDL_Surface * surface, 
   803                          SDL_PixelFormat * format, SDL_BlitMap * blitmap)
   804 {
   805     int bpp;
   806     Uint32 Rmask, Gmask, Bmask, Amask;
   807 
   808     if (!SDL_PixelFormatEnumToMasks(pixel_format,
   809                                     &bpp, &Rmask, &Gmask, &Bmask, &Amask)) {
   810         return SDL_FALSE;
   811     }
   812     if (bpp <= 8) {
   813         SDL_SetError("Indexed pixel formats not supported");
   814         return SDL_FALSE;
   815     }
   816 
   817     SDL_zerop(surface);
   818     surface->flags = SDL_PREALLOC;
   819     surface->format = SDL_InitFormat(format, bpp, Rmask, Gmask, Bmask, Amask);
   820     surface->pixels = pixels;
   821     surface->w = width;
   822     surface->h = height;
   823     surface->pitch = pitch;
   824     /* We don't actually need to set up the clip rect for our purposes */
   825     /*SDL_SetClipRect(surface, NULL);*/
   826 
   827     /* Allocate an empty mapping */
   828     SDL_zerop(blitmap);
   829     blitmap->info.r = 0xFF;
   830     blitmap->info.g = 0xFF;
   831     blitmap->info.b = 0xFF;
   832     blitmap->info.a = 0xFF;
   833     surface->map = blitmap;
   834     SDL_FormatChanged(surface);
   835 
   836     /* The surface is ready to go */
   837     surface->refcount = 1;
   838     return SDL_TRUE;
   839 }
   840 
   841 /*
   842  * Copy a block of pixels of one format to another format
   843  */
   844 int SDL_ConvertPixels(int width, int height,
   845                       Uint32 src_format, const void * src, int src_pitch,
   846                       Uint32 dst_format, void * dst, int dst_pitch)
   847 {
   848     SDL_Surface src_surface, dst_surface;
   849     SDL_PixelFormat src_fmt, dst_fmt;
   850     SDL_BlitMap src_blitmap, dst_blitmap;
   851     SDL_Rect rect;
   852 
   853     /* Fast path for same format copy */
   854     if (src_format == dst_format) {
   855         int bpp;
   856 
   857         if (SDL_ISPIXELFORMAT_FOURCC(src_format)) {
   858             switch (src_format) {
   859             case SDL_PIXELFORMAT_YV12:
   860             case SDL_PIXELFORMAT_IYUV:
   861             case SDL_PIXELFORMAT_YUY2:
   862             case SDL_PIXELFORMAT_UYVY:
   863             case SDL_PIXELFORMAT_YVYU:
   864                 bpp = 2;
   865             default:
   866                 SDL_SetError("Unknown FOURCC pixel format");
   867                 return -1;
   868             }
   869         } else {
   870             bpp = SDL_BYTESPERPIXEL(src_format);
   871         }
   872         width *= bpp;
   873 
   874         while (height-- > 0) {
   875             SDL_memcpy(dst, src, width);
   876             src = (Uint8*)src + src_pitch;
   877             dst = (Uint8*)dst + dst_pitch;
   878         }
   879         return SDL_TRUE;
   880     }
   881 
   882     if (!SDL_CreateSurfaceOnStack(width, height, src_format, (void*)src,
   883                                   src_pitch,
   884                                   &src_surface, &src_fmt, &src_blitmap)) {
   885         return -1;
   886     }
   887     if (!SDL_CreateSurfaceOnStack(width, height, dst_format, dst, dst_pitch,
   888                                   &dst_surface, &dst_fmt, &dst_blitmap)) {
   889         return -1;
   890     }
   891 
   892     /* Set up the rect and go! */
   893     rect.x = 0;
   894     rect.y = 0;
   895     rect.w = width;
   896     rect.h = height;
   897     return SDL_LowerBlit(&src_surface, &rect, &dst_surface, &rect);
   898 }
   899 
   900 /*
   901  * Free a surface created by the above function.
   902  */
   903 void
   904 SDL_FreeSurface(SDL_Surface * surface)
   905 {
   906     if (surface == NULL) {
   907         return;
   908     }
   909     if (--surface->refcount > 0) {
   910         return;
   911     }
   912     while (surface->locked > 0) {
   913         SDL_UnlockSurface(surface);
   914     }
   915     if (surface->flags & SDL_RLEACCEL) {
   916         SDL_UnRLESurface(surface, 0);
   917     }
   918     if (surface->format) {
   919         SDL_SetSurfacePalette(surface, NULL);
   920         SDL_FreeFormat(surface->format);
   921         surface->format = NULL;
   922     }
   923     if (surface->map != NULL) {
   924         SDL_FreeBlitMap(surface->map);
   925         surface->map = NULL;
   926     }
   927     if (surface->pixels && ((surface->flags & SDL_PREALLOC) != SDL_PREALLOC)) {
   928         SDL_free(surface->pixels);
   929     }
   930     SDL_free(surface);
   931 }
   932 
   933 /* vi: set ts=4 sw=4 expandtab: */