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