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