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