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