src/video/SDL_surface.c
author Sam Lantinga <slouken@libsdl.org>
Sat, 20 Dec 2008 12:00:00 +0000
changeset 2884 9dde605c7540
parent 2859 99210400e8b9
child 3011 8f4ed5ec2b06
permissions -rw-r--r--
Date: Fri, 19 Dec 2008 20:17:35 +0100
From: Couriersud
Subject: Re: Aw: Experience using SDL1.3 in sdlmame/Proposal for api additions

> For consistency you'd probably want:
> SDL_SetRenderDrawColor(Uint8 r, Uint8 g, Uint8 b, Uint8 a);
> SDL_SetRenderDrawBlendMode(SDL_BlendMode blendMode);
> SDL_RenderLine(int x1, int y1, int x2, int y2);
> SDL_RenderFill(SDL_Rect *rect);
>
> You probably also want to add API functions query the current state.
>

I have implemented the above api for the opengl, x11, directfb and
software renderers. I have also renamed *TEXTUREBLENDMODE* constants to
BLENDMODE*. The unix build compiles. The windows renderer still needs to
be updated, but I have no windows development machine at hand. Have a
look at the x11 renderer for a sample.

Vector games now run at 90% both on opengl and directfb in comparison to
sdlmame's own opengl renderer. The same applies to raster games.

The diff also includes

