Home | History | Annotate | Download | only in video
      1 /*
      2     SDL - Simple DirectMedia Layer
      3     Copyright (C) 1997-2012 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)+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 */
    529