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