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