Atlas - SDL_RLEaccel.c
Home / ext / SDL / src / video Lines: 1 | Size: 66987 bytes [Download] [Show on GitHub] [Search similar files] [Raw] [Raw (proxy)][FILE BEGIN]1/* 2 Simple DirectMedia Layer 3 Copyright (C) 1997-2025 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#ifdef SDL_HAVE_RLE 24 25/* 26 * RLE encoding for software colorkey and alpha-channel acceleration 27 * 28 * Original version by Sam Lantinga 29 * 30 * Mattias EngdegÄrd (Yorick): Rewrite. New encoding format, encoder and 31 * decoder. Added per-surface alpha blitter. Added per-pixel alpha 32 * format, encoder and blitter. 33 * 34 * Many thanks to Xark and johns for hints, benchmarks and useful comments 35 * leading to this code. 36 * 37 * Welcome to Macro Mayhem. 38 */ 39 40/* 41 * The encoding translates the image data to a stream of segments of the form 42 * 43 * <skip> <run> <data> 44 * 45 * where <skip> is the number of transparent pixels to skip, 46 * <run> is the number of opaque pixels to blit, 47 * and <data> are the pixels themselves. 48 * 49 * This basic structure is used both for colorkeyed surfaces, used for simple 50 * binary transparency and for per-surface alpha blending, and for surfaces 51 * with per-pixel alpha. The details differ, however: 52 * 53 * Encoding of colorkeyed surfaces: 54 * 55 * Encoded pixels always have the same format as the target surface. 56 * <skip> and <run> are unsigned 8 bit integers, except for 32 bit depth 57 * where they are 16 bit. This makes the pixel data aligned at all times. 58 * Segments never wrap around from one scan line to the next. 59 * 60 * The end of the sequence is marked by a zero <skip>,<run> pair at the * 61 * beginning of a line. 62 * 63 * Encoding of surfaces with per-pixel alpha: 64 * 65 * The sequence begins with an SDL_PixelFormat value describing the target 66 * pixel format, to provide reliable un-encoding. 67 * 68 * Each scan line is encoded twice: First all completely opaque pixels, 69 * encoded in the target format as described above, and then all 70 * partially transparent (translucent) pixels (where 1 <= alpha <= 254), 71 * in the following 32-bit format: 72 * 73 * For 32-bit targets, each pixel has the target RGB format but with 74 * the alpha value occupying the highest 8 bits. The <skip> and <run> 75 * counts are 16 bit. 76 * 77 * For 16-bit targets, each pixel has the target RGB format, but with 78 * the middle component (usually green) shifted 16 steps to the left, 79 * and the hole filled with the 5 most significant bits of the alpha value. 80 * i.e. if the target has the format rrrrrggggggbbbbb, 81 * the encoded pixel will be 00000gggggg00000rrrrr0aaaaabbbbb. 82 * The <skip> and <run> counts are 8 bit for the opaque lines, 16 bit 83 * for the translucent lines. Two padding bytes may be inserted 84 * before each translucent line to keep them 32-bit aligned. 85 * 86 * The end of the sequence is marked by a zero <skip>,<run> pair at the 87 * beginning of an opaque line. 88 */ 89 90#include "SDL_sysvideo.h" 91#include "SDL_surface_c.h" 92#include "SDL_pixels_c.h" 93#include "SDL_RLEaccel_c.h" 94 95#define PIXEL_COPY(to, from, len, bpp) \ 96 SDL_memcpy(to, from, (size_t)(len) * (bpp)) 97 98/* 99 * Various colorkey blit methods, for opaque and per-surface alpha 100 */ 101 102#define OPAQUE_BLIT(to, from, length, bpp, alpha) \ 103 PIXEL_COPY(to, from, length, bpp) 104 105/* 106 * For 32bpp pixels on the form 0x00rrggbb: 107 * If we treat the middle component separately, we can process the two 108 * remaining in parallel. This is safe to do because of the gap to the left 109 * of each component, so the bits from the multiplication don't collide. 110 * This can be used for any RGB permutation of course. 111 */ 112#define ALPHA_BLIT32_888(to, from, length, bpp, alpha) \ 113 do { \ 114 int i; \ 115 Uint32 *src = (Uint32 *)(from); \ 116 Uint32 *dst = (Uint32 *)(to); \ 117 for (i = 0; i < (int)(length); i++) { \ 118 Uint32 s = *src++; \ 119 Uint32 d = *dst; \ 120 Uint32 s1 = s & 0xff00ff; \ 121 Uint32 d1 = d & 0xff00ff; \ 122 d1 = (d1 + ((s1 - d1) * alpha >> 8)) & 0xff00ff; \ 123 s &= 0xff00; \ 124 d &= 0xff00; \ 125 d = (d + ((s - d) * alpha >> 8)) & 0xff00; \ 126 *dst++ = d1 | d; \ 127 } \ 128 } while (0) 129 130/* 131 * For 16bpp pixels we can go a step further: put the middle component 132 * in the high 16 bits of a 32 bit word, and process all three RGB 133 * components at the same time. Since the smallest gap is here just 134 * 5 bits, we have to scale alpha down to 5 bits as well. 135 */ 136#define ALPHA_BLIT16_565(to, from, length, bpp, alpha) \ 137 do { \ 138 int i; \ 139 Uint16 *src = (Uint16 *)(from); \ 140 Uint16 *dst = (Uint16 *)(to); \ 141 Uint32 ALPHA = alpha >> 3; \ 142 for (i = 0; i < (int)(length); i++) { \ 143 Uint32 s = *src++; \ 144 Uint32 d = *dst; \ 145 s = (s | s << 16) & 0x07e0f81f; \ 146 d = (d | d << 16) & 0x07e0f81f; \ 147 d += (s - d) * ALPHA >> 5; \ 148 d &= 0x07e0f81f; \ 149 *dst++ = (Uint16)(d | d >> 16); \ 150 } \ 151 } while (0) 152 153#define ALPHA_BLIT16_555(to, from, length, bpp, alpha) \ 154 do { \ 155 int i; \ 156 Uint16 *src = (Uint16 *)(from); \ 157 Uint16 *dst = (Uint16 *)(to); \ 158 Uint32 ALPHA = alpha >> 3; \ 159 for (i = 0; i < (int)(length); i++) { \ 160 Uint32 s = *src++; \ 161 Uint32 d = *dst; \ 162 s = (s | s << 16) & 0x03e07c1f; \ 163 d = (d | d << 16) & 0x03e07c1f; \ 164 d += (s - d) * ALPHA >> 5; \ 165 d &= 0x03e07c1f; \ 166 *dst++ = (Uint16)(d | d >> 16); \ 167 } \ 168 } while (0) 169 170/* 171 * The general slow catch-all function, for remaining depths and formats 172 */ 173#if SDL_BYTEORDER == SDL_BIG_ENDIAN 174#define SET_RGB24(dst, d) \ 175 dst[0] = (Uint8)(d >> 16); \ 176 dst[1] = (Uint8)(d >> 8); \ 177 dst[2] = (Uint8)(d); 178#else 179#define SET_RGB24(dst, d) \ 180 dst[0] = (Uint8)(d); \ 181 dst[1] = (Uint8)(d >> 8); \ 182 dst[2] = (Uint8)(d >> 16); 183#endif 184#define ALPHA_BLIT_ANY(to, from, length, bpp, alpha) \ 185 do { \ 186 int i; \ 187 Uint8 *src = from; \ 188 Uint8 *dst = to; \ 189 for (i = 0; i < (int)(length); i++) { \ 190 Uint32 s = 0, d = 0; \ 191 unsigned rs, gs, bs, rd, gd, bd; \ 192 switch (bpp) { \ 193 case 2: \ 194 s = *(Uint16 *)src; \ 195 d = *(Uint16 *)dst; \ 196 break; \ 197 case 3: \ 198 s = GET_RGB24(src); \ 199 d = GET_RGB24(dst); \ 200 break; \ 201 case 4: \ 202 s = *(Uint32 *)src; \ 203 d = *(Uint32 *)dst; \ 204 break; \ 205 } \ 206 RGB_FROM_PIXEL(s, fmt, rs, gs, bs); \ 207 RGB_FROM_PIXEL(d, fmt, rd, gd, bd); \ 208 rd += (rs - rd) * alpha >> 8; \ 209 gd += (gs - gd) * alpha >> 8; \ 210 bd += (bs - bd) * alpha >> 8; \ 211 PIXEL_FROM_RGB(d, fmt, rd, gd, bd); \ 212 switch (bpp) { \ 213 case 2: \ 214 *(Uint16 *)dst = (Uint16)d; \ 215 break; \ 216 case 3: \ 217 SET_RGB24(dst, d); \ 218 break; \ 219 case 4: \ 220 *(Uint32 *)dst = d; \ 221 break; \ 222 } \ 223 src += bpp; \ 224 dst += bpp; \ 225 } \ 226 } while (0) 227 228/* 229 * Special case: 50% alpha (alpha=128) 230 * This is treated specially because it can be optimized very well, and 231 * since it is good for many cases of semi-translucency. 232 * The theory is to do all three components at the same time: 233 * First zero the lowest bit of each component, which gives us room to 234 * add them. Then shift right and add the sum of the lowest bits. 235 */ 236#define ALPHA_BLIT32_888_50(to, from, length, bpp, alpha) \ 237 do { \ 238 int i; \ 239 Uint32 *src = (Uint32 *)(from); \ 240 Uint32 *dst = (Uint32 *)(to); \ 241 for (i = 0; i < (int)(length); i++) { \ 242 Uint32 s = *src++; \ 243 Uint32 d = *dst; \ 244 *dst++ = (((s & 0x00fefefe) + (d & 0x00fefefe)) >> 1) + (s & d & 0x00010101); \ 245 } \ 246 } while (0) 247 248/* 249 * For 16bpp, we can actually blend two pixels in parallel, if we take 250 * care to shift before we add, not after. 251 */ 252 253// helper: blend a single 16 bit pixel at 50% 254#define BLEND16_50(dst, src, mask) \ 255 do { \ 256 Uint32 s = *src++; \ 257 Uint32 d = *dst; \ 258 *dst++ = (Uint16)((((s & mask) + (d & mask)) >> 1) + \ 259 (s & d & (~mask & 0xffff))); \ 260 } while (0) 261 262// basic 16bpp blender. mask is the pixels to keep when adding. 263#define ALPHA_BLIT16_50(to, from, length, bpp, alpha, mask) \ 264 do { \ 265 unsigned n = (length); \ 266 Uint16 *src = (Uint16 *)(from); \ 267 Uint16 *dst = (Uint16 *)(to); \ 268 if (((uintptr_t)src ^ (uintptr_t)dst) & 3) { \ 269 /* source and destination not in phase, blit one by one */ \ 270 while (n--) \ 271 BLEND16_50(dst, src, mask); \ 272 } else { \ 273 if ((uintptr_t)src & 3) { \ 274 /* first odd pixel */ \ 275 BLEND16_50(dst, src, mask); \ 276 n--; \ 277 } \ 278 for (; n > 1; n -= 2) { \ 279 Uint32 s = *(Uint32 *)src; \ 280 Uint32 d = *(Uint32 *)dst; \ 281 *(Uint32 *)dst = ((s & (mask | mask << 16)) >> 1) + ((d & (mask | mask << 16)) >> 1) + (s & d & (~(mask | mask << 16))); \ 282 src += 2; \ 283 dst += 2; \ 284 } \ 285 if (n) \ 286 BLEND16_50(dst, src, mask); /* last odd pixel */ \ 287 } \ 288 } while (0) 289 290#define ALPHA_BLIT16_565_50(to, from, length, bpp, alpha) \ 291 ALPHA_BLIT16_50(to, from, length, bpp, alpha, 0xf7deU) 292 293#define ALPHA_BLIT16_555_50(to, from, length, bpp, alpha) \ 294 ALPHA_BLIT16_50(to, from, length, bpp, alpha, 0xfbdeU) 295 296#define CHOOSE_BLIT(blitter, alpha, fmt) \ 297 do { \ 298 if (alpha == 255) { \ 299 switch (fmt->bytes_per_pixel) { \ 300 case 1: \ 301 blitter(1, Uint8, OPAQUE_BLIT); \ 302 break; \ 303 case 2: \ 304 blitter(2, Uint8, OPAQUE_BLIT); \ 305 break; \ 306 case 3: \ 307 blitter(3, Uint8, OPAQUE_BLIT); \ 308 break; \ 309 case 4: \ 310 blitter(4, Uint16, OPAQUE_BLIT); \ 311 break; \ 312 } \ 313 } else { \ 314 switch (fmt->bytes_per_pixel) { \ 315 case 1: \ 316 /* No 8bpp alpha blitting */ \ 317 break; \ 318 \ 319 case 2: \ 320 switch (fmt->Rmask | fmt->Gmask | fmt->Bmask) { \ 321 case 0xffff: \ 322 if (fmt->Gmask == 0x07e0 || fmt->Rmask == 0x07e0 || fmt->Bmask == 0x07e0) { \ 323 if (alpha == 128) { \ 324 blitter(2, Uint8, ALPHA_BLIT16_565_50); \ 325 } else { \ 326 blitter(2, Uint8, ALPHA_BLIT16_565); \ 327 } \ 328 } else { \ 329 goto general16; \ 330 } \ 331 break; \ 332 \ 333 case 0x7fff: \ 334 if (fmt->Gmask == 0x03e0 || fmt->Rmask == 0x03e0 || fmt->Bmask == 0x03e0) { \ 335 if (alpha == 128) { \ 336 blitter(2, Uint8, ALPHA_BLIT16_555_50); \ 337 } else { \ 338 blitter(2, Uint8, ALPHA_BLIT16_555); \ 339 } \ 340 break; \ 341 } else { \ 342 goto general16; \ 343 } \ 344 break; \ 345 \ 346 default: \ 347 general16: \ 348 blitter(2, Uint8, ALPHA_BLIT_ANY); \ 349 } \ 350 break; \ 351 \ 352 case 3: \ 353 blitter(3, Uint8, ALPHA_BLIT_ANY); \ 354 break; \ 355 \ 356 case 4: \ 357 if ((fmt->Rmask | fmt->Gmask | fmt->Bmask) == 0x00ffffff && (fmt->Gmask == 0xff00 || fmt->Rmask == 0xff00 || fmt->Bmask == 0xff00)) { \ 358 if (alpha == 128) { \ 359 blitter(4, Uint16, ALPHA_BLIT32_888_50); \ 360 } else { \ 361 blitter(4, Uint16, ALPHA_BLIT32_888); \ 362 } \ 363 } else { \ 364 blitter(4, Uint16, ALPHA_BLIT_ANY); \ 365 } \ 366 break; \ 367 } \ 368 } \ 369 } while (0) 370 371/* 372 * Set a pixel value using the given format, except that the alpha value is 373 * placed in the top byte. This is the format used for RLE with alpha. 374 */ 375#define RLEPIXEL_FROM_RGBA(Pixel, fmt, r, g, b, a) \ 376 { \ 377 Pixel = ((r >> (8 - fmt->Rbits)) << fmt->Rshift) | \ 378 ((g >> (8 - fmt->Gbits)) << fmt->Gshift) | \ 379 ((b >> (8 - fmt->Bbits)) << fmt->Bshift) | \ 380 (a << 24); \ 381 } 382 383/* 384 * This takes care of the case when the surface is clipped on the left and/or 385 * right. Top clipping has already been taken care of. 386 */ 387#define RLECLIPBLIT(bpp, Type, do_blit) \ 388 do { \ 389 int linecount = srcrect->h; \ 390 int ofs = 0; \ 391 int left = srcrect->x; \ 392 int right = left + srcrect->w; \ 393 dstbuf -= left * bpp; \ 394 for (;;) { \ 395 int run; \ 396 ofs += *(Type *)srcbuf; \ 397 run = ((Type *)srcbuf)[1]; \ 398 srcbuf += 2 * sizeof(Type); \ 399 if (run) { \ 400 /* clip to left and right borders */ \ 401 if (ofs < right) { \ 402 int start = 0; \ 403 int len = run; \ 404 int startcol; \ 405 if (left - ofs > 0) { \ 406 start = left - ofs; \ 407 len -= start; \ 408 if (len <= 0) \ 409 goto nocopy##bpp##do_blit; \ 410 } \ 411 startcol = ofs + start; \ 412 if (len > right - startcol) \ 413 len = right - startcol; \ 414 do_blit(dstbuf + startcol * bpp, srcbuf + start * bpp, \ 415 len, bpp, alpha); \ 416 } \ 417 nocopy##bpp##do_blit : srcbuf += run * bpp; \ 418 ofs += run; \ 419 } else if (!ofs) { \ 420 break; \ 421 } \ 422 \ 423 if (ofs == w) { \ 424 ofs = 0; \ 425 dstbuf += surf_dst->pitch; \ 426 if (!--linecount) { \ 427 break; \ 428 } \ 429 } \ 430 } \ 431 } while (0) 432 433static void RLEClipBlit(int w, Uint8 *srcbuf, SDL_Surface *surf_dst, 434 Uint8 *dstbuf, const SDL_Rect *srcrect, unsigned alpha) 435{ 436 const SDL_PixelFormatDetails *fmt = surf_dst->fmt; 437 438 CHOOSE_BLIT(RLECLIPBLIT, alpha, fmt); 439} 440 441#undef RLECLIPBLIT 442 443// blit a colorkeyed RLE surface 444static bool SDLCALL SDL_RLEBlit(SDL_Surface *surf_src, const SDL_Rect *srcrect, 445 SDL_Surface *surf_dst, const SDL_Rect *dstrect) 446{ 447 Uint8 *dstbuf; 448 Uint8 *srcbuf; 449 int x, y; 450 int w = surf_src->w; 451 unsigned alpha; 452 453 // Lock the destination if necessary 454 if (SDL_MUSTLOCK(surf_dst)) { 455 if (!SDL_LockSurface(surf_dst)) { 456 return false; 457 } 458 } 459 460 // Set up the source and destination pointers 461 x = dstrect->x; 462 y = dstrect->y; 463 dstbuf = (Uint8 *)surf_dst->pixels + y * surf_dst->pitch + x * surf_src->fmt->bytes_per_pixel; 464 srcbuf = (Uint8 *)surf_src->map.data + sizeof(SDL_PixelFormat); 465 466 { 467 // skip lines at the top if necessary 468 int vskip = srcrect->y; 469 int ofs = 0; 470 if (vskip) { 471 472#define RLESKIP(bpp, Type) \ 473 for (;;) { \ 474 int run; \ 475 ofs += *(Type *)srcbuf; \ 476 run = ((Type *)srcbuf)[1]; \ 477 srcbuf += sizeof(Type) * 2; \ 478 if (run) { \ 479 srcbuf += run * bpp; \ 480 ofs += run; \ 481 } else if (!ofs) \ 482 goto done; \ 483 if (ofs == w) { \ 484 ofs = 0; \ 485 if (!--vskip) \ 486 break; \ 487 } \ 488 } 489 490 switch (surf_src->fmt->bytes_per_pixel) { 491 case 1: 492 RLESKIP(1, Uint8); 493 break; 494 case 2: 495 RLESKIP(2, Uint8); 496 break; 497 case 3: 498 RLESKIP(3, Uint8); 499 break; 500 case 4: 501 RLESKIP(4, Uint16); 502 break; 503 } 504 505#undef RLESKIP 506 } 507 } 508 509 alpha = surf_src->map.info.a; 510 // if left or right edge clipping needed, call clip blit 511 if (srcrect->x || srcrect->w != surf_src->w) { 512 RLEClipBlit(w, srcbuf, surf_dst, dstbuf, srcrect, alpha); 513 } else { 514 const SDL_PixelFormatDetails *fmt = surf_src->fmt; 515 516#define RLEBLIT(bpp, Type, do_blit) \ 517 do { \ 518 int linecount = srcrect->h; \ 519 int ofs = 0; \ 520 for (;;) { \ 521 unsigned run; \ 522 ofs += *(Type *)srcbuf; \ 523 run = ((Type *)srcbuf)[1]; \ 524 srcbuf += 2 * sizeof(Type); \ 525 if (run) { \ 526 do_blit(dstbuf + ofs * bpp, srcbuf, run, bpp, alpha); \ 527 srcbuf += run * bpp; \ 528 ofs += run; \ 529 } else if (!ofs) \ 530 break; \ 531 if (ofs == w) { \ 532 ofs = 0; \ 533 dstbuf += surf_dst->pitch; \ 534 if (!--linecount) \ 535 break; \ 536 } \ 537 } \ 538 } while (0) 539 540 CHOOSE_BLIT(RLEBLIT, alpha, fmt); 541 542#undef RLEBLIT 543 } 544 545done: 546 // Unlock the destination if necessary 547 if (SDL_MUSTLOCK(surf_dst)) { 548 SDL_UnlockSurface(surf_dst); 549 } 550 return true; 551} 552 553#undef OPAQUE_BLIT 554 555/* 556 * Per-pixel blitting macros for translucent pixels: 557 * These use the same techniques as the per-surface blitting macros 558 */ 559 560/* 561 * For 32bpp pixels, we have made sure the alpha is stored in the top 562 * 8 bits, so proceed as usual 563 */ 564#define BLIT_TRANSL_888(src, dst) \ 565 do { \ 566 Uint32 s = src; \ 567 Uint32 d = dst; \ 568 unsigned alpha = s >> 24; \ 569 Uint32 s1 = s & 0xff00ff; \ 570 Uint32 d1 = d & 0xff00ff; \ 571 d1 = (d1 + ((s1 - d1) * alpha >> 8)) & 0xff00ff; \ 572 s &= 0xff00; \ 573 d &= 0xff00; \ 574 d = (d + ((s - d) * alpha >> 8)) & 0xff00; \ 575 dst = d1 | d | 0xff000000; \ 576 } while (0) 577 578/* 579 * For 16bpp pixels, we have stored the 5 most significant alpha bits in 580 * bits 5-10. As before, we can process all 3 RGB components at the same time. 581 */ 582#define BLIT_TRANSL_565(src, dst) \ 583 do { \ 584 Uint32 s = src; \ 585 Uint32 d = dst; \ 586 unsigned alpha = (s & 0x3e0) >> 5; \ 587 s &= 0x07e0f81f; \ 588 d = (d | d << 16) & 0x07e0f81f; \ 589 d += (s - d) * alpha >> 5; \ 590 d &= 0x07e0f81f; \ 591 dst = (Uint16)(d | d >> 16); \ 592 } while (0) 593 594#define BLIT_TRANSL_555(src, dst) \ 595 do { \ 596 Uint32 s = src; \ 597 Uint32 d = dst; \ 598 unsigned alpha = (s & 0x3e0) >> 5; \ 599 s &= 0x03e07c1f; \ 600 d = (d | d << 16) & 0x03e07c1f; \ 601 d += (s - d) * alpha >> 5; \ 602 d &= 0x03e07c1f; \ 603 dst = (Uint16)(d | d >> 16); \ 604 } while (0) 605 606// blit a pixel-alpha RLE surface clipped at the right and/or left edges 607static void RLEAlphaClipBlit(int w, Uint8 *srcbuf, SDL_Surface *surf_dst, 608 Uint8 *dstbuf, const SDL_Rect *srcrect) 609{ 610 const SDL_PixelFormatDetails *df = surf_dst->fmt; 611 /* 612 * clipped blitter: Ptype is the destination pixel type, 613 * Ctype the translucent count type, and do_blend the macro 614 * to blend one pixel. 615 */ 616#define RLEALPHACLIPBLIT(Ptype, Ctype, do_blend) \ 617 do { \ 618 int linecount = srcrect->h; \ 619 int left = srcrect->x; \ 620 int right = left + srcrect->w; \ 621 dstbuf -= left * sizeof(Ptype); \ 622 do { \ 623 int ofs = 0; \ 624 /* blit opaque pixels on one line */ \ 625 do { \ 626 unsigned run; \ 627 ofs += ((Ctype *)srcbuf)[0]; \ 628 run = ((Ctype *)srcbuf)[1]; \ 629 srcbuf += 2 * sizeof(Ctype); \ 630 if (run) { \ 631 /* clip to left and right borders */ \ 632 int cofs = ofs; \ 633 int crun = run; \ 634 if (left - cofs > 0) { \ 635 crun -= left - cofs; \ 636 cofs = left; \ 637 } \ 638 if (crun > right - cofs) \ 639 crun = right - cofs; \ 640 if (crun > 0) \ 641 PIXEL_COPY(dstbuf + cofs * sizeof(Ptype), \ 642 srcbuf + (cofs - ofs) * sizeof(Ptype), \ 643 (unsigned)crun, sizeof(Ptype)); \ 644 srcbuf += run * sizeof(Ptype); \ 645 ofs += run; \ 646 } else if (!ofs) \ 647 return; \ 648 } while (ofs < w); \ 649 /* skip padding if necessary */ \ 650 const size_t psize = sizeof(Ptype); \ 651 if (psize == 2) \ 652 srcbuf += (uintptr_t)srcbuf & 2; \ 653 /* blit translucent pixels on the same line */ \ 654 ofs = 0; \ 655 do { \ 656 unsigned run; \ 657 ofs += ((Uint16 *)srcbuf)[0]; \ 658 run = ((Uint16 *)srcbuf)[1]; \ 659 srcbuf += 4; \ 660 if (run) { \ 661 /* clip to left and right borders */ \ 662 int cofs = ofs; \ 663 int crun = run; \ 664 if (left - cofs > 0) { \ 665 crun -= left - cofs; \ 666 cofs = left; \ 667 } \ 668 if (crun > right - cofs) \ 669 crun = right - cofs; \ 670 if (crun > 0) { \ 671 Ptype *dst = (Ptype *)dstbuf + cofs; \ 672 Uint32 *src = (Uint32 *)srcbuf + (cofs - ofs); \ 673 int i; \ 674 for (i = 0; i < crun; i++) \ 675 do_blend(src[i], dst[i]); \ 676 } \ 677 srcbuf += run * 4; \ 678 ofs += run; \ 679 } \ 680 } while (ofs < w); \ 681 dstbuf += surf_dst->pitch; \ 682 } while (--linecount); \ 683 } while (0) 684 685 switch (df->bytes_per_pixel) { 686 case 2: 687 if (df->Gmask == 0x07e0 || df->Rmask == 0x07e0 || df->Bmask == 0x07e0) { 688 RLEALPHACLIPBLIT(Uint16, Uint8, BLIT_TRANSL_565); 689 } else { 690 RLEALPHACLIPBLIT(Uint16, Uint8, BLIT_TRANSL_555); 691 } 692 break; 693 case 4: 694 RLEALPHACLIPBLIT(Uint32, Uint16, BLIT_TRANSL_888); 695 break; 696 } 697} 698 699// blit a pixel-alpha RLE surface 700static bool SDLCALL SDL_RLEAlphaBlit(SDL_Surface *surf_src, const SDL_Rect *srcrect, 701 SDL_Surface *surf_dst, const SDL_Rect *dstrect) 702{ 703 int x, y; 704 int w = surf_src->w; 705 Uint8 *srcbuf, *dstbuf; 706 const SDL_PixelFormatDetails *df = surf_dst->fmt; 707 708 // Lock the destination if necessary 709 if (SDL_MUSTLOCK(surf_dst)) { 710 if (!SDL_LockSurface(surf_dst)) { 711 return false; 712 } 713 } 714 715 x = dstrect->x; 716 y = dstrect->y; 717 dstbuf = (Uint8 *)surf_dst->pixels + y * surf_dst->pitch + x * df->bytes_per_pixel; 718 srcbuf = (Uint8 *)surf_src->map.data + sizeof(SDL_PixelFormat); 719 720 { 721 // skip lines at the top if necessary 722 int vskip = srcrect->y; 723 if (vskip) { 724 int ofs; 725 if (df->bytes_per_pixel == 2) { 726 // the 16/32 interleaved format 727 do { 728 // skip opaque line 729 ofs = 0; 730 do { 731 int run; 732 ofs += srcbuf[0]; 733 run = srcbuf[1]; 734 srcbuf += 2; 735 if (run) { 736 srcbuf += 2 * run; 737 ofs += run; 738 } else if (ofs == 0) { 739 goto done; 740 } 741 } while (ofs < w); 742 743 // skip padding 744 srcbuf += (uintptr_t)srcbuf & 2; 745 746 // skip translucent line 747 ofs = 0; 748 do { 749 int run; 750 ofs += ((Uint16 *)srcbuf)[0]; 751 run = ((Uint16 *)srcbuf)[1]; 752 srcbuf += 4 * (run + 1); 753 ofs += run; 754 } while (ofs < w); 755 } while (--vskip); 756 } else { 757 // the 32/32 interleaved format 758 vskip <<= 1; // opaque and translucent have same format 759 do { 760 ofs = 0; 761 do { 762 int run; 763 ofs += ((Uint16 *)srcbuf)[0]; 764 run = ((Uint16 *)srcbuf)[1]; 765 srcbuf += 4; 766 if (run) { 767 srcbuf += 4 * run; 768 ofs += run; 769 } else if (ofs == 0) { 770 goto done; 771 } 772 } while (ofs < w); 773 } while (--vskip); 774 } 775 } 776 } 777 778 // if left or right edge clipping needed, call clip blit 779 if (srcrect->x || srcrect->w != surf_src->w) { 780 RLEAlphaClipBlit(w, srcbuf, surf_dst, dstbuf, srcrect); 781 } else { 782 783 /* 784 * non-clipped blitter. Ptype is the destination pixel type, 785 * Ctype the translucent count type, and do_blend the 786 * macro to blend one pixel. 787 */ 788#define RLEALPHABLIT(Ptype, Ctype, do_blend) \ 789 do { \ 790 int linecount = srcrect->h; \ 791 do { \ 792 int ofs = 0; \ 793 /* blit opaque pixels on one line */ \ 794 do { \ 795 unsigned run; \ 796 ofs += ((Ctype *)srcbuf)[0]; \ 797 run = ((Ctype *)srcbuf)[1]; \ 798 srcbuf += 2 * sizeof(Ctype); \ 799 if (run) { \ 800 PIXEL_COPY(dstbuf + ofs * sizeof(Ptype), srcbuf, \ 801 run, sizeof(Ptype)); \ 802 srcbuf += run * sizeof(Ptype); \ 803 ofs += run; \ 804 } else if (!ofs) \ 805 goto done; \ 806 } while (ofs < w); \ 807 /* skip padding if necessary */ \ 808 const size_t psize = sizeof(Ptype); \ 809 if (psize == 2) \ 810 srcbuf += (uintptr_t)srcbuf & 2; \ 811 /* blit translucent pixels on the same line */ \ 812 ofs = 0; \ 813 do { \ 814 unsigned run; \ 815 ofs += ((Uint16 *)srcbuf)[0]; \ 816 run = ((Uint16 *)srcbuf)[1]; \ 817 srcbuf += 4; \ 818 if (run) { \ 819 Ptype *dst = (Ptype *)dstbuf + ofs; \ 820 unsigned i; \ 821 for (i = 0; i < run; i++) { \ 822 Uint32 src = *(Uint32 *)srcbuf; \ 823 do_blend(src, *dst); \ 824 srcbuf += 4; \ 825 dst++; \ 826 } \ 827 ofs += run; \ 828 } \ 829 } while (ofs < w); \ 830 dstbuf += surf_dst->pitch; \ 831 } while (--linecount); \ 832 } while (0) 833 834 switch (df->bytes_per_pixel) { 835 case 2: 836 if (df->Gmask == 0x07e0 || df->Rmask == 0x07e0 || df->Bmask == 0x07e0) { 837 RLEALPHABLIT(Uint16, Uint8, BLIT_TRANSL_565); 838 } else { 839 RLEALPHABLIT(Uint16, Uint8, BLIT_TRANSL_555); 840 } 841 break; 842 case 4: 843 RLEALPHABLIT(Uint32, Uint16, BLIT_TRANSL_888); 844 break; 845 } 846 } 847 848done: 849 // Unlock the destination if necessary 850 if (SDL_MUSTLOCK(surf_dst)) { 851 SDL_UnlockSurface(surf_dst); 852 } 853 return true; 854} 855 856/* 857 * Auxiliary functions: 858 * The encoding functions take 32bpp rgb + a, and 859 * return the number of bytes copied to the destination. 860 * The decoding functions copy to 32bpp rgb + a, and 861 * return the number of bytes copied from the source. 862 * These are only used in the encoder and un-RLE code and are therefore not 863 * highly optimised. 864 */ 865 866// encode 32bpp rgb + a into 16bpp rgb, losing alpha 867static int copy_opaque_16(void *dst, const Uint32 *src, int n, 868 const SDL_PixelFormatDetails *sfmt, const SDL_PixelFormatDetails *dfmt) 869{ 870 int i; 871 Uint16 *d = (Uint16 *)dst; 872 for (i = 0; i < n; i++) { 873 unsigned r, g, b; 874 RGB_FROM_PIXEL(*src, sfmt, r, g, b); 875 PIXEL_FROM_RGB(*d, dfmt, r, g, b); 876 src++; 877 d++; 878 } 879 return n * 2; 880} 881 882// encode 32bpp rgb + a into 32bpp G0RAB format for blitting into 565 883static int copy_transl_565(void *dst, const Uint32 *src, int n, 884 const SDL_PixelFormatDetails *sfmt, const SDL_PixelFormatDetails *dfmt) 885{ 886 int i; 887 Uint32 *d = (Uint32 *)dst; 888 for (i = 0; i < n; i++) { 889 unsigned r, g, b, a; 890 Uint16 pix; 891 RGBA_FROM_8888(*src, sfmt, r, g, b, a); 892 PIXEL_FROM_RGB(pix, dfmt, r, g, b); 893 *d = ((pix & 0x7e0) << 16) | (pix & 0xf81f) | ((a << 2) & 0x7e0); 894 src++; 895 d++; 896 } 897 return n * 4; 898} 899 900// encode 32bpp rgb + a into 32bpp G0RAB format for blitting into 555 901static int copy_transl_555(void *dst, const Uint32 *src, int n, 902 const SDL_PixelFormatDetails *sfmt, const SDL_PixelFormatDetails *dfmt) 903{ 904 int i; 905 Uint32 *d = (Uint32 *)dst; 906 for (i = 0; i < n; i++) { 907 unsigned r, g, b, a; 908 Uint16 pix; 909 RGBA_FROM_8888(*src, sfmt, r, g, b, a); 910 PIXEL_FROM_RGB(pix, dfmt, r, g, b); 911 *d = ((pix & 0x3e0) << 16) | (pix & 0xfc1f) | ((a << 2) & 0x3e0); 912 src++; 913 d++; 914 } 915 return n * 4; 916} 917 918// encode 32bpp rgba into 32bpp rgba, keeping alpha (dual purpose) 919static int copy_32(void *dst, const Uint32 *src, int n, 920 const SDL_PixelFormatDetails *sfmt, const SDL_PixelFormatDetails *dfmt) 921{ 922 int i; 923 Uint32 *d = (Uint32 *)dst; 924 for (i = 0; i < n; i++) { 925 unsigned r, g, b, a; 926 RGBA_FROM_8888(*src, sfmt, r, g, b, a); 927 RLEPIXEL_FROM_RGBA(*d, dfmt, r, g, b, a); 928 d++; 929 src++; 930 } 931 return n * 4; 932} 933 934#define ISOPAQUE(pixel, fmt) ((((pixel)&fmt->Amask) >> fmt->Ashift) == 255) 935 936#define ISTRANSL(pixel, fmt) \ 937 ((unsigned)((((pixel)&fmt->Amask) >> fmt->Ashift) - 1U) < 254U) 938 939// convert surface to be quickly alpha-blittable onto dest, if possible 940static bool RLEAlphaSurface(SDL_Surface *surface) 941{ 942 SDL_Surface *dest; 943 const SDL_PixelFormatDetails *df; 944 int maxsize = 0; 945 int max_opaque_run; 946 int max_transl_run = 65535; 947 unsigned masksum; 948 Uint8 *rlebuf, *dst; 949 int (*copy_opaque)(void *, const Uint32 *, int, 950 const SDL_PixelFormatDetails *, const SDL_PixelFormatDetails *); 951 int (*copy_transl)(void *, const Uint32 *, int, 952 const SDL_PixelFormatDetails *, const SDL_PixelFormatDetails *); 953 954 dest = surface->map.info.dst_surface; 955 if (!dest) { 956 return false; 957 } 958 df = dest->fmt; 959 if (surface->fmt->bits_per_pixel != 32) { 960 return false; // only 32bpp source supported 961 } 962 963 /* find out whether the destination is one we support, 964 and determine the max size of the encoded result */ 965 masksum = df->Rmask | df->Gmask | df->Bmask; 966 switch (df->bytes_per_pixel) { 967 case 2: 968 // 16bpp: only support 565 and 555 formats 969 switch (masksum) { 970 case 0xffff: 971 if (df->Gmask == 0x07e0 || df->Rmask == 0x07e0 || df->Bmask == 0x07e0) { 972 copy_opaque = copy_opaque_16; 973 copy_transl = copy_transl_565; 974 } else { 975 return false; 976 } 977 break; 978 case 0x7fff: 979 if (df->Gmask == 0x03e0 || df->Rmask == 0x03e0 || df->Bmask == 0x03e0) { 980 copy_opaque = copy_opaque_16; 981 copy_transl = copy_transl_555; 982 } else { 983 return false; 984 } 985 break; 986 default: 987 return false; 988 } 989 max_opaque_run = 255; // runs stored as bytes 990 991 /* worst case is alternating opaque and translucent pixels, 992 with room for alignment padding between lines */ 993 maxsize = surface->h * (2 + (4 + 2) * (surface->w + 1)) + 2; 994 break; 995 case 4: 996 if (masksum != 0x00ffffff) { 997 return false; // requires unused high byte 998 } 999 copy_opaque = copy_32; 1000 copy_transl = copy_32; 1001 max_opaque_run = 255; // runs stored as short ints 1002 1003 // worst case is alternating opaque and translucent pixels 1004 maxsize = surface->h * 2 * 4 * (surface->w + 1) + 4; 1005 break; 1006 default: 1007 return false; // anything else unsupported right now 1008 } 1009 1010 maxsize += sizeof(SDL_PixelFormat); 1011 rlebuf = (Uint8 *)SDL_malloc(maxsize); 1012 if (!rlebuf) { 1013 return false; 1014 } 1015 // save the destination format so we can undo the encoding later 1016 *(SDL_PixelFormat *)rlebuf = dest->format; 1017 dst = rlebuf + sizeof(SDL_PixelFormat); 1018 1019 // Do the actual encoding 1020 { 1021 int x, y; 1022 int h = surface->h, w = surface->w; 1023 const SDL_PixelFormatDetails *sf = surface->fmt; 1024 Uint32 *src = (Uint32 *)surface->pixels; 1025 Uint8 *lastline = dst; // end of last non-blank line 1026 1027 // opaque counts are 8 or 16 bits, depending on target depth 1028#define ADD_OPAQUE_COUNTS(n, m) \ 1029 if (df->bytes_per_pixel == 4) { \ 1030 ((Uint16 *)dst)[0] = (Uint16)n; \ 1031 ((Uint16 *)dst)[1] = (Uint16)m; \ 1032 dst += 4; \ 1033 } else { \ 1034 dst[0] = (Uint8)n; \ 1035 dst[1] = (Uint8)m; \ 1036 dst += 2; \ 1037 } 1038 1039 // translucent counts are always 16 bit 1040#define ADD_TRANSL_COUNTS(n, m) \ 1041 (((Uint16 *)dst)[0] = (Uint16)n, ((Uint16 *)dst)[1] = (Uint16)m, dst += 4) 1042 1043 for (y = 0; y < h; y++) { 1044 int runstart, skipstart; 1045 int blankline = 0; 1046 // First encode all opaque pixels of a scan line 1047 x = 0; 1048 do { 1049 int run, skip, len; 1050 skipstart = x; 1051 while (x < w && !ISOPAQUE(src[x], sf)) { 1052 x++; 1053 } 1054 runstart = x; 1055 while (x < w && ISOPAQUE(src[x], sf)) { 1056 x++; 1057 } 1058 skip = runstart - skipstart; 1059 if (skip == w) { 1060 blankline = 1; 1061 } 1062 run = x - runstart; 1063 while (skip > max_opaque_run) { 1064 ADD_OPAQUE_COUNTS(max_opaque_run, 0); 1065 skip -= max_opaque_run; 1066 } 1067 len = SDL_min(run, max_opaque_run); 1068 ADD_OPAQUE_COUNTS(skip, len); 1069 dst += copy_opaque(dst, src + runstart, len, sf, df); 1070 runstart += len; 1071 run -= len; 1072 while (run) { 1073 len = SDL_min(run, max_opaque_run); 1074 ADD_OPAQUE_COUNTS(0, len); 1075 dst += copy_opaque(dst, src + runstart, len, sf, df); 1076 runstart += len; 1077 run -= len; 1078 } 1079 } while (x < w); 1080 1081 // Make sure the next output address is 32-bit aligned 1082 dst += (uintptr_t)dst & 2; 1083 1084 // Next, encode all translucent pixels of the same scan line 1085 x = 0; 1086 do { 1087 int run, skip, len; 1088 skipstart = x; 1089 while (x < w && !ISTRANSL(src[x], sf)) { 1090 x++; 1091 } 1092 runstart = x; 1093 while (x < w && ISTRANSL(src[x], sf)) { 1094 x++; 1095 } 1096 skip = runstart - skipstart; 1097 blankline &= (skip == w); 1098 run = x - runstart; 1099 while (skip > max_transl_run) { 1100 ADD_TRANSL_COUNTS(max_transl_run, 0); 1101 skip -= max_transl_run; 1102 } 1103 len = SDL_min(run, max_transl_run); 1104 ADD_TRANSL_COUNTS(skip, len); 1105 dst += copy_transl(dst, src + runstart, len, sf, df); 1106 runstart += len; 1107 run -= len; 1108 while (run) { 1109 len = SDL_min(run, max_transl_run); 1110 ADD_TRANSL_COUNTS(0, len); 1111 dst += copy_transl(dst, src + runstart, len, sf, df); 1112 runstart += len; 1113 run -= len; 1114 } 1115 if (!blankline) { 1116 lastline = dst; 1117 } 1118 } while (x < w); 1119 1120 src += surface->pitch >> 2; 1121 } 1122 dst = lastline; // back up past trailing blank lines 1123 ADD_OPAQUE_COUNTS(0, 0); 1124 } 1125 1126#undef ADD_OPAQUE_COUNTS 1127#undef ADD_TRANSL_COUNTS 1128 1129 // reallocate the buffer to release unused memory 1130 { 1131 Uint8 *p = (Uint8 *)SDL_realloc(rlebuf, dst - rlebuf); 1132 if (!p) { 1133 p = rlebuf; 1134 } 1135 surface->map.data = p; 1136 } 1137 1138 return true; 1139} 1140 1141static Uint32 getpix_8(const Uint8 *srcbuf) 1142{ 1143 return *srcbuf; 1144} 1145 1146static Uint32 getpix_16(const Uint8 *srcbuf) 1147{ 1148 return *(const Uint16 *)srcbuf; 1149} 1150 1151static Uint32 getpix_24(const Uint8 *srcbuf) 1152{ 1153#if SDL_BYTEORDER == SDL_LIL_ENDIAN 1154 return srcbuf[0] + (srcbuf[1] << 8) + (srcbuf[2] << 16); 1155#else 1156 return (srcbuf[0] << 16) + (srcbuf[1] << 8) + srcbuf[2]; 1157#endif 1158} 1159 1160static Uint32 getpix_32(const Uint8 *srcbuf) 1161{ 1162 return *(const Uint32 *)srcbuf; 1163} 1164 1165typedef Uint32 (*getpix_func)(const Uint8 *); 1166 1167static const getpix_func getpixes[4] = { 1168 getpix_8, getpix_16, getpix_24, getpix_32 1169}; 1170 1171static bool RLEColorkeySurface(SDL_Surface *surface) 1172{ 1173 SDL_Surface *dest; 1174 Uint8 *rlebuf, *dst; 1175 int maxn; 1176 int y; 1177 Uint8 *srcbuf, *lastline; 1178 int maxsize = 0; 1179 const int bpp = surface->fmt->bytes_per_pixel; 1180 getpix_func getpix; 1181 Uint32 ckey, rgbmask; 1182 int w, h; 1183 1184 dest = surface->map.info.dst_surface; 1185 if (!dest) { 1186 return false; 1187 } 1188 1189 // calculate the worst case size for the compressed surface 1190 switch (bpp) { 1191 case 1: 1192 /* worst case is alternating opaque and transparent pixels, 1193 starting with an opaque pixel */ 1194 maxsize = surface->h * 3 * (surface->w / 2 + 1) + 2; 1195 break; 1196 case 2: 1197 case 3: 1198 // worst case is solid runs, at most 255 pixels wide 1199 maxsize = surface->h * (2 * (surface->w / 255 + 1) + surface->w * bpp) + 2; 1200 break; 1201 case 4: 1202 // worst case is solid runs, at most 65535 pixels wide 1203 maxsize = surface->h * (4 * (surface->w / 65535 + 1) + surface->w * 4) + 4; 1204 break; 1205 1206 default: 1207 return false; 1208 } 1209 1210 maxsize += sizeof(SDL_PixelFormat); 1211 rlebuf = (Uint8 *)SDL_malloc(maxsize); 1212 if (!rlebuf) { 1213 return false; 1214 } 1215 // save the destination format so we can undo the encoding later 1216 *(SDL_PixelFormat *)rlebuf = dest->format; 1217 1218 // Set up the conversion 1219 srcbuf = (Uint8 *)surface->pixels; 1220 maxn = bpp == 4 ? 65535 : 255; 1221 dst = rlebuf + sizeof(SDL_PixelFormat); 1222 rgbmask = ~surface->fmt->Amask; 1223 ckey = surface->map.info.colorkey & rgbmask; 1224 lastline = dst; 1225 getpix = getpixes[bpp - 1]; 1226 w = surface->w; 1227 h = surface->h; 1228 1229#define ADD_COUNTS(n, m) \ 1230 if (bpp == 4) { \ 1231 ((Uint16 *)dst)[0] = (Uint16)n; \ 1232 ((Uint16 *)dst)[1] = (Uint16)m; \ 1233 dst += 4; \ 1234 } else { \ 1235 dst[0] = (Uint8)n; \ 1236 dst[1] = (Uint8)m; \ 1237 dst += 2; \ 1238 } 1239 1240 for (y = 0; y < h; y++) { 1241 int x = 0; 1242 int blankline = 0; 1243 do { 1244 int run, skip; 1245 int len; 1246 int runstart; 1247 int skipstart = x; 1248 1249 // find run of transparent, then opaque pixels 1250 while (x < w && (getpix(srcbuf + x * bpp) & rgbmask) == ckey) { 1251 x++; 1252 } 1253 runstart = x; 1254 while (x < w && (getpix(srcbuf + x * bpp) & rgbmask) != ckey) { 1255 x++; 1256 } 1257 skip = runstart - skipstart; 1258 if (skip == w) { 1259 blankline = 1; 1260 } 1261 run = x - runstart; 1262 1263 // encode segment 1264 while (skip > maxn) { 1265 ADD_COUNTS(maxn, 0); 1266 skip -= maxn; 1267 } 1268 len = SDL_min(run, maxn); 1269 ADD_COUNTS(skip, len); 1270 SDL_memcpy(dst, srcbuf + runstart * bpp, (size_t)len * bpp); 1271 dst += len * bpp; 1272 run -= len; 1273 runstart += len; 1274 while (run) { 1275 len = SDL_min(run, maxn); 1276 ADD_COUNTS(0, len); 1277 SDL_memcpy(dst, srcbuf + runstart * bpp, (size_t)len * bpp); 1278 dst += len * bpp; 1279 runstart += len; 1280 run -= len; 1281 } 1282 if (!blankline) { 1283 lastline = dst; 1284 } 1285 } while (x < w); 1286 1287 srcbuf += surface->pitch; 1288 } 1289 dst = lastline; // back up bast trailing blank lines 1290 ADD_COUNTS(0, 0); 1291 1292#undef ADD_COUNTS 1293 1294 // reallocate the buffer to release unused memory 1295 { 1296 // If SDL_realloc returns NULL, the original block is left intact 1297 Uint8 *p = (Uint8 *)SDL_realloc(rlebuf, dst - rlebuf); 1298 if (!p) { 1299 p = rlebuf; 1300 } 1301 surface->map.data = p; 1302 } 1303 1304 return true; 1305} 1306 1307bool SDL_RLESurface(SDL_Surface *surface) 1308{ 1309 int flags; 1310 1311 // Clear any previous RLE conversion 1312 if (surface->internal_flags & SDL_INTERNAL_SURFACE_RLEACCEL) { 1313 SDL_UnRLESurface(surface); 1314 } 1315 1316 // We don't support RLE encoding of bitmaps 1317 if (SDL_BITSPERPIXEL(surface->format) < 8) { 1318 return false; 1319 } 1320 1321 // Make sure the pixels are available 1322 if (!surface->pixels) { 1323 return false; 1324 } 1325 1326 flags = surface->map.info.flags; 1327 if (flags & SDL_COPY_COLORKEY) { 1328 // ok 1329 } else if ((flags & SDL_COPY_BLEND) && SDL_ISPIXELFORMAT_ALPHA(surface->format)) { 1330 // ok 1331 } else { 1332 // If we don't have colorkey or blending, nothing to do... 1333 return false; 1334 } 1335 1336 // Pass on combinations not supported 1337 if ((flags & SDL_COPY_MODULATE_COLOR) || 1338 ((flags & SDL_COPY_MODULATE_ALPHA) && SDL_ISPIXELFORMAT_ALPHA(surface->format)) || 1339 (flags & (SDL_COPY_BLEND_PREMULTIPLIED | SDL_COPY_ADD | SDL_COPY_ADD_PREMULTIPLIED | SDL_COPY_MOD | SDL_COPY_MUL)) || 1340 (flags & SDL_COPY_NEAREST)) { 1341 return false; 1342 } 1343 1344 // Encode and set up the blit 1345 if (!SDL_ISPIXELFORMAT_ALPHA(surface->format) || !(flags & SDL_COPY_BLEND)) { 1346 if (!surface->map.identity) { 1347 return false; 1348 } 1349 if (!RLEColorkeySurface(surface)) { 1350 return false; 1351 } 1352 surface->map.blit = SDL_RLEBlit; 1353 surface->map.info.flags |= SDL_COPY_RLE_COLORKEY; 1354 } else { 1355 if (!RLEAlphaSurface(surface)) { 1356 return false; 1357 } 1358 surface->map.blit = SDL_RLEAlphaBlit; 1359 surface->map.info.flags |= SDL_COPY_RLE_ALPHAKEY; 1360 } 1361 1362 if (!(surface->flags & SDL_SURFACE_PREALLOCATED)) { 1363 surface->saved_pixels = surface->pixels; 1364 surface->pixels = NULL; 1365 } 1366 1367 // The surface is now accelerated 1368 surface->internal_flags |= SDL_INTERNAL_SURFACE_RLEACCEL; 1369 SDL_UpdateSurfaceLockFlag(surface); 1370 1371 return true; 1372} 1373 1374void SDL_UnRLESurface(SDL_Surface *surface) 1375{ 1376 if (surface->internal_flags & SDL_INTERNAL_SURFACE_RLEACCEL) { 1377 surface->internal_flags &= ~SDL_INTERNAL_SURFACE_RLEACCEL; 1378 1379 surface->map.info.flags &= ~(SDL_COPY_RLE_COLORKEY | SDL_COPY_RLE_ALPHAKEY); 1380 1381 if (!(surface->flags & SDL_SURFACE_PREALLOCATED)) { 1382 surface->pixels = surface->saved_pixels; 1383 surface->saved_pixels = NULL; 1384 } 1385 1386 SDL_free(surface->map.data); 1387 surface->map.data = NULL; 1388 1389 SDL_InvalidateMap(&surface->map); 1390 1391 SDL_UpdateSurfaceLockFlag(surface); 1392 } 1393} 1394 1395#endif // SDL_HAVE_RLE 1396[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.