src/video/SDL_surface.c
author Ken Rogoway <ken@rogoway.com>
Sun, 13 Mar 2011 22:38:41 -0500
changeset 5499 2b8e6d1e3817
parent 5438 b705640cb34a
child 5515 0fcf231a6e74
permissions -rw-r--r--
Split SDL_BlitScaled into SDL_UpperBlitScaled and SDL_LowerBlitScaled.
Fixed issue when calling SDL_BlitScaled() directly with src or dst rectangles that were out of bounds.
     1 /*
     2     SDL - Simple DirectMedia Layer
     3     Copyright (C) 1997-2011 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 
    31 
    32 /* Public routines */
    33 /*
    34  * Create an empty RGB surface of the appropriate depth
    35  */
    36 SDL_Surface *
    37 SDL_CreateRGBSurface(Uint32 flags,
    38                      int width, int height, int depth,
    39                      Uint32 Rmask, Uint32 Gmask, Uint32 Bmask, Uint32 Amask)
    40 {
    41     SDL_Surface *surface;
    42     Uint32 format;
    43 
    44     /* The flags are no longer used, make the compiler happy */
    45     (void)flags;
    46 
    47     /* Get the pixel format */
    48     format = SDL_MasksToPixelFormatEnum(depth, Rmask, Gmask, Bmask, Amask);
    49     if (format == SDL_PIXELFORMAT_UNKNOWN) {
    50         SDL_SetError("Unknown pixel format");
    51         return NULL;
    52     }
    53 
    54     /* Allocate the surface */
    55     surface = (SDL_Surface *) SDL_calloc(1, sizeof(*surface));
    56     if (surface == NULL) {
    57         SDL_OutOfMemory();
    58         return NULL;
    59     }
    60 
    61     surface->format = SDL_AllocFormat(format);
    62     if (!surface->format) {
    63         SDL_FreeSurface(surface);
    64         return NULL;
    65     }
    66     surface->w = width;
    67     surface->h = height;
    68     surface->pitch = SDL_CalculatePitch(surface);
    69     SDL_SetClipRect(surface, NULL);
    70 
    71     if (SDL_ISPIXELFORMAT_INDEXED(surface->format->format)) {
    72         SDL_Palette *palette =
    73             SDL_AllocPalette((1 << surface->format->BitsPerPixel));
    74         if (!palette) {
    75             SDL_FreeSurface(surface);
    76             return NULL;
    77         }
    78         if (palette->ncolors == 2) {
    79             /* Create a black and white bitmap palette */
    80             palette->colors[0].r = 0xFF;
    81             palette->colors[0].g = 0xFF;
    82             palette->colors[0].b = 0xFF;
    83             palette->colors[1].r = 0x00;
    84             palette->colors[1].g = 0x00;
    85             palette->colors[1].b = 0x00;
    86         }
    87         SDL_SetSurfacePalette(surface, palette);
    88         SDL_FreePalette(palette);
    89     }
    90 
    91     /* Get the pixels */
    92     if (surface->w && surface->h) {
    93         surface->pixels = SDL_malloc(surface->h * surface->pitch);
    94         if (!surface->pixels) {
    95             SDL_FreeSurface(surface);
    96             SDL_OutOfMemory();
    97             return NULL;
    98         }
    99         /* This is important for bitmaps */
   100         SDL_memset(surface->pixels, 0, surface->h * surface->pitch);
   101     }
   102 
   103     /* Allocate an empty mapping */
   104     surface->map = SDL_AllocBlitMap();
   105     if (!surface->map) {
   106         SDL_FreeSurface(surface);
   107         return NULL;
   108     }
   109 
   110     /* By default surface with an alpha mask are set up for blending */
   111     if (Amask) {
   112         SDL_SetSurfaceBlendMode(surface, SDL_BLENDMODE_BLEND);
   113     }
   114 
   115     /* The surface is ready to go */
   116     surface->refcount = 1;
   117     return surface;
   118 }
   119 
   120 /*
   121  * Create an RGB surface from an existing memory buffer
   122  */
   123 SDL_Surface *
   124 SDL_CreateRGBSurfaceFrom(void *pixels,
   125                          int width, int height, int depth, int pitch,
   126                          Uint32 Rmask, Uint32 Gmask, Uint32 Bmask,
   127                          Uint32 Amask)
   128 {
   129     SDL_Surface *surface;
   130 
   131     surface =
   132         SDL_CreateRGBSurface(0, 0, 0, depth, Rmask, Gmask, Bmask, Amask);
   133     if (surface != NULL) {
   134         surface->flags |= SDL_PREALLOC;
   135         surface->pixels = pixels;
   136         surface->w = width;
   137         surface->h = height;
   138         surface->pitch = pitch;
   139         SDL_SetClipRect(surface, NULL);
   140     }
   141     return surface;
   142 }
   143 
   144 int
   145 SDL_SetSurfacePalette(SDL_Surface * surface, SDL_Palette * palette)
   146 {
   147     if (!surface) {
   148         SDL_SetError("SDL_SetSurfacePalette() passed a NULL surface");
   149         return -1;
   150     }
   151     return SDL_SetPixelFormatPalette(surface->format, palette);
   152 }
   153 
   154 int
   155 SDL_SetSurfaceRLE(SDL_Surface * surface, int flag)
   156 {
   157     int flags;
   158 
   159     if (!surface) {
   160         return -1;
   161     }
   162 
   163     flags = surface->map->info.flags;
   164     if (flag) {
   165         surface->map->info.flags |= SDL_COPY_RLE_DESIRED;
   166     } else {
   167         surface->map->info.flags &= ~SDL_COPY_RLE_DESIRED;
   168     }
   169     if (surface->map->info.flags != flags) {
   170         SDL_InvalidateMap(surface->map);
   171     }
   172     return 0;
   173 }
   174 
   175 int
   176 SDL_SetColorKey(SDL_Surface * surface, int flag, Uint32 key)
   177 {
   178     int flags;
   179 
   180     if (!surface) {
   181         return -1;
   182     }
   183 
   184     if (flag & SDL_RLEACCEL) {
   185         SDL_SetSurfaceRLE(surface, 1);
   186     }
   187 
   188     flags = surface->map->info.flags;
   189     if (flag) {
   190         surface->map->info.flags |= SDL_COPY_COLORKEY;
   191         surface->map->info.colorkey = key;
   192     } else {
   193         surface->map->info.flags &= ~SDL_COPY_COLORKEY;
   194     }
   195     if (surface->map->info.flags != flags) {
   196         SDL_InvalidateMap(surface->map);
   197     }
   198 
   199     /* Compatibility mode */
   200     if (surface->map->info.flags & SDL_COPY_COLORKEY) {
   201         surface->flags |= SDL_SRCCOLORKEY;
   202     } else {
   203         surface->flags &= ~SDL_SRCCOLORKEY;
   204     }
   205 
   206     return 0;
   207 }
   208 
   209 int
   210 SDL_GetColorKey(SDL_Surface * surface, Uint32 * key)
   211 {
   212     if (!surface) {
   213         return -1;
   214     }
   215 
   216     if (!(surface->map->info.flags & SDL_COPY_COLORKEY)) {
   217         return -1;
   218     }
   219 
   220     if (key) {
   221         *key = surface->map->info.colorkey;
   222     }
   223     return 0;
   224 }
   225 
   226 /* This is a fairly slow function to switch from colorkey to alpha */
   227 static void
   228 SDL_ConvertColorkeyToAlpha(SDL_Surface * surface)
   229 {
   230     int x, y;
   231 
   232     if (!surface) {
   233         return;
   234     }
   235 
   236     if (!(surface->map->info.flags & SDL_COPY_COLORKEY) ||
   237         !surface->format->Amask) {
   238         return;
   239     }
   240 
   241     SDL_LockSurface(surface);
   242 
   243     switch (surface->format->BytesPerPixel) {
   244     case 2:
   245         {
   246             Uint16 *row, *spot;
   247             Uint16 ckey = (Uint16) surface->map->info.colorkey;
   248             Uint16 mask = (Uint16) (~surface->format->Amask);
   249 
   250             row = (Uint16 *) surface->pixels;
   251             for (y = surface->h; y--;) {
   252                 spot = row;
   253                 for (x = surface->w; x--;) {
   254                     if (*spot == ckey) {
   255                         *spot &= mask;
   256                     }
   257                     ++spot;
   258                 }
   259                 row += surface->pitch / 2;
   260             }
   261         }
   262         break;
   263     case 3:
   264         /* FIXME */
   265         break;
   266     case 4:
   267         {
   268             Uint32 *row, *spot;
   269             Uint32 ckey = surface->map->info.colorkey;
   270             Uint32 mask = ~surface->format->Amask;
   271 
   272             row = (Uint32 *) surface->pixels;
   273             for (y = surface->h; y--;) {
   274                 spot = row;
   275                 for (x = surface->w; x--;) {
   276                     if (*spot == ckey) {
   277                         *spot &= mask;
   278                     }
   279                     ++spot;
   280                 }
   281                 row += surface->pitch / 4;
   282             }
   283         }
   284         break;
   285     }
   286 
   287     SDL_UnlockSurface(surface);
   288 
   289     SDL_SetColorKey(surface, 0, 0);
   290     SDL_SetSurfaceBlendMode(surface, SDL_BLENDMODE_BLEND);
   291 }
   292 
   293 int
   294 SDL_SetSurfaceColorMod(SDL_Surface * surface, Uint8 r, Uint8 g, Uint8 b)
   295 {
   296     int flags;
   297 
   298     if (!surface) {
   299         return -1;
   300     }
   301 
   302     surface->map->info.r = r;
   303     surface->map->info.g = g;
   304     surface->map->info.b = b;
   305 
   306     flags = surface->map->info.flags;
   307     if (r != 0xFF || g != 0xFF || b != 0xFF) {
   308         surface->map->info.flags |= SDL_COPY_MODULATE_COLOR;
   309     } else {
   310         surface->map->info.flags &= ~SDL_COPY_MODULATE_COLOR;
   311     }
   312     if (surface->map->info.flags != flags) {
   313         SDL_InvalidateMap(surface->map);
   314     }
   315     return 0;
   316 }
   317 
   318 
   319 int
   320 SDL_GetSurfaceColorMod(SDL_Surface * surface, Uint8 * r, Uint8 * g, Uint8 * b)
   321 {
   322     if (!surface) {
   323         return -1;
   324     }
   325 
   326     if (r) {
   327         *r = surface->map->info.r;
   328     }
   329     if (g) {
   330         *g = surface->map->info.g;
   331     }
   332     if (b) {
   333         *b = surface->map->info.b;
   334     }
   335     return 0;
   336 }
   337 
   338 int
   339 SDL_SetSurfaceAlphaMod(SDL_Surface * surface, Uint8 alpha)
   340 {
   341     int flags;
   342 
   343     if (!surface) {
   344         return -1;
   345     }
   346 
   347     surface->map->info.a = alpha;
   348 
   349     flags = surface->map->info.flags;
   350     if (alpha != 0xFF) {
   351         surface->map->info.flags |= SDL_COPY_MODULATE_ALPHA;
   352     } else {
   353         surface->map->info.flags &= ~SDL_COPY_MODULATE_ALPHA;
   354     }
   355     if (surface->map->info.flags != flags) {
   356         SDL_InvalidateMap(surface->map);
   357     }
   358     return 0;
   359 }
   360 
   361 int
   362 SDL_GetSurfaceAlphaMod(SDL_Surface * surface, Uint8 * alpha)
   363 {
   364     if (!surface) {
   365         return -1;
   366     }
   367 
   368     if (alpha) {
   369         *alpha = surface->map->info.a;
   370     }
   371     return 0;
   372 }
   373 
   374 int
   375 SDL_SetSurfaceBlendMode(SDL_Surface * surface, SDL_BlendMode blendMode)
   376 {
   377     int flags, status;
   378 
   379     if (!surface) {
   380         return -1;
   381     }
   382 
   383     status = 0;
   384     flags = surface->map->info.flags;
   385     surface->map->info.flags &=
   386         ~(SDL_COPY_BLEND | SDL_COPY_ADD | SDL_COPY_MOD);
   387     switch (blendMode) {
   388     case SDL_BLENDMODE_NONE:
   389         break;
   390     case SDL_BLENDMODE_BLEND:
   391         surface->map->info.flags |= SDL_COPY_BLEND;
   392         break;
   393     case SDL_BLENDMODE_ADD:
   394         surface->map->info.flags |= SDL_COPY_ADD;
   395         break;
   396     case SDL_BLENDMODE_MOD:
   397         surface->map->info.flags |= SDL_COPY_MOD;
   398         break;
   399     default:
   400         SDL_Unsupported();
   401         status = -1;
   402         break;
   403     }
   404 
   405     if (surface->map->info.flags != flags) {
   406         SDL_InvalidateMap(surface->map);
   407     }
   408 
   409     /* Compatibility mode */
   410     if (surface->map->info.flags & SDL_COPY_BLEND) {
   411         surface->flags |= SDL_SRCALPHA;
   412     } else {
   413         surface->flags &= ~SDL_SRCALPHA;
   414     }
   415 
   416     return status;
   417 }
   418 
   419 int
   420 SDL_GetSurfaceBlendMode(SDL_Surface * surface, SDL_BlendMode *blendMode)
   421 {
   422     if (!surface) {
   423         return -1;
   424     }
   425 
   426     if (!blendMode) {
   427         return 0;
   428     }
   429 
   430     switch (surface->map->
   431             info.flags & (SDL_COPY_BLEND | SDL_COPY_ADD | SDL_COPY_MOD)) {
   432     case SDL_COPY_BLEND:
   433         *blendMode = SDL_BLENDMODE_BLEND;
   434         break;
   435     case SDL_COPY_ADD:
   436         *blendMode = SDL_BLENDMODE_ADD;
   437         break;
   438     case SDL_COPY_MOD:
   439         *blendMode = SDL_BLENDMODE_MOD;
   440         break;
   441     default:
   442         *blendMode = SDL_BLENDMODE_NONE;
   443         break;
   444     }
   445     return 0;
   446 }
   447 
   448 SDL_bool
   449 SDL_SetClipRect(SDL_Surface * surface, const SDL_Rect * rect)
   450 {
   451     SDL_Rect full_rect;
   452 
   453     /* Don't do anything if there's no surface to act on */
   454     if (!surface) {
   455         return SDL_FALSE;
   456     }
   457 
   458     /* Set up the full surface rectangle */
   459     full_rect.x = 0;
   460     full_rect.y = 0;
   461     full_rect.w = surface->w;
   462     full_rect.h = surface->h;
   463 
   464     /* Set the clipping rectangle */
   465     if (!rect) {
   466         surface->clip_rect = full_rect;
   467         return SDL_TRUE;
   468     }
   469     return SDL_IntersectRect(rect, &full_rect, &surface->clip_rect);
   470 }
   471 
   472 void
   473 SDL_GetClipRect(SDL_Surface * surface, SDL_Rect * rect)
   474 {
   475     if (surface && rect) {
   476         *rect = surface->clip_rect;
   477     }
   478 }
   479 
   480 /* 
   481  * Set up a blit between two surfaces -- split into three parts:
   482  * The upper part, SDL_UpperBlit(), performs clipping and rectangle 
   483  * verification.  The lower part is a pointer to a low level
   484  * accelerated blitting function.
   485  *
   486  * These parts are separated out and each used internally by this 
   487  * library in the optimimum places.  They are exported so that if
   488  * you know exactly what you are doing, you can optimize your code
   489  * by calling the one(s) you need.
   490  */
   491 int
   492 SDL_LowerBlit(SDL_Surface * src, SDL_Rect * srcrect,
   493               SDL_Surface * dst, SDL_Rect * dstrect)
   494 {
   495     /* Check to make sure the blit mapping is valid */
   496     if ((src->map->dst != dst) ||
   497         (dst->format->palette &&
   498          src->map->palette_version != dst->format->palette->version)) {
   499         if (SDL_MapSurface(src, dst) < 0) {
   500             return (-1);
   501         }
   502         /* just here for debugging */
   503 /*         printf */
   504 /*             ("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", */
   505 /*              src, dst->flags, src->map->info.flags, dst, dst->flags, */
   506 /*              dst->map->info.flags, src->map->blit); */
   507     }
   508     return (src->map->blit(src, srcrect, dst, dstrect));
   509 }
   510 
   511 
   512 int
   513 SDL_UpperBlit(SDL_Surface * src, const SDL_Rect * srcrect,
   514               SDL_Surface * dst, SDL_Rect * dstrect)
   515 {
   516     SDL_Rect fulldst;
   517     int srcx, srcy, w, h;
   518 
   519     /* Make sure the surfaces aren't locked */
   520     if (!src || !dst) {
   521         SDL_SetError("SDL_UpperBlit: passed a NULL surface");
   522         return (-1);
   523     }
   524     if (src->locked || dst->locked) {
   525         SDL_SetError("Surfaces must not be locked during blit");
   526         return (-1);
   527     }
   528 
   529     /* If the destination rectangle is NULL, use the entire dest surface */
   530     if (dstrect == NULL) {
   531         fulldst.x = fulldst.y = 0;
   532         dstrect = &fulldst;
   533     }
   534 
   535     /* clip the source rectangle to the source surface */
   536     if (srcrect) {
   537         int maxw, maxh;
   538 
   539         srcx = srcrect->x;
   540         w = srcrect->w;
   541         if (srcx < 0) {
   542             w += srcx;
   543             dstrect->x -= srcx;
   544             srcx = 0;
   545         }
   546         maxw = src->w - srcx;
   547         if (maxw < w)
   548             w = maxw;
   549 
   550         srcy = srcrect->y;
   551         h = srcrect->h;
   552         if (srcy < 0) {
   553             h += srcy;
   554             dstrect->y -= srcy;
   555             srcy = 0;
   556         }
   557         maxh = src->h - srcy;
   558         if (maxh < h)
   559             h = maxh;
   560 
   561     } else {
   562         srcx = srcy = 0;
   563         w = src->w;
   564         h = src->h;
   565     }
   566 
   567     /* clip the destination rectangle against the clip rectangle */
   568     {
   569         SDL_Rect *clip = &dst->clip_rect;
   570         int dx, dy;
   571 
   572         dx = clip->x - dstrect->x;
   573         if (dx > 0) {
   574             w -= dx;
   575             dstrect->x += dx;
   576             srcx += dx;
   577         }
   578         dx = dstrect->x + w - clip->x - clip->w;
   579         if (dx > 0)
   580             w -= dx;
   581 
   582         dy = clip->y - dstrect->y;
   583         if (dy > 0) {
   584             h -= dy;
   585             dstrect->y += dy;
   586             srcy += dy;
   587         }
   588         dy = dstrect->y + h - clip->y - clip->h;
   589         if (dy > 0)
   590             h -= dy;
   591     }
   592 
   593     if (w > 0 && h > 0) {
   594         SDL_Rect sr;
   595         sr.x = srcx;
   596         sr.y = srcy;
   597         sr.w = dstrect->w = w;
   598         sr.h = dstrect->h = h;
   599         return SDL_LowerBlit(src, &sr, dst, dstrect);
   600     }
   601     dstrect->w = dstrect->h = 0;
   602     return 0;
   603 }
   604 
   605 int
   606 SDL_UpperBlitScaled(SDL_Surface * src, const SDL_Rect * srcrect,
   607               SDL_Surface * dst, SDL_Rect * dstrect)
   608 {
   609     SDL_Rect final_src, final_dst, fulldst;
   610 
   611     /* Make sure the surfaces aren't locked */
   612     if (!src || !dst) {
   613         SDL_SetError("SDL_UpperBlitScaled: passed a NULL surface");
   614         return (-1);
   615     }
   616     if (src->locked || dst->locked) {
   617         SDL_SetError("Surfaces must not be locked during blit");
   618         return (-1);
   619     }
   620 
   621     /* If the destination rectangle is NULL, use the entire dest surface */
   622     if (dstrect == NULL) {
   623         fulldst.x = fulldst.y = 0;
   624         dstrect = &fulldst;
   625     }
   626 
   627     /* clip the source rectangle to the source surface */
   628     if (srcrect) {
   629         int maxw, maxh;
   630 
   631         final_src.x = srcrect->x;
   632         final_src.w = srcrect->w;
   633         if (final_src.x < 0) {
   634             final_src.w += final_src.x;
   635             final_src.x = 0;
   636         }
   637         maxw = src->w - final_src.x;
   638         if (maxw < final_src.w)
   639             final_src.w = maxw;
   640 
   641         final_src.y = srcrect->y;
   642         final_src.h = srcrect->h;
   643         if (final_src.y < 0) {
   644             final_src.h += final_src.y;
   645             final_src.y = 0;
   646         }
   647         maxh = src->h - final_src.y;
   648         if (maxh < final_src.h)
   649             final_src.h = maxh;
   650 
   651     } else {
   652         final_src.x = final_src.y = 0;
   653         final_src.w = src->w;
   654         final_src.h = src->h;
   655     }
   656 
   657     /* clip the destination rectangle against the clip rectangle */
   658     if (dstrect) {
   659         int maxw, maxh;
   660 
   661         final_dst.x = dstrect->x;
   662         final_dst.w = dstrect->w;
   663         if (final_dst.x < 0) {
   664             final_dst.w += final_dst.x;
   665             final_dst.x = 0;
   666         }
   667         maxw = dst->w - final_dst.x;
   668         if (maxw < final_dst.w)
   669             final_dst.w = maxw;
   670 
   671         final_dst.y = dstrect->y;
   672         final_dst.h = dstrect->h;
   673         if (final_dst.y < 0) {
   674             final_dst.h += final_dst.y;
   675             final_dst.y = 0;
   676         }
   677         maxh = dst->h - final_dst.y;
   678         if (maxh < final_dst.h)
   679             final_dst.h = maxh;
   680     } else {
   681         final_dst.x = final_dst.y = 0;
   682         final_dst.w = dst->w;
   683         final_dst.h = dst->h;
   684     }
   685 
   686     if (final_dst.w > 0 && final_dst.h > 0) {
   687         return SDL_LowerBlitScaled(src, &final_src, dst, &final_dst);
   688     }
   689 
   690     return 0;
   691 }
   692 
   693 /**
   694  *  This is a semi-private blit function and it performs low-level surface
   695  *  scaled blitting only.
   696  */
   697 int
   698 SDL_LowerBlitScaled(SDL_Surface * src, SDL_Rect * srcrect,
   699                 SDL_Surface * dst, SDL_Rect * dstrect)
   700 {
   701     /* Save off the original dst width, height */
   702     int dstW = dstrect->w;
   703     int dstH = dstrect->h;
   704     SDL_Rect final_dst = *dstrect;
   705     SDL_Rect final_src = *srcrect;
   706 
   707     /* Clip the dst surface to the dstrect */
   708     SDL_SetClipRect( dst, &final_dst );
   709 
   710     /* Did the dst width change? */
   711     if ( dstW != dst->clip_rect.w ) {
   712         /* scale the src width appropriately */
   713         final_src.w = final_src.w * dst->clip_rect.w / dstW;
   714     }
   715 
   716     /* Did the dst height change? */
   717     if ( dstH != dst->clip_rect.h ) {
   718         /* scale the src width appropriately */
   719         final_src.h = final_src.h * dst->clip_rect.h / dstH;
   720     }
   721 
   722     /* Clip the src surface to the srcrect */
   723     SDL_SetClipRect( src, &final_src );
   724 
   725     src->map->info.flags |= SDL_COPY_NEAREST;
   726 
   727     if ( src->format->format == dst->format->format && !SDL_ISPIXELFORMAT_INDEXED(src->format->format) ) {
   728         return SDL_SoftStretch( src, &final_src, dst, &final_dst );
   729     } else {
   730         return SDL_LowerBlit( src, &final_src, dst, &final_dst );
   731     }
   732 }
   733 
   734 /*
   735  * Lock a surface to directly access the pixels
   736  */
   737 int
   738 SDL_LockSurface(SDL_Surface * surface)
   739 {
   740     if (!surface->locked) {
   741         /* Perform the lock */
   742         if (surface->flags & SDL_RLEACCEL) {
   743             SDL_UnRLESurface(surface, 1);
   744             surface->flags |= SDL_RLEACCEL;     /* save accel'd state */
   745         }
   746     }
   747 
   748     /* Increment the surface lock count, for recursive locks */
   749     ++surface->locked;
   750 
   751     /* Ready to go.. */
   752     return (0);
   753 }
   754 
   755 /*
   756  * Unlock a previously locked surface
   757  */
   758 void
   759 SDL_UnlockSurface(SDL_Surface * surface)
   760 {
   761     /* Only perform an unlock if we are locked */
   762     if (!surface->locked || (--surface->locked > 0)) {
   763         return;
   764     }
   765 
   766     /* Update RLE encoded surface with new data */
   767     if ((surface->flags & SDL_RLEACCEL) == SDL_RLEACCEL) {
   768         surface->flags &= ~SDL_RLEACCEL;        /* stop lying */
   769         SDL_RLESurface(surface);
   770     }
   771 }
   772 
   773 /* 
   774  * Convert a surface into the specified pixel format.
   775  */
   776 SDL_Surface *
   777 SDL_ConvertSurface(SDL_Surface * surface, SDL_PixelFormat * format,
   778                    Uint32 flags)
   779 {
   780     SDL_Surface *convert;
   781     Uint32 copy_flags;
   782     SDL_Rect bounds;
   783 
   784     /* Check for empty destination palette! (results in empty image) */
   785     if (format->palette != NULL) {
   786         int i;
   787         for (i = 0; i < format->palette->ncolors; ++i) {
   788             if ((format->palette->colors[i].r != 0xFF) ||
   789                 (format->palette->colors[i].g != 0xFF) ||
   790                 (format->palette->colors[i].b != 0xFF))
   791                 break;
   792         }
   793         if (i == format->palette->ncolors) {
   794             SDL_SetError("Empty destination palette");
   795             return (NULL);
   796         }
   797     }
   798 
   799     /* Create a new surface with the desired format */
   800     convert = SDL_CreateRGBSurface(flags, surface->w, surface->h,
   801                                    format->BitsPerPixel, format->Rmask,
   802                                    format->Gmask, format->Bmask,
   803                                    format->Amask);
   804     if (convert == NULL) {
   805         return (NULL);
   806     }
   807 
   808     /* Copy the palette if any */
   809     if (format->palette && convert->format->palette) {
   810         SDL_memcpy(convert->format->palette->colors,
   811                    format->palette->colors,
   812                    format->palette->ncolors * sizeof(SDL_Color));
   813         convert->format->palette->ncolors = format->palette->ncolors;
   814     }
   815 
   816     /* Save the original copy flags */
   817     copy_flags = surface->map->info.flags;
   818     surface->map->info.flags = 0;
   819 
   820     /* Copy over the image data */
   821     bounds.x = 0;
   822     bounds.y = 0;
   823     bounds.w = surface->w;
   824     bounds.h = surface->h;
   825     SDL_LowerBlit(surface, &bounds, convert, &bounds);
   826 
   827     /* Clean up the original surface, and update converted surface */
   828     convert->map->info.r = surface->map->info.r;
   829     convert->map->info.g = surface->map->info.g;
   830     convert->map->info.b = surface->map->info.b;
   831     convert->map->info.a = surface->map->info.a;
   832     convert->map->info.flags =
   833         (copy_flags &
   834          ~(SDL_COPY_COLORKEY | SDL_COPY_BLEND
   835            | SDL_COPY_RLE_DESIRED | SDL_COPY_RLE_COLORKEY |
   836            SDL_COPY_RLE_ALPHAKEY));
   837     surface->map->info.flags = copy_flags;
   838     if (copy_flags & SDL_COPY_COLORKEY) {
   839         Uint8 keyR, keyG, keyB, keyA;
   840 
   841         SDL_GetRGBA(surface->map->info.colorkey, surface->format, &keyR,
   842                     &keyG, &keyB, &keyA);
   843         SDL_SetColorKey(convert, 1,
   844                         SDL_MapRGBA(convert->format, keyR, keyG, keyB, keyA));
   845         /* This is needed when converting for 3D texture upload */
   846         SDL_ConvertColorkeyToAlpha(convert);
   847     }
   848     SDL_SetClipRect(convert, &surface->clip_rect);
   849 
   850     /* Enable alpha blending by default if the new surface has an
   851      * alpha channel or alpha modulation */
   852     if ((surface->format->Amask && format->Amask) ||
   853         (copy_flags & (SDL_COPY_COLORKEY|SDL_COPY_MODULATE_ALPHA))) {
   854         SDL_SetSurfaceBlendMode(convert, SDL_BLENDMODE_BLEND);
   855     }
   856     if ((copy_flags & SDL_COPY_RLE_DESIRED) || (flags & SDL_RLEACCEL)) {
   857         SDL_SetSurfaceRLE(convert, SDL_RLEACCEL);
   858     }
   859 
   860     /* We're ready to go! */
   861     return (convert);
   862 }
   863 
   864 SDL_Surface *
   865 SDL_ConvertSurfaceFormat(SDL_Surface * surface, Uint32 pixel_format,
   866                          Uint32 flags)
   867 {
   868     SDL_PixelFormat *fmt;
   869     SDL_Surface *convert;
   870 
   871     fmt = SDL_AllocFormat(pixel_format);
   872     if (fmt) {
   873         convert = SDL_ConvertSurface(surface, fmt, flags);
   874         SDL_FreeFormat(fmt);
   875     }
   876     return convert;
   877 }
   878 
   879 /*
   880  * Create a surface on the stack for quick blit operations
   881  */
   882 static __inline__ SDL_bool
   883 SDL_CreateSurfaceOnStack(int width, int height, Uint32 pixel_format,
   884                          void * pixels, int pitch, SDL_Surface * surface, 
   885                          SDL_PixelFormat * format, SDL_BlitMap * blitmap)
   886 {
   887     if (SDL_ISPIXELFORMAT_INDEXED(pixel_format)) {
   888         SDL_SetError("Indexed pixel formats not supported");
   889         return SDL_FALSE;
   890     }
   891     if (SDL_InitFormat(format, pixel_format) < 0) {
   892         return SDL_FALSE;
   893     }
   894 
   895     SDL_zerop(surface);
   896     surface->flags = SDL_PREALLOC;
   897     surface->format = format;
   898     surface->pixels = pixels;
   899     surface->w = width;
   900     surface->h = height;
   901     surface->pitch = pitch;
   902     /* We don't actually need to set up the clip rect for our purposes */
   903     /*SDL_SetClipRect(surface, NULL);*/
   904 
   905     /* Allocate an empty mapping */
   906     SDL_zerop(blitmap);
   907     blitmap->info.r = 0xFF;
   908     blitmap->info.g = 0xFF;
   909     blitmap->info.b = 0xFF;
   910     blitmap->info.a = 0xFF;
   911     surface->map = blitmap;
   912 
   913     /* The surface is ready to go */
   914     surface->refcount = 1;
   915     return SDL_TRUE;
   916 }
   917 
   918 /*
   919  * Copy a block of pixels of one format to another format
   920  */
   921 int SDL_ConvertPixels(int width, int height,
   922                       Uint32 src_format, const void * src, int src_pitch,
   923                       Uint32 dst_format, void * dst, int dst_pitch)
   924 {
   925     SDL_Surface src_surface, dst_surface;
   926     SDL_PixelFormat src_fmt, dst_fmt;
   927     SDL_BlitMap src_blitmap, dst_blitmap;
   928     SDL_Rect rect;
   929 
   930     /* Fast path for same format copy */
   931     if (src_format == dst_format) {
   932         int bpp;
   933 
   934         if (SDL_ISPIXELFORMAT_FOURCC(src_format)) {
   935             switch (src_format) {
   936             case SDL_PIXELFORMAT_YV12:
   937             case SDL_PIXELFORMAT_IYUV:
   938             case SDL_PIXELFORMAT_YUY2:
   939             case SDL_PIXELFORMAT_UYVY:
   940             case SDL_PIXELFORMAT_YVYU:
   941                 bpp = 2;
   942             default:
   943                 SDL_SetError("Unknown FOURCC pixel format");
   944                 return -1;
   945             }
   946         } else {
   947             bpp = SDL_BYTESPERPIXEL(src_format);
   948         }
   949         width *= bpp;
   950 
   951         while (height-- > 0) {
   952             SDL_memcpy(dst, src, width);
   953             src = (Uint8*)src + src_pitch;
   954             dst = (Uint8*)dst + dst_pitch;
   955         }
   956         return SDL_TRUE;
   957     }
   958 
   959     if (!SDL_CreateSurfaceOnStack(width, height, src_format, (void*)src,
   960                                   src_pitch,
   961                                   &src_surface, &src_fmt, &src_blitmap)) {
   962         return -1;
   963     }
   964     if (!SDL_CreateSurfaceOnStack(width, height, dst_format, dst, dst_pitch,
   965                                   &dst_surface, &dst_fmt, &dst_blitmap)) {
   966         return -1;
   967     }
   968 
   969     /* Set up the rect and go! */
   970     rect.x = 0;
   971     rect.y = 0;
   972     rect.w = width;
   973     rect.h = height;
   974     return SDL_LowerBlit(&src_surface, &rect, &dst_surface, &rect);
   975 }
   976 
   977 /*
   978  * Free a surface created by the above function.
   979  */
   980 void
   981 SDL_FreeSurface(SDL_Surface * surface)
   982 {
   983     if (surface == NULL) {
   984         return;
   985     }
   986     if (surface->flags & SDL_DONTFREE) {
   987         return;
   988     }
   989     if (--surface->refcount > 0) {
   990         return;
   991     }
   992     while (surface->locked > 0) {
   993         SDL_UnlockSurface(surface);
   994     }
   995     if (surface->flags & SDL_RLEACCEL) {
   996         SDL_UnRLESurface(surface, 0);
   997     }
   998     if (surface->format) {
   999         SDL_SetSurfacePalette(surface, NULL);
  1000         SDL_FreeFormat(surface->format);
  1001         surface->format = NULL;
  1002     }
  1003     if (surface->map != NULL) {
  1004         SDL_FreeBlitMap(surface->map);
  1005         surface->map = NULL;
  1006     }
  1007     if (surface->pixels && ((surface->flags & SDL_PREALLOC) != SDL_PREALLOC)) {
  1008         SDL_free(surface->pixels);
  1009     }
  1010     SDL_free(surface);
  1011 }
  1012 
  1013 /* vi: set ts=4 sw=4 expandtab: */