Atlas - SDL_surface.c
Home / ext / SDL2 / src / video Lines: 4 | Size: 34324 bytes [Download] [Show on GitHub] [Search similar files] [Raw] [Raw (proxy)][FILE BEGIN]1/* 2 Simple DirectMedia Layer 3 Copyright (C) 1997-2018 Sam Lantinga <[email protected]> 4 5 This software is provided 'as-is', without any express or implied 6 warranty. In no event will the authors be held liable for any damages 7 arising from the use of this software. 8 9 Permission is granted to anyone to use this software for any purpose, 10 including commercial applications, and to alter it and redistribute it 11 freely, subject to the following restrictions: 12 13 1. The origin of this software must not be misrepresented; you must not 14 claim that you wrote the original software. If you use this software 15 in a product, an acknowledgment in the product documentation would be 16 appreciated but is not required. 17 2. Altered source versions must be plainly marked as such, and must not be 18 misrepresented as being the original software. 19 3. This notice may not be removed or altered from any source distribution. 20*/ 21#include "../SDL_internal.h" 22 23#include "SDL_video.h" 24#include "SDL_sysvideo.h" 25#include "SDL_blit.h" 26#include "SDL_RLEaccel_c.h" 27#include "SDL_pixels_c.h" 28#include "SDL_yuv_c.h" 29 30 31/* Check to make sure we can safely check multiplication of surface w and pitch and it won't overflow size_t */ 32SDL_COMPILE_TIME_ASSERT(surface_size_assumptions, 33 sizeof(int) == sizeof(Sint32) && sizeof(size_t) >= sizeof(Sint32)); 34 35/* Public routines */ 36 37/* 38 * Calculate the pad-aligned scanline width of a surface 39 */ 40int 41SDL_CalculatePitch(Uint32 format, int width) 42{ 43 int pitch; 44 45 /* Surface should be 4-byte aligned for speed */ 46 pitch = width * SDL_BYTESPERPIXEL(format); 47 switch (SDL_BITSPERPIXEL(format)) { 48 case 1: 49 pitch = (pitch + 7) / 8; 50 break; 51 case 4: 52 pitch = (pitch + 1) / 2; 53 break; 54 default: 55 break; 56 } 57 pitch = (pitch + 3) & ~3; /* 4-byte aligning */ 58 return pitch; 59} 60 61/* 62 * Create an empty RGB surface of the appropriate depth using the given 63 * enum SDL_PIXELFORMAT_* format 64 */ 65SDL_Surface * 66SDL_CreateRGBSurfaceWithFormat(Uint32 flags, int width, int height, int depth, 67 Uint32 format) 68{ 69 SDL_Surface *surface; 70 71 /* The flags are no longer used, make the compiler happy */ 72 (void)flags; 73 74 /* Allocate the surface */ 75 surface = (SDL_Surface *) SDL_calloc(1, sizeof(*surface)); 76 if (surface == NULL) { 77 SDL_OutOfMemory(); 78 return NULL; 79 } 80 81 surface->format = SDL_AllocFormat(format); 82 if (!surface->format) { 83 SDL_FreeSurface(surface); 84 return NULL; 85 } 86 surface->w = width; 87 surface->h = height; 88 surface->pitch = SDL_CalculatePitch(format, width); 89 SDL_SetClipRect(surface, NULL); 90 91 if (SDL_ISPIXELFORMAT_INDEXED(surface->format->format)) { 92 SDL_Palette *palette = 93 SDL_AllocPalette((1 << surface->format->BitsPerPixel)); 94 if (!palette) { 95 SDL_FreeSurface(surface); 96 return NULL; 97 } 98 if (palette->ncolors == 2) { 99 /* Create a black and white bitmap palette */ 100 palette->colors[0].r = 0xFF; 101 palette->colors[0].g = 0xFF; 102 palette->colors[0].b = 0xFF; 103 palette->colors[1].r = 0x00; 104 palette->colors[1].g = 0x00; 105 palette->colors[1].b = 0x00; 106 } 107 SDL_SetSurfacePalette(surface, palette); 108 SDL_FreePalette(palette); 109 } 110 111 /* Get the pixels */ 112 if (surface->w && surface->h) { 113 /* Assumptions checked in surface_size_assumptions assert above */ 114 Sint64 size = ((Sint64)surface->h * surface->pitch); 115 if (size < 0 || size > SDL_MAX_SINT32) { 116 /* Overflow... */ 117 SDL_FreeSurface(surface); 118 SDL_OutOfMemory(); 119 return NULL; 120 } 121 122 surface->pixels = SDL_malloc((size_t)size); 123 if (!surface->pixels) { 124 SDL_FreeSurface(surface); 125 SDL_OutOfMemory(); 126 return NULL; 127 } 128 /* This is important for bitmaps */ 129 SDL_memset(surface->pixels, 0, surface->h * surface->pitch); 130 } 131 132 /* Allocate an empty mapping */ 133 surface->map = SDL_AllocBlitMap(); 134 if (!surface->map) { 135 SDL_FreeSurface(surface); 136 return NULL; 137 } 138 139 /* By default surface with an alpha mask are set up for blending */ 140 if (surface->format->Amask) { 141 SDL_SetSurfaceBlendMode(surface, SDL_BLENDMODE_BLEND); 142 } 143 144 /* The surface is ready to go */ 145 surface->refcount = 1; 146 return surface; 147} 148 149/* 150 * Create an empty RGB surface of the appropriate depth 151 */ 152SDL_Surface * 153SDL_CreateRGBSurface(Uint32 flags, 154 int width, int height, int depth, 155 Uint32 Rmask, Uint32 Gmask, Uint32 Bmask, Uint32 Amask) 156{ 157 Uint32 format; 158 159 /* Get the pixel format */ 160 format = SDL_MasksToPixelFormatEnum(depth, Rmask, Gmask, Bmask, Amask); 161 if (format == SDL_PIXELFORMAT_UNKNOWN) { 162 SDL_SetError("Unknown pixel format"); 163 return NULL; 164 } 165 166 return SDL_CreateRGBSurfaceWithFormat(flags, width, height, depth, format); 167} 168 169/* 170 * Create an RGB surface from an existing memory buffer 171 */ 172SDL_Surface * 173SDL_CreateRGBSurfaceFrom(void *pixels, 174 int width, int height, int depth, int pitch, 175 Uint32 Rmask, Uint32 Gmask, Uint32 Bmask, 176 Uint32 Amask) 177{ 178 SDL_Surface *surface; 179 180 surface = SDL_CreateRGBSurface(0, 0, 0, depth, Rmask, Gmask, Bmask, Amask); 181 if (surface != NULL) { 182 surface->flags |= SDL_PREALLOC; 183 surface->pixels = pixels; 184 surface->w = width; 185 surface->h = height; 186 surface->pitch = pitch; 187 SDL_SetClipRect(surface, NULL); 188 } 189 return surface; 190} 191 192/* 193 * Create an RGB surface from an existing memory buffer using the given given 194 * enum SDL_PIXELFORMAT_* format 195 */ 196SDL_Surface * 197SDL_CreateRGBSurfaceWithFormatFrom(void *pixels, 198 int width, int height, int depth, int pitch, 199 Uint32 format) 200{ 201 SDL_Surface *surface; 202 203 surface = SDL_CreateRGBSurfaceWithFormat(0, 0, 0, depth, format); 204 if (surface != NULL) { 205 surface->flags |= SDL_PREALLOC; 206 surface->pixels = pixels; 207 surface->w = width; 208 surface->h = height; 209 surface->pitch = pitch; 210 SDL_SetClipRect(surface, NULL); 211 } 212 return surface; 213} 214 215int 216SDL_SetSurfacePalette(SDL_Surface * surface, SDL_Palette * palette) 217{ 218 if (!surface) { 219 return SDL_SetError("SDL_SetSurfacePalette() passed a NULL surface"); 220 } 221 if (SDL_SetPixelFormatPalette(surface->format, palette) < 0) { 222 return -1; 223 } 224 SDL_InvalidateMap(surface->map); 225 226 return 0; 227} 228 229int 230SDL_SetSurfaceRLE(SDL_Surface * surface, int flag) 231{ 232 int flags; 233 234 if (!surface) { 235 return -1; 236 } 237 238 flags = surface->map->info.flags; 239 if (flag) { 240 surface->map->info.flags |= SDL_COPY_RLE_DESIRED; 241 } else { 242 surface->map->info.flags &= ~SDL_COPY_RLE_DESIRED; 243 } 244 if (surface->map->info.flags != flags) { 245 SDL_InvalidateMap(surface->map); 246 } 247 return 0; 248} 249 250int 251SDL_SetColorKey(SDL_Surface * surface, int flag, Uint32 key) 252{ 253 int flags; 254 255 if (!surface) { 256 return SDL_InvalidParamError("surface"); 257 } 258 259 if (surface->format->palette && key >= ((Uint32) surface->format->palette->ncolors)) { 260 return SDL_InvalidParamError("key"); 261 } 262 263 if (flag & SDL_RLEACCEL) { 264 SDL_SetSurfaceRLE(surface, 1); 265 } 266 267 flags = surface->map->info.flags; 268 if (flag) { 269 surface->map->info.flags |= SDL_COPY_COLORKEY; 270 surface->map->info.colorkey = key; 271 if (surface->format->palette) { 272 surface->format->palette->colors[surface->map->info.colorkey].a = SDL_ALPHA_TRANSPARENT; 273 ++surface->format->palette->version; 274 if (!surface->format->palette->version) { 275 surface->format->palette->version = 1; 276 } 277 } 278 } else { 279 if (surface->format->palette) { 280 surface->format->palette->colors[surface->map->info.colorkey].a = SDL_ALPHA_OPAQUE; 281 ++surface->format->palette->version; 282 if (!surface->format->palette->version) { 283 surface->format->palette->version = 1; 284 } 285 } 286 surface->map->info.flags &= ~SDL_COPY_COLORKEY; 287 } 288 if (surface->map->info.flags != flags) { 289 SDL_InvalidateMap(surface->map); 290 } 291 292 return 0; 293} 294 295int 296SDL_GetColorKey(SDL_Surface * surface, Uint32 * key) 297{ 298 if (!surface) { 299 return SDL_InvalidParamError("surface"); 300 } 301 302 if (!(surface->map->info.flags & SDL_COPY_COLORKEY)) { 303 return SDL_SetError("Surface doesn't have a colorkey"); 304 } 305 306 if (key) { 307 *key = surface->map->info.colorkey; 308 } 309 return 0; 310} 311 312/* This is a fairly slow function to switch from colorkey to alpha */ 313static void 314SDL_ConvertColorkeyToAlpha(SDL_Surface * surface) 315{ 316 int x, y; 317 318 if (!surface) { 319 return; 320 } 321 322 if (!(surface->map->info.flags & SDL_COPY_COLORKEY) || 323 !surface->format->Amask) { 324 return; 325 } 326 327 SDL_LockSurface(surface); 328 329 switch (surface->format->BytesPerPixel) { 330 case 2: 331 { 332 Uint16 *row, *spot; 333 Uint16 ckey = (Uint16) surface->map->info.colorkey; 334 Uint16 mask = (Uint16) (~surface->format->Amask); 335 336 /* Ignore alpha in colorkey comparison */ 337 ckey &= mask; 338 row = (Uint16 *) surface->pixels; 339 for (y = surface->h; y--;) { 340 spot = row; 341 for (x = surface->w; x--;) { 342 if ((*spot & mask) == ckey) { 343 *spot &= mask; 344 } 345 ++spot; 346 } 347 row += surface->pitch / 2; 348 } 349 } 350 break; 351 case 3: 352 /* FIXME */ 353 break; 354 case 4: 355 { 356 Uint32 *row, *spot; 357 Uint32 ckey = surface->map->info.colorkey; 358 Uint32 mask = ~surface->format->Amask; 359 360 /* Ignore alpha in colorkey comparison */ 361 ckey &= mask; 362 row = (Uint32 *) surface->pixels; 363 for (y = surface->h; y--;) { 364 spot = row; 365 for (x = surface->w; x--;) { 366 if ((*spot & mask) == ckey) { 367 *spot &= mask; 368 } 369 ++spot; 370 } 371 row += surface->pitch / 4; 372 } 373 } 374 break; 375 } 376 377 SDL_UnlockSurface(surface); 378 379 SDL_SetColorKey(surface, 0, 0); 380 SDL_SetSurfaceBlendMode(surface, SDL_BLENDMODE_BLEND); 381} 382 383int 384SDL_SetSurfaceColorMod(SDL_Surface * surface, Uint8 r, Uint8 g, Uint8 b) 385{ 386 int flags; 387 388 if (!surface) { 389 return -1; 390 } 391 392 surface->map->info.r = r; 393 surface->map->info.g = g; 394 surface->map->info.b = b; 395 396 flags = surface->map->info.flags; 397 if (r != 0xFF || g != 0xFF || b != 0xFF) { 398 surface->map->info.flags |= SDL_COPY_MODULATE_COLOR; 399 } else { 400 surface->map->info.flags &= ~SDL_COPY_MODULATE_COLOR; 401 } 402 if (surface->map->info.flags != flags) { 403 SDL_InvalidateMap(surface->map); 404 } 405 return 0; 406} 407 408 409int 410SDL_GetSurfaceColorMod(SDL_Surface * surface, Uint8 * r, Uint8 * g, Uint8 * b) 411{ 412 if (!surface) { 413 return -1; 414 } 415 416 if (r) { 417 *r = surface->map->info.r; 418 } 419 if (g) { 420 *g = surface->map->info.g; 421 } 422 if (b) { 423 *b = surface->map->info.b; 424 } 425 return 0; 426} 427 428int 429SDL_SetSurfaceAlphaMod(SDL_Surface * surface, Uint8 alpha) 430{ 431 int flags; 432 433 if (!surface) { 434 return -1; 435 } 436 437 surface->map->info.a = alpha; 438 439 flags = surface->map->info.flags; 440 if (alpha != 0xFF) { 441 surface->map->info.flags |= SDL_COPY_MODULATE_ALPHA; 442 } else { 443 surface->map->info.flags &= ~SDL_COPY_MODULATE_ALPHA; 444 } 445 if (surface->map->info.flags != flags) { 446 SDL_InvalidateMap(surface->map); 447 } 448 return 0; 449} 450 451int 452SDL_GetSurfaceAlphaMod(SDL_Surface * surface, Uint8 * alpha) 453{ 454 if (!surface) { 455 return -1; 456 } 457 458 if (alpha) { 459 *alpha = surface->map->info.a; 460 } 461 return 0; 462} 463 464int 465SDL_SetSurfaceBlendMode(SDL_Surface * surface, SDL_BlendMode blendMode) 466{ 467 int flags, status; 468 469 if (!surface) { 470 return -1; 471 } 472 473 status = 0; 474 flags = surface->map->info.flags; 475 surface->map->info.flags &= 476 ~(SDL_COPY_BLEND | SDL_COPY_ADD | SDL_COPY_MOD); 477 switch (blendMode) { 478 case SDL_BLENDMODE_NONE: 479 break; 480 case SDL_BLENDMODE_BLEND: 481 surface->map->info.flags |= SDL_COPY_BLEND; 482 break; 483 case SDL_BLENDMODE_ADD: 484 surface->map->info.flags |= SDL_COPY_ADD; 485 break; 486 case SDL_BLENDMODE_MOD: 487 surface->map->info.flags |= SDL_COPY_MOD; 488 break; 489 default: 490 status = SDL_Unsupported(); 491 break; 492 } 493 494 if (surface->map->info.flags != flags) { 495 SDL_InvalidateMap(surface->map); 496 } 497 498 return status; 499} 500 501int 502SDL_GetSurfaceBlendMode(SDL_Surface * surface, SDL_BlendMode *blendMode) 503{ 504 if (!surface) { 505 return -1; 506 } 507 508 if (!blendMode) { 509 return 0; 510 } 511 512 switch (surface->map-> 513 info.flags & (SDL_COPY_BLEND | SDL_COPY_ADD | SDL_COPY_MOD)) { 514 case SDL_COPY_BLEND: 515 *blendMode = SDL_BLENDMODE_BLEND; 516 break; 517 case SDL_COPY_ADD: 518 *blendMode = SDL_BLENDMODE_ADD; 519 break; 520 case SDL_COPY_MOD: 521 *blendMode = SDL_BLENDMODE_MOD; 522 break; 523 default: 524 *blendMode = SDL_BLENDMODE_NONE; 525 break; 526 } 527 return 0; 528} 529 530SDL_bool 531SDL_SetClipRect(SDL_Surface * surface, const SDL_Rect * rect) 532{ 533 SDL_Rect full_rect; 534 535 /* Don't do anything if there's no surface to act on */ 536 if (!surface) { 537 return SDL_FALSE; 538 } 539 540 /* Set up the full surface rectangle */ 541 full_rect.x = 0; 542 full_rect.y = 0; 543 full_rect.w = surface->w; 544 full_rect.h = surface->h; 545 546 /* Set the clipping rectangle */ 547 if (!rect) { 548 surface->clip_rect = full_rect; 549 return SDL_TRUE; 550 } 551 return SDL_IntersectRect(rect, &full_rect, &surface->clip_rect); 552} 553 554void 555SDL_GetClipRect(SDL_Surface * surface, SDL_Rect * rect) 556{ 557 if (surface && rect) { 558 *rect = surface->clip_rect; 559 } 560} 561 562/* 563 * Set up a blit between two surfaces -- split into three parts: 564 * The upper part, SDL_UpperBlit(), performs clipping and rectangle 565 * verification. The lower part is a pointer to a low level 566 * accelerated blitting function. 567 * 568 * These parts are separated out and each used internally by this 569 * library in the optimimum places. They are exported so that if 570 * you know exactly what you are doing, you can optimize your code 571 * by calling the one(s) you need. 572 */ 573int 574SDL_LowerBlit(SDL_Surface * src, SDL_Rect * srcrect, 575 SDL_Surface * dst, SDL_Rect * dstrect) 576{ 577 /* Check to make sure the blit mapping is valid */ 578 if ((src->map->dst != dst) || 579 (dst->format->palette && 580 src->map->dst_palette_version != dst->format->palette->version) || 581 (src->format->palette && 582 src->map->src_palette_version != src->format->palette->version)) { 583 if (SDL_MapSurface(src, dst) < 0) { 584 return (-1); 585 } 586 /* just here for debugging */ 587/* printf */ 588/* ("src = 0x%08X src->flags = %08X src->map->info.flags = %08x\ndst = 0x%08X dst->flags = %08X dst->map->info.flags = %08X\nsrc->map->blit = 0x%08x\n", */ 589/* src, dst->flags, src->map->info.flags, dst, dst->flags, */ 590/* dst->map->info.flags, src->map->blit); */ 591 } 592 return (src->map->blit(src, srcrect, dst, dstrect)); 593} 594 595 596int 597SDL_UpperBlit(SDL_Surface * src, const SDL_Rect * srcrect, 598 SDL_Surface * dst, SDL_Rect * dstrect) 599{ 600 SDL_Rect fulldst; 601 int srcx, srcy, w, h; 602 603 /* Make sure the surfaces aren't locked */ 604 if (!src || !dst) { 605 return SDL_SetError("SDL_UpperBlit: passed a NULL surface"); 606 } 607 if (src->locked || dst->locked) { 608 return SDL_SetError("Surfaces must not be locked during blit"); 609 } 610 611 /* If the destination rectangle is NULL, use the entire dest surface */ 612 if (dstrect == NULL) { 613 fulldst.x = fulldst.y = 0; 614 fulldst.w = dst->w; 615 fulldst.h = dst->h; 616 dstrect = &fulldst; 617 } 618 619 /* clip the source rectangle to the source surface */ 620 if (srcrect) { 621 int maxw, maxh; 622 623 srcx = srcrect->x; 624 w = srcrect->w; 625 if (srcx < 0) { 626 w += srcx; 627 dstrect->x -= srcx; 628 srcx = 0; 629 } 630 maxw = src->w - srcx; 631 if (maxw < w) 632 w = maxw; 633 634 srcy = srcrect->y; 635 h = srcrect->h; 636 if (srcy < 0) { 637 h += srcy; 638 dstrect->y -= srcy; 639 srcy = 0; 640 } 641 maxh = src->h - srcy; 642 if (maxh < h) 643 h = maxh; 644 645 } else { 646 srcx = srcy = 0; 647 w = src->w; 648 h = src->h; 649 } 650 651 /* clip the destination rectangle against the clip rectangle */ 652 { 653 SDL_Rect *clip = &dst->clip_rect; 654 int dx, dy; 655 656 dx = clip->x - dstrect->x; 657 if (dx > 0) { 658 w -= dx; 659 dstrect->x += dx; 660 srcx += dx; 661 } 662 dx = dstrect->x + w - clip->x - clip->w; 663 if (dx > 0) 664 w -= dx; 665 666 dy = clip->y - dstrect->y; 667 if (dy > 0) { 668 h -= dy; 669 dstrect->y += dy; 670 srcy += dy; 671 } 672 dy = dstrect->y + h - clip->y - clip->h; 673 if (dy > 0) 674 h -= dy; 675 } 676 677 /* Switch back to a fast blit if we were previously stretching */ 678 if (src->map->info.flags & SDL_COPY_NEAREST) { 679 src->map->info.flags &= ~SDL_COPY_NEAREST; 680 SDL_InvalidateMap(src->map); 681 } 682 683 if (w > 0 && h > 0) { 684 SDL_Rect sr; 685 sr.x = srcx; 686 sr.y = srcy; 687 sr.w = dstrect->w = w; 688 sr.h = dstrect->h = h; 689 return SDL_LowerBlit(src, &sr, dst, dstrect); 690 } 691 dstrect->w = dstrect->h = 0; 692 return 0; 693} 694 695int 696SDL_UpperBlitScaled(SDL_Surface * src, const SDL_Rect * srcrect, 697 SDL_Surface * dst, SDL_Rect * dstrect) 698{ 699 double src_x0, src_y0, src_x1, src_y1; 700 double dst_x0, dst_y0, dst_x1, dst_y1; 701 SDL_Rect final_src, final_dst; 702 double scaling_w, scaling_h; 703 int src_w, src_h; 704 int dst_w, dst_h; 705 706 /* Make sure the surfaces aren't locked */ 707 if (!src || !dst) { 708 return SDL_SetError("SDL_UpperBlitScaled: passed a NULL surface"); 709 } 710 if (src->locked || dst->locked) { 711 return SDL_SetError("Surfaces must not be locked during blit"); 712 } 713 714 if (NULL == srcrect) { 715 src_w = src->w; 716 src_h = src->h; 717 } else { 718 src_w = srcrect->w; 719 src_h = srcrect->h; 720 } 721 722 if (NULL == dstrect) { 723 dst_w = dst->w; 724 dst_h = dst->h; 725 } else { 726 dst_w = dstrect->w; 727 dst_h = dstrect->h; 728 } 729 730 if (dst_w == src_w && dst_h == src_h) { 731 /* No scaling, defer to regular blit */ 732 return SDL_BlitSurface(src, srcrect, dst, dstrect); 733 } 734 735 scaling_w = (double)dst_w / src_w; 736 scaling_h = (double)dst_h / src_h; 737 738 if (NULL == dstrect) { 739 dst_x0 = 0; 740 dst_y0 = 0; 741 dst_x1 = dst_w - 1; 742 dst_y1 = dst_h - 1; 743 } else { 744 dst_x0 = dstrect->x; 745 dst_y0 = dstrect->y; 746 dst_x1 = dst_x0 + dst_w - 1; 747 dst_y1 = dst_y0 + dst_h - 1; 748 } 749 750 if (NULL == srcrect) { 751 src_x0 = 0; 752 src_y0 = 0; 753 src_x1 = src_w - 1; 754 src_y1 = src_h - 1; 755 } else { 756 src_x0 = srcrect->x; 757 src_y0 = srcrect->y; 758 src_x1 = src_x0 + src_w - 1; 759 src_y1 = src_y0 + src_h - 1; 760 761 /* Clip source rectangle to the source surface */ 762 763 if (src_x0 < 0) { 764 dst_x0 -= src_x0 * scaling_w; 765 src_x0 = 0; 766 } 767 768 if (src_x1 >= src->w) { 769 dst_x1 -= (src_x1 - src->w + 1) * scaling_w; 770 src_x1 = src->w - 1; 771 } 772 773 if (src_y0 < 0) { 774 dst_y0 -= src_y0 * scaling_h; 775 src_y0 = 0; 776 } 777 778 if (src_y1 >= src->h) { 779 dst_y1 -= (src_y1 - src->h + 1) * scaling_h; 780 src_y1 = src->h - 1; 781 } 782 } 783 784 /* Clip destination rectangle to the clip rectangle */ 785 786 /* Translate to clip space for easier calculations */ 787 dst_x0 -= dst->clip_rect.x; 788 dst_x1 -= dst->clip_rect.x; 789 dst_y0 -= dst->clip_rect.y; 790 dst_y1 -= dst->clip_rect.y; 791 792 if (dst_x0 < 0) { 793 src_x0 -= dst_x0 / scaling_w; 794 dst_x0 = 0; 795 } 796 797 if (dst_x1 >= dst->clip_rect.w) { 798 src_x1 -= (dst_x1 - dst->clip_rect.w + 1) / scaling_w; 799 dst_x1 = dst->clip_rect.w - 1; 800 } 801 802 if (dst_y0 < 0) { 803 src_y0 -= dst_y0 / scaling_h; 804 dst_y0 = 0; 805 } 806 807 if (dst_y1 >= dst->clip_rect.h) { 808 src_y1 -= (dst_y1 - dst->clip_rect.h + 1) / scaling_h; 809 dst_y1 = dst->clip_rect.h - 1; 810 } 811 812 /* Translate back to surface coordinates */ 813 dst_x0 += dst->clip_rect.x; 814 dst_x1 += dst->clip_rect.x; 815 dst_y0 += dst->clip_rect.y; 816 dst_y1 += dst->clip_rect.y; 817 818 final_src.x = (int)SDL_floor(src_x0 + 0.5); 819 final_src.y = (int)SDL_floor(src_y0 + 0.5); 820 final_src.w = (int)SDL_floor(src_x1 + 1 + 0.5) - (int)SDL_floor(src_x0 + 0.5); 821 final_src.h = (int)SDL_floor(src_y1 + 1 + 0.5) - (int)SDL_floor(src_y0 + 0.5); 822 823 final_dst.x = (int)SDL_floor(dst_x0 + 0.5); 824 final_dst.y = (int)SDL_floor(dst_y0 + 0.5); 825 final_dst.w = (int)SDL_floor(dst_x1 - dst_x0 + 1.5); 826 final_dst.h = (int)SDL_floor(dst_y1 - dst_y0 + 1.5); 827 828 if (final_dst.w < 0) 829 final_dst.w = 0; 830 if (final_dst.h < 0) 831 final_dst.h = 0; 832 833 if (dstrect) 834 *dstrect = final_dst; 835 836 if (final_dst.w == 0 || final_dst.h == 0 || 837 final_src.w <= 0 || final_src.h <= 0) { 838 /* No-op. */ 839 return 0; 840 } 841 842 return SDL_LowerBlitScaled(src, &final_src, dst, &final_dst); 843} 844 845/** 846 * This is a semi-private blit function and it performs low-level surface 847 * scaled blitting only. 848 */ 849int 850SDL_LowerBlitScaled(SDL_Surface * src, SDL_Rect * srcrect, 851 SDL_Surface * dst, SDL_Rect * dstrect) 852{ 853 static const Uint32 complex_copy_flags = ( 854 SDL_COPY_MODULATE_COLOR | SDL_COPY_MODULATE_ALPHA | 855 SDL_COPY_BLEND | SDL_COPY_ADD | SDL_COPY_MOD | 856 SDL_COPY_COLORKEY 857 ); 858 859 if (!(src->map->info.flags & SDL_COPY_NEAREST)) { 860 src->map->info.flags |= SDL_COPY_NEAREST; 861 SDL_InvalidateMap(src->map); 862 } 863 864 if ( !(src->map->info.flags & complex_copy_flags) && 865 src->format->format == dst->format->format && 866 !SDL_ISPIXELFORMAT_INDEXED(src->format->format) ) { 867 return SDL_SoftStretch( src, srcrect, dst, dstrect ); 868 } else { 869 return SDL_LowerBlit( src, srcrect, dst, dstrect ); 870 } 871} 872 873/* 874 * Lock a surface to directly access the pixels 875 */ 876int 877SDL_LockSurface(SDL_Surface * surface) 878{ 879 if (!surface->locked) { 880 /* Perform the lock */ 881 if (surface->flags & SDL_RLEACCEL) { 882 SDL_UnRLESurface(surface, 1); 883 surface->flags |= SDL_RLEACCEL; /* save accel'd state */ 884 } 885 } 886 887 /* Increment the surface lock count, for recursive locks */ 888 ++surface->locked; 889 890 /* Ready to go.. */ 891 return (0); 892} 893 894/* 895 * Unlock a previously locked surface 896 */ 897void 898SDL_UnlockSurface(SDL_Surface * surface) 899{ 900 /* Only perform an unlock if we are locked */ 901 if (!surface->locked || (--surface->locked > 0)) { 902 return; 903 } 904 905 /* Update RLE encoded surface with new data */ 906 if ((surface->flags & SDL_RLEACCEL) == SDL_RLEACCEL) { 907 surface->flags &= ~SDL_RLEACCEL; /* stop lying */ 908 SDL_RLESurface(surface); 909 } 910} 911 912/* 913 * Creates a new surface identical to the existing surface 914 */ 915SDL_Surface * 916SDL_DuplicateSurface(SDL_Surface * surface) 917{ 918 return SDL_ConvertSurface(surface, surface->format, surface->flags); 919} 920 921/* 922 * Convert a surface into the specified pixel format. 923 */ 924SDL_Surface * 925SDL_ConvertSurface(SDL_Surface * surface, const SDL_PixelFormat * format, 926 Uint32 flags) 927{ 928 SDL_Surface *convert; 929 Uint32 copy_flags; 930 SDL_Color copy_color; 931 SDL_Rect bounds; 932 933 if (!surface) { 934 SDL_InvalidParamError("surface"); 935 return NULL; 936 } 937 if (!format) { 938 SDL_InvalidParamError("format"); 939 return NULL; 940 } 941 942 /* Check for empty destination palette! (results in empty image) */ 943 if (format->palette != NULL) { 944 int i; 945 for (i = 0; i < format->palette->ncolors; ++i) { 946 if ((format->palette->colors[i].r != 0xFF) || 947 (format->palette->colors[i].g != 0xFF) || 948 (format->palette->colors[i].b != 0xFF)) 949 break; 950 } 951 if (i == format->palette->ncolors) { 952 SDL_SetError("Empty destination palette"); 953 return (NULL); 954 } 955 } 956 957 /* Create a new surface with the desired format */ 958 convert = SDL_CreateRGBSurface(flags, surface->w, surface->h, 959 format->BitsPerPixel, format->Rmask, 960 format->Gmask, format->Bmask, 961 format->Amask); 962 if (convert == NULL) { 963 return (NULL); 964 } 965 966 /* Copy the palette if any */ 967 if (format->palette && convert->format->palette) { 968 SDL_memcpy(convert->format->palette->colors, 969 format->palette->colors, 970 format->palette->ncolors * sizeof(SDL_Color)); 971 convert->format->palette->ncolors = format->palette->ncolors; 972 } 973 974 /* Save the original copy flags */ 975 copy_flags = surface->map->info.flags; 976 copy_color.r = surface->map->info.r; 977 copy_color.g = surface->map->info.g; 978 copy_color.b = surface->map->info.b; 979 copy_color.a = surface->map->info.a; 980 surface->map->info.r = 0xFF; 981 surface->map->info.g = 0xFF; 982 surface->map->info.b = 0xFF; 983 surface->map->info.a = 0xFF; 984 surface->map->info.flags = 0; 985 SDL_InvalidateMap(surface->map); 986 987 /* Copy over the image data */ 988 bounds.x = 0; 989 bounds.y = 0; 990 bounds.w = surface->w; 991 bounds.h = surface->h; 992 SDL_LowerBlit(surface, &bounds, convert, &bounds); 993 994 /* Clean up the original surface, and update converted surface */ 995 convert->map->info.r = copy_color.r; 996 convert->map->info.g = copy_color.g; 997 convert->map->info.b = copy_color.b; 998 convert->map->info.a = copy_color.a; 999 convert->map->info.flags = 1000 (copy_flags & 1001 ~(SDL_COPY_COLORKEY | SDL_COPY_BLEND 1002 | SDL_COPY_RLE_DESIRED | SDL_COPY_RLE_COLORKEY | 1003 SDL_COPY_RLE_ALPHAKEY)); 1004 surface->map->info.r = copy_color.r; 1005 surface->map->info.g = copy_color.g; 1006 surface->map->info.b = copy_color.b; 1007 surface->map->info.a = copy_color.a; 1008 surface->map->info.flags = copy_flags; 1009 SDL_InvalidateMap(surface->map); 1010 if (copy_flags & SDL_COPY_COLORKEY) { 1011 SDL_bool set_colorkey_by_color = SDL_FALSE; 1012 1013 if (surface->format->palette) { 1014 if (format->palette && 1015 surface->format->palette->ncolors <= format->palette->ncolors && 1016 (SDL_memcmp(surface->format->palette->colors, format->palette->colors, 1017 surface->format->palette->ncolors * sizeof(SDL_Color)) == 0)) { 1018 /* The palette is identical, just set the same colorkey */ 1019 SDL_SetColorKey(convert, 1, surface->map->info.colorkey); 1020 } else if (format->Amask) { 1021 /* The alpha was set in the destination from the palette */ 1022 } else { 1023 set_colorkey_by_color = SDL_TRUE; 1024 } 1025 } else { 1026 set_colorkey_by_color = SDL_TRUE; 1027 } 1028 1029 if (set_colorkey_by_color) { 1030 SDL_Surface *tmp; 1031 SDL_Surface *tmp2; 1032 int converted_colorkey = 0; 1033 1034 /* Create a dummy surface to get the colorkey converted */ 1035 tmp = SDL_CreateRGBSurface(0, 1, 1, 1036 surface->format->BitsPerPixel, surface->format->Rmask, 1037 surface->format->Gmask, surface->format->Bmask, 1038 surface->format->Amask); 1039 1040 /* Share the palette, if any */ 1041 if (surface->format->palette) { 1042 SDL_SetSurfacePalette(tmp, surface->format->palette); 1043 } 1044 1045 SDL_FillRect(tmp, NULL, surface->map->info.colorkey); 1046 1047 tmp->map->info.flags &= ~SDL_COPY_COLORKEY; 1048 1049 /* Convertion of the colorkey */ 1050 tmp2 = SDL_ConvertSurface(tmp, format, 0); 1051 1052 /* Get the converted colorkey */ 1053 SDL_memcpy(&converted_colorkey, tmp2->pixels, tmp2->format->BytesPerPixel); 1054 1055 SDL_FreeSurface(tmp); 1056 SDL_FreeSurface(tmp2); 1057 1058 /* Set the converted colorkey on the new surface */ 1059 SDL_SetColorKey(convert, 1, converted_colorkey); 1060 1061 /* This is needed when converting for 3D texture upload */ 1062 SDL_ConvertColorkeyToAlpha(convert); 1063 } 1064 } 1065 SDL_SetClipRect(convert, &surface->clip_rect); 1066 1067 /* Enable alpha blending by default if the new surface has an 1068 * alpha channel or alpha modulation */ 1069 if ((surface->format->Amask && format->Amask) || 1070 (copy_flags & SDL_COPY_MODULATE_ALPHA)) { 1071 SDL_SetSurfaceBlendMode(convert, SDL_BLENDMODE_BLEND); 1072 } 1073 if ((copy_flags & SDL_COPY_RLE_DESIRED) || (flags & SDL_RLEACCEL)) { 1074 SDL_SetSurfaceRLE(convert, SDL_RLEACCEL); 1075 } 1076 1077 /* We're ready to go! */ 1078 return (convert); 1079} 1080 1081SDL_Surface * 1082SDL_ConvertSurfaceFormat(SDL_Surface * surface, Uint32 pixel_format, 1083 Uint32 flags) 1084{ 1085 SDL_PixelFormat *fmt; 1086 SDL_Surface *convert = NULL; 1087 1088 fmt = SDL_AllocFormat(pixel_format); 1089 if (fmt) { 1090 convert = SDL_ConvertSurface(surface, fmt, flags); 1091 SDL_FreeFormat(fmt); 1092 } 1093 return convert; 1094} 1095 1096/* 1097 * Create a surface on the stack for quick blit operations 1098 */ 1099static SDL_INLINE SDL_bool 1100SDL_CreateSurfaceOnStack(int width, int height, Uint32 pixel_format, 1101 void * pixels, int pitch, SDL_Surface * surface, 1102 SDL_PixelFormat * format, SDL_BlitMap * blitmap) 1103{ 1104 if (SDL_ISPIXELFORMAT_INDEXED(pixel_format)) { 1105 SDL_SetError("Indexed pixel formats not supported"); 1106 return SDL_FALSE; 1107 } 1108 if (SDL_InitFormat(format, pixel_format) < 0) { 1109 return SDL_FALSE; 1110 } 1111 1112 SDL_zerop(surface); 1113 surface->flags = SDL_PREALLOC; 1114 surface->format = format; 1115 surface->pixels = pixels; 1116 surface->w = width; 1117 surface->h = height; 1118 surface->pitch = pitch; 1119 /* We don't actually need to set up the clip rect for our purposes */ 1120 /* SDL_SetClipRect(surface, NULL); */ 1121 1122 /* Allocate an empty mapping */ 1123 SDL_zerop(blitmap); 1124 blitmap->info.r = 0xFF; 1125 blitmap->info.g = 0xFF; 1126 blitmap->info.b = 0xFF; 1127 blitmap->info.a = 0xFF; 1128 surface->map = blitmap; 1129 1130 /* The surface is ready to go */ 1131 surface->refcount = 1; 1132 return SDL_TRUE; 1133} 1134 1135/* 1136 * Copy a block of pixels of one format to another format 1137 */ 1138int SDL_ConvertPixels(int width, int height, 1139 Uint32 src_format, const void * src, int src_pitch, 1140 Uint32 dst_format, void * dst, int dst_pitch) 1141{ 1142 SDL_Surface src_surface, dst_surface; 1143 SDL_PixelFormat src_fmt, dst_fmt; 1144 SDL_BlitMap src_blitmap, dst_blitmap; 1145 SDL_Rect rect; 1146 void *nonconst_src = (void *) src; 1147 1148 /* Check to make sure we are blitting somewhere, so we don't crash */ 1149 if (!dst) { 1150 return SDL_InvalidParamError("dst"); 1151 } 1152 if (!dst_pitch) { 1153 return SDL_InvalidParamError("dst_pitch"); 1154 } 1155 1156 if (SDL_ISPIXELFORMAT_FOURCC(src_format) && SDL_ISPIXELFORMAT_FOURCC(dst_format)) { 1157 return SDL_ConvertPixels_YUV_to_YUV(width, height, src_format, src, src_pitch, dst_format, dst, dst_pitch); 1158 } else if (SDL_ISPIXELFORMAT_FOURCC(src_format)) { 1159 return SDL_ConvertPixels_YUV_to_RGB(width, height, src_format, src, src_pitch, dst_format, dst, dst_pitch); 1160 } else if (SDL_ISPIXELFORMAT_FOURCC(dst_format)) { 1161 return SDL_ConvertPixels_RGB_to_YUV(width, height, src_format, src, src_pitch, dst_format, dst, dst_pitch); 1162 } 1163 1164 /* Fast path for same format copy */ 1165 if (src_format == dst_format) { 1166 int i; 1167 const int bpp = SDL_BYTESPERPIXEL(src_format); 1168 width *= bpp; 1169 for (i = height; i--;) { 1170 SDL_memcpy(dst, src, width); 1171 src = (const Uint8*)src + src_pitch; 1172 dst = (Uint8*)dst + dst_pitch; 1173 } 1174 return 0; 1175 } 1176 1177 if (!SDL_CreateSurfaceOnStack(width, height, src_format, nonconst_src, 1178 src_pitch, 1179 &src_surface, &src_fmt, &src_blitmap)) { 1180 return -1; 1181 } 1182 if (!SDL_CreateSurfaceOnStack(width, height, dst_format, dst, dst_pitch, 1183 &dst_surface, &dst_fmt, &dst_blitmap)) { 1184 return -1; 1185 } 1186 1187 /* Set up the rect and go! */ 1188 rect.x = 0; 1189 rect.y = 0; 1190 rect.w = width; 1191 rect.h = height; 1192 return SDL_LowerBlit(&src_surface, &rect, &dst_surface, &rect); 1193} 1194 1195/* 1196 * Free a surface created by the above function. 1197 */ 1198void 1199SDL_FreeSurface(SDL_Surface * surface) 1200{ 1201 if (surface == NULL) { 1202 return; 1203 } 1204 if (surface->flags & SDL_DONTFREE) { 1205 return; 1206 } 1207 SDL_InvalidateMap(surface->map); 1208 1209 if (--surface->refcount > 0) { 1210 return; 1211 } 1212 while (surface->locked > 0) { 1213 SDL_UnlockSurface(surface); 1214 } 1215 if (surface->flags & SDL_RLEACCEL) { 1216 SDL_UnRLESurface(surface, 0); 1217 } 1218 if (surface->format) { 1219 SDL_SetSurfacePalette(surface, NULL); 1220 SDL_FreeFormat(surface->format); 1221 surface->format = NULL; 1222 } 1223 if (!(surface->flags & SDL_PREALLOC)) { 1224 SDL_free(surface->pixels); 1225 } 1226 if (surface->map) { 1227 SDL_FreeBlitMap(surface->map); 1228 } 1229 SDL_free(surface); 1230} 1231 1232/* vi: set ts=4 sw=4 expandtab: */ 1233[FILE END](C) 2025 0x4248 (C) 2025 4248 Media and 4248 Systems, All part of 0x4248 See LICENCE files for more information. Not all files are by 0x4248 always check Licencing.