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