src/video/SDL_RLEaccel.c
author Sam Lantinga <slouken@libsdl.org>
Tue, 26 May 2015 06:27:46 -0700
changeset 9619 b94b6d0bff0f
parent 8924 b80cdf666e91
child 9761 fd7fe355f173
permissions -rw-r--r--
Updated the copyright year to 2015
     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  * This takes care of the case when the surface is clipped on the left and/or
   378  * right. Top clipping has already been taken care of.
   379  */
   380 static void
   381 RLEClipBlit(int w, Uint8 * srcbuf, SDL_Surface * surf_dst,
   382             Uint8 * dstbuf, SDL_Rect * srcrect, unsigned alpha)
   383 {
   384     SDL_PixelFormat *fmt = surf_dst->format;
   385 
   386 #define RLECLIPBLIT(bpp, Type, do_blit)                         \
   387     do {                                                        \
   388         int linecount = srcrect->h;                             \
   389         int ofs = 0;                                            \
   390         int left = srcrect->x;                                  \
   391         int right = left + srcrect->w;                          \
   392         dstbuf -= left * bpp;                                   \
   393         for (;;) {                                              \
   394             int run;                                            \
   395             ofs += *(Type *)srcbuf;                             \
   396             run = ((Type *)srcbuf)[1];                          \
   397             srcbuf += 2 * sizeof(Type);                         \
   398             if (run) {                                          \
   399                 /* clip to left and right borders */            \
   400                 if (ofs < right) {                              \
   401                     int start = 0;                              \
   402                     int len = run;                              \
   403                     int startcol;                               \
   404                     if (left - ofs > 0) {                       \
   405                         start = left - ofs;                     \
   406                         len -= start;                           \
   407                         if (len <= 0)                           \
   408                             goto nocopy ## bpp ## do_blit;      \
   409                     }                                           \
   410                     startcol = ofs + start;                     \
   411                     if (len > right - startcol)                 \
   412                         len = right - startcol;                 \
   413                     do_blit(dstbuf + startcol * bpp, srcbuf + start * bpp, \
   414                         len, bpp, alpha);                       \
   415                 }                                               \
   416     nocopy ## bpp ## do_blit:                                   \
   417                 srcbuf += run * bpp;                            \
   418                 ofs += run;                                     \
   419             } else if (!ofs)                                    \
   420                 break;                                          \
   421                                                                 \
   422             if (ofs == w) {                                     \
   423                 ofs = 0;                                        \
   424                 dstbuf += surf_dst->pitch;                      \
   425                 if (!--linecount)                               \
   426                     break;                                      \
   427             }                                                   \
   428         }                                                       \
   429     } while(0)
   430 
   431     CHOOSE_BLIT(RLECLIPBLIT, alpha, fmt);
   432 
   433 #undef RLECLIPBLIT
   434 
   435 }
   436 
   437 
   438 /* blit a colorkeyed RLE surface */
   439 int
   440 SDL_RLEBlit(SDL_Surface * surf_src, SDL_Rect * srcrect,
   441             SDL_Surface * surf_dst, SDL_Rect * dstrect)
   442 {
   443     Uint8 *dstbuf;
   444     Uint8 *srcbuf;
   445     int x, y;
   446     int w = surf_src->w;
   447     unsigned alpha;
   448 
   449     /* Lock the destination if necessary */
   450     if (SDL_MUSTLOCK(surf_dst)) {
   451         if (SDL_LockSurface(surf_dst) < 0) {
   452             return (-1);
   453         }
   454     }
   455 
   456     /* Set up the source and destination pointers */
   457     x = dstrect->x;
   458     y = dstrect->y;
   459     dstbuf = (Uint8 *) surf_dst->pixels
   460         + y * surf_dst->pitch + x * surf_src->format->BytesPerPixel;
   461     srcbuf = (Uint8 *) surf_src->map->data;
   462 
   463     {
   464         /* skip lines at the top if necessary */
   465         int vskip = srcrect->y;
   466         int ofs = 0;
   467         if (vskip) {
   468 
   469 #define RLESKIP(bpp, Type)          \
   470         for(;;) {           \
   471             int run;            \
   472             ofs += *(Type *)srcbuf; \
   473             run = ((Type *)srcbuf)[1];  \
   474             srcbuf += sizeof(Type) * 2; \
   475             if(run) {           \
   476             srcbuf += run * bpp;    \
   477             ofs += run;     \
   478             } else if(!ofs)     \
   479             goto done;      \
   480             if(ofs == w) {      \
   481             ofs = 0;        \
   482             if(!--vskip)        \
   483                 break;      \
   484             }               \
   485         }
   486 
   487             switch (surf_src->format->BytesPerPixel) {
   488             case 1:
   489                 RLESKIP(1, Uint8);
   490                 break;
   491             case 2:
   492                 RLESKIP(2, Uint8);
   493                 break;
   494             case 3:
   495                 RLESKIP(3, Uint8);
   496                 break;
   497             case 4:
   498                 RLESKIP(4, Uint16);
   499                 break;
   500             }
   501 
   502 #undef RLESKIP
   503 
   504         }
   505     }
   506 
   507     alpha = surf_src->map->info.a;
   508     /* if left or right edge clipping needed, call clip blit */
   509     if (srcrect->x || srcrect->w != surf_src->w) {
   510         RLEClipBlit(w, srcbuf, surf_dst, dstbuf, srcrect, alpha);
   511     } else {
   512         SDL_PixelFormat *fmt = surf_src->format;
   513 
   514 #define RLEBLIT(bpp, Type, do_blit)                       \
   515         do {                                  \
   516         int linecount = srcrect->h;                   \
   517         int ofs = 0;                              \
   518         for(;;) {                             \
   519             unsigned run;                         \
   520             ofs += *(Type *)srcbuf;                   \
   521             run = ((Type *)srcbuf)[1];                    \
   522             srcbuf += 2 * sizeof(Type);                   \
   523             if(run) {                             \
   524             do_blit(dstbuf + ofs * bpp, srcbuf, run, bpp, alpha); \
   525             srcbuf += run * bpp;                      \
   526             ofs += run;                       \
   527             } else if(!ofs)                       \
   528             break;                            \
   529             if(ofs == w) {                        \
   530             ofs = 0;                          \
   531             dstbuf += surf_dst->pitch;                     \
   532             if(!--linecount)                      \
   533                 break;                        \
   534             }                                 \
   535         }                                 \
   536         } while(0)
   537 
   538         CHOOSE_BLIT(RLEBLIT, alpha, fmt);
   539 
   540 #undef RLEBLIT
   541     }
   542 
   543   done:
   544     /* Unlock the destination if necessary */
   545     if (SDL_MUSTLOCK(surf_dst)) {
   546         SDL_UnlockSurface(surf_dst);
   547     }
   548     return (0);
   549 }
   550 
   551 #undef OPAQUE_BLIT
   552 
   553 /*
   554  * Per-pixel blitting macros for translucent pixels:
   555  * These use the same techniques as the per-surface blitting macros
   556  */
   557 
   558 /*
   559  * For 32bpp pixels, we have made sure the alpha is stored in the top
   560  * 8 bits, so proceed as usual
   561  */
   562 #define BLIT_TRANSL_888(src, dst)               \
   563     do {                            \
   564         Uint32 s = src;                     \
   565     Uint32 d = dst;                     \
   566     unsigned alpha = s >> 24;               \
   567     Uint32 s1 = s & 0xff00ff;               \
   568     Uint32 d1 = d & 0xff00ff;               \
   569     d1 = (d1 + ((s1 - d1) * alpha >> 8)) & 0xff00ff;    \
   570     s &= 0xff00;                        \
   571     d &= 0xff00;                        \
   572     d = (d + ((s - d) * alpha >> 8)) & 0xff00;      \
   573     dst = d1 | d | 0xff000000;              \
   574     } while(0)
   575 
   576 /*
   577  * For 16bpp pixels, we have stored the 5 most significant alpha bits in
   578  * bits 5-10. As before, we can process all 3 RGB components at the same time.
   579  */
   580 #define BLIT_TRANSL_565(src, dst)       \
   581     do {                    \
   582     Uint32 s = src;             \
   583     Uint32 d = dst;             \
   584     unsigned alpha = (s & 0x3e0) >> 5;  \
   585     s &= 0x07e0f81f;            \
   586     d = (d | d << 16) & 0x07e0f81f;     \
   587     d += (s - d) * alpha >> 5;      \
   588     d &= 0x07e0f81f;            \
   589     dst = (Uint16)(d | d >> 16);            \
   590     } while(0)
   591 
   592 #define BLIT_TRANSL_555(src, dst)       \
   593     do {                    \
   594     Uint32 s = src;             \
   595     Uint32 d = dst;             \
   596     unsigned alpha = (s & 0x3e0) >> 5;  \
   597     s &= 0x03e07c1f;            \
   598     d = (d | d << 16) & 0x03e07c1f;     \
   599     d += (s - d) * alpha >> 5;      \
   600     d &= 0x03e07c1f;            \
   601     dst = (Uint16)(d | d >> 16);            \
   602     } while(0)
   603 
   604 /* used to save the destination format in the encoding. Designed to be
   605    macro-compatible with SDL_PixelFormat but without the unneeded fields */
   606 typedef struct
   607 {
   608     Uint8 BytesPerPixel;
   609     Uint8 padding[3];
   610     Uint32 Rmask;
   611     Uint32 Gmask;
   612     Uint32 Bmask;
   613     Uint32 Amask;
   614     Uint8 Rloss;
   615     Uint8 Gloss;
   616     Uint8 Bloss;
   617     Uint8 Aloss;
   618     Uint8 Rshift;
   619     Uint8 Gshift;
   620     Uint8 Bshift;
   621     Uint8 Ashift;
   622 } RLEDestFormat;
   623 
   624 /* blit a pixel-alpha RLE surface clipped at the right and/or left edges */
   625 static void
   626 RLEAlphaClipBlit(int w, Uint8 * srcbuf, SDL_Surface * surf_dst,
   627                  Uint8 * dstbuf, SDL_Rect * srcrect)
   628 {
   629     SDL_PixelFormat *df = surf_dst->format;
   630     /*
   631      * clipped blitter: Ptype is the destination pixel type,
   632      * Ctype the translucent count type, and do_blend the macro
   633      * to blend one pixel.
   634      */
   635 #define RLEALPHACLIPBLIT(Ptype, Ctype, do_blend)              \
   636     do {                                  \
   637     int linecount = srcrect->h;                   \
   638     int left = srcrect->x;                        \
   639     int right = left + srcrect->w;                    \
   640     dstbuf -= left * sizeof(Ptype);                   \
   641     do {                                  \
   642         int ofs = 0;                          \
   643         /* blit opaque pixels on one line */              \
   644         do {                              \
   645         unsigned run;                         \
   646         ofs += ((Ctype *)srcbuf)[0];                  \
   647         run = ((Ctype *)srcbuf)[1];               \
   648         srcbuf += 2 * sizeof(Ctype);                  \
   649         if(run) {                         \
   650             /* clip to left and right borders */          \
   651             int cofs = ofs;                   \
   652             int crun = run;                   \
   653             if(left - cofs > 0) {                 \
   654             crun -= left - cofs;                  \
   655             cofs = left;                      \
   656             }                             \
   657             if(crun > right - cofs)               \
   658             crun = right - cofs;                  \
   659             if(crun > 0)                      \
   660             PIXEL_COPY(dstbuf + cofs * sizeof(Ptype),     \
   661                    srcbuf + (cofs - ofs) * sizeof(Ptype), \
   662                    (unsigned)crun, sizeof(Ptype));    \
   663             srcbuf += run * sizeof(Ptype);            \
   664             ofs += run;                       \
   665         } else if(!ofs)                       \
   666             return;                       \
   667         } while(ofs < w);                         \
   668         /* skip padding if necessary */               \
   669         if(sizeof(Ptype) == 2)                    \
   670         srcbuf += (uintptr_t)srcbuf & 2;              \
   671         /* blit translucent pixels on the same line */        \
   672         ofs = 0;                              \
   673         do {                              \
   674         unsigned run;                         \
   675         ofs += ((Uint16 *)srcbuf)[0];                 \
   676         run = ((Uint16 *)srcbuf)[1];                  \
   677         srcbuf += 4;                          \
   678         if(run) {                         \
   679             /* clip to left and right borders */          \
   680             int cofs = ofs;                   \
   681             int crun = run;                   \
   682             if(left - cofs > 0) {                 \
   683             crun -= left - cofs;                  \
   684             cofs = left;                      \
   685             }                             \
   686             if(crun > right - cofs)               \
   687             crun = right - cofs;                  \
   688             if(crun > 0) {                    \
   689             Ptype *dst = (Ptype *)dstbuf + cofs;          \
   690             Uint32 *src = (Uint32 *)srcbuf + (cofs - ofs);    \
   691             int i;                        \
   692             for(i = 0; i < crun; i++)             \
   693                 do_blend(src[i], dst[i]);             \
   694             }                             \
   695             srcbuf += run * 4;                    \
   696             ofs += run;                       \
   697         }                             \
   698         } while(ofs < w);                         \
   699         dstbuf += surf_dst->pitch;                     \
   700     } while(--linecount);                         \
   701     } while(0)
   702 
   703     switch (df->BytesPerPixel) {
   704     case 2:
   705         if (df->Gmask == 0x07e0 || df->Rmask == 0x07e0 || df->Bmask == 0x07e0)
   706             RLEALPHACLIPBLIT(Uint16, Uint8, BLIT_TRANSL_565);
   707         else
   708             RLEALPHACLIPBLIT(Uint16, Uint8, BLIT_TRANSL_555);
   709         break;
   710     case 4:
   711         RLEALPHACLIPBLIT(Uint32, Uint16, BLIT_TRANSL_888);
   712         break;
   713     }
   714 }
   715 
   716 /* blit a pixel-alpha RLE surface */
   717 int
   718 SDL_RLEAlphaBlit(SDL_Surface * surf_src, SDL_Rect * srcrect,
   719                  SDL_Surface * surf_dst, SDL_Rect * dstrect)
   720 {
   721     int x, y;
   722     int w = surf_src->w;
   723     Uint8 *srcbuf, *dstbuf;
   724     SDL_PixelFormat *df = surf_dst->format;
   725 
   726     /* Lock the destination if necessary */
   727     if (SDL_MUSTLOCK(surf_dst)) {
   728         if (SDL_LockSurface(surf_dst) < 0) {
   729             return -1;
   730         }
   731     }
   732 
   733     x = dstrect->x;
   734     y = dstrect->y;
   735     dstbuf = (Uint8 *) surf_dst->pixels + y * surf_dst->pitch + x * df->BytesPerPixel;
   736     srcbuf = (Uint8 *) surf_src->map->data + sizeof(RLEDestFormat);
   737 
   738     {
   739         /* skip lines at the top if necessary */
   740         int vskip = srcrect->y;
   741         if (vskip) {
   742             int ofs;
   743             if (df->BytesPerPixel == 2) {
   744                 /* the 16/32 interleaved format */
   745                 do {
   746                     /* skip opaque line */
   747                     ofs = 0;
   748                     do {
   749                         int run;
   750                         ofs += srcbuf[0];
   751                         run = srcbuf[1];
   752                         srcbuf += 2;
   753                         if (run) {
   754                             srcbuf += 2 * run;
   755                             ofs += run;
   756                         } else if (!ofs)
   757                             goto done;
   758                     } while (ofs < w);
   759 
   760                     /* skip padding */
   761                     srcbuf += (uintptr_t) srcbuf & 2;
   762 
   763                     /* skip translucent line */
   764                     ofs = 0;
   765                     do {
   766                         int run;
   767                         ofs += ((Uint16 *) srcbuf)[0];
   768                         run = ((Uint16 *) srcbuf)[1];
   769                         srcbuf += 4 * (run + 1);
   770                         ofs += run;
   771                     } while (ofs < w);
   772                 } while (--vskip);
   773             } else {
   774                 /* the 32/32 interleaved format */
   775                 vskip <<= 1;    /* opaque and translucent have same format */
   776                 do {
   777                     ofs = 0;
   778                     do {
   779                         int run;
   780                         ofs += ((Uint16 *) srcbuf)[0];
   781                         run = ((Uint16 *) srcbuf)[1];
   782                         srcbuf += 4;
   783                         if (run) {
   784                             srcbuf += 4 * run;
   785                             ofs += run;
   786                         } else if (!ofs)
   787                             goto done;
   788                     } while (ofs < w);
   789                 } while (--vskip);
   790             }
   791         }
   792     }
   793 
   794     /* if left or right edge clipping needed, call clip blit */
   795     if (srcrect->x || srcrect->w != surf_src->w) {
   796         RLEAlphaClipBlit(w, srcbuf, surf_dst, dstbuf, srcrect);
   797     } else {
   798 
   799         /*
   800          * non-clipped blitter. Ptype is the destination pixel type,
   801          * Ctype the translucent count type, and do_blend the
   802          * macro to blend one pixel.
   803          */
   804 #define RLEALPHABLIT(Ptype, Ctype, do_blend)                 \
   805     do {                                 \
   806         int linecount = srcrect->h;                  \
   807         do {                             \
   808         int ofs = 0;                         \
   809         /* blit opaque pixels on one line */             \
   810         do {                             \
   811             unsigned run;                    \
   812             ofs += ((Ctype *)srcbuf)[0];             \
   813             run = ((Ctype *)srcbuf)[1];              \
   814             srcbuf += 2 * sizeof(Ctype);             \
   815             if(run) {                        \
   816             PIXEL_COPY(dstbuf + ofs * sizeof(Ptype), srcbuf, \
   817                    run, sizeof(Ptype));          \
   818             srcbuf += run * sizeof(Ptype);           \
   819             ofs += run;                  \
   820             } else if(!ofs)                  \
   821             goto done;                   \
   822         } while(ofs < w);                    \
   823         /* skip padding if necessary */              \
   824         if(sizeof(Ptype) == 2)                   \
   825             srcbuf += (uintptr_t)srcbuf & 2;             \
   826         /* blit translucent pixels on the same line */       \
   827         ofs = 0;                         \
   828         do {                             \
   829             unsigned run;                    \
   830             ofs += ((Uint16 *)srcbuf)[0];            \
   831             run = ((Uint16 *)srcbuf)[1];             \
   832             srcbuf += 4;                     \
   833             if(run) {                        \
   834             Ptype *dst = (Ptype *)dstbuf + ofs;      \
   835             unsigned i;                  \
   836             for(i = 0; i < run; i++) {           \
   837                 Uint32 src = *(Uint32 *)srcbuf;      \
   838                 do_blend(src, *dst);             \
   839                 srcbuf += 4;                 \
   840                 dst++;                   \
   841             }                        \
   842             ofs += run;                  \
   843             }                            \
   844         } while(ofs < w);                    \
   845         dstbuf += surf_dst->pitch;                    \
   846         } while(--linecount);                    \
   847     } while(0)
   848 
   849         switch (df->BytesPerPixel) {
   850         case 2:
   851             if (df->Gmask == 0x07e0 || df->Rmask == 0x07e0
   852                 || df->Bmask == 0x07e0)
   853                 RLEALPHABLIT(Uint16, Uint8, BLIT_TRANSL_565);
   854             else
   855                 RLEALPHABLIT(Uint16, Uint8, BLIT_TRANSL_555);
   856             break;
   857         case 4:
   858             RLEALPHABLIT(Uint32, Uint16, BLIT_TRANSL_888);
   859             break;
   860         }
   861     }
   862 
   863   done:
   864     /* Unlock the destination if necessary */
   865     if (SDL_MUSTLOCK(surf_dst)) {
   866         SDL_UnlockSurface(surf_dst);
   867     }
   868     return 0;
   869 }
   870 
   871 /*
   872  * Auxiliary functions:
   873  * The encoding functions take 32bpp rgb + a, and
   874  * return the number of bytes copied to the destination.
   875  * The decoding functions copy to 32bpp rgb + a, and
   876  * return the number of bytes copied from the source.
   877  * These are only used in the encoder and un-RLE code and are therefore not
   878  * highly optimised.
   879  */
   880 
   881 /* encode 32bpp rgb + a into 16bpp rgb, losing alpha */
   882 static int
   883 copy_opaque_16(void *dst, Uint32 * src, int n,
   884                SDL_PixelFormat * sfmt, SDL_PixelFormat * dfmt)
   885 {
   886     int i;
   887     Uint16 *d = dst;
   888     for (i = 0; i < n; i++) {
   889         unsigned r, g, b;
   890         RGB_FROM_PIXEL(*src, sfmt, r, g, b);
   891         PIXEL_FROM_RGB(*d, dfmt, r, g, b);
   892         src++;
   893         d++;
   894     }
   895     return n * 2;
   896 }
   897 
   898 /* decode opaque pixels from 16bpp to 32bpp rgb + a */
   899 static int
   900 uncopy_opaque_16(Uint32 * dst, void *src, int n,
   901                  RLEDestFormat * sfmt, SDL_PixelFormat * dfmt)
   902 {
   903     int i;
   904     Uint16 *s = src;
   905     unsigned alpha = dfmt->Amask ? 255 : 0;
   906     for (i = 0; i < n; i++) {
   907         unsigned r, g, b;
   908         RGB_FROM_PIXEL(*s, sfmt, r, g, b);
   909         PIXEL_FROM_RGBA(*dst, dfmt, r, g, b, alpha);
   910         s++;
   911         dst++;
   912     }
   913     return n * 2;
   914 }
   915 
   916 
   917 
   918 /* encode 32bpp rgb + a into 32bpp G0RAB format for blitting into 565 */
   919 static int
   920 copy_transl_565(void *dst, Uint32 * src, int n,
   921                 SDL_PixelFormat * sfmt, SDL_PixelFormat * dfmt)
   922 {
   923     int i;
   924     Uint32 *d = dst;
   925     for (i = 0; i < n; i++) {
   926         unsigned r, g, b, a;
   927         Uint16 pix;
   928         RGBA_FROM_8888(*src, sfmt, r, g, b, a);
   929         PIXEL_FROM_RGB(pix, dfmt, r, g, b);
   930         *d = ((pix & 0x7e0) << 16) | (pix & 0xf81f) | ((a << 2) & 0x7e0);
   931         src++;
   932         d++;
   933     }
   934     return n * 4;
   935 }
   936 
   937 /* encode 32bpp rgb + a into 32bpp G0RAB format for blitting into 555 */
   938 static int
   939 copy_transl_555(void *dst, Uint32 * src, int n,
   940                 SDL_PixelFormat * sfmt, SDL_PixelFormat * dfmt)
   941 {
   942     int i;
   943     Uint32 *d = dst;
   944     for (i = 0; i < n; i++) {
   945         unsigned r, g, b, a;
   946         Uint16 pix;
   947         RGBA_FROM_8888(*src, sfmt, r, g, b, a);
   948         PIXEL_FROM_RGB(pix, dfmt, r, g, b);
   949         *d = ((pix & 0x3e0) << 16) | (pix & 0xfc1f) | ((a << 2) & 0x3e0);
   950         src++;
   951         d++;
   952     }
   953     return n * 4;
   954 }
   955 
   956 /* decode translucent pixels from 32bpp GORAB to 32bpp rgb + a */
   957 static int
   958 uncopy_transl_16(Uint32 * dst, void *src, int n,
   959                  RLEDestFormat * sfmt, SDL_PixelFormat * dfmt)
   960 {
   961     int i;
   962     Uint32 *s = src;
   963     for (i = 0; i < n; i++) {
   964         unsigned r, g, b, a;
   965         Uint32 pix = *s++;
   966         a = (pix & 0x3e0) >> 2;
   967         pix = (pix & ~0x3e0) | pix >> 16;
   968         RGB_FROM_PIXEL(pix, sfmt, r, g, b);
   969         PIXEL_FROM_RGBA(*dst, dfmt, r, g, b, a);
   970         dst++;
   971     }
   972     return n * 4;
   973 }
   974 
   975 /* encode 32bpp rgba into 32bpp rgba, keeping alpha (dual purpose) */
   976 static int
   977 copy_32(void *dst, Uint32 * src, int n,
   978         SDL_PixelFormat * sfmt, SDL_PixelFormat * dfmt)
   979 {
   980     int i;
   981     Uint32 *d = dst;
   982     for (i = 0; i < n; i++) {
   983         unsigned r, g, b, a;
   984         RGBA_FROM_8888(*src, sfmt, r, g, b, a);
   985         PIXEL_FROM_RGBA(*d, dfmt, r, g, b, a);
   986         d++;
   987         src++;
   988     }
   989     return n * 4;
   990 }
   991 
   992 /* decode 32bpp rgba into 32bpp rgba, keeping alpha (dual purpose) */
   993 static int
   994 uncopy_32(Uint32 * dst, void *src, int n,
   995           RLEDestFormat * sfmt, SDL_PixelFormat * dfmt)
   996 {
   997     int i;
   998     Uint32 *s = src;
   999     for (i = 0; i < n; i++) {
  1000         unsigned r, g, b, a;
  1001         Uint32 pixel = *s++;
  1002         RGB_FROM_PIXEL(pixel, sfmt, r, g, b);
  1003         a = pixel >> 24;
  1004         PIXEL_FROM_RGBA(*dst, dfmt, r, g, b, a);
  1005         dst++;
  1006     }
  1007     return n * 4;
  1008 }
  1009 
  1010 #define ISOPAQUE(pixel, fmt) ((((pixel) & fmt->Amask) >> fmt->Ashift) == 255)
  1011 
  1012 #define ISTRANSL(pixel, fmt)    \
  1013     ((unsigned)((((pixel) & fmt->Amask) >> fmt->Ashift) - 1U) < 254U)
  1014 
  1015 /* convert surface to be quickly alpha-blittable onto dest, if possible */
  1016 static int
  1017 RLEAlphaSurface(SDL_Surface * surface)
  1018 {
  1019     SDL_Surface *dest;
  1020     SDL_PixelFormat *df;
  1021     int maxsize = 0;
  1022     int max_opaque_run;
  1023     int max_transl_run = 65535;
  1024     unsigned masksum;
  1025     Uint8 *rlebuf, *dst;
  1026     int (*copy_opaque) (void *, Uint32 *, int,
  1027                         SDL_PixelFormat *, SDL_PixelFormat *);
  1028     int (*copy_transl) (void *, Uint32 *, int,
  1029                         SDL_PixelFormat *, SDL_PixelFormat *);
  1030 
  1031     dest = surface->map->dst;
  1032     if (!dest)
  1033         return -1;
  1034     df = dest->format;
  1035     if (surface->format->BitsPerPixel != 32)
  1036         return -1;              /* only 32bpp source supported */
  1037 
  1038     /* find out whether the destination is one we support,
  1039        and determine the max size of the encoded result */
  1040     masksum = df->Rmask | df->Gmask | df->Bmask;
  1041     switch (df->BytesPerPixel) {
  1042     case 2:
  1043         /* 16bpp: only support 565 and 555 formats */
  1044         switch (masksum) {
  1045         case 0xffff:
  1046             if (df->Gmask == 0x07e0
  1047                 || df->Rmask == 0x07e0 || df->Bmask == 0x07e0) {
  1048                 copy_opaque = copy_opaque_16;
  1049                 copy_transl = copy_transl_565;
  1050             } else
  1051                 return -1;
  1052             break;
  1053         case 0x7fff:
  1054             if (df->Gmask == 0x03e0
  1055                 || df->Rmask == 0x03e0 || df->Bmask == 0x03e0) {
  1056                 copy_opaque = copy_opaque_16;
  1057                 copy_transl = copy_transl_555;
  1058             } else
  1059                 return -1;
  1060             break;
  1061         default:
  1062             return -1;
  1063         }
  1064         max_opaque_run = 255;   /* runs stored as bytes */
  1065 
  1066         /* worst case is alternating opaque and translucent pixels,
  1067            with room for alignment padding between lines */
  1068         maxsize = surface->h * (2 + (4 + 2) * (surface->w + 1)) + 2;
  1069         break;
  1070     case 4:
  1071         if (masksum != 0x00ffffff)
  1072             return -1;          /* requires unused high byte */
  1073         copy_opaque = copy_32;
  1074         copy_transl = copy_32;
  1075         max_opaque_run = 255;   /* runs stored as short ints */
  1076 
  1077         /* worst case is alternating opaque and translucent pixels */
  1078         maxsize = surface->h * 2 * 4 * (surface->w + 1) + 4;
  1079         break;
  1080     default:
  1081         return -1;              /* anything else unsupported right now */
  1082     }
  1083 
  1084     maxsize += sizeof(RLEDestFormat);
  1085     rlebuf = (Uint8 *) SDL_malloc(maxsize);
  1086     if (!rlebuf) {
  1087         return SDL_OutOfMemory();
  1088     }
  1089     {
  1090         /* save the destination format so we can undo the encoding later */
  1091         RLEDestFormat *r = (RLEDestFormat *) rlebuf;
  1092         r->BytesPerPixel = df->BytesPerPixel;
  1093         r->Rmask = df->Rmask;
  1094         r->Gmask = df->Gmask;
  1095         r->Bmask = df->Bmask;
  1096         r->Amask = df->Amask;
  1097         r->Rloss = df->Rloss;
  1098         r->Gloss = df->Gloss;
  1099         r->Bloss = df->Bloss;
  1100         r->Aloss = df->Aloss;
  1101         r->Rshift = df->Rshift;
  1102         r->Gshift = df->Gshift;
  1103         r->Bshift = df->Bshift;
  1104         r->Ashift = df->Ashift;
  1105     }
  1106     dst = rlebuf + sizeof(RLEDestFormat);
  1107 
  1108     /* Do the actual encoding */
  1109     {
  1110         int x, y;
  1111         int h = surface->h, w = surface->w;
  1112         SDL_PixelFormat *sf = surface->format;
  1113         Uint32 *src = (Uint32 *) surface->pixels;
  1114         Uint8 *lastline = dst;  /* end of last non-blank line */
  1115 
  1116         /* opaque counts are 8 or 16 bits, depending on target depth */
  1117 #define ADD_OPAQUE_COUNTS(n, m)         \
  1118     if(df->BytesPerPixel == 4) {        \
  1119         ((Uint16 *)dst)[0] = n;     \
  1120         ((Uint16 *)dst)[1] = m;     \
  1121         dst += 4;               \
  1122     } else {                \
  1123         dst[0] = n;             \
  1124         dst[1] = m;             \
  1125         dst += 2;               \
  1126     }
  1127 
  1128         /* translucent counts are always 16 bit */
  1129 #define ADD_TRANSL_COUNTS(n, m)     \
  1130     (((Uint16 *)dst)[0] = n, ((Uint16 *)dst)[1] = m, dst += 4)
  1131 
  1132         for (y = 0; y < h; y++) {
  1133             int runstart, skipstart;
  1134             int blankline = 0;
  1135             /* First encode all opaque pixels of a scan line */
  1136             x = 0;
  1137             do {
  1138                 int run, skip, len;
  1139                 skipstart = x;
  1140                 while (x < w && !ISOPAQUE(src[x], sf))
  1141                     x++;
  1142                 runstart = x;
  1143                 while (x < w && ISOPAQUE(src[x], sf))
  1144                     x++;
  1145                 skip = runstart - skipstart;
  1146                 if (skip == w)
  1147                     blankline = 1;
  1148                 run = x - runstart;
  1149                 while (skip > max_opaque_run) {
  1150                     ADD_OPAQUE_COUNTS(max_opaque_run, 0);
  1151                     skip -= max_opaque_run;
  1152                 }
  1153                 len = MIN(run, max_opaque_run);
  1154                 ADD_OPAQUE_COUNTS(skip, len);
  1155                 dst += copy_opaque(dst, src + runstart, len, sf, df);
  1156                 runstart += len;
  1157                 run -= len;
  1158                 while (run) {
  1159                     len = MIN(run, max_opaque_run);
  1160                     ADD_OPAQUE_COUNTS(0, len);
  1161                     dst += copy_opaque(dst, src + runstart, len, sf, df);
  1162                     runstart += len;
  1163                     run -= len;
  1164                 }
  1165             } while (x < w);
  1166 
  1167             /* Make sure the next output address is 32-bit aligned */
  1168             dst += (uintptr_t) dst & 2;
  1169 
  1170             /* Next, encode all translucent pixels of the same scan line */
  1171             x = 0;
  1172             do {
  1173                 int run, skip, len;
  1174                 skipstart = x;
  1175                 while (x < w && !ISTRANSL(src[x], sf))
  1176                     x++;
  1177                 runstart = x;
  1178                 while (x < w && ISTRANSL(src[x], sf))
  1179                     x++;
  1180                 skip = runstart - skipstart;
  1181                 blankline &= (skip == w);
  1182                 run = x - runstart;
  1183                 while (skip > max_transl_run) {
  1184                     ADD_TRANSL_COUNTS(max_transl_run, 0);
  1185                     skip -= max_transl_run;
  1186                 }
  1187                 len = MIN(run, max_transl_run);
  1188                 ADD_TRANSL_COUNTS(skip, len);
  1189                 dst += copy_transl(dst, src + runstart, len, sf, df);
  1190                 runstart += len;
  1191                 run -= len;
  1192                 while (run) {
  1193                     len = MIN(run, max_transl_run);
  1194                     ADD_TRANSL_COUNTS(0, len);
  1195                     dst += copy_transl(dst, src + runstart, len, sf, df);
  1196                     runstart += len;
  1197                     run -= len;
  1198                 }
  1199                 if (!blankline)
  1200                     lastline = dst;
  1201             } while (x < w);
  1202 
  1203             src += surface->pitch >> 2;
  1204         }
  1205         dst = lastline;         /* back up past trailing blank lines */
  1206         ADD_OPAQUE_COUNTS(0, 0);
  1207     }
  1208 
  1209 #undef ADD_OPAQUE_COUNTS
  1210 #undef ADD_TRANSL_COUNTS
  1211 
  1212     /* Now that we have it encoded, release the original pixels */
  1213     if (!(surface->flags & SDL_PREALLOC)) {
  1214         SDL_free(surface->pixels);
  1215         surface->pixels = NULL;
  1216     }
  1217 
  1218     /* realloc the buffer to release unused memory */
  1219     {
  1220         Uint8 *p = SDL_realloc(rlebuf, dst - rlebuf);
  1221         if (!p)
  1222             p = rlebuf;
  1223         surface->map->data = p;
  1224     }
  1225 
  1226     return 0;
  1227 }
  1228 
  1229 static Uint32
  1230 getpix_8(Uint8 * srcbuf)
  1231 {
  1232     return *srcbuf;
  1233 }
  1234 
  1235 static Uint32
  1236 getpix_16(Uint8 * srcbuf)
  1237 {
  1238     return *(Uint16 *) srcbuf;
  1239 }
  1240 
  1241 static Uint32
  1242 getpix_24(Uint8 * srcbuf)
  1243 {
  1244 #if SDL_BYTEORDER == SDL_LIL_ENDIAN
  1245     return srcbuf[0] + (srcbuf[1] << 8) + (srcbuf[2] << 16);
  1246 #else
  1247     return (srcbuf[0] << 16) + (srcbuf[1] << 8) + srcbuf[2];
  1248 #endif
  1249 }
  1250 
  1251 static Uint32
  1252 getpix_32(Uint8 * srcbuf)
  1253 {
  1254     return *(Uint32 *) srcbuf;
  1255 }
  1256 
  1257 typedef Uint32(*getpix_func) (Uint8 *);
  1258 
  1259 static const getpix_func getpixes[4] = {
  1260     getpix_8, getpix_16, getpix_24, getpix_32
  1261 };
  1262 
  1263 static int
  1264 RLEColorkeySurface(SDL_Surface * surface)
  1265 {
  1266     Uint8 *rlebuf, *dst;
  1267     int maxn;
  1268     int y;
  1269     Uint8 *srcbuf, *lastline;
  1270     int maxsize = 0;
  1271     int bpp = surface->format->BytesPerPixel;
  1272     getpix_func getpix;
  1273     Uint32 ckey, rgbmask;
  1274     int w, h;
  1275 
  1276     /* calculate the worst case size for the compressed surface */
  1277     switch (bpp) {
  1278     case 1:
  1279         /* worst case is alternating opaque and transparent pixels,
  1280            starting with an opaque pixel */
  1281         maxsize = surface->h * 3 * (surface->w / 2 + 1) + 2;
  1282         break;
  1283     case 2:
  1284     case 3:
  1285         /* worst case is solid runs, at most 255 pixels wide */
  1286         maxsize = surface->h * (2 * (surface->w / 255 + 1)
  1287                                 + surface->w * bpp) + 2;
  1288         break;
  1289     case 4:
  1290         /* worst case is solid runs, at most 65535 pixels wide */
  1291         maxsize = surface->h * (4 * (surface->w / 65535 + 1)
  1292                                 + surface->w * 4) + 4;
  1293         break;
  1294     }
  1295 
  1296     rlebuf = (Uint8 *) SDL_malloc(maxsize);
  1297     if (rlebuf == NULL) {
  1298         return SDL_OutOfMemory();
  1299     }
  1300 
  1301     /* Set up the conversion */
  1302     srcbuf = (Uint8 *) surface->pixels;
  1303     maxn = bpp == 4 ? 65535 : 255;
  1304     dst = rlebuf;
  1305     rgbmask = ~surface->format->Amask;
  1306     ckey = surface->map->info.colorkey & rgbmask;
  1307     lastline = dst;
  1308     getpix = getpixes[bpp - 1];
  1309     w = surface->w;
  1310     h = surface->h;
  1311 
  1312 #define ADD_COUNTS(n, m)            \
  1313     if(bpp == 4) {              \
  1314         ((Uint16 *)dst)[0] = n;     \
  1315         ((Uint16 *)dst)[1] = m;     \
  1316         dst += 4;               \
  1317     } else {                \
  1318         dst[0] = n;             \
  1319         dst[1] = m;             \
  1320         dst += 2;               \
  1321     }
  1322 
  1323     for (y = 0; y < h; y++) {
  1324         int x = 0;
  1325         int blankline = 0;
  1326         do {
  1327             int run, skip, len;
  1328             int runstart;
  1329             int skipstart = x;
  1330 
  1331             /* find run of transparent, then opaque pixels */
  1332             while (x < w && (getpix(srcbuf + x * bpp) & rgbmask) == ckey)
  1333                 x++;
  1334             runstart = x;
  1335             while (x < w && (getpix(srcbuf + x * bpp) & rgbmask) != ckey)
  1336                 x++;
  1337             skip = runstart - skipstart;
  1338             if (skip == w)
  1339                 blankline = 1;
  1340             run = x - runstart;
  1341 
  1342             /* encode segment */
  1343             while (skip > maxn) {
  1344                 ADD_COUNTS(maxn, 0);
  1345                 skip -= maxn;
  1346             }
  1347             len = MIN(run, maxn);
  1348             ADD_COUNTS(skip, len);
  1349             SDL_memcpy(dst, srcbuf + runstart * bpp, len * bpp);
  1350             dst += len * bpp;
  1351             run -= len;
  1352             runstart += len;
  1353             while (run) {
  1354                 len = MIN(run, maxn);
  1355                 ADD_COUNTS(0, len);
  1356                 SDL_memcpy(dst, srcbuf + runstart * bpp, len * bpp);
  1357                 dst += len * bpp;
  1358                 runstart += len;
  1359                 run -= len;
  1360             }
  1361             if (!blankline)
  1362                 lastline = dst;
  1363         } while (x < w);
  1364 
  1365         srcbuf += surface->pitch;
  1366     }
  1367     dst = lastline;             /* back up bast trailing blank lines */
  1368     ADD_COUNTS(0, 0);
  1369 
  1370 #undef ADD_COUNTS
  1371 
  1372     /* Now that we have it encoded, release the original pixels */
  1373     if (!(surface->flags & SDL_PREALLOC)) {
  1374         SDL_free(surface->pixels);
  1375         surface->pixels = NULL;
  1376     }
  1377 
  1378     /* realloc the buffer to release unused memory */
  1379     {
  1380         /* If realloc returns NULL, the original block is left intact */
  1381         Uint8 *p = SDL_realloc(rlebuf, dst - rlebuf);
  1382         if (!p)
  1383             p = rlebuf;
  1384         surface->map->data = p;
  1385     }
  1386 
  1387     return (0);
  1388 }
  1389 
  1390 int
  1391 SDL_RLESurface(SDL_Surface * surface)
  1392 {
  1393     int flags;
  1394 
  1395     /* Clear any previous RLE conversion */
  1396     if ((surface->flags & SDL_RLEACCEL) == SDL_RLEACCEL) {
  1397         SDL_UnRLESurface(surface, 1);
  1398     }
  1399 
  1400     /* We don't support RLE encoding of bitmaps */
  1401     if (surface->format->BitsPerPixel < 8) {
  1402         return -1;
  1403     }
  1404 
  1405     /* Make sure the pixels are available */
  1406     if (!surface->pixels) {
  1407         return -1;
  1408     }
  1409 
  1410     /* If we don't have colorkey or blending, nothing to do... */
  1411     flags = surface->map->info.flags;
  1412     if (!(flags & (SDL_COPY_COLORKEY | SDL_COPY_BLEND))) {
  1413         return -1;
  1414     }
  1415 
  1416     /* Pass on combinations not supported */
  1417     if ((flags & SDL_COPY_MODULATE_COLOR) ||
  1418         ((flags & SDL_COPY_MODULATE_ALPHA) && surface->format->Amask) ||
  1419         (flags & (SDL_COPY_ADD | SDL_COPY_MOD)) ||
  1420         (flags & SDL_COPY_NEAREST)) {
  1421         return -1;
  1422     }
  1423 
  1424     /* Encode and set up the blit */
  1425     if (!surface->format->Amask || !(flags & SDL_COPY_BLEND)) {
  1426         if (!surface->map->identity) {
  1427             return -1;
  1428         }
  1429         if (RLEColorkeySurface(surface) < 0) {
  1430             return -1;
  1431         }
  1432         surface->map->blit = SDL_RLEBlit;
  1433         surface->map->info.flags |= SDL_COPY_RLE_COLORKEY;
  1434     } else {
  1435         if (RLEAlphaSurface(surface) < 0) {
  1436             return -1;
  1437         }
  1438         surface->map->blit = SDL_RLEAlphaBlit;
  1439         surface->map->info.flags |= SDL_COPY_RLE_ALPHAKEY;
  1440     }
  1441 
  1442     /* The surface is now accelerated */
  1443     surface->flags |= SDL_RLEACCEL;
  1444 
  1445     return (0);
  1446 }
  1447 
  1448 /*
  1449  * Un-RLE a surface with pixel alpha
  1450  * This may not give back exactly the image before RLE-encoding; all
  1451  * completely transparent pixels will be lost, and color and alpha depth
  1452  * may have been reduced (when encoding for 16bpp targets).
  1453  */
  1454 static SDL_bool
  1455 UnRLEAlpha(SDL_Surface * surface)
  1456 {
  1457     Uint8 *srcbuf;
  1458     Uint32 *dst;
  1459     SDL_PixelFormat *sf = surface->format;
  1460     RLEDestFormat *df = surface->map->data;
  1461     int (*uncopy_opaque) (Uint32 *, void *, int,
  1462                           RLEDestFormat *, SDL_PixelFormat *);
  1463     int (*uncopy_transl) (Uint32 *, void *, int,
  1464                           RLEDestFormat *, SDL_PixelFormat *);
  1465     int w = surface->w;
  1466     int bpp = df->BytesPerPixel;
  1467 
  1468     if (bpp == 2) {
  1469         uncopy_opaque = uncopy_opaque_16;
  1470         uncopy_transl = uncopy_transl_16;
  1471     } else {
  1472         uncopy_opaque = uncopy_transl = uncopy_32;
  1473     }
  1474 
  1475     surface->pixels = SDL_malloc(surface->h * surface->pitch);
  1476     if (!surface->pixels) {
  1477         return (SDL_FALSE);
  1478     }
  1479     /* fill background with transparent pixels */
  1480     SDL_memset(surface->pixels, 0, surface->h * surface->pitch);
  1481 
  1482     dst = surface->pixels;
  1483     srcbuf = (Uint8 *) (df + 1);
  1484     for (;;) {
  1485         /* copy opaque pixels */
  1486         int ofs = 0;
  1487         do {
  1488             unsigned run;
  1489             if (bpp == 2) {
  1490                 ofs += srcbuf[0];
  1491                 run = srcbuf[1];
  1492                 srcbuf += 2;
  1493             } else {
  1494                 ofs += ((Uint16 *) srcbuf)[0];
  1495                 run = ((Uint16 *) srcbuf)[1];
  1496                 srcbuf += 4;
  1497             }
  1498             if (run) {
  1499                 srcbuf += uncopy_opaque(dst + ofs, srcbuf, run, df, sf);
  1500                 ofs += run;
  1501             } else if (!ofs)
  1502                 return (SDL_TRUE);
  1503         } while (ofs < w);
  1504 
  1505         /* skip padding if needed */
  1506         if (bpp == 2)
  1507             srcbuf += (uintptr_t) srcbuf & 2;
  1508 
  1509         /* copy translucent pixels */
  1510         ofs = 0;
  1511         do {
  1512             unsigned run;
  1513             ofs += ((Uint16 *) srcbuf)[0];
  1514             run = ((Uint16 *) srcbuf)[1];
  1515             srcbuf += 4;
  1516             if (run) {
  1517                 srcbuf += uncopy_transl(dst + ofs, srcbuf, run, df, sf);
  1518                 ofs += run;
  1519             }
  1520         } while (ofs < w);
  1521         dst += surface->pitch >> 2;
  1522     }
  1523     /* Make the compiler happy */
  1524     return (SDL_TRUE);
  1525 }
  1526 
  1527 void
  1528 SDL_UnRLESurface(SDL_Surface * surface, int recode)
  1529 {
  1530     if (surface->flags & SDL_RLEACCEL) {
  1531         surface->flags &= ~SDL_RLEACCEL;
  1532 
  1533         if (recode && !(surface->flags & SDL_PREALLOC)) {
  1534             if (surface->map->info.flags & SDL_COPY_RLE_COLORKEY) {
  1535                 SDL_Rect full;
  1536 
  1537                 /* re-create the original surface */
  1538                 surface->pixels = SDL_malloc(surface->h * surface->pitch);
  1539                 if (!surface->pixels) {
  1540                     /* Oh crap... */
  1541                     surface->flags |= SDL_RLEACCEL;
  1542                     return;
  1543                 }
  1544 
  1545                 /* fill it with the background color */
  1546                 SDL_FillRect(surface, NULL, surface->map->info.colorkey);
  1547 
  1548                 /* now render the encoded surface */
  1549                 full.x = full.y = 0;
  1550                 full.w = surface->w;
  1551                 full.h = surface->h;
  1552                 SDL_RLEBlit(surface, &full, surface, &full);
  1553             } else {
  1554                 if (!UnRLEAlpha(surface)) {
  1555                     /* Oh crap... */
  1556                     surface->flags |= SDL_RLEACCEL;
  1557                     return;
  1558                 }
  1559             }
  1560         }
  1561         surface->map->info.flags &=
  1562             ~(SDL_COPY_RLE_COLORKEY | SDL_COPY_RLE_ALPHAKEY);
  1563 
  1564         SDL_free(surface->map->data);
  1565         surface->map->data = NULL;
  1566     }
  1567 }
  1568 
  1569 /* vi: set ts=4 sw=4 expandtab: */