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