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 (at) libsdl.org 21 */ 22 #include "SDL_config.h" 23 24 #include "SDL_video.h" 25 #include "SDL_sysvideo.h" 26 #include "SDL_cursor_c.h" 27 #include "SDL_blit.h" 28 #include "SDL_RLEaccel_c.h" 29 #include "SDL_pixels_c.h" 30 #include "SDL_leaks.h" 31 32 33 /* Public routines */ 34 /* 35 * Create an empty RGB surface of the appropriate depth 36 */ 37 SDL_Surface * SDL_CreateRGBSurface (Uint32 flags, 38 int width, int height, int depth, 39 Uint32 Rmask, Uint32 Gmask, Uint32 Bmask, Uint32 Amask) 40 { 41 SDL_VideoDevice *video = current_video; 42 SDL_VideoDevice *this = current_video; 43 SDL_Surface *screen; 44 SDL_Surface *surface; 45 46 /* Make sure the size requested doesn't overflow our datatypes */ 47 /* Next time I write a library like SDL, I'll use int for size. :) */ 48 if ( width >= 16384 || height >= 65536 ) { 49 SDL_SetError("Width or height is too large"); 50 return(NULL); 51 } 52 53 /* Check to see if we desire the surface in video memory */ 54 if ( video ) { 55 screen = SDL_PublicSurface; 56 } else { 57 screen = NULL; 58 } 59 if ( screen && ((screen->flags&SDL_HWSURFACE) == SDL_HWSURFACE) ) { 60 if ( (flags&(SDL_SRCCOLORKEY|SDL_SRCALPHA)) != 0 ) { 61 flags |= SDL_HWSURFACE; 62 } 63 if ( (flags & SDL_SRCCOLORKEY) == SDL_SRCCOLORKEY ) { 64 if ( ! current_video->info.blit_hw_CC ) { 65 flags &= ~SDL_HWSURFACE; 66 } 67 } 68 if ( (flags & SDL_SRCALPHA) == SDL_SRCALPHA ) { 69 if ( ! current_video->info.blit_hw_A ) { 70 flags &= ~SDL_HWSURFACE; 71 } 72 } 73 } else { 74 flags &= ~SDL_HWSURFACE; 75 } 76 77 /* Allocate the surface */ 78 surface = (SDL_Surface *)SDL_malloc(sizeof(*surface)); 79 if ( surface == NULL ) { 80 SDL_OutOfMemory(); 81 return(NULL); 82 } 83 surface->flags = SDL_SWSURFACE; 84 if ( (flags & SDL_HWSURFACE) == SDL_HWSURFACE ) { 85 if ((Amask) && (video->displayformatalphapixel)) 86 { 87 depth = video->displayformatalphapixel->BitsPerPixel; 88 Rmask = video->displayformatalphapixel->Rmask; 89 Gmask = video->displayformatalphapixel->Gmask; 90 Bmask = video->displayformatalphapixel->Bmask; 91 Amask = video->displayformatalphapixel->Amask; 92 } 93 else 94 { 95 depth = screen->format->BitsPerPixel; 96 Rmask = screen->format->Rmask; 97 Gmask = screen->format->Gmask; 98 Bmask = screen->format->Bmask; 99 Amask = screen->format->Amask; 100 } 101 } 102 surface->format = SDL_AllocFormat(depth, Rmask, Gmask, Bmask, Amask); 103 if ( surface->format == NULL ) { 104 SDL_free(surface); 105 return(NULL); 106 } 107 if ( Amask ) { 108 surface->flags |= SDL_SRCALPHA; 109 } 110 surface->w = width; 111 surface->h = height; 112 surface->pitch = SDL_CalculatePitch(surface); 113 surface->pixels = NULL; 114 surface->offset = 0; 115 surface->hwdata = NULL; 116 surface->locked = 0; 117 surface->map = NULL; 118 surface->unused1 = 0; 119 SDL_SetClipRect(surface, NULL); 120 SDL_FormatChanged(surface); 121 122 /* Get the pixels */ 123 if ( ((flags&SDL_HWSURFACE) == SDL_SWSURFACE) || 124 (video->AllocHWSurface(this, surface) < 0) ) { 125 if ( surface->w && surface->h ) { 126 surface->pixels = SDL_malloc(surface->h*surface->pitch); 127 if ( surface->pixels == NULL ) { 128 SDL_FreeSurface(surface); 129 SDL_OutOfMemory(); 130 return(NULL); 131 } 132 /* This is important for bitmaps */ 133 SDL_memset(surface->pixels, 0, surface->h*surface->pitch); 134 } 135 } 136 137 /* Allocate an empty mapping */ 138 surface->map = SDL_AllocBlitMap(); 139 if ( surface->map == NULL ) { 140 SDL_FreeSurface(surface); 141 return(NULL); 142 } 143 144 /* The surface is ready to go */ 145 surface->refcount = 1; 146 #ifdef CHECK_LEAKS 147 ++surfaces_allocated; 148 #endif 149 return(surface); 150 } 151 /* 152 * Create an RGB surface from an existing memory buffer 153 */ 154 SDL_Surface * SDL_CreateRGBSurfaceFrom (void *pixels, 155 int width, int height, int depth, int pitch, 156 Uint32 Rmask, Uint32 Gmask, Uint32 Bmask, Uint32 Amask) 157 { 158 SDL_Surface *surface; 159 160 surface = SDL_CreateRGBSurface(SDL_SWSURFACE, 0, 0, depth, 161 Rmask, Gmask, Bmask, Amask); 162 if ( surface != NULL ) { 163 surface->flags |= SDL_PREALLOC; 164 surface->pixels = pixels; 165 surface->w = width; 166 surface->h = height; 167 surface->pitch = pitch; 168 SDL_SetClipRect(surface, NULL); 169 } 170 return(surface); 171 } 172 /* 173 * Set the color key in a blittable surface 174 */ 175 int SDL_SetColorKey (SDL_Surface *surface, Uint32 flag, Uint32 key) 176 { 177 /* Sanity check the flag as it gets passed in */ 178 if ( flag & SDL_SRCCOLORKEY ) { 179 if ( flag & (SDL_RLEACCEL|SDL_RLEACCELOK) ) { 180 flag = (SDL_SRCCOLORKEY | SDL_RLEACCELOK); 181 } else { 182 flag = SDL_SRCCOLORKEY; 183 } 184 } else { 185 flag = 0; 186 } 187 188 /* Optimize away operations that don't change anything */ 189 if ( (flag == (surface->flags & (SDL_SRCCOLORKEY|SDL_RLEACCELOK))) && 190 (key == surface->format->colorkey) ) { 191 return(0); 192 } 193 194 /* UnRLE surfaces before we change the colorkey */ 195 if ( surface->flags & SDL_RLEACCEL ) { 196 SDL_UnRLESurface(surface, 1); 197 } 198 199 if ( flag ) { 200 SDL_VideoDevice *video = current_video; 201 SDL_VideoDevice *this = current_video; 202 203 204 surface->flags |= SDL_SRCCOLORKEY; 205 surface->format->colorkey = key; 206 if ( (surface->flags & SDL_HWACCEL) == SDL_HWACCEL ) { 207 if ( (video->SetHWColorKey == NULL) || 208 (video->SetHWColorKey(this, surface, key) < 0) ) { 209 surface->flags &= ~SDL_HWACCEL; 210 } 211 } 212 if ( flag & SDL_RLEACCELOK ) { 213 surface->flags |= SDL_RLEACCELOK; 214 } else { 215 surface->flags &= ~SDL_RLEACCELOK; 216 } 217 } else { 218 surface->flags &= ~(SDL_SRCCOLORKEY|SDL_RLEACCELOK); 219 surface->format->colorkey = 0; 220 } 221 SDL_InvalidateMap(surface->map); 222 return(0); 223 } 224 /* This function sets the alpha channel of a surface */ 225 int SDL_SetAlpha (SDL_Surface *surface, Uint32 flag, Uint8 value) 226 { 227 Uint32 oldflags = surface->flags; 228 Uint32 oldalpha = surface->format->alpha; 229 230 /* Sanity check the flag as it gets passed in */ 231 if ( flag & SDL_SRCALPHA ) { 232 if ( flag & (SDL_RLEACCEL|SDL_RLEACCELOK) ) { 233 flag = (SDL_SRCALPHA | SDL_RLEACCELOK); 234 } else { 235 flag = SDL_SRCALPHA; 236 } 237 } else { 238 flag = 0; 239 } 240 241 /* Optimize away operations that don't change anything */ 242 if ( (flag == (surface->flags & (SDL_SRCALPHA|SDL_RLEACCELOK))) && 243 (!flag || value == oldalpha) ) { 244 return(0); 245 } 246 247 if(!(flag & SDL_RLEACCELOK) && (surface->flags & SDL_RLEACCEL)) 248 SDL_UnRLESurface(surface, 1); 249 250 if ( flag ) { 251 SDL_VideoDevice *video = current_video; 252 SDL_VideoDevice *this = current_video; 253 254 surface->flags |= SDL_SRCALPHA; 255 surface->format->alpha = value; 256 if ( (surface->flags & SDL_HWACCEL) == SDL_HWACCEL ) { 257 if ( (video->SetHWAlpha == NULL) || 258 (video->SetHWAlpha(this, surface, value) < 0) ) { 259 surface->flags &= ~SDL_HWACCEL; 260 } 261 } 262 if ( flag & SDL_RLEACCELOK ) { 263 surface->flags |= SDL_RLEACCELOK; 264 } else { 265 surface->flags &= ~SDL_RLEACCELOK; 266 } 267 } else { 268 surface->flags &= ~SDL_SRCALPHA; 269 surface->format->alpha = SDL_ALPHA_OPAQUE; 270 } 271 /* 272 * The representation for software surfaces is independent of 273 * per-surface alpha, so no need to invalidate the blit mapping 274 * if just the alpha value was changed. (If either is 255, we still 275 * need to invalidate.) 276 */ 277 if((surface->flags & SDL_HWACCEL) == SDL_HWACCEL 278 || oldflags != surface->flags 279 || (((oldalpha + 1) ^ (value + 1)) & 0x100)) 280 SDL_InvalidateMap(surface->map); 281 return(0); 282 } 283 int SDL_SetAlphaChannel(SDL_Surface *surface, Uint8 value) 284 { 285 int row, col; 286 int offset; 287 Uint8 *buf; 288 289 if ( (surface->format->Amask != 0xFF000000) && 290 (surface->format->Amask != 0x000000FF) ) { 291 SDL_SetError("Unsupported surface alpha mask format"); 292 return -1; 293 } 294 295 #if SDL_BYTEORDER == SDL_LIL_ENDIAN 296 if ( surface->format->Amask == 0xFF000000 ) { 297 offset = 3; 298 } else { 299 offset = 0; 300 } 301 #else 302 if ( surface->format->Amask == 0xFF000000 ) { 303 offset = 0; 304 } else { 305 offset = 3; 306 } 307 #endif /* Byte ordering */ 308 309 /* Quickly set the alpha channel of an RGBA or ARGB surface */ 310 if ( SDL_MUSTLOCK(surface) ) { 311 if ( SDL_LockSurface(surface) < 0 ) { 312 return -1; 313 } 314 } 315 row = surface->h; 316 while (row--) { 317 col = surface->w; 318 buf = (Uint8 *)surface->pixels + row * surface->pitch + offset; 319 while(col--) { 320 *buf = value; 321 buf += 4; 322 } 323 } 324 if ( SDL_MUSTLOCK(surface) ) { 325 SDL_UnlockSurface(surface); 326 } 327 return 0; 328 } 329 330 /* 331 * A function to calculate the intersection of two rectangles: 332 * return true if the rectangles intersect, false otherwise 333 */ 334 static __inline__ 335 SDL_bool SDL_IntersectRect(const SDL_Rect *A, const SDL_Rect *B, SDL_Rect *intersection) 336 { 337 int Amin, Amax, Bmin, Bmax; 338 339 /* Horizontal intersection */ 340 Amin = A->x; 341 Amax = Amin + A->w; 342 Bmin = B->x; 343 Bmax = Bmin + B->w; 344 if(Bmin > Amin) 345 Amin = Bmin; 346 intersection->x = Amin; 347 if(Bmax < Amax) 348 Amax = Bmax; 349 intersection->w = Amax - Amin > 0 ? Amax - Amin : 0; 350 351 /* Vertical intersection */ 352 Amin = A->y; 353 Amax = Amin + A->h; 354 Bmin = B->y; 355 Bmax = Bmin + B->h; 356 if(Bmin > Amin) 357 Amin = Bmin; 358 intersection->y = Amin; 359 if(Bmax < Amax) 360 Amax = Bmax; 361 intersection->h = Amax - Amin > 0 ? Amax - Amin : 0; 362 363 return (intersection->w && intersection->h); 364 } 365 /* 366 * Set the clipping rectangle for a blittable surface 367 */ 368 SDL_bool SDL_SetClipRect(SDL_Surface *surface, const SDL_Rect *rect) 369 { 370 SDL_Rect full_rect; 371 372 /* Don't do anything if there's no surface to act on */ 373 if ( ! surface ) { 374 return SDL_FALSE; 375 } 376 377 /* Set up the full surface rectangle */ 378 full_rect.x = 0; 379 full_rect.y = 0; 380 full_rect.w = surface->w; 381 full_rect.h = surface->h; 382 383 /* Set the clipping rectangle */ 384 if ( ! rect ) { 385 surface->clip_rect = full_rect; 386 return 1; 387 } 388 return SDL_IntersectRect(rect, &full_rect, &surface->clip_rect); 389 } 390 void SDL_GetClipRect(SDL_Surface *surface, SDL_Rect *rect) 391 { 392 if ( surface && rect ) { 393 *rect = surface->clip_rect; 394 } 395 } 396 /* 397 * Set up a blit between two surfaces -- split into three parts: 398 * The upper part, SDL_UpperBlit(), performs clipping and rectangle 399 * verification. The lower part is a pointer to a low level 400 * accelerated blitting function. 401 * 402 * These parts are separated out and each used internally by this 403 * library in the optimimum places. They are exported so that if 404 * you know exactly what you are doing, you can optimize your code 405 * by calling the one(s) you need. 406 */ 407 int SDL_LowerBlit (SDL_Surface *src, SDL_Rect *srcrect, 408 SDL_Surface *dst, SDL_Rect *dstrect) 409 { 410 SDL_blit do_blit; 411 SDL_Rect hw_srcrect; 412 SDL_Rect hw_dstrect; 413 414 /* Check to make sure the blit mapping is valid */ 415 if ( (src->map->dst != dst) || 416 (src->map->dst->format_version != src->map->format_version) ) { 417 if ( SDL_MapSurface(src, dst) < 0 ) { 418 return(-1); 419 } 420 } 421 422 /* Figure out which blitter to use */ 423 if ( (src->flags & SDL_HWACCEL) == SDL_HWACCEL ) { 424 if ( src == SDL_VideoSurface ) { 425 hw_srcrect = *srcrect; 426 hw_srcrect.x += current_video->offset_x; 427 hw_srcrect.y += current_video->offset_y; 428 srcrect = &hw_srcrect; 429 } 430 if ( dst == SDL_VideoSurface ) { 431 hw_dstrect = *dstrect; 432 hw_dstrect.x += current_video->offset_x; 433 hw_dstrect.y += current_video->offset_y; 434 dstrect = &hw_dstrect; 435 } 436 do_blit = src->map->hw_blit; 437 } else { 438 do_blit = src->map->sw_blit; 439 } 440 return(do_blit(src, srcrect, dst, dstrect)); 441 } 442 443 444 int SDL_UpperBlit (SDL_Surface *src, SDL_Rect *srcrect, 445 SDL_Surface *dst, SDL_Rect *dstrect) 446 { 447 SDL_Rect fulldst; 448 int srcx, srcy, w, h; 449 450 /* Make sure the surfaces aren't locked */ 451 if ( ! src || ! dst ) { 452 SDL_SetError("SDL_UpperBlit: passed a NULL surface"); 453 return(-1); 454 } 455 if ( src->locked || dst->locked ) { 456 SDL_SetError("Surfaces must not be locked during blit"); 457 return(-1); 458 } 459 460 /* If the destination rectangle is NULL, use the entire dest surface */ 461 if ( dstrect == NULL ) { 462 fulldst.x = fulldst.y = 0; 463 dstrect = &fulldst; 464 } 465 466 /* clip the source rectangle to the source surface */ 467 if(srcrect) { 468 int maxw, maxh; 469 470 srcx = srcrect->x; 471 w = srcrect->w; 472 if(srcx < 0) { 473 w += srcx; 474 dstrect->x -= srcx; 475 srcx = 0; 476 } 477 maxw = src->w - srcx; 478 if(maxw < w) 479 w = maxw; 480 481 srcy = srcrect->y; 482 h = srcrect->h; 483 if(srcy < 0) { 484 h += srcy; 485 dstrect->y -= srcy; 486 srcy = 0; 487 } 488 maxh = src->h - srcy; 489 if(maxh < h) 490 h = maxh; 491 492 } else { 493 srcx = srcy = 0; 494 w = src->w; 495 h = src->h; 496 } 497 498 /* clip the destination rectangle against the clip rectangle */ 499 { 500 SDL_Rect *clip = &dst->clip_rect; 501 int dx, dy; 502 503 dx = clip->x - dstrect->x; 504 if(dx > 0) { 505 w -= dx; 506 dstrect->x += dx; 507 srcx += dx; 508 } 509 dx = dstrect->x + w - clip->x - clip->w; 510 if(dx > 0) 511 w -= dx; 512 513 dy = clip->y - dstrect->y; 514 if(dy > 0) { 515 h -= dy; 516 dstrect->y += dy; 517 srcy += dy; 518 } 519 dy = dstrect->y + h - clip->y - clip->h; 520 if(dy > 0) 521 h -= dy; 522 } 523 524 if(w > 0 && h > 0) { 525 SDL_Rect sr; 526 sr.x = srcx; 527 sr.y = srcy; 528 sr.w = dstrect->w = w; 529 sr.h = dstrect->h = h; 530 return SDL_LowerBlit(src, &sr, dst, dstrect); 531 } 532 dstrect->w = dstrect->h = 0; 533 return 0; 534 } 535 536 static int SDL_FillRect1(SDL_Surface *dst, SDL_Rect *dstrect, Uint32 color) 537 { 538 /* FIXME: We have to worry about packing order.. *sigh* */ 539 SDL_SetError("1-bpp rect fill not yet implemented"); 540 return -1; 541 } 542 543 static int SDL_FillRect4(SDL_Surface *dst, SDL_Rect *dstrect, Uint32 color) 544 { 545 /* FIXME: We have to worry about packing order.. *sigh* */ 546 SDL_SetError("4-bpp rect fill not yet implemented"); 547 return -1; 548 } 549 550 /* 551 * This function performs a fast fill of the given rectangle with 'color' 552 */ 553 int SDL_FillRect(SDL_Surface *dst, SDL_Rect *dstrect, Uint32 color) 554 { 555 SDL_VideoDevice *video = current_video; 556 SDL_VideoDevice *this = current_video; 557 int x, y; 558 Uint8 *row; 559 560 /* This function doesn't work on surfaces < 8 bpp */ 561 if ( dst->format->BitsPerPixel < 8 ) { 562 switch(dst->format->BitsPerPixel) { 563 case 1: 564 return SDL_FillRect1(dst, dstrect, color); 565 break; 566 case 4: 567 return SDL_FillRect4(dst, dstrect, color); 568 break; 569 default: 570 SDL_SetError("Fill rect on unsupported surface format"); 571 return(-1); 572 break; 573 } 574 } 575 576 /* If 'dstrect' == NULL, then fill the whole surface */ 577 if ( dstrect ) { 578 /* Perform clipping */ 579 if ( !SDL_IntersectRect(dstrect, &dst->clip_rect, dstrect) ) { 580 return(0); 581 } 582 } else { 583 dstrect = &dst->clip_rect; 584 } 585 586 /* Check for hardware acceleration */ 587 if ( ((dst->flags & SDL_HWSURFACE) == SDL_HWSURFACE) && 588 video->info.blit_fill ) { 589 SDL_Rect hw_rect; 590 if ( dst == SDL_VideoSurface ) { 591 hw_rect = *dstrect; 592 hw_rect.x += current_video->offset_x; 593 hw_rect.y += current_video->offset_y; 594 dstrect = &hw_rect; 595 } 596 return(video->FillHWRect(this, dst, dstrect, color)); 597 } 598 599 /* Perform software fill */ 600 if ( SDL_LockSurface(dst) != 0 ) { 601 return(-1); 602 } 603 row = (Uint8 *)dst->pixels+dstrect->y*dst->pitch+ 604 dstrect->x*dst->format->BytesPerPixel; 605 if ( dst->format->palette || (color == 0) ) { 606 x = dstrect->w*dst->format->BytesPerPixel; 607 if ( !color && !((uintptr_t)row&3) && !(x&3) && !(dst->pitch&3) ) { 608 int n = x >> 2; 609 for ( y=dstrect->h; y; --y ) { 610 SDL_memset4(row, 0, n); 611 row += dst->pitch; 612 } 613 } else { 614 #ifdef __powerpc__ 615 /* 616 * SDL_memset() on PPC (both glibc and codewarrior) uses 617 * the dcbz (Data Cache Block Zero) instruction, which 618 * causes an alignment exception if the destination is 619 * uncachable, so only use it on software surfaces 620 */ 621 if((dst->flags & SDL_HWSURFACE) == SDL_HWSURFACE) { 622 if(dstrect->w >= 8) { 623 /* 624 * 64-bit stores are probably most 625 * efficient to uncached video memory 626 */ 627 double fill; 628 SDL_memset(&fill, color, (sizeof fill)); 629 for(y = dstrect->h; y; y--) { 630 Uint8 *d = row; 631 unsigned n = x; 632 unsigned nn; 633 Uint8 c = color; 634 double f = fill; 635 while((unsigned long)d 636 & (sizeof(double) - 1)) { 637 *d++ = c; 638 n--; 639 } 640 nn = n / (sizeof(double) * 4); 641 while(nn) { 642 ((double *)d)[0] = f; 643 ((double *)d)[1] = f; 644 ((double *)d)[2] = f; 645 ((double *)d)[3] = f; 646 d += 4*sizeof(double); 647 nn--; 648 } 649 n &= ~(sizeof(double) * 4 - 1); 650 nn = n / sizeof(double); 651 while(nn) { 652 *(double *)d = f; 653 d += sizeof(double); 654 nn--; 655 } 656 n &= ~(sizeof(double) - 1); 657 while(n) { 658 *d++ = c; 659 n--; 660 } 661 row += dst->pitch; 662 } 663 } else { 664 /* narrow boxes */ 665 for(y = dstrect->h; y; y--) { 666 Uint8 *d = row; 667 Uint8 c = color; 668 int n = x; 669 while(n) { 670 *d++ = c; 671 n--; 672 } 673 row += dst->pitch; 674 } 675 } 676 } else 677 #endif /* __powerpc__ */ 678 { 679 for(y = dstrect->h; y; y--) { 680 SDL_memset(row, color, x); 681 row += dst->pitch; 682 } 683 } 684 } 685 } else { 686 switch (dst->format->BytesPerPixel) { 687 case 2: 688 for ( y=dstrect->h; y; --y ) { 689 Uint16 *pixels = (Uint16 *)row; 690 Uint16 c = (Uint16)color; 691 Uint32 cc = (Uint32)c << 16 | c; 692 int n = dstrect->w; 693 if((uintptr_t)pixels & 3) { 694 *pixels++ = c; 695 n--; 696 } 697 if(n >> 1) 698 SDL_memset4(pixels, cc, n >> 1); 699 if(n & 1) 700 pixels[n - 1] = c; 701 row += dst->pitch; 702 } 703 break; 704 705 case 3: 706 #if SDL_BYTEORDER == SDL_BIG_ENDIAN 707 color <<= 8; 708 #endif 709 for ( y=dstrect->h; y; --y ) { 710 Uint8 *pixels = row; 711 for ( x=dstrect->w; x; --x ) { 712 SDL_memcpy(pixels, &color, 3); 713 pixels += 3; 714 } 715 row += dst->pitch; 716 } 717 break; 718 719 case 4: 720 for(y = dstrect->h; y; --y) { 721 SDL_memset4(row, color, dstrect->w); 722 row += dst->pitch; 723 } 724 break; 725 } 726 } 727 SDL_UnlockSurface(dst); 728 729 /* We're done! */ 730 return(0); 731 } 732 733 /* 734 * Lock a surface to directly access the pixels 735 */ 736 int SDL_LockSurface (SDL_Surface *surface) 737 { 738 if ( ! surface->locked ) { 739 /* Perform the lock */ 740 if ( surface->flags & (SDL_HWSURFACE|SDL_ASYNCBLIT) ) { 741 SDL_VideoDevice *video = current_video; 742 SDL_VideoDevice *this = current_video; 743 if ( video->LockHWSurface(this, surface) < 0 ) { 744 return(-1); 745 } 746 } 747 if ( surface->flags & SDL_RLEACCEL ) { 748 SDL_UnRLESurface(surface, 1); 749 surface->flags |= SDL_RLEACCEL; /* save accel'd state */ 750 } 751 /* This needs to be done here in case pixels changes value */ 752 surface->pixels = (Uint8 *)surface->pixels + surface->offset; 753 } 754 755 /* Increment the surface lock count, for recursive locks */ 756 ++surface->locked; 757 758 /* Ready to go.. */ 759 return(0); 760 } 761 /* 762 * Unlock a previously locked surface 763 */ 764 void SDL_UnlockSurface (SDL_Surface *surface) 765 { 766 /* Only perform an unlock if we are locked */ 767 if ( ! surface->locked || (--surface->locked > 0) ) { 768 return; 769 } 770 771 /* Perform the unlock */ 772 surface->pixels = (Uint8 *)surface->pixels - surface->offset; 773 774 /* Unlock hardware or accelerated surfaces */ 775 if ( surface->flags & (SDL_HWSURFACE|SDL_ASYNCBLIT) ) { 776 SDL_VideoDevice *video = current_video; 777 SDL_VideoDevice *this = current_video; 778 video->UnlockHWSurface(this, surface); 779 } else { 780 /* Update RLE encoded surface with new data */ 781 if ( (surface->flags & SDL_RLEACCEL) == SDL_RLEACCEL ) { 782 surface->flags &= ~SDL_RLEACCEL; /* stop lying */ 783 SDL_RLESurface(surface); 784 } 785 } 786 } 787 788 /* 789 * Convert a surface into the specified pixel format. 790 */ 791 SDL_Surface * SDL_ConvertSurface (SDL_Surface *surface, 792 SDL_PixelFormat *format, Uint32 flags) 793 { 794 SDL_Surface *convert; 795 Uint32 colorkey = 0; 796 Uint8 alpha = 0; 797 Uint32 surface_flags; 798 SDL_Rect bounds; 799 800 /* Check for empty destination palette! (results in empty image) */ 801 if ( format->palette != NULL ) { 802 int i; 803 for ( i=0; i<format->palette->ncolors; ++i ) { 804 if ( (format->palette->colors[i].r != 0) || 805 (format->palette->colors[i].g != 0) || 806 (format->palette->colors[i].b != 0) ) 807 break; 808 } 809 if ( i == format->palette->ncolors ) { 810 SDL_SetError("Empty destination palette"); 811 return(NULL); 812 } 813 } 814 815 /* Only create hw surfaces with alpha channel if hw alpha blits 816 are supported */ 817 if(format->Amask != 0 && (flags & SDL_HWSURFACE)) { 818 const SDL_VideoInfo *vi = SDL_GetVideoInfo(); 819 if(!vi || !vi->blit_hw_A) 820 flags &= ~SDL_HWSURFACE; 821 } 822 823 /* Create a new surface with the desired format */ 824 convert = SDL_CreateRGBSurface(flags, 825 surface->w, surface->h, format->BitsPerPixel, 826 format->Rmask, format->Gmask, format->Bmask, format->Amask); 827 if ( convert == NULL ) { 828 return(NULL); 829 } 830 831 /* Copy the palette if any */ 832 if ( format->palette && convert->format->palette ) { 833 SDL_memcpy(convert->format->palette->colors, 834 format->palette->colors, 835 format->palette->ncolors*sizeof(SDL_Color)); 836 convert->format->palette->ncolors = format->palette->ncolors; 837 } 838 839 /* Save the original surface color key and alpha */ 840 surface_flags = surface->flags; 841 if ( (surface_flags & SDL_SRCCOLORKEY) == SDL_SRCCOLORKEY ) { 842 /* Convert colourkeyed surfaces to RGBA if requested */ 843 if((flags & SDL_SRCCOLORKEY) != SDL_SRCCOLORKEY 844 && format->Amask) { 845 surface_flags &= ~SDL_SRCCOLORKEY; 846 } else { 847 colorkey = surface->format->colorkey; 848 SDL_SetColorKey(surface, 0, 0); 849 } 850 } 851 if ( (surface_flags & SDL_SRCALPHA) == SDL_SRCALPHA ) { 852 /* Copy over the alpha channel to RGBA if requested */ 853 if ( format->Amask ) { 854 surface->flags &= ~SDL_SRCALPHA; 855 } else { 856 alpha = surface->format->alpha; 857 SDL_SetAlpha(surface, 0, 0); 858 } 859 } 860 861 /* Copy over the image data */ 862 bounds.x = 0; 863 bounds.y = 0; 864 bounds.w = surface->w; 865 bounds.h = surface->h; 866 SDL_LowerBlit(surface, &bounds, convert, &bounds); 867 868 /* Clean up the original surface, and update converted surface */ 869 if ( convert != NULL ) { 870 SDL_SetClipRect(convert, &surface->clip_rect); 871 } 872 if ( (surface_flags & SDL_SRCCOLORKEY) == SDL_SRCCOLORKEY ) { 873 Uint32 cflags = surface_flags&(SDL_SRCCOLORKEY|SDL_RLEACCELOK); 874 if ( convert != NULL ) { 875 Uint8 keyR, keyG, keyB; 876 877 SDL_GetRGB(colorkey,surface->format,&keyR,&keyG,&keyB); 878 SDL_SetColorKey(convert, cflags|(flags&SDL_RLEACCELOK), 879 SDL_MapRGB(convert->format, keyR, keyG, keyB)); 880 } 881 SDL_SetColorKey(surface, cflags, colorkey); 882 } 883 if ( (surface_flags & SDL_SRCALPHA) == SDL_SRCALPHA ) { 884 Uint32 aflags = surface_flags&(SDL_SRCALPHA|SDL_RLEACCELOK); 885 if ( convert != NULL ) { 886 SDL_SetAlpha(convert, aflags|(flags&SDL_RLEACCELOK), 887 alpha); 888 } 889 if ( format->Amask ) { 890 surface->flags |= SDL_SRCALPHA; 891 } else { 892 SDL_SetAlpha(surface, aflags, alpha); 893 } 894 } 895 896 /* We're ready to go! */ 897 return(convert); 898 } 899 900 /* 901 * Free a surface created by the above function. 902 */ 903 void SDL_FreeSurface (SDL_Surface *surface) 904 { 905 /* Free anything that's not NULL, and not the screen surface */ 906 if ((surface == NULL) || 907 (current_video && 908 ((surface == SDL_ShadowSurface)||(surface == SDL_VideoSurface)))) { 909 return; 910 } 911 if ( --surface->refcount > 0 ) { 912 return; 913 } 914 while ( surface->locked > 0 ) { 915 SDL_UnlockSurface(surface); 916 } 917 if ( (surface->flags & SDL_RLEACCEL) == SDL_RLEACCEL ) { 918 SDL_UnRLESurface(surface, 0); 919 } 920 if ( surface->format ) { 921 SDL_FreeFormat(surface->format); 922 surface->format = NULL; 923 } 924 if ( surface->map != NULL ) { 925 SDL_FreeBlitMap(surface->map); 926 surface->map = NULL; 927 } 928 if ( surface->hwdata ) { 929 SDL_VideoDevice *video = current_video; 930 SDL_VideoDevice *this = current_video; 931 video->FreeHWSurface(this, surface); 932 } 933 if ( surface->pixels && 934 ((surface->flags & SDL_PREALLOC) != SDL_PREALLOC) ) { 935 SDL_free(surface->pixels); 936 } 937 SDL_free(surface); 938 #ifdef CHECK_LEAKS 939 --surfaces_allocated; 940 #endif 941 } 942