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