1 // Copyright (C) 2002-2012 Nikolaus Gebhardt / Thomas Alten
\r
2 // This file is part of the "Irrlicht Engine".
\r
3 // For conditions of distribution and use, see copyright notice in irrlicht.h
\r
5 #ifndef _C_BLIT_H_INCLUDED_
\r
6 #define _C_BLIT_H_INCLUDED_
\r
8 #include "SoftwareDriver2_helper.h"
\r
13 //! f18 - fixpoint 14.18 limit to 16k Textures
\r
14 #define CBLIT_USE_FIXPOINT18
\r
16 #if defined(CBLIT_USE_FIXPOINT18)
\r
18 #define f18_one 262144
\r
20 #define f32_to_f18(x)((f18)floorf(((x) * 262144.f) + 0.f))
\r
21 #define f32_to_f32(x)(x)
\r
22 #define f18_floor(x) ((x)>>18)
\r
23 #define f18_round(x) ((x+131.072)>>18)
\r
27 #define f18_zero_dot_five 0.5f
\r
28 #define f18_zero 0.f
\r
29 #define f32_to_f18(x)(x)
\r
30 #define f32_to_f32(x)(x)
\r
31 #define f18_floor(x) ((int)(x))
\r
32 #define f18_round(x) ((int)(x+0.5f))
\r
38 AbsRectangle Source;
\r
45 u32 width; //draw size
\r
48 u32 srcPixelMul; //pixel byte size
\r
51 int srcPitch; //scanline byte size. allow negative for mirror
\r
59 // Bitfields Cohen Sutherland
\r
63 CLIPCODE_BOTTOM = 1,
\r
69 inline u32 GetClipCode( const AbsRectangle &r, const core::position2d<s32> &p )
\r
71 u32 code = CLIPCODE_EMPTY;
\r
74 code = CLIPCODE_LEFT;
\r
77 code = CLIPCODE_RIGHT;
\r
80 code |= CLIPCODE_TOP;
\r
83 code |= CLIPCODE_BOTTOM;
\r
90 Cohen Sutherland clipping
\r
94 static int ClipLine(const AbsRectangle &clipping,
\r
95 core::position2d<s32> &p0,
\r
96 core::position2d<s32> &p1,
\r
97 const core::position2d<s32>& p0_in,
\r
98 const core::position2d<s32>& p1_in)
\r
107 code0 = GetClipCode( clipping, p0 );
\r
108 code1 = GetClipCode( clipping, p1 );
\r
110 // trivial accepted
\r
111 while ( code0 | code1 )
\r
117 if ( code0 & code1 )
\r
122 // clip first point
\r
131 if ( (code & CLIPCODE_BOTTOM) == CLIPCODE_BOTTOM )
\r
133 // clip bottom viewport
\r
135 x = p0.X + ( p1.X - p0.X ) * ( y - p0.Y ) / ( p1.Y - p0.Y );
\r
138 if ( (code & CLIPCODE_TOP) == CLIPCODE_TOP )
\r
140 // clip to viewport
\r
142 x = p0.X + ( p1.X - p0.X ) * ( y - p0.Y ) / ( p1.Y - p0.Y );
\r
145 if ( (code & CLIPCODE_RIGHT) == CLIPCODE_RIGHT )
\r
147 // clip right viewport
\r
149 y = p0.Y + ( p1.Y - p0.Y ) * ( x - p0.X ) / ( p1.X - p0.X );
\r
152 if ( (code & CLIPCODE_LEFT) == CLIPCODE_LEFT )
\r
154 // clip left viewport
\r
156 y = p0.Y + ( p1.Y - p0.Y ) * ( x - p0.X ) / ( p1.X - p0.X );
\r
159 if ( code == code0 )
\r
161 // modify first point
\r
164 code0 = GetClipCode( clipping, p0 );
\r
168 // modify second point
\r
171 code1 = GetClipCode( clipping, p1 );
\r
180 inline void GetClip(AbsRectangle &clipping, video::IImage * t)
\r
184 clipping.x1 = t->getDimension().Width - 1;
\r
185 clipping.y1 = t->getDimension().Height - 1;
\r
189 return alpha in [0;256] Granularity from 32-Bit ARGB
\r
190 add highbit alpha ( alpha > 127 ? + 1 )
\r
192 static inline u32 extractAlpha(const u32 c)
\r
194 return ( c >> 24 ) + ( c >> 31 );
\r
198 return alpha in [0;255] Granularity and 32-Bit ARGB
\r
199 add highbit alpha ( alpha > 127 ? + 1 )
\r
201 static inline u32 packAlpha(const u32 c)
\r
203 return (c > 127 ? c - 1 : c) << 24;
\r
208 Scale Color by (1/value)
\r
209 value 0 - 256 ( alpha )
\r
211 inline u32 PixelLerp32(const u32 source, const u32 value)
\r
213 u32 srcRB = source & 0x00FF00FF;
\r
214 u32 srcXG = (source & 0xFF00FF00) >> 8;
\r
222 srcXG &= 0xFF00FF00;
\r
223 srcRB &= 0x00FF00FF;
\r
225 return srcRB | srcXG;
\r
231 static void RenderLine32_Decal(video::IImage *t,
\r
232 const core::position2d<s32> &p0,
\r
233 const core::position2d<s32> &p1,
\r
236 s32 dx = p1.X - p0.X;
\r
237 s32 dy = p1.Y - p0.Y;
\r
245 s32 yInc = (s32) t->getPitch();
\r
260 dst = (u32*) ( (u8*) t->getData() + ( p0.Y * t->getPitch() ) + ( p0.X * 4 ) );
\r
281 dst = (u32*) ( (u8*) dst + xInc ); // x += xInc
\r
285 dst = (u32*) ( (u8*) dst + yInc ); // y += yInc
\r
295 static void RenderLine32_Blend(video::IImage *t,
\r
296 const core::position2d<s32> &p0,
\r
297 const core::position2d<s32> &p1,
\r
298 u32 argb, u32 alpha)
\r
300 s32 dx = p1.X - p0.X;
\r
301 s32 dy = p1.Y - p0.Y;
\r
309 s32 yInc = (s32) t->getPitch();
\r
324 dst = (u32*) ( (u8*) t->getData() + ( p0.Y * t->getPitch() ) + ( p0.X * 4 ) );
\r
341 const u32 packA = packAlpha ( alpha );
\r
344 *dst = packA | PixelBlend32( *dst, argb, alpha );
\r
346 dst = (u32*) ( (u8*) dst + xInc ); // x += xInc
\r
350 dst = (u32*) ( (u8*) dst + yInc ); // y += yInc
\r
359 static void RenderLine16_Decal(video::IImage *t,
\r
360 const core::position2d<s32> &p0,
\r
361 const core::position2d<s32> &p1,
\r
364 s32 dx = p1.X - p0.X;
\r
365 s32 dy = p1.Y - p0.Y;
\r
373 s32 yInc = (s32) t->getPitch();
\r
388 dst = (u16*) ( (u8*) t->getData() + ( p0.Y * t->getPitch() ) + ( p0.X * 2 ) );
\r
409 dst = (u16*) ( (u8*) dst + xInc ); // x += xInc
\r
413 dst = (u16*) ( (u8*) dst + yInc ); // y += yInc
\r
422 static void RenderLine16_Blend(video::IImage *t,
\r
423 const core::position2d<s32> &p0,
\r
424 const core::position2d<s32> &p1,
\r
428 s32 dx = p1.X - p0.X;
\r
429 s32 dy = p1.Y - p0.Y;
\r
437 s32 yInc = (s32) t->getPitch();
\r
452 dst = (u16*) ( (u8*) t->getData() + ( p0.Y * t->getPitch() ) + ( p0.X * 2 ) );
\r
469 const u16 packA = alpha ? 0x8000 : 0;
\r
472 *dst = packA | PixelBlend16( *dst, argb, alpha );
\r
474 dst = (u16*) ( (u8*) dst + xInc ); // x += xInc
\r
478 dst = (u16*) ( (u8*) dst + yInc ); // y += yInc
\r
488 static void executeBlit_TextureCopy_x_to_x( const SBlitJob * job )
\r
492 const f18 wscale = f32_to_f18(job->x_stretch);
\r
493 const f18 hscale = f32_to_f18(job->y_stretch);
\r
495 f18 src_y = f18_zero;
\r
497 if (job->srcPixelMul == 4)
\r
499 const u32 *src = (u32*)(job->src);
\r
500 u32 *dst = (u32*)(job->dst);
\r
502 for (u32 dy = 0; dy < job->height; ++dy, src_y += hscale)
\r
504 src = (u32*)((u8*)(job->src) + job->srcPitch*f18_floor(src_y));
\r
506 f18 src_x = f18_zero;
\r
507 for (u32 dx = 0; dx < job->width; ++dx, src_x += wscale)
\r
509 dst[dx] = src[f18_floor(src_x)];
\r
511 dst = (u32*)((u8*)(dst)+job->dstPitch);
\r
514 else if (job->srcPixelMul == 2)
\r
516 const u16 *src = (u16*)(job->src);
\r
517 u16* dst = (u16*)(job->dst);
\r
519 for (u32 dy = 0; dy < job->height; ++dy, src_y += hscale)
\r
521 src = (u16*)((u8*)(job->src) + job->srcPitch*f18_floor(src_y));
\r
523 f18 src_x = f18_zero;
\r
524 for (u32 dx = 0; dx < job->width; ++dx, src_x += wscale)
\r
526 dst[dx] = src[f18_floor(src_x)];
\r
528 dst = (u16*)((u8*)(dst)+job->dstPitch);
\r
534 const size_t widthPitch = job->width * job->dstPixelMul;
\r
535 const void *src = (void*) job->src;
\r
536 void *dst = (void*) job->dst;
\r
538 for ( u32 dy = 0; dy < job->height; ++dy )
\r
540 memcpy( dst, src, widthPitch);
\r
542 src = (void*) ( (u8*) (src) + job->srcPitch );
\r
543 dst = (void*) ( (u8*) (dst) + job->dstPitch );
\r
550 static void executeBlit_TextureCopy_32_to_16( const SBlitJob * job )
\r
552 const u32 w = job->width;
\r
553 const u32 h = job->height;
\r
554 const u32 *src = static_cast<const u32*>(job->src);
\r
555 u16 *dst = static_cast<u16*>(job->dst);
\r
559 const float wscale = job->x_stretch;
\r
560 const float hscale = job->y_stretch;
\r
562 for ( u32 dy = 0; dy < h; ++dy )
\r
564 const u32 src_y = (u32)(dy*hscale);
\r
565 src = (u32*) ( (u8*) (job->src) + job->srcPitch*src_y );
\r
567 for ( u32 dx = 0; dx < w; ++dx )
\r
569 const u32 src_x = (u32)(dx*wscale);
\r
570 //16 bit Blitter depends on pre-multiplied color
\r
571 const u32 s = PixelLerp32( src[src_x] | 0xFF000000, extractAlpha( src[src_x] ) );
\r
572 dst[dx] = video::A8R8G8B8toA1R5G5B5( s );
\r
574 dst = (u16*) ( (u8*) (dst) + job->dstPitch );
\r
579 for ( u32 dy = 0; dy != h; ++dy )
\r
581 for ( u32 dx = 0; dx != w; ++dx )
\r
583 //16 bit Blitter depends on pre-multiplied color
\r
584 const u32 s = PixelLerp32( src[dx] | 0xFF000000, extractAlpha( src[dx] ) );
\r
585 dst[dx] = video::A8R8G8B8toA1R5G5B5( s );
\r
588 src = (u32*) ( (u8*) (src) + job->srcPitch );
\r
589 dst = (u16*) ( (u8*) (dst) + job->dstPitch );
\r
596 static void executeBlit_TextureCopy_24_to_16( const SBlitJob * job )
\r
598 const u32 w = job->width;
\r
599 const u32 h = job->height;
\r
600 const u8 *src = static_cast<const u8*>(job->src);
\r
601 u16 *dst = static_cast<u16*>(job->dst);
\r
605 const float wscale = job->x_stretch * 3.f;
\r
606 const float hscale = job->y_stretch;
\r
608 for ( u32 dy = 0; dy < h; ++dy )
\r
610 const u32 src_y = (u32)(dy*hscale);
\r
611 src = (u8*)(job->src) + job->srcPitch*src_y;
\r
613 for ( u32 dx = 0; dx < w; ++dx )
\r
615 const u8* src_x = src+(u32)(dx*wscale);
\r
616 dst[dx] = video::RGBA16(src_x[0], src_x[1], src_x[2]);
\r
618 dst = (u16*) ( (u8*) (dst) + job->dstPitch );
\r
623 for ( u32 dy = 0; dy != h; ++dy )
\r
626 for ( u32 dx = 0; dx != w; ++dx )
\r
628 dst[dx] = video::RGBA16(s[0], s[1], s[2]);
\r
632 src = src+job->srcPitch;
\r
633 dst = (u16*) ( (u8*) (dst) + job->dstPitch );
\r
641 static void executeBlit_TextureCopy_16_to_32( const SBlitJob * job )
\r
643 const u32 w = job->width;
\r
644 const u32 h = job->height;
\r
645 const u16 *src = static_cast<const u16*>(job->src);
\r
646 u32 *dst = static_cast<u32*>(job->dst);
\r
650 const float wscale = job->x_stretch;
\r
651 const float hscale = job->y_stretch;
\r
653 for ( u32 dy = 0; dy < h; ++dy )
\r
655 const u32 src_y = (u32)(dy*hscale);
\r
656 src = (u16*) ( (u8*) (job->src) + job->srcPitch*src_y );
\r
658 for ( u32 dx = 0; dx < w; ++dx )
\r
660 const u32 src_x = (u32)(dx*wscale);
\r
661 dst[dx] = video::A1R5G5B5toA8R8G8B8(src[src_x]);
\r
663 dst = (u32*) ( (u8*) (dst) + job->dstPitch );
\r
668 for ( u32 dy = 0; dy != h; ++dy )
\r
670 for ( u32 dx = 0; dx != w; ++dx )
\r
672 dst[dx] = video::A1R5G5B5toA8R8G8B8( src[dx] );
\r
675 src = (u16*) ( (u8*) (src) + job->srcPitch );
\r
676 dst = (u32*) ( (u8*) (dst) + job->dstPitch );
\r
681 static void executeBlit_TextureCopy_16_to_24( const SBlitJob * job )
\r
683 const u32 w = job->width;
\r
684 const u32 h = job->height;
\r
685 const u16 *src = static_cast<const u16*>(job->src);
\r
686 u8 *dst = static_cast<u8*>(job->dst);
\r
690 const float wscale = job->x_stretch;
\r
691 const float hscale = job->y_stretch;
\r
693 for ( u32 dy = 0; dy < h; ++dy )
\r
695 const u32 src_y = (u32)(dy*hscale);
\r
696 src = (u16*) ( (u8*) (job->src) + job->srcPitch*src_y );
\r
698 for ( u32 dx = 0; dx < w; ++dx )
\r
700 const u32 src_x = (u32)(dx*wscale);
\r
701 u32 color = video::A1R5G5B5toA8R8G8B8(src[src_x]);
\r
702 u8 * writeTo = &dst[dx * 3];
\r
703 *writeTo++ = (color >> 16)& 0xFF;
\r
704 *writeTo++ = (color >> 8) & 0xFF;
\r
705 *writeTo++ = color & 0xFF;
\r
707 dst += job->dstPitch;
\r
712 for ( u32 dy = 0; dy != h; ++dy )
\r
714 for ( u32 dx = 0; dx != w; ++dx )
\r
716 u32 color = video::A1R5G5B5toA8R8G8B8(src[dx]);
\r
717 u8 * writeTo = &dst[dx * 3];
\r
718 *writeTo++ = (color >> 16)& 0xFF;
\r
719 *writeTo++ = (color >> 8) & 0xFF;
\r
720 *writeTo++ = color & 0xFF;
\r
723 src = (u16*) ( (u8*) (src) + job->srcPitch );
\r
724 dst += job->dstPitch;
\r
731 static void executeBlit_TextureCopy_24_to_32( const SBlitJob * job )
\r
733 const u32 w = job->width;
\r
734 const u32 h = job->height;
\r
735 const u8 *src = static_cast<const u8*>(job->src);
\r
736 u32 *dst = static_cast<u32*>(job->dst);
\r
740 const float wscale = job->x_stretch * 3.f;
\r
741 const float hscale = job->y_stretch;
\r
743 for ( u32 dy = 0; dy < h; ++dy )
\r
745 const u32 src_y = (u32)(dy*hscale);
\r
746 src = (const u8*)job->src+(job->srcPitch*src_y);
\r
748 for ( u32 dx = 0; dx < w; ++dx )
\r
750 const u8* s = src+(u32)(dx*wscale);
\r
751 dst[dx] = 0xFF000000 | s[0] << 16 | s[1] << 8 | s[2];
\r
753 dst = (u32*) ( (u8*) (dst) + job->dstPitch );
\r
758 for ( u32 dy = 0; dy < job->height; ++dy )
\r
762 for ( u32 dx = 0; dx < job->width; ++dx )
\r
764 dst[dx] = 0xFF000000 | s[0] << 16 | s[1] << 8 | s[2];
\r
768 src = src + job->srcPitch;
\r
769 dst = (u32*) ( (u8*) (dst) + job->dstPitch );
\r
774 static void executeBlit_TextureCopy_32_to_24( const SBlitJob * job )
\r
776 const u32 w = job->width;
\r
777 const u32 h = job->height;
\r
778 const u32 *src = static_cast<const u32*>(job->src);
\r
779 u8 *dst = static_cast<u8*>(job->dst);
\r
783 const float wscale = job->x_stretch;
\r
784 const float hscale = job->y_stretch;
\r
786 for ( u32 dy = 0; dy < h; ++dy )
\r
788 const u32 src_y = (u32)(dy*hscale);
\r
789 src = (u32*) ( (u8*) (job->src) + job->srcPitch*src_y);
\r
791 for ( u32 dx = 0; dx < w; ++dx )
\r
793 const u32 src_x = src[(u32)(dx*wscale)];
\r
794 u8 * writeTo = &dst[dx * 3];
\r
795 *writeTo++ = (src_x >> 16)& 0xFF;
\r
796 *writeTo++ = (src_x >> 8) & 0xFF;
\r
797 *writeTo++ = src_x & 0xFF;
\r
799 dst += job->dstPitch;
\r
804 for ( u32 dy = 0; dy != h; ++dy )
\r
806 for ( u32 dx = 0; dx != w; ++dx )
\r
808 u8 * writeTo = &dst[dx * 3];
\r
809 *writeTo++ = (src[dx] >> 16)& 0xFF;
\r
810 *writeTo++ = (src[dx] >> 8) & 0xFF;
\r
811 *writeTo++ = src[dx] & 0xFF;
\r
814 src = (u32*) ( (u8*) (src) + job->srcPitch );
\r
815 dst += job->dstPitch;
\r
822 static void executeBlit_TextureBlend_16_to_16( const SBlitJob * job )
\r
824 const f18 wscale = f32_to_f18(job->x_stretch);
\r
825 const f18 hscale = f32_to_f18(job->y_stretch);
\r
827 f18 src_y = f18_zero;
\r
828 u16 *dst = (u16*)job->dst;
\r
830 for (u32 dy = 0; dy < job->height; ++dy, src_y += hscale)
\r
832 const u16* src = (u16*)((u8*)(job->src) + job->srcPitch*f18_floor(src_y));
\r
833 f18 src_x = f18_zero;
\r
834 for (u32 dx = 0; dx < job->width; ++dx, src_x += wscale)
\r
836 dst[dx] = PixelBlend16(dst[dx], src[f18_floor(src_x)]);
\r
838 dst = (u16*)((u8*)(dst)+job->dstPitch);
\r
844 static void executeBlit_TextureBlend_32_to_32( const SBlitJob * job )
\r
846 const f18 wscale = f32_to_f18(job->x_stretch);
\r
847 const f18 hscale = f32_to_f18(job->y_stretch);
\r
849 f18 src_y = f18_zero;
\r
850 u32 *dst = (u32*)job->dst;
\r
851 for (u32 dy = 0; dy < job->height; ++dy, src_y += hscale)
\r
853 const u32* src = (u32*)((u8*)(job->src) + job->srcPitch*f18_floor(src_y));
\r
855 f18 src_x = f18_zero;
\r
856 for (u32 dx = 0; dx < job->width; ++dx, src_x += wscale)
\r
858 dst[dx] = PixelBlend32(dst[dx], src[f18_floor(src_x)]);
\r
860 dst = (u32*)((u8*)(dst)+job->dstPitch);
\r
866 static void executeBlit_TextureBlendColor_16_to_16( const SBlitJob * job )
\r
868 const u16 blend = video::A8R8G8B8toA1R5G5B5(job->argb);
\r
870 const f18 wscale = f32_to_f18(job->x_stretch);
\r
871 const f18 hscale = f32_to_f18(job->y_stretch);
\r
873 f18 src_y = f18_zero;
\r
874 u16 *dst = (u16*)job->dst;
\r
875 for (u32 dy = 0; dy < job->height; ++dy, src_y += hscale)
\r
877 const u16* src = (u16*)((u8*)(job->src) + job->srcPitch*f18_floor(src_y));
\r
878 f18 src_x = f18_zero;
\r
879 for (u32 dx = 0; dx < job->width; ++dx, src_x += wscale)
\r
881 u16 c0 = src[f18_floor(src_x)];
\r
882 if (0 == (c0 & 0x8000))
\r
885 dst[dx] = PixelMul16_2(c0, blend);
\r
887 dst = (u16*)((u8*)(dst)+job->dstPitch);
\r
894 static void executeBlit_TextureBlendColor_32_to_32( const SBlitJob * job )
\r
896 const f18 wscale = f32_to_f18(job->x_stretch);
\r
897 const f18 hscale = f32_to_f18(job->y_stretch);
\r
899 u32* dst = (u32*)job->dst;
\r
900 f18 src_y = f18_zero;
\r
901 for (u32 dy = 0; dy < job->height; ++dy, src_y += hscale)
\r
903 const u32* src = (u32*)((u8*)(job->src) + job->srcPitch*f18_floor(src_y));
\r
905 f18 src_x = f18_zero;
\r
906 for (u32 dx = 0; dx < job->width; ++dx, src_x += wscale)
\r
908 dst[dx] = PixelBlend32(dst[dx], PixelMul32_2(src[f18_floor(src_x)], job->argb));
\r
910 dst = (u32*)((u8*)(dst)+job->dstPitch);
\r
916 static void executeBlit_Color_16_to_16( const SBlitJob * job )
\r
918 const u16 c = video::A8R8G8B8toA1R5G5B5(job->argb);
\r
919 u16 *dst = (u16*) job->dst;
\r
921 for ( u32 dy = 0; dy < job->height; ++dy )
\r
923 memset16(dst, c, job->srcPitch);
\r
924 dst = (u16*) ( (u8*) (dst) + job->dstPitch );
\r
930 static void executeBlit_Color_32_to_32( const SBlitJob * job )
\r
932 u32 *dst = (u32*) job->dst;
\r
934 for ( u32 dy = 0; dy < job->height; ++dy )
\r
936 memset32( dst, job->argb, job->srcPitch );
\r
937 dst = (u32*) ( (u8*) (dst) + job->dstPitch );
\r
943 static void executeBlit_ColorAlpha_16_to_16( const SBlitJob * job )
\r
945 u16 *dst = (u16*) job->dst;
\r
947 const u16 alpha = extractAlpha( job->argb ) >> 3;
\r
950 const u32 src = video::A8R8G8B8toA1R5G5B5( job->argb );
\r
952 for ( u32 dy = 0; dy != job->height; ++dy )
\r
954 for ( u32 dx = 0; dx != job->width; ++dx )
\r
956 dst[dx] = PixelBlend16( dst[dx], src, alpha );
\r
958 dst = (u16*) ( (u8*) (dst) + job->dstPitch );
\r
964 static void executeBlit_ColorAlpha_32_to_32( const SBlitJob * job )
\r
966 const u32 alpha = extractAlpha( job->argb );
\r
970 u32 *dst = (u32*)job->dst;
\r
971 for ( u32 dy = 0; dy < job->height; ++dy )
\r
973 for ( u32 dx = 0; dx < job->width; ++dx )
\r
975 dst[dx] = PixelBlend32( dst[dx], job->argb, alpha );
\r
977 dst = (u32*) ( (u8*) (dst) + job->dstPitch );
\r
984 color = sourceAlpha > 0 ? source, else dest
\r
985 alpha = max(destAlpha, sourceAlpha)
\r
987 inline u16 PixelCombine16(const u16 c2, const u16 c1)
\r
989 if (video::getAlpha(c1) > 0)
\r
996 Combine alpha channels (increases alpha / reduces transparency)
\r
998 static void executeBlit_TextureCombineColor_16_to_16( const SBlitJob * job )
\r
1000 const u32 w = job->width * 2;
\r
1001 const u32 h = job->height * 2;
\r
1002 u16* src = (u16*) job->src;
\r
1003 u16* dst = (u16*) job->dst;
\r
1005 const u16 jobColor = video::A8R8G8B8toA1R5G5B5( job->argb );
\r
1008 Stretch not supported.
\r
1010 for ( u32 dy = 0; dy != h; dy++ )
\r
1012 for ( u32 dx = 0; dx != w; dx++ )
\r
1014 const u16 src_x = src[dx];
\r
1015 const u16 dst_x = dst[dx];
\r
1016 dst[dx] = PixelCombine16( dst_x, PixelMul16_2( src_x, jobColor ) );
\r
1018 src = (u16*) ( (u8*) (src) + job->srcPitch );
\r
1019 dst = (u16*) ( (u8*) (dst) + job->dstPitch );
\r
1024 Combine alpha channels (increases alpha / reduces transparency)
\r
1026 static void executeBlit_TextureCombineColor_16_to_24( const SBlitJob * job )
\r
1028 const u32 w = job->width;
\r
1029 const u32 h = job->height;
\r
1030 const u16 *src = static_cast<const u16*>(job->src);
\r
1031 u8 *dst = static_cast<u8*>(job->dst);
\r
1033 const u16 jobColor = video::A8R8G8B8toA1R5G5B5( job->argb );
\r
1037 const float wscale = job->x_stretch;
\r
1038 const float hscale = job->y_stretch;
\r
1040 for ( u32 dy = 0; dy < h; ++dy )
\r
1042 const u32 src_y = (u32)(dy*hscale);
\r
1043 src = (u16*) ( (u8*) (job->src) + job->srcPitch*src_y );
\r
1045 for ( u32 dx = 0; dx < w; ++dx )
\r
1047 const u32 src_x = (u32)(dx*wscale);
\r
1048 u32 color = PixelMul16_2( video::A1R5G5B5toA8R8G8B8(src[src_x]), jobColor);
\r
1049 u8 * writeTo = &dst[dx * 3];
\r
1050 if ( video::getAlpha(src[src_x]) > 0 ) // only overlay if source has visible alpha (alpha == 1)
\r
1052 *writeTo++ = (color >> 16)& 0xFF;
\r
1053 *writeTo++ = (color >> 8) & 0xFF;
\r
1054 *writeTo++ = color & 0xFF;
\r
1057 dst += job->dstPitch;
\r
1062 for ( u32 dy = 0; dy != h; ++dy )
\r
1064 for ( u32 dx = 0; dx != w; ++dx )
\r
1066 u32 color = PixelMul16_2( video::A1R5G5B5toA8R8G8B8(src[dx]), jobColor);
\r
1067 u8 * writeTo = &dst[dx * 3];
\r
1068 if ( video::getAlpha(src[dx]) > 0 ) // only overlay if source has visible alpha (alpha == 1)
\r
1070 *writeTo++ = (color >> 16)& 0xFF;
\r
1071 *writeTo++ = (color >> 8) & 0xFF;
\r
1072 *writeTo++ = color & 0xFF;
\r
1076 src = (u16*) ( (u8*) (src) + job->srcPitch );
\r
1077 dst += job->dstPitch;
\r
1084 color = dest * ( 1 - SourceAlpha ) + source * SourceAlpha,
\r
1085 alpha = destAlpha * ( 1 - SourceAlpha ) + sourceAlpha
\r
1087 where "1" means "full scale" (255)
\r
1089 inline u32 PixelCombine32(const u32 c2, const u32 c1)
\r
1092 u32 alpha = c1 & 0xFF000000;
\r
1096 if (0xFF000000 == alpha)
\r
1103 // add highbit alpha, if ( alpha > 127 ) alpha += 1;
\r
1104 // stretches [0;255] to [0;256] to avoid division by 255. use division 256 == shr 8
\r
1105 alpha += (alpha >> 7);
\r
1107 u32 srcRB = c1 & 0x00FF00FF;
\r
1108 u32 srcXG = c1 & 0x0000FF00;
\r
1110 u32 dstRB = c2 & 0x00FF00FF;
\r
1111 u32 dstXG = c2 & 0x0000FF00;
\r
1114 u32 rb = srcRB - dstRB;
\r
1115 u32 xg = srcXG - dstXG;
\r
1128 u32 sa = c1 >> 24;
\r
1129 u32 da = c2 >> 24;
\r
1130 u32 blendAlpha_fix8 = (sa * 256 + da * (256 - alpha)) >> 8;
\r
1131 return blendAlpha_fix8 << 24 | rb | xg;
\r
1135 Combine alpha channels (increases alpha / reduces transparency)
\r
1136 Destination alpha is treated as full 255
\r
1138 static void executeBlit_TextureCombineColor_32_to_24( const SBlitJob * job )
\r
1140 const u32 w = job->width;
\r
1141 const u32 h = job->height;
\r
1142 const u32 *src = static_cast<const u32*>(job->src);
\r
1143 u8 *dst = static_cast<u8*>(job->dst);
\r
1147 const float wscale = job->x_stretch;
\r
1148 const float hscale = job->y_stretch;
\r
1150 for ( u32 dy = 0; dy < h; ++dy )
\r
1152 const u32 src_y = (u32)(dy*hscale);
\r
1153 src = (u32*) ( (u8*) (job->src) + job->srcPitch*src_y);
\r
1155 for ( u32 dx = 0; dx < w; ++dx )
\r
1157 const u32 src_x = src[(u32)(dx*wscale)];
\r
1158 u8* writeTo = &dst[dx * 3];
\r
1159 const u32 dst_x = 0xFF000000 | writeTo[0] << 16 | writeTo[1] << 8 | writeTo[2];
\r
1160 const u32 combo = PixelCombine32( dst_x, PixelMul32_2( src_x, job->argb ) );
\r
1161 *writeTo++ = (combo >> 16) & 0xFF;
\r
1162 *writeTo++ = (combo >> 8) & 0xFF;
\r
1163 *writeTo++ = combo & 0xFF;
\r
1165 dst += job->dstPitch;
\r
1170 for ( u32 dy = 0; dy != h; ++dy )
\r
1172 for ( u32 dx = 0; dx != w; ++dx )
\r
1174 u8* writeTo = &dst[dx * 3];
\r
1175 const u32 dst_x = 0xFF000000 | writeTo[0] << 16 | writeTo[1] << 8 | writeTo[2];
\r
1176 const u32 combo = PixelCombine32( dst_x, PixelMul32_2( src[dx], job->argb ) );
\r
1177 *writeTo++ = (combo >> 16) & 0xFF;
\r
1178 *writeTo++ = (combo >> 8) & 0xFF;
\r
1179 *writeTo++ = combo & 0xFF;
\r
1182 src = (u32*) ( (u8*) (src) + job->srcPitch );
\r
1183 dst += job->dstPitch;
\r
1189 Combine alpha channels (increases alpha / reduces transparency)
\r
1191 static void executeBlit_TextureCombineColor_32_to_32( const SBlitJob * job )
\r
1193 u32 *src = (u32*) job->src;
\r
1194 u32 *dst = (u32*) job->dst;
\r
1196 for ( u32 dy = 0; dy != job->height; ++dy )
\r
1198 for (u32 dx = 0; dx != job->width; ++dx )
\r
1200 dst[dx] = PixelCombine32( dst[dx], PixelMul32_2( src[dx], job->argb ) );
\r
1202 src = (u32*) ( (u8*) (src) + job->srcPitch );
\r
1203 dst = (u32*) ( (u8*) (dst) + job->dstPitch );
\r
1207 // Blitter Operation
\r
1210 BLITTER_INVALID = 0,
\r
1212 BLITTER_COLOR_ALPHA,
\r
1214 BLITTER_TEXTURE_ALPHA_BLEND,
\r
1215 BLITTER_TEXTURE_ALPHA_COLOR_BLEND,
\r
1216 BLITTER_TEXTURE_COMBINE_ALPHA,
\r
1219 typedef void (*tExecuteBlit) ( const SBlitJob * job );
\r
1224 struct blitterTable
\r
1226 eBlitter operation;
\r
1229 tExecuteBlit func;
\r
1232 static const blitterTable blitTable[] =
\r
1234 { BLITTER_TEXTURE, -2, -2, executeBlit_TextureCopy_x_to_x },
\r
1235 { BLITTER_TEXTURE, video::ECF_A1R5G5B5, video::ECF_A8R8G8B8, executeBlit_TextureCopy_32_to_16 },
\r
1236 { BLITTER_TEXTURE, video::ECF_A1R5G5B5, video::ECF_R8G8B8, executeBlit_TextureCopy_24_to_16 },
\r
1237 { BLITTER_TEXTURE, video::ECF_A8R8G8B8, video::ECF_A1R5G5B5, executeBlit_TextureCopy_16_to_32 },
\r
1238 { BLITTER_TEXTURE, video::ECF_A8R8G8B8, video::ECF_R8G8B8, executeBlit_TextureCopy_24_to_32 },
\r
1239 { BLITTER_TEXTURE, video::ECF_R8G8B8, video::ECF_A1R5G5B5, executeBlit_TextureCopy_16_to_24 },
\r
1240 { BLITTER_TEXTURE, video::ECF_R8G8B8, video::ECF_A8R8G8B8, executeBlit_TextureCopy_32_to_24 },
\r
1241 { BLITTER_TEXTURE_ALPHA_BLEND, video::ECF_A1R5G5B5, video::ECF_A1R5G5B5, executeBlit_TextureBlend_16_to_16 },
\r
1242 { BLITTER_TEXTURE_ALPHA_BLEND, video::ECF_A8R8G8B8, video::ECF_A8R8G8B8, executeBlit_TextureBlend_32_to_32 },
\r
1243 { BLITTER_TEXTURE_ALPHA_COLOR_BLEND, video::ECF_A1R5G5B5, video::ECF_A1R5G5B5, executeBlit_TextureBlendColor_16_to_16 },
\r
1244 { BLITTER_TEXTURE_ALPHA_COLOR_BLEND, video::ECF_A8R8G8B8, video::ECF_A8R8G8B8, executeBlit_TextureBlendColor_32_to_32 },
\r
1245 { BLITTER_COLOR, video::ECF_A1R5G5B5, -1, executeBlit_Color_16_to_16 },
\r
1246 { BLITTER_COLOR, video::ECF_A8R8G8B8, -1, executeBlit_Color_32_to_32 },
\r
1247 { BLITTER_COLOR_ALPHA, video::ECF_A1R5G5B5, -1, executeBlit_ColorAlpha_16_to_16 },
\r
1248 { BLITTER_COLOR_ALPHA, video::ECF_A8R8G8B8, -1, executeBlit_ColorAlpha_32_to_32 },
\r
1249 { BLITTER_TEXTURE_COMBINE_ALPHA, video::ECF_A8R8G8B8, video::ECF_A8R8G8B8, executeBlit_TextureCombineColor_32_to_32 },
\r
1250 { BLITTER_TEXTURE_COMBINE_ALPHA, video::ECF_A8R8G8B8, video::ECF_R8G8B8, executeBlit_TextureCopy_24_to_32 },
\r
1251 { BLITTER_TEXTURE_COMBINE_ALPHA, video::ECF_R8G8B8, video::ECF_A8R8G8B8, executeBlit_TextureCombineColor_32_to_24 },
\r
1252 { BLITTER_TEXTURE_COMBINE_ALPHA, video::ECF_R8G8B8, video::ECF_R8G8B8, executeBlit_TextureCopy_x_to_x },
\r
1253 { BLITTER_TEXTURE_COMBINE_ALPHA, video::ECF_A1R5G5B5, video::ECF_R8G8B8, executeBlit_TextureCopy_24_to_16 },
\r
1254 { BLITTER_TEXTURE_COMBINE_ALPHA, video::ECF_A1R5G5B5, video::ECF_A1R5G5B5, executeBlit_TextureCombineColor_16_to_16 },
\r
1255 { BLITTER_TEXTURE_COMBINE_ALPHA, video::ECF_A1R5G5B5, video::ECF_R8G8B8, executeBlit_TextureCopy_24_to_16 },
\r
1256 { BLITTER_TEXTURE_COMBINE_ALPHA, video::ECF_R8G8B8, video::ECF_A1R5G5B5, executeBlit_TextureCombineColor_16_to_24 },
\r
1257 { BLITTER_INVALID, -1, -1, 0 }
\r
1261 static inline tExecuteBlit getBlitter2( eBlitter operation,const video::IImage * dest,const video::IImage * source )
\r
1263 video::ECOLOR_FORMAT sourceFormat = (video::ECOLOR_FORMAT) ( source ? source->getColorFormat() : -1 );
\r
1264 video::ECOLOR_FORMAT destFormat = (video::ECOLOR_FORMAT) ( dest ? dest->getColorFormat() : -1 );
\r
1266 const blitterTable * b = blitTable;
\r
1268 while ( b->operation != BLITTER_INVALID )
\r
1270 if ( b->operation == operation )
\r
1272 if (( b->destFormat == -1 || b->destFormat == destFormat ) &&
\r
1273 ( b->sourceFormat == -1 || b->sourceFormat == sourceFormat ) )
\r
1276 if ( b->destFormat == -2 && ( sourceFormat == destFormat ) )
\r
1285 // bounce clipping to texture
\r
1286 inline void setClip(AbsRectangle &out, const core::rect<s32> *clip,
\r
1287 const video::IImage* tex, s32 passnative, const core::dimension2d<u32>* tex_org)
\r
1291 if (clip && passnative)
\r
1293 out.x0 = clip->UpperLeftCorner.X;
\r
1294 out.x1 = clip->LowerRightCorner.X;
\r
1295 out.y0 = clip->UpperLeftCorner.Y;
\r
1296 out.y1 = clip->LowerRightCorner.Y;
\r
1308 const s32 w = tex->getDimension().Width;
\r
1309 const s32 h = tex->getDimension().Height;
\r
1311 //driver could have changed texture size.
\r
1312 if (clip && tex_org && ((u32)w != tex_org->Width || (u32)h != tex_org->Height))
\r
1314 out.x0 = core::s32_clamp((clip->UpperLeftCorner.X*w) / tex_org->Width, 0, w - 1);
\r
1315 out.x1 = core::s32_clamp((clip->LowerRightCorner.X*w) / tex_org->Width, out.x0, w);
\r
1316 out.y0 = core::s32_clamp((clip->UpperLeftCorner.Y*h) / tex_org->Height, 0, h - 1);
\r
1317 out.y1 = core::s32_clamp((clip->LowerRightCorner.Y*h) / tex_org->Height, out.y0, h);
\r
1321 //y-1 to prevent starting on illegal memory (not ideal!).
\r
1322 out.x0 = core::s32_clamp(clip->UpperLeftCorner.X, 0, w - 1);
\r
1323 out.x1 = core::s32_clamp(clip->LowerRightCorner.X, passnative ? 0 : out.x0, w);
\r
1324 out.y0 = core::s32_clamp(clip->UpperLeftCorner.Y, 0, h - 1);
\r
1325 out.y1 = core::s32_clamp(clip->LowerRightCorner.Y, passnative ? 0 : out.y0, h);
\r
1338 a generic 2D Blitter
\r
1340 static s32 Blit(eBlitter operation,
\r
1341 video::IImage * dest,
\r
1342 const core::rect<s32> *destClipping,
\r
1343 const core::position2d<s32> *destPos,
\r
1344 video::IImage * const source,
\r
1345 const core::rect<s32> *sourceClipping,
\r
1348 tExecuteBlit blitter = getBlitter2( operation, dest, source );
\r
1349 if ( 0 == blitter )
\r
1355 AbsRectangle sourceClip;
\r
1356 AbsRectangle destClip;
\r
1361 setClip ( sourceClip, sourceClipping, source, 1,0 );
\r
1362 setClip ( destClip, destClipping, dest, 0,0 );
\r
1364 v.x0 = destPos ? destPos->X : 0;
\r
1365 v.y0 = destPos ? destPos->Y : 0;
\r
1366 v.x1 = v.x0 + ( sourceClip.x1 - sourceClip.x0 );
\r
1367 v.y1 = v.y0 + ( sourceClip.y1 - sourceClip.y0 );
\r
1369 if ( !intersect( job.Dest, destClip, v ) )
\r
1372 job.width = job.Dest.x1 - job.Dest.x0;
\r
1373 job.height = job.Dest.y1 - job.Dest.y0;
\r
1375 job.Source.x0 = sourceClip.x0 + ( job.Dest.x0 - v.x0 );
\r
1376 job.Source.x1 = job.Source.x0 + job.width;
\r
1377 job.Source.y0 = sourceClip.y0 + ( job.Dest.y0 - v.y0 );
\r
1378 job.Source.y1 = job.Source.y0 + job.height;
\r
1382 job.stretch = false;
\r
1383 job.x_stretch = 1.f;
\r
1384 job.y_stretch = 1.f;
\r
1388 job.srcPitch = source->getPitch();
\r
1389 job.srcPixelMul = source->getBytesPerPixel();
\r
1390 job.src = (void*) ( (u8*) source->getData() + ( job.Source.y0 * job.srcPitch ) + ( job.Source.x0 * job.srcPixelMul ) );
\r
1394 // use srcPitch for color operation on dest
\r
1395 job.srcPitch = job.width * dest->getBytesPerPixel();
\r
1398 job.dstPitch = dest->getPitch();
\r
1399 job.dstPixelMul = dest->getBytesPerPixel();
\r
1400 job.dst = (void*) ( (u8*) dest->getData() + ( job.Dest.y0 * job.dstPitch ) + ( job.Dest.x0 * job.dstPixelMul ) );
\r
1407 #if defined(SOFTWARE_DRIVER_2_2D_AS_2D)
\r
1408 static s32 StretchBlit(eBlitter operation,
\r
1409 video::IImage* dest, const core::rect<s32>* destClipping,const core::rect<s32> *destRect,
\r
1410 video::IImage* const source,const core::rect<s32> *srcRect, const core::dimension2d<u32>* source_org,
\r
1413 tExecuteBlit blitter = getBlitter2( operation, dest, source );
\r
1414 if ( 0 == blitter )
\r
1421 AbsRectangle destClip;
\r
1423 setClip(destClip, destClipping, dest, 0, 0);
\r
1424 setClip(v, destRect, 0, 1, 0);
\r
1425 if (!intersect(job.Dest, destClip, v))
\r
1429 setClip ( job.Source, srcRect, source, 1, source_org);
\r
1431 job.width = job.Dest.x1-job.Dest.x0;
\r
1432 job.height = job.Dest.y1-job.Dest.y0;
\r
1436 // use original dest size, despite any clipping
\r
1437 const int dst_w = v.x1 - v.x0; // destRect->getWidth();
\r
1438 const int dst_h = v.y1 - v.y0; // destRect->getHeight();
\r
1439 const int src_w = job.Source.x1 - job.Source.x0;
\r
1440 const int src_h = job.Source.y1 - job.Source.y0;
\r
1442 job.stretch = dst_w != src_w || dst_h != src_h;
\r
1443 job.x_stretch = dst_w ? (float)src_w / (float)dst_w : 1.f;
\r
1444 job.y_stretch = dst_h ? (float)src_h / (float)dst_h : 1.f;
\r
1449 job.srcPitch = source->getPitch();
\r
1450 job.srcPixelMul = source->getBytesPerPixel();
\r
1452 //dest-clippling. advance source. loosing subpixel precision
\r
1453 job.Source.x0 += (s32)floorf(job.x_stretch * (job.Dest.x0 - v.x0));
\r
1454 job.Source.y0 += (s32)floorf(job.y_stretch * (job.Dest.y0 - v.y0));
\r
1456 job.src = (void*) ( (u8*) source->getData() + ( job.Source.y0 * job.srcPitch ) + ( job.Source.x0 * job.srcPixelMul ) );
\r
1460 // use srcPitch for color operation on dest
\r
1461 job.srcPitch = job.width * dest->getBytesPerPixel();
\r
1464 job.dstPitch = dest->getPitch();
\r
1465 job.dstPixelMul = dest->getBytesPerPixel();
\r
1466 job.dst = (void*) ( (u8*) dest->getData() + ( job.Dest.y0 * job.dstPitch ) + ( job.Dest.x0 * job.dstPixelMul ) );
\r
1474 // Methods for Software drivers
\r
1475 //! draws a rectangle
\r
1476 static void drawRectangle(video::IImage* img, const core::rect<s32>& rect, const video::SColor &color)
\r
1478 Blit(color.getAlpha() == 0xFF ? BLITTER_COLOR : BLITTER_COLOR_ALPHA,
\r
1479 img, 0, &rect.UpperLeftCorner, 0, &rect, color.color);
\r
1483 //! draws a line from to with color
\r
1484 static void drawLine(video::IImage* img, const core::position2d<s32>& from,
\r
1485 const core::position2d<s32>& to, const video::SColor &color)
\r
1487 AbsRectangle clip;
\r
1488 GetClip(clip, img);
\r
1490 core::position2d<s32> p[2];
\r
1491 if (ClipLine( clip, p[0], p[1], from, to))
\r
1493 u32 alpha = extractAlpha(color.color);
\r
1495 switch(img->getColorFormat())
\r
1497 case video::ECF_A1R5G5B5:
\r
1500 RenderLine16_Decal(img, p[0], p[1], video::A8R8G8B8toA1R5G5B5(color.color));
\r
1504 RenderLine16_Blend(img, p[0], p[1], video::A8R8G8B8toA1R5G5B5(color.color), alpha >> 3);
\r
1507 case video::ECF_A8R8G8B8:
\r
1510 RenderLine32_Decal(img, p[0], p[1], color.color);
\r
1514 RenderLine32_Blend(img, p[0], p[1], color.color, alpha);
\r