src/video/SDL_surface.c
author Sam Lantinga <slouken@libsdl.org>
Tue, 15 Dec 2009 08:11:06 +0000
changeset 3565 f43c8f688f77
parent 3560 5543db4239e6
child 3697 f7b03b6838cb
permissions -rw-r--r--
Fixed bug #906

Added better error reporting for OpenGL context creation failing.
     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, int 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 int
   276 SDL_GetColorKey(SDL_Surface * surface, Uint32 * key)
   277 {
   278     if (!surface) {
   279         return -1;
   280     }
   281 
   282     if (!(surface->map->info.flags & SDL_COPY_COLORKEY)) {
   283         return -1;
   284     }
   285 
   286     if (key) {
   287         *key = surface->map->info.colorkey;
   288     }
   289     return 0;
   290 }
   291 
   292 /* This is a fairly slow function to switch from colorkey to alpha */
   293 static void
   294 SDL_ConvertColorkeyToAlpha(SDL_Surface * surface)
   295 {
   296     int x, y;
   297 
   298     if (!surface) {
   299         return;
   300     }
   301 
   302     if (!(surface->map->info.flags & SDL_COPY_COLORKEY) ||
   303         !surface->format->Amask) {
   304         return;
   305     }
   306 
   307     SDL_LockSurface(surface);
   308 
   309     switch (surface->format->BytesPerPixel) {
   310     case 2:
   311         {
   312             Uint16 *row, *spot;
   313             Uint16 ckey = (Uint16) surface->map->info.colorkey;
   314             Uint16 mask = (Uint16) (~surface->format->Amask);
   315 
   316             row = (Uint16 *) surface->pixels;
   317             for (y = surface->h; y--;) {
   318                 spot = row;
   319                 for (x = surface->w; x--;) {
   320                     if (*spot == ckey) {
   321                         *spot &= mask;
   322                     }
   323                     ++spot;
   324                 }
   325                 row += surface->pitch / 2;
   326             }
   327         }
   328         break;
   329     case 3:
   330         /* FIXME */
   331         break;
   332     case 4:
   333         {
   334             Uint32 *row, *spot;
   335             Uint32 ckey = surface->map->info.colorkey;
   336             Uint32 mask = ~surface->format->Amask;
   337 
   338             row = (Uint32 *) surface->pixels;
   339             for (y = surface->h; y--;) {
   340                 spot = row;
   341                 for (x = surface->w; x--;) {
   342                     if (*spot == ckey) {
   343                         *spot &= mask;
   344                     }
   345                     ++spot;
   346                 }
   347                 row += surface->pitch / 4;
   348             }
   349         }
   350         break;
   351     }
   352 
   353     SDL_UnlockSurface(surface);
   354 
   355     SDL_SetColorKey(surface, 0, 0);
   356     SDL_SetSurfaceBlendMode(surface, SDL_BLENDMODE_BLEND);
   357 }
   358 
   359 int
   360 SDL_SetSurfaceColorMod(SDL_Surface * surface, Uint8 r, Uint8 g, Uint8 b)
   361 {
   362     int flags;
   363 
   364     if (!surface) {
   365         return -1;
   366     }
   367 
   368     surface->map->info.r = r;
   369     surface->map->info.g = g;
   370     surface->map->info.b = b;
   371 
   372     flags = surface->map->info.flags;
   373     if (r != 0xFF || g != 0xFF || b != 0xFF) {
   374         surface->map->info.flags |= SDL_COPY_MODULATE_COLOR;
   375     } else {
   376         surface->map->info.flags &= ~SDL_COPY_MODULATE_COLOR;
   377     }
   378     if (surface->map->info.flags != flags) {
   379         SDL_InvalidateMap(surface->map);
   380     }
   381     return 0;
   382 }
   383 
   384 
   385 int
   386 SDL_GetSurfaceColorMod(SDL_Surface * surface, Uint8 * r, Uint8 * g, Uint8 * b)
   387 {
   388     if (!surface) {
   389         return -1;
   390     }
   391 
   392     if (r) {
   393         *r = surface->map->info.r;
   394     }
   395     if (g) {
   396         *g = surface->map->info.g;
   397     }
   398     if (b) {
   399         *b = surface->map->info.b;
   400     }
   401     return 0;
   402 }
   403 
   404 int
   405 SDL_SetSurfaceAlphaMod(SDL_Surface * surface, Uint8 alpha)
   406 {
   407     int flags;
   408 
   409     if (!surface) {
   410         return -1;
   411     }
   412 
   413     surface->map->info.a = alpha;
   414 
   415     flags = surface->map->info.flags;
   416     if (alpha != 0xFF) {
   417         surface->map->info.flags |= SDL_COPY_MODULATE_ALPHA;
   418     } else {
   419         surface->map->info.flags &= ~SDL_COPY_MODULATE_ALPHA;
   420     }
   421     if (surface->map->info.flags != flags) {
   422         SDL_InvalidateMap(surface->map);
   423     }
   424     return 0;
   425 }
   426 
   427 int
   428 SDL_GetSurfaceAlphaMod(SDL_Surface * surface, Uint8 * alpha)
   429 {
   430     if (!surface) {
   431         return -1;
   432     }
   433 
   434     if (alpha) {
   435         *alpha = surface->map->info.a;
   436     }
   437     return 0;
   438 }
   439 
   440 int
   441 SDL_SetSurfaceBlendMode(SDL_Surface * surface, int blendMode)
   442 {
   443     int flags, status;
   444 
   445     if (!surface) {
   446         return -1;
   447     }
   448 
   449     status = 0;
   450     flags = surface->map->info.flags;
   451     surface->map->info.flags &=
   452         ~(SDL_COPY_MASK | SDL_COPY_BLEND | SDL_COPY_ADD | SDL_COPY_MOD);
   453     switch (blendMode) {
   454     case SDL_BLENDMODE_NONE:
   455         break;
   456     case SDL_BLENDMODE_MASK:
   457         surface->map->info.flags |= SDL_COPY_MASK;
   458         break;
   459     case SDL_BLENDMODE_BLEND:
   460         surface->map->info.flags |= SDL_COPY_BLEND;
   461         break;
   462     case SDL_BLENDMODE_ADD:
   463         surface->map->info.flags |= SDL_COPY_ADD;
   464         break;
   465     case SDL_BLENDMODE_MOD:
   466         surface->map->info.flags |= SDL_COPY_MOD;
   467         break;
   468     default:
   469         SDL_Unsupported();
   470         status = -1;
   471         break;
   472     }
   473 
   474     if (surface->map->info.flags != flags) {
   475         SDL_InvalidateMap(surface->map);
   476     }
   477 
   478     /* Compatibility mode */
   479     if (surface->map->info.flags & SDL_COPY_BLEND) {
   480         surface->flags |= SDL_SRCALPHA;
   481     } else {
   482         surface->flags &= ~SDL_SRCALPHA;
   483     }
   484 
   485     return status;
   486 }
   487 
   488 int
   489 SDL_GetSurfaceBlendMode(SDL_Surface * surface, int *blendMode)
   490 {
   491     if (!surface) {
   492         return -1;
   493     }
   494 
   495     if (!blendMode) {
   496         return 0;
   497     }
   498 
   499     switch (surface->map->
   500             info.flags & (SDL_COPY_MASK | SDL_COPY_BLEND | SDL_COPY_ADD |
   501                           SDL_COPY_MOD)) {
   502     case SDL_COPY_MASK:
   503         *blendMode = SDL_BLENDMODE_MASK;
   504         break;
   505     case SDL_COPY_BLEND:
   506         *blendMode = SDL_BLENDMODE_BLEND;
   507         break;
   508     case SDL_COPY_ADD:
   509         *blendMode = SDL_BLENDMODE_ADD;
   510         break;
   511     case SDL_COPY_MOD:
   512         *blendMode = SDL_BLENDMODE_MOD;
   513         break;
   514     default:
   515         *blendMode = SDL_BLENDMODE_NONE;
   516         break;
   517     }
   518     return 0;
   519 }
   520 
   521 int
   522 SDL_SetSurfaceScaleMode(SDL_Surface * surface, int scaleMode)
   523 {
   524     int flags, status;
   525 
   526     if (!surface) {
   527         return -1;
   528     }
   529 
   530     status = 0;
   531     flags = surface->map->info.flags;
   532     surface->map->info.flags &= ~(SDL_COPY_NEAREST);
   533     switch (scaleMode) {
   534     case SDL_TEXTURESCALEMODE_NONE:
   535         break;
   536     case SDL_TEXTURESCALEMODE_FAST:
   537         surface->map->info.flags |= SDL_COPY_NEAREST;
   538         break;
   539     case SDL_TEXTURESCALEMODE_SLOW:
   540     case SDL_TEXTURESCALEMODE_BEST:
   541         SDL_Unsupported();
   542         surface->map->info.flags |= SDL_COPY_NEAREST;
   543         status = -1;
   544         break;
   545     default:
   546         SDL_Unsupported();
   547         status = -1;
   548         break;
   549     }
   550 
   551     if (surface->map->info.flags != flags) {
   552         SDL_InvalidateMap(surface->map);
   553     }
   554     return status;
   555 }
   556 
   557 int
   558 SDL_GetSurfaceScaleMode(SDL_Surface * surface, int *scaleMode)
   559 {
   560     if (!surface) {
   561         return -1;
   562     }
   563 
   564     if (!scaleMode) {
   565         return 0;
   566     }
   567 
   568     switch (surface->map->info.flags & SDL_COPY_NEAREST) {
   569     case SDL_COPY_NEAREST:
   570         *scaleMode = SDL_TEXTURESCALEMODE_FAST;
   571         break;
   572     default:
   573         *scaleMode = SDL_TEXTURESCALEMODE_NONE;
   574         break;
   575     }
   576     return 0;
   577 }
   578 
   579 SDL_bool
   580 SDL_SetClipRect(SDL_Surface * surface, const SDL_Rect * rect)
   581 {
   582     SDL_Rect full_rect;
   583 
   584     /* Don't do anything if there's no surface to act on */
   585     if (!surface) {
   586         return SDL_FALSE;
   587     }
   588 
   589     /* Set up the full surface rectangle */
   590     full_rect.x = 0;
   591     full_rect.y = 0;
   592     full_rect.w = surface->w;
   593     full_rect.h = surface->h;
   594 
   595     /* Set the clipping rectangle */
   596     if (!rect) {
   597         surface->clip_rect = full_rect;
   598         return 1;
   599     }
   600     return SDL_IntersectRect(rect, &full_rect, &surface->clip_rect);
   601 }
   602 
   603 void
   604 SDL_GetClipRect(SDL_Surface * surface, SDL_Rect * rect)
   605 {
   606     if (surface && rect) {
   607         *rect = surface->clip_rect;
   608     }
   609 }
   610 
   611 /* 
   612  * Set up a blit between two surfaces -- split into three parts:
   613  * The upper part, SDL_UpperBlit(), performs clipping and rectangle 
   614  * verification.  The lower part is a pointer to a low level
   615  * accelerated blitting function.
   616  *
   617  * These parts are separated out and each used internally by this 
   618  * library in the optimimum places.  They are exported so that if
   619  * you know exactly what you are doing, you can optimize your code
   620  * by calling the one(s) you need.
   621  */
   622 int
   623 SDL_LowerBlit(SDL_Surface * src, SDL_Rect * srcrect,
   624               SDL_Surface * dst, SDL_Rect * dstrect)
   625 {
   626     /* Check to make sure the blit mapping is valid */
   627     if ((src->map->dst != dst) ||
   628         (src->map->dst->format_version != src->map->format_version)) {
   629         if (SDL_MapSurface(src, dst) < 0) {
   630             return (-1);
   631         }
   632         /* just here for debugging */
   633 /*         printf */
   634 /*             ("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", */
   635 /*              src, dst->flags, src->map->info.flags, dst, dst->flags, */
   636 /*              dst->map->info.flags, src->map->blit); */
   637     }
   638     return (src->map->blit(src, srcrect, dst, dstrect));
   639 }
   640 
   641 
   642 int
   643 SDL_UpperBlit(SDL_Surface * src, SDL_Rect * srcrect,
   644               SDL_Surface * dst, SDL_Rect * dstrect)
   645 {
   646     SDL_Rect fulldst;
   647     int srcx, srcy, w, h;
   648 
   649     /* Make sure the surfaces aren't locked */
   650     if (!src || !dst) {
   651         SDL_SetError("SDL_UpperBlit: passed a NULL surface");
   652         return (-1);
   653     }
   654     if (src->locked || dst->locked) {
   655         SDL_SetError("Surfaces must not be locked during blit");
   656         return (-1);
   657     }
   658 
   659     /* If the destination rectangle is NULL, use the entire dest surface */
   660     if (dstrect == NULL) {
   661         fulldst.x = fulldst.y = 0;
   662         dstrect = &fulldst;
   663     }
   664 
   665     /* clip the source rectangle to the source surface */
   666     if (srcrect) {
   667         int maxw, maxh;
   668 
   669         srcx = srcrect->x;
   670         w = srcrect->w;
   671         if (srcx < 0) {
   672             w += srcx;
   673             dstrect->x -= srcx;
   674             srcx = 0;
   675         }
   676         maxw = src->w - srcx;
   677         if (maxw < w)
   678             w = maxw;
   679 
   680         srcy = srcrect->y;
   681         h = srcrect->h;
   682         if (srcy < 0) {
   683             h += srcy;
   684             dstrect->y -= srcy;
   685             srcy = 0;
   686         }
   687         maxh = src->h - srcy;
   688         if (maxh < h)
   689             h = maxh;
   690 
   691     } else {
   692         srcx = srcy = 0;
   693         w = src->w;
   694         h = src->h;
   695     }
   696 
   697     /* clip the destination rectangle against the clip rectangle */
   698     {
   699         SDL_Rect *clip = &dst->clip_rect;
   700         int dx, dy;
   701 
   702         dx = clip->x - dstrect->x;
   703         if (dx > 0) {
   704             w -= dx;
   705             dstrect->x += dx;
   706             srcx += dx;
   707         }
   708         dx = dstrect->x + w - clip->x - clip->w;
   709         if (dx > 0)
   710             w -= dx;
   711 
   712         dy = clip->y - dstrect->y;
   713         if (dy > 0) {
   714             h -= dy;
   715             dstrect->y += dy;
   716             srcy += dy;
   717         }
   718         dy = dstrect->y + h - clip->y - clip->h;
   719         if (dy > 0)
   720             h -= dy;
   721     }
   722 
   723     if (w > 0 && h > 0) {
   724         SDL_Rect sr;
   725         sr.x = srcx;
   726         sr.y = srcy;
   727         sr.w = dstrect->w = w;
   728         sr.h = dstrect->h = h;
   729         return SDL_LowerBlit(src, &sr, dst, dstrect);
   730     }
   731     dstrect->w = dstrect->h = 0;
   732     return 0;
   733 }
   734 
   735 /*
   736  * Lock a surface to directly access the pixels
   737  */
   738 int
   739 SDL_LockSurface(SDL_Surface * surface)
   740 {
   741     if (!surface->locked) {
   742         /* Perform the lock */
   743         if (surface->flags & SDL_RLEACCEL) {
   744             SDL_UnRLESurface(surface, 1);
   745             surface->flags |= SDL_RLEACCEL;     /* save accel'd state */
   746         }
   747     }
   748 
   749     /* Increment the surface lock count, for recursive locks */
   750     ++surface->locked;
   751 
   752     /* Ready to go.. */
   753     return (0);
   754 }
   755 
   756 /*
   757  * Unlock a previously locked surface
   758  */
   759 void
   760 SDL_UnlockSurface(SDL_Surface * surface)
   761 {
   762     /* Only perform an unlock if we are locked */
   763     if (!surface->locked || (--surface->locked > 0)) {
   764         return;
   765     }
   766 
   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  * Convert a surface into the specified pixel format.
   776  */
   777 SDL_Surface *
   778 SDL_ConvertSurface(SDL_Surface * surface, SDL_PixelFormat * format,
   779                    Uint32 flags)
   780 {
   781     SDL_Surface *convert;
   782     Uint32 copy_flags;
   783     SDL_Rect bounds;
   784 
   785     /* Check for empty destination palette! (results in empty image) */
   786     if (format->palette != NULL) {
   787         int i;
   788         for (i = 0; i < format->palette->ncolors; ++i) {
   789             if ((format->palette->colors[i].r != 0xFF) ||
   790                 (format->palette->colors[i].g != 0xFF) ||
   791                 (format->palette->colors[i].b != 0xFF))
   792                 break;
   793         }
   794         if (i == format->palette->ncolors) {
   795             SDL_SetError("Empty destination palette");
   796             return (NULL);
   797         }
   798     }
   799 
   800     /* Create a new surface with the desired format */
   801     convert = SDL_CreateRGBSurface(flags, surface->w, surface->h,
   802                                    format->BitsPerPixel, format->Rmask,
   803                                    format->Gmask, format->Bmask,
   804                                    format->Amask);
   805     if (convert == NULL) {
   806         return (NULL);
   807     }
   808 
   809     /* Copy the palette if any */
   810     if (format->palette && convert->format->palette) {
   811         SDL_memcpy(convert->format->palette->colors,
   812                    format->palette->colors,
   813                    format->palette->ncolors * sizeof(SDL_Color));
   814         convert->format->palette->ncolors = format->palette->ncolors;
   815     }
   816 
   817     /* Save the original copy flags */
   818     copy_flags = surface->map->info.flags;
   819     surface->map->info.flags = 0;
   820 
   821     /* Copy over the image data */
   822     bounds.x = 0;
   823     bounds.y = 0;
   824     bounds.w = surface->w;
   825     bounds.h = surface->h;
   826     SDL_LowerBlit(surface, &bounds, convert, &bounds);
   827 
   828     /* Clean up the original surface, and update converted surface */
   829     convert->map->info.r = surface->map->info.r;
   830     convert->map->info.g = surface->map->info.g;
   831     convert->map->info.b = surface->map->info.b;
   832     convert->map->info.a = surface->map->info.a;
   833     convert->map->info.flags =
   834         (copy_flags &
   835          ~(SDL_COPY_COLORKEY | SDL_COPY_BLEND
   836            | SDL_COPY_RLE_DESIRED | SDL_COPY_RLE_COLORKEY |
   837            SDL_COPY_RLE_ALPHAKEY));
   838     surface->map->info.flags = copy_flags;
   839     if (copy_flags & SDL_COPY_COLORKEY) {
   840         Uint8 keyR, keyG, keyB, keyA;
   841 
   842         SDL_GetRGBA(surface->map->info.colorkey, surface->format, &keyR,
   843                     &keyG, &keyB, &keyA);
   844         SDL_SetColorKey(convert, 1,
   845                         SDL_MapRGBA(convert->format, keyR, keyG, keyB, keyA));
   846         /* This is needed when converting for 3D texture upload */
   847         SDL_ConvertColorkeyToAlpha(convert);
   848     }
   849     SDL_SetClipRect(convert, &surface->clip_rect);
   850 
   851     /* Enable alpha blending by default if the new surface has an
   852      * alpha channel or alpha modulation */
   853     if ((surface->format->Amask && format->Amask) ||
   854         (copy_flags & SDL_COPY_MODULATE_ALPHA)) {
   855         SDL_SetSurfaceBlendMode(convert, SDL_BLENDMODE_BLEND);
   856     }
   857     if ((copy_flags & SDL_COPY_RLE_DESIRED) || (flags & SDL_RLEACCEL)) {
   858         SDL_SetSurfaceRLE(convert, SDL_RLEACCEL);
   859     }
   860 
   861     /* We're ready to go! */
   862     return (convert);
   863 }
   864 
   865 /*
   866  * Create a surface on the stack for quick blit operations
   867  */
   868 static __inline__ SDL_bool
   869 SDL_CreateSurfaceOnStack(int width, int height, Uint32 pixel_format,
   870                          void * pixels, int pitch, SDL_Surface * surface, 
   871                          SDL_PixelFormat * format, SDL_BlitMap * blitmap)
   872 {
   873     int bpp;
   874     Uint32 Rmask, Gmask, Bmask, Amask;
   875 
   876     if (!SDL_PixelFormatEnumToMasks(pixel_format,
   877                                     &bpp, &Rmask, &Gmask, &Bmask, &Amask)) {
   878         return SDL_FALSE;
   879     }
   880     if (bpp <= 8) {
   881         SDL_SetError("Indexed pixel formats not supported");
   882         return SDL_FALSE;
   883     }
   884 
   885     SDL_zerop(surface);
   886     surface->flags = SDL_PREALLOC;
   887     surface->format = SDL_InitFormat(format, bpp, Rmask, Gmask, Bmask, Amask);
   888     surface->pixels = pixels;
   889     surface->w = width;
   890     surface->h = height;
   891     surface->pitch = pitch;
   892     /* We don't actually need to set up the clip rect for our purposes */
   893     /*SDL_SetClipRect(surface, NULL);*/
   894 
   895     /* Allocate an empty mapping */
   896     SDL_zerop(blitmap);
   897     blitmap->info.r = 0xFF;
   898     blitmap->info.g = 0xFF;
   899     blitmap->info.b = 0xFF;
   900     blitmap->info.a = 0xFF;
   901     surface->map = blitmap;
   902     SDL_FormatChanged(surface);
   903 
   904     /* The surface is ready to go */
   905     surface->refcount = 1;
   906     return SDL_TRUE;
   907 }
   908 
   909 /*
   910  * Copy a block of pixels of one format to another format
   911  */
   912 int SDL_ConvertPixels(int width, int height,
   913                       Uint32 src_format, const void * src, int src_pitch,
   914                       Uint32 dst_format, void * dst, int dst_pitch)
   915 {
   916     SDL_Surface src_surface, dst_surface;
   917     SDL_PixelFormat src_fmt, dst_fmt;
   918     SDL_BlitMap src_blitmap, dst_blitmap;
   919     SDL_Rect rect;
   920 
   921     /* Fast path for same format copy */
   922     if (src_format == dst_format) {
   923         int bpp;
   924 
   925         if (SDL_ISPIXELFORMAT_FOURCC(src_format)) {
   926             switch (src_format) {
   927             case SDL_PIXELFORMAT_YV12:
   928             case SDL_PIXELFORMAT_IYUV:
   929             case SDL_PIXELFORMAT_YUY2:
   930             case SDL_PIXELFORMAT_UYVY:
   931             case SDL_PIXELFORMAT_YVYU:
   932                 bpp = 2;
   933             default:
   934                 SDL_SetError("Unknown FOURCC pixel format");
   935                 return -1;
   936             }
   937         } else {
   938             bpp = SDL_BYTESPERPIXEL(src_format);
   939         }
   940         width *= bpp;
   941 
   942         while (height-- > 0) {
   943             SDL_memcpy(dst, src, width);
   944             src = (Uint8*)src + src_pitch;
   945             dst = (Uint8*)dst + dst_pitch;
   946         }
   947         return SDL_TRUE;
   948     }
   949 
   950     if (!SDL_CreateSurfaceOnStack(width, height, src_format, (void*)src,
   951                                   src_pitch,
   952                                   &src_surface, &src_fmt, &src_blitmap)) {
   953         return -1;
   954     }
   955     if (!SDL_CreateSurfaceOnStack(width, height, dst_format, dst, dst_pitch,
   956                                   &dst_surface, &dst_fmt, &dst_blitmap)) {
   957         return -1;
   958     }
   959 
   960     /* Set up the rect and go! */
   961     rect.x = 0;
   962     rect.y = 0;
   963     rect.w = width;
   964     rect.h = height;
   965     return SDL_LowerBlit(&src_surface, &rect, &dst_surface, &rect);
   966 }
   967 
   968 /*
   969  * Free a surface created by the above function.
   970  */
   971 void
   972 SDL_FreeSurface(SDL_Surface * surface)
   973 {
   974     if (surface == NULL) {
   975         return;
   976     }
   977     if (--surface->refcount > 0) {
   978         return;
   979     }
   980     while (surface->locked > 0) {
   981         SDL_UnlockSurface(surface);
   982     }
   983     if (surface->flags & SDL_RLEACCEL) {
   984         SDL_UnRLESurface(surface, 0);
   985     }
   986     if (surface->format) {
   987         SDL_SetSurfacePalette(surface, NULL);
   988         SDL_FreeFormat(surface->format);
   989         surface->format = NULL;
   990     }
   991     if (surface->map != NULL) {
   992         SDL_FreeBlitMap(surface->map);
   993         surface->map = NULL;
   994     }
   995     if (surface->pixels && ((surface->flags & SDL_PREALLOC) != SDL_PREALLOC)) {
   996         SDL_free(surface->pixels);
   997     }
   998     SDL_free(surface);
   999 #ifdef CHECK_LEAKS
  1000     --surfaces_allocated;
  1001 #endif
  1002 }
  1003 
  1004 /* vi: set ts=4 sw=4 expandtab: */