Mercurial > sdl-ios-xcode
annotate src/video/SDL_RLEaccel.c @ 563:04dcaf3da918
Massive Quartz input enhancements from Darrell Walisser. His email:
Enclosed is a patch that addresses the following:
--Various minor cleanups.
Removed dead/obsolete code, made some style cleanups
--Mouse Events
Now keep track of what button(s) were pressed so we know when to send
the mouse up event. This fixes the case where the mouse is dragged
outside of the game window and released (in which case we want to send
the mouse up event even though the mouse is outside the game window).
--Input Grabbing
Here is my take on the grabbing situation, which is the basis for the
new implementation.
There are 3 grab states, ungrabbed (UG), visible (VG), and invisible
(IG). Both VG and IG keep the mouse constrained to the window and
produce relative motion events. In VG the cursor is visible (duh), in
IG it is not. In VG, absolute motion events also work.
There are 6 actions that can affect grabbing:
1. Set Fullscreen/Window (F/W). In fullscreen, a visible grab should do
nothing. However, a fullscreen visible grab can be treated just like a
windowed visible grab, which is what I have done to help simplify
things.
2. Cursor hide/show (H/S). If the cursor is hidden when grabbing, the
grab is an invisible grab. If the cursor is visible, the grab should
just constrain the mouse to the window.
3. Input grab/ungrab(G/U). If grabbed, the cursor should be confined to
the window as should the keyboard input. On Mac OS X, the keyboard
input is implicitly grabbed by confining the cursor, except for
command-tab which can switch away from the application. Should the
window come to the foreground if the application is deactivated and
grab input is called? This isn't necessary in this implementation
because the grab state will be asserted upon activation.
Using my notation, these are all the cases that need to be handled
(state + action = new state).
UG+U = UG
UG+G = VG or IG, if cursor is visible or not
UG+H = UG
UG+S = UG
VG+U = UG
VG+G = VG
VG+H = IG
VG+S = VG
IG+U = UG
IG+G = IG
IG+H = IG
IG+S = VG
The cases that result in the same state can be ignored in the code,
which cuts it down to just 5 cases.
Another issue is what happens when the app loses/gains input focus from
deactivate/activate or iconify/deiconify. I think that if input focus
is ever lost (outside of SDL's control), the grab state should be
suspended and the cursor should become visible and active again. When
regained, the cursor should reappear in its original location and/or
grab state. This way, when reactivating the cursor is still in the same
position as before so apps shouldn't get confused when the next motion
event comes in. This is what I've done in this patch.
author | Ryan C. Gordon <icculus@icculus.org> |
---|---|
date | Fri, 27 Dec 2002 20:52:41 +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 |