2 Simple DirectMedia Layer
3 Copyright (C) 1997-2016 Sam Lantinga <slouken@libsdl.org>
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.
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:
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.
21 #include "../SDL_internal.h"
24 * RLE encoding for software colorkey and alpha-channel acceleration
26 * Original version by Sam Lantinga
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.
32 * Many thanks to Xark and johns for hints, benchmarks and useful comments
33 * leading to this code.
35 * Welcome to Macro Mayhem.
39 * The encoding translates the image data to a stream of segments of the form
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.
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:
51 * Encoding of colorkeyed surfaces:
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.
58 * The end of the sequence is marked by a zero <skip>,<run> pair at the *
59 * beginning of a line.
61 * Encoding of surfaces with per-pixel alpha:
63 * The sequence begins with a struct RLEDestFormat describing the target
64 * pixel format, to provide reliable un-encoding.
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:
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>
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.
84 * The end of the sequence is marked by a zero <skip>,<run> pair at the
85 * beginning of an opaque line.
88 #include "SDL_video.h"
89 #include "SDL_sysvideo.h"
91 #include "SDL_RLEaccel_c.h"
94 #define MAX(a, b) ((a) > (b) ? (a) : (b))
97 #define MIN(a, b) ((a) < (b) ? (a) : (b))
100 #define PIXEL_COPY(to, from, len, bpp) \
101 SDL_memcpy(to, from, (size_t)(len) * (bpp))
104 * Various colorkey blit methods, for opaque and per-surface alpha
107 #define OPAQUE_BLIT(to, from, length, bpp, alpha) \
108 PIXEL_COPY(to, from, length, bpp)
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.
117 #define ALPHA_BLIT32_888(to, from, length, bpp, alpha) \
120 Uint32 *src = (Uint32 *)(from); \
121 Uint32 *dst = (Uint32 *)(to); \
122 for (i = 0; i < (int)(length); i++) { \
125 Uint32 s1 = s & 0xff00ff; \
126 Uint32 d1 = d & 0xff00ff; \
127 d1 = (d1 + ((s1 - d1) * alpha >> 8)) & 0xff00ff; \
130 d = (d + ((s - d) * alpha >> 8)) & 0xff00; \
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.
141 #define ALPHA_BLIT16_565(to, from, length, bpp, alpha) \
144 Uint16 *src = (Uint16 *)(from); \
145 Uint16 *dst = (Uint16 *)(to); \
146 Uint32 ALPHA = alpha >> 3; \
147 for(i = 0; i < (int)(length); i++) { \
150 s = (s | s << 16) & 0x07e0f81f; \
151 d = (d | d << 16) & 0x07e0f81f; \
152 d += (s - d) * ALPHA >> 5; \
154 *dst++ = (Uint16)(d | d >> 16); \
158 #define ALPHA_BLIT16_555(to, from, length, bpp, alpha) \
161 Uint16 *src = (Uint16 *)(from); \
162 Uint16 *dst = (Uint16 *)(to); \
163 Uint32 ALPHA = alpha >> 3; \
164 for(i = 0; i < (int)(length); i++) { \
167 s = (s | s << 16) & 0x03e07c1f; \
168 d = (d | d << 16) & 0x03e07c1f; \
169 d += (s - d) * ALPHA >> 5; \
171 *dst++ = (Uint16)(d | d >> 16); \
176 * The general slow catch-all function, for remaining depths and formats
178 #define ALPHA_BLIT_ANY(to, from, length, bpp, alpha) \
183 for (i = 0; i < (int)(length); i++) { \
185 unsigned rs, gs, bs, rd, gd, bd; \
188 s = *(Uint16 *)src; \
189 d = *(Uint16 *)dst; \
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]; \
196 s = (src[2] << 16) | (src[1] << 8) | src[0]; \
197 d = (dst[2] << 16) | (dst[1] << 8) | dst[0]; \
201 s = *(Uint32 *)src; \
202 d = *(Uint32 *)dst; \
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); \
213 *(Uint16 *)dst = (Uint16)d; \
216 if (SDL_BYTEORDER == SDL_BIG_ENDIAN) { \
217 dst[0] = (Uint8)(d >> 16); \
218 dst[1] = (Uint8)(d >> 8); \
219 dst[2] = (Uint8)(d); \
222 dst[1] = (Uint8)(d >> 8); \
223 dst[2] = (Uint8)(d >> 16); \
227 *(Uint32 *)dst = d; \
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.
243 #define ALPHA_BLIT32_888_50(to, from, length, bpp, alpha) \
246 Uint32 *src = (Uint32 *)(from); \
247 Uint32 *dst = (Uint32 *)(to); \
248 for(i = 0; i < (int)(length); i++) { \
251 *dst++ = (((s & 0x00fefefe) + (d & 0x00fefefe)) >> 1) \
252 + (s & d & 0x00010101); \
257 * For 16bpp, we can actually blend two pixels in parallel, if we take
258 * care to shift before we add, not after.
261 /* helper: blend a single 16 bit pixel at 50% */
262 #define BLEND16_50(dst, src, mask) \
266 *dst++ = (Uint16)((((s & mask) + (d & mask)) >> 1) + \
267 (s & d & (~mask & 0xffff))); \
270 /* basic 16bpp blender. mask is the pixels to keep when adding. */
271 #define ALPHA_BLIT16_50(to, from, length, bpp, alpha, mask) \
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 */ \
279 BLEND16_50(dst, src, mask); \
281 if ((uintptr_t)src & 3) { \
282 /* first odd pixel */ \
283 BLEND16_50(dst, src, mask); \
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))); \
296 BLEND16_50(dst, src, mask); /* last odd pixel */ \
300 #define ALPHA_BLIT16_565_50(to, from, length, bpp, alpha) \
301 ALPHA_BLIT16_50(to, from, length, bpp, alpha, 0xf7de)
303 #define ALPHA_BLIT16_555_50(to, from, length, bpp, alpha) \
304 ALPHA_BLIT16_50(to, from, length, bpp, alpha, 0xfbde)
306 #define CHOOSE_BLIT(blitter, alpha, fmt) \
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; \
316 switch (fmt->BytesPerPixel) { \
318 /* No 8bpp alpha blitting */ \
322 switch (fmt->Rmask | fmt->Gmask | fmt->Bmask) { \
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); \
330 blitter(2, Uint8, ALPHA_BLIT16_565); \
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); \
343 blitter(2, Uint8, ALPHA_BLIT16_555); \
352 blitter(2, Uint8, ALPHA_BLIT_ANY); \
357 blitter(3, Uint8, ALPHA_BLIT_ANY); \
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); \
367 blitter(4, Uint16, ALPHA_BLIT32_888); \
370 blitter(4, Uint16, ALPHA_BLIT_ANY); \
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.
380 #define RLEPIXEL_FROM_RGBA(Pixel, fmt, r, g, b, a) \
382 Pixel = ((r>>fmt->Rloss)<<fmt->Rshift)| \
383 ((g>>fmt->Gloss)<<fmt->Gshift)| \
384 ((b>>fmt->Bloss)<<fmt->Bshift)| \
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.
393 RLEClipBlit(int w, Uint8 * srcbuf, SDL_Surface * surf_dst,
394 Uint8 * dstbuf, SDL_Rect * srcrect, unsigned alpha)
396 SDL_PixelFormat *fmt = surf_dst->format;
398 #define RLECLIPBLIT(bpp, Type, do_blit) \
400 int linecount = srcrect->h; \
402 int left = srcrect->x; \
403 int right = left + srcrect->w; \
404 dstbuf -= left * bpp; \
407 ofs += *(Type *)srcbuf; \
408 run = ((Type *)srcbuf)[1]; \
409 srcbuf += 2 * sizeof(Type); \
411 /* clip to left and right borders */ \
416 if (left - ofs > 0) { \
417 start = left - ofs; \
420 goto nocopy ## bpp ## do_blit; \
422 startcol = ofs + start; \
423 if (len > right - startcol) \
424 len = right - startcol; \
425 do_blit(dstbuf + startcol * bpp, srcbuf + start * bpp, \
428 nocopy ## bpp ## do_blit: \
429 srcbuf += run * bpp; \
436 dstbuf += surf_dst->pitch; \
443 CHOOSE_BLIT(RLECLIPBLIT, alpha, fmt);
450 /* blit a colorkeyed RLE surface */
452 SDL_RLEBlit(SDL_Surface * surf_src, SDL_Rect * srcrect,
453 SDL_Surface * surf_dst, SDL_Rect * dstrect)
461 /* Lock the destination if necessary */
462 if (SDL_MUSTLOCK(surf_dst)) {
463 if (SDL_LockSurface(surf_dst) < 0) {
468 /* Set up the source and destination pointers */
471 dstbuf = (Uint8 *) surf_dst->pixels
472 + y * surf_dst->pitch + x * surf_src->format->BytesPerPixel;
473 srcbuf = (Uint8 *) surf_src->map->data;
476 /* skip lines at the top if necessary */
477 int vskip = srcrect->y;
481 #define RLESKIP(bpp, Type) \
484 ofs += *(Type *)srcbuf; \
485 run = ((Type *)srcbuf)[1]; \
486 srcbuf += sizeof(Type) * 2; \
488 srcbuf += run * bpp; \
499 switch (surf_src->format->BytesPerPixel) {
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);
524 SDL_PixelFormat *fmt = surf_src->format;
526 #define RLEBLIT(bpp, Type, do_blit) \
528 int linecount = srcrect->h; \
532 ofs += *(Type *)srcbuf; \
533 run = ((Type *)srcbuf)[1]; \
534 srcbuf += 2 * sizeof(Type); \
536 do_blit(dstbuf + ofs * bpp, srcbuf, run, bpp, alpha); \
537 srcbuf += run * bpp; \
543 dstbuf += surf_dst->pitch; \
550 CHOOSE_BLIT(RLEBLIT, alpha, fmt);
556 /* Unlock the destination if necessary */
557 if (SDL_MUSTLOCK(surf_dst)) {
558 SDL_UnlockSurface(surf_dst);
566 * Per-pixel blitting macros for translucent pixels:
567 * These use the same techniques as the per-surface blitting macros
571 * For 32bpp pixels, we have made sure the alpha is stored in the top
572 * 8 bits, so proceed as usual
574 #define BLIT_TRANSL_888(src, dst) \
578 unsigned alpha = s >> 24; \
579 Uint32 s1 = s & 0xff00ff; \
580 Uint32 d1 = d & 0xff00ff; \
581 d1 = (d1 + ((s1 - d1) * alpha >> 8)) & 0xff00ff; \
584 d = (d + ((s - d) * alpha >> 8)) & 0xff00; \
585 dst = d1 | d | 0xff000000; \
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.
592 #define BLIT_TRANSL_565(src, dst) \
596 unsigned alpha = (s & 0x3e0) >> 5; \
598 d = (d | d << 16) & 0x07e0f81f; \
599 d += (s - d) * alpha >> 5; \
601 dst = (Uint16)(d | d >> 16); \
604 #define BLIT_TRANSL_555(src, dst) \
608 unsigned alpha = (s & 0x3e0) >> 5; \
610 d = (d | d << 16) & 0x03e07c1f; \
611 d += (s - d) * alpha >> 5; \
613 dst = (Uint16)(d | d >> 16); \
616 /* used to save the destination format in the encoding. Designed to be
617 macro-compatible with SDL_PixelFormat but without the unneeded fields */
636 /* blit a pixel-alpha RLE surface clipped at the right and/or left edges */
638 RLEAlphaClipBlit(int w, Uint8 * srcbuf, SDL_Surface * surf_dst,
639 Uint8 * dstbuf, SDL_Rect * srcrect)
641 SDL_PixelFormat *df = surf_dst->format;
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.
647 #define RLEALPHACLIPBLIT(Ptype, Ctype, do_blend) \
649 int linecount = srcrect->h; \
650 int left = srcrect->x; \
651 int right = left + srcrect->w; \
652 dstbuf -= left * sizeof(Ptype); \
655 /* blit opaque pixels on one line */ \
658 ofs += ((Ctype *)srcbuf)[0]; \
659 run = ((Ctype *)srcbuf)[1]; \
660 srcbuf += 2 * sizeof(Ctype); \
662 /* clip to left and right borders */ \
665 if(left - cofs > 0) { \
666 crun -= left - cofs; \
669 if(crun > right - cofs) \
670 crun = right - cofs; \
672 PIXEL_COPY(dstbuf + cofs * sizeof(Ptype), \
673 srcbuf + (cofs - ofs) * sizeof(Ptype), \
674 (unsigned)crun, sizeof(Ptype)); \
675 srcbuf += run * sizeof(Ptype); \
680 /* skip padding if necessary */ \
681 if(sizeof(Ptype) == 2) \
682 srcbuf += (uintptr_t)srcbuf & 2; \
683 /* blit translucent pixels on the same line */ \
687 ofs += ((Uint16 *)srcbuf)[0]; \
688 run = ((Uint16 *)srcbuf)[1]; \
691 /* clip to left and right borders */ \
694 if(left - cofs > 0) { \
695 crun -= left - cofs; \
698 if(crun > right - cofs) \
699 crun = right - cofs; \
701 Ptype *dst = (Ptype *)dstbuf + cofs; \
702 Uint32 *src = (Uint32 *)srcbuf + (cofs - ofs); \
704 for(i = 0; i < crun; i++) \
705 do_blend(src[i], dst[i]); \
711 dstbuf += surf_dst->pitch; \
712 } while(--linecount); \
715 switch (df->BytesPerPixel) {
717 if (df->Gmask == 0x07e0 || df->Rmask == 0x07e0 || df->Bmask == 0x07e0)
718 RLEALPHACLIPBLIT(Uint16, Uint8, BLIT_TRANSL_565);
720 RLEALPHACLIPBLIT(Uint16, Uint8, BLIT_TRANSL_555);
723 RLEALPHACLIPBLIT(Uint32, Uint16, BLIT_TRANSL_888);
728 /* blit a pixel-alpha RLE surface */
730 SDL_RLEAlphaBlit(SDL_Surface * surf_src, SDL_Rect * srcrect,
731 SDL_Surface * surf_dst, SDL_Rect * dstrect)
735 Uint8 *srcbuf, *dstbuf;
736 SDL_PixelFormat *df = surf_dst->format;
738 /* Lock the destination if necessary */
739 if (SDL_MUSTLOCK(surf_dst)) {
740 if (SDL_LockSurface(surf_dst) < 0) {
747 dstbuf = (Uint8 *) surf_dst->pixels + y * surf_dst->pitch + x * df->BytesPerPixel;
748 srcbuf = (Uint8 *) surf_src->map->data + sizeof(RLEDestFormat);
751 /* skip lines at the top if necessary */
752 int vskip = srcrect->y;
755 if (df->BytesPerPixel == 2) {
756 /* the 16/32 interleaved format */
758 /* skip opaque line */
773 srcbuf += (uintptr_t) srcbuf & 2;
775 /* skip translucent line */
779 ofs += ((Uint16 *) srcbuf)[0];
780 run = ((Uint16 *) srcbuf)[1];
781 srcbuf += 4 * (run + 1);
786 /* the 32/32 interleaved format */
787 vskip <<= 1; /* opaque and translucent have same format */
792 ofs += ((Uint16 *) srcbuf)[0];
793 run = ((Uint16 *) srcbuf)[1];
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);
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.
816 #define RLEALPHABLIT(Ptype, Ctype, do_blend) \
818 int linecount = srcrect->h; \
821 /* blit opaque pixels on one line */ \
824 ofs += ((Ctype *)srcbuf)[0]; \
825 run = ((Ctype *)srcbuf)[1]; \
826 srcbuf += 2 * sizeof(Ctype); \
828 PIXEL_COPY(dstbuf + ofs * sizeof(Ptype), srcbuf, \
829 run, sizeof(Ptype)); \
830 srcbuf += run * sizeof(Ptype); \
835 /* skip padding if necessary */ \
836 if(sizeof(Ptype) == 2) \
837 srcbuf += (uintptr_t)srcbuf & 2; \
838 /* blit translucent pixels on the same line */ \
842 ofs += ((Uint16 *)srcbuf)[0]; \
843 run = ((Uint16 *)srcbuf)[1]; \
846 Ptype *dst = (Ptype *)dstbuf + ofs; \
848 for(i = 0; i < run; i++) { \
849 Uint32 src = *(Uint32 *)srcbuf; \
850 do_blend(src, *dst); \
857 dstbuf += surf_dst->pitch; \
858 } while(--linecount); \
861 switch (df->BytesPerPixel) {
863 if (df->Gmask == 0x07e0 || df->Rmask == 0x07e0
864 || df->Bmask == 0x07e0)
865 RLEALPHABLIT(Uint16, Uint8, BLIT_TRANSL_565);
867 RLEALPHABLIT(Uint16, Uint8, BLIT_TRANSL_555);
870 RLEALPHABLIT(Uint32, Uint16, BLIT_TRANSL_888);
876 /* Unlock the destination if necessary */
877 if (SDL_MUSTLOCK(surf_dst)) {
878 SDL_UnlockSurface(surf_dst);
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
893 /* encode 32bpp rgb + a into 16bpp rgb, losing alpha */
895 copy_opaque_16(void *dst, Uint32 * src, int n,
896 SDL_PixelFormat * sfmt, SDL_PixelFormat * dfmt)
900 for (i = 0; i < n; i++) {
902 RGB_FROM_PIXEL(*src, sfmt, r, g, b);
903 PIXEL_FROM_RGB(*d, dfmt, r, g, b);
910 /* decode opaque pixels from 16bpp to 32bpp rgb + a */
912 uncopy_opaque_16(Uint32 * dst, void *src, int n,
913 RLEDestFormat * sfmt, SDL_PixelFormat * dfmt)
917 unsigned alpha = dfmt->Amask ? 255 : 0;
918 for (i = 0; i < n; i++) {
920 RGB_FROM_PIXEL(*s, sfmt, r, g, b);
921 PIXEL_FROM_RGBA(*dst, dfmt, r, g, b, alpha);
930 /* encode 32bpp rgb + a into 32bpp G0RAB format for blitting into 565 */
932 copy_transl_565(void *dst, Uint32 * src, int n,
933 SDL_PixelFormat * sfmt, SDL_PixelFormat * dfmt)
937 for (i = 0; i < n; i++) {
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);
949 /* encode 32bpp rgb + a into 32bpp G0RAB format for blitting into 555 */
951 copy_transl_555(void *dst, Uint32 * src, int n,
952 SDL_PixelFormat * sfmt, SDL_PixelFormat * dfmt)
956 for (i = 0; i < n; i++) {
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);
968 /* decode translucent pixels from 32bpp GORAB to 32bpp rgb + a */
970 uncopy_transl_16(Uint32 * dst, void *src, int n,
971 RLEDestFormat * sfmt, SDL_PixelFormat * dfmt)
975 for (i = 0; i < n; i++) {
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);
987 /* encode 32bpp rgba into 32bpp rgba, keeping alpha (dual purpose) */
989 copy_32(void *dst, Uint32 * src, int n,
990 SDL_PixelFormat * sfmt, SDL_PixelFormat * dfmt)
994 for (i = 0; i < n; i++) {
996 RGBA_FROM_8888(*src, sfmt, r, g, b, a);
997 RLEPIXEL_FROM_RGBA(*d, dfmt, r, g, b, a);
1004 /* decode 32bpp rgba into 32bpp rgba, keeping alpha (dual purpose) */
1006 uncopy_32(Uint32 * dst, void *src, int n,
1007 RLEDestFormat * sfmt, SDL_PixelFormat * dfmt)
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);
1016 PIXEL_FROM_RGBA(*dst, dfmt, r, g, b, a);
1022 #define ISOPAQUE(pixel, fmt) ((((pixel) & fmt->Amask) >> fmt->Ashift) == 255)
1024 #define ISTRANSL(pixel, fmt) \
1025 ((unsigned)((((pixel) & fmt->Amask) >> fmt->Ashift) - 1U) < 254U)
1027 /* convert surface to be quickly alpha-blittable onto dest, if possible */
1029 RLEAlphaSurface(SDL_Surface * surface)
1032 SDL_PixelFormat *df;
1035 int max_transl_run = 65535;
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 *);
1043 dest = surface->map->dst;
1047 if (surface->format->BitsPerPixel != 32)
1048 return -1; /* only 32bpp source supported */
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) {
1055 /* 16bpp: only support 565 and 555 formats */
1058 if (df->Gmask == 0x07e0
1059 || df->Rmask == 0x07e0 || df->Bmask == 0x07e0) {
1060 copy_opaque = copy_opaque_16;
1061 copy_transl = copy_transl_565;
1066 if (df->Gmask == 0x03e0
1067 || df->Rmask == 0x03e0 || df->Bmask == 0x03e0) {
1068 copy_opaque = copy_opaque_16;
1069 copy_transl = copy_transl_555;
1076 max_opaque_run = 255; /* runs stored as bytes */
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;
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 */
1089 /* worst case is alternating opaque and translucent pixels */
1090 maxsize = surface->h * 2 * 4 * (surface->w + 1) + 4;
1093 return -1; /* anything else unsupported right now */
1096 maxsize += sizeof(RLEDestFormat);
1097 rlebuf = (Uint8 *) SDL_malloc(maxsize);
1099 return SDL_OutOfMemory();
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;
1118 dst = rlebuf + sizeof(RLEDestFormat);
1120 /* Do the actual encoding */
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 */
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; \
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)
1144 for (y = 0; y < h; y++) {
1145 int runstart, skipstart;
1147 /* First encode all opaque pixels of a scan line */
1152 while (x < w && !ISOPAQUE(src[x], sf))
1155 while (x < w && ISOPAQUE(src[x], sf))
1157 skip = runstart - skipstart;
1161 while (skip > max_opaque_run) {
1162 ADD_OPAQUE_COUNTS(max_opaque_run, 0);
1163 skip -= max_opaque_run;
1165 len = MIN(run, max_opaque_run);
1166 ADD_OPAQUE_COUNTS(skip, len);
1167 dst += copy_opaque(dst, src + runstart, len, sf, df);
1171 len = MIN(run, max_opaque_run);
1172 ADD_OPAQUE_COUNTS(0, len);
1173 dst += copy_opaque(dst, src + runstart, len, sf, df);
1179 /* Make sure the next output address is 32-bit aligned */
1180 dst += (uintptr_t) dst & 2;
1182 /* Next, encode all translucent pixels of the same scan line */
1187 while (x < w && !ISTRANSL(src[x], sf))
1190 while (x < w && ISTRANSL(src[x], sf))
1192 skip = runstart - skipstart;
1193 blankline &= (skip == w);
1195 while (skip > max_transl_run) {
1196 ADD_TRANSL_COUNTS(max_transl_run, 0);
1197 skip -= max_transl_run;
1199 len = MIN(run, max_transl_run);
1200 ADD_TRANSL_COUNTS(skip, len);
1201 dst += copy_transl(dst, src + runstart, len, sf, df);
1205 len = MIN(run, max_transl_run);
1206 ADD_TRANSL_COUNTS(0, len);
1207 dst += copy_transl(dst, src + runstart, len, sf, df);
1215 src += surface->pitch >> 2;
1217 dst = lastline; /* back up past trailing blank lines */
1218 ADD_OPAQUE_COUNTS(0, 0);
1221 #undef ADD_OPAQUE_COUNTS
1222 #undef ADD_TRANSL_COUNTS
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;
1230 /* realloc the buffer to release unused memory */
1232 Uint8 *p = SDL_realloc(rlebuf, dst - rlebuf);
1235 surface->map->data = p;
1242 getpix_8(Uint8 * srcbuf)
1248 getpix_16(Uint8 * srcbuf)
1250 return *(Uint16 *) srcbuf;
1254 getpix_24(Uint8 * srcbuf)
1256 #if SDL_BYTEORDER == SDL_LIL_ENDIAN
1257 return srcbuf[0] + (srcbuf[1] << 8) + (srcbuf[2] << 16);
1259 return (srcbuf[0] << 16) + (srcbuf[1] << 8) + srcbuf[2];
1264 getpix_32(Uint8 * srcbuf)
1266 return *(Uint32 *) srcbuf;
1269 typedef Uint32(*getpix_func) (Uint8 *);
1271 static const getpix_func getpixes[4] = {
1272 getpix_8, getpix_16, getpix_24, getpix_32
1276 RLEColorkeySurface(SDL_Surface * surface)
1278 Uint8 *rlebuf, *dst;
1281 Uint8 *srcbuf, *lastline;
1283 int bpp = surface->format->BytesPerPixel;
1285 Uint32 ckey, rgbmask;
1288 /* calculate the worst case size for the compressed surface */
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;
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;
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;
1308 rlebuf = (Uint8 *) SDL_malloc(maxsize);
1309 if (rlebuf == NULL) {
1310 return SDL_OutOfMemory();
1313 /* Set up the conversion */
1314 srcbuf = (Uint8 *) surface->pixels;
1315 maxn = bpp == 4 ? 65535 : 255;
1317 rgbmask = ~surface->format->Amask;
1318 ckey = surface->map->info.colorkey & rgbmask;
1320 getpix = getpixes[bpp - 1];
1324 #define ADD_COUNTS(n, m) \
1326 ((Uint16 *)dst)[0] = n; \
1327 ((Uint16 *)dst)[1] = m; \
1335 for (y = 0; y < h; y++) {
1343 /* find run of transparent, then opaque pixels */
1344 while (x < w && (getpix(srcbuf + x * bpp) & rgbmask) == ckey)
1347 while (x < w && (getpix(srcbuf + x * bpp) & rgbmask) != ckey)
1349 skip = runstart - skipstart;
1354 /* encode segment */
1355 while (skip > maxn) {
1356 ADD_COUNTS(maxn, 0);
1359 len = MIN(run, maxn);
1360 ADD_COUNTS(skip, len);
1361 SDL_memcpy(dst, srcbuf + runstart * bpp, len * bpp);
1366 len = MIN(run, maxn);
1368 SDL_memcpy(dst, srcbuf + runstart * bpp, len * bpp);
1377 srcbuf += surface->pitch;
1379 dst = lastline; /* back up bast trailing blank lines */
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;
1390 /* realloc the buffer to release unused memory */
1392 /* If realloc returns NULL, the original block is left intact */
1393 Uint8 *p = SDL_realloc(rlebuf, dst - rlebuf);
1396 surface->map->data = p;
1403 SDL_RLESurface(SDL_Surface * surface)
1407 /* Clear any previous RLE conversion */
1408 if ((surface->flags & SDL_RLEACCEL) == SDL_RLEACCEL) {
1409 SDL_UnRLESurface(surface, 1);
1412 /* We don't support RLE encoding of bitmaps */
1413 if (surface->format->BitsPerPixel < 8) {
1417 /* Make sure the pixels are available */
1418 if (!surface->pixels) {
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))) {
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)) {
1436 /* Encode and set up the blit */
1437 if (!surface->format->Amask || !(flags & SDL_COPY_BLEND)) {
1438 if (!surface->map->identity) {
1441 if (RLEColorkeySurface(surface) < 0) {
1444 surface->map->blit = SDL_RLEBlit;
1445 surface->map->info.flags |= SDL_COPY_RLE_COLORKEY;
1447 if (RLEAlphaSurface(surface) < 0) {
1450 surface->map->blit = SDL_RLEAlphaBlit;
1451 surface->map->info.flags |= SDL_COPY_RLE_ALPHAKEY;
1454 /* The surface is now accelerated */
1455 surface->flags |= SDL_RLEACCEL;
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).
1467 UnRLEAlpha(SDL_Surface * surface)
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 *);
1478 int bpp = df->BytesPerPixel;
1481 uncopy_opaque = uncopy_opaque_16;
1482 uncopy_transl = uncopy_transl_16;
1484 uncopy_opaque = uncopy_transl = uncopy_32;
1487 surface->pixels = SDL_malloc(surface->h * surface->pitch);
1488 if (!surface->pixels) {
1491 /* fill background with transparent pixels */
1492 SDL_memset(surface->pixels, 0, surface->h * surface->pitch);
1494 dst = surface->pixels;
1495 srcbuf = (Uint8 *) (df + 1);
1497 /* copy opaque pixels */
1506 ofs += ((Uint16 *) srcbuf)[0];
1507 run = ((Uint16 *) srcbuf)[1];
1511 srcbuf += uncopy_opaque(dst + ofs, srcbuf, run, df, sf);
1517 /* skip padding if needed */
1519 srcbuf += (uintptr_t) srcbuf & 2;
1521 /* copy translucent pixels */
1525 ofs += ((Uint16 *) srcbuf)[0];
1526 run = ((Uint16 *) srcbuf)[1];
1529 srcbuf += uncopy_transl(dst + ofs, srcbuf, run, df, sf);
1533 dst += surface->pitch >> 2;
1535 /* Make the compiler happy */
1540 SDL_UnRLESurface(SDL_Surface * surface, int recode)
1542 if (surface->flags & SDL_RLEACCEL) {
1543 surface->flags &= ~SDL_RLEACCEL;
1545 if (recode && !(surface->flags & SDL_PREALLOC)) {
1546 if (surface->map->info.flags & SDL_COPY_RLE_COLORKEY) {
1549 /* re-create the original surface */
1550 surface->pixels = SDL_malloc(surface->h * surface->pitch);
1551 if (!surface->pixels) {
1553 surface->flags |= SDL_RLEACCEL;
1557 /* fill it with the background color */
1558 SDL_FillRect(surface, NULL, surface->map->info.colorkey);
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);
1566 if (!UnRLEAlpha(surface)) {
1568 surface->flags |= SDL_RLEACCEL;
1573 surface->map->info.flags &=
1574 ~(SDL_COPY_RLE_COLORKEY | SDL_COPY_RLE_ALPHAKEY);
1576 SDL_free(surface->map->data);
1577 surface->map->data = NULL;
1581 /* vi: set ts=4 sw=4 expandtab: */