e14743d1 |
1 | /* |
2 | SDL - Simple DirectMedia Layer |
3 | Copyright (C) 1997-2009 Sam Lantinga |
4 | |
5 | This library is free software; you can redistribute it and/or |
6 | modify it under the terms of the GNU Lesser General Public |
7 | License as published by the Free Software Foundation; either |
8 | version 2.1 of the License, or (at your option) any later version. |
9 | |
10 | This library is distributed in the hope that it will be useful, |
11 | but WITHOUT ANY WARRANTY; without even the implied warranty of |
12 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU |
13 | Lesser General Public License for more details. |
14 | |
15 | You should have received a copy of the GNU Lesser General Public |
16 | License along with this library; if not, write to the Free Software |
17 | Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA |
18 | |
19 | Sam Lantinga |
20 | slouken@libsdl.org |
21 | */ |
22 | #include "SDL_config.h" |
23 | |
24 | #ifndef _SDL_blit_h |
25 | #define _SDL_blit_h |
26 | |
27 | #include "SDL_endian.h" |
28 | |
29 | /* The structure passed to the low level blit functions */ |
30 | typedef struct { |
31 | Uint8 *s_pixels; |
32 | int s_width; |
33 | int s_height; |
34 | int s_skip; |
35 | Uint8 *d_pixels; |
36 | int d_width; |
37 | int d_height; |
38 | int d_skip; |
39 | void *aux_data; |
40 | SDL_PixelFormat *src; |
41 | Uint8 *table; |
42 | SDL_PixelFormat *dst; |
43 | } SDL_BlitInfo; |
44 | |
45 | /* The type definition for the low level blit functions */ |
46 | typedef void (*SDL_loblit)(SDL_BlitInfo *info); |
47 | |
48 | /* This is the private info structure for software accelerated blits */ |
49 | struct private_swaccel { |
50 | SDL_loblit blit; |
51 | void *aux_data; |
52 | }; |
53 | |
54 | /* Blit mapping definition */ |
55 | typedef struct SDL_BlitMap { |
56 | SDL_Surface *dst; |
57 | int identity; |
58 | Uint8 *table; |
59 | SDL_blit hw_blit; |
60 | SDL_blit sw_blit; |
61 | struct private_hwaccel *hw_data; |
62 | struct private_swaccel *sw_data; |
63 | |
64 | /* the version count matches the destination; mismatch indicates |
65 | an invalid mapping */ |
66 | unsigned int format_version; |
67 | } SDL_BlitMap; |
68 | |
69 | |
70 | /* Functions found in SDL_blit.c */ |
71 | extern int SDL_CalculateBlit(SDL_Surface *surface); |
72 | |
73 | /* Functions found in SDL_blit_{0,1,N,A}.c */ |
74 | extern SDL_loblit SDL_CalculateBlit0(SDL_Surface *surface, int complex); |
75 | extern SDL_loblit SDL_CalculateBlit1(SDL_Surface *surface, int complex); |
76 | extern SDL_loblit SDL_CalculateBlitN(SDL_Surface *surface, int complex); |
77 | extern SDL_loblit SDL_CalculateAlphaBlit(SDL_Surface *surface, int complex); |
78 | |
79 | /* |
80 | * Useful macros for blitting routines |
81 | */ |
82 | |
83 | #define FORMAT_EQUAL(A, B) \ |
84 | ((A)->BitsPerPixel == (B)->BitsPerPixel \ |
85 | && ((A)->Rmask == (B)->Rmask) && ((A)->Amask == (B)->Amask)) |
86 | |
87 | /* Load pixel of the specified format from a buffer and get its R-G-B values */ |
88 | /* FIXME: rescale values to 0..255 here? */ |
89 | #define RGB_FROM_PIXEL(Pixel, fmt, r, g, b) \ |
90 | { \ |
91 | r = (((Pixel&fmt->Rmask)>>fmt->Rshift)<<fmt->Rloss); \ |
92 | g = (((Pixel&fmt->Gmask)>>fmt->Gshift)<<fmt->Gloss); \ |
93 | b = (((Pixel&fmt->Bmask)>>fmt->Bshift)<<fmt->Bloss); \ |
94 | } |
95 | #define RGB_FROM_RGB565(Pixel, r, g, b) \ |
96 | { \ |
97 | r = (((Pixel&0xF800)>>11)<<3); \ |
98 | g = (((Pixel&0x07E0)>>5)<<2); \ |
99 | b = ((Pixel&0x001F)<<3); \ |
100 | } |
101 | #define RGB_FROM_RGB555(Pixel, r, g, b) \ |
102 | { \ |
103 | r = (((Pixel&0x7C00)>>10)<<3); \ |
104 | g = (((Pixel&0x03E0)>>5)<<3); \ |
105 | b = ((Pixel&0x001F)<<3); \ |
106 | } |
107 | #define RGB_FROM_RGB888(Pixel, r, g, b) \ |
108 | { \ |
109 | r = ((Pixel&0xFF0000)>>16); \ |
110 | g = ((Pixel&0xFF00)>>8); \ |
111 | b = (Pixel&0xFF); \ |
112 | } |
113 | #define RETRIEVE_RGB_PIXEL(buf, bpp, Pixel) \ |
114 | do { \ |
115 | switch (bpp) { \ |
116 | case 2: \ |
117 | Pixel = *((Uint16 *)(buf)); \ |
118 | break; \ |
119 | \ |
120 | case 3: { \ |
121 | Uint8 *B = (Uint8 *)(buf); \ |
122 | if(SDL_BYTEORDER == SDL_LIL_ENDIAN) { \ |
123 | Pixel = B[0] + (B[1] << 8) + (B[2] << 16); \ |
124 | } else { \ |
125 | Pixel = (B[0] << 16) + (B[1] << 8) + B[2]; \ |
126 | } \ |
127 | } \ |
128 | break; \ |
129 | \ |
130 | case 4: \ |
131 | Pixel = *((Uint32 *)(buf)); \ |
132 | break; \ |
133 | \ |
134 | default: \ |
135 | Pixel = 0; /* appease gcc */ \ |
136 | break; \ |
137 | } \ |
138 | } while(0) |
139 | |
140 | #define DISEMBLE_RGB(buf, bpp, fmt, Pixel, r, g, b) \ |
141 | do { \ |
142 | switch (bpp) { \ |
143 | case 2: \ |
144 | Pixel = *((Uint16 *)(buf)); \ |
145 | break; \ |
146 | \ |
147 | case 3: { \ |
148 | Uint8 *B = (Uint8 *)buf; \ |
149 | if(SDL_BYTEORDER == SDL_LIL_ENDIAN) { \ |
150 | Pixel = B[0] + (B[1] << 8) + (B[2] << 16); \ |
151 | } else { \ |
152 | Pixel = (B[0] << 16) + (B[1] << 8) + B[2]; \ |
153 | } \ |
154 | } \ |
155 | break; \ |
156 | \ |
157 | case 4: \ |
158 | Pixel = *((Uint32 *)(buf)); \ |
159 | break; \ |
160 | \ |
161 | default: \ |
162 | Pixel = 0; /* prevent gcc from complaining */ \ |
163 | break; \ |
164 | } \ |
165 | RGB_FROM_PIXEL(Pixel, fmt, r, g, b); \ |
166 | } while(0) |
167 | |
168 | /* Assemble R-G-B values into a specified pixel format and store them */ |
169 | #ifdef __NDS__ /* FIXME */ |
170 | #define PIXEL_FROM_RGB(Pixel, fmt, r, g, b) \ |
171 | { \ |
172 | Pixel = ((r>>fmt->Rloss)<<fmt->Rshift)| \ |
173 | ((g>>fmt->Gloss)<<fmt->Gshift)| \ |
174 | ((b>>fmt->Bloss)<<fmt->Bshift) | (1<<15); \ |
175 | } |
176 | #else |
177 | #define PIXEL_FROM_RGB(Pixel, fmt, r, g, b) \ |
178 | { \ |
179 | Pixel = ((r>>fmt->Rloss)<<fmt->Rshift)| \ |
180 | ((g>>fmt->Gloss)<<fmt->Gshift)| \ |
181 | ((b>>fmt->Bloss)<<fmt->Bshift); \ |
182 | } |
183 | #endif /* __NDS__ FIXME */ |
184 | #define RGB565_FROM_RGB(Pixel, r, g, b) \ |
185 | { \ |
186 | Pixel = ((r>>3)<<11)|((g>>2)<<5)|(b>>3); \ |
187 | } |
188 | #define RGB555_FROM_RGB(Pixel, r, g, b) \ |
189 | { \ |
190 | Pixel = ((r>>3)<<10)|((g>>3)<<5)|(b>>3); \ |
191 | } |
192 | #define RGB888_FROM_RGB(Pixel, r, g, b) \ |
193 | { \ |
194 | Pixel = (r<<16)|(g<<8)|b; \ |
195 | } |
196 | #define ASSEMBLE_RGB(buf, bpp, fmt, r, g, b) \ |
197 | { \ |
198 | switch (bpp) { \ |
199 | case 2: { \ |
200 | Uint16 Pixel; \ |
201 | \ |
202 | PIXEL_FROM_RGB(Pixel, fmt, r, g, b); \ |
203 | *((Uint16 *)(buf)) = Pixel; \ |
204 | } \ |
205 | break; \ |
206 | \ |
207 | case 3: { \ |
208 | if(SDL_BYTEORDER == SDL_LIL_ENDIAN) { \ |
209 | *((buf)+fmt->Rshift/8) = r; \ |
210 | *((buf)+fmt->Gshift/8) = g; \ |
211 | *((buf)+fmt->Bshift/8) = b; \ |
212 | } else { \ |
213 | *((buf)+2-fmt->Rshift/8) = r; \ |
214 | *((buf)+2-fmt->Gshift/8) = g; \ |
215 | *((buf)+2-fmt->Bshift/8) = b; \ |
216 | } \ |
217 | } \ |
218 | break; \ |
219 | \ |
220 | case 4: { \ |
221 | Uint32 Pixel; \ |
222 | \ |
223 | PIXEL_FROM_RGB(Pixel, fmt, r, g, b); \ |
224 | *((Uint32 *)(buf)) = Pixel; \ |
225 | } \ |
226 | break; \ |
227 | } \ |
228 | } |
229 | #define ASSEMBLE_RGB_AMASK(buf, bpp, fmt, r, g, b, Amask) \ |
230 | { \ |
231 | switch (bpp) { \ |
232 | case 2: { \ |
233 | Uint16 *bufp; \ |
234 | Uint16 Pixel; \ |
235 | \ |
236 | bufp = (Uint16 *)buf; \ |
237 | PIXEL_FROM_RGB(Pixel, fmt, r, g, b); \ |
238 | *bufp = Pixel | (*bufp & Amask); \ |
239 | } \ |
240 | break; \ |
241 | \ |
242 | case 3: { \ |
243 | if(SDL_BYTEORDER == SDL_LIL_ENDIAN) { \ |
244 | *((buf)+fmt->Rshift/8) = r; \ |
245 | *((buf)+fmt->Gshift/8) = g; \ |
246 | *((buf)+fmt->Bshift/8) = b; \ |
247 | } else { \ |
248 | *((buf)+2-fmt->Rshift/8) = r; \ |
249 | *((buf)+2-fmt->Gshift/8) = g; \ |
250 | *((buf)+2-fmt->Bshift/8) = b; \ |
251 | } \ |
252 | } \ |
253 | break; \ |
254 | \ |
255 | case 4: { \ |
256 | Uint32 *bufp; \ |
257 | Uint32 Pixel; \ |
258 | \ |
259 | bufp = (Uint32 *)buf; \ |
260 | PIXEL_FROM_RGB(Pixel, fmt, r, g, b); \ |
261 | *bufp = Pixel | (*bufp & Amask); \ |
262 | } \ |
263 | break; \ |
264 | } \ |
265 | } |
266 | |
267 | /* FIXME: Should we rescale alpha into 0..255 here? */ |
268 | #define RGBA_FROM_PIXEL(Pixel, fmt, r, g, b, a) \ |
269 | { \ |
270 | r = ((Pixel&fmt->Rmask)>>fmt->Rshift)<<fmt->Rloss; \ |
271 | g = ((Pixel&fmt->Gmask)>>fmt->Gshift)<<fmt->Gloss; \ |
272 | b = ((Pixel&fmt->Bmask)>>fmt->Bshift)<<fmt->Bloss; \ |
273 | a = ((Pixel&fmt->Amask)>>fmt->Ashift)<<fmt->Aloss; \ |
274 | } |
275 | #define RGBA_FROM_8888(Pixel, fmt, r, g, b, a) \ |
276 | { \ |
277 | r = (Pixel&fmt->Rmask)>>fmt->Rshift; \ |
278 | g = (Pixel&fmt->Gmask)>>fmt->Gshift; \ |
279 | b = (Pixel&fmt->Bmask)>>fmt->Bshift; \ |
280 | a = (Pixel&fmt->Amask)>>fmt->Ashift; \ |
281 | } |
282 | #define RGBA_FROM_RGBA8888(Pixel, r, g, b, a) \ |
283 | { \ |
284 | r = (Pixel>>24); \ |
285 | g = ((Pixel>>16)&0xFF); \ |
286 | b = ((Pixel>>8)&0xFF); \ |
287 | a = (Pixel&0xFF); \ |
288 | } |
289 | #define RGBA_FROM_ARGB8888(Pixel, r, g, b, a) \ |
290 | { \ |
291 | r = ((Pixel>>16)&0xFF); \ |
292 | g = ((Pixel>>8)&0xFF); \ |
293 | b = (Pixel&0xFF); \ |
294 | a = (Pixel>>24); \ |
295 | } |
296 | #define RGBA_FROM_ABGR8888(Pixel, r, g, b, a) \ |
297 | { \ |
298 | r = (Pixel&0xFF); \ |
299 | g = ((Pixel>>8)&0xFF); \ |
300 | b = ((Pixel>>16)&0xFF); \ |
301 | a = (Pixel>>24); \ |
302 | } |
303 | #define DISEMBLE_RGBA(buf, bpp, fmt, Pixel, r, g, b, a) \ |
304 | do { \ |
305 | switch (bpp) { \ |
306 | case 2: \ |
307 | Pixel = *((Uint16 *)(buf)); \ |
308 | break; \ |
309 | \ |
310 | case 3: {/* FIXME: broken code (no alpha) */ \ |
311 | Uint8 *b = (Uint8 *)buf; \ |
312 | if(SDL_BYTEORDER == SDL_LIL_ENDIAN) { \ |
313 | Pixel = b[0] + (b[1] << 8) + (b[2] << 16); \ |
314 | } else { \ |
315 | Pixel = (b[0] << 16) + (b[1] << 8) + b[2]; \ |
316 | } \ |
317 | } \ |
318 | break; \ |
319 | \ |
320 | case 4: \ |
321 | Pixel = *((Uint32 *)(buf)); \ |
322 | break; \ |
323 | \ |
324 | default: \ |
325 | Pixel = 0; /* stop gcc complaints */ \ |
326 | break; \ |
327 | } \ |
328 | RGBA_FROM_PIXEL(Pixel, fmt, r, g, b, a); \ |
329 | Pixel &= ~fmt->Amask; \ |
330 | } while(0) |
331 | |
332 | /* FIXME: this isn't correct, especially for Alpha (maximum != 255) */ |
333 | #ifdef __NDS__ /* FIXME */ |
334 | #define PIXEL_FROM_RGBA(Pixel, fmt, r, g, b, a) \ |
335 | { \ |
336 | Pixel = ((r>>fmt->Rloss)<<fmt->Rshift)| \ |
337 | ((g>>fmt->Gloss)<<fmt->Gshift)| \ |
338 | ((b>>fmt->Bloss)<<fmt->Bshift)| \ |
339 | ((a>>fmt->Aloss)<<fmt->Ashift) | (1<<15); \ |
340 | } |
341 | #else |
342 | #define PIXEL_FROM_RGBA(Pixel, fmt, r, g, b, a) \ |
343 | { \ |
344 | Pixel = ((r>>fmt->Rloss)<<fmt->Rshift)| \ |
345 | ((g>>fmt->Gloss)<<fmt->Gshift)| \ |
346 | ((b>>fmt->Bloss)<<fmt->Bshift)| \ |
347 | ((a>>fmt->Aloss)<<fmt->Ashift); \ |
348 | } |
349 | #endif /* __NDS__ FIXME */ |
350 | #define ASSEMBLE_RGBA(buf, bpp, fmt, r, g, b, a) \ |
351 | { \ |
352 | switch (bpp) { \ |
353 | case 2: { \ |
354 | Uint16 Pixel; \ |
355 | \ |
356 | PIXEL_FROM_RGBA(Pixel, fmt, r, g, b, a); \ |
357 | *((Uint16 *)(buf)) = Pixel; \ |
358 | } \ |
359 | break; \ |
360 | \ |
361 | case 3: { /* FIXME: broken code (no alpha) */ \ |
362 | if(SDL_BYTEORDER == SDL_LIL_ENDIAN) { \ |
363 | *((buf)+fmt->Rshift/8) = r; \ |
364 | *((buf)+fmt->Gshift/8) = g; \ |
365 | *((buf)+fmt->Bshift/8) = b; \ |
366 | } else { \ |
367 | *((buf)+2-fmt->Rshift/8) = r; \ |
368 | *((buf)+2-fmt->Gshift/8) = g; \ |
369 | *((buf)+2-fmt->Bshift/8) = b; \ |
370 | } \ |
371 | } \ |
372 | break; \ |
373 | \ |
374 | case 4: { \ |
375 | Uint32 Pixel; \ |
376 | \ |
377 | PIXEL_FROM_RGBA(Pixel, fmt, r, g, b, a); \ |
378 | *((Uint32 *)(buf)) = Pixel; \ |
379 | } \ |
380 | break; \ |
381 | } \ |
382 | } |
383 | |
384 | /* Blend the RGB values of two Pixels based on a source alpha value */ |
385 | #define ALPHA_BLEND(sR, sG, sB, A, dR, dG, dB) \ |
386 | do { \ |
387 | dR = (((sR-dR)*(A)+255)>>8)+dR; \ |
388 | dG = (((sG-dG)*(A)+255)>>8)+dG; \ |
389 | dB = (((sB-dB)*(A)+255)>>8)+dB; \ |
390 | } while(0) |
391 | |
392 | |
393 | /* This is a very useful loop for optimizing blitters */ |
394 | #if defined(_MSC_VER) && (_MSC_VER == 1300) |
395 | /* There's a bug in the Visual C++ 7 optimizer when compiling this code */ |
396 | #else |
397 | #define USE_DUFFS_LOOP |
398 | #endif |
399 | #ifdef USE_DUFFS_LOOP |
400 | |
401 | /* 8-times unrolled loop */ |
402 | #define DUFFS_LOOP8(pixel_copy_increment, width) \ |
403 | { int n = (width+7)/8; \ |
404 | switch (width & 7) { \ |
405 | case 0: do { pixel_copy_increment; \ |
406 | case 7: pixel_copy_increment; \ |
407 | case 6: pixel_copy_increment; \ |
408 | case 5: pixel_copy_increment; \ |
409 | case 4: pixel_copy_increment; \ |
410 | case 3: pixel_copy_increment; \ |
411 | case 2: pixel_copy_increment; \ |
412 | case 1: pixel_copy_increment; \ |
413 | } while ( --n > 0 ); \ |
414 | } \ |
415 | } |
416 | |
417 | /* 4-times unrolled loop */ |
418 | #define DUFFS_LOOP4(pixel_copy_increment, width) \ |
419 | { int n = (width+3)/4; \ |
420 | switch (width & 3) { \ |
421 | case 0: do { pixel_copy_increment; \ |
422 | case 3: pixel_copy_increment; \ |
423 | case 2: pixel_copy_increment; \ |
424 | case 1: pixel_copy_increment; \ |
425 | } while ( --n > 0 ); \ |
426 | } \ |
427 | } |
428 | |
429 | /* 2 - times unrolled loop */ |
430 | #define DUFFS_LOOP_DOUBLE2(pixel_copy_increment, \ |
431 | double_pixel_copy_increment, width) \ |
432 | { int n, w = width; \ |
433 | if( w & 1 ) { \ |
434 | pixel_copy_increment; \ |
435 | w--; \ |
436 | } \ |
437 | if ( w > 0 ) { \ |
438 | n = ( w + 2) / 4; \ |
439 | switch( w & 2 ) { \ |
440 | case 0: do { double_pixel_copy_increment; \ |
441 | case 2: double_pixel_copy_increment; \ |
442 | } while ( --n > 0 ); \ |
443 | } \ |
444 | } \ |
445 | } |
446 | |
447 | /* 2 - times unrolled loop 4 pixels */ |
448 | #define DUFFS_LOOP_QUATRO2(pixel_copy_increment, \ |
449 | double_pixel_copy_increment, \ |
450 | quatro_pixel_copy_increment, width) \ |
451 | { int n, w = width; \ |
452 | if(w & 1) { \ |
453 | pixel_copy_increment; \ |
454 | w--; \ |
455 | } \ |
456 | if(w & 2) { \ |
457 | double_pixel_copy_increment; \ |
458 | w -= 2; \ |
459 | } \ |
460 | if ( w > 0 ) { \ |
461 | n = ( w + 7 ) / 8; \ |
462 | switch( w & 4 ) { \ |
463 | case 0: do { quatro_pixel_copy_increment; \ |
464 | case 4: quatro_pixel_copy_increment; \ |
465 | } while ( --n > 0 ); \ |
466 | } \ |
467 | } \ |
468 | } |
469 | |
470 | /* Use the 8-times version of the loop by default */ |
471 | #define DUFFS_LOOP(pixel_copy_increment, width) \ |
472 | DUFFS_LOOP8(pixel_copy_increment, width) |
473 | |
474 | #else |
475 | |
476 | /* Don't use Duff's device to unroll loops */ |
477 | #define DUFFS_LOOP_DOUBLE2(pixel_copy_increment, \ |
478 | double_pixel_copy_increment, width) \ |
479 | { int n = width; \ |
480 | if( n & 1 ) { \ |
481 | pixel_copy_increment; \ |
482 | n--; \ |
483 | } \ |
484 | n=n>>1; \ |
485 | for(; n > 0; --n) { \ |
486 | double_pixel_copy_increment; \ |
487 | } \ |
488 | } |
489 | |
490 | /* Don't use Duff's device to unroll loops */ |
491 | #define DUFFS_LOOP_QUATRO2(pixel_copy_increment, \ |
492 | double_pixel_copy_increment, \ |
493 | quatro_pixel_copy_increment, width) \ |
494 | { int n = width; \ |
495 | if(n & 1) { \ |
496 | pixel_copy_increment; \ |
497 | n--; \ |
498 | } \ |
499 | if(n & 2) { \ |
500 | double_pixel_copy_increment; \ |
501 | n -= 2; \ |
502 | } \ |
503 | n=n>>2; \ |
504 | for(; n > 0; --n) { \ |
505 | quatro_pixel_copy_increment; \ |
506 | } \ |
507 | } |
508 | |
509 | /* Don't use Duff's device to unroll loops */ |
510 | #define DUFFS_LOOP(pixel_copy_increment, width) \ |
511 | { int n; \ |
512 | for ( n=width; n > 0; --n ) { \ |
513 | pixel_copy_increment; \ |
514 | } \ |
515 | } |
516 | #define DUFFS_LOOP8(pixel_copy_increment, width) \ |
517 | DUFFS_LOOP(pixel_copy_increment, width) |
518 | #define DUFFS_LOOP4(pixel_copy_increment, width) \ |
519 | DUFFS_LOOP(pixel_copy_increment, width) |
520 | |
521 | #endif /* USE_DUFFS_LOOP */ |
522 | |
523 | /* Prevent Visual C++ 6.0 from printing out stupid warnings */ |
524 | #if defined(_MSC_VER) && (_MSC_VER >= 600) |
525 | #pragma warning(disable: 4550) |
526 | #endif |
527 | |
528 | #endif /* _SDL_blit_h */ |