src/video/SDL_RLEaccel.c

/* [<][>]
[^][v][top][bottom][index][help] */

FUNCTIONS

This source file includes following functions.
  1. MAX
  2. MIN
  3. OPAQUE_BLIT
  4. ALPHA_BLIT32_888
  5. ALPHA_BLIT16_565
  6. ALPHA_BLIT16_555
  7. ALPHA_BLIT_ANY
  8. ALPHA_BLIT32_888_50
  9. BLEND16_50
  10. ALPHA_BLIT16_50
  11. ALPHA_BLIT16_565_50
  12. ALPHA_BLIT16_555_50
  13. CHOOSE_BLIT
  14. RLEClipBlit
  15. RLECLIPBLIT
  16. SDL_RLEBlit
  17. RLESKIP
  18. RLEBLIT
  19. BLIT_TRANSL_888
  20. BLIT_TRANSL_565
  21. BLIT_TRANSL_555
  22. RLEAlphaClipBlit
  23. RLEALPHACLIPBLIT
  24. SDL_RLEAlphaBlit
  25. RLEALPHABLIT
  26. copy_opaque_16
  27. uncopy_opaque_16
  28. copy_transl_565
  29. copy_transl_555
  30. uncopy_transl_16
  31. copy_32
  32. uncopy_32
  33. ISOPAQUE
  34. ISTRANSL
  35. RLEAlphaSurface
  36. ADD_OPAQUE_COUNTS
  37. ADD_TRANSL_COUNTS
  38. getpix_8
  39. getpix_16
  40. getpix_24
  41. getpix_32
  42. RLEColorkeySurface
  43. ADD_COUNTS
  44. SDL_RLESurface
  45. UnRLEAlpha
  46. SDL_UnRLESurface

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

/* [<][>][^][v][top][bottom][index][help] */