src/video/SDL_surface.c
author Sam Lantinga <slouken@libsdl.org>
Sun, 20 Oct 2013 21:56:15 -0700
changeset 7860 2b0bcdea3a79
parent 7834 e22726c82922
child 8093 b43765095a6f
permissions -rw-r--r--
Fixed bug 2129 - fix for bug 2121 breaks linking for mingw and throws multiple warnings

Andreas Ertelt

The problem in question is caused by changeset 7771 (http://hg.libsdl.org/SDL/rev/4434498bf4b9 / https://bugzilla.libsdl.org/show_bug.cgi?id=2121)

The redefinition of __inline__ (introduced by the addition of begin_code.h:128's "|| __STRICT_ANSI__") results in mingw's gcc throwing multiple

warning: always_inline function might not be inlinable [-Wattributes]

as well as a whole bunch of redefinitions of mingw internals which break linking of projects including the SDL2 headers.
     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     /* Switch back to a fast blit if we were previously stretching */
   600     if (src->map->info.flags & SDL_COPY_NEAREST) {
   601         src->map->info.flags &= ~SDL_COPY_NEAREST;
   602         SDL_InvalidateMap(src->map);
   603     }
   604 
   605     if (w > 0 && h > 0) {
   606         SDL_Rect sr;
   607         sr.x = srcx;
   608         sr.y = srcy;
   609         sr.w = dstrect->w = w;
   610         sr.h = dstrect->h = h;
   611         return SDL_LowerBlit(src, &sr, dst, dstrect);
   612     }
   613     dstrect->w = dstrect->h = 0;
   614     return 0;
   615 }
   616 
   617 int
   618 SDL_UpperBlitScaled(SDL_Surface * src, const SDL_Rect * srcrect,
   619               SDL_Surface * dst, SDL_Rect * dstrect)
   620 {
   621     SDL_Rect final_src, final_dst, fulldst;
   622 
   623     /* Make sure the surfaces aren't locked */
   624     if (!src || !dst) {
   625         return SDL_SetError("SDL_UpperBlitScaled: passed a NULL surface");
   626     }
   627     if (src->locked || dst->locked) {
   628         return SDL_SetError("Surfaces must not be locked during blit");
   629     }
   630 
   631     /* If the destination rectangle is NULL, use the entire dest surface */
   632     if (dstrect == NULL) {
   633         fulldst.x = fulldst.y = 0;
   634         fulldst.w = dst->w;
   635         fulldst.h = dst->h;
   636         dstrect = &fulldst;
   637     }
   638 
   639     /* clip the source rectangle to the source surface */
   640     if (srcrect) {
   641         int maxw, maxh;
   642 
   643         final_src.x = srcrect->x;
   644         final_src.w = srcrect->w;
   645         if (final_src.x < 0) {
   646             final_src.w += final_src.x;
   647             final_src.x = 0;
   648         }
   649         maxw = src->w - final_src.x;
   650         if (maxw < final_src.w)
   651             final_src.w = maxw;
   652 
   653         final_src.y = srcrect->y;
   654         final_src.h = srcrect->h;
   655         if (final_src.y < 0) {
   656             final_src.h += final_src.y;
   657             final_src.y = 0;
   658         }
   659         maxh = src->h - final_src.y;
   660         if (maxh < final_src.h)
   661             final_src.h = maxh;
   662 
   663     } else {
   664         final_src.x = final_src.y = 0;
   665         final_src.w = src->w;
   666         final_src.h = src->h;
   667     }
   668 
   669     /* clip the destination rectangle against the clip rectangle */
   670     if (dstrect) {
   671         int maxw, maxh;
   672 
   673         final_dst.x = dstrect->x;
   674         final_dst.w = dstrect->w;
   675         if (final_dst.x < 0) {
   676             final_dst.w += final_dst.x;
   677             final_dst.x = 0;
   678         }
   679         maxw = dst->w - final_dst.x;
   680         if (maxw < final_dst.w)
   681             final_dst.w = maxw;
   682 
   683         final_dst.y = dstrect->y;
   684         final_dst.h = dstrect->h;
   685         if (final_dst.y < 0) {
   686             final_dst.h += final_dst.y;
   687             final_dst.y = 0;
   688         }
   689         maxh = dst->h - final_dst.y;
   690         if (maxh < final_dst.h)
   691             final_dst.h = maxh;
   692     } else {
   693         final_dst.x = final_dst.y = 0;
   694         final_dst.w = dst->w;
   695         final_dst.h = dst->h;
   696     }
   697 
   698     if (final_dst.w > 0 && final_dst.h > 0) {
   699         return SDL_LowerBlitScaled(src, &final_src, dst, &final_dst);
   700     }
   701 
   702     return 0;
   703 }
   704 
   705 /**
   706  *  This is a semi-private blit function and it performs low-level surface
   707  *  scaled blitting only.
   708  */
   709 int
   710 SDL_LowerBlitScaled(SDL_Surface * src, SDL_Rect * srcrect,
   711                 SDL_Surface * dst, SDL_Rect * dstrect)
   712 {
   713     static const Uint32 complex_copy_flags = (
   714         SDL_COPY_MODULATE_COLOR | SDL_COPY_MODULATE_ALPHA |
   715         SDL_COPY_BLEND | SDL_COPY_ADD | SDL_COPY_MOD |
   716         SDL_COPY_COLORKEY
   717     );
   718 
   719     /* Save off the original dst width, height */
   720     int dstW = dstrect->w;
   721     int dstH = dstrect->h;
   722     SDL_Rect full_rect;
   723     SDL_Rect final_dst = *dstrect;
   724     SDL_Rect final_src = *srcrect;
   725 
   726     /* Clip the dst surface to the dstrect */
   727     full_rect.x = 0;
   728     full_rect.y = 0;
   729     full_rect.w = dst->w;
   730     full_rect.h = dst->h;
   731     if (!SDL_IntersectRect(&final_dst, &full_rect, &final_dst)) {
   732         return 0;
   733     }
   734 
   735     /* Did the dst width change? */
   736     if ( dstW != final_dst.w ) {
   737         /* scale the src width appropriately */
   738         final_src.w = final_src.w * dst->clip_rect.w / dstW;
   739     }
   740 
   741     /* Did the dst height change? */
   742     if ( dstH != final_dst.h ) {
   743         /* scale the src width appropriately */
   744         final_src.h = final_src.h * dst->clip_rect.h / dstH;
   745     }
   746 
   747     /* Clip the src surface to the srcrect */
   748     full_rect.x = 0;
   749     full_rect.y = 0;
   750     full_rect.w = src->w;
   751     full_rect.h = src->h;
   752     if (!SDL_IntersectRect(&final_src, &full_rect, &final_src)) {
   753         return 0;
   754     }
   755 
   756     if (!(src->map->info.flags & SDL_COPY_NEAREST)) {
   757         src->map->info.flags |= SDL_COPY_NEAREST;
   758         SDL_InvalidateMap(src->map);
   759     }
   760 
   761     if ( !(src->map->info.flags & complex_copy_flags) &&
   762          src->format->format == dst->format->format &&
   763          !SDL_ISPIXELFORMAT_INDEXED(src->format->format) ) {
   764         return SDL_SoftStretch( src, &final_src, dst, &final_dst );
   765     } else {
   766         return SDL_LowerBlit( src, &final_src, dst, &final_dst );
   767     }
   768 }
   769 
   770 /*
   771  * Lock a surface to directly access the pixels
   772  */
   773 int
   774 SDL_LockSurface(SDL_Surface * surface)
   775 {
   776     if (!surface->locked) {
   777         /* Perform the lock */
   778         if (surface->flags & SDL_RLEACCEL) {
   779             SDL_UnRLESurface(surface, 1);
   780             surface->flags |= SDL_RLEACCEL;     /* save accel'd state */
   781         }
   782     }
   783 
   784     /* Increment the surface lock count, for recursive locks */
   785     ++surface->locked;
   786 
   787     /* Ready to go.. */
   788     return (0);
   789 }
   790 
   791 /*
   792  * Unlock a previously locked surface
   793  */
   794 void
   795 SDL_UnlockSurface(SDL_Surface * surface)
   796 {
   797     /* Only perform an unlock if we are locked */
   798     if (!surface->locked || (--surface->locked > 0)) {
   799         return;
   800     }
   801 
   802     /* Update RLE encoded surface with new data */
   803     if ((surface->flags & SDL_RLEACCEL) == SDL_RLEACCEL) {
   804         surface->flags &= ~SDL_RLEACCEL;        /* stop lying */
   805         SDL_RLESurface(surface);
   806     }
   807 }
   808 
   809 /*
   810  * Convert a surface into the specified pixel format.
   811  */
   812 SDL_Surface *
   813 SDL_ConvertSurface(SDL_Surface * surface, const SDL_PixelFormat * format,
   814                    Uint32 flags)
   815 {
   816     SDL_Surface *convert;
   817     Uint32 copy_flags;
   818     SDL_Color copy_color;
   819     SDL_Rect bounds;
   820 
   821     /* Check for empty destination palette! (results in empty image) */
   822     if (format->palette != NULL) {
   823         int i;
   824         for (i = 0; i < format->palette->ncolors; ++i) {
   825             if ((format->palette->colors[i].r != 0xFF) ||
   826                 (format->palette->colors[i].g != 0xFF) ||
   827                 (format->palette->colors[i].b != 0xFF))
   828                 break;
   829         }
   830         if (i == format->palette->ncolors) {
   831             SDL_SetError("Empty destination palette");
   832             return (NULL);
   833         }
   834     }
   835 
   836     /* Create a new surface with the desired format */
   837     convert = SDL_CreateRGBSurface(flags, surface->w, surface->h,
   838                                    format->BitsPerPixel, format->Rmask,
   839                                    format->Gmask, format->Bmask,
   840                                    format->Amask);
   841     if (convert == NULL) {
   842         return (NULL);
   843     }
   844 
   845     /* Copy the palette if any */
   846     if (format->palette && convert->format->palette) {
   847         SDL_memcpy(convert->format->palette->colors,
   848                    format->palette->colors,
   849                    format->palette->ncolors * sizeof(SDL_Color));
   850         convert->format->palette->ncolors = format->palette->ncolors;
   851     }
   852 
   853     /* Save the original copy flags */
   854     copy_flags = surface->map->info.flags;
   855     copy_color.r = surface->map->info.r;
   856     copy_color.g = surface->map->info.g;
   857     copy_color.b = surface->map->info.b;
   858     copy_color.a = surface->map->info.a;
   859     surface->map->info.r = 0xFF;
   860     surface->map->info.g = 0xFF;
   861     surface->map->info.b = 0xFF;
   862     surface->map->info.a = 0xFF;
   863     surface->map->info.flags = 0;
   864     SDL_InvalidateMap(surface->map);
   865 
   866     /* Copy over the image data */
   867     bounds.x = 0;
   868     bounds.y = 0;
   869     bounds.w = surface->w;
   870     bounds.h = surface->h;
   871     SDL_LowerBlit(surface, &bounds, convert, &bounds);
   872 
   873     /* Clean up the original surface, and update converted surface */
   874     convert->map->info.r = copy_color.r;
   875     convert->map->info.g = copy_color.g;
   876     convert->map->info.b = copy_color.b;
   877     convert->map->info.a = copy_color.a;
   878     convert->map->info.flags =
   879         (copy_flags &
   880          ~(SDL_COPY_COLORKEY | SDL_COPY_BLEND
   881            | SDL_COPY_RLE_DESIRED | SDL_COPY_RLE_COLORKEY |
   882            SDL_COPY_RLE_ALPHAKEY));
   883     surface->map->info.r = copy_color.r;
   884     surface->map->info.g = copy_color.g;
   885     surface->map->info.b = copy_color.b;
   886     surface->map->info.a = copy_color.a;
   887     surface->map->info.flags = copy_flags;
   888     SDL_InvalidateMap(surface->map);
   889     if (copy_flags & SDL_COPY_COLORKEY) {
   890         SDL_bool set_colorkey_by_color = SDL_FALSE;
   891 
   892         if (surface->format->palette) {
   893             if (format->palette &&
   894                 surface->format->palette->ncolors <= format->palette->ncolors &&
   895                 (SDL_memcmp(surface->format->palette->colors, format->palette->colors,
   896                   surface->format->palette->ncolors * sizeof(SDL_Color)) == 0)) {
   897                 /* The palette is identical, just set the same colorkey */
   898                 SDL_SetColorKey(convert, 1, surface->map->info.colorkey);
   899             } else if (format->Amask) {
   900                 /* The alpha was set in the destination from the palette */
   901             } else {
   902                 set_colorkey_by_color = SDL_TRUE;
   903             }
   904         } else {
   905             set_colorkey_by_color = SDL_TRUE;
   906         }
   907 
   908         if (set_colorkey_by_color) {
   909             /* Set the colorkey by color, which needs to be unique */
   910             Uint8 keyR, keyG, keyB, keyA;
   911 
   912             SDL_GetRGBA(surface->map->info.colorkey, surface->format, &keyR,
   913                         &keyG, &keyB, &keyA);
   914             SDL_SetColorKey(convert, 1,
   915                             SDL_MapRGBA(convert->format, keyR, keyG, keyB, keyA));
   916             /* This is needed when converting for 3D texture upload */
   917             SDL_ConvertColorkeyToAlpha(convert);
   918         }
   919     }
   920     SDL_SetClipRect(convert, &surface->clip_rect);
   921 
   922     /* Enable alpha blending by default if the new surface has an
   923      * alpha channel or alpha modulation */
   924     if ((surface->format->Amask && format->Amask) ||
   925         (copy_flags & (SDL_COPY_COLORKEY|SDL_COPY_MODULATE_ALPHA))) {
   926         SDL_SetSurfaceBlendMode(convert, SDL_BLENDMODE_BLEND);
   927     }
   928     if ((copy_flags & SDL_COPY_RLE_DESIRED) || (flags & SDL_RLEACCEL)) {
   929         SDL_SetSurfaceRLE(convert, SDL_RLEACCEL);
   930     }
   931 
   932     /* We're ready to go! */
   933     return (convert);
   934 }
   935 
   936 SDL_Surface *
   937 SDL_ConvertSurfaceFormat(SDL_Surface * surface, Uint32 pixel_format,
   938                          Uint32 flags)
   939 {
   940     SDL_PixelFormat *fmt;
   941     SDL_Surface *convert = NULL;
   942 
   943     fmt = SDL_AllocFormat(pixel_format);
   944     if (fmt) {
   945         convert = SDL_ConvertSurface(surface, fmt, flags);
   946         SDL_FreeFormat(fmt);
   947     }
   948     return convert;
   949 }
   950 
   951 /*
   952  * Create a surface on the stack for quick blit operations
   953  */
   954 static SDL_INLINE SDL_bool
   955 SDL_CreateSurfaceOnStack(int width, int height, Uint32 pixel_format,
   956                          void * pixels, int pitch, SDL_Surface * surface,
   957                          SDL_PixelFormat * format, SDL_BlitMap * blitmap)
   958 {
   959     if (SDL_ISPIXELFORMAT_INDEXED(pixel_format)) {
   960         SDL_SetError("Indexed pixel formats not supported");
   961         return SDL_FALSE;
   962     }
   963     if (SDL_InitFormat(format, pixel_format) < 0) {
   964         return SDL_FALSE;
   965     }
   966 
   967     SDL_zerop(surface);
   968     surface->flags = SDL_PREALLOC;
   969     surface->format = format;
   970     surface->pixels = pixels;
   971     surface->w = width;
   972     surface->h = height;
   973     surface->pitch = pitch;
   974     /* We don't actually need to set up the clip rect for our purposes */
   975     /* SDL_SetClipRect(surface, NULL); */
   976 
   977     /* Allocate an empty mapping */
   978     SDL_zerop(blitmap);
   979     blitmap->info.r = 0xFF;
   980     blitmap->info.g = 0xFF;
   981     blitmap->info.b = 0xFF;
   982     blitmap->info.a = 0xFF;
   983     surface->map = blitmap;
   984 
   985     /* The surface is ready to go */
   986     surface->refcount = 1;
   987     return SDL_TRUE;
   988 }
   989 
   990 /*
   991  * Copy a block of pixels of one format to another format
   992  */
   993 int SDL_ConvertPixels(int width, int height,
   994                       Uint32 src_format, const void * src, int src_pitch,
   995                       Uint32 dst_format, void * dst, int dst_pitch)
   996 {
   997     SDL_Surface src_surface, dst_surface;
   998     SDL_PixelFormat src_fmt, dst_fmt;
   999     SDL_BlitMap src_blitmap, dst_blitmap;
  1000     SDL_Rect rect;
  1001     void *nonconst_src = (void *) src;
  1002 
  1003     /* Check to make sure we are bliting somewhere, so we don't crash */
  1004     if (!dst) {
  1005         return SDL_InvalidParamError("dst");
  1006     }
  1007     if (!dst_pitch) {
  1008         return SDL_InvalidParamError("dst_pitch");
  1009     }
  1010 
  1011     /* Fast path for same format copy */
  1012     if (src_format == dst_format) {
  1013         int bpp;
  1014 
  1015         if (SDL_ISPIXELFORMAT_FOURCC(src_format)) {
  1016             switch (src_format) {
  1017             case SDL_PIXELFORMAT_YV12:
  1018             case SDL_PIXELFORMAT_IYUV:
  1019             case SDL_PIXELFORMAT_YUY2:
  1020             case SDL_PIXELFORMAT_UYVY:
  1021             case SDL_PIXELFORMAT_YVYU:
  1022                 bpp = 2;
  1023                 break;
  1024             default:
  1025                 return SDL_SetError("Unknown FOURCC pixel format");
  1026             }
  1027         } else {
  1028             bpp = SDL_BYTESPERPIXEL(src_format);
  1029         }
  1030         width *= bpp;
  1031 
  1032         while (height-- > 0) {
  1033             SDL_memcpy(dst, src, width);
  1034             src = (Uint8*)src + src_pitch;
  1035             dst = (Uint8*)dst + dst_pitch;
  1036         }
  1037         return 0;
  1038     }
  1039 
  1040     if (!SDL_CreateSurfaceOnStack(width, height, src_format, nonconst_src,
  1041                                   src_pitch,
  1042                                   &src_surface, &src_fmt, &src_blitmap)) {
  1043         return -1;
  1044     }
  1045     if (!SDL_CreateSurfaceOnStack(width, height, dst_format, dst, dst_pitch,
  1046                                   &dst_surface, &dst_fmt, &dst_blitmap)) {
  1047         return -1;
  1048     }
  1049 
  1050     /* Set up the rect and go! */
  1051     rect.x = 0;
  1052     rect.y = 0;
  1053     rect.w = width;
  1054     rect.h = height;
  1055     return SDL_LowerBlit(&src_surface, &rect, &dst_surface, &rect);
  1056 }
  1057 
  1058 /*
  1059  * Free a surface created by the above function.
  1060  */
  1061 void
  1062 SDL_FreeSurface(SDL_Surface * surface)
  1063 {
  1064     if (surface == NULL) {
  1065         return;
  1066     }
  1067     if (surface->flags & SDL_DONTFREE) {
  1068         return;
  1069     }
  1070     if (--surface->refcount > 0) {
  1071         return;
  1072     }
  1073     while (surface->locked > 0) {
  1074         SDL_UnlockSurface(surface);
  1075     }
  1076     if (surface->flags & SDL_RLEACCEL) {
  1077         SDL_UnRLESurface(surface, 0);
  1078     }
  1079     if (surface->format) {
  1080         SDL_SetSurfacePalette(surface, NULL);
  1081         SDL_FreeFormat(surface->format);
  1082         surface->format = NULL;
  1083     }
  1084     if (surface->map != NULL) {
  1085         SDL_FreeBlitMap(surface->map);
  1086         surface->map = NULL;
  1087     }
  1088     if (!(surface->flags & SDL_PREALLOC)) {
  1089         SDL_free(surface->pixels);
  1090     }
  1091     SDL_free(surface);
  1092 }
  1093 
  1094 /* vi: set ts=4 sw=4 expandtab: */