src/video/SDL_surface.c
author Sam Lantinga <slouken@libsdl.org>
Sat, 22 Jul 2006 08:33:18 +0000
changeset 1920 8a162bfdc838
parent 1895 c121d94672cb
child 2222 926294b2bb4e
permissions -rw-r--r--
Convert SDL_malloc to SDL_calloc if appropriate, slightly faster on operating systems which map the zero page for memory allocations.
OpenGL renderer in progress
     1 /*
     2     SDL - Simple DirectMedia Layer
     3     Copyright (C) 1997-2006 Sam Lantinga
     4 
     5     This library is free software; you can redistribute it and/or
     6     modify it under the terms of the GNU Lesser General Public
     7     License as published by the Free Software Foundation; either
     8     version 2.1 of the License, or (at your option) any later version.
     9 
    10     This library is distributed in the hope that it will be useful,
    11     but WITHOUT ANY WARRANTY; without even the implied warranty of
    12     MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
    13     Lesser General Public License for more details.
    14 
    15     You should have received a copy of the GNU Lesser General Public
    16     License along with this library; if not, write to the Free Software
    17     Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
    18 
    19     Sam Lantinga
    20     slouken@libsdl.org
    21 */
    22 #include "SDL_config.h"
    23 
    24 #include "SDL_video.h"
    25 #include "SDL_compat.h"
    26 #include "SDL_sysvideo.h"
    27 #include "SDL_blit.h"
    28 #include "SDL_RLEaccel_c.h"
    29 #include "SDL_pixels_c.h"
    30 #include "SDL_leaks.h"
    31 
    32 
    33 /* Public routines */
    34 /*
    35  * Create an empty RGB surface of the appropriate depth
    36  */
    37 SDL_Surface *
    38 SDL_CreateRGBSurface(Uint32 flags,
    39                      int width, int height, int depth,
    40                      Uint32 Rmask, Uint32 Gmask, Uint32 Bmask, Uint32 Amask)
    41 {
    42     SDL_Surface *surface;
    43 
    44     /* Allocate the surface */
    45     surface = (SDL_Surface *) SDL_calloc(1, sizeof(*surface));
    46     if (surface == NULL) {
    47         SDL_OutOfMemory();
    48         return NULL;
    49     }
    50 
    51     surface->format = SDL_AllocFormat(depth, Rmask, Gmask, Bmask, Amask);
    52     if (!surface->format) {
    53         SDL_FreeSurface(surface);
    54         return NULL;
    55     }
    56     if (Amask) {
    57         surface->flags |= SDL_SRCALPHA;
    58     }
    59     surface->w = width;
    60     surface->h = height;
    61     surface->pitch = SDL_CalculatePitch(surface);
    62     SDL_SetClipRect(surface, NULL);
    63 
    64     if (surface->format->BitsPerPixel <= 8) {
    65         SDL_Palette *palette =
    66             SDL_AllocPalette((1 << surface->format->BitsPerPixel));
    67         if (!palette) {
    68             SDL_FreeSurface(surface);
    69             return NULL;
    70         }
    71         if (Rmask || Bmask || Gmask) {
    72             const SDL_PixelFormat *format = surface->format;
    73 
    74             /* create palette according to masks */
    75             int i;
    76             int Rm = 0, Gm = 0, Bm = 0;
    77             int Rw = 0, Gw = 0, Bw = 0;
    78 
    79             if (Rmask) {
    80                 Rw = 8 - format->Rloss;
    81                 for (i = format->Rloss; i > 0; i -= Rw)
    82                     Rm |= 1 << i;
    83             }
    84             if (Gmask) {
    85                 Gw = 8 - format->Gloss;
    86                 for (i = format->Gloss; i > 0; i -= Gw)
    87                     Gm |= 1 << i;
    88             }
    89             if (Bmask) {
    90                 Bw = 8 - format->Bloss;
    91                 for (i = format->Bloss; i > 0; i -= Bw)
    92                     Bm |= 1 << i;
    93             }
    94             for (i = 0; i < palette->ncolors; ++i) {
    95                 int r, g, b;
    96                 r = (i & Rmask) >> format->Rshift;
    97                 r = (r << format->Rloss) | ((r * Rm) >> Rw);
    98                 palette->colors[i].r = r;
    99 
   100                 g = (i & Gmask) >> format->Gshift;
   101                 g = (g << format->Gloss) | ((g * Gm) >> Gw);
   102                 palette->colors[i].g = g;
   103 
   104                 b = (i & Bmask) >> format->Bshift;
   105                 b = (b << format->Bloss) | ((b * Bm) >> Bw);
   106                 palette->colors[i].b = b;
   107             }
   108         } else if (palette->ncolors == 2) {
   109             /* Create a black and white bitmap palette */
   110             palette->colors[0].r = 0xFF;
   111             palette->colors[0].g = 0xFF;
   112             palette->colors[0].b = 0xFF;
   113             palette->colors[1].r = 0x00;
   114             palette->colors[1].g = 0x00;
   115             palette->colors[1].b = 0x00;
   116         }
   117         SDL_SetSurfacePalette(surface, palette);
   118         SDL_FreePalette(palette);
   119     }
   120 
   121     /* Get the pixels */
   122     if (surface->w && surface->h) {
   123         surface->pixels = SDL_malloc(surface->h * surface->pitch);
   124         if (!surface->pixels) {
   125             SDL_FreeSurface(surface);
   126             SDL_OutOfMemory();
   127             return NULL;
   128         }
   129         /* This is important for bitmaps */
   130         SDL_memset(surface->pixels, 0, surface->h * surface->pitch);
   131     }
   132 
   133     /* Allocate an empty mapping */
   134     surface->map = SDL_AllocBlitMap();
   135     if (!surface->map) {
   136         SDL_FreeSurface(surface);
   137         return NULL;
   138     }
   139     SDL_FormatChanged(surface);
   140 
   141     /* The surface is ready to go */
   142     surface->refcount = 1;
   143 #ifdef CHECK_LEAKS
   144     ++surfaces_allocated;
   145 #endif
   146     return surface;
   147 }
   148 
   149 /*
   150  * Create an RGB surface from an existing memory buffer
   151  */
   152 SDL_Surface *
   153 SDL_CreateRGBSurfaceFrom(void *pixels,
   154                          int width, int height, int depth, int pitch,
   155                          Uint32 Rmask, Uint32 Gmask, Uint32 Bmask,
   156                          Uint32 Amask)
   157 {
   158     SDL_Surface *surface;
   159 
   160     surface =
   161         SDL_CreateRGBSurface(0, 0, 0, depth, Rmask, Gmask, Bmask, Amask);
   162     if (surface != NULL) {
   163         surface->flags |= SDL_PREALLOC;
   164         surface->pixels = pixels;
   165         surface->w = width;
   166         surface->h = height;
   167         surface->pitch = pitch;
   168         SDL_SetClipRect(surface, NULL);
   169     }
   170     return surface;
   171 }
   172 
   173 SDL_Surface *
   174 SDL_CreateRGBSurfaceFromTexture(SDL_TextureID textureID)
   175 {
   176     SDL_Surface *surface;
   177     Uint32 format;
   178     int w, h;
   179     int bpp;
   180     Uint32 Rmask, Gmask, Bmask, Amask;
   181     void *pixels;
   182     int pitch;
   183 
   184     if (SDL_QueryTexture(textureID, &format, NULL, &w, &h) < 0) {
   185         return NULL;
   186     }
   187 
   188     if (!SDL_PixelFormatEnumToMasks
   189         (format, &bpp, &Rmask, &Gmask, &Bmask, &Amask)) {
   190         SDL_SetError("Unknown texture format");
   191         return NULL;
   192     }
   193 
   194     if (SDL_QueryTexturePixels(textureID, &pixels, &pitch) == 0) {
   195         surface =
   196             SDL_CreateRGBSurfaceFrom(pixels, w, h, bpp, pitch, Rmask, Gmask,
   197                                      Bmask, Amask);
   198     } else {
   199         surface =
   200             SDL_CreateRGBSurface(0, 0, 0, bpp, Rmask, Gmask, Bmask, Amask);
   201         if (surface) {
   202             surface->flags |= SDL_HWSURFACE;
   203             surface->w = w;
   204             surface->h = h;
   205             surface->pitch = SDL_CalculatePitch(surface);
   206             SDL_SetClipRect(surface, NULL);
   207         }
   208     }
   209     if (surface) {
   210         surface->textureID = textureID;
   211     }
   212 
   213     return surface;
   214 }
   215 
   216 static int
   217 SDL_SurfacePaletteChanged(void *userdata, SDL_Palette * palette)
   218 {
   219     SDL_Surface *surface = (SDL_Surface *) userdata;
   220 
   221     if (surface->textureID) {
   222         if (SDL_SetTexturePalette
   223             (surface->textureID, palette->colors, 0, palette->ncolors) < 0) {
   224             SDL_GetTexturePalette(surface->textureID, palette->colors, 0,
   225                                   palette->ncolors);
   226             return -1;
   227         }
   228     }
   229     SDL_FormatChanged(surface);
   230 
   231     return 0;
   232 }
   233 
   234 int
   235 SDL_SetSurfacePalette(SDL_Surface * surface, SDL_Palette * palette)
   236 {
   237     if (!surface || !surface->format) {
   238         SDL_SetError("SDL_SetSurfacePalette() passed a NULL surface");
   239         return -1;
   240     }
   241 
   242     if (palette && palette->ncolors != (1 << surface->format->BitsPerPixel)) {
   243         SDL_SetError
   244             ("SDL_SetSurfacePalette() passed a palette that doesn't match the surface format");
   245         return -1;
   246     }
   247 
   248     if (surface->format->palette == palette) {
   249         return 0;
   250     }
   251 
   252     if (surface->format->palette) {
   253         SDL_DelPaletteWatch(surface->format->palette,
   254                             SDL_SurfacePaletteChanged, surface);
   255     }
   256 
   257     surface->format->palette = palette;
   258 
   259     if (surface->format->palette) {
   260         SDL_AddPaletteWatch(surface->format->palette,
   261                             SDL_SurfacePaletteChanged, surface);
   262     }
   263     return 0;
   264 }
   265 
   266 /*
   267  * Set the color key in a blittable surface
   268  */
   269 int
   270 SDL_SetColorKey(SDL_Surface * surface, Uint32 flag, Uint32 key)
   271 {
   272     /* Sanity check the flag as it gets passed in */
   273     if (flag & SDL_SRCCOLORKEY) {
   274         if (flag & (SDL_RLEACCEL | SDL_RLEACCELOK)) {
   275             flag = (SDL_SRCCOLORKEY | SDL_RLEACCELOK);
   276         } else {
   277             flag = SDL_SRCCOLORKEY;
   278         }
   279     } else {
   280         flag = 0;
   281     }
   282 
   283     /* Optimize away operations that don't change anything */
   284     if ((flag == (surface->flags & (SDL_SRCCOLORKEY | SDL_RLEACCELOK))) &&
   285         (key == surface->format->colorkey)) {
   286         return (0);
   287     }
   288 
   289     /* UnRLE surfaces before we change the colorkey */
   290     if (surface->flags & SDL_RLEACCEL) {
   291         SDL_UnRLESurface(surface, 1);
   292     }
   293 
   294     if (flag) {
   295         surface->flags |= SDL_SRCCOLORKEY;
   296         surface->format->colorkey = key;
   297         if (flag & SDL_RLEACCELOK) {
   298             surface->flags |= SDL_RLEACCELOK;
   299         } else {
   300             surface->flags &= ~SDL_RLEACCELOK;
   301         }
   302     } else {
   303         surface->flags &= ~(SDL_SRCCOLORKEY | SDL_RLEACCELOK);
   304         surface->format->colorkey = 0;
   305     }
   306     SDL_InvalidateMap(surface->map);
   307     return (0);
   308 }
   309 
   310 /* This function sets the alpha channel of a surface */
   311 int
   312 SDL_SetAlpha(SDL_Surface * surface, Uint32 flag, Uint8 value)
   313 {
   314     Uint32 oldflags = surface->flags;
   315     Uint32 oldalpha = surface->format->alpha;
   316 
   317     /* Sanity check the flag as it gets passed in */
   318     if (flag & SDL_SRCALPHA) {
   319         if (flag & (SDL_RLEACCEL | SDL_RLEACCELOK)) {
   320             flag = (SDL_SRCALPHA | SDL_RLEACCELOK);
   321         } else {
   322             flag = SDL_SRCALPHA;
   323         }
   324     } else {
   325         flag = 0;
   326     }
   327 
   328     /* Optimize away operations that don't change anything */
   329     if ((flag == (surface->flags & (SDL_SRCALPHA | SDL_RLEACCELOK))) &&
   330         (!flag || value == oldalpha)) {
   331         return (0);
   332     }
   333 
   334     if (!(flag & SDL_RLEACCELOK) && (surface->flags & SDL_RLEACCEL))
   335         SDL_UnRLESurface(surface, 1);
   336 
   337     if (flag) {
   338         surface->flags |= SDL_SRCALPHA;
   339         surface->format->alpha = value;
   340         if (flag & SDL_RLEACCELOK) {
   341             surface->flags |= SDL_RLEACCELOK;
   342         } else {
   343             surface->flags &= ~SDL_RLEACCELOK;
   344         }
   345     } else {
   346         surface->flags &= ~SDL_SRCALPHA;
   347         surface->format->alpha = SDL_ALPHA_OPAQUE;
   348     }
   349     /*
   350      * The representation for software surfaces is independent of
   351      * per-surface alpha, so no need to invalidate the blit mapping
   352      * if just the alpha value was changed. (If either is 255, we still
   353      * need to invalidate.)
   354      */
   355     if (oldflags != surface->flags
   356         || (((oldalpha + 1) ^ (value + 1)) & 0x100)) {
   357         SDL_InvalidateMap(surface->map);
   358     }
   359     return (0);
   360 }
   361 
   362 int
   363 SDL_SetAlphaChannel(SDL_Surface * surface, Uint8 value)
   364 {
   365     int row, col;
   366     int offset;
   367     Uint8 *buf;
   368 
   369     if ((surface->format->Amask != 0xFF000000) &&
   370         (surface->format->Amask != 0x000000FF)) {
   371         SDL_SetError("Unsupported surface alpha mask format");
   372         return -1;
   373     }
   374 #if SDL_BYTEORDER == SDL_LIL_ENDIAN
   375     if (surface->format->Amask == 0xFF000000) {
   376         offset = 3;
   377     } else {
   378         offset = 0;
   379     }
   380 #else
   381     if (surface->format->Amask == 0xFF000000) {
   382         offset = 0;
   383     } else {
   384         offset = 3;
   385     }
   386 #endif /* Byte ordering */
   387 
   388     /* Quickly set the alpha channel of an RGBA or ARGB surface */
   389     if (SDL_MUSTLOCK(surface)) {
   390         if (SDL_LockSurface(surface) < 0) {
   391             return -1;
   392         }
   393     }
   394     row = surface->h;
   395     while (row--) {
   396         col = surface->w;
   397         buf = (Uint8 *) surface->pixels + row * surface->pitch + offset;
   398         while (col--) {
   399             *buf = value;
   400             buf += 4;
   401         }
   402     }
   403     if (SDL_MUSTLOCK(surface)) {
   404         SDL_UnlockSurface(surface);
   405     }
   406     return 0;
   407 }
   408 
   409 /*
   410  * Set the clipping rectangle for a blittable surface
   411  */
   412 SDL_bool
   413 SDL_SetClipRect(SDL_Surface * surface, const SDL_Rect * rect)
   414 {
   415     SDL_Rect full_rect;
   416 
   417     /* Don't do anything if there's no surface to act on */
   418     if (!surface) {
   419         return SDL_FALSE;
   420     }
   421 
   422     /* Set up the full surface rectangle */
   423     full_rect.x = 0;
   424     full_rect.y = 0;
   425     full_rect.w = surface->w;
   426     full_rect.h = surface->h;
   427 
   428     /* Set the clipping rectangle */
   429     if (!rect) {
   430         surface->clip_rect = full_rect;
   431         return 1;
   432     }
   433     return SDL_IntersectRect(rect, &full_rect, &surface->clip_rect);
   434 }
   435 
   436 void
   437 SDL_GetClipRect(SDL_Surface * surface, SDL_Rect * rect)
   438 {
   439     if (surface && rect) {
   440         *rect = surface->clip_rect;
   441     }
   442 }
   443 
   444 /* 
   445  * Set up a blit between two surfaces -- split into three parts:
   446  * The upper part, SDL_UpperBlit(), performs clipping and rectangle 
   447  * verification.  The lower part is a pointer to a low level
   448  * accelerated blitting function.
   449  *
   450  * These parts are separated out and each used internally by this 
   451  * library in the optimimum places.  They are exported so that if
   452  * you know exactly what you are doing, you can optimize your code
   453  * by calling the one(s) you need.
   454  */
   455 int
   456 SDL_LowerBlit(SDL_Surface * src, SDL_Rect * srcrect,
   457               SDL_Surface * dst, SDL_Rect * dstrect)
   458 {
   459     /* Check to make sure the blit mapping is valid */
   460     if ((src->map->dst != dst) ||
   461         (src->map->dst->format_version != src->map->format_version)) {
   462         if (SDL_MapSurface(src, dst) < 0) {
   463             return (-1);
   464         }
   465     }
   466     return (src->map->sw_blit(src, srcrect, dst, dstrect));
   467 }
   468 
   469 
   470 int
   471 SDL_UpperBlit(SDL_Surface * src, SDL_Rect * srcrect,
   472               SDL_Surface * dst, SDL_Rect * dstrect)
   473 {
   474     SDL_Rect fulldst;
   475     int srcx, srcy, w, h;
   476 
   477     /* Make sure the surfaces aren't locked */
   478     if (!src || !dst) {
   479         SDL_SetError("SDL_UpperBlit: passed a NULL surface");
   480         return (-1);
   481     }
   482     if (src->locked || dst->locked) {
   483         SDL_SetError("Surfaces must not be locked during blit");
   484         return (-1);
   485     }
   486 
   487     /* If the destination rectangle is NULL, use the entire dest surface */
   488     if (dstrect == NULL) {
   489         fulldst.x = fulldst.y = 0;
   490         dstrect = &fulldst;
   491     }
   492 
   493     /* clip the source rectangle to the source surface */
   494     if (srcrect) {
   495         int maxw, maxh;
   496 
   497         srcx = srcrect->x;
   498         w = srcrect->w;
   499         if (srcx < 0) {
   500             w += srcx;
   501             dstrect->x -= srcx;
   502             srcx = 0;
   503         }
   504         maxw = src->w - srcx;
   505         if (maxw < w)
   506             w = maxw;
   507 
   508         srcy = srcrect->y;
   509         h = srcrect->h;
   510         if (srcy < 0) {
   511             h += srcy;
   512             dstrect->y -= srcy;
   513             srcy = 0;
   514         }
   515         maxh = src->h - srcy;
   516         if (maxh < h)
   517             h = maxh;
   518 
   519     } else {
   520         srcx = srcy = 0;
   521         w = src->w;
   522         h = src->h;
   523     }
   524 
   525     /* clip the destination rectangle against the clip rectangle */
   526     {
   527         SDL_Rect *clip = &dst->clip_rect;
   528         int dx, dy;
   529 
   530         dx = clip->x - dstrect->x;
   531         if (dx > 0) {
   532             w -= dx;
   533             dstrect->x += dx;
   534             srcx += dx;
   535         }
   536         dx = dstrect->x + w - clip->x - clip->w;
   537         if (dx > 0)
   538             w -= dx;
   539 
   540         dy = clip->y - dstrect->y;
   541         if (dy > 0) {
   542             h -= dy;
   543             dstrect->y += dy;
   544             srcy += dy;
   545         }
   546         dy = dstrect->y + h - clip->y - clip->h;
   547         if (dy > 0)
   548             h -= dy;
   549     }
   550 
   551     if (w > 0 && h > 0) {
   552         SDL_Rect sr;
   553         sr.x = srcx;
   554         sr.y = srcy;
   555         sr.w = dstrect->w = w;
   556         sr.h = dstrect->h = h;
   557         return SDL_LowerBlit(src, &sr, dst, dstrect);
   558     }
   559     dstrect->w = dstrect->h = 0;
   560     return 0;
   561 }
   562 
   563 static int
   564 SDL_FillRect1(SDL_Surface * dst, SDL_Rect * dstrect, Uint32 color)
   565 {
   566     /* FIXME: We have to worry about packing order.. *sigh* */
   567     SDL_SetError("1-bpp rect fill not yet implemented");
   568     return -1;
   569 }
   570 
   571 static int
   572 SDL_FillRect4(SDL_Surface * dst, SDL_Rect * dstrect, Uint32 color)
   573 {
   574     /* FIXME: We have to worry about packing order.. *sigh* */
   575     SDL_SetError("4-bpp rect fill not yet implemented");
   576     return -1;
   577 }
   578 
   579 /* 
   580  * This function performs a fast fill of the given rectangle with 'color'
   581  */
   582 int
   583 SDL_FillRect(SDL_Surface * dst, SDL_Rect * dstrect, Uint32 color)
   584 {
   585     int x, y;
   586     Uint8 *row;
   587 
   588     /* This function doesn't work on surfaces < 8 bpp */
   589     if (dst->format->BitsPerPixel < 8) {
   590         switch (dst->format->BitsPerPixel) {
   591         case 1:
   592             return SDL_FillRect1(dst, dstrect, color);
   593             break;
   594         case 4:
   595             return SDL_FillRect4(dst, dstrect, color);
   596             break;
   597         default:
   598             SDL_SetError("Fill rect on unsupported surface format");
   599             return (-1);
   600             break;
   601         }
   602     }
   603 
   604     /* If 'dstrect' == NULL, then fill the whole surface */
   605     if (dstrect) {
   606         /* Perform clipping */
   607         if (!SDL_IntersectRect(dstrect, &dst->clip_rect, dstrect)) {
   608             return (0);
   609         }
   610     } else {
   611         dstrect = &dst->clip_rect;
   612     }
   613 
   614     /* Perform software fill */
   615     if (SDL_LockSurface(dst) != 0) {
   616         return (-1);
   617     }
   618     row = (Uint8 *) dst->pixels + dstrect->y * dst->pitch +
   619         dstrect->x * dst->format->BytesPerPixel;
   620     if (dst->format->palette || (color == 0)) {
   621         x = dstrect->w * dst->format->BytesPerPixel;
   622         if (!color && !((uintptr_t) row & 3) && !(x & 3)
   623             && !(dst->pitch & 3)) {
   624             int n = x >> 2;
   625             for (y = dstrect->h; y; --y) {
   626                 SDL_memset4(row, 0, n);
   627                 row += dst->pitch;
   628             }
   629         } else {
   630 #ifdef __powerpc__
   631             /*
   632              * SDL_memset() on PPC (both glibc and codewarrior) uses
   633              * the dcbz (Data Cache Block Zero) instruction, which
   634              * causes an alignment exception if the destination is
   635              * uncachable, so only use it on software surfaces
   636              */
   637             if (dst->flags & SDL_HWSURFACE) {
   638                 if (dstrect->w >= 8) {
   639                     /*
   640                      * 64-bit stores are probably most
   641                      * efficient to uncached video memory
   642                      */
   643                     double fill;
   644                     SDL_memset(&fill, color, (sizeof fill));
   645                     for (y = dstrect->h; y; y--) {
   646                         Uint8 *d = row;
   647                         unsigned n = x;
   648                         unsigned nn;
   649                         Uint8 c = color;
   650                         double f = fill;
   651                         while ((unsigned long) d & (sizeof(double) - 1)) {
   652                             *d++ = c;
   653                             n--;
   654                         }
   655                         nn = n / (sizeof(double) * 4);
   656                         while (nn) {
   657                             ((double *) d)[0] = f;
   658                             ((double *) d)[1] = f;
   659                             ((double *) d)[2] = f;
   660                             ((double *) d)[3] = f;
   661                             d += 4 * sizeof(double);
   662                             nn--;
   663                         }
   664                         n &= ~(sizeof(double) * 4 - 1);
   665                         nn = n / sizeof(double);
   666                         while (nn) {
   667                             *(double *) d = f;
   668                             d += sizeof(double);
   669                             nn--;
   670                         }
   671                         n &= ~(sizeof(double) - 1);
   672                         while (n) {
   673                             *d++ = c;
   674                             n--;
   675                         }
   676                         row += dst->pitch;
   677                     }
   678                 } else {
   679                     /* narrow boxes */
   680                     for (y = dstrect->h; y; y--) {
   681                         Uint8 *d = row;
   682                         Uint8 c = color;
   683                         int n = x;
   684                         while (n) {
   685                             *d++ = c;
   686                             n--;
   687                         }
   688                         row += dst->pitch;
   689                     }
   690                 }
   691             } else
   692 #endif /* __powerpc__ */
   693             {
   694                 for (y = dstrect->h; y; y--) {
   695                     SDL_memset(row, color, x);
   696                     row += dst->pitch;
   697                 }
   698             }
   699         }
   700     } else {
   701         switch (dst->format->BytesPerPixel) {
   702         case 2:
   703             for (y = dstrect->h; y; --y) {
   704                 Uint16 *pixels = (Uint16 *) row;
   705                 Uint16 c = (Uint16) color;
   706                 Uint32 cc = (Uint32) c << 16 | c;
   707                 int n = dstrect->w;
   708                 if ((uintptr_t) pixels & 3) {
   709                     *pixels++ = c;
   710                     n--;
   711                 }
   712                 if (n >> 1)
   713                     SDL_memset4(pixels, cc, n >> 1);
   714                 if (n & 1)
   715                     pixels[n - 1] = c;
   716                 row += dst->pitch;
   717             }
   718             break;
   719 
   720         case 3:
   721 #if SDL_BYTEORDER == SDL_BIG_ENDIAN
   722             color <<= 8;
   723 #endif
   724             for (y = dstrect->h; y; --y) {
   725                 Uint8 *pixels = row;
   726                 for (x = dstrect->w; x; --x) {
   727                     SDL_memcpy(pixels, &color, 3);
   728                     pixels += 3;
   729                 }
   730                 row += dst->pitch;
   731             }
   732             break;
   733 
   734         case 4:
   735             for (y = dstrect->h; y; --y) {
   736                 SDL_memset4(row, color, dstrect->w);
   737                 row += dst->pitch;
   738             }
   739             break;
   740         }
   741     }
   742     SDL_UnlockSurface(dst);
   743 
   744     /* We're done! */
   745     return (0);
   746 }
   747 
   748 /*
   749  * Lock a surface to directly access the pixels
   750  */
   751 int
   752 SDL_LockSurface(SDL_Surface * surface)
   753 {
   754     if (!surface->locked) {
   755         /* Perform the lock */
   756         if (surface->flags & SDL_HWSURFACE) {
   757             if (SDL_LockTexture
   758                 (surface->textureID, NULL, 1, &surface->pixels,
   759                  &surface->pitch) < 0) {
   760                 return (-1);
   761             }
   762         }
   763         if (surface->flags & SDL_RLEACCEL) {
   764             SDL_UnRLESurface(surface, 1);
   765             surface->flags |= SDL_RLEACCEL;     /* save accel'd state */
   766         }
   767     }
   768 
   769     /* Increment the surface lock count, for recursive locks */
   770     ++surface->locked;
   771 
   772     /* Ready to go.. */
   773     return (0);
   774 }
   775 
   776 /*
   777  * Unlock a previously locked surface
   778  */
   779 void
   780 SDL_UnlockSurface(SDL_Surface * surface)
   781 {
   782     /* Only perform an unlock if we are locked */
   783     if (!surface->locked || (--surface->locked > 0)) {
   784         return;
   785     }
   786 
   787     /* Unlock hardware or accelerated surfaces */
   788     if (surface->flags & SDL_HWSURFACE) {
   789         SDL_UnlockTexture(surface->textureID);
   790     }
   791 
   792     /* Update RLE encoded surface with new data */
   793     if ((surface->flags & SDL_RLEACCEL) == SDL_RLEACCEL) {
   794         surface->flags &= ~SDL_RLEACCEL;        /* stop lying */
   795         SDL_RLESurface(surface);
   796     }
   797 }
   798 
   799 /* 
   800  * Convert a surface into the specified pixel format.
   801  */
   802 SDL_Surface *
   803 SDL_ConvertSurface(SDL_Surface * surface,
   804                    SDL_PixelFormat * format, Uint32 flags)
   805 {
   806     SDL_Surface *convert;
   807     Uint32 colorkey = 0;
   808     Uint8 alpha = 0;
   809     Uint32 surface_flags;
   810     SDL_Rect bounds;
   811 
   812     /* Check for empty destination palette! (results in empty image) */
   813     if (format->palette != NULL) {
   814         int i;
   815         for (i = 0; i < format->palette->ncolors; ++i) {
   816             if ((format->palette->colors[i].r != 0xFF) ||
   817                 (format->palette->colors[i].g != 0xFF) ||
   818                 (format->palette->colors[i].b != 0xFF))
   819                 break;
   820         }
   821         if (i == format->palette->ncolors) {
   822             SDL_SetError("Empty destination palette");
   823             return (NULL);
   824         }
   825     }
   826 
   827     /* Create a new surface with the desired format */
   828     convert = SDL_CreateRGBSurface(flags,
   829                                    surface->w, surface->h,
   830                                    format->BitsPerPixel, format->Rmask,
   831                                    format->Gmask, format->Bmask,
   832                                    format->Amask);
   833     if (convert == NULL) {
   834         return (NULL);
   835     }
   836 
   837     /* Copy the palette if any */
   838     if (format->palette && convert->format->palette) {
   839         SDL_memcpy(convert->format->palette->colors,
   840                    format->palette->colors,
   841                    format->palette->ncolors * sizeof(SDL_Color));
   842         convert->format->palette->ncolors = format->palette->ncolors;
   843     }
   844 
   845     /* Save the original surface color key and alpha */
   846     surface_flags = surface->flags;
   847     if ((surface_flags & SDL_SRCCOLORKEY) == SDL_SRCCOLORKEY) {
   848         /* Convert colourkeyed surfaces to RGBA if requested */
   849         if ((flags & SDL_SRCCOLORKEY) != SDL_SRCCOLORKEY && format->Amask) {
   850             surface_flags &= ~SDL_SRCCOLORKEY;
   851         } else {
   852             colorkey = surface->format->colorkey;
   853             SDL_SetColorKey(surface, 0, 0);
   854         }
   855     }
   856     if ((surface_flags & SDL_SRCALPHA) == SDL_SRCALPHA) {
   857         /* Copy over the alpha channel to RGBA if requested */
   858         if (format->Amask) {
   859             surface->flags &= ~SDL_SRCALPHA;
   860         } else {
   861             alpha = surface->format->alpha;
   862             SDL_SetAlpha(surface, 0, 0);
   863         }
   864     }
   865 
   866     /* Copy over the image data */
   867     bounds.x = 0;
   868     bounds.y = 0;
   869     bounds.w = surface->w;
   870     bounds.h = surface->h;
   871     SDL_LowerBlit(surface, &bounds, convert, &bounds);
   872 
   873     /* Clean up the original surface, and update converted surface */
   874     if (convert != NULL) {
   875         SDL_SetClipRect(convert, &surface->clip_rect);
   876     }
   877     if ((surface_flags & SDL_SRCCOLORKEY) == SDL_SRCCOLORKEY) {
   878         Uint32 cflags = surface_flags & (SDL_SRCCOLORKEY | SDL_RLEACCELOK);
   879         if (convert != NULL) {
   880             Uint8 keyR, keyG, keyB;
   881 
   882             SDL_GetRGB(colorkey, surface->format, &keyR, &keyG, &keyB);
   883             SDL_SetColorKey(convert, cflags | (flags & SDL_RLEACCELOK),
   884                             SDL_MapRGB(convert->format, keyR, keyG, keyB));
   885         }
   886         SDL_SetColorKey(surface, cflags, colorkey);
   887     }
   888     if ((surface_flags & SDL_SRCALPHA) == SDL_SRCALPHA) {
   889         Uint32 aflags = surface_flags & (SDL_SRCALPHA | SDL_RLEACCELOK);
   890         if (convert != NULL) {
   891             SDL_SetAlpha(convert, aflags | (flags & SDL_RLEACCELOK), alpha);
   892         }
   893         if (format->Amask) {
   894             surface->flags |= SDL_SRCALPHA;
   895         } else {
   896             SDL_SetAlpha(surface, aflags, alpha);
   897         }
   898     }
   899 
   900     /* We're ready to go! */
   901     return (convert);
   902 }
   903 
   904 /*
   905  * Free a surface created by the above function.
   906  */
   907 void
   908 SDL_FreeSurface(SDL_Surface * surface)
   909 {
   910     if (surface == NULL) {
   911         return;
   912     }
   913     if (--surface->refcount > 0) {
   914         return;
   915     }
   916     while (surface->locked > 0) {
   917         SDL_UnlockSurface(surface);
   918     }
   919     if (surface->flags & SDL_RLEACCEL) {
   920         SDL_UnRLESurface(surface, 0);
   921     }
   922     if (surface->format) {
   923         SDL_SetSurfacePalette(surface, NULL);
   924         SDL_FreeFormat(surface->format);
   925         surface->format = NULL;
   926     }
   927     if (surface->map != NULL) {
   928         SDL_FreeBlitMap(surface->map);
   929         surface->map = NULL;
   930     }
   931     /* Should we destroy the texture too?
   932        if (surface->textureID) {
   933        SDL_DestroyTexture(surface->textureID);
   934        }
   935      */
   936     if (surface->pixels && ((surface->flags & SDL_PREALLOC) != SDL_PREALLOC)) {
   937         SDL_free(surface->pixels);
   938     }
   939     SDL_free(surface);
   940 #ifdef CHECK_LEAKS
   941     --surfaces_allocated;
   942 #endif
   943 }
   944 
   945 /* vi: set ts=4 sw=4 expandtab: */