src/video/SDL_surface.c
author Sam Lantinga <slouken@libsdl.org>
Mon, 07 Mar 2011 00:30:05 -0800
changeset 5438 b705640cb34a
parent 5375 16877f74123c
child 5499 2b8e6d1e3817
permissions -rw-r--r--
Fixed bitmap order interpretation; SDL defaults to MSB ordering so a bitstream corresponds to a pixel stream.

The bitmap ordering is defined such that the numbering refers to the pixel index from left to right, and the number position refers to the bit position in the byte.

SDL_BITMAPORDER_4321 is the fourth pixel at the high bit and the first pixel at the low bit (LSBFirst)

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