Home | History | Annotate | Download | only in video
      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 (at) 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