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