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 #include "SDL_video.h"
     25 #include "SDL_blit.h"
     26 #include "SDL_sysvideo.h"
     27 #include "SDL_endian.h"
     28 
     29 /* Functions to blit from 8-bit surfaces to other surfaces */
     30 
     31 static void Blit1to1(SDL_BlitInfo *info)
     32 {
     33 #ifndef USE_DUFFS_LOOP
     34 	int c;
     35 #endif
     36 	int width, height;
     37 	Uint8 *src, *map, *dst;
     38 	int srcskip, dstskip;
     39 
     40 	/* Set up some basic variables */
     41 	width = info->d_width;
     42 	height = info->d_height;
     43 	src = info->s_pixels;
     44 	srcskip = info->s_skip;
     45 	dst = info->d_pixels;
     46 	dstskip = info->d_skip;
     47 	map = info->table;
     48 
     49 	while ( height-- ) {
     50 #ifdef USE_DUFFS_LOOP
     51 		DUFFS_LOOP(
     52 			{
     53 			  *dst = map[*src];
     54 			}
     55 			dst++;
     56 			src++;
     57 		, width);
     58 #else
     59 		for ( c=width; c; --c ) {
     60 		        *dst = map[*src];
     61 			dst++;
     62 			src++;
     63 		}
     64 #endif
     65 		src += srcskip;
     66 		dst += dstskip;
     67 	}
     68 }
     69 /* This is now endian dependent */
     70 #if ( SDL_BYTEORDER == SDL_LIL_ENDIAN )
     71 #define HI	1
     72 #define LO	0
     73 #else /* ( SDL_BYTEORDER == SDL_BIG_ENDIAN ) */
     74 #define HI	0
     75 #define LO	1
     76 #endif
     77 static void Blit1to2(SDL_BlitInfo *info)
     78 {
     79 #ifndef USE_DUFFS_LOOP
     80 	int c;
     81 #endif
     82 	int width, height;
     83 	Uint8 *src, *dst;
     84 	Uint16 *map;
     85 	int srcskip, dstskip;
     86 
     87 	/* Set up some basic variables */
     88 	width = info->d_width;
     89 	height = info->d_height;
     90 	src = info->s_pixels;
     91 	srcskip = info->s_skip;
     92 	dst = info->d_pixels;
     93 	dstskip = info->d_skip;
     94 	map = (Uint16 *)info->table;
     95 
     96 #ifdef USE_DUFFS_LOOP
     97 	while ( height-- ) {
     98 		DUFFS_LOOP(
     99 		{
    100 			*(Uint16 *)dst = map[*src++];
    101 			dst += 2;
    102 		},
    103 		width);
    104 		src += srcskip;
    105 		dst += dstskip;
    106 	}
    107 #else
    108 	/* Memory align at 4-byte boundary, if necessary */
    109 	if ( (long)dst & 0x03 ) {
    110 		/* Don't do anything if width is 0 */
    111 		if ( width == 0 ) {
    112 			return;
    113 		}
    114 		--width;
    115 
    116 		while ( height-- ) {
    117 			/* Perform copy alignment */
    118 			*(Uint16 *)dst = map[*src++];
    119 			dst += 2;
    120 
    121 			/* Copy in 4 pixel chunks */
    122 			for ( c=width/4; c; --c ) {
    123 				*(Uint32 *)dst =
    124 					(map[src[HI]]<<16)|(map[src[LO]]);
    125 				src += 2;
    126 				dst += 4;
    127 				*(Uint32 *)dst =
    128 					(map[src[HI]]<<16)|(map[src[LO]]);
    129 				src += 2;
    130 				dst += 4;
    131 			}
    132 			/* Get any leftovers */
    133 			switch (width & 3) {
    134 				case 3:
    135 					*(Uint16 *)dst = map[*src++];
    136 					dst += 2;
    137 				case 2:
    138 					*(Uint32 *)dst =
    139 					  (map[src[HI]]<<16)|(map[src[LO]]);
    140 					src += 2;
    141 					dst += 4;
    142 					break;
    143 				case 1:
    144 					*(Uint16 *)dst = map[*src++];
    145 					dst += 2;
    146 					break;
    147 			}
    148 			src += srcskip;
    149 			dst += dstskip;
    150 		}
    151 	} else {
    152 		while ( height-- ) {
    153 			/* Copy in 4 pixel chunks */
    154 			for ( c=width/4; c; --c ) {
    155 				*(Uint32 *)dst =
    156 					(map[src[HI]]<<16)|(map[src[LO]]);
    157 				src += 2;
    158 				dst += 4;
    159 				*(Uint32 *)dst =
    160 					(map[src[HI]]<<16)|(map[src[LO]]);
    161 				src += 2;
    162 				dst += 4;
    163 			}
    164 			/* Get any leftovers */
    165 			switch (width & 3) {
    166 				case 3:
    167 					*(Uint16 *)dst = map[*src++];
    168 					dst += 2;
    169 				case 2:
    170 					*(Uint32 *)dst =
    171 					  (map[src[HI]]<<16)|(map[src[LO]]);
    172 					src += 2;
    173 					dst += 4;
    174 					break;
    175 				case 1:
    176 					*(Uint16 *)dst = map[*src++];
    177 					dst += 2;
    178 					break;
    179 			}
    180 			src += srcskip;
    181 			dst += dstskip;
    182 		}
    183 	}
    184 #endif /* USE_DUFFS_LOOP */
    185 }
    186 static void Blit1to3(SDL_BlitInfo *info)
    187 {
    188 #ifndef USE_DUFFS_LOOP
    189 	int c;
    190 #endif
    191 	int o;
    192 	int width, height;
    193 	Uint8 *src, *map, *dst;
    194 	int srcskip, dstskip;
    195 
    196 	/* Set up some basic variables */
    197 	width = info->d_width;
    198 	height = info->d_height;
    199 	src = info->s_pixels;
    200 	srcskip = info->s_skip;
    201 	dst = info->d_pixels;
    202 	dstskip = info->d_skip;
    203 	map = info->table;
    204 
    205 	while ( height-- ) {
    206 #ifdef USE_DUFFS_LOOP
    207 		DUFFS_LOOP(
    208 			{
    209 				o = *src * 4;
    210 				dst[0] = map[o++];
    211 				dst[1] = map[o++];
    212 				dst[2] = map[o++];
    213 			}
    214 			src++;
    215 			dst += 3;
    216 		, width);
    217 #else
    218 		for ( c=width; c; --c ) {
    219 			o = *src * 4;
    220 			dst[0] = map[o++];
    221 			dst[1] = map[o++];
    222 			dst[2] = map[o++];
    223 			src++;
    224 			dst += 3;
    225 		}
    226 #endif /* USE_DUFFS_LOOP */
    227 		src += srcskip;
    228 		dst += dstskip;
    229 	}
    230 }
    231 static void Blit1to4(SDL_BlitInfo *info)
    232 {
    233 #ifndef USE_DUFFS_LOOP
    234 	int c;
    235 #endif
    236 	int width, height;
    237 	Uint8 *src;
    238 	Uint32 *map, *dst;
    239 	int srcskip, dstskip;
    240 
    241 	/* Set up some basic variables */
    242 	width = info->d_width;
    243 	height = info->d_height;
    244 	src = info->s_pixels;
    245 	srcskip = info->s_skip;
    246 	dst = (Uint32 *)info->d_pixels;
    247 	dstskip = info->d_skip/4;
    248 	map = (Uint32 *)info->table;
    249 
    250 	while ( height-- ) {
    251 #ifdef USE_DUFFS_LOOP
    252 		DUFFS_LOOP(
    253 			*dst++ = map[*src++];
    254 		, width);
    255 #else
    256 		for ( c=width/4; c; --c ) {
    257 			*dst++ = map[*src++];
    258 			*dst++ = map[*src++];
    259 			*dst++ = map[*src++];
    260 			*dst++ = map[*src++];
    261 		}
    262 		switch ( width & 3 ) {
    263 			case 3:
    264 				*dst++ = map[*src++];
    265 			case 2:
    266 				*dst++ = map[*src++];
    267 			case 1:
    268 				*dst++ = map[*src++];
    269 		}
    270 #endif /* USE_DUFFS_LOOP */
    271 		src += srcskip;
    272 		dst += dstskip;
    273 	}
    274 }
    275 
    276 static void Blit1to1Key(SDL_BlitInfo *info)
    277 {
    278 	int width = info->d_width;
    279 	int height = info->d_height;
    280 	Uint8 *src = info->s_pixels;
    281 	int srcskip = info->s_skip;
    282 	Uint8 *dst = info->d_pixels;
    283 	int dstskip = info->d_skip;
    284 	Uint8 *palmap = info->table;
    285 	Uint32 ckey = info->src->colorkey;
    286 
    287 	if ( palmap ) {
    288 		while ( height-- ) {
    289 			DUFFS_LOOP(
    290 			{
    291 				if ( *src != ckey ) {
    292 				  *dst = palmap[*src];
    293 				}
    294 				dst++;
    295 				src++;
    296 			},
    297 			width);
    298 			src += srcskip;
    299 			dst += dstskip;
    300 		}
    301 	} else {
    302 		while ( height-- ) {
    303 			DUFFS_LOOP(
    304 			{
    305 				if ( *src != ckey ) {
    306 				  *dst = *src;
    307 				}
    308 				dst++;
    309 				src++;
    310 			},
    311 			width);
    312 			src += srcskip;
    313 			dst += dstskip;
    314 		}
    315 	}
    316 }
    317 
    318 static void Blit1to2Key(SDL_BlitInfo *info)
    319 {
    320 	int width = info->d_width;
    321 	int height = info->d_height;
    322 	Uint8 *src = info->s_pixels;
    323 	int srcskip = info->s_skip;
    324 	Uint16 *dstp = (Uint16 *)info->d_pixels;
    325 	int dstskip = info->d_skip;
    326 	Uint16 *palmap = (Uint16 *)info->table;
    327 	Uint32 ckey = info->src->colorkey;
    328 
    329 	/* Set up some basic variables */
    330 	dstskip /= 2;
    331 
    332 	while ( height-- ) {
    333 		DUFFS_LOOP(
    334 		{
    335 			if ( *src != ckey ) {
    336 				*dstp=palmap[*src];
    337 			}
    338 			src++;
    339 			dstp++;
    340 		},
    341 		width);
    342 		src += srcskip;
    343 		dstp += dstskip;
    344 	}
    345 }
    346 
    347 static void Blit1to3Key(SDL_BlitInfo *info)
    348 {
    349 	int width = info->d_width;
    350 	int height = info->d_height;
    351 	Uint8 *src = info->s_pixels;
    352 	int srcskip = info->s_skip;
    353 	Uint8 *dst = info->d_pixels;
    354 	int dstskip = info->d_skip;
    355 	Uint8 *palmap = info->table;
    356 	Uint32 ckey = info->src->colorkey;
    357 	int o;
    358 
    359 	while ( height-- ) {
    360 		DUFFS_LOOP(
    361 		{
    362 			if ( *src != ckey ) {
    363 				o = *src * 4;
    364 				dst[0] = palmap[o++];
    365 				dst[1] = palmap[o++];
    366 				dst[2] = palmap[o++];
    367 			}
    368 			src++;
    369 			dst += 3;
    370 		},
    371 		width);
    372 		src += srcskip;
    373 		dst += dstskip;
    374 	}
    375 }
    376 
    377 static void Blit1to4Key(SDL_BlitInfo *info)
    378 {
    379 	int width = info->d_width;
    380 	int height = info->d_height;
    381 	Uint8 *src = info->s_pixels;
    382 	int srcskip = info->s_skip;
    383 	Uint32 *dstp = (Uint32 *)info->d_pixels;
    384 	int dstskip = info->d_skip;
    385 	Uint32 *palmap = (Uint32 *)info->table;
    386 	Uint32 ckey = info->src->colorkey;
    387 
    388 	/* Set up some basic variables */
    389 	dstskip /= 4;
    390 
    391 	while ( height-- ) {
    392 		DUFFS_LOOP(
    393 		{
    394 			if ( *src != ckey ) {
    395 				*dstp = palmap[*src];
    396 			}
    397 			src++;
    398 			dstp++;
    399 		},
    400 		width);
    401 		src += srcskip;
    402 		dstp += dstskip;
    403 	}
    404 }
    405 
    406 static void Blit1toNAlpha(SDL_BlitInfo *info)
    407 {
    408 	int width = info->d_width;
    409 	int height = info->d_height;
    410 	Uint8 *src = info->s_pixels;
    411 	int srcskip = info->s_skip;
    412 	Uint8 *dst = info->d_pixels;
    413 	int dstskip = info->d_skip;
    414 	SDL_PixelFormat *dstfmt = info->dst;
    415 	const SDL_Color *srcpal	= info->src->palette->colors;
    416 	int dstbpp;
    417 	const int A = info->src->alpha;
    418 
    419 	/* Set up some basic variables */
    420 	dstbpp = dstfmt->BytesPerPixel;
    421 
    422 	while ( height-- ) {
    423 	        int sR, sG, sB;
    424 		int dR, dG, dB;
    425 	    	DUFFS_LOOP4(
    426 			{
    427 			        Uint32 pixel;
    428 				sR = srcpal[*src].r;
    429 				sG = srcpal[*src].g;
    430 				sB = srcpal[*src].b;
    431 				DISEMBLE_RGB(dst, dstbpp, dstfmt,
    432 					     pixel, dR, dG, dB);
    433 				ALPHA_BLEND(sR, sG, sB, A, dR, dG, dB);
    434 			  	ASSEMBLE_RGB(dst, dstbpp, dstfmt, dR, dG, dB);
    435 				src++;
    436 				dst += dstbpp;
    437 			},
    438 			width);
    439 		src += srcskip;
    440 		dst += dstskip;
    441 	}
    442 }
    443 
    444 static void Blit1toNAlphaKey(SDL_BlitInfo *info)
    445 {
    446 	int width = info->d_width;
    447 	int height = info->d_height;
    448 	Uint8 *src = info->s_pixels;
    449 	int srcskip = info->s_skip;
    450 	Uint8 *dst = info->d_pixels;
    451 	int dstskip = info->d_skip;
    452 	SDL_PixelFormat *srcfmt = info->src;
    453 	SDL_PixelFormat *dstfmt = info->dst;
    454 	const SDL_Color *srcpal	= info->src->palette->colors;
    455 	Uint32 ckey = srcfmt->colorkey;
    456 	int dstbpp;
    457 	const int A = srcfmt->alpha;
    458 
    459 	/* Set up some basic variables */
    460 	dstbpp = dstfmt->BytesPerPixel;
    461 
    462 	while ( height-- ) {
    463 	        int sR, sG, sB;
    464 		int dR, dG, dB;
    465 		DUFFS_LOOP(
    466 		{
    467 			if ( *src != ckey ) {
    468 			        Uint32 pixel;
    469 				sR = srcpal[*src].r;
    470 				sG = srcpal[*src].g;
    471 				sB = srcpal[*src].b;
    472 				DISEMBLE_RGB(dst, dstbpp, dstfmt,
    473 							pixel, dR, dG, dB);
    474 				ALPHA_BLEND(sR, sG, sB, A, dR, dG, dB);
    475 			  	ASSEMBLE_RGB(dst, dstbpp, dstfmt, dR, dG, dB);
    476 			}
    477 			src++;
    478 			dst += dstbpp;
    479 		},
    480 		width);
    481 		src += srcskip;
    482 		dst += dstskip;
    483 	}
    484 }
    485 
    486 static SDL_loblit one_blit[] = {
    487 	NULL, Blit1to1, Blit1to2, Blit1to3, Blit1to4
    488 };
    489 
    490 static SDL_loblit one_blitkey[] = {
    491         NULL, Blit1to1Key, Blit1to2Key, Blit1to3Key, Blit1to4Key
    492 };
    493 
    494 SDL_loblit SDL_CalculateBlit1(SDL_Surface *surface, int blit_index)
    495 {
    496 	int which;
    497 	SDL_PixelFormat *dstfmt;
    498 
    499 	dstfmt = surface->map->dst->format;
    500 	if ( dstfmt->BitsPerPixel < 8 ) {
    501 		which = 0;
    502 	} else {
    503 		which = dstfmt->BytesPerPixel;
    504 	}
    505 	switch(blit_index) {
    506 	case 0:			/* copy */
    507 	    return one_blit[which];
    508 
    509 	case 1:			/* colorkey */
    510 	    return one_blitkey[which];
    511 
    512 	case 2:			/* alpha */
    513 	    /* Supporting 8bpp->8bpp alpha is doable but requires lots of
    514 	       tables which consume space and takes time to precompute,
    515 	       so is better left to the user */
    516 	    return which >= 2 ? Blit1toNAlpha : NULL;
    517 
    518 	case 3:			/* alpha + colorkey */
    519 	    return which >= 2 ? Blit1toNAlphaKey : NULL;
    520 
    521 	}
    522 	return NULL;
    523 }
    524