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