• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2     SDL - Simple DirectMedia Layer
3     Copyright (C) 1997-2006 Sam Lantinga
4 
5     This library is free software; you can redistribute it and/or
6     modify it under the terms of the GNU Lesser General Public
7     License as published by the Free Software Foundation; either
8     version 2.1 of the License, or (at your option) any later version.
9 
10     This library is distributed in the hope that it will be useful,
11     but WITHOUT ANY WARRANTY; without even the implied warranty of
12     MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
13     Lesser General Public License for more details.
14 
15     You should have received a copy of the GNU Lesser General Public
16     License along with this library; if not, write to the Free Software
17     Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
18 
19     Sam Lantinga
20     slouken@libsdl.org
21 */
22 #include "SDL_config.h"
23 
24 #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))>>8)+dR;		\
388 	dG = (((sG-dG)*(A))>>8)+dG;		\
389 	dB = (((sB-dB)*(A))>>8)+dB;		\
390 } while(0)
391 
392 /* Blend the RGB values of two Pixels based on a source alpha value */
393 #define ACCURATE_ALPHA_BLEND(sR, sG, sB, sA, dR, dG, dB)	\
394 do {						\
395     unsigned tR, tG, tB, tA; \
396     tA = 255 - sA; \
397     tR = 1 + (sR * sA) + (dR * tA); \
398     dR = (tR + (tR >> 8)) >> 8; \
399     tG = 1 + (sG * sA) + (dG * tA); \
400     dG = (tG + (tG >> 8)) >> 8; \
401     tB = 1 + (sB * sA) + (dB * tA); \
402     dB = (tB + (tB >> 8)) >> 8; \
403 } while(0)
404 
405 
406 /* This is a very useful loop for optimizing blitters */
407 #if defined(_MSC_VER) && (_MSC_VER == 1300)
408 /* There's a bug in the Visual C++ 7 optimizer when compiling this code */
409 #else
410 #define USE_DUFFS_LOOP
411 #endif
412 #ifdef USE_DUFFS_LOOP
413 
414 /* 8-times unrolled loop */
415 #define DUFFS_LOOP8(pixel_copy_increment, width)			\
416 { int n = (width+7)/8;							\
417 	switch (width & 7) {						\
418 	case 0: do {	pixel_copy_increment;				\
419 	case 7:		pixel_copy_increment;				\
420 	case 6:		pixel_copy_increment;				\
421 	case 5:		pixel_copy_increment;				\
422 	case 4:		pixel_copy_increment;				\
423 	case 3:		pixel_copy_increment;				\
424 	case 2:		pixel_copy_increment;				\
425 	case 1:		pixel_copy_increment;				\
426 		} while ( --n > 0 );					\
427 	}								\
428 }
429 
430 /* 4-times unrolled loop */
431 #define DUFFS_LOOP4(pixel_copy_increment, width)			\
432 { int n = (width+3)/4;							\
433 	switch (width & 3) {						\
434 	case 0: do {	pixel_copy_increment;				\
435 	case 3:		pixel_copy_increment;				\
436 	case 2:		pixel_copy_increment;				\
437 	case 1:		pixel_copy_increment;				\
438 		} while ( --n > 0 );					\
439 	}								\
440 }
441 
442 /* 2 - times unrolled loop */
443 #define DUFFS_LOOP_DOUBLE2(pixel_copy_increment,			\
444 				double_pixel_copy_increment, width)	\
445 { int n, w = width;							\
446 	if( w & 1 ) {							\
447 	    pixel_copy_increment;					\
448 	    w--;							\
449 	}								\
450 	if ( w > 0 )	{						\
451 	    n = ( w + 2) / 4;						\
452 	    switch( w & 2 ) {						\
453 	    case 0: do {	double_pixel_copy_increment;		\
454 	    case 2:		double_pixel_copy_increment;		\
455 		    } while ( --n > 0 );					\
456 	    }								\
457 	}								\
458 }
459 
460 /* 2 - times unrolled loop 4 pixels */
461 #define DUFFS_LOOP_QUATRO2(pixel_copy_increment,			\
462 				double_pixel_copy_increment,		\
463 				quatro_pixel_copy_increment, width)	\
464 { int n, w = width;								\
465         if(w & 1) {							\
466 	  pixel_copy_increment;						\
467 	  w--;								\
468 	}								\
469 	if(w & 2) {							\
470 	  double_pixel_copy_increment;					\
471 	  w -= 2;							\
472 	}								\
473 	if ( w > 0 ) {							\
474 	    n = ( w + 7 ) / 8;						\
475 	    switch( w & 4 ) {						\
476 	    case 0: do {	quatro_pixel_copy_increment;		\
477 	    case 4:		quatro_pixel_copy_increment;		\
478 		    } while ( --n > 0 );					\
479 	    }								\
480 	}								\
481 }
482 
483 /* Use the 8-times version of the loop by default */
484 #define DUFFS_LOOP(pixel_copy_increment, width)				\
485 	DUFFS_LOOP8(pixel_copy_increment, width)
486 
487 #else
488 
489 /* Don't use Duff's device to unroll loops */
490 #define DUFFS_LOOP_DOUBLE2(pixel_copy_increment,			\
491 			 double_pixel_copy_increment, width)		\
492 { int n = width;								\
493     if( n & 1 ) {							\
494 	pixel_copy_increment;						\
495 	n--;								\
496     }									\
497     n=n>>1;								\
498     for(; n > 0; --n) {   						\
499 	double_pixel_copy_increment;					\
500     }									\
501 }
502 
503 /* Don't use Duff's device to unroll loops */
504 #define DUFFS_LOOP_QUATRO2(pixel_copy_increment,			\
505 				double_pixel_copy_increment,		\
506 				quatro_pixel_copy_increment, width)	\
507 { int n = width;								\
508         if(n & 1) {							\
509 	  pixel_copy_increment;						\
510 	  n--;								\
511 	}								\
512 	if(n & 2) {							\
513 	  double_pixel_copy_increment;					\
514 	  n -= 2;							\
515 	}								\
516 	n=n>>2;								\
517 	for(; n > 0; --n) {   						\
518 	  quatro_pixel_copy_increment;					\
519         }								\
520 }
521 
522 /* Don't use Duff's device to unroll loops */
523 #define DUFFS_LOOP(pixel_copy_increment, width)				\
524 { int n;								\
525 	for ( n=width; n > 0; --n ) {					\
526 		pixel_copy_increment;					\
527 	}								\
528 }
529 #define DUFFS_LOOP8(pixel_copy_increment, width)			\
530 	DUFFS_LOOP(pixel_copy_increment, width)
531 #define DUFFS_LOOP4(pixel_copy_increment, width)			\
532 	DUFFS_LOOP(pixel_copy_increment, width)
533 
534 #endif /* USE_DUFFS_LOOP */
535 
536 /* Prevent Visual C++ 6.0 from printing out stupid warnings */
537 #if defined(_MSC_VER) && (_MSC_VER >= 600)
538 #pragma warning(disable: 4550)
539 #endif
540 
541 #endif /* _SDL_blit_h */
542