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