a) Changed XDrawRect to XFillRect in x11 renderer
b) A number of changes to fix blending and modulation issues in the
directfb renderer.
     1 /*
     2     SDL - Simple DirectMedia Layer
     3     Copyright (C) 1997-2009 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     /* The flags are no longer used, make the compiler happy */
    45     flags;
    46 
    47     /* Allocate the surface */
    48     surface = (SDL_Surface *) SDL_calloc(1, sizeof(*surface));
    49     if (surface == NULL) {
    50         SDL_OutOfMemory();
    51         return NULL;
    52     }
    53 
    54     surface->format = SDL_AllocFormat(depth, Rmask, Gmask, Bmask, Amask);
    55     if (!surface->format) {
    56         SDL_FreeSurface(surface);
    57         return NULL;
    58     }
    59     surface->w = width;
    60     surface->h = height;
    61     surface->pitch = SDL_CalculatePitch(surface);
    62     SDL_SetClipRect(surface, NULL);
    63 
    64     if (surface->format->BitsPerPixel <= 8) {
    65         SDL_Palette *palette =
    66             SDL_AllocPalette((1 << surface->format->BitsPerPixel));
    67         if (!palette) {
    68             SDL_FreeSurface(surface);
    69             return NULL;
    70         }
    71         if (Rmask || Bmask || Gmask) {
    72             const SDL_PixelFormat *format = surface->format;
    73 
    74             /* create palette according to masks */
    75             int i;
    76             int Rm = 0, Gm = 0, Bm = 0;
    77             int Rw = 0, Gw = 0, Bw = 0;
    78 
    79             if (Rmask) {
    80                 Rw = 8 - format->Rloss;
    81                 for (i = format->Rloss; i > 0; i -= Rw)
    82                     Rm |= 1 << i;
    83             }
    84             if (Gmask) {
    85                 Gw = 8 - format->Gloss;
    86                 for (i = format->Gloss; i > 0; i -= Gw)
    87                     Gm |= 1 << i;
    88             }
    89             if (Bmask) {
    90                 Bw = 8 - format->Bloss;
    91                 for (i = format->Bloss; i > 0; i -= Bw)
    92                     Bm |= 1 << i;
    93             }
    94             for (i = 0; i < palette->ncolors; ++i) {
    95                 int r, g, b;
    96                 r = (i & Rmask) >> format->Rshift;
    97                 r = (r << format->Rloss) | ((r * Rm) >> Rw);
    98                 palette->colors[i].r = r;
    99 
   100                 g = (i & Gmask) >> format->Gshift;
   101                 g = (g << format->Gloss) | ((g * Gm) >> Gw);
   102                 palette->colors[i].g = g;
   103 
   104                 b = (i & Bmask) >> format->Bshift;
   105                 b = (b << format->Bloss) | ((b * Bm) >> Bw);
   106                 palette->colors[i].b = b;
   107             }
   108         } else if (palette->ncolors == 2) {
   109             /* Create a black and white bitmap palette */
   110             palette->colors[0].r = 0xFF;
   111             palette->colors[0].g = 0xFF;
   112             palette->colors[0].b = 0xFF;
   113             palette->colors[1].r = 0x00;
   114             palette->colors[1].g = 0x00;
   115             palette->colors[1].b = 0x00;
   116         }
   117         SDL_SetSurfacePalette(surface, palette);
   118         SDL_FreePalette(palette);
   119     }
   120 
   121     /* Get the pixels */
   122     if (surface->w && surface->h) {
   123         surface->pixels = SDL_malloc(surface->h * surface->pitch);
   124         if (!surface->pixels) {
   125             SDL_FreeSurface(surface);
   126             SDL_OutOfMemory();
   127             return NULL;
   128         }
   129         /* This is important for bitmaps */
   130         SDL_memset(surface->pixels, 0, surface->h * surface->pitch);
   131     }
   132 
   133     /* Allocate an empty mapping */
   134     surface->map = SDL_AllocBlitMap();
   135     if (!surface->map) {
   136         SDL_FreeSurface(surface);
   137         return NULL;
   138     }
   139     SDL_FormatChanged(surface);
   140 
   141     /* By default surface with an alpha mask are set up for blending */
   142     if (Amask) {
   143         SDL_SetSurfaceBlendMode(surface, SDL_BLENDMODE_BLEND);
   144     }
   145 
   146     /* The surface is ready to go */
   147     surface->refcount = 1;
   148 #ifdef CHECK_LEAKS
   149     ++surfaces_allocated;
   150 #endif
   151     return surface;
   152 }
   153 
   154 /*
   155  * Create an RGB surface from an existing memory buffer
   156  */
   157 SDL_Surface *
   158 SDL_CreateRGBSurfaceFrom(void *pixels,
   159                          int width, int height, int depth, int pitch,
   160                          Uint32 Rmask, Uint32 Gmask, Uint32 Bmask,
   161                          Uint32 Amask)
   162 {
   163     SDL_Surface *surface;
   164 
   165     surface =
   166         SDL_CreateRGBSurface(0, 0, 0, depth, Rmask, Gmask, Bmask, Amask);
   167     if (surface != NULL) {
   168         surface->flags |= SDL_PREALLOC;
   169         surface->pixels = pixels;
   170         surface->w = width;
   171         surface->h = height;
   172         surface->pitch = pitch;
   173         SDL_SetClipRect(surface, NULL);
   174     }
   175     return surface;
   176 }
   177 
   178 static int
   179 SDL_SurfacePaletteChanged(void *userdata, SDL_Palette * palette)
   180 {
   181     SDL_Surface *surface = (SDL_Surface *) userdata;
   182 
   183     SDL_FormatChanged(surface);
   184 
   185     return 0;
   186 }
   187 
   188 int
   189 SDL_SetSurfacePalette(SDL_Surface * surface, SDL_Palette * palette)
   190 {
   191     if (!surface || !surface->format) {
   192         SDL_SetError("SDL_SetSurfacePalette() passed a NULL surface");
   193         return -1;
   194     }
   195 
   196     if (palette && palette->ncolors != (1 << surface->format->BitsPerPixel)) {
   197         SDL_SetError
   198             ("SDL_SetSurfacePalette() passed a palette that doesn't match the surface format");
   199         return -1;
   200     }
   201 
   202     if (surface->format->palette == palette) {
   203         return 0;
   204     }
   205 
   206     if (surface->format->palette) {
   207         SDL_DelPaletteWatch(surface->format->palette,
   208                             SDL_SurfacePaletteChanged, surface);
   209     }
   210 
   211     surface->format->palette = palette;
   212 
   213     if (surface->format->palette) {
   214         SDL_AddPaletteWatch(surface->format->palette,
   215                             SDL_SurfacePaletteChanged, surface);
   216     }
   217     return 0;
   218 }
   219 
   220 int
   221 SDL_SetSurfaceRLE(SDL_Surface * surface, int flag)
   222 {
   223     int flags;
   224 
   225     if (!surface) {
   226         return -1;
   227     }
   228 
   229     flags = surface->map->info.flags;
   230     if (flag) {
   231         surface->map->info.flags |= SDL_COPY_RLE_DESIRED;
   232     } else {
   233         surface->map->info.flags &= ~SDL_COPY_RLE_DESIRED;
   234     }
   235     if (surface->map->info.flags != flags) {
   236         SDL_InvalidateMap(surface->map);
   237     }
   238     return 0;
   239 }
   240 
   241 int
   242 SDL_SetColorKey(SDL_Surface * surface, Uint32 flag, Uint32 key)
   243 {
   244     int flags;
   245 
   246     if (!surface) {
   247         return -1;
   248     }
   249 
   250     if (flag & SDL_RLEACCEL) {
   251         SDL_SetSurfaceRLE(surface, 1);
   252     }
   253 
   254     flags = surface->map->info.flags;
   255     if (flag) {
   256         surface->map->info.flags |= SDL_COPY_COLORKEY;
   257         surface->map->info.colorkey = key;
   258     } else {
   259         surface->map->info.flags &= ~SDL_COPY_COLORKEY;
   260     }
   261     if (surface->map->info.flags != flags) {
   262         SDL_InvalidateMap(surface->map);
   263     }
   264 
   265     /* Compatibility mode */
   266     if (surface->map->info.flags & SDL_COPY_COLORKEY) {
   267         surface->flags |= SDL_SRCCOLORKEY;
   268     } else {
   269         surface->flags &= ~SDL_SRCCOLORKEY;
   270     }
   271 
   272     return 0;
   273 }
   274 
   275 /* This is a fairly slow function to switch from colorkey to alpha */
   276 static void
   277 SDL_ConvertColorkeyToAlpha(SDL_Surface * surface)
   278 {
   279     int x, y;
   280 
   281     if (!surface) {
   282         return;
   283     }
   284 
   285     if (!(surface->map->info.flags & SDL_COPY_COLORKEY) ||
   286         !surface->format->Amask) {
   287         return;
   288     }
   289 
   290     SDL_LockSurface(surface);
   291 
   292     switch (surface->format->BytesPerPixel) {
   293     case 2:
   294         {
   295             Uint16 *row, *spot;
   296             Uint16 ckey = (Uint16) surface->map->info.colorkey;
   297             Uint16 mask = (Uint16) (~surface->format->Amask);
   298 
   299             row = (Uint16 *) surface->pixels;
   300             for (y = surface->h; y--;) {
   301                 spot = row;
   302                 for (x = surface->w; x--;) {
   303                     if (*spot == ckey) {
   304                         *spot &= mask;
   305                     }
   306                     ++spot;
   307                 }
   308                 row += surface->pitch / 2;
   309             }
   310         }
   311         break;
   312     case 3:
   313         /* FIXME */
   314         break;
   315     case 4:
   316         {
   317             Uint32 *row, *spot;
   318             Uint32 ckey = surface->map->info.colorkey;
   319             Uint32 mask = ~surface->format->Amask;
   320 
   321             row = (Uint32 *) surface->pixels;
   322             for (y = surface->h; y--;) {
   323                 spot = row;
   324                 for (x = surface->w; x--;) {
   325                     if (*spot == ckey) {
   326                         *spot &= mask;
   327                     }
   328                     ++spot;
   329                 }
   330                 row += surface->pitch / 4;
   331             }
   332         }
   333         break;
   334     }
   335 
   336     SDL_UnlockSurface(surface);
   337 
   338     SDL_SetColorKey(surface, 0, 0);
   339     SDL_SetSurfaceBlendMode(surface, SDL_BLENDMODE_BLEND);
   340 }
   341 
   342 int
   343 SDL_SetSurfaceColorMod(SDL_Surface * surface, Uint8 r, Uint8 g, Uint8 b)
   344 {
   345     int flags;
   346 
   347     if (!surface) {
   348         return -1;
   349     }
   350 
   351     surface->map->info.r = r;
   352     surface->map->info.g = g;
   353     surface->map->info.b = b;
   354 
   355     flags = surface->map->info.flags;
   356     if (r != 0xFF || g != 0xFF || b != 0xFF) {
   357         surface->map->info.flags |= SDL_COPY_MODULATE_COLOR;
   358     } else {
   359         surface->map->info.flags &= ~SDL_COPY_MODULATE_COLOR;
   360     }
   361     if (surface->map->info.flags != flags) {
   362         SDL_InvalidateMap(surface->map);
   363     }
   364     return 0;
   365 }
   366 
   367 
   368 int
   369 SDL_GetSurfaceColorMod(SDL_Surface * surface, Uint8 * r, Uint8 * g, Uint8 * b)
   370 {
   371     if (!surface) {
   372         return -1;
   373     }
   374 
   375     if (r) {
   376         *r = surface->map->info.r;
   377     }
   378     if (g) {
   379         *g = surface->map->info.g;
   380     }
   381     if (b) {
   382         *b = surface->map->info.b;
   383     }
   384     return 0;
   385 }
   386 
   387 int
   388 SDL_SetSurfaceAlphaMod(SDL_Surface * surface, Uint8 alpha)
   389 {
   390     int flags;
   391 
   392     if (!surface) {
   393         return -1;
   394     }
   395 
   396     surface->map->info.a = alpha;
   397 
   398     flags = surface->map->info.flags;
   399     if (alpha != 0xFF) {
   400         surface->map->info.flags |= SDL_COPY_MODULATE_ALPHA;
   401     } else {
   402         surface->map->info.flags &= ~SDL_COPY_MODULATE_ALPHA;
   403     }
   404     if (surface->map->info.flags != flags) {
   405         SDL_InvalidateMap(surface->map);
   406     }
   407     return 0;
   408 }
   409 
   410 int
   411 SDL_GetSurfaceAlphaMod(SDL_Surface * surface, Uint8 * alpha)
   412 {
   413     if (!surface) {
   414         return -1;
   415     }
   416 
   417     if (alpha) {
   418         *alpha = surface->map->info.a;
   419     }
   420     return 0;
   421 }
   422 
   423 int
   424 SDL_SetSurfaceBlendMode(SDL_Surface * surface, int blendMode)
   425 {
   426     int flags, status;
   427 
   428     if (!surface) {
   429         return -1;
   430     }
   431 
   432     status = 0;
   433     flags = surface->map->info.flags;
   434     surface->map->info.flags &=
   435         ~(SDL_COPY_MASK | SDL_COPY_BLEND | SDL_COPY_ADD | SDL_COPY_MOD);
   436     switch (blendMode) {
   437     case SDL_BLENDMODE_NONE:
   438         break;
   439     case SDL_BLENDMODE_MASK:
   440         surface->map->info.flags |= SDL_COPY_MASK;
   441         break;
   442     case SDL_BLENDMODE_BLEND:
   443         surface->map->info.flags |= SDL_COPY_BLEND;
   444         break;
   445     case SDL_BLENDMODE_ADD:
   446         surface->map->info.flags |= SDL_COPY_ADD;
   447         break;
   448     case SDL_BLENDMODE_MOD:
   449         surface->map->info.flags |= SDL_COPY_MOD;
   450         break;
   451     default:
   452         SDL_Unsupported();
   453         status = -1;
   454         break;
   455     }
   456 
   457     if (surface->map->info.flags != flags) {
   458         SDL_InvalidateMap(surface->map);
   459     }
   460 
   461     /* Compatibility mode */
   462     if (surface->map->info.flags & SDL_COPY_BLEND) {
   463         surface->flags |= SDL_SRCALPHA;
   464     } else {
   465         surface->flags &= ~SDL_SRCALPHA;
   466     }
   467 
   468     return status;
   469 }
   470 
   471 int
   472 SDL_GetSurfaceBlendMode(SDL_Surface * surface, int *blendMode)
   473 {
   474     if (!surface) {
   475         return -1;
   476     }
   477 
   478     if (!blendMode) {
   479         return 0;
   480     }
   481 
   482     switch (surface->map->
   483             info.flags & (SDL_COPY_MASK | SDL_COPY_BLEND | SDL_COPY_ADD |
   484                           SDL_COPY_MOD)) {
   485     case SDL_COPY_MASK:
   486         *blendMode = SDL_BLENDMODE_MASK;
   487         break;
   488     case SDL_COPY_BLEND:
   489         *blendMode = SDL_BLENDMODE_BLEND;
   490         break;
   491     case SDL_COPY_ADD:
   492         *blendMode = SDL_BLENDMODE_ADD;
   493         break;
   494     case SDL_COPY_MOD:
   495         *blendMode = SDL_BLENDMODE_MOD;
   496         break;
   497     default:
   498         *blendMode = SDL_BLENDMODE_NONE;
   499         break;
   500     }
   501     return 0;
   502 }
   503 
   504 int
   505 SDL_SetSurfaceScaleMode(SDL_Surface * surface, int scaleMode)
   506 {
   507     int flags, status;
   508 
   509     if (!surface) {
   510         return -1;
   511     }
   512 
   513     status = 0;
   514     flags = surface->map->info.flags;
   515     surface->map->info.flags &= ~(SDL_COPY_NEAREST);
   516     switch (scaleMode) {
   517     case SDL_TEXTURESCALEMODE_NONE:
   518         break;
   519     case SDL_TEXTURESCALEMODE_FAST:
   520         surface->map->info.flags |= SDL_COPY_NEAREST;
   521         break;
   522     case SDL_TEXTURESCALEMODE_SLOW:
   523     case SDL_TEXTURESCALEMODE_BEST:
   524         SDL_Unsupported();
   525         surface->map->info.flags |= SDL_COPY_NEAREST;
   526         status = -1;
   527         break;
   528     default:
   529         SDL_Unsupported();
   530         status = -1;
   531         break;
   532     }
   533 
   534     if (surface->map->info.flags != flags) {
   535         SDL_InvalidateMap(surface->map);
   536     }
   537     return status;
   538 }
   539 
   540 int
   541 SDL_GetSurfaceScaleMode(SDL_Surface * surface, int *scaleMode)
   542 {
   543     if (!surface) {
   544         return -1;
   545     }
   546 
   547     if (!scaleMode) {
   548         return 0;
   549     }
   550 
   551     switch (surface->map->info.flags & SDL_COPY_NEAREST) {
   552     case SDL_COPY_NEAREST:
   553         *scaleMode = SDL_TEXTURESCALEMODE_FAST;
   554         break;
   555     default:
   556         *scaleMode = SDL_TEXTURESCALEMODE_NONE;
   557         break;
   558     }
   559     return 0;
   560 }
   561 
   562 SDL_bool
   563 SDL_SetClipRect(SDL_Surface * surface, const SDL_Rect * rect)
   564 {
   565     SDL_Rect full_rect;
   566 
   567     /* Don't do anything if there's no surface to act on */
   568     if (!surface) {
   569         return SDL_FALSE;
   570     }
   571 
   572     /* Set up the full surface rectangle */
   573     full_rect.x = 0;
   574     full_rect.y = 0;
   575     full_rect.w = surface->w;
   576     full_rect.h = surface->h;
   577 
   578     /* Set the clipping rectangle */
   579     if (!rect) {
   580         surface->clip_rect = full_rect;
   581         return 1;
   582     }
   583     return SDL_IntersectRect(rect, &full_rect, &surface->clip_rect);
   584 }
   585 
   586 void
   587 SDL_GetClipRect(SDL_Surface * surface, SDL_Rect * rect)
   588 {
   589     if (surface && rect) {
   590         *rect = surface->clip_rect;
   591     }
   592 }
   593 
   594 /* 
   595  * Set up a blit between two surfaces -- split into three parts:
   596  * The upper part, SDL_UpperBlit(), performs clipping and rectangle 
   597  * verification.  The lower part is a pointer to a low level
   598  * accelerated blitting function.
   599  *
   600  * These parts are separated out and each used internally by this 
   601  * library in the optimimum places.  They are exported so that if
   602  * you know exactly what you are doing, you can optimize your code
   603  * by calling the one(s) you need.
   604  */
   605 int
   606 SDL_LowerBlit(SDL_Surface * src, SDL_Rect * srcrect,
   607               SDL_Surface * dst, SDL_Rect * dstrect)
   608 {
   609     /* Check to make sure the blit mapping is valid */
   610     if ((src->map->dst != dst) ||
   611         (src->map->dst->format_version != src->map->format_version)) {
   612         if (SDL_MapSurface(src, dst) < 0) {
   613             return (-1);
   614         }
   615         /* just here for debugging */
   616 /*         printf */
   617 /*             ("src = 0x%08X src->flags = %08X src->map->info.flags = %08x\ndst = 0x%08X dst->flags = %08X dst->map->info.flags = %08X\nsrc->map->blit = 0x%08x\n", */
   618 /*              src, dst->flags, src->map->info.flags, dst, dst->flags, */
   619 /*              dst->map->info.flags, src->map->blit); */
   620     }
   621     return (src->map->blit(src, srcrect, dst, dstrect));
   622 }
   623 
   624 
   625 int
   626 SDL_UpperBlit(SDL_Surface * src, SDL_Rect * srcrect,
   627               SDL_Surface * dst, SDL_Rect * dstrect)
   628 {
   629     SDL_Rect fulldst;
   630     int srcx, srcy, w, h;
   631 
   632     /* Make sure the surfaces aren't locked */
   633     if (!src || !dst) {
   634         SDL_SetError("SDL_UpperBlit: passed a NULL surface");
   635         return (-1);
   636     }
   637     if (src->locked || dst->locked) {
   638         SDL_SetError("Surfaces must not be locked during blit");
   639         return (-1);
   640     }
   641 
   642     /* If the destination rectangle is NULL, use the entire dest surface */
   643     if (dstrect == NULL) {
   644         fulldst.x = fulldst.y = 0;
   645         dstrect = &fulldst;
   646     }
   647 
   648     /* clip the source rectangle to the source surface */
   649     if (srcrect) {
   650         int maxw, maxh;
   651 
   652         srcx = srcrect->x;
   653         w = srcrect->w;
   654         if (srcx < 0) {
   655             w += srcx;
   656             dstrect->x -= srcx;
   657             srcx = 0;
   658         }
   659         maxw = src->w - srcx;
   660         if (maxw < w)
   661             w = maxw;
   662 
   663         srcy = srcrect->y;
   664         h = srcrect->h;
   665         if (srcy < 0) {
   666             h += srcy;
   667             dstrect->y -= srcy;
   668             srcy = 0;
   669         }
   670         maxh = src->h - srcy;
   671         if (maxh < h)
   672             h = maxh;
   673 
   674     } else {
   675         srcx = srcy = 0;
   676         w = src->w;
   677         h = src->h;
   678     }
   679 
   680     /* clip the destination rectangle against the clip rectangle */
   681     {
   682         SDL_Rect *clip = &dst->clip_rect;
   683         int dx, dy;
   684 
   685         dx = clip->x - dstrect->x;
   686         if (dx > 0) {
   687             w -= dx;
   688             dstrect->x += dx;
   689             srcx += dx;
   690         }
   691         dx = dstrect->x + w - clip->x - clip->w;
   692         if (dx > 0)
   693             w -= dx;
   694 
   695         dy = clip->y - dstrect->y;
   696         if (dy > 0) {
   697             h -= dy;
   698             dstrect->y += dy;
   699             srcy += dy;
   700         }
   701         dy = dstrect->y + h - clip->y - clip->h;
   702         if (dy > 0)
   703             h -= dy;
   704     }
   705 
   706     if (w > 0 && h > 0) {
   707         SDL_Rect sr;
   708         sr.x = srcx;
   709         sr.y = srcy;
   710         sr.w = dstrect->w = w;
   711         sr.h = dstrect->h = h;
   712         return SDL_LowerBlit(src, &sr, dst, dstrect);
   713     }
   714     dstrect->w = dstrect->h = 0;
   715     return 0;
   716 }
   717 
   718 /*
   719  * Lock a surface to directly access the pixels
   720  */
   721 int
   722 SDL_LockSurface(SDL_Surface * surface)
   723 {
   724     if (!surface->locked) {
   725         /* Perform the lock */
   726         if (surface->flags & SDL_RLEACCEL) {
   727             SDL_UnRLESurface(surface, 1);
   728             surface->flags |= SDL_RLEACCEL;     /* save accel'd state */
   729         }
   730     }
   731 
   732     /* Increment the surface lock count, for recursive locks */
   733     ++surface->locked;
   734 
   735     /* Ready to go.. */
   736     return (0);
   737 }
   738 
   739 /*
   740  * Unlock a previously locked surface
   741  */
   742 void
   743 SDL_UnlockSurface(SDL_Surface * surface)
   744 {
   745     /* Only perform an unlock if we are locked */
   746     if (!surface->locked || (--surface->locked > 0)) {
   747         return;
   748     }
   749 
   750     /* Update RLE encoded surface with new data */
   751     if ((surface->flags & SDL_RLEACCEL) == SDL_RLEACCEL) {
   752         surface->flags &= ~SDL_RLEACCEL;        /* stop lying */
   753         SDL_RLESurface(surface);
   754     }
   755 }
   756 
   757 /* 
   758  * Convert a surface into the specified pixel format.
   759  */
   760 SDL_Surface *
   761 SDL_ConvertSurface(SDL_Surface * surface, SDL_PixelFormat * format,
   762                    Uint32 flags)
   763 {
   764     SDL_Surface *convert;
   765     Uint32 copy_flags;
   766     SDL_Rect bounds;
   767 
   768     /* Check for empty destination palette! (results in empty image) */
   769     if (format->palette != NULL) {
   770         int i;
   771         for (i = 0; i < format->palette->ncolors; ++i) {
   772             if ((format->palette->colors[i].r != 0xFF) ||
   773                 (format->palette->colors[i].g != 0xFF) ||
   774                 (format->palette->colors[i].b != 0xFF))
   775                 break;
   776         }
   777         if (i == format->palette->ncolors) {
   778             SDL_SetError("Empty destination palette");
   779             return (NULL);
   780         }
   781     }
   782 
   783     /* Create a new surface with the desired format */
   784     convert = SDL_CreateRGBSurface(flags, surface->w, surface->h,
   785                                    format->BitsPerPixel, format->Rmask,
   786                                    format->Gmask, format->Bmask,
   787                                    format->Amask);
   788     if (convert == NULL) {
   789         return (NULL);
   790     }
   791 
   792     /* Copy the palette if any */
   793     if (format->palette && convert->format->palette) {
   794         SDL_memcpy(convert->format->palette->colors,
   795                    format->palette->colors,
   796                    format->palette->ncolors * sizeof(SDL_Color));
   797         convert->format->palette->ncolors = format->palette->ncolors;
   798     }
   799 
   800     /* Save the original copy flags */
   801     copy_flags = surface->map->info.flags;
   802     surface->map->info.flags = 0;
   803 
   804     /* Copy over the image data */
   805     bounds.x = 0;
   806     bounds.y = 0;
   807     bounds.w = surface->w;
   808     bounds.h = surface->h;
   809     SDL_LowerBlit(surface, &bounds, convert, &bounds);
   810 
   811     /* Clean up the original surface, and update converted surface */
   812     convert->map->info.r = surface->map->info.r;
   813     convert->map->info.g = surface->map->info.g;
   814     convert->map->info.b = surface->map->info.b;
   815     convert->map->info.a = surface->map->info.a;
   816     convert->map->info.flags =
   817         (copy_flags &
   818          ~(SDL_COPY_COLORKEY | SDL_COPY_BLEND
   819            | SDL_COPY_RLE_DESIRED | SDL_COPY_RLE_COLORKEY |
   820            SDL_COPY_RLE_ALPHAKEY));
   821     surface->map->info.flags = copy_flags;
   822     if (copy_flags & SDL_COPY_COLORKEY) {
   823         Uint8 keyR, keyG, keyB, keyA;
   824 
   825         SDL_GetRGBA(surface->map->info.colorkey, surface->format, &keyR,
   826                     &keyG, &keyB, &keyA);
   827         SDL_SetColorKey(convert, 1,
   828                         SDL_MapRGBA(convert->format, keyR, keyG, keyB, keyA));
   829         /* This is needed when converting for 3D texture upload */
   830         SDL_ConvertColorkeyToAlpha(convert);
   831     }
   832     SDL_SetClipRect(convert, &surface->clip_rect);
   833 
   834     /* Enable alpha blending by default if the new surface has an
   835      * alpha channel or alpha modulation */
   836     if ((surface->format->Amask && format->Amask) ||
   837         (copy_flags & SDL_COPY_MODULATE_ALPHA)) {
   838         SDL_SetSurfaceBlendMode(convert, SDL_BLENDMODE_BLEND);
   839     }
   840     if ((copy_flags & SDL_COPY_RLE_DESIRED) || (flags & SDL_RLEACCEL)) {
   841         SDL_SetSurfaceRLE(convert, SDL_RLEACCEL);
   842     }
   843 
   844     /* We're ready to go! */
   845     return (convert);
   846 }
   847 
   848 /*
   849  * Free a surface created by the above function.
   850  */
   851 void
   852 SDL_FreeSurface(SDL_Surface * surface)
   853 {
   854     if (surface == NULL) {
   855         return;
   856     }
   857     if (--surface->refcount > 0) {
   858         return;
   859     }
   860     while (surface->locked > 0) {
   861         SDL_UnlockSurface(surface);
   862     }
   863     if (surface->flags & SDL_RLEACCEL) {
   864         SDL_UnRLESurface(surface, 0);
   865     }
   866     if (surface->format) {
   867         SDL_SetSurfacePalette(surface, NULL);
   868         SDL_FreeFormat(surface->format);
   869         surface->format = NULL;
   870     }
   871     if (surface->map != NULL) {
   872         SDL_FreeBlitMap(surface->map);
   873         surface->map = NULL;
   874     }
   875     if (surface->pixels && ((surface->flags & SDL_PREALLOC) != SDL_PREALLOC)) {
   876         SDL_free(surface->pixels);
   877     }
   878     SDL_free(surface);
   879 #ifdef CHECK_LEAKS
   880     --surfaces_allocated;
   881 #endif
   882 }
   883 
   884 /* vi: set ts=4 sw=4 expandtab: */