comparison src/video/SDL_RLEaccel.c @ 0:74212992fb08

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