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