src/video/SDL_RLEaccel.c
author Bob Pendleton <bob@pendleton.com>
Fri, 14 Mar 2008 18:17:49 +0000
changeset 2328 91e601d9df8b
parent 2267 c785543d1843
child 2669 e27bdcc80744
permissions -rw-r--r--
re: bug#563. checking in some commented out trace code and a fix so that the in testalpha.c the background only flashes when alpha == 255. The problem that is being
fixed is caused by clearing SDL_COPY_RLE_COLORKEY without setting SDL_COPY_RLE_DESIRED in SDL_UnRELSurface.
     1 /*
     2     SDL - Simple DirectMedia Layer
     3     Copyright (C) 1997-2006 Sam Lantinga
     4 
     5     This library is free software; you can redistribute it and/or
     6     modify it under the terms of the GNU Lesser General Public
     7     License as published by the Free Software Foundation; either
     8     version 2.1 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     Lesser General Public License for more details.
    14 
    15     You should have received a copy of the GNU Lesser General Public
    16     License along with this library; if not, write to the Free Software
    17     Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
    18 
    19     Sam Lantinga
    20     slouken@libsdl.org
    21 */
    22 #include "SDL_config.h"
    23 
    24 /*
    25  * RLE encoding for software colorkey and alpha-channel acceleration
    26  *
    27  * Original version by Sam Lantinga
    28  *
    29  * Mattias Engdegård (Yorick): Rewrite. New encoding format, encoder and
    30  * decoder. Added per-surface alpha blitter. Added per-pixel alpha
    31  * format, encoder and blitter.
    32  *
    33  * Many thanks to Xark and johns for hints, benchmarks and useful comments
    34  * leading to this code.
    35  *
    36  * Welcome to Macro Mayhem.
    37  */
    38 
    39 /*
    40  * The encoding translates the image data to a stream of segments of the form
    41  *
    42  * <skip> <run> <data>
    43  *
    44  * where <skip> is the number of transparent pixels to skip,
    45  *       <run>  is the number of opaque pixels to blit,
    46  * and   <data> are the pixels themselves.
    47  *
    48  * This basic structure is used both for colorkeyed surfaces, used for simple
    49  * binary transparency and for per-surface alpha blending, and for surfaces
    50  * with per-pixel alpha. The details differ, however:
    51  *
    52  * Encoding of colorkeyed surfaces:
    53  *
    54  *   Encoded pixels always have the same format as the target surface.
    55  *   <skip> and <run> are unsigned 8 bit integers, except for 32 bit depth
    56  *   where they are 16 bit. This makes the pixel data aligned at all times.
    57  *   Segments never wrap around from one scan line to the next.
    58  *
    59  *   The end of the sequence is marked by a zero <skip>,<run> pair at the *
    60  *   beginning of a line.
    61  *
    62  * Encoding of surfaces with per-pixel alpha:
    63  *
    64  *   The sequence begins with a struct RLEDestFormat describing the target
    65  *   pixel format, to provide reliable un-encoding.
    66  *
    67  *   Each scan line is encoded twice: First all completely opaque pixels,
    68  *   encoded in the target format as described above, and then all
    69  *   partially transparent (translucent) pixels (where 1 <= alpha <= 254),
    70  *   in the following 32-bit format:
    71  *
    72  *   For 32-bit targets, each pixel has the target RGB format but with
    73  *   the alpha value occupying the highest 8 bits. The <skip> and <run>
    74  *   counts are 16 bit.
    75  * 
    76  *   For 16-bit targets, each pixel has the target RGB format, but with
    77  *   the middle component (usually green) shifted 16 steps to the left,
    78  *   and the hole filled with the 5 most significant bits of the alpha value.
    79  *   i.e. if the target has the format         rrrrrggggggbbbbb,
    80  *   the encoded pixel will be 00000gggggg00000rrrrr0aaaaabbbbb.
    81  *   The <skip> and <run> counts are 8 bit for the opaque lines, 16 bit
    82  *   for the translucent lines. Two padding bytes may be inserted
    83  *   before each translucent line to keep them 32-bit aligned.
    84  *
    85  *   The end of the sequence is marked by a zero <skip>,<run> pair at the
    86  *   beginning of an opaque line.
    87  */
    88 
    89 #include "SDL_video.h"
    90 #include "SDL_sysvideo.h"
    91 #include "SDL_blit.h"
    92 #include "SDL_RLEaccel_c.h"
    93 
    94 #if defined(__GNUC__) && (defined(__i386__) || defined(__x86_64__)) && SDL_ASSEMBLY_ROUTINES
    95 #define MMX_ASMBLIT
    96 #endif
    97 
    98 #ifdef MMX_ASMBLIT
    99 #include "mmx.h"
   100 #include "SDL_cpuinfo.h"
   101 #endif
   102 
   103 #ifndef MAX
   104 #define MAX(a, b) ((a) > (b) ? (a) : (b))
   105 #endif
   106 #ifndef MIN
   107 #define MIN(a, b) ((a) < (b) ? (a) : (b))
   108 #endif
   109 
   110 #define PIXEL_COPY(to, from, len, bpp)			\
   111 do {							\
   112     if(bpp == 4) {					\
   113 	SDL_memcpy4(to, from, (size_t)(len));		\
   114     } else {						\
   115 	SDL_memcpy(to, from, (size_t)(len) * (bpp));	\
   116     }							\
   117 } while(0)
   118 
   119 /*
   120  * Various colorkey blit methods, for opaque and per-surface alpha
   121  */
   122 
   123 #define OPAQUE_BLIT(to, from, length, bpp, alpha)	\
   124     PIXEL_COPY(to, from, length, bpp)
   125 
   126 #ifdef MMX_ASMBLIT
   127 
   128 #define ALPHA_BLIT32_888MMX(to, from, length, bpp, alpha)	\
   129     do {							\
   130 	Uint32 *srcp = (Uint32 *)(from);			\
   131 	Uint32 *dstp = (Uint32 *)(to);				\
   132         int i = 0x00FF00FF;					\
   133         movd_m2r(*(&i), mm3);					\
   134         punpckldq_r2r(mm3, mm3);				\
   135         i = 0xFF000000;						\
   136         movd_m2r(*(&i), mm7);					\
   137         punpckldq_r2r(mm7, mm7);				\
   138         i = alpha | alpha << 16;				\
   139         movd_m2r(*(&i), mm4);					\
   140         punpckldq_r2r(mm4, mm4);				\
   141 	pcmpeqd_r2r(mm5,mm5); /* set mm5 to "1" */		\
   142 	pxor_r2r(mm7, mm5); /* make clear alpha mask */		\
   143         i = length;						\
   144 	if(i & 1) {						\
   145           movd_m2r((*srcp), mm1); /* src -> mm1 */		\
   146           punpcklbw_r2r(mm1, mm1);				\
   147           pand_r2r(mm3, mm1);					\
   148 	  movd_m2r((*dstp), mm2); /* dst -> mm2 */		\
   149           punpcklbw_r2r(mm2, mm2);				\
   150           pand_r2r(mm3, mm2);					\
   151 	  psubw_r2r(mm2, mm1);					\
   152 	  pmullw_r2r(mm4, mm1);					\
   153 	  psrlw_i2r(8, mm1);					\
   154 	  paddw_r2r(mm1, mm2);					\
   155 	  pand_r2r(mm3, mm2);					\
   156 	  packuswb_r2r(mm2, mm2);				\
   157 	  pand_r2r(mm5, mm2); /* 00000RGB -> mm2 */		\
   158 	  movd_r2m(mm2, *dstp);					\
   159 	  ++srcp;						\
   160 	  ++dstp;						\
   161 	  i--;							\
   162 	}							\
   163 	for(; i > 0; --i) {					\
   164           movq_m2r((*srcp), mm0);				\
   165 	  movq_r2r(mm0, mm1);					\
   166           punpcklbw_r2r(mm0, mm0);				\
   167 	  movq_m2r((*dstp), mm2);				\
   168 	  punpckhbw_r2r(mm1, mm1);				\
   169 	  movq_r2r(mm2, mm6);					\
   170           pand_r2r(mm3, mm0);					\
   171           punpcklbw_r2r(mm2, mm2);				\
   172 	  pand_r2r(mm3, mm1);					\
   173 	  punpckhbw_r2r(mm6, mm6);				\
   174           pand_r2r(mm3, mm2);					\
   175 	  psubw_r2r(mm2, mm0);					\
   176 	  pmullw_r2r(mm4, mm0);					\
   177 	  pand_r2r(mm3, mm6);					\
   178 	  psubw_r2r(mm6, mm1);					\
   179 	  pmullw_r2r(mm4, mm1);					\
   180 	  psrlw_i2r(8, mm0);					\
   181 	  paddw_r2r(mm0, mm2);					\
   182 	  psrlw_i2r(8, mm1);					\
   183 	  paddw_r2r(mm1, mm6);					\
   184 	  pand_r2r(mm3, mm2);					\
   185 	  pand_r2r(mm3, mm6);					\
   186 	  packuswb_r2r(mm2, mm2);				\
   187 	  packuswb_r2r(mm6, mm6);				\
   188 	  psrlq_i2r(32, mm2);					\
   189 	  psllq_i2r(32, mm6);					\
   190 	  por_r2r(mm6, mm2);					\
   191 	  pand_r2r(mm5, mm2); /* 00000RGB -> mm2 */		\
   192          movq_r2m(mm2, *dstp);					\
   193 	  srcp += 2;						\
   194 	  dstp += 2;						\
   195 	  i--;							\
   196 	}							\
   197 	emms();							\
   198     } while(0)
   199 
   200 #define ALPHA_BLIT16_565MMX(to, from, length, bpp, alpha)	\
   201     do {						\
   202         int i, n = 0;					\
   203 	Uint16 *srcp = (Uint16 *)(from);		\
   204 	Uint16 *dstp = (Uint16 *)(to);			\
   205         Uint32 ALPHA = 0xF800;				\
   206 	movd_m2r(*(&ALPHA), mm1);			\
   207         punpcklwd_r2r(mm1, mm1);			\
   208         punpcklwd_r2r(mm1, mm1);			\
   209 	ALPHA = 0x07E0;					\
   210 	movd_m2r(*(&ALPHA), mm4);			\
   211         punpcklwd_r2r(mm4, mm4);			\
   212         punpcklwd_r2r(mm4, mm4);			\
   213 	ALPHA = 0x001F;					\
   214 	movd_m2r(*(&ALPHA), mm7);			\
   215         punpcklwd_r2r(mm7, mm7);			\
   216         punpcklwd_r2r(mm7, mm7);			\
   217 	alpha &= ~(1+2+4);				\
   218         i = (Uint32)alpha | (Uint32)alpha << 16;	\
   219         movd_m2r(*(&i), mm0);				\
   220         punpckldq_r2r(mm0, mm0);			\
   221         ALPHA = alpha >> 3;				\
   222         i = ((int)(length) & 3);			\
   223 	for(; i > 0; --i) {				\
   224 	    Uint32 s = *srcp++;				\
   225 	    Uint32 d = *dstp;				\
   226 	    s = (s | s << 16) & 0x07e0f81f;		\
   227 	    d = (d | d << 16) & 0x07e0f81f;		\
   228 	    d += (s - d) * ALPHA >> 5;			\
   229 	    d &= 0x07e0f81f;				\
   230 	    *dstp++ = d | d >> 16;			\
   231 	    n++;					\
   232 	}						\
   233 	i = (int)(length) - n;				\
   234 	for(; i > 0; --i) {				\
   235 	  movq_m2r((*dstp), mm3);			\
   236 	  movq_m2r((*srcp), mm2);			\
   237 	  movq_r2r(mm2, mm5);				\
   238 	  pand_r2r(mm1 , mm5);				\
   239 	  psrlq_i2r(11, mm5);				\
   240 	  movq_r2r(mm3, mm6);				\
   241 	  pand_r2r(mm1 , mm6);				\
   242 	  psrlq_i2r(11, mm6);				\
   243 	  psubw_r2r(mm6, mm5);				\
   244 	  pmullw_r2r(mm0, mm5);				\
   245 	  psrlw_i2r(8, mm5);				\
   246 	  paddw_r2r(mm5, mm6);				\
   247 	  psllq_i2r(11, mm6);				\
   248 	  pand_r2r(mm1, mm6);				\
   249 	  movq_r2r(mm4, mm5);				\
   250 	  por_r2r(mm7, mm5);				\
   251 	  pand_r2r(mm5, mm3);				\
   252 	  por_r2r(mm6, mm3);				\
   253 	  movq_r2r(mm2, mm5);				\
   254 	  pand_r2r(mm4 , mm5);				\
   255 	  psrlq_i2r(5, mm5);				\
   256 	  movq_r2r(mm3, mm6);				\
   257 	  pand_r2r(mm4 , mm6);				\
   258 	  psrlq_i2r(5, mm6);				\
   259 	  psubw_r2r(mm6, mm5);				\
   260 	  pmullw_r2r(mm0, mm5);				\
   261 	  psrlw_i2r(8, mm5);				\
   262 	  paddw_r2r(mm5, mm6);				\
   263 	  psllq_i2r(5, mm6);				\
   264 	  pand_r2r(mm4, mm6);				\
   265 	  movq_r2r(mm1, mm5);				\
   266 	  por_r2r(mm7, mm5);				\
   267 	  pand_r2r(mm5, mm3);				\
   268 	  por_r2r(mm6, mm3);				\
   269 	  movq_r2r(mm2, mm5);				\
   270 	  pand_r2r(mm7 , mm5);				\
   271           movq_r2r(mm3, mm6);				\
   272 	  pand_r2r(mm7 , mm6);				\
   273 	  psubw_r2r(mm6, mm5);				\
   274 	  pmullw_r2r(mm0, mm5);				\
   275 	  psrlw_i2r(8, mm5);				\
   276 	  paddw_r2r(mm5, mm6);				\
   277 	  pand_r2r(mm7, mm6);				\
   278 	  movq_r2r(mm1, mm5);				\
   279 	  por_r2r(mm4, mm5);				\
   280 	  pand_r2r(mm5, mm3);				\
   281 	  por_r2r(mm6, mm3);				\
   282 	  movq_r2m(mm3, *dstp);				\
   283 	  srcp += 4;					\
   284 	  dstp += 4;					\
   285 	  i -= 3;					\
   286 	}						\
   287 	emms();						\
   288     } while(0)
   289 
   290 #define ALPHA_BLIT16_555MMX(to, from, length, bpp, alpha)	\
   291     do {						\
   292         int i, n = 0;					\
   293 	Uint16 *srcp = (Uint16 *)(from);		\
   294 	Uint16 *dstp = (Uint16 *)(to);			\
   295         Uint32 ALPHA = 0x7C00;				\
   296 	movd_m2r(*(&ALPHA), mm1);			\
   297         punpcklwd_r2r(mm1, mm1);			\
   298         punpcklwd_r2r(mm1, mm1);			\
   299 	ALPHA = 0x03E0;					\
   300         movd_m2r(*(&ALPHA), mm4);			\
   301         punpcklwd_r2r(mm4, mm4);			\
   302         punpcklwd_r2r(mm4, mm4);			\
   303 	ALPHA = 0x001F;					\
   304 	movd_m2r(*(&ALPHA), mm7);			\
   305         punpcklwd_r2r(mm7, mm7);			\
   306         punpcklwd_r2r(mm7, mm7);			\
   307 	alpha &= ~(1+2+4);				\
   308         i = (Uint32)alpha | (Uint32)alpha << 16;	\
   309         movd_m2r(*(&i), mm0);				\
   310         punpckldq_r2r(mm0, mm0);			\
   311         i = ((int)(length) & 3);				\
   312         ALPHA = alpha >> 3;				\
   313 	for(; i > 0; --i) {				\
   314 	    Uint32 s = *srcp++;				\
   315 	    Uint32 d = *dstp;				\
   316 	    s = (s | s << 16) & 0x03e07c1f;		\
   317 	    d = (d | d << 16) & 0x03e07c1f;		\
   318 	    d += (s - d) * ALPHA >> 5;			\
   319 	    d &= 0x03e07c1f;				\
   320 	    *dstp++ = d | d >> 16;			\
   321 	    n++;					\
   322 	}						\
   323 	i = (int)(length) - n;				\
   324 	for(; i > 0; --i) {				\
   325 	  movq_m2r((*dstp), mm3);			\
   326 	  movq_m2r((*srcp), mm2);			\
   327 	  movq_r2r(mm2, mm5);				\
   328 	  pand_r2r(mm1 , mm5);				\
   329 	  psrlq_i2r(10, mm5);				\
   330 	  movq_r2r(mm3, mm6);				\
   331 	  pand_r2r(mm1 , mm6);				\
   332 	  psrlq_i2r(10, mm6);				\
   333 	  psubw_r2r(mm6, mm5);				\
   334 	  pmullw_r2r(mm0, mm5);				\
   335 	  psrlw_i2r(8, mm5);				\
   336 	  paddw_r2r(mm5, mm6);				\
   337 	  psllq_i2r(10, mm6);				\
   338 	  pand_r2r(mm1, mm6);				\
   339 	  movq_r2r(mm4, mm5);				\
   340 	  por_r2r(mm7, mm5);				\
   341 	  pand_r2r(mm5, mm3);				\
   342 	  por_r2r(mm6, mm3);				\
   343 	  movq_r2r(mm2, mm5);				\
   344 	  pand_r2r(mm4 , mm5);				\
   345 	  psrlq_i2r(5, mm5);				\
   346 	  movq_r2r(mm3, mm6);				\
   347 	  pand_r2r(mm4 , mm6);				\
   348 	  psrlq_i2r(5, mm6);				\
   349 	  psubw_r2r(mm6, mm5);				\
   350 	  pmullw_r2r(mm0, mm5);				\
   351 	  psrlw_i2r(8, mm5);				\
   352 	  paddw_r2r(mm5, mm6);				\
   353 	  psllq_i2r(5, mm6);				\
   354 	  pand_r2r(mm4, mm6);				\
   355 	  movq_r2r(mm1, mm5);				\
   356 	  por_r2r(mm7, mm5);				\
   357 	  pand_r2r(mm5, mm3);				\
   358 	  por_r2r(mm6, mm3);				\
   359 	  movq_r2r(mm2, mm5);				\
   360 	  pand_r2r(mm7 , mm5);				\
   361           movq_r2r(mm3, mm6);				\
   362 	  pand_r2r(mm7 , mm6);				\
   363 	  psubw_r2r(mm6, mm5);				\
   364 	  pmullw_r2r(mm0, mm5);				\
   365 	  psrlw_i2r(8, mm5);				\
   366 	  paddw_r2r(mm5, mm6);				\
   367 	  pand_r2r(mm7, mm6);				\
   368 	  movq_r2r(mm1, mm5);				\
   369 	  por_r2r(mm4, mm5);				\
   370 	  pand_r2r(mm5, mm3);				\
   371 	  por_r2r(mm6, mm3);				\
   372 	  movq_r2m(mm3, *dstp);				\
   373 	  srcp += 4;					\
   374 	  dstp += 4;					\
   375 	  i -= 3;					\
   376 	}						\
   377 	emms();						\
   378     } while(0)
   379 
   380 #endif
   381 
   382 /*
   383  * For 32bpp pixels on the form 0x00rrggbb:
   384  * If we treat the middle component separately, we can process the two
   385  * remaining in parallel. This is safe to do because of the gap to the left
   386  * of each component, so the bits from the multiplication don't collide.
   387  * This can be used for any RGB permutation of course.
   388  */
   389 #define ALPHA_BLIT32_888(to, from, length, bpp, alpha)		\
   390     do {							\
   391         int i;							\
   392 	Uint32 *src = (Uint32 *)(from);				\
   393 	Uint32 *dst = (Uint32 *)(to);				\
   394 	for(i = 0; i < (int)(length); i++) {			\
   395 	    Uint32 s = *src++;					\
   396 	    Uint32 d = *dst;					\
   397 	    Uint32 s1 = s & 0xff00ff;				\
   398 	    Uint32 d1 = d & 0xff00ff;				\
   399 	    d1 = (d1 + ((s1 - d1) * alpha >> 8)) & 0xff00ff;	\
   400 	    s &= 0xff00;					\
   401 	    d &= 0xff00;					\
   402 	    d = (d + ((s - d) * alpha >> 8)) & 0xff00;		\
   403 	    *dst++ = d1 | d;					\
   404 	}							\
   405     } while(0)
   406 
   407 /*
   408  * For 16bpp pixels we can go a step further: put the middle component
   409  * in the high 16 bits of a 32 bit word, and process all three RGB
   410  * components at the same time. Since the smallest gap is here just
   411  * 5 bits, we have to scale alpha down to 5 bits as well.
   412  */
   413 #define ALPHA_BLIT16_565(to, from, length, bpp, alpha)	\
   414     do {						\
   415         int i;						\
   416 	Uint16 *src = (Uint16 *)(from);			\
   417 	Uint16 *dst = (Uint16 *)(to);			\
   418 	Uint32 ALPHA = alpha >> 3;			\
   419 	for(i = 0; i < (int)(length); i++) {		\
   420 	    Uint32 s = *src++;				\
   421 	    Uint32 d = *dst;				\
   422 	    s = (s | s << 16) & 0x07e0f81f;		\
   423 	    d = (d | d << 16) & 0x07e0f81f;		\
   424 	    d += (s - d) * ALPHA >> 5;			\
   425 	    d &= 0x07e0f81f;				\
   426 	    *dst++ = (Uint16)(d | d >> 16);			\
   427 	}						\
   428     } while(0)
   429 
   430 #define ALPHA_BLIT16_555(to, from, length, bpp, alpha)	\
   431     do {						\
   432         int i;						\
   433 	Uint16 *src = (Uint16 *)(from);			\
   434 	Uint16 *dst = (Uint16 *)(to);			\
   435 	Uint32 ALPHA = alpha >> 3;			\
   436 	for(i = 0; i < (int)(length); i++) {		\
   437 	    Uint32 s = *src++;				\
   438 	    Uint32 d = *dst;				\
   439 	    s = (s | s << 16) & 0x03e07c1f;		\
   440 	    d = (d | d << 16) & 0x03e07c1f;		\
   441 	    d += (s - d) * ALPHA >> 5;			\
   442 	    d &= 0x03e07c1f;				\
   443 	    *dst++ = (Uint16)(d | d >> 16);			\
   444 	}						\
   445     } while(0)
   446 
   447 /*
   448  * The general slow catch-all function, for remaining depths and formats
   449  */
   450 #define ALPHA_BLIT_ANY(to, from, length, bpp, alpha)			\
   451     do {								\
   452         int i;								\
   453 	Uint8 *src = from;						\
   454 	Uint8 *dst = to;						\
   455 	for(i = 0; i < (int)(length); i++) {				\
   456 	    Uint32 s, d;						\
   457 	    unsigned rs, gs, bs, rd, gd, bd;				\
   458 	    switch(bpp) {						\
   459 	    case 2:							\
   460 		s = *(Uint16 *)src;					\
   461 		d = *(Uint16 *)dst;					\
   462 		break;							\
   463 	    case 3:							\
   464 		if(SDL_BYTEORDER == SDL_BIG_ENDIAN) {			\
   465 		    s = (src[0] << 16) | (src[1] << 8) | src[2];	\
   466 		    d = (dst[0] << 16) | (dst[1] << 8) | dst[2];	\
   467 		} else {						\
   468 		    s = (src[2] << 16) | (src[1] << 8) | src[0];	\
   469 		    d = (dst[2] << 16) | (dst[1] << 8) | dst[0];	\
   470 		}							\
   471 		break;							\
   472 	    case 4:							\
   473 		s = *(Uint32 *)src;					\
   474 		d = *(Uint32 *)dst;					\
   475 		break;							\
   476 	    }								\
   477 	    RGB_FROM_PIXEL(s, fmt, rs, gs, bs);				\
   478 	    RGB_FROM_PIXEL(d, fmt, rd, gd, bd);				\
   479 	    rd += (rs - rd) * alpha >> 8;				\
   480 	    gd += (gs - gd) * alpha >> 8;				\
   481 	    bd += (bs - bd) * alpha >> 8;				\
   482 	    PIXEL_FROM_RGB(d, fmt, rd, gd, bd);				\
   483 	    switch(bpp) {						\
   484 	    case 2:							\
   485 		*(Uint16 *)dst = (Uint16)d;					\
   486 		break;							\
   487 	    case 3:							\
   488 		if(SDL_BYTEORDER == SDL_BIG_ENDIAN) {			\
   489 		    dst[0] = (Uint8)(d >> 16);					\
   490 		    dst[1] = (Uint8)(d >> 8);					\
   491 		    dst[2] = (Uint8)(d);						\
   492 		} else {						\
   493 		    dst[0] = (Uint8)d;						\
   494 		    dst[1] = (Uint8)(d >> 8);					\
   495 		    dst[2] = (Uint8)(d >> 16);					\
   496 		}							\
   497 		break;							\
   498 	    case 4:							\
   499 		*(Uint32 *)dst = d;					\
   500 		break;							\
   501 	    }								\
   502 	    src += bpp;							\
   503 	    dst += bpp;							\
   504 	}								\
   505     } while(0)
   506 
   507 #ifdef MMX_ASMBLIT
   508 
   509 #define ALPHA_BLIT32_888_50MMX(to, from, length, bpp, alpha)		\
   510     do {								\
   511 	Uint32 *srcp = (Uint32 *)(from);				\
   512 	Uint32 *dstp = (Uint32 *)(to);					\
   513         int i = 0x00fefefe;						\
   514         movd_m2r(*(&i), mm4);						\
   515         punpckldq_r2r(mm4, mm4);					\
   516         i = 0x00010101;							\
   517         movd_m2r(*(&i), mm3);						\
   518         punpckldq_r2r(mm3, mm3);					\
   519         i = (int)(length);						\
   520         if( i & 1 ) {							\
   521 	  Uint32 s = *srcp++;						\
   522 	  Uint32 d = *dstp;						\
   523 	  *dstp++ = (((s & 0x00fefefe) + (d & 0x00fefefe)) >> 1)	\
   524 		     + (s & d & 0x00010101);				\
   525 	  i--;								\
   526 	}								\
   527 	for(; i > 0; --i) {						\
   528 	    movq_m2r((*dstp), mm2); /* dst -> mm2 */			\
   529 	    movq_r2r(mm2, mm6);	/* dst -> mm6 */			\
   530 	    movq_m2r((*srcp), mm1); /* src -> mm1 */			\
   531 	    movq_r2r(mm1, mm5);	/* src -> mm5 */			\
   532 	    pand_r2r(mm4, mm6);	/* dst & 0x00fefefe -> mm6 */		\
   533 	    pand_r2r(mm4, mm5); /* src & 0x00fefefe -> mm5 */		\
   534 	    paddd_r2r(mm6, mm5); /* (dst & 0x00fefefe) + (dst & 0x00fefefe) -> mm5 */	\
   535 	    psrld_i2r(1, mm5);						\
   536 	    pand_r2r(mm1, mm2);	/* s & d -> mm2 */			\
   537 	    pand_r2r(mm3, mm2);	/* s & d & 0x00010101 -> mm2 */		\
   538 	    paddd_r2r(mm5, mm2);					\
   539 	    movq_r2m(mm2, (*dstp));					\
   540 	    dstp += 2;							\
   541 	    srcp += 2;							\
   542 	    i--;							\
   543 	}								\
   544 	emms();								\
   545     } while(0)
   546 
   547 #endif
   548 
   549 /*
   550  * Special case: 50% alpha (alpha=128)
   551  * This is treated specially because it can be optimized very well, and
   552  * since it is good for many cases of semi-translucency.
   553  * The theory is to do all three components at the same time:
   554  * First zero the lowest bit of each component, which gives us room to
   555  * add them. Then shift right and add the sum of the lowest bits.
   556  */
   557 #define ALPHA_BLIT32_888_50(to, from, length, bpp, alpha)		\
   558     do {								\
   559         int i;								\
   560 	Uint32 *src = (Uint32 *)(from);					\
   561 	Uint32 *dst = (Uint32 *)(to);					\
   562 	for(i = 0; i < (int)(length); i++) {				\
   563 	    Uint32 s = *src++;						\
   564 	    Uint32 d = *dst;						\
   565 	    *dst++ = (((s & 0x00fefefe) + (d & 0x00fefefe)) >> 1)	\
   566 		     + (s & d & 0x00010101);				\
   567 	}								\
   568     } while(0)
   569 
   570 /*
   571  * For 16bpp, we can actually blend two pixels in parallel, if we take
   572  * care to shift before we add, not after.
   573  */
   574 
   575 /* helper: blend a single 16 bit pixel at 50% */
   576 #define BLEND16_50(dst, src, mask)			\
   577     do {						\
   578 	Uint32 s = *src++;				\
   579 	Uint32 d = *dst;				\
   580 	*dst++ = (Uint16)((((s & mask) + (d & mask)) >> 1) +	\
   581 	                  (s & d & (~mask & 0xffff)));		\
   582     } while(0)
   583 
   584 /* basic 16bpp blender. mask is the pixels to keep when adding. */
   585 #define ALPHA_BLIT16_50(to, from, length, bpp, alpha, mask)		\
   586     do {								\
   587 	unsigned n = (length);						\
   588 	Uint16 *src = (Uint16 *)(from);					\
   589 	Uint16 *dst = (Uint16 *)(to);					\
   590 	if(((uintptr_t)src ^ (uintptr_t)dst) & 3) {			\
   591 	    /* source and destination not in phase, blit one by one */	\
   592 	    while(n--)							\
   593 		BLEND16_50(dst, src, mask);				\
   594 	} else {							\
   595 	    if((uintptr_t)src & 3) {					\
   596 		/* first odd pixel */					\
   597 		BLEND16_50(dst, src, mask);				\
   598 		n--;							\
   599 	    }								\
   600 	    for(; n > 1; n -= 2) {					\
   601 		Uint32 s = *(Uint32 *)src;				\
   602 		Uint32 d = *(Uint32 *)dst;				\
   603 		*(Uint32 *)dst = ((s & (mask | mask << 16)) >> 1)	\
   604 		               + ((d & (mask | mask << 16)) >> 1)	\
   605 		               + (s & d & (~(mask | mask << 16)));	\
   606 		src += 2;						\
   607 		dst += 2;						\
   608 	    }								\
   609 	    if(n)							\
   610 		BLEND16_50(dst, src, mask); /* last odd pixel */	\
   611 	}								\
   612     } while(0)
   613 
   614 #define ALPHA_BLIT16_565_50(to, from, length, bpp, alpha)	\
   615     ALPHA_BLIT16_50(to, from, length, bpp, alpha, 0xf7de)
   616 
   617 #define ALPHA_BLIT16_555_50(to, from, length, bpp, alpha)	\
   618     ALPHA_BLIT16_50(to, from, length, bpp, alpha, 0xfbde)
   619 
   620 #ifdef MMX_ASMBLIT
   621 
   622 #define CHOOSE_BLIT(blitter, alpha, fmt)				\
   623     do {								\
   624         if(alpha == 255) {						\
   625 	    switch(fmt->BytesPerPixel) {				\
   626 	    case 1: blitter(1, Uint8, OPAQUE_BLIT); break;		\
   627 	    case 2: blitter(2, Uint8, OPAQUE_BLIT); break;		\
   628 	    case 3: blitter(3, Uint8, OPAQUE_BLIT); break;		\
   629 	    case 4: blitter(4, Uint16, OPAQUE_BLIT); break;		\
   630 	    }								\
   631 	} else {							\
   632 	    switch(fmt->BytesPerPixel) {				\
   633 	    case 1:							\
   634 		/* No 8bpp alpha blitting */				\
   635 		break;							\
   636 									\
   637 	    case 2:							\
   638 		switch(fmt->Rmask | fmt->Gmask | fmt->Bmask) {		\
   639 		case 0xffff:						\
   640 		    if(fmt->Gmask == 0x07e0				\
   641 		       || fmt->Rmask == 0x07e0				\
   642 		       || fmt->Bmask == 0x07e0) {			\
   643 			if(alpha == 128)				\
   644 			    blitter(2, Uint8, ALPHA_BLIT16_565_50);	\
   645 			else {						\
   646 			    if(SDL_HasMMX())				\
   647 				blitter(2, Uint8, ALPHA_BLIT16_565MMX);	\
   648 			    else					\
   649 				blitter(2, Uint8, ALPHA_BLIT16_565);	\
   650 			}						\
   651 		    } else						\
   652 			goto general16;					\
   653 		    break;						\
   654 									\
   655 		case 0x7fff:						\
   656 		    if(fmt->Gmask == 0x03e0				\
   657 		       || fmt->Rmask == 0x03e0				\
   658 		       || fmt->Bmask == 0x03e0) {			\
   659 			if(alpha == 128)				\
   660 			    blitter(2, Uint8, ALPHA_BLIT16_555_50);	\
   661 			else {						\
   662 			    if(SDL_HasMMX())				\
   663 				blitter(2, Uint8, ALPHA_BLIT16_555MMX);	\
   664 			    else					\
   665 				blitter(2, Uint8, ALPHA_BLIT16_555);	\
   666 			}						\
   667 			break;						\
   668 		    }							\
   669 		    /* fallthrough */					\
   670 									\
   671 		default:						\
   672 		general16:						\
   673 		    blitter(2, Uint8, ALPHA_BLIT_ANY);			\
   674 		}							\
   675 		break;							\
   676 									\
   677 	    case 3:							\
   678 		blitter(3, Uint8, ALPHA_BLIT_ANY);			\
   679 		break;							\
   680 									\
   681 	    case 4:							\
   682 		if((fmt->Rmask | fmt->Gmask | fmt->Bmask) == 0x00ffffff	\
   683 		   && (fmt->Gmask == 0xff00 || fmt->Rmask == 0xff00	\
   684 		       || fmt->Bmask == 0xff00)) {			\
   685 		    if(alpha == 128)					\
   686 		    {							\
   687 			if(SDL_HasMMX())				\
   688 				blitter(4, Uint16, ALPHA_BLIT32_888_50MMX);\
   689 			else						\
   690 				blitter(4, Uint16, ALPHA_BLIT32_888_50);\
   691 		    }							\
   692 		    else						\
   693 		    {							\
   694 			if(SDL_HasMMX())				\
   695 				blitter(4, Uint16, ALPHA_BLIT32_888MMX);\
   696 			else						\
   697 				blitter(4, Uint16, ALPHA_BLIT32_888);	\
   698 		    }							\
   699 		} else							\
   700 		    blitter(4, Uint16, ALPHA_BLIT_ANY);			\
   701 		break;							\
   702 	    }								\
   703 	}								\
   704     } while(0)
   705 
   706 #else
   707 
   708 #define CHOOSE_BLIT(blitter, alpha, fmt)				\
   709     do {								\
   710         if(alpha == 255) {						\
   711 	    switch(fmt->BytesPerPixel) {				\
   712 	    case 1: blitter(1, Uint8, OPAQUE_BLIT); break;		\
   713 	    case 2: blitter(2, Uint8, OPAQUE_BLIT); break;		\
   714 	    case 3: blitter(3, Uint8, OPAQUE_BLIT); break;		\
   715 	    case 4: blitter(4, Uint16, OPAQUE_BLIT); break;		\
   716 	    }								\
   717 	} else {							\
   718 	    switch(fmt->BytesPerPixel) {				\
   719 	    case 1:							\
   720 		/* No 8bpp alpha blitting */				\
   721 		break;							\
   722 									\
   723 	    case 2:							\
   724 		switch(fmt->Rmask | fmt->Gmask | fmt->Bmask) {		\
   725 		case 0xffff:						\
   726 		    if(fmt->Gmask == 0x07e0				\
   727 		       || fmt->Rmask == 0x07e0				\
   728 		       || fmt->Bmask == 0x07e0) {			\
   729 			if(alpha == 128)				\
   730 			    blitter(2, Uint8, ALPHA_BLIT16_565_50);	\
   731 			else {						\
   732 			    blitter(2, Uint8, ALPHA_BLIT16_565);	\
   733 			}						\
   734 		    } else						\
   735 			goto general16;					\
   736 		    break;						\
   737 									\
   738 		case 0x7fff:						\
   739 		    if(fmt->Gmask == 0x03e0				\
   740 		       || fmt->Rmask == 0x03e0				\
   741 		       || fmt->Bmask == 0x03e0) {			\
   742 			if(alpha == 128)				\
   743 			    blitter(2, Uint8, ALPHA_BLIT16_555_50);	\
   744 			else {						\
   745 			    blitter(2, Uint8, ALPHA_BLIT16_555);	\
   746 			}						\
   747 			break;						\
   748 		    }							\
   749 		    /* fallthrough */					\
   750 									\
   751 		default:						\
   752 		general16:						\
   753 		    blitter(2, Uint8, ALPHA_BLIT_ANY);			\
   754 		}							\
   755 		break;							\
   756 									\
   757 	    case 3:							\
   758 		blitter(3, Uint8, ALPHA_BLIT_ANY);			\
   759 		break;							\
   760 									\
   761 	    case 4:							\
   762 		if((fmt->Rmask | fmt->Gmask | fmt->Bmask) == 0x00ffffff	\
   763 		   && (fmt->Gmask == 0xff00 || fmt->Rmask == 0xff00	\
   764 		       || fmt->Bmask == 0xff00)) {			\
   765 		    if(alpha == 128)					\
   766 			blitter(4, Uint16, ALPHA_BLIT32_888_50);	\
   767 		    else						\
   768 			blitter(4, Uint16, ALPHA_BLIT32_888);		\
   769 		} else							\
   770 		    blitter(4, Uint16, ALPHA_BLIT_ANY);			\
   771 		break;							\
   772 	    }								\
   773 	}								\
   774     } while(0)
   775 
   776 #endif
   777 
   778 /*
   779  * This takes care of the case when the surface is clipped on the left and/or
   780  * right. Top clipping has already been taken care of.
   781  */
   782 static void
   783 RLEClipBlit(int w, Uint8 * srcbuf, SDL_Surface * dst,
   784             Uint8 * dstbuf, SDL_Rect * srcrect, unsigned alpha)
   785 {
   786     SDL_PixelFormat *fmt = dst->format;
   787 
   788 #define RLECLIPBLIT(bpp, Type, do_blit)					   \
   789     do {								   \
   790 	int linecount = srcrect->h;					   \
   791 	int ofs = 0;							   \
   792 	int left = srcrect->x;						   \
   793 	int right = left + srcrect->w;					   \
   794 	dstbuf -= left * bpp;						   \
   795 	for(;;) {							   \
   796 	    int run;							   \
   797 	    ofs += *(Type *)srcbuf;					   \
   798 	    run = ((Type *)srcbuf)[1];					   \
   799 	    srcbuf += 2 * sizeof(Type);					   \
   800 	    if(run) {							   \
   801 		/* clip to left and right borders */			   \
   802 		if(ofs < right) {					   \
   803 		    int start = 0;					   \
   804 		    int len = run;					   \
   805 		    int startcol;					   \
   806 		    if(left - ofs > 0) {				   \
   807 			start = left - ofs;				   \
   808 			len -= start;					   \
   809 			if(len <= 0)					   \
   810 			    goto nocopy ## bpp ## do_blit;		   \
   811 		    }							   \
   812 		    startcol = ofs + start;				   \
   813 		    if(len > right - startcol)				   \
   814 			len = right - startcol;				   \
   815 		    do_blit(dstbuf + startcol * bpp, srcbuf + start * bpp, \
   816 			    len, bpp, alpha);				   \
   817 		}							   \
   818 	    nocopy ## bpp ## do_blit:					   \
   819 		srcbuf += run * bpp;					   \
   820 		ofs += run;						   \
   821 	    } else if(!ofs)						   \
   822 		break;							   \
   823 	    if(ofs == w) {						   \
   824 		ofs = 0;						   \
   825 		dstbuf += dst->pitch;					   \
   826 		if(!--linecount)					   \
   827 		    break;						   \
   828 	    }								   \
   829 	}								   \
   830     } while(0)
   831 
   832     CHOOSE_BLIT(RLECLIPBLIT, alpha, fmt);
   833 
   834 #undef RLECLIPBLIT
   835 
   836 }
   837 
   838 
   839 /* blit a colorkeyed RLE surface */
   840 int
   841 SDL_RLEBlit(SDL_Surface * src, SDL_Rect * srcrect,
   842             SDL_Surface * dst, SDL_Rect * dstrect)
   843 {
   844     Uint8 *dstbuf;
   845     Uint8 *srcbuf;
   846     int x, y;
   847     int w = src->w;
   848     unsigned alpha;
   849 
   850     /* Lock the destination if necessary */
   851     if (SDL_MUSTLOCK(dst)) {
   852         if (SDL_LockSurface(dst) < 0) {
   853             return (-1);
   854         }
   855     }
   856 
   857     /* Set up the source and destination pointers */
   858     x = dstrect->x;
   859     y = dstrect->y;
   860     dstbuf = (Uint8 *) dst->pixels
   861         + y * dst->pitch + x * src->format->BytesPerPixel;
   862     srcbuf = (Uint8 *) src->map->data;
   863 
   864     {
   865         /* skip lines at the top if neccessary */
   866         int vskip = srcrect->y;
   867         int ofs = 0;
   868         if (vskip) {
   869 
   870 #define RLESKIP(bpp, Type)			\
   871 		for(;;) {			\
   872 		    int run;			\
   873 		    ofs += *(Type *)srcbuf;	\
   874 		    run = ((Type *)srcbuf)[1];	\
   875 		    srcbuf += sizeof(Type) * 2;	\
   876 		    if(run) {			\
   877 			srcbuf += run * bpp;	\
   878 			ofs += run;		\
   879 		    } else if(!ofs)		\
   880 			goto done;		\
   881 		    if(ofs == w) {		\
   882 			ofs = 0;		\
   883 			if(!--vskip)		\
   884 			    break;		\
   885 		    }				\
   886 		}
   887 
   888             switch (src->format->BytesPerPixel) {
   889             case 1:
   890                 RLESKIP(1, Uint8);
   891                 break;
   892             case 2:
   893                 RLESKIP(2, Uint8);
   894                 break;
   895             case 3:
   896                 RLESKIP(3, Uint8);
   897                 break;
   898             case 4:
   899                 RLESKIP(4, Uint16);
   900                 break;
   901             }
   902 
   903 #undef RLESKIP
   904 
   905         }
   906     }
   907 
   908     alpha = src->map->info.a;
   909     /* if left or right edge clipping needed, call clip blit */
   910     if (srcrect->x || srcrect->w != src->w) {
   911         RLEClipBlit(w, srcbuf, dst, dstbuf, srcrect, alpha);
   912     } else {
   913         SDL_PixelFormat *fmt = src->format;
   914 
   915 #define RLEBLIT(bpp, Type, do_blit)					      \
   916 	    do {							      \
   917 		int linecount = srcrect->h;				      \
   918 		int ofs = 0;						      \
   919 		for(;;) {						      \
   920 		    unsigned run;					      \
   921 		    ofs += *(Type *)srcbuf;				      \
   922 		    run = ((Type *)srcbuf)[1];				      \
   923 		    srcbuf += 2 * sizeof(Type);				      \
   924 		    if(run) {						      \
   925 			do_blit(dstbuf + ofs * bpp, srcbuf, run, bpp, alpha); \
   926 			srcbuf += run * bpp;				      \
   927 			ofs += run;					      \
   928 		    } else if(!ofs)					      \
   929 			break;						      \
   930 		    if(ofs == w) {					      \
   931 			ofs = 0;					      \
   932 			dstbuf += dst->pitch;				      \
   933 			if(!--linecount)				      \
   934 			    break;					      \
   935 		    }							      \
   936 		}							      \
   937 	    } while(0)
   938 
   939         CHOOSE_BLIT(RLEBLIT, alpha, fmt);
   940 
   941 #undef RLEBLIT
   942     }
   943 
   944   done:
   945     /* Unlock the destination if necessary */
   946     if (SDL_MUSTLOCK(dst)) {
   947         SDL_UnlockSurface(dst);
   948     }
   949     return (0);
   950 }
   951 
   952 #undef OPAQUE_BLIT
   953 
   954 /*
   955  * Per-pixel blitting macros for translucent pixels:
   956  * These use the same techniques as the per-surface blitting macros
   957  */
   958 
   959 /*
   960  * For 32bpp pixels, we have made sure the alpha is stored in the top
   961  * 8 bits, so proceed as usual
   962  */
   963 #define BLIT_TRANSL_888(src, dst)				\
   964     do {							\
   965         Uint32 s = src;						\
   966 	Uint32 d = dst;						\
   967 	unsigned alpha = s >> 24;				\
   968 	Uint32 s1 = s & 0xff00ff;				\
   969 	Uint32 d1 = d & 0xff00ff;				\
   970 	d1 = (d1 + ((s1 - d1) * alpha >> 8)) & 0xff00ff;	\
   971 	s &= 0xff00;						\
   972 	d &= 0xff00;						\
   973 	d = (d + ((s - d) * alpha >> 8)) & 0xff00;		\
   974 	dst = d1 | d;						\
   975     } while(0)
   976 
   977 /*
   978  * For 16bpp pixels, we have stored the 5 most significant alpha bits in
   979  * bits 5-10. As before, we can process all 3 RGB components at the same time.
   980  */
   981 #define BLIT_TRANSL_565(src, dst)		\
   982     do {					\
   983 	Uint32 s = src;				\
   984 	Uint32 d = dst;				\
   985 	unsigned alpha = (s & 0x3e0) >> 5;	\
   986 	s &= 0x07e0f81f;			\
   987 	d = (d | d << 16) & 0x07e0f81f;		\
   988 	d += (s - d) * alpha >> 5;		\
   989 	d &= 0x07e0f81f;			\
   990 	dst = (Uint16)(d | d >> 16);			\
   991     } while(0)
   992 
   993 #define BLIT_TRANSL_555(src, dst)		\
   994     do {					\
   995 	Uint32 s = src;				\
   996 	Uint32 d = dst;				\
   997 	unsigned alpha = (s & 0x3e0) >> 5;	\
   998 	s &= 0x03e07c1f;			\
   999 	d = (d | d << 16) & 0x03e07c1f;		\
  1000 	d += (s - d) * alpha >> 5;		\
  1001 	d &= 0x03e07c1f;			\
  1002 	dst = (Uint16)(d | d >> 16);			\
  1003     } while(0)
  1004 
  1005 /* used to save the destination format in the encoding. Designed to be
  1006    macro-compatible with SDL_PixelFormat but without the unneeded fields */
  1007 typedef struct
  1008 {
  1009     Uint8 BytesPerPixel;
  1010     Uint8 Rloss;
  1011     Uint8 Gloss;
  1012     Uint8 Bloss;
  1013     Uint8 Rshift;
  1014     Uint8 Gshift;
  1015     Uint8 Bshift;
  1016     Uint8 Ashift;
  1017     Uint32 Rmask;
  1018     Uint32 Gmask;
  1019     Uint32 Bmask;
  1020     Uint32 Amask;
  1021 } RLEDestFormat;
  1022 
  1023 /* blit a pixel-alpha RLE surface clipped at the right and/or left edges */
  1024 static void
  1025 RLEAlphaClipBlit(int w, Uint8 * srcbuf, SDL_Surface * dst,
  1026                  Uint8 * dstbuf, SDL_Rect * srcrect)
  1027 {
  1028     SDL_PixelFormat *df = dst->format;
  1029     /*
  1030      * clipped blitter: Ptype is the destination pixel type,
  1031      * Ctype the translucent count type, and do_blend the macro
  1032      * to blend one pixel.
  1033      */
  1034 #define RLEALPHACLIPBLIT(Ptype, Ctype, do_blend)			  \
  1035     do {								  \
  1036 	int linecount = srcrect->h;					  \
  1037 	int left = srcrect->x;						  \
  1038 	int right = left + srcrect->w;					  \
  1039 	dstbuf -= left * sizeof(Ptype);					  \
  1040 	do {								  \
  1041 	    int ofs = 0;						  \
  1042 	    /* blit opaque pixels on one line */			  \
  1043 	    do {							  \
  1044 		unsigned run;						  \
  1045 		ofs += ((Ctype *)srcbuf)[0];				  \
  1046 		run = ((Ctype *)srcbuf)[1];				  \
  1047 		srcbuf += 2 * sizeof(Ctype);				  \
  1048 		if(run) {						  \
  1049 		    /* clip to left and right borders */		  \
  1050 		    int cofs = ofs;					  \
  1051 		    int crun = run;					  \
  1052 		    if(left - cofs > 0) {				  \
  1053 			crun -= left - cofs;				  \
  1054 			cofs = left;					  \
  1055 		    }							  \
  1056 		    if(crun > right - cofs)				  \
  1057 			crun = right - cofs;				  \
  1058 		    if(crun > 0)					  \
  1059 			PIXEL_COPY(dstbuf + cofs * sizeof(Ptype),	  \
  1060 				   srcbuf + (cofs - ofs) * sizeof(Ptype), \
  1061 				   (unsigned)crun, sizeof(Ptype));	  \
  1062 		    srcbuf += run * sizeof(Ptype);			  \
  1063 		    ofs += run;						  \
  1064 		} else if(!ofs)						  \
  1065 		    return;						  \
  1066 	    } while(ofs < w);						  \
  1067 	    /* skip padding if necessary */				  \
  1068 	    if(sizeof(Ptype) == 2)					  \
  1069 		srcbuf += (uintptr_t)srcbuf & 2;			  \
  1070 	    /* blit translucent pixels on the same line */		  \
  1071 	    ofs = 0;							  \
  1072 	    do {							  \
  1073 		unsigned run;						  \
  1074 		ofs += ((Uint16 *)srcbuf)[0];				  \
  1075 		run = ((Uint16 *)srcbuf)[1];				  \
  1076 		srcbuf += 4;						  \
  1077 		if(run) {						  \
  1078 		    /* clip to left and right borders */		  \
  1079 		    int cofs = ofs;					  \
  1080 		    int crun = run;					  \
  1081 		    if(left - cofs > 0) {				  \
  1082 			crun -= left - cofs;				  \
  1083 			cofs = left;					  \
  1084 		    }							  \
  1085 		    if(crun > right - cofs)				  \
  1086 			crun = right - cofs;				  \
  1087 		    if(crun > 0) {					  \
  1088 			Ptype *dst = (Ptype *)dstbuf + cofs;		  \
  1089 			Uint32 *src = (Uint32 *)srcbuf + (cofs - ofs);	  \
  1090 			int i;						  \
  1091 			for(i = 0; i < crun; i++)			  \
  1092 			    do_blend(src[i], dst[i]);			  \
  1093 		    }							  \
  1094 		    srcbuf += run * 4;					  \
  1095 		    ofs += run;						  \
  1096 		}							  \
  1097 	    } while(ofs < w);						  \
  1098 	    dstbuf += dst->pitch;					  \
  1099 	} while(--linecount);						  \
  1100     } while(0)
  1101 
  1102     switch (df->BytesPerPixel) {
  1103     case 2:
  1104         if (df->Gmask == 0x07e0 || df->Rmask == 0x07e0 || df->Bmask == 0x07e0)
  1105             RLEALPHACLIPBLIT(Uint16, Uint8, BLIT_TRANSL_565);
  1106         else
  1107             RLEALPHACLIPBLIT(Uint16, Uint8, BLIT_TRANSL_555);
  1108         break;
  1109     case 4:
  1110         RLEALPHACLIPBLIT(Uint32, Uint16, BLIT_TRANSL_888);
  1111         break;
  1112     }
  1113 }
  1114 
  1115 /* blit a pixel-alpha RLE surface */
  1116 int
  1117 SDL_RLEAlphaBlit(SDL_Surface * src, SDL_Rect * srcrect,
  1118                  SDL_Surface * dst, SDL_Rect * dstrect)
  1119 {
  1120     int x, y;
  1121     int w = src->w;
  1122     Uint8 *srcbuf, *dstbuf;
  1123     SDL_PixelFormat *df = dst->format;
  1124 
  1125     /* Lock the destination if necessary */
  1126     if (SDL_MUSTLOCK(dst)) {
  1127         if (SDL_LockSurface(dst) < 0) {
  1128             return -1;
  1129         }
  1130     }
  1131 
  1132     x = dstrect->x;
  1133     y = dstrect->y;
  1134     dstbuf = (Uint8 *) dst->pixels + y * dst->pitch + x * df->BytesPerPixel;
  1135     srcbuf = (Uint8 *) src->map->data + sizeof(RLEDestFormat);
  1136 
  1137     {
  1138         /* skip lines at the top if necessary */
  1139         int vskip = srcrect->y;
  1140         if (vskip) {
  1141             int ofs;
  1142             if (df->BytesPerPixel == 2) {
  1143                 /* the 16/32 interleaved format */
  1144                 do {
  1145                     /* skip opaque line */
  1146                     ofs = 0;
  1147                     do {
  1148                         int run;
  1149                         ofs += srcbuf[0];
  1150                         run = srcbuf[1];
  1151                         srcbuf += 2;
  1152                         if (run) {
  1153                             srcbuf += 2 * run;
  1154                             ofs += run;
  1155                         } else if (!ofs)
  1156                             goto done;
  1157                     }
  1158                     while (ofs < w);
  1159 
  1160                     /* skip padding */
  1161                     srcbuf += (uintptr_t) srcbuf & 2;
  1162 
  1163                     /* skip translucent line */
  1164                     ofs = 0;
  1165                     do {
  1166                         int run;
  1167                         ofs += ((Uint16 *) srcbuf)[0];
  1168                         run = ((Uint16 *) srcbuf)[1];
  1169                         srcbuf += 4 * (run + 1);
  1170                         ofs += run;
  1171                     }
  1172                     while (ofs < w);
  1173                 }
  1174                 while (--vskip);
  1175             } else {
  1176                 /* the 32/32 interleaved format */
  1177                 vskip <<= 1;    /* opaque and translucent have same format */
  1178                 do {
  1179                     ofs = 0;
  1180                     do {
  1181                         int run;
  1182                         ofs += ((Uint16 *) srcbuf)[0];
  1183                         run = ((Uint16 *) srcbuf)[1];
  1184                         srcbuf += 4;
  1185                         if (run) {
  1186                             srcbuf += 4 * run;
  1187                             ofs += run;
  1188                         } else if (!ofs)
  1189                             goto done;
  1190                     }
  1191                     while (ofs < w);
  1192                 }
  1193                 while (--vskip);
  1194             }
  1195         }
  1196     }
  1197 
  1198     /* if left or right edge clipping needed, call clip blit */
  1199     if (srcrect->x || srcrect->w != src->w) {
  1200         RLEAlphaClipBlit(w, srcbuf, dst, dstbuf, srcrect);
  1201     } else {
  1202 
  1203         /*
  1204          * non-clipped blitter. Ptype is the destination pixel type,
  1205          * Ctype the translucent count type, and do_blend the
  1206          * macro to blend one pixel.
  1207          */
  1208 #define RLEALPHABLIT(Ptype, Ctype, do_blend)				 \
  1209 	do {								 \
  1210 	    int linecount = srcrect->h;					 \
  1211 	    do {							 \
  1212 		int ofs = 0;						 \
  1213 		/* blit opaque pixels on one line */			 \
  1214 		do {							 \
  1215 		    unsigned run;					 \
  1216 		    ofs += ((Ctype *)srcbuf)[0];			 \
  1217 		    run = ((Ctype *)srcbuf)[1];				 \
  1218 		    srcbuf += 2 * sizeof(Ctype);			 \
  1219 		    if(run) {						 \
  1220 			PIXEL_COPY(dstbuf + ofs * sizeof(Ptype), srcbuf, \
  1221 				   run, sizeof(Ptype));			 \
  1222 			srcbuf += run * sizeof(Ptype);			 \
  1223 			ofs += run;					 \
  1224 		    } else if(!ofs)					 \
  1225 			goto done;					 \
  1226 		} while(ofs < w);					 \
  1227 		/* skip padding if necessary */				 \
  1228 		if(sizeof(Ptype) == 2)					 \
  1229 		    srcbuf += (uintptr_t)srcbuf & 2;		 	 \
  1230 		/* blit translucent pixels on the same line */		 \
  1231 		ofs = 0;						 \
  1232 		do {							 \
  1233 		    unsigned run;					 \
  1234 		    ofs += ((Uint16 *)srcbuf)[0];			 \
  1235 		    run = ((Uint16 *)srcbuf)[1];			 \
  1236 		    srcbuf += 4;					 \
  1237 		    if(run) {						 \
  1238 			Ptype *dst = (Ptype *)dstbuf + ofs;		 \
  1239 			unsigned i;					 \
  1240 			for(i = 0; i < run; i++) {			 \
  1241 			    Uint32 src = *(Uint32 *)srcbuf;		 \
  1242 			    do_blend(src, *dst);			 \
  1243 			    srcbuf += 4;				 \
  1244 			    dst++;					 \
  1245 			}						 \
  1246 			ofs += run;					 \
  1247 		    }							 \
  1248 		} while(ofs < w);					 \
  1249 		dstbuf += dst->pitch;					 \
  1250 	    } while(--linecount);					 \
  1251 	} while(0)
  1252 
  1253         switch (df->BytesPerPixel) {
  1254         case 2:
  1255             if (df->Gmask == 0x07e0 || df->Rmask == 0x07e0
  1256                 || df->Bmask == 0x07e0)
  1257                 RLEALPHABLIT(Uint16, Uint8, BLIT_TRANSL_565);
  1258             else
  1259                 RLEALPHABLIT(Uint16, Uint8, BLIT_TRANSL_555);
  1260             break;
  1261         case 4:
  1262             RLEALPHABLIT(Uint32, Uint16, BLIT_TRANSL_888);
  1263             break;
  1264         }
  1265     }
  1266 
  1267   done:
  1268     /* Unlock the destination if necessary */
  1269     if (SDL_MUSTLOCK(dst)) {
  1270         SDL_UnlockSurface(dst);
  1271     }
  1272     return 0;
  1273 }
  1274 
  1275 /*
  1276  * Auxiliary functions:
  1277  * The encoding functions take 32bpp rgb + a, and
  1278  * return the number of bytes copied to the destination.
  1279  * The decoding functions copy to 32bpp rgb + a, and
  1280  * return the number of bytes copied from the source.
  1281  * These are only used in the encoder and un-RLE code and are therefore not
  1282  * highly optimised.
  1283  */
  1284 
  1285 /* encode 32bpp rgb + a into 16bpp rgb, losing alpha */
  1286 static int
  1287 copy_opaque_16(void *dst, Uint32 * src, int n,
  1288                SDL_PixelFormat * sfmt, SDL_PixelFormat * dfmt)
  1289 {
  1290     int i;
  1291     Uint16 *d = dst;
  1292     for (i = 0; i < n; i++) {
  1293         unsigned r, g, b;
  1294         RGB_FROM_PIXEL(*src, sfmt, r, g, b);
  1295         PIXEL_FROM_RGB(*d, dfmt, r, g, b);
  1296         src++;
  1297         d++;
  1298     }
  1299     return n * 2;
  1300 }
  1301 
  1302 /* decode opaque pixels from 16bpp to 32bpp rgb + a */
  1303 static int
  1304 uncopy_opaque_16(Uint32 * dst, void *src, int n,
  1305                  RLEDestFormat * sfmt, SDL_PixelFormat * dfmt)
  1306 {
  1307     int i;
  1308     Uint16 *s = src;
  1309     unsigned alpha = dfmt->Amask ? 255 : 0;
  1310     for (i = 0; i < n; i++) {
  1311         unsigned r, g, b;
  1312         RGB_FROM_PIXEL(*s, sfmt, r, g, b);
  1313         PIXEL_FROM_RGBA(*dst, dfmt, r, g, b, alpha);
  1314         s++;
  1315         dst++;
  1316     }
  1317     return n * 2;
  1318 }
  1319 
  1320 
  1321 
  1322 /* encode 32bpp rgb + a into 32bpp G0RAB format for blitting into 565 */
  1323 static int
  1324 copy_transl_565(void *dst, Uint32 * src, int n,
  1325                 SDL_PixelFormat * sfmt, SDL_PixelFormat * dfmt)
  1326 {
  1327     int i;
  1328     Uint32 *d = dst;
  1329     for (i = 0; i < n; i++) {
  1330         unsigned r, g, b, a;
  1331         Uint16 pix;
  1332         RGBA_FROM_8888(*src, sfmt, r, g, b, a);
  1333         PIXEL_FROM_RGB(pix, dfmt, r, g, b);
  1334         *d = ((pix & 0x7e0) << 16) | (pix & 0xf81f) | ((a << 2) & 0x7e0);
  1335         src++;
  1336         d++;
  1337     }
  1338     return n * 4;
  1339 }
  1340 
  1341 /* encode 32bpp rgb + a into 32bpp G0RAB format for blitting into 555 */
  1342 static int
  1343 copy_transl_555(void *dst, Uint32 * src, int n,
  1344                 SDL_PixelFormat * sfmt, SDL_PixelFormat * dfmt)
  1345 {
  1346     int i;
  1347     Uint32 *d = dst;
  1348     for (i = 0; i < n; i++) {
  1349         unsigned r, g, b, a;
  1350         Uint16 pix;
  1351         RGBA_FROM_8888(*src, sfmt, r, g, b, a);
  1352         PIXEL_FROM_RGB(pix, dfmt, r, g, b);
  1353         *d = ((pix & 0x3e0) << 16) | (pix & 0xfc1f) | ((a << 2) & 0x3e0);
  1354         src++;
  1355         d++;
  1356     }
  1357     return n * 4;
  1358 }
  1359 
  1360 /* decode translucent pixels from 32bpp GORAB to 32bpp rgb + a */
  1361 static int
  1362 uncopy_transl_16(Uint32 * dst, void *src, int n,
  1363                  RLEDestFormat * sfmt, SDL_PixelFormat * dfmt)
  1364 {
  1365     int i;
  1366     Uint32 *s = src;
  1367     for (i = 0; i < n; i++) {
  1368         unsigned r, g, b, a;
  1369         Uint32 pix = *s++;
  1370         a = (pix & 0x3e0) >> 2;
  1371         pix = (pix & ~0x3e0) | pix >> 16;
  1372         RGB_FROM_PIXEL(pix, sfmt, r, g, b);
  1373         PIXEL_FROM_RGBA(*dst, dfmt, r, g, b, a);
  1374         dst++;
  1375     }
  1376     return n * 4;
  1377 }
  1378 
  1379 /* encode 32bpp rgba into 32bpp rgba, keeping alpha (dual purpose) */
  1380 static int
  1381 copy_32(void *dst, Uint32 * src, int n,
  1382         SDL_PixelFormat * sfmt, SDL_PixelFormat * dfmt)
  1383 {
  1384     int i;
  1385     Uint32 *d = dst;
  1386     for (i = 0; i < n; i++) {
  1387         unsigned r, g, b, a;
  1388         Uint32 pixel;
  1389         RGBA_FROM_8888(*src, sfmt, r, g, b, a);
  1390         PIXEL_FROM_RGB(pixel, dfmt, r, g, b);
  1391         *d++ = pixel | a << 24;
  1392         src++;
  1393     }
  1394     return n * 4;
  1395 }
  1396 
  1397 /* decode 32bpp rgba into 32bpp rgba, keeping alpha (dual purpose) */
  1398 static int
  1399 uncopy_32(Uint32 * dst, void *src, int n,
  1400           RLEDestFormat * sfmt, SDL_PixelFormat * dfmt)
  1401 {
  1402     int i;
  1403     Uint32 *s = src;
  1404     for (i = 0; i < n; i++) {
  1405         unsigned r, g, b, a;
  1406         Uint32 pixel = *s++;
  1407         RGB_FROM_PIXEL(pixel, sfmt, r, g, b);
  1408         a = pixel >> 24;
  1409         PIXEL_FROM_RGBA(*dst, dfmt, r, g, b, a);
  1410         dst++;
  1411     }
  1412     return n * 4;
  1413 }
  1414 
  1415 #define ISOPAQUE(pixel, fmt) ((((pixel) & fmt->Amask) >> fmt->Ashift) == 255)
  1416 
  1417 #define ISTRANSL(pixel, fmt)	\
  1418     ((unsigned)((((pixel) & fmt->Amask) >> fmt->Ashift) - 1U) < 254U)
  1419 
  1420 /* convert surface to be quickly alpha-blittable onto dest, if possible */
  1421 static int
  1422 RLEAlphaSurface(SDL_Surface * surface)
  1423 {
  1424     SDL_Surface *dest;
  1425     SDL_PixelFormat *df;
  1426     int maxsize = 0;
  1427     int max_opaque_run;
  1428     int max_transl_run = 65535;
  1429     unsigned masksum;
  1430     Uint8 *rlebuf, *dst;
  1431     int (*copy_opaque) (void *, Uint32 *, int,
  1432                         SDL_PixelFormat *, SDL_PixelFormat *);
  1433     int (*copy_transl) (void *, Uint32 *, int,
  1434                         SDL_PixelFormat *, SDL_PixelFormat *);
  1435 
  1436     dest = surface->map->dst;
  1437     if (!dest)
  1438         return -1;
  1439     df = dest->format;
  1440     if (surface->format->BitsPerPixel != 32)
  1441         return -1;              /* only 32bpp source supported */
  1442 
  1443     /* find out whether the destination is one we support,
  1444        and determine the max size of the encoded result */
  1445     masksum = df->Rmask | df->Gmask | df->Bmask;
  1446     switch (df->BytesPerPixel) {
  1447     case 2:
  1448         /* 16bpp: only support 565 and 555 formats */
  1449         switch (masksum) {
  1450         case 0xffff:
  1451             if (df->Gmask == 0x07e0
  1452                 || df->Rmask == 0x07e0 || df->Bmask == 0x07e0) {
  1453                 copy_opaque = copy_opaque_16;
  1454                 copy_transl = copy_transl_565;
  1455             } else
  1456                 return -1;
  1457             break;
  1458         case 0x7fff:
  1459             if (df->Gmask == 0x03e0
  1460                 || df->Rmask == 0x03e0 || df->Bmask == 0x03e0) {
  1461                 copy_opaque = copy_opaque_16;
  1462                 copy_transl = copy_transl_555;
  1463             } else
  1464                 return -1;
  1465             break;
  1466         default:
  1467             return -1;
  1468         }
  1469         max_opaque_run = 255;   /* runs stored as bytes */
  1470 
  1471         /* worst case is alternating opaque and translucent pixels,
  1472            with room for alignment padding between lines */
  1473         maxsize = surface->h * (2 + (4 + 2) * (surface->w + 1)) + 2;
  1474         break;
  1475     case 4:
  1476         if (masksum != 0x00ffffff)
  1477             return -1;          /* requires unused high byte */
  1478         copy_opaque = copy_32;
  1479         copy_transl = copy_32;
  1480         max_opaque_run = 255;   /* runs stored as short ints */
  1481 
  1482         /* worst case is alternating opaque and translucent pixels */
  1483         maxsize = surface->h * 2 * 4 * (surface->w + 1) + 4;
  1484         break;
  1485     default:
  1486         return -1;              /* anything else unsupported right now */
  1487     }
  1488 
  1489     maxsize += sizeof(RLEDestFormat);
  1490     rlebuf = (Uint8 *) SDL_malloc(maxsize);
  1491     if (!rlebuf) {
  1492         SDL_OutOfMemory();
  1493         return -1;
  1494     }
  1495     {
  1496         /* save the destination format so we can undo the encoding later */
  1497         RLEDestFormat *r = (RLEDestFormat *) rlebuf;
  1498         r->BytesPerPixel = df->BytesPerPixel;
  1499         r->Rloss = df->Rloss;
  1500         r->Gloss = df->Gloss;
  1501         r->Bloss = df->Bloss;
  1502         r->Rshift = df->Rshift;
  1503         r->Gshift = df->Gshift;
  1504         r->Bshift = df->Bshift;
  1505         r->Ashift = df->Ashift;
  1506         r->Rmask = df->Rmask;
  1507         r->Gmask = df->Gmask;
  1508         r->Bmask = df->Bmask;
  1509         r->Amask = df->Amask;
  1510     }
  1511     dst = rlebuf + sizeof(RLEDestFormat);
  1512 
  1513     /* Do the actual encoding */
  1514     {
  1515         int x, y;
  1516         int h = surface->h, w = surface->w;
  1517         SDL_PixelFormat *sf = surface->format;
  1518         Uint32 *src = (Uint32 *) surface->pixels;
  1519         Uint8 *lastline = dst;  /* end of last non-blank line */
  1520 
  1521         /* opaque counts are 8 or 16 bits, depending on target depth */
  1522 #define ADD_OPAQUE_COUNTS(n, m)			\
  1523 	if(df->BytesPerPixel == 4) {		\
  1524 	    ((Uint16 *)dst)[0] = n;		\
  1525 	    ((Uint16 *)dst)[1] = m;		\
  1526 	    dst += 4;				\
  1527 	} else {				\
  1528 	    dst[0] = n;				\
  1529 	    dst[1] = m;				\
  1530 	    dst += 2;				\
  1531 	}
  1532 
  1533         /* translucent counts are always 16 bit */
  1534 #define ADD_TRANSL_COUNTS(n, m)		\
  1535 	(((Uint16 *)dst)[0] = n, ((Uint16 *)dst)[1] = m, dst += 4)
  1536 
  1537         for (y = 0; y < h; y++) {
  1538             int runstart, skipstart;
  1539             int blankline = 0;
  1540             /* First encode all opaque pixels of a scan line */
  1541             x = 0;
  1542             do {
  1543                 int run, skip, len;
  1544                 skipstart = x;
  1545                 while (x < w && !ISOPAQUE(src[x], sf))
  1546                     x++;
  1547                 runstart = x;
  1548                 while (x < w && ISOPAQUE(src[x], sf))
  1549                     x++;
  1550                 skip = runstart - skipstart;
  1551                 if (skip == w)
  1552                     blankline = 1;
  1553                 run = x - runstart;
  1554                 while (skip > max_opaque_run) {
  1555                     ADD_OPAQUE_COUNTS(max_opaque_run, 0);
  1556                     skip -= max_opaque_run;
  1557                 }
  1558                 len = MIN(run, max_opaque_run);
  1559                 ADD_OPAQUE_COUNTS(skip, len);
  1560                 dst += copy_opaque(dst, src + runstart, len, sf, df);
  1561                 runstart += len;
  1562                 run -= len;
  1563                 while (run) {
  1564                     len = MIN(run, max_opaque_run);
  1565                     ADD_OPAQUE_COUNTS(0, len);
  1566                     dst += copy_opaque(dst, src + runstart, len, sf, df);
  1567                     runstart += len;
  1568                     run -= len;
  1569                 }
  1570             }
  1571             while (x < w);
  1572 
  1573             /* Make sure the next output address is 32-bit aligned */
  1574             dst += (uintptr_t) dst & 2;
  1575 
  1576             /* Next, encode all translucent pixels of the same scan line */
  1577             x = 0;
  1578             do {
  1579                 int run, skip, len;
  1580                 skipstart = x;
  1581                 while (x < w && !ISTRANSL(src[x], sf))
  1582                     x++;
  1583                 runstart = x;
  1584                 while (x < w && ISTRANSL(src[x], sf))
  1585                     x++;
  1586                 skip = runstart - skipstart;
  1587                 blankline &= (skip == w);
  1588                 run = x - runstart;
  1589                 while (skip > max_transl_run) {
  1590                     ADD_TRANSL_COUNTS(max_transl_run, 0);
  1591                     skip -= max_transl_run;
  1592                 }
  1593                 len = MIN(run, max_transl_run);
  1594                 ADD_TRANSL_COUNTS(skip, len);
  1595                 dst += copy_transl(dst, src + runstart, len, sf, df);
  1596                 runstart += len;
  1597                 run -= len;
  1598                 while (run) {
  1599                     len = MIN(run, max_transl_run);
  1600                     ADD_TRANSL_COUNTS(0, len);
  1601                     dst += copy_transl(dst, src + runstart, len, sf, df);
  1602                     runstart += len;
  1603                     run -= len;
  1604                 }
  1605                 if (!blankline)
  1606                     lastline = dst;
  1607             }
  1608             while (x < w);
  1609 
  1610             src += surface->pitch >> 2;
  1611         }
  1612         dst = lastline;         /* back up past trailing blank lines */
  1613         ADD_OPAQUE_COUNTS(0, 0);
  1614     }
  1615 
  1616 #undef ADD_OPAQUE_COUNTS
  1617 #undef ADD_TRANSL_COUNTS
  1618 
  1619     /* Now that we have it encoded, release the original pixels */
  1620     if (!(surface->flags & SDL_PREALLOC)) {
  1621         SDL_free(surface->pixels);
  1622         surface->pixels = NULL;
  1623     }
  1624 
  1625     /* realloc the buffer to release unused memory */
  1626     {
  1627         Uint8 *p = SDL_realloc(rlebuf, dst - rlebuf);
  1628         if (!p)
  1629             p = rlebuf;
  1630         surface->map->data = p;
  1631     }
  1632 
  1633     return 0;
  1634 }
  1635 
  1636 static Uint32
  1637 getpix_8(Uint8 * srcbuf)
  1638 {
  1639     return *srcbuf;
  1640 }
  1641 
  1642 static Uint32
  1643 getpix_16(Uint8 * srcbuf)
  1644 {
  1645     return *(Uint16 *) srcbuf;
  1646 }
  1647 
  1648 static Uint32
  1649 getpix_24(Uint8 * srcbuf)
  1650 {
  1651 #if SDL_BYTEORDER == SDL_LIL_ENDIAN
  1652     return srcbuf[0] + (srcbuf[1] << 8) + (srcbuf[2] << 16);
  1653 #else
  1654     return (srcbuf[0] << 16) + (srcbuf[1] << 8) + srcbuf[2];
  1655 #endif
  1656 }
  1657 
  1658 static Uint32
  1659 getpix_32(Uint8 * srcbuf)
  1660 {
  1661     return *(Uint32 *) srcbuf;
  1662 }
  1663 
  1664 typedef Uint32(*getpix_func) (Uint8 *);
  1665 
  1666 static getpix_func getpixes[4] = {
  1667     getpix_8, getpix_16, getpix_24, getpix_32
  1668 };
  1669 
  1670 static int
  1671 RLEColorkeySurface(SDL_Surface * surface)
  1672 {
  1673     Uint8 *rlebuf, *dst;
  1674     int maxn;
  1675     int y;
  1676     Uint8 *srcbuf, *curbuf, *lastline;
  1677     int maxsize = 0;
  1678     int skip, run;
  1679     int bpp = surface->format->BytesPerPixel;
  1680     getpix_func getpix;
  1681     Uint32 ckey, rgbmask;
  1682     int w, h;
  1683 
  1684     /* calculate the worst case size for the compressed surface */
  1685     switch (bpp) {
  1686     case 1:
  1687         /* worst case is alternating opaque and transparent pixels,
  1688            starting with an opaque pixel */
  1689         maxsize = surface->h * 3 * (surface->w / 2 + 1) + 2;
  1690         break;
  1691     case 2:
  1692     case 3:
  1693         /* worst case is solid runs, at most 255 pixels wide */
  1694         maxsize = surface->h * (2 * (surface->w / 255 + 1)
  1695                                 + surface->w * bpp) + 2;
  1696         break;
  1697     case 4:
  1698         /* worst case is solid runs, at most 65535 pixels wide */
  1699         maxsize = surface->h * (4 * (surface->w / 65535 + 1)
  1700                                 + surface->w * 4) + 4;
  1701         break;
  1702     }
  1703 
  1704     rlebuf = (Uint8 *) SDL_malloc(maxsize);
  1705     if (rlebuf == NULL) {
  1706         SDL_OutOfMemory();
  1707         return (-1);
  1708     }
  1709 
  1710     /* Set up the conversion */
  1711     srcbuf = (Uint8 *) surface->pixels;
  1712     curbuf = srcbuf;
  1713     maxn = bpp == 4 ? 65535 : 255;
  1714     skip = run = 0;
  1715     dst = rlebuf;
  1716     rgbmask = ~surface->format->Amask;
  1717     ckey = surface->map->info.colorkey & rgbmask;
  1718     lastline = dst;
  1719     getpix = getpixes[bpp - 1];
  1720     w = surface->w;
  1721     h = surface->h;
  1722 
  1723 #define ADD_COUNTS(n, m)			\
  1724 	if(bpp == 4) {				\
  1725 	    ((Uint16 *)dst)[0] = n;		\
  1726 	    ((Uint16 *)dst)[1] = m;		\
  1727 	    dst += 4;				\
  1728 	} else {				\
  1729 	    dst[0] = n;				\
  1730 	    dst[1] = m;				\
  1731 	    dst += 2;				\
  1732 	}
  1733 
  1734     for (y = 0; y < h; y++) {
  1735         int x = 0;
  1736         int blankline = 0;
  1737         do {
  1738             int run, skip, len;
  1739             int runstart;
  1740             int skipstart = x;
  1741 
  1742             /* find run of transparent, then opaque pixels */
  1743             while (x < w && (getpix(srcbuf + x * bpp) & rgbmask) == ckey)
  1744                 x++;
  1745             runstart = x;
  1746             while (x < w && (getpix(srcbuf + x * bpp) & rgbmask) != ckey)
  1747                 x++;
  1748             skip = runstart - skipstart;
  1749             if (skip == w)
  1750                 blankline = 1;
  1751             run = x - runstart;
  1752 
  1753             /* encode segment */
  1754             while (skip > maxn) {
  1755                 ADD_COUNTS(maxn, 0);
  1756                 skip -= maxn;
  1757             }
  1758             len = MIN(run, maxn);
  1759             ADD_COUNTS(skip, len);
  1760             SDL_memcpy(dst, srcbuf + runstart * bpp, len * bpp);
  1761             dst += len * bpp;
  1762             run -= len;
  1763             runstart += len;
  1764             while (run) {
  1765                 len = MIN(run, maxn);
  1766                 ADD_COUNTS(0, len);
  1767                 SDL_memcpy(dst, srcbuf + runstart * bpp, len * bpp);
  1768                 dst += len * bpp;
  1769                 runstart += len;
  1770                 run -= len;
  1771             }
  1772             if (!blankline)
  1773                 lastline = dst;
  1774         }
  1775         while (x < w);
  1776 
  1777         srcbuf += surface->pitch;
  1778     }
  1779     dst = lastline;             /* back up bast trailing blank lines */
  1780     ADD_COUNTS(0, 0);
  1781 
  1782 #undef ADD_COUNTS
  1783 
  1784     /* Now that we have it encoded, release the original pixels */
  1785     if (!(surface->flags & SDL_PREALLOC)) {
  1786         SDL_free(surface->pixels);
  1787         surface->pixels = NULL;
  1788     }
  1789 
  1790     /* realloc the buffer to release unused memory */
  1791     {
  1792         /* If realloc returns NULL, the original block is left intact */
  1793         Uint8 *p = SDL_realloc(rlebuf, dst - rlebuf);
  1794         if (!p)
  1795             p = rlebuf;
  1796         surface->map->data = p;
  1797     }
  1798 
  1799     return (0);
  1800 }
  1801 
  1802 int
  1803 SDL_RLESurface(SDL_Surface * surface)
  1804 {
  1805     int flags;
  1806 
  1807     /* Clear any previous RLE conversion */
  1808     if ((surface->flags & SDL_RLEACCEL) == SDL_RLEACCEL) {
  1809         SDL_UnRLESurface(surface, 1);
  1810     }
  1811 
  1812     /* We don't support RLE encoding of bitmaps */
  1813     if (surface->format->BitsPerPixel < 8) {
  1814         return -1;
  1815     }
  1816 
  1817     /* Make sure the pixels are available */
  1818     if (!surface->pixels) {
  1819         return -1;
  1820     }
  1821 
  1822     /* If we don't have colorkey or blending, nothing to do... */
  1823     flags = surface->map->info.flags;
  1824     if (!(flags & (SDL_COPY_COLORKEY | SDL_COPY_BLEND))) {
  1825         return -1;
  1826     }
  1827 
  1828     /* Pass on combinations not supported */
  1829     if ((flags & SDL_COPY_MODULATE_COLOR) ||
  1830         (flags & (SDL_COPY_ADD | SDL_COPY_MOD)) ||
  1831         (flags & SDL_COPY_NEAREST)) {
  1832         return -1;
  1833     }
  1834 
  1835     /* Encode and set up the blit */
  1836     if (!surface->format->Amask || !(flags & SDL_COPY_BLEND)) {
  1837         if (!surface->map->identity) {
  1838             return -1;
  1839         }
  1840         if (RLEColorkeySurface(surface) < 0) {
  1841             return -1;
  1842         }
  1843         surface->map->blit = SDL_RLEBlit;
  1844         surface->map->info.flags |= SDL_COPY_RLE_COLORKEY;
  1845     } else {
  1846         if (RLEAlphaSurface(surface) < 0) {
  1847             return -1;
  1848         }
  1849         surface->map->blit = SDL_RLEAlphaBlit;
  1850         surface->map->info.flags |= SDL_COPY_RLE_ALPHAKEY;
  1851     }
  1852 
  1853     /* The surface is now accelerated */
  1854     surface->flags |= SDL_RLEACCEL;
  1855 
  1856     return (0);
  1857 }
  1858 
  1859 /*
  1860  * Un-RLE a surface with pixel alpha
  1861  * This may not give back exactly the image before RLE-encoding; all
  1862  * completely transparent pixels will be lost, and colour and alpha depth
  1863  * may have been reduced (when encoding for 16bpp targets).
  1864  */
  1865 static SDL_bool
  1866 UnRLEAlpha(SDL_Surface * surface)
  1867 {
  1868     Uint8 *srcbuf;
  1869     Uint32 *dst;
  1870     SDL_PixelFormat *sf = surface->format;
  1871     RLEDestFormat *df = surface->map->data;
  1872     int (*uncopy_opaque) (Uint32 *, void *, int,
  1873                           RLEDestFormat *, SDL_PixelFormat *);
  1874     int (*uncopy_transl) (Uint32 *, void *, int,
  1875                           RLEDestFormat *, SDL_PixelFormat *);
  1876     int w = surface->w;
  1877     int bpp = df->BytesPerPixel;
  1878 
  1879     if (bpp == 2) {
  1880         uncopy_opaque = uncopy_opaque_16;
  1881         uncopy_transl = uncopy_transl_16;
  1882     } else {
  1883         uncopy_opaque = uncopy_transl = uncopy_32;
  1884     }
  1885 
  1886     surface->pixels = SDL_malloc(surface->h * surface->pitch);
  1887     if (!surface->pixels) {
  1888         return (SDL_FALSE);
  1889     }
  1890     /* fill background with transparent pixels */
  1891     SDL_memset(surface->pixels, 0, surface->h * surface->pitch);
  1892 
  1893     dst = surface->pixels;
  1894     srcbuf = (Uint8 *) (df + 1);
  1895     for (;;) {
  1896         /* copy opaque pixels */
  1897         int ofs = 0;
  1898         do {
  1899             unsigned run;
  1900             if (bpp == 2) {
  1901                 ofs += srcbuf[0];
  1902                 run = srcbuf[1];
  1903                 srcbuf += 2;
  1904             } else {
  1905                 ofs += ((Uint16 *) srcbuf)[0];
  1906                 run = ((Uint16 *) srcbuf)[1];
  1907                 srcbuf += 4;
  1908             }
  1909             if (run) {
  1910                 srcbuf += uncopy_opaque(dst + ofs, srcbuf, run, df, sf);
  1911                 ofs += run;
  1912             } else if (!ofs)
  1913                 return (SDL_TRUE);
  1914         }
  1915         while (ofs < w);
  1916 
  1917         /* skip padding if needed */
  1918         if (bpp == 2)
  1919             srcbuf += (uintptr_t) srcbuf & 2;
  1920 
  1921         /* copy translucent pixels */
  1922         ofs = 0;
  1923         do {
  1924             unsigned run;
  1925             ofs += ((Uint16 *) srcbuf)[0];
  1926             run = ((Uint16 *) srcbuf)[1];
  1927             srcbuf += 4;
  1928             if (run) {
  1929                 srcbuf += uncopy_transl(dst + ofs, srcbuf, run, df, sf);
  1930                 ofs += run;
  1931             }
  1932         }
  1933         while (ofs < w);
  1934         dst += surface->pitch >> 2;
  1935     }
  1936     /* Make the compiler happy */
  1937     return (SDL_TRUE);
  1938 }
  1939 
  1940 void
  1941 SDL_UnRLESurface(SDL_Surface * surface, int recode)
  1942 {
  1943     if (surface->flags & SDL_RLEACCEL) {
  1944         surface->flags &= ~SDL_RLEACCEL;
  1945 
  1946         if (recode && !(surface->flags & SDL_PREALLOC)) {
  1947             if (surface->map->info.flags & SDL_COPY_RLE_COLORKEY) {
  1948                 SDL_Rect full;
  1949 
  1950                 /* re-create the original surface */
  1951                 surface->pixels = SDL_malloc(surface->h * surface->pitch);
  1952                 if (!surface->pixels) {
  1953                     /* Oh crap... */
  1954                     surface->flags |= SDL_RLEACCEL;
  1955                     return;
  1956                 }
  1957 
  1958                 /* fill it with the background colour */
  1959                 SDL_FillRect(surface, NULL, surface->map->info.colorkey);
  1960 
  1961                 /* now render the encoded surface */
  1962                 full.x = full.y = 0;
  1963                 full.w = surface->w;
  1964                 full.h = surface->h;
  1965                 SDL_RLEBlit(surface, &full, surface, &full);
  1966             } else {
  1967                 if (!UnRLEAlpha(surface)) {
  1968                     /* Oh crap... */
  1969                     surface->flags |= SDL_RLEACCEL;
  1970                     return;
  1971                 }
  1972             }
  1973         }
  1974         surface->map->info.flags &=
  1975             (SDL_COPY_RLE_COLORKEY | SDL_COPY_RLE_ALPHAKEY);
  1976         surface->map->info.flags |= SDL_COPY_RLE_DESIRED;
  1977 
  1978         if (surface->map->data) {
  1979             SDL_free(surface->map->data);
  1980             surface->map->data = NULL;
  1981         }
  1982     }
  1983 }
  1984 
  1985 /* vi: set ts=4 sw=4 expandtab: */