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