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