src/video/SDL_RLEaccel.c
author Sam Lantinga
Sat, 02 Jan 2016 10:10:34 -0800
changeset 9998 f67cf37e9cd4
parent 9761 fd7fe355f173
child 10000 acd714e378f4
permissions -rw-r--r--
Updated copyright to 2016
     1 /*
     2   Simple DirectMedia Layer
     3   Copyright (C) 1997-2015 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 /*
    24  * RLE encoding for software colorkey and alpha-channel acceleration
    25  *
    26  * Original version by Sam Lantinga
    27  *
    28  * Mattias Engdegård (Yorick): Rewrite. New encoding format, encoder and
    29  * decoder. Added per-surface alpha blitter. Added per-pixel alpha
    30  * format, encoder and blitter.
    31  *
    32  * Many thanks to Xark and johns for hints, benchmarks and useful comments
    33  * leading to this code.
    34  *
    35  * Welcome to Macro Mayhem.
    36  */
    37 
    38 /*
    39  * The encoding translates the image data to a stream of segments of the form
    40  *
    41  * <skip> <run> <data>
    42  *
    43  * where <skip> is the number of transparent pixels to skip,
    44  *       <run>  is the number of opaque pixels to blit,
    45  * and   <data> are the pixels themselves.
    46  *
    47  * This basic structure is used both for colorkeyed surfaces, used for simple
    48  * binary transparency and for per-surface alpha blending, and for surfaces
    49  * with per-pixel alpha. The details differ, however:
    50  *
    51  * Encoding of colorkeyed surfaces:
    52  *
    53  *   Encoded pixels always have the same format as the target surface.
    54  *   <skip> and <run> are unsigned 8 bit integers, except for 32 bit depth
    55  *   where they are 16 bit. This makes the pixel data aligned at all times.
    56  *   Segments never wrap around from one scan line to the next.
    57  *
    58  *   The end of the sequence is marked by a zero <skip>,<run> pair at the *
    59  *   beginning of a line.
    60  *
    61  * Encoding of surfaces with per-pixel alpha:
    62  *
    63  *   The sequence begins with a struct RLEDestFormat describing the target
    64  *   pixel format, to provide reliable un-encoding.
    65  *
    66  *   Each scan line is encoded twice: First all completely opaque pixels,
    67  *   encoded in the target format as described above, and then all
    68  *   partially transparent (translucent) pixels (where 1 <= alpha <= 254),
    69  *   in the following 32-bit format:
    70  *
    71  *   For 32-bit targets, each pixel has the target RGB format but with
    72  *   the alpha value occupying the highest 8 bits. The <skip> and <run>
    73  *   counts are 16 bit.
    74  *
    75  *   For 16-bit targets, each pixel has the target RGB format, but with
    76  *   the middle component (usually green) shifted 16 steps to the left,
    77  *   and the hole filled with the 5 most significant bits of the alpha value.
    78  *   i.e. if the target has the format         rrrrrggggggbbbbb,
    79  *   the encoded pixel will be 00000gggggg00000rrrrr0aaaaabbbbb.
    80  *   The <skip> and <run> counts are 8 bit for the opaque lines, 16 bit
    81  *   for the translucent lines. Two padding bytes may be inserted
    82  *   before each translucent line to keep them 32-bit aligned.
    83  *
    84  *   The end of the sequence is marked by a zero <skip>,<run> pair at the
    85  *   beginning of an opaque line.
    86  */
    87 
    88 #include "SDL_video.h"
    89 #include "SDL_sysvideo.h"
    90 #include "SDL_blit.h"
    91 #include "SDL_RLEaccel_c.h"
    92 
    93 #ifndef MAX
    94 #define MAX(a, b) ((a) > (b) ? (a) : (b))
    95 #endif
    96 #ifndef MIN
    97 #define MIN(a, b) ((a) < (b) ? (a) : (b))
    98 #endif
    99 
   100 #define PIXEL_COPY(to, from, len, bpp)          \
   101     SDL_memcpy(to, from, (size_t)(len) * (bpp))
   102 
   103 /*
   104  * Various colorkey blit methods, for opaque and per-surface alpha
   105  */
   106 
   107 #define OPAQUE_BLIT(to, from, length, bpp, alpha)   \
   108     PIXEL_COPY(to, from, length, bpp)
   109 
   110 /*
   111  * For 32bpp pixels on the form 0x00rrggbb:
   112  * If we treat the middle component separately, we can process the two
   113  * remaining in parallel. This is safe to do because of the gap to the left
   114  * of each component, so the bits from the multiplication don't collide.
   115  * This can be used for any RGB permutation of course.
   116  */
   117 #define ALPHA_BLIT32_888(to, from, length, bpp, alpha)      \
   118     do {                                                    \
   119         int i;                                              \
   120         Uint32 *src = (Uint32 *)(from);                     \
   121         Uint32 *dst = (Uint32 *)(to);                       \
   122         for (i = 0; i < (int)(length); i++) {               \
   123             Uint32 s = *src++;                              \
   124             Uint32 d = *dst;                                \
   125             Uint32 s1 = s & 0xff00ff;                       \
   126             Uint32 d1 = d & 0xff00ff;                       \
   127             d1 = (d1 + ((s1 - d1) * alpha >> 8)) & 0xff00ff; \
   128             s &= 0xff00;                                    \
   129             d &= 0xff00;                                    \
   130             d = (d + ((s - d) * alpha >> 8)) & 0xff00;      \
   131             *dst++ = d1 | d;                                \
   132         }                                                   \
   133     } while (0)
   134 
   135 /*
   136  * For 16bpp pixels we can go a step further: put the middle component
   137  * in the high 16 bits of a 32 bit word, and process all three RGB
   138  * components at the same time. Since the smallest gap is here just
   139  * 5 bits, we have to scale alpha down to 5 bits as well.
   140  */
   141 #define ALPHA_BLIT16_565(to, from, length, bpp, alpha)  \
   142     do {                                                \
   143         int i;                                          \
   144         Uint16 *src = (Uint16 *)(from);                 \
   145         Uint16 *dst = (Uint16 *)(to);                   \
   146         Uint32 ALPHA = alpha >> 3;                      \
   147         for(i = 0; i < (int)(length); i++) {            \
   148             Uint32 s = *src++;                          \
   149             Uint32 d = *dst;                            \
   150             s = (s | s << 16) & 0x07e0f81f;             \
   151             d = (d | d << 16) & 0x07e0f81f;             \
   152             d += (s - d) * ALPHA >> 5;                  \
   153             d &= 0x07e0f81f;                            \
   154             *dst++ = (Uint16)(d | d >> 16);             \
   155         }                                               \
   156     } while(0)
   157 
   158 #define ALPHA_BLIT16_555(to, from, length, bpp, alpha)  \
   159     do {                                                \
   160         int i;                                          \
   161         Uint16 *src = (Uint16 *)(from);                 \
   162         Uint16 *dst = (Uint16 *)(to);                   \
   163         Uint32 ALPHA = alpha >> 3;                      \
   164         for(i = 0; i < (int)(length); i++) {            \
   165             Uint32 s = *src++;                          \
   166             Uint32 d = *dst;                            \
   167             s = (s | s << 16) & 0x03e07c1f;             \
   168             d = (d | d << 16) & 0x03e07c1f;             \
   169             d += (s - d) * ALPHA >> 5;                  \
   170             d &= 0x03e07c1f;                            \
   171             *dst++ = (Uint16)(d | d >> 16);             \
   172         }                                               \
   173     } while(0)
   174 
   175 /*
   176  * The general slow catch-all function, for remaining depths and formats
   177  */
   178 #define ALPHA_BLIT_ANY(to, from, length, bpp, alpha)            \
   179     do {                                                        \
   180         int i;                                                  \
   181         Uint8 *src = from;                                      \
   182         Uint8 *dst = to;                                        \
   183         for (i = 0; i < (int)(length); i++) {                   \
   184             Uint32 s, d;                                        \
   185             unsigned rs, gs, bs, rd, gd, bd;                    \
   186             switch (bpp) {                                      \
   187             case 2:                                             \
   188                 s = *(Uint16 *)src;                             \
   189                 d = *(Uint16 *)dst;                             \
   190                 break;                                          \
   191             case 3:                                             \
   192                 if (SDL_BYTEORDER == SDL_BIG_ENDIAN) {          \
   193                     s = (src[0] << 16) | (src[1] << 8) | src[2]; \
   194                     d = (dst[0] << 16) | (dst[1] << 8) | dst[2]; \
   195                 } else {                                        \
   196                     s = (src[2] << 16) | (src[1] << 8) | src[0]; \
   197                     d = (dst[2] << 16) | (dst[1] << 8) | dst[0]; \
   198                 }                                               \
   199                 break;                                          \
   200             case 4:                                             \
   201                 s = *(Uint32 *)src;                             \
   202                 d = *(Uint32 *)dst;                             \
   203                 break;                                          \
   204             }                                                   \
   205             RGB_FROM_PIXEL(s, fmt, rs, gs, bs);                 \
   206             RGB_FROM_PIXEL(d, fmt, rd, gd, bd);                 \
   207             rd += (rs - rd) * alpha >> 8;                       \
   208             gd += (gs - gd) * alpha >> 8;                       \
   209             bd += (bs - bd) * alpha >> 8;                       \
   210             PIXEL_FROM_RGB(d, fmt, rd, gd, bd);                 \
   211             switch (bpp) {                                      \
   212             case 2:                                             \
   213                 *(Uint16 *)dst = (Uint16)d;                     \
   214                 break;                                          \
   215             case 3:                                             \
   216                 if (SDL_BYTEORDER == SDL_BIG_ENDIAN) {          \
   217                     dst[0] = (Uint8)(d >> 16);                  \
   218                     dst[1] = (Uint8)(d >> 8);                   \
   219                     dst[2] = (Uint8)(d);                        \
   220                 } else {                                        \
   221                     dst[0] = (Uint8)d;                          \
   222                     dst[1] = (Uint8)(d >> 8);                   \
   223                     dst[2] = (Uint8)(d >> 16);                  \
   224                 }                                               \
   225                 break;                                          \
   226             case 4:                                             \
   227                 *(Uint32 *)dst = d;                             \
   228                 break;                                          \
   229             }                                                   \
   230             src += bpp;                                         \
   231             dst += bpp;                                         \
   232         }                                                       \
   233     } while(0)
   234 
   235 /*
   236  * Special case: 50% alpha (alpha=128)
   237  * This is treated specially because it can be optimized very well, and
   238  * since it is good for many cases of semi-translucency.
   239  * The theory is to do all three components at the same time:
   240  * First zero the lowest bit of each component, which gives us room to
   241  * add them. Then shift right and add the sum of the lowest bits.
   242  */
   243 #define ALPHA_BLIT32_888_50(to, from, length, bpp, alpha)       \
   244     do {                                                        \
   245         int i;                                                  \
   246         Uint32 *src = (Uint32 *)(from);                         \
   247         Uint32 *dst = (Uint32 *)(to);                           \
   248         for(i = 0; i < (int)(length); i++) {                    \
   249             Uint32 s = *src++;                                  \
   250             Uint32 d = *dst;                                    \
   251             *dst++ = (((s & 0x00fefefe) + (d & 0x00fefefe)) >> 1) \
   252                  + (s & d & 0x00010101);                        \
   253         }                                                       \
   254     } while(0)
   255 
   256 /*
   257  * For 16bpp, we can actually blend two pixels in parallel, if we take
   258  * care to shift before we add, not after.
   259  */
   260 
   261 /* helper: blend a single 16 bit pixel at 50% */
   262 #define BLEND16_50(dst, src, mask)                              \
   263     do {                                                        \
   264         Uint32 s = *src++;                                      \
   265         Uint32 d = *dst;                                        \
   266         *dst++ = (Uint16)((((s & mask) + (d & mask)) >> 1) +    \
   267                           (s & d & (~mask & 0xffff)));          \
   268     } while(0)
   269 
   270 /* basic 16bpp blender. mask is the pixels to keep when adding. */
   271 #define ALPHA_BLIT16_50(to, from, length, bpp, alpha, mask)     \
   272     do {                                                        \
   273         unsigned n = (length);                                  \
   274         Uint16 *src = (Uint16 *)(from);                         \
   275         Uint16 *dst = (Uint16 *)(to);                           \
   276         if (((uintptr_t)src ^ (uintptr_t)dst) & 3) {            \
   277             /* source and destination not in phase, blit one by one */ \
   278             while (n--)                                         \
   279                 BLEND16_50(dst, src, mask);                     \
   280         } else {                                                \
   281             if ((uintptr_t)src & 3) {                           \
   282                 /* first odd pixel */                           \
   283                 BLEND16_50(dst, src, mask);                     \
   284                 n--;                                            \
   285             }                                                   \
   286             for (; n > 1; n -= 2) {                             \
   287                 Uint32 s = *(Uint32 *)src;                      \
   288                 Uint32 d = *(Uint32 *)dst;                      \
   289                 *(Uint32 *)dst = ((s & (mask | mask << 16)) >> 1) \
   290                     + ((d & (mask | mask << 16)) >> 1)          \
   291                     + (s & d & (~(mask | mask << 16)));         \
   292                 src += 2;                                       \
   293                 dst += 2;                                       \
   294             }                                                   \
   295             if (n)                                              \
   296                 BLEND16_50(dst, src, mask); /* last odd pixel */ \
   297         }                                                       \
   298     } while(0)
   299 
   300 #define ALPHA_BLIT16_565_50(to, from, length, bpp, alpha)       \
   301     ALPHA_BLIT16_50(to, from, length, bpp, alpha, 0xf7de)
   302 
   303 #define ALPHA_BLIT16_555_50(to, from, length, bpp, alpha)       \
   304     ALPHA_BLIT16_50(to, from, length, bpp, alpha, 0xfbde)
   305 
   306 #define CHOOSE_BLIT(blitter, alpha, fmt)                        \
   307     do {                                                        \
   308         if (alpha == 255) {                                     \
   309             switch (fmt->BytesPerPixel) {                       \
   310             case 1: blitter(1, Uint8, OPAQUE_BLIT); break;      \
   311             case 2: blitter(2, Uint8, OPAQUE_BLIT); break;      \
   312             case 3: blitter(3, Uint8, OPAQUE_BLIT); break;      \
   313             case 4: blitter(4, Uint16, OPAQUE_BLIT); break;     \
   314             }                                                   \
   315         } else {                                                \
   316             switch (fmt->BytesPerPixel) {                       \
   317             case 1:                                             \
   318                 /* No 8bpp alpha blitting */                    \
   319                 break;                                          \
   320                                                                 \
   321             case 2:                                             \
   322                 switch (fmt->Rmask | fmt->Gmask | fmt->Bmask) { \
   323                 case 0xffff:                                    \
   324                     if (fmt->Gmask == 0x07e0                    \
   325                         || fmt->Rmask == 0x07e0                 \
   326                         || fmt->Bmask == 0x07e0) {              \
   327                         if (alpha == 128) {                     \
   328                             blitter(2, Uint8, ALPHA_BLIT16_565_50); \
   329                         } else {                                \
   330                             blitter(2, Uint8, ALPHA_BLIT16_565); \
   331                         }                                       \
   332                     } else                                      \
   333                         goto general16;                         \
   334                     break;                                      \
   335                                                                 \
   336                 case 0x7fff:                                    \
   337                     if (fmt->Gmask == 0x03e0                    \
   338                         || fmt->Rmask == 0x03e0                 \
   339                         || fmt->Bmask == 0x03e0) {              \
   340                         if (alpha == 128) {                     \
   341                             blitter(2, Uint8, ALPHA_BLIT16_555_50); \
   342                         } else {                                \
   343                             blitter(2, Uint8, ALPHA_BLIT16_555); \
   344                         }                                       \
   345                         break;                                  \
   346                     } else                                      \
   347                         goto general16;                         \
   348                     break;                                      \
   349                                                                 \
   350                 default:                                        \
   351     general16:                                                  \
   352                     blitter(2, Uint8, ALPHA_BLIT_ANY);          \
   353                 }                                               \
   354                 break;                                          \
   355                                                                 \
   356             case 3:                                             \
   357                 blitter(3, Uint8, ALPHA_BLIT_ANY);              \
   358                 break;                                          \
   359                                                                 \
   360             case 4:                                             \
   361                 if ((fmt->Rmask | fmt->Gmask | fmt->Bmask) == 0x00ffffff \
   362                     && (fmt->Gmask == 0xff00 || fmt->Rmask == 0xff00 \
   363                     || fmt->Bmask == 0xff00)) {                 \
   364                     if (alpha == 128) {                         \
   365                         blitter(4, Uint16, ALPHA_BLIT32_888_50); \
   366                     } else {                                    \
   367                         blitter(4, Uint16, ALPHA_BLIT32_888);   \
   368                     }                                           \
   369                 } else                                          \
   370                     blitter(4, Uint16, ALPHA_BLIT_ANY);         \
   371                 break;                                          \
   372             }                                                   \
   373         }                                                       \
   374     } while(0)
   375 
   376 /*
   377  * Set a pixel value using the given format, except that the alpha value is
   378  * placed in the top byte. This is the format used for RLE with alpha.
   379  */
   380 #define RLEPIXEL_FROM_RGBA(Pixel, fmt, r, g, b, a)                      \
   381 {                                                                       \
   382     Pixel = ((r>>fmt->Rloss)<<fmt->Rshift)|                             \
   383         ((g>>fmt->Gloss)<<fmt->Gshift)|                                 \
   384         ((b>>fmt->Bloss)<<fmt->Bshift)|                                 \
   385         (a<<24);                                                        \
   386 }
   387 
   388 /*
   389  * This takes care of the case when the surface is clipped on the left and/or
   390  * right. Top clipping has already been taken care of.
   391  */
   392 static void
   393 RLEClipBlit(int w, Uint8 * srcbuf, SDL_Surface * surf_dst,
   394             Uint8 * dstbuf, SDL_Rect * srcrect, unsigned alpha)
   395 {
   396     SDL_PixelFormat *fmt = surf_dst->format;
   397 
   398 #define RLECLIPBLIT(bpp, Type, do_blit)                         \
   399     do {                                                        \
   400         int linecount = srcrect->h;                             \
   401         int ofs = 0;                                            \
   402         int left = srcrect->x;                                  \
   403         int right = left + srcrect->w;                          \
   404         dstbuf -= left * bpp;                                   \
   405         for (;;) {                                              \
   406             int run;                                            \
   407             ofs += *(Type *)srcbuf;                             \
   408             run = ((Type *)srcbuf)[1];                          \
   409             srcbuf += 2 * sizeof(Type);                         \
   410             if (run) {                                          \
   411                 /* clip to left and right borders */            \
   412                 if (ofs < right) {                              \
   413                     int start = 0;                              \
   414                     int len = run;                              \
   415                     int startcol;                               \
   416                     if (left - ofs > 0) {                       \
   417                         start = left - ofs;                     \
   418                         len -= start;                           \
   419                         if (len <= 0)                           \
   420                             goto nocopy ## bpp ## do_blit;      \
   421                     }                                           \
   422                     startcol = ofs + start;                     \
   423                     if (len > right - startcol)                 \
   424                         len = right - startcol;                 \
   425                     do_blit(dstbuf + startcol * bpp, srcbuf + start * bpp, \
   426                         len, bpp, alpha);                       \
   427                 }                                               \
   428     nocopy ## bpp ## do_blit:                                   \
   429                 srcbuf += run * bpp;                            \
   430                 ofs += run;                                     \
   431             } else if (!ofs)                                    \
   432                 break;                                          \
   433                                                                 \
   434             if (ofs == w) {                                     \
   435                 ofs = 0;                                        \
   436                 dstbuf += surf_dst->pitch;                      \
   437                 if (!--linecount)                               \
   438                     break;                                      \
   439             }                                                   \
   440         }                                                       \
   441     } while(0)
   442 
   443     CHOOSE_BLIT(RLECLIPBLIT, alpha, fmt);
   444 
   445 #undef RLECLIPBLIT
   446 
   447 }
   448 
   449 
   450 /* blit a colorkeyed RLE surface */
   451 int
   452 SDL_RLEBlit(SDL_Surface * surf_src, SDL_Rect * srcrect,
   453             SDL_Surface * surf_dst, SDL_Rect * dstrect)
   454 {
   455     Uint8 *dstbuf;
   456     Uint8 *srcbuf;
   457     int x, y;
   458     int w = surf_src->w;
   459     unsigned alpha;
   460 
   461     /* Lock the destination if necessary */
   462     if (SDL_MUSTLOCK(surf_dst)) {
   463         if (SDL_LockSurface(surf_dst) < 0) {
   464             return (-1);
   465         }
   466     }
   467 
   468     /* Set up the source and destination pointers */
   469     x = dstrect->x;
   470     y = dstrect->y;
   471     dstbuf = (Uint8 *) surf_dst->pixels
   472         + y * surf_dst->pitch + x * surf_src->format->BytesPerPixel;
   473     srcbuf = (Uint8 *) surf_src->map->data;
   474 
   475     {
   476         /* skip lines at the top if necessary */
   477         int vskip = srcrect->y;
   478         int ofs = 0;
   479         if (vskip) {
   480 
   481 #define RLESKIP(bpp, Type)          \
   482         for(;;) {           \
   483             int run;            \
   484             ofs += *(Type *)srcbuf; \
   485             run = ((Type *)srcbuf)[1];  \
   486             srcbuf += sizeof(Type) * 2; \
   487             if(run) {           \
   488             srcbuf += run * bpp;    \
   489             ofs += run;     \
   490             } else if(!ofs)     \
   491             goto done;      \
   492             if(ofs == w) {      \
   493             ofs = 0;        \
   494             if(!--vskip)        \
   495                 break;      \
   496             }               \
   497         }
   498 
   499             switch (surf_src->format->BytesPerPixel) {
   500             case 1:
   501                 RLESKIP(1, Uint8);
   502                 break;
   503             case 2:
   504                 RLESKIP(2, Uint8);
   505                 break;
   506             case 3:
   507                 RLESKIP(3, Uint8);
   508                 break;
   509             case 4:
   510                 RLESKIP(4, Uint16);
   511                 break;
   512             }
   513 
   514 #undef RLESKIP
   515 
   516         }
   517     }
   518 
   519     alpha = surf_src->map->info.a;
   520     /* if left or right edge clipping needed, call clip blit */
   521     if (srcrect->x || srcrect->w != surf_src->w) {
   522         RLEClipBlit(w, srcbuf, surf_dst, dstbuf, srcrect, alpha);
   523     } else {
   524         SDL_PixelFormat *fmt = surf_src->format;
   525 
   526 #define RLEBLIT(bpp, Type, do_blit)                       \
   527         do {                                  \
   528         int linecount = srcrect->h;                   \
   529         int ofs = 0;                              \
   530         for(;;) {                             \
   531             unsigned run;                         \
   532             ofs += *(Type *)srcbuf;                   \
   533             run = ((Type *)srcbuf)[1];                    \
   534             srcbuf += 2 * sizeof(Type);                   \
   535             if(run) {                             \
   536             do_blit(dstbuf + ofs * bpp, srcbuf, run, bpp, alpha); \
   537             srcbuf += run * bpp;                      \
   538             ofs += run;                       \
   539             } else if(!ofs)                       \
   540             break;                            \
   541             if(ofs == w) {                        \
   542             ofs = 0;                          \
   543             dstbuf += surf_dst->pitch;                     \
   544             if(!--linecount)                      \
   545                 break;                        \
   546             }                                 \
   547         }                                 \
   548         } while(0)
   549 
   550         CHOOSE_BLIT(RLEBLIT, alpha, fmt);
   551 
   552 #undef RLEBLIT
   553     }
   554 
   555   done:
   556     /* Unlock the destination if necessary */
   557     if (SDL_MUSTLOCK(surf_dst)) {
   558         SDL_UnlockSurface(surf_dst);
   559     }
   560     return (0);
   561 }
   562 
   563 #undef OPAQUE_BLIT
   564 
   565 /*
   566  * Per-pixel blitting macros for translucent pixels:
   567  * These use the same techniques as the per-surface blitting macros
   568  */
   569 
   570 /*
   571  * For 32bpp pixels, we have made sure the alpha is stored in the top
   572  * 8 bits, so proceed as usual
   573  */
   574 #define BLIT_TRANSL_888(src, dst)               \
   575     do {                            \
   576         Uint32 s = src;                     \
   577     Uint32 d = dst;                     \
   578     unsigned alpha = s >> 24;               \
   579     Uint32 s1 = s & 0xff00ff;               \
   580     Uint32 d1 = d & 0xff00ff;               \
   581     d1 = (d1 + ((s1 - d1) * alpha >> 8)) & 0xff00ff;    \
   582     s &= 0xff00;                        \
   583     d &= 0xff00;                        \
   584     d = (d + ((s - d) * alpha >> 8)) & 0xff00;      \
   585     dst = d1 | d | 0xff000000;              \
   586     } while(0)
   587 
   588 /*
   589  * For 16bpp pixels, we have stored the 5 most significant alpha bits in
   590  * bits 5-10. As before, we can process all 3 RGB components at the same time.
   591  */
   592 #define BLIT_TRANSL_565(src, dst)       \
   593     do {                    \
   594     Uint32 s = src;             \
   595     Uint32 d = dst;             \
   596     unsigned alpha = (s & 0x3e0) >> 5;  \
   597     s &= 0x07e0f81f;            \
   598     d = (d | d << 16) & 0x07e0f81f;     \
   599     d += (s - d) * alpha >> 5;      \
   600     d &= 0x07e0f81f;            \
   601     dst = (Uint16)(d | d >> 16);            \
   602     } while(0)
   603 
   604 #define BLIT_TRANSL_555(src, dst)       \
   605     do {                    \
   606     Uint32 s = src;             \
   607     Uint32 d = dst;             \
   608     unsigned alpha = (s & 0x3e0) >> 5;  \
   609     s &= 0x03e07c1f;            \
   610     d = (d | d << 16) & 0x03e07c1f;     \
   611     d += (s - d) * alpha >> 5;      \
   612     d &= 0x03e07c1f;            \
   613     dst = (Uint16)(d | d >> 16);            \
   614     } while(0)
   615 
   616 /* used to save the destination format in the encoding. Designed to be
   617    macro-compatible with SDL_PixelFormat but without the unneeded fields */
   618 typedef struct
   619 {
   620     Uint8 BytesPerPixel;
   621     Uint8 padding[3];
   622     Uint32 Rmask;
   623     Uint32 Gmask;
   624     Uint32 Bmask;
   625     Uint32 Amask;
   626     Uint8 Rloss;
   627     Uint8 Gloss;
   628     Uint8 Bloss;
   629     Uint8 Aloss;
   630     Uint8 Rshift;
   631     Uint8 Gshift;
   632     Uint8 Bshift;
   633     Uint8 Ashift;
   634 } RLEDestFormat;
   635 
   636 /* blit a pixel-alpha RLE surface clipped at the right and/or left edges */
   637 static void
   638 RLEAlphaClipBlit(int w, Uint8 * srcbuf, SDL_Surface * surf_dst,
   639                  Uint8 * dstbuf, SDL_Rect * srcrect)
   640 {
   641     SDL_PixelFormat *df = surf_dst->format;
   642     /*
   643      * clipped blitter: Ptype is the destination pixel type,
   644      * Ctype the translucent count type, and do_blend the macro
   645      * to blend one pixel.
   646      */
   647 #define RLEALPHACLIPBLIT(Ptype, Ctype, do_blend)              \
   648     do {                                  \
   649     int linecount = srcrect->h;                   \
   650     int left = srcrect->x;                        \
   651     int right = left + srcrect->w;                    \
   652     dstbuf -= left * sizeof(Ptype);                   \
   653     do {                                  \
   654         int ofs = 0;                          \
   655         /* blit opaque pixels on one line */              \
   656         do {                              \
   657         unsigned run;                         \
   658         ofs += ((Ctype *)srcbuf)[0];                  \
   659         run = ((Ctype *)srcbuf)[1];               \
   660         srcbuf += 2 * sizeof(Ctype);                  \
   661         if(run) {                         \
   662             /* clip to left and right borders */          \
   663             int cofs = ofs;                   \
   664             int crun = run;                   \
   665             if(left - cofs > 0) {                 \
   666             crun -= left - cofs;                  \
   667             cofs = left;                      \
   668             }                             \
   669             if(crun > right - cofs)               \
   670             crun = right - cofs;                  \
   671             if(crun > 0)                      \
   672             PIXEL_COPY(dstbuf + cofs * sizeof(Ptype),     \
   673                    srcbuf + (cofs - ofs) * sizeof(Ptype), \
   674                    (unsigned)crun, sizeof(Ptype));    \
   675             srcbuf += run * sizeof(Ptype);            \
   676             ofs += run;                       \
   677         } else if(!ofs)                       \
   678             return;                       \
   679         } while(ofs < w);                         \
   680         /* skip padding if necessary */               \
   681         if(sizeof(Ptype) == 2)                    \
   682         srcbuf += (uintptr_t)srcbuf & 2;              \
   683         /* blit translucent pixels on the same line */        \
   684         ofs = 0;                              \
   685         do {                              \
   686         unsigned run;                         \
   687         ofs += ((Uint16 *)srcbuf)[0];                 \
   688         run = ((Uint16 *)srcbuf)[1];                  \
   689         srcbuf += 4;                          \
   690         if(run) {                         \
   691             /* clip to left and right borders */          \
   692             int cofs = ofs;                   \
   693             int crun = run;                   \
   694             if(left - cofs > 0) {                 \
   695             crun -= left - cofs;                  \
   696             cofs = left;                      \
   697             }                             \
   698             if(crun > right - cofs)               \
   699             crun = right - cofs;                  \
   700             if(crun > 0) {                    \
   701             Ptype *dst = (Ptype *)dstbuf + cofs;          \
   702             Uint32 *src = (Uint32 *)srcbuf + (cofs - ofs);    \
   703             int i;                        \
   704             for(i = 0; i < crun; i++)             \
   705                 do_blend(src[i], dst[i]);             \
   706             }                             \
   707             srcbuf += run * 4;                    \
   708             ofs += run;                       \
   709         }                             \
   710         } while(ofs < w);                         \
   711         dstbuf += surf_dst->pitch;                     \
   712     } while(--linecount);                         \
   713     } while(0)
   714 
   715     switch (df->BytesPerPixel) {
   716     case 2:
   717         if (df->Gmask == 0x07e0 || df->Rmask == 0x07e0 || df->Bmask == 0x07e0)
   718             RLEALPHACLIPBLIT(Uint16, Uint8, BLIT_TRANSL_565);
   719         else
   720             RLEALPHACLIPBLIT(Uint16, Uint8, BLIT_TRANSL_555);
   721         break;
   722     case 4:
   723         RLEALPHACLIPBLIT(Uint32, Uint16, BLIT_TRANSL_888);
   724         break;
   725     }
   726 }
   727 
   728 /* blit a pixel-alpha RLE surface */
   729 int
   730 SDL_RLEAlphaBlit(SDL_Surface * surf_src, SDL_Rect * srcrect,
   731                  SDL_Surface * surf_dst, SDL_Rect * dstrect)
   732 {
   733     int x, y;
   734     int w = surf_src->w;
   735     Uint8 *srcbuf, *dstbuf;
   736     SDL_PixelFormat *df = surf_dst->format;
   737 
   738     /* Lock the destination if necessary */
   739     if (SDL_MUSTLOCK(surf_dst)) {
   740         if (SDL_LockSurface(surf_dst) < 0) {
   741             return -1;
   742         }
   743     }
   744 
   745     x = dstrect->x;
   746     y = dstrect->y;
   747     dstbuf = (Uint8 *) surf_dst->pixels + y * surf_dst->pitch + x * df->BytesPerPixel;
   748     srcbuf = (Uint8 *) surf_src->map->data + sizeof(RLEDestFormat);
   749 
   750     {
   751         /* skip lines at the top if necessary */
   752         int vskip = srcrect->y;
   753         if (vskip) {
   754             int ofs;
   755             if (df->BytesPerPixel == 2) {
   756                 /* the 16/32 interleaved format */
   757                 do {
   758                     /* skip opaque line */
   759                     ofs = 0;
   760                     do {
   761                         int run;
   762                         ofs += srcbuf[0];
   763                         run = srcbuf[1];
   764                         srcbuf += 2;
   765                         if (run) {
   766                             srcbuf += 2 * run;
   767                             ofs += run;
   768                         } else if (!ofs)
   769                             goto done;
   770                     } while (ofs < w);
   771 
   772                     /* skip padding */
   773                     srcbuf += (uintptr_t) srcbuf & 2;
   774 
   775                     /* skip translucent line */
   776                     ofs = 0;
   777                     do {
   778                         int run;
   779                         ofs += ((Uint16 *) srcbuf)[0];
   780                         run = ((Uint16 *) srcbuf)[1];
   781                         srcbuf += 4 * (run + 1);
   782                         ofs += run;
   783                     } while (ofs < w);
   784                 } while (--vskip);
   785             } else {
   786                 /* the 32/32 interleaved format */
   787                 vskip <<= 1;    /* opaque and translucent have same format */
   788                 do {
   789                     ofs = 0;
   790                     do {
   791                         int run;
   792                         ofs += ((Uint16 *) srcbuf)[0];
   793                         run = ((Uint16 *) srcbuf)[1];
   794                         srcbuf += 4;
   795                         if (run) {
   796                             srcbuf += 4 * run;
   797                             ofs += run;
   798                         } else if (!ofs)
   799                             goto done;
   800                     } while (ofs < w);
   801                 } while (--vskip);
   802             }
   803         }
   804     }
   805 
   806     /* if left or right edge clipping needed, call clip blit */
   807     if (srcrect->x || srcrect->w != surf_src->w) {
   808         RLEAlphaClipBlit(w, srcbuf, surf_dst, dstbuf, srcrect);
   809     } else {
   810 
   811         /*
   812          * non-clipped blitter. Ptype is the destination pixel type,
   813          * Ctype the translucent count type, and do_blend the
   814          * macro to blend one pixel.
   815          */
   816 #define RLEALPHABLIT(Ptype, Ctype, do_blend)                 \
   817     do {                                 \
   818         int linecount = srcrect->h;                  \
   819         do {                             \
   820         int ofs = 0;                         \
   821         /* blit opaque pixels on one line */             \
   822         do {                             \
   823             unsigned run;                    \
   824             ofs += ((Ctype *)srcbuf)[0];             \
   825             run = ((Ctype *)srcbuf)[1];              \
   826             srcbuf += 2 * sizeof(Ctype);             \
   827             if(run) {                        \
   828             PIXEL_COPY(dstbuf + ofs * sizeof(Ptype), srcbuf, \
   829                    run, sizeof(Ptype));          \
   830             srcbuf += run * sizeof(Ptype);           \
   831             ofs += run;                  \
   832             } else if(!ofs)                  \
   833             goto done;                   \
   834         } while(ofs < w);                    \
   835         /* skip padding if necessary */              \
   836         if(sizeof(Ptype) == 2)                   \
   837             srcbuf += (uintptr_t)srcbuf & 2;             \
   838         /* blit translucent pixels on the same line */       \
   839         ofs = 0;                         \
   840         do {                             \
   841             unsigned run;                    \
   842             ofs += ((Uint16 *)srcbuf)[0];            \
   843             run = ((Uint16 *)srcbuf)[1];             \
   844             srcbuf += 4;                     \
   845             if(run) {                        \
   846             Ptype *dst = (Ptype *)dstbuf + ofs;      \
   847             unsigned i;                  \
   848             for(i = 0; i < run; i++) {           \
   849                 Uint32 src = *(Uint32 *)srcbuf;      \
   850                 do_blend(src, *dst);             \
   851                 srcbuf += 4;                 \
   852                 dst++;                   \
   853             }                        \
   854             ofs += run;                  \
   855             }                            \
   856         } while(ofs < w);                    \
   857         dstbuf += surf_dst->pitch;                    \
   858         } while(--linecount);                    \
   859     } while(0)
   860 
   861         switch (df->BytesPerPixel) {
   862         case 2:
   863             if (df->Gmask == 0x07e0 || df->Rmask == 0x07e0
   864                 || df->Bmask == 0x07e0)
   865                 RLEALPHABLIT(Uint16, Uint8, BLIT_TRANSL_565);
   866             else
   867                 RLEALPHABLIT(Uint16, Uint8, BLIT_TRANSL_555);
   868             break;
   869         case 4:
   870             RLEALPHABLIT(Uint32, Uint16, BLIT_TRANSL_888);
   871             break;
   872         }
   873     }
   874 
   875   done:
   876     /* Unlock the destination if necessary */
   877     if (SDL_MUSTLOCK(surf_dst)) {
   878         SDL_UnlockSurface(surf_dst);
   879     }
   880     return 0;
   881 }
   882 
   883 /*
   884  * Auxiliary functions:
   885  * The encoding functions take 32bpp rgb + a, and
   886  * return the number of bytes copied to the destination.
   887  * The decoding functions copy to 32bpp rgb + a, and
   888  * return the number of bytes copied from the source.
   889  * These are only used in the encoder and un-RLE code and are therefore not
   890  * highly optimised.
   891  */
   892 
   893 /* encode 32bpp rgb + a into 16bpp rgb, losing alpha */
   894 static int
   895 copy_opaque_16(void *dst, Uint32 * src, int n,
   896                SDL_PixelFormat * sfmt, SDL_PixelFormat * dfmt)
   897 {
   898     int i;
   899     Uint16 *d = dst;
   900     for (i = 0; i < n; i++) {
   901         unsigned r, g, b;
   902         RGB_FROM_PIXEL(*src, sfmt, r, g, b);
   903         PIXEL_FROM_RGB(*d, dfmt, r, g, b);
   904         src++;
   905         d++;
   906     }
   907     return n * 2;
   908 }
   909 
   910 /* decode opaque pixels from 16bpp to 32bpp rgb + a */
   911 static int
   912 uncopy_opaque_16(Uint32 * dst, void *src, int n,
   913                  RLEDestFormat * sfmt, SDL_PixelFormat * dfmt)
   914 {
   915     int i;
   916     Uint16 *s = src;
   917     unsigned alpha = dfmt->Amask ? 255 : 0;
   918     for (i = 0; i < n; i++) {
   919         unsigned r, g, b;
   920         RGB_FROM_PIXEL(*s, sfmt, r, g, b);
   921         PIXEL_FROM_RGBA(*dst, dfmt, r, g, b, alpha);
   922         s++;
   923         dst++;
   924     }
   925     return n * 2;
   926 }
   927 
   928 
   929 
   930 /* encode 32bpp rgb + a into 32bpp G0RAB format for blitting into 565 */
   931 static int
   932 copy_transl_565(void *dst, Uint32 * src, int n,
   933                 SDL_PixelFormat * sfmt, SDL_PixelFormat * dfmt)
   934 {
   935     int i;
   936     Uint32 *d = dst;
   937     for (i = 0; i < n; i++) {
   938         unsigned r, g, b, a;
   939         Uint16 pix;
   940         RGBA_FROM_8888(*src, sfmt, r, g, b, a);
   941         PIXEL_FROM_RGB(pix, dfmt, r, g, b);
   942         *d = ((pix & 0x7e0) << 16) | (pix & 0xf81f) | ((a << 2) & 0x7e0);
   943         src++;
   944         d++;
   945     }
   946     return n * 4;
   947 }
   948 
   949 /* encode 32bpp rgb + a into 32bpp G0RAB format for blitting into 555 */
   950 static int
   951 copy_transl_555(void *dst, Uint32 * src, int n,
   952                 SDL_PixelFormat * sfmt, SDL_PixelFormat * dfmt)
   953 {
   954     int i;
   955     Uint32 *d = dst;
   956     for (i = 0; i < n; i++) {
   957         unsigned r, g, b, a;
   958         Uint16 pix;
   959         RGBA_FROM_8888(*src, sfmt, r, g, b, a);
   960         PIXEL_FROM_RGB(pix, dfmt, r, g, b);
   961         *d = ((pix & 0x3e0) << 16) | (pix & 0xfc1f) | ((a << 2) & 0x3e0);
   962         src++;
   963         d++;
   964     }
   965     return n * 4;
   966 }
   967 
   968 /* decode translucent pixels from 32bpp GORAB to 32bpp rgb + a */
   969 static int
   970 uncopy_transl_16(Uint32 * dst, void *src, int n,
   971                  RLEDestFormat * sfmt, SDL_PixelFormat * dfmt)
   972 {
   973     int i;
   974     Uint32 *s = src;
   975     for (i = 0; i < n; i++) {
   976         unsigned r, g, b, a;
   977         Uint32 pix = *s++;
   978         a = (pix & 0x3e0) >> 2;
   979         pix = (pix & ~0x3e0) | pix >> 16;
   980         RGB_FROM_PIXEL(pix, sfmt, r, g, b);
   981         PIXEL_FROM_RGBA(*dst, dfmt, r, g, b, a);
   982         dst++;
   983     }
   984     return n * 4;
   985 }
   986 
   987 /* encode 32bpp rgba into 32bpp rgba, keeping alpha (dual purpose) */
   988 static int
   989 copy_32(void *dst, Uint32 * src, int n,
   990         SDL_PixelFormat * sfmt, SDL_PixelFormat * dfmt)
   991 {
   992     int i;
   993     Uint32 *d = dst;
   994     for (i = 0; i < n; i++) {
   995         unsigned r, g, b, a;
   996         RGBA_FROM_8888(*src, sfmt, r, g, b, a);
   997         RLEPIXEL_FROM_RGBA(*d, dfmt, r, g, b, a);
   998         d++;
   999         src++;
  1000     }
  1001     return n * 4;
  1002 }
  1003 
  1004 /* decode 32bpp rgba into 32bpp rgba, keeping alpha (dual purpose) */
  1005 static int
  1006 uncopy_32(Uint32 * dst, void *src, int n,
  1007           RLEDestFormat * sfmt, SDL_PixelFormat * dfmt)
  1008 {
  1009     int i;
  1010     Uint32 *s = src;
  1011     for (i = 0; i < n; i++) {
  1012         unsigned r, g, b, a;
  1013         Uint32 pixel = *s++;
  1014         RGB_FROM_PIXEL(pixel, sfmt, r, g, b);
  1015         a = pixel >> 24;
  1016         PIXEL_FROM_RGBA(*dst, dfmt, r, g, b, a);
  1017         dst++;
  1018     }
  1019     return n * 4;
  1020 }
  1021 
  1022 #define ISOPAQUE(pixel, fmt) ((((pixel) & fmt->Amask) >> fmt->Ashift) == 255)
  1023 
  1024 #define ISTRANSL(pixel, fmt)    \
  1025     ((unsigned)((((pixel) & fmt->Amask) >> fmt->Ashift) - 1U) < 254U)
  1026 
  1027 /* convert surface to be quickly alpha-blittable onto dest, if possible */
  1028 static int
  1029 RLEAlphaSurface(SDL_Surface * surface)
  1030 {
  1031     SDL_Surface *dest;
  1032     SDL_PixelFormat *df;
  1033     int maxsize = 0;
  1034     int max_opaque_run;
  1035     int max_transl_run = 65535;
  1036     unsigned masksum;
  1037     Uint8 *rlebuf, *dst;
  1038     int (*copy_opaque) (void *, Uint32 *, int,
  1039                         SDL_PixelFormat *, SDL_PixelFormat *);
  1040     int (*copy_transl) (void *, Uint32 *, int,
  1041                         SDL_PixelFormat *, SDL_PixelFormat *);
  1042 
  1043     dest = surface->map->dst;
  1044     if (!dest)
  1045         return -1;
  1046     df = dest->format;
  1047     if (surface->format->BitsPerPixel != 32)
  1048         return -1;              /* only 32bpp source supported */
  1049 
  1050     /* find out whether the destination is one we support,
  1051        and determine the max size of the encoded result */
  1052     masksum = df->Rmask | df->Gmask | df->Bmask;
  1053     switch (df->BytesPerPixel) {
  1054     case 2:
  1055         /* 16bpp: only support 565 and 555 formats */
  1056         switch (masksum) {
  1057         case 0xffff:
  1058             if (df->Gmask == 0x07e0
  1059                 || df->Rmask == 0x07e0 || df->Bmask == 0x07e0) {
  1060                 copy_opaque = copy_opaque_16;
  1061                 copy_transl = copy_transl_565;
  1062             } else
  1063                 return -1;
  1064             break;
  1065         case 0x7fff:
  1066             if (df->Gmask == 0x03e0
  1067                 || df->Rmask == 0x03e0 || df->Bmask == 0x03e0) {
  1068                 copy_opaque = copy_opaque_16;
  1069                 copy_transl = copy_transl_555;
  1070             } else
  1071                 return -1;
  1072             break;
  1073         default:
  1074             return -1;
  1075         }
  1076         max_opaque_run = 255;   /* runs stored as bytes */
  1077 
  1078         /* worst case is alternating opaque and translucent pixels,
  1079            with room for alignment padding between lines */
  1080         maxsize = surface->h * (2 + (4 + 2) * (surface->w + 1)) + 2;
  1081         break;
  1082     case 4:
  1083         if (masksum != 0x00ffffff)
  1084             return -1;          /* requires unused high byte */
  1085         copy_opaque = copy_32;
  1086         copy_transl = copy_32;
  1087         max_opaque_run = 255;   /* runs stored as short ints */
  1088 
  1089         /* worst case is alternating opaque and translucent pixels */
  1090         maxsize = surface->h * 2 * 4 * (surface->w + 1) + 4;
  1091         break;
  1092     default:
  1093         return -1;              /* anything else unsupported right now */
  1094     }
  1095 
  1096     maxsize += sizeof(RLEDestFormat);
  1097     rlebuf = (Uint8 *) SDL_malloc(maxsize);
  1098     if (!rlebuf) {
  1099         return SDL_OutOfMemory();
  1100     }
  1101     {
  1102         /* save the destination format so we can undo the encoding later */
  1103         RLEDestFormat *r = (RLEDestFormat *) rlebuf;
  1104         r->BytesPerPixel = df->BytesPerPixel;
  1105         r->Rmask = df->Rmask;
  1106         r->Gmask = df->Gmask;
  1107         r->Bmask = df->Bmask;
  1108         r->Amask = df->Amask;
  1109         r->Rloss = df->Rloss;
  1110         r->Gloss = df->Gloss;
  1111         r->Bloss = df->Bloss;
  1112         r->Aloss = df->Aloss;
  1113         r->Rshift = df->Rshift;
  1114         r->Gshift = df->Gshift;
  1115         r->Bshift = df->Bshift;
  1116         r->Ashift = df->Ashift;
  1117     }
  1118     dst = rlebuf + sizeof(RLEDestFormat);
  1119 
  1120     /* Do the actual encoding */
  1121     {
  1122         int x, y;
  1123         int h = surface->h, w = surface->w;
  1124         SDL_PixelFormat *sf = surface->format;
  1125         Uint32 *src = (Uint32 *) surface->pixels;
  1126         Uint8 *lastline = dst;  /* end of last non-blank line */
  1127 
  1128         /* opaque counts are 8 or 16 bits, depending on target depth */
  1129 #define ADD_OPAQUE_COUNTS(n, m)         \
  1130     if(df->BytesPerPixel == 4) {        \
  1131         ((Uint16 *)dst)[0] = n;     \
  1132         ((Uint16 *)dst)[1] = m;     \
  1133         dst += 4;               \
  1134     } else {                \
  1135         dst[0] = n;             \
  1136         dst[1] = m;             \
  1137         dst += 2;               \
  1138     }
  1139 
  1140         /* translucent counts are always 16 bit */
  1141 #define ADD_TRANSL_COUNTS(n, m)     \
  1142     (((Uint16 *)dst)[0] = n, ((Uint16 *)dst)[1] = m, dst += 4)
  1143 
  1144         for (y = 0; y < h; y++) {
  1145             int runstart, skipstart;
  1146             int blankline = 0;
  1147             /* First encode all opaque pixels of a scan line */
  1148             x = 0;
  1149             do {
  1150                 int run, skip, len;
  1151                 skipstart = x;
  1152                 while (x < w && !ISOPAQUE(src[x], sf))
  1153                     x++;
  1154                 runstart = x;
  1155                 while (x < w && ISOPAQUE(src[x], sf))
  1156                     x++;
  1157                 skip = runstart - skipstart;
  1158                 if (skip == w)
  1159                     blankline = 1;
  1160                 run = x - runstart;
  1161                 while (skip > max_opaque_run) {
  1162                     ADD_OPAQUE_COUNTS(max_opaque_run, 0);
  1163                     skip -= max_opaque_run;
  1164                 }
  1165                 len = MIN(run, max_opaque_run);
  1166                 ADD_OPAQUE_COUNTS(skip, len);
  1167                 dst += copy_opaque(dst, src + runstart, len, sf, df);
  1168                 runstart += len;
  1169                 run -= len;
  1170                 while (run) {
  1171                     len = MIN(run, max_opaque_run);
  1172                     ADD_OPAQUE_COUNTS(0, len);
  1173                     dst += copy_opaque(dst, src + runstart, len, sf, df);
  1174                     runstart += len;
  1175                     run -= len;
  1176                 }
  1177             } while (x < w);
  1178 
  1179             /* Make sure the next output address is 32-bit aligned */
  1180             dst += (uintptr_t) dst & 2;
  1181 
  1182             /* Next, encode all translucent pixels of the same scan line */
  1183             x = 0;
  1184             do {
  1185                 int run, skip, len;
  1186                 skipstart = x;
  1187                 while (x < w && !ISTRANSL(src[x], sf))
  1188                     x++;
  1189                 runstart = x;
  1190                 while (x < w && ISTRANSL(src[x], sf))
  1191                     x++;
  1192                 skip = runstart - skipstart;
  1193                 blankline &= (skip == w);
  1194                 run = x - runstart;
  1195                 while (skip > max_transl_run) {
  1196                     ADD_TRANSL_COUNTS(max_transl_run, 0);
  1197                     skip -= max_transl_run;
  1198                 }
  1199                 len = MIN(run, max_transl_run);
  1200                 ADD_TRANSL_COUNTS(skip, len);
  1201                 dst += copy_transl(dst, src + runstart, len, sf, df);
  1202                 runstart += len;
  1203                 run -= len;
  1204                 while (run) {
  1205                     len = MIN(run, max_transl_run);
  1206                     ADD_TRANSL_COUNTS(0, len);
  1207                     dst += copy_transl(dst, src + runstart, len, sf, df);
  1208                     runstart += len;
  1209                     run -= len;
  1210                 }
  1211                 if (!blankline)
  1212                     lastline = dst;
  1213             } while (x < w);
  1214 
  1215             src += surface->pitch >> 2;
  1216         }
  1217         dst = lastline;         /* back up past trailing blank lines */
  1218         ADD_OPAQUE_COUNTS(0, 0);
  1219     }
  1220 
  1221 #undef ADD_OPAQUE_COUNTS
  1222 #undef ADD_TRANSL_COUNTS
  1223 
  1224     /* Now that we have it encoded, release the original pixels */
  1225     if (!(surface->flags & SDL_PREALLOC)) {
  1226         SDL_free(surface->pixels);
  1227         surface->pixels = NULL;
  1228     }
  1229 
  1230     /* realloc the buffer to release unused memory */
  1231     {
  1232         Uint8 *p = SDL_realloc(rlebuf, dst - rlebuf);
  1233         if (!p)
  1234             p = rlebuf;
  1235         surface->map->data = p;
  1236     }
  1237 
  1238     return 0;
  1239 }
  1240 
  1241 static Uint32
  1242 getpix_8(Uint8 * srcbuf)
  1243 {
  1244     return *srcbuf;
  1245 }
  1246 
  1247 static Uint32
  1248 getpix_16(Uint8 * srcbuf)
  1249 {
  1250     return *(Uint16 *) srcbuf;
  1251 }
  1252 
  1253 static Uint32
  1254 getpix_24(Uint8 * srcbuf)
  1255 {
  1256 #if SDL_BYTEORDER == SDL_LIL_ENDIAN
  1257     return srcbuf[0] + (srcbuf[1] << 8) + (srcbuf[2] << 16);
  1258 #else
  1259     return (srcbuf[0] << 16) + (srcbuf[1] << 8) + srcbuf[2];
  1260 #endif
  1261 }
  1262 
  1263 static Uint32
  1264 getpix_32(Uint8 * srcbuf)
  1265 {
  1266     return *(Uint32 *) srcbuf;
  1267 }
  1268 
  1269 typedef Uint32(*getpix_func) (Uint8 *);
  1270 
  1271 static const getpix_func getpixes[4] = {
  1272     getpix_8, getpix_16, getpix_24, getpix_32
  1273 };
  1274 
  1275 static int
  1276 RLEColorkeySurface(SDL_Surface * surface)
  1277 {
  1278     Uint8 *rlebuf, *dst;
  1279     int maxn;
  1280     int y;
  1281     Uint8 *srcbuf, *lastline;
  1282     int maxsize = 0;
  1283     int bpp = surface->format->BytesPerPixel;
  1284     getpix_func getpix;
  1285     Uint32 ckey, rgbmask;
  1286     int w, h;
  1287 
  1288     /* calculate the worst case size for the compressed surface */
  1289     switch (bpp) {
  1290     case 1:
  1291         /* worst case is alternating opaque and transparent pixels,
  1292            starting with an opaque pixel */
  1293         maxsize = surface->h * 3 * (surface->w / 2 + 1) + 2;
  1294         break;
  1295     case 2:
  1296     case 3:
  1297         /* worst case is solid runs, at most 255 pixels wide */
  1298         maxsize = surface->h * (2 * (surface->w / 255 + 1)
  1299                                 + surface->w * bpp) + 2;
  1300         break;
  1301     case 4:
  1302         /* worst case is solid runs, at most 65535 pixels wide */
  1303         maxsize = surface->h * (4 * (surface->w / 65535 + 1)
  1304                                 + surface->w * 4) + 4;
  1305         break;
  1306     }
  1307 
  1308     rlebuf = (Uint8 *) SDL_malloc(maxsize);
  1309     if (rlebuf == NULL) {
  1310         return SDL_OutOfMemory();
  1311     }
  1312 
  1313     /* Set up the conversion */
  1314     srcbuf = (Uint8 *) surface->pixels;
  1315     maxn = bpp == 4 ? 65535 : 255;
  1316     dst = rlebuf;
  1317     rgbmask = ~surface->format->Amask;
  1318     ckey = surface->map->info.colorkey & rgbmask;
  1319     lastline = dst;
  1320     getpix = getpixes[bpp - 1];
  1321     w = surface->w;
  1322     h = surface->h;
  1323 
  1324 #define ADD_COUNTS(n, m)            \
  1325     if(bpp == 4) {              \
  1326         ((Uint16 *)dst)[0] = n;     \
  1327         ((Uint16 *)dst)[1] = m;     \
  1328         dst += 4;               \
  1329     } else {                \
  1330         dst[0] = n;             \
  1331         dst[1] = m;             \
  1332         dst += 2;               \
  1333     }
  1334 
  1335     for (y = 0; y < h; y++) {
  1336         int x = 0;
  1337         int blankline = 0;
  1338         do {
  1339             int run, skip, len;
  1340             int runstart;
  1341             int skipstart = x;
  1342 
  1343             /* find run of transparent, then opaque pixels */
  1344             while (x < w && (getpix(srcbuf + x * bpp) & rgbmask) == ckey)
  1345                 x++;
  1346             runstart = x;
  1347             while (x < w && (getpix(srcbuf + x * bpp) & rgbmask) != ckey)
  1348                 x++;
  1349             skip = runstart - skipstart;
  1350             if (skip == w)
  1351                 blankline = 1;
  1352             run = x - runstart;
  1353 
  1354             /* encode segment */
  1355             while (skip > maxn) {
  1356                 ADD_COUNTS(maxn, 0);
  1357                 skip -= maxn;
  1358             }
  1359             len = MIN(run, maxn);
  1360             ADD_COUNTS(skip, len);
  1361             SDL_memcpy(dst, srcbuf + runstart * bpp, len * bpp);
  1362             dst += len * bpp;
  1363             run -= len;
  1364             runstart += len;
  1365             while (run) {
  1366                 len = MIN(run, maxn);
  1367                 ADD_COUNTS(0, len);
  1368                 SDL_memcpy(dst, srcbuf + runstart * bpp, len * bpp);
  1369                 dst += len * bpp;
  1370                 runstart += len;
  1371                 run -= len;
  1372             }
  1373             if (!blankline)
  1374                 lastline = dst;
  1375         } while (x < w);
  1376 
  1377         srcbuf += surface->pitch;
  1378     }
  1379     dst = lastline;             /* back up bast trailing blank lines */
  1380     ADD_COUNTS(0, 0);
  1381 
  1382 #undef ADD_COUNTS
  1383 
  1384     /* Now that we have it encoded, release the original pixels */
  1385     if (!(surface->flags & SDL_PREALLOC)) {
  1386         SDL_free(surface->pixels);
  1387         surface->pixels = NULL;
  1388     }
  1389 
  1390     /* realloc the buffer to release unused memory */
  1391     {
  1392         /* If realloc returns NULL, the original block is left intact */
  1393         Uint8 *p = SDL_realloc(rlebuf, dst - rlebuf);
  1394         if (!p)
  1395             p = rlebuf;
  1396         surface->map->data = p;
  1397     }
  1398 
  1399     return (0);
  1400 }
  1401 
  1402 int
  1403 SDL_RLESurface(SDL_Surface * surface)
  1404 {
  1405     int flags;
  1406 
  1407     /* Clear any previous RLE conversion */
  1408     if ((surface->flags & SDL_RLEACCEL) == SDL_RLEACCEL) {
  1409         SDL_UnRLESurface(surface, 1);
  1410     }
  1411 
  1412     /* We don't support RLE encoding of bitmaps */
  1413     if (surface->format->BitsPerPixel < 8) {
  1414         return -1;
  1415     }
  1416 
  1417     /* Make sure the pixels are available */
  1418     if (!surface->pixels) {
  1419         return -1;
  1420     }
  1421 
  1422     /* If we don't have colorkey or blending, nothing to do... */
  1423     flags = surface->map->info.flags;
  1424     if (!(flags & (SDL_COPY_COLORKEY | SDL_COPY_BLEND))) {
  1425         return -1;
  1426     }
  1427 
  1428     /* Pass on combinations not supported */
  1429     if ((flags & SDL_COPY_MODULATE_COLOR) ||
  1430         ((flags & SDL_COPY_MODULATE_ALPHA) && surface->format->Amask) ||
  1431         (flags & (SDL_COPY_ADD | SDL_COPY_MOD)) ||
  1432         (flags & SDL_COPY_NEAREST)) {
  1433         return -1;
  1434     }
  1435 
  1436     /* Encode and set up the blit */
  1437     if (!surface->format->Amask || !(flags & SDL_COPY_BLEND)) {
  1438         if (!surface->map->identity) {
  1439             return -1;
  1440         }
  1441         if (RLEColorkeySurface(surface) < 0) {
  1442             return -1;
  1443         }
  1444         surface->map->blit = SDL_RLEBlit;
  1445         surface->map->info.flags |= SDL_COPY_RLE_COLORKEY;
  1446     } else {
  1447         if (RLEAlphaSurface(surface) < 0) {
  1448             return -1;
  1449         }
  1450         surface->map->blit = SDL_RLEAlphaBlit;
  1451         surface->map->info.flags |= SDL_COPY_RLE_ALPHAKEY;
  1452     }
  1453 
  1454     /* The surface is now accelerated */
  1455     surface->flags |= SDL_RLEACCEL;
  1456 
  1457     return (0);
  1458 }
  1459 
  1460 /*
  1461  * Un-RLE a surface with pixel alpha
  1462  * This may not give back exactly the image before RLE-encoding; all
  1463  * completely transparent pixels will be lost, and color and alpha depth
  1464  * may have been reduced (when encoding for 16bpp targets).
  1465  */
  1466 static SDL_bool
  1467 UnRLEAlpha(SDL_Surface * surface)
  1468 {
  1469     Uint8 *srcbuf;
  1470     Uint32 *dst;
  1471     SDL_PixelFormat *sf = surface->format;
  1472     RLEDestFormat *df = surface->map->data;
  1473     int (*uncopy_opaque) (Uint32 *, void *, int,
  1474                           RLEDestFormat *, SDL_PixelFormat *);
  1475     int (*uncopy_transl) (Uint32 *, void *, int,
  1476                           RLEDestFormat *, SDL_PixelFormat *);
  1477     int w = surface->w;
  1478     int bpp = df->BytesPerPixel;
  1479 
  1480     if (bpp == 2) {
  1481         uncopy_opaque = uncopy_opaque_16;
  1482         uncopy_transl = uncopy_transl_16;
  1483     } else {
  1484         uncopy_opaque = uncopy_transl = uncopy_32;
  1485     }
  1486 
  1487     surface->pixels = SDL_malloc(surface->h * surface->pitch);
  1488     if (!surface->pixels) {
  1489         return (SDL_FALSE);
  1490     }
  1491     /* fill background with transparent pixels */
  1492     SDL_memset(surface->pixels, 0, surface->h * surface->pitch);
  1493 
  1494     dst = surface->pixels;
  1495     srcbuf = (Uint8 *) (df + 1);
  1496     for (;;) {
  1497         /* copy opaque pixels */
  1498         int ofs = 0;
  1499         do {
  1500             unsigned run;
  1501             if (bpp == 2) {
  1502                 ofs += srcbuf[0];
  1503                 run = srcbuf[1];
  1504                 srcbuf += 2;
  1505             } else {
  1506                 ofs += ((Uint16 *) srcbuf)[0];
  1507                 run = ((Uint16 *) srcbuf)[1];
  1508                 srcbuf += 4;
  1509             }
  1510             if (run) {
  1511                 srcbuf += uncopy_opaque(dst + ofs, srcbuf, run, df, sf);
  1512                 ofs += run;
  1513             } else if (!ofs)
  1514                 return (SDL_TRUE);
  1515         } while (ofs < w);
  1516 
  1517         /* skip padding if needed */
  1518         if (bpp == 2)
  1519             srcbuf += (uintptr_t) srcbuf & 2;
  1520 
  1521         /* copy translucent pixels */
  1522         ofs = 0;
  1523         do {
  1524             unsigned run;
  1525             ofs += ((Uint16 *) srcbuf)[0];
  1526             run = ((Uint16 *) srcbuf)[1];
  1527             srcbuf += 4;
  1528             if (run) {
  1529                 srcbuf += uncopy_transl(dst + ofs, srcbuf, run, df, sf);
  1530                 ofs += run;
  1531             }
  1532         } while (ofs < w);
  1533         dst += surface->pitch >> 2;
  1534     }
  1535     /* Make the compiler happy */
  1536     return (SDL_TRUE);
  1537 }
  1538 
  1539 void
  1540 SDL_UnRLESurface(SDL_Surface * surface, int recode)
  1541 {
  1542     if (surface->flags & SDL_RLEACCEL) {
  1543         surface->flags &= ~SDL_RLEACCEL;
  1544 
  1545         if (recode && !(surface->flags & SDL_PREALLOC)) {
  1546             if (surface->map->info.flags & SDL_COPY_RLE_COLORKEY) {
  1547                 SDL_Rect full;
  1548 
  1549                 /* re-create the original surface */
  1550                 surface->pixels = SDL_malloc(surface->h * surface->pitch);
  1551                 if (!surface->pixels) {
  1552                     /* Oh crap... */
  1553                     surface->flags |= SDL_RLEACCEL;
  1554                     return;
  1555                 }
  1556 
  1557                 /* fill it with the background color */
  1558                 SDL_FillRect(surface, NULL, surface->map->info.colorkey);
  1559 
  1560                 /* now render the encoded surface */
  1561                 full.x = full.y = 0;
  1562                 full.w = surface->w;
  1563                 full.h = surface->h;
  1564                 SDL_RLEBlit(surface, &full, surface, &full);
  1565             } else {
  1566                 if (!UnRLEAlpha(surface)) {
  1567                     /* Oh crap... */
  1568                     surface->flags |= SDL_RLEACCEL;
  1569                     return;
  1570                 }
  1571             }
  1572         }
  1573         surface->map->info.flags &=
  1574             ~(SDL_COPY_RLE_COLORKEY | SDL_COPY_RLE_ALPHAKEY);
  1575 
  1576         SDL_free(surface->map->data);
  1577         surface->map->data = NULL;
  1578     }
  1579 }
  1580 
  1581 /* vi: set ts=4 sw=4 expandtab: */