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