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