2 SDL - Simple DirectMedia Layer
3 Copyright (C) 1997, 1998, 1999, 2000, 2001, 2002 Sam Lantinga
5 This library is free software; you can redistribute it and/or
6 modify it under the terms of the GNU Library General Public
7 License as published by the Free Software Foundation; either
8 version 2 of the License, or (at your option) any later version.
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 Library General Public License for more details.
15 You should have received a copy of the GNU Library General Public
16 License along with this library; if not, write to the Free
17 Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
30 #include "SDL_types.h"
31 #include "SDL_video.h"
34 /* Functions to perform alpha blended blitting */
36 /* N->1 blending with per-surface alpha */
37 static void BlitNto1SurfaceAlpha(SDL_BlitInfo
*info
)
39 int width
= info
->d_width
;
40 int height
= info
->d_height
;
41 Uint8
*src
= info
->s_pixels
;
42 int srcskip
= info
->s_skip
;
43 Uint8
*dst
= info
->d_pixels
;
44 int dstskip
= info
->d_skip
;
45 Uint8
*palmap
= info
->table
;
46 SDL_PixelFormat
*srcfmt
= info
->src
;
47 SDL_PixelFormat
*dstfmt
= info
->dst
;
48 int srcbpp
= srcfmt
->BytesPerPixel
;
50 const unsigned A
= srcfmt
->alpha
;
62 DISEMBLE_RGB(src
, srcbpp
, srcfmt
, pixel
, sR
, sG
, sB
);
63 dR
= dstfmt
->palette
->colors
[*dst
].r
;
64 dG
= dstfmt
->palette
->colors
[*dst
].g
;
65 dB
= dstfmt
->palette
->colors
[*dst
].b
;
66 ALPHA_BLEND(sR
, sG
, sB
, A
, dR
, dG
, dB
);
70 /* Pack RGB into 8bit pixel */
71 if ( palmap
== NULL
) {
72 *dst
=((dR
>>5)<<(3+2))|
76 *dst
= palmap
[((dR
>>5)<<(3+2))|
89 /* N->1 blending with pixel alpha */
90 static void BlitNto1PixelAlpha(SDL_BlitInfo
*info
)
92 int width
= info
->d_width
;
93 int height
= info
->d_height
;
94 Uint8
*src
= info
->s_pixels
;
95 int srcskip
= info
->s_skip
;
96 Uint8
*dst
= info
->d_pixels
;
97 int dstskip
= info
->d_skip
;
98 Uint8
*palmap
= info
->table
;
99 SDL_PixelFormat
*srcfmt
= info
->src
;
100 SDL_PixelFormat
*dstfmt
= info
->dst
;
101 int srcbpp
= srcfmt
->BytesPerPixel
;
103 /* FIXME: fix alpha bit field expansion here too? */
115 DISEMBLE_RGBA(src
,srcbpp
,srcfmt
,pixel
,sR
,sG
,sB
,sA
);
116 dR
= dstfmt
->palette
->colors
[*dst
].r
;
117 dG
= dstfmt
->palette
->colors
[*dst
].g
;
118 dB
= dstfmt
->palette
->colors
[*dst
].b
;
119 ALPHA_BLEND(sR
, sG
, sB
, sA
, dR
, dG
, dB
);
123 /* Pack RGB into 8bit pixel */
124 if ( palmap
== NULL
) {
125 *dst
=((dR
>>5)<<(3+2))|
129 *dst
= palmap
[((dR
>>5)<<(3+2))|
142 /* colorkeyed N->1 blending with per-surface alpha */
143 static void BlitNto1SurfaceAlphaKey(SDL_BlitInfo
*info
)
145 int width
= info
->d_width
;
146 int height
= info
->d_height
;
147 Uint8
*src
= info
->s_pixels
;
148 int srcskip
= info
->s_skip
;
149 Uint8
*dst
= info
->d_pixels
;
150 int dstskip
= info
->d_skip
;
151 Uint8
*palmap
= info
->table
;
152 SDL_PixelFormat
*srcfmt
= info
->src
;
153 SDL_PixelFormat
*dstfmt
= info
->dst
;
154 int srcbpp
= srcfmt
->BytesPerPixel
;
155 Uint32 ckey
= srcfmt
->colorkey
;
157 const int A
= srcfmt
->alpha
;
169 DISEMBLE_RGB(src
, srcbpp
, srcfmt
, pixel
, sR
, sG
, sB
);
170 if ( pixel
!= ckey
) {
171 dR
= dstfmt
->palette
->colors
[*dst
].r
;
172 dG
= dstfmt
->palette
->colors
[*dst
].g
;
173 dB
= dstfmt
->palette
->colors
[*dst
].b
;
174 ALPHA_BLEND(sR
, sG
, sB
, A
, dR
, dG
, dB
);
178 /* Pack RGB into 8bit pixel */
179 if ( palmap
== NULL
) {
180 *dst
=((dR
>>5)<<(3+2))|
184 *dst
= palmap
[((dR
>>5)<<(3+2))|
198 /* fast RGB888->(A)RGB888 blending with surface alpha=128 special case */
199 static void BlitRGBtoRGBSurfaceAlpha128(SDL_BlitInfo
*info
)
201 int width
= info
->d_width
;
202 int height
= info
->d_height
;
203 Uint32
*srcp
= (Uint32
*)info
->s_pixels
;
204 int srcskip
= info
->s_skip
>> 2;
205 Uint32
*dstp
= (Uint32
*)info
->d_pixels
;
206 int dstskip
= info
->d_skip
>> 2;
212 *dstp
++ = ((((s
& 0x00fefefe) + (d
& 0x00fefefe)) >> 1)
213 + (s
& d
& 0x00010101)) | 0xff000000;
220 /* fast RGB888->(A)RGB888 blending with surface alpha */
221 static void BlitRGBtoRGBSurfaceAlpha(SDL_BlitInfo
*info
)
223 unsigned alpha
= info
->src
->alpha
;
225 BlitRGBtoRGBSurfaceAlpha128(info
);
227 int width
= info
->d_width
;
228 int height
= info
->d_height
;
229 Uint32
*srcp
= (Uint32
*)info
->s_pixels
;
230 int srcskip
= info
->s_skip
>> 2;
231 Uint32
*dstp
= (Uint32
*)info
->d_pixels
;
232 int dstskip
= info
->d_skip
>> 2;
244 d1
= (d1
+ ((s1
- d1
) * alpha
>> 8))
248 d
= (d
+ ((s
- d
) * alpha
>> 8)) & 0xff00;
249 *dstp
= d1
| d
| 0xff000000;
259 /* fast ARGB888->(A)RGB888 blending with pixel alpha */
260 static void BlitRGBtoRGBPixelAlpha(SDL_BlitInfo
*info
)
262 int width
= info
->d_width
;
263 int height
= info
->d_height
;
264 Uint32
*srcp
= (Uint32
*)info
->s_pixels
;
265 int srcskip
= info
->s_skip
>> 2;
266 Uint32
*dstp
= (Uint32
*)info
->d_pixels
;
267 int dstskip
= info
->d_skip
>> 2;
276 Uint32 alpha
= s
>> 24;
277 /* FIXME: Here we special-case opaque alpha since the
278 compositioning used (>>8 instead of /255) doesn't handle
279 it correctly. Also special-case alpha=0 for speed?
281 if(alpha
== SDL_ALPHA_OPAQUE
) {
282 *dstp
= (s
& 0x00ffffff) | (*dstp
& 0xff000000);
285 * take out the middle component (green), and process
286 * the other two in parallel. One multiply less.
289 dalpha
= d
& 0xff000000;
292 d1
= (d1
+ ((s1
- d1
) * alpha
>> 8)) & 0xff00ff;
295 d
= (d
+ ((s
- d
) * alpha
>> 8)) & 0xff00;
296 *dstp
= d1
| d
| dalpha
;
306 /* 16bpp special case for per-surface alpha=50%: blend 2 pixels in parallel */
308 /* blend a single 16 bit pixel at 50% */
309 #define BLEND16_50(d, s, mask) \
310 ((((s & mask) + (d & mask)) >> 1) + (s & d & (~mask & 0xffff)))
312 /* blend two 16 bit pixels at 50% */
313 #define BLEND2x16_50(d, s, mask) \
314 (((s & (mask | mask << 16)) >> 1) + ((d & (mask | mask << 16)) >> 1) \
315 + (s & d & (~(mask | mask << 16))))
317 static void Blit16to16SurfaceAlpha128(SDL_BlitInfo
*info
, Uint16 mask
)
319 int width
= info
->d_width
;
320 int height
= info
->d_height
;
321 Uint16
*srcp
= (Uint16
*)info
->s_pixels
;
322 int srcskip
= info
->s_skip
>> 1;
323 Uint16
*dstp
= (Uint16
*)info
->d_pixels
;
324 int dstskip
= info
->d_skip
>> 1;
327 if(((unsigned long)srcp
^ (unsigned long)dstp
) & 2) {
329 * Source and destination not aligned, pipeline it.
330 * This is mostly a win for big blits but no loss for
336 /* handle odd destination */
337 if((unsigned long)dstp
& 2) {
338 Uint16 d
= *dstp
, s
= *srcp
;
339 *dstp
= BLEND16_50(d
, s
, mask
);
344 srcp
++; /* srcp is now 32-bit aligned */
346 /* bootstrap pipeline with first halfword */
347 prev_sw
= ((Uint32
*)srcp
)[-1];
351 sw
= *(Uint32
*)srcp
;
352 dw
= *(Uint32
*)dstp
;
353 if(SDL_BYTEORDER
== SDL_BIG_ENDIAN
)
354 s
= (prev_sw
<< 16) + (sw
>> 16);
356 s
= (prev_sw
>> 16) + (sw
<< 16);
358 *(Uint32
*)dstp
= BLEND2x16_50(dw
, s
, mask
);
364 /* final pixel if any */
367 if(SDL_BYTEORDER
== SDL_BIG_ENDIAN
)
371 *dstp
= BLEND16_50(d
, s
, mask
);
378 /* source and destination are aligned */
381 /* first odd pixel? */
382 if((unsigned long)srcp
& 2) {
383 Uint16 d
= *dstp
, s
= *srcp
;
384 *dstp
= BLEND16_50(d
, s
, mask
);
389 /* srcp and dstp are now 32-bit aligned */
392 Uint32 sw
= *(Uint32
*)srcp
;
393 Uint32 dw
= *(Uint32
*)dstp
;
394 *(Uint32
*)dstp
= BLEND2x16_50(dw
, sw
, mask
);
400 /* last odd pixel? */
402 Uint16 d
= *dstp
, s
= *srcp
;
403 *dstp
= BLEND16_50(d
, s
, mask
);
413 /* fast RGB565->RGB565 blending with surface alpha */
414 static void Blit565to565SurfaceAlpha(SDL_BlitInfo
*info
)
416 unsigned alpha
= info
->src
->alpha
;
418 Blit16to16SurfaceAlpha128(info
, 0xf7de);
420 int width
= info
->d_width
;
421 int height
= info
->d_height
;
422 Uint16
*srcp
= (Uint16
*)info
->s_pixels
;
423 int srcskip
= info
->s_skip
>> 1;
424 Uint16
*dstp
= (Uint16
*)info
->d_pixels
;
425 int dstskip
= info
->d_skip
>> 1;
426 alpha
>>= 3; /* downscale alpha to 5 bits */
433 * shift out the middle component (green) to
434 * the high 16 bits, and process all three RGB
435 * components at the same time.
437 s
= (s
| s
<< 16) & 0x07e0f81f;
438 d
= (d
| d
<< 16) & 0x07e0f81f;
439 d
+= (s
- d
) * alpha
>> 5;
441 *dstp
++ = d
| d
>> 16;
449 /* fast RGB555->RGB555 blending with surface alpha */
450 static void Blit555to555SurfaceAlpha(SDL_BlitInfo
*info
)
452 unsigned alpha
= info
->src
->alpha
; /* downscale alpha to 5 bits */
454 Blit16to16SurfaceAlpha128(info
, 0xfbde);
456 int width
= info
->d_width
;
457 int height
= info
->d_height
;
458 Uint16
*srcp
= (Uint16
*)info
->s_pixels
;
459 int srcskip
= info
->s_skip
>> 1;
460 Uint16
*dstp
= (Uint16
*)info
->d_pixels
;
461 int dstskip
= info
->d_skip
>> 1;
462 alpha
>>= 3; /* downscale alpha to 5 bits */
469 * shift out the middle component (green) to
470 * the high 16 bits, and process all three RGB
471 * components at the same time.
473 s
= (s
| s
<< 16) & 0x03e07c1f;
474 d
= (d
| d
<< 16) & 0x03e07c1f;
475 d
+= (s
- d
) * alpha
>> 5;
477 *dstp
++ = d
| d
>> 16;
485 /* fast ARGB8888->RGB565 blending with pixel alpha */
486 static void BlitARGBto565PixelAlpha(SDL_BlitInfo
*info
)
488 int width
= info
->d_width
;
489 int height
= info
->d_height
;
490 Uint32
*srcp
= (Uint32
*)info
->s_pixels
;
491 int srcskip
= info
->s_skip
>> 2;
492 Uint16
*dstp
= (Uint16
*)info
->d_pixels
;
493 int dstskip
= info
->d_skip
>> 1;
498 unsigned alpha
= s
>> 27; /* downscale alpha to 5 bits */
499 /* FIXME: Here we special-case opaque alpha since the
500 compositioning used (>>8 instead of /255) doesn't handle
501 it correctly. Also special-case alpha=0 for speed?
503 if(alpha
== (SDL_ALPHA_OPAQUE
>> 3)) {
504 *dstp
= (s
>> 8 & 0xf800) + (s
>> 5 & 0x7e0)
509 * convert source and destination to G0RAB65565
510 * and blend all components at the same time
512 s
= ((s
& 0xfc00) << 11) + (s
>> 8 & 0xf800)
514 d
= (d
| d
<< 16) & 0x07e0f81f;
515 d
+= (s
- d
) * alpha
>> 5;
527 /* fast ARGB8888->RGB555 blending with pixel alpha */
528 static void BlitARGBto555PixelAlpha(SDL_BlitInfo
*info
)
530 int width
= info
->d_width
;
531 int height
= info
->d_height
;
532 Uint32
*srcp
= (Uint32
*)info
->s_pixels
;
533 int srcskip
= info
->s_skip
>> 2;
534 Uint16
*dstp
= (Uint16
*)info
->d_pixels
;
535 int dstskip
= info
->d_skip
>> 1;
541 alpha
= s
>> 27; /* downscale alpha to 5 bits */
542 /* FIXME: Here we special-case opaque alpha since the
543 compositioning used (>>8 instead of /255) doesn't handle
544 it correctly. Also special-case alpha=0 for speed?
546 if(alpha
== (SDL_ALPHA_OPAQUE
>> 3)) {
547 *dstp
= (s
>> 9 & 0x7c00) + (s
>> 6 & 0x3e0)
552 * convert source and destination to G0RAB65565
553 * and blend all components at the same time
555 s
= ((s
& 0xf800) << 10) + (s
>> 9 & 0x7c00)
557 d
= (d
| d
<< 16) & 0x03e07c1f;
558 d
+= (s
- d
) * alpha
>> 5;
570 /* General (slow) N->N blending with per-surface alpha */
571 static void BlitNtoNSurfaceAlpha(SDL_BlitInfo
*info
)
573 int width
= info
->d_width
;
574 int height
= info
->d_height
;
575 Uint8
*src
= info
->s_pixels
;
576 int srcskip
= info
->s_skip
;
577 Uint8
*dst
= info
->d_pixels
;
578 int dstskip
= info
->d_skip
;
579 SDL_PixelFormat
*srcfmt
= info
->src
;
580 SDL_PixelFormat
*dstfmt
= info
->dst
;
581 int srcbpp
= srcfmt
->BytesPerPixel
;
582 int dstbpp
= dstfmt
->BytesPerPixel
;
583 unsigned sA
= srcfmt
->alpha
;
584 unsigned dA
= dstfmt
->Amask
? SDL_ALPHA_OPAQUE
: 0;
596 DISEMBLE_RGB(src
, srcbpp
, srcfmt
, pixel
, sR
, sG
, sB
);
597 DISEMBLE_RGB(dst
, dstbpp
, dstfmt
, pixel
, dR
, dG
, dB
);
598 ALPHA_BLEND(sR
, sG
, sB
, sA
, dR
, dG
, dB
);
599 ASSEMBLE_RGBA(dst
, dstbpp
, dstfmt
, dR
, dG
, dB
, dA
);
609 /* General (slow) colorkeyed N->N blending with per-surface alpha */
610 static void BlitNtoNSurfaceAlphaKey(SDL_BlitInfo
*info
)
612 int width
= info
->d_width
;
613 int height
= info
->d_height
;
614 Uint8
*src
= info
->s_pixels
;
615 int srcskip
= info
->s_skip
;
616 Uint8
*dst
= info
->d_pixels
;
617 int dstskip
= info
->d_skip
;
618 SDL_PixelFormat
*srcfmt
= info
->src
;
619 SDL_PixelFormat
*dstfmt
= info
->dst
;
620 Uint32 ckey
= srcfmt
->colorkey
;
621 int srcbpp
= srcfmt
->BytesPerPixel
;
622 int dstbpp
= dstfmt
->BytesPerPixel
;
623 unsigned sA
= srcfmt
->alpha
;
624 unsigned dA
= dstfmt
->Amask
? SDL_ALPHA_OPAQUE
: 0;
636 RETRIEVE_RGB_PIXEL(src
, srcbpp
, pixel
);
638 RGB_FROM_PIXEL(pixel
, srcfmt
, sR
, sG
, sB
);
639 DISEMBLE_RGB(dst
, dstbpp
, dstfmt
, pixel
, dR
, dG
, dB
);
640 ALPHA_BLEND(sR
, sG
, sB
, sA
, dR
, dG
, dB
);
641 ASSEMBLE_RGBA(dst
, dstbpp
, dstfmt
, dR
, dG
, dB
, dA
);
652 /* General (slow) N->N blending with pixel alpha */
653 static void BlitNtoNPixelAlpha(SDL_BlitInfo
*info
)
655 int width
= info
->d_width
;
656 int height
= info
->d_height
;
657 Uint8
*src
= info
->s_pixels
;
658 int srcskip
= info
->s_skip
;
659 Uint8
*dst
= info
->d_pixels
;
660 int dstskip
= info
->d_skip
;
661 SDL_PixelFormat
*srcfmt
= info
->src
;
662 SDL_PixelFormat
*dstfmt
= info
->dst
;
667 /* Set up some basic variables */
668 srcbpp
= srcfmt
->BytesPerPixel
;
669 dstbpp
= dstfmt
->BytesPerPixel
;
671 /* FIXME: for 8bpp source alpha, this doesn't get opaque values
672 quite right. for <8bpp source alpha, it gets them very wrong
674 It is unclear whether there is a good general solution that doesn't
675 need a branch (or a divide). */
688 DISEMBLE_RGBA(src
, srcbpp
, srcfmt
, pixel
, sR
, sG
, sB
, sA
);
689 DISEMBLE_RGBA(dst
, dstbpp
, dstfmt
, pixel
, dR
, dG
, dB
, dA
);
690 ALPHA_BLEND(sR
, sG
, sB
, sA
, dR
, dG
, dB
);
691 ASSEMBLE_RGBA(dst
, dstbpp
, dstfmt
, dR
, dG
, dB
, dA
);
702 SDL_loblit
SDL_CalculateAlphaBlit(SDL_Surface
*surface
, int blit_index
)
704 SDL_PixelFormat
*sf
= surface
->format
;
705 SDL_PixelFormat
*df
= surface
->map
->dst
->format
;
708 if((surface
->flags
& SDL_SRCCOLORKEY
) == SDL_SRCCOLORKEY
) {
709 if(df
->BytesPerPixel
== 1)
710 return BlitNto1SurfaceAlphaKey
;
712 return BlitNtoNSurfaceAlphaKey
;
714 /* Per-surface alpha blits */
715 switch(df
->BytesPerPixel
) {
717 return BlitNto1SurfaceAlpha
;
720 if(surface
->map
->identity
) {
721 if(df
->Gmask
== 0x7e0)
722 return Blit565to565SurfaceAlpha
;
723 else if(df
->Gmask
== 0x3e0)
724 return Blit555to555SurfaceAlpha
;
726 return BlitNtoNSurfaceAlpha
;
729 if(sf
->Rmask
== df
->Rmask
730 && sf
->Gmask
== df
->Gmask
731 && sf
->Bmask
== df
->Bmask
732 && (sf
->Rmask
| sf
->Gmask
| sf
->Bmask
) == 0xffffff
733 && sf
->BytesPerPixel
== 4)
734 return BlitRGBtoRGBSurfaceAlpha
;
736 return BlitNtoNSurfaceAlpha
;
740 return BlitNtoNSurfaceAlpha
;
744 /* Per-pixel alpha blits */
745 switch(df
->BytesPerPixel
) {
747 return BlitNto1PixelAlpha
;
750 if(sf
->BytesPerPixel
== 4 && sf
->Amask
== 0xff000000
751 && sf
->Gmask
== 0xff00
752 && ((sf
->Rmask
== 0xff && df
->Rmask
== 0x1f)
753 || (sf
->Bmask
== 0xff && df
->Bmask
== 0x1f))) {
754 if(df
->Gmask
== 0x7e0)
755 return BlitARGBto565PixelAlpha
;
756 else if(df
->Gmask
== 0x3e0)
757 return BlitARGBto555PixelAlpha
;
759 return BlitNtoNPixelAlpha
;
762 if(sf
->Amask
== 0xff000000
763 && sf
->Rmask
== df
->Rmask
764 && sf
->Gmask
== df
->Gmask
765 && sf
->Bmask
== df
->Bmask
766 && sf
->BytesPerPixel
== 4)
767 return BlitRGBtoRGBPixelAlpha
;
768 return BlitNtoNPixelAlpha
;
772 return BlitNtoNPixelAlpha
;