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 #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))>>8)+dR; \ 388 dG = (((sG-dG)*(A))>>8)+dG; \ 389 dB = (((sB-dB)*(A))>>8)+dB; \ 390 } while(0) 391 392 /* Blend the RGB values of two Pixels based on a source alpha value */ 393 #define ACCURATE_ALPHA_BLEND(sR, sG, sB, sA, dR, dG, dB) \ 394 do { \ 395 unsigned tR, tG, tB, tA; \ 396 tA = 255 - sA; \ 397 tR = 1 + (sR * sA) + (dR * tA); \ 398 dR = (tR + (tR >> 8)) >> 8; \ 399 tG = 1 + (sG * sA) + (dG * tA); \ 400 dG = (tG + (tG >> 8)) >> 8; \ 401 tB = 1 + (sB * sA) + (dB * tA); \ 402 dB = (tB + (tB >> 8)) >> 8; \ 403 } while(0) 404 405 406 /* This is a very useful loop for optimizing blitters */ 407 #if defined(_MSC_VER) && (_MSC_VER == 1300) 408 /* There's a bug in the Visual C++ 7 optimizer when compiling this code */ 409 #else 410 #define USE_DUFFS_LOOP 411 #endif 412 #ifdef USE_DUFFS_LOOP 413 414 /* 8-times unrolled loop */ 415 #define DUFFS_LOOP8(pixel_copy_increment, width) \ 416 { int n = (width+7)/8; \ 417 switch (width & 7) { \ 418 case 0: do { pixel_copy_increment; \ 419 case 7: pixel_copy_increment; \ 420 case 6: pixel_copy_increment; \ 421 case 5: pixel_copy_increment; \ 422 case 4: pixel_copy_increment; \ 423 case 3: pixel_copy_increment; \ 424 case 2: pixel_copy_increment; \ 425 case 1: pixel_copy_increment; \ 426 } while ( --n > 0 ); \ 427 } \ 428 } 429 430 /* 4-times unrolled loop */ 431 #define DUFFS_LOOP4(pixel_copy_increment, width) \ 432 { int n = (width+3)/4; \ 433 switch (width & 3) { \ 434 case 0: do { pixel_copy_increment; \ 435 case 3: pixel_copy_increment; \ 436 case 2: pixel_copy_increment; \ 437 case 1: pixel_copy_increment; \ 438 } while ( --n > 0 ); \ 439 } \ 440 } 441 442 /* 2 - times unrolled loop */ 443 #define DUFFS_LOOP_DOUBLE2(pixel_copy_increment, \ 444 double_pixel_copy_increment, width) \ 445 { int n, w = width; \ 446 if( w & 1 ) { \ 447 pixel_copy_increment; \ 448 w--; \ 449 } \ 450 if ( w > 0 ) { \ 451 n = ( w + 2) / 4; \ 452 switch( w & 2 ) { \ 453 case 0: do { double_pixel_copy_increment; \ 454 case 2: double_pixel_copy_increment; \ 455 } while ( --n > 0 ); \ 456 } \ 457 } \ 458 } 459 460 /* 2 - times unrolled loop 4 pixels */ 461 #define DUFFS_LOOP_QUATRO2(pixel_copy_increment, \ 462 double_pixel_copy_increment, \ 463 quatro_pixel_copy_increment, width) \ 464 { int n, w = width; \ 465 if(w & 1) { \ 466 pixel_copy_increment; \ 467 w--; \ 468 } \ 469 if(w & 2) { \ 470 double_pixel_copy_increment; \ 471 w -= 2; \ 472 } \ 473 if ( w > 0 ) { \ 474 n = ( w + 7 ) / 8; \ 475 switch( w & 4 ) { \ 476 case 0: do { quatro_pixel_copy_increment; \ 477 case 4: quatro_pixel_copy_increment; \ 478 } while ( --n > 0 ); \ 479 } \ 480 } \ 481 } 482 483 /* Use the 8-times version of the loop by default */ 484 #define DUFFS_LOOP(pixel_copy_increment, width) \ 485 DUFFS_LOOP8(pixel_copy_increment, width) 486 487 #else 488 489 /* Don't use Duff's device to unroll loops */ 490 #define DUFFS_LOOP_DOUBLE2(pixel_copy_increment, \ 491 double_pixel_copy_increment, width) \ 492 { int n = width; \ 493 if( n & 1 ) { \ 494 pixel_copy_increment; \ 495 n--; \ 496 } \ 497 n=n>>1; \ 498 for(; n > 0; --n) { \ 499 double_pixel_copy_increment; \ 500 } \ 501 } 502 503 /* Don't use Duff's device to unroll loops */ 504 #define DUFFS_LOOP_QUATRO2(pixel_copy_increment, \ 505 double_pixel_copy_increment, \ 506 quatro_pixel_copy_increment, width) \ 507 { int n = width; \ 508 if(n & 1) { \ 509 pixel_copy_increment; \ 510 n--; \ 511 } \ 512 if(n & 2) { \ 513 double_pixel_copy_increment; \ 514 n -= 2; \ 515 } \ 516 n=n>>2; \ 517 for(; n > 0; --n) { \ 518 quatro_pixel_copy_increment; \ 519 } \ 520 } 521 522 /* Don't use Duff's device to unroll loops */ 523 #define DUFFS_LOOP(pixel_copy_increment, width) \ 524 { int n; \ 525 for ( n=width; n > 0; --n ) { \ 526 pixel_copy_increment; \ 527 } \ 528 } 529 #define DUFFS_LOOP8(pixel_copy_increment, width) \ 530 DUFFS_LOOP(pixel_copy_increment, width) 531 #define DUFFS_LOOP4(pixel_copy_increment, width) \ 532 DUFFS_LOOP(pixel_copy_increment, width) 533 534 #endif /* USE_DUFFS_LOOP */ 535 536 /* Prevent Visual C++ 6.0 from printing out stupid warnings */ 537 #if defined(_MSC_VER) && (_MSC_VER >= 600) 538 #pragma warning(disable: 4550) 539 #endif 540 541 #endif /* _SDL_blit_h */ 542