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