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