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 inline void GetClip(AbsRectangle &clipping, video::IImage * t)
\r
94 clipping.x1 = t->getDimension().Width - 1;
\r
95 clipping.y1 = t->getDimension().Height - 1;
\r
99 return alpha in [0;256] Granularity from 32-Bit ARGB
\r
100 add highbit alpha ( alpha > 127 ? + 1 )
\r
102 static inline u32 extractAlpha(const u32 c)
\r
104 return ( c >> 24 ) + ( c >> 31 );
\r
108 return alpha in [0;255] Granularity and 32-Bit ARGB
\r
109 add highbit alpha ( alpha > 127 ? + 1 )
\r
111 static inline u32 packAlpha(const u32 c)
\r
113 return (c > 127 ? c - 1 : c) << 24;
\r
118 Scale Color by (1/value)
\r
119 value 0 - 256 ( alpha )
\r
121 inline u32 PixelLerp32(const u32 source, const u32 value)
\r
123 u32 srcRB = source & 0x00FF00FF;
\r
124 u32 srcXG = (source & 0xFF00FF00) >> 8;
\r
132 srcXG &= 0xFF00FF00;
\r
133 srcRB &= 0x00FF00FF;
\r
135 return srcRB | srcXG;
\r
141 static void executeBlit_TextureCopy_x_to_x( const SBlitJob * job )
\r
145 const f18 wscale = f32_to_f18(job->x_stretch);
\r
146 const f18 hscale = f32_to_f18(job->y_stretch);
\r
148 f18 src_y = f18_zero;
\r
150 if (job->srcPixelMul == 4)
\r
152 const u32 *src = (u32*)(job->src);
\r
153 u32 *dst = (u32*)(job->dst);
\r
155 for (u32 dy = 0; dy < job->height; ++dy, src_y += hscale)
\r
157 src = (u32*)((u8*)(job->src) + job->srcPitch*f18_floor(src_y));
\r
159 f18 src_x = f18_zero;
\r
160 for (u32 dx = 0; dx < job->width; ++dx, src_x += wscale)
\r
162 dst[dx] = src[f18_floor(src_x)];
\r
164 dst = (u32*)((u8*)(dst)+job->dstPitch);
\r
167 else if (job->srcPixelMul == 2)
\r
169 const u16 *src = (u16*)(job->src);
\r
170 u16* dst = (u16*)(job->dst);
\r
172 for (u32 dy = 0; dy < job->height; ++dy, src_y += hscale)
\r
174 src = (u16*)((u8*)(job->src) + job->srcPitch*f18_floor(src_y));
\r
176 f18 src_x = f18_zero;
\r
177 for (u32 dx = 0; dx < job->width; ++dx, src_x += wscale)
\r
179 dst[dx] = src[f18_floor(src_x)];
\r
181 dst = (u16*)((u8*)(dst)+job->dstPitch);
\r
187 const size_t widthPitch = job->width * job->dstPixelMul;
\r
188 const void *src = (void*) job->src;
\r
189 void *dst = (void*) job->dst;
\r
191 for ( u32 dy = 0; dy < job->height; ++dy )
\r
193 memcpy( dst, src, widthPitch);
\r
195 src = (void*) ( (u8*) (src) + job->srcPitch );
\r
196 dst = (void*) ( (u8*) (dst) + job->dstPitch );
\r
203 static void executeBlit_TextureCopy_32_to_16( const SBlitJob * job )
\r
205 const u32 w = job->width;
\r
206 const u32 h = job->height;
\r
207 const u32 *src = static_cast<const u32*>(job->src);
\r
208 u16 *dst = static_cast<u16*>(job->dst);
\r
212 const float wscale = job->x_stretch;
\r
213 const float hscale = job->y_stretch;
\r
215 for ( u32 dy = 0; dy < h; ++dy )
\r
217 const u32 src_y = (u32)(dy*hscale);
\r
218 src = (u32*) ( (u8*) (job->src) + job->srcPitch*src_y );
\r
220 for ( u32 dx = 0; dx < w; ++dx )
\r
222 const u32 src_x = (u32)(dx*wscale);
\r
223 //16 bit Blitter depends on pre-multiplied color
\r
224 const u32 s = PixelLerp32( src[src_x] | 0xFF000000, extractAlpha( src[src_x] ) );
\r
225 dst[dx] = video::A8R8G8B8toA1R5G5B5( s );
\r
227 dst = (u16*) ( (u8*) (dst) + job->dstPitch );
\r
232 for ( u32 dy = 0; dy != h; ++dy )
\r
234 for ( u32 dx = 0; dx != w; ++dx )
\r
236 //16 bit Blitter depends on pre-multiplied color
\r
237 const u32 s = PixelLerp32( src[dx] | 0xFF000000, extractAlpha( src[dx] ) );
\r
238 dst[dx] = video::A8R8G8B8toA1R5G5B5( s );
\r
241 src = (u32*) ( (u8*) (src) + job->srcPitch );
\r
242 dst = (u16*) ( (u8*) (dst) + job->dstPitch );
\r
249 static void executeBlit_TextureCopy_24_to_16( const SBlitJob * job )
\r
251 const u32 w = job->width;
\r
252 const u32 h = job->height;
\r
253 const u8 *src = static_cast<const u8*>(job->src);
\r
254 u16 *dst = static_cast<u16*>(job->dst);
\r
258 const float wscale = job->x_stretch * 3.f;
\r
259 const float hscale = job->y_stretch;
\r
261 for ( u32 dy = 0; dy < h; ++dy )
\r
263 const u32 src_y = (u32)(dy*hscale);
\r
264 src = (u8*)(job->src) + job->srcPitch*src_y;
\r
266 for ( u32 dx = 0; dx < w; ++dx )
\r
268 const u8* src_x = src+(u32)(dx*wscale);
\r
269 dst[dx] = video::RGBA16(src_x[0], src_x[1], src_x[2]);
\r
271 dst = (u16*) ( (u8*) (dst) + job->dstPitch );
\r
276 for ( u32 dy = 0; dy != h; ++dy )
\r
279 for ( u32 dx = 0; dx != w; ++dx )
\r
281 dst[dx] = video::RGBA16(s[0], s[1], s[2]);
\r
285 src = src+job->srcPitch;
\r
286 dst = (u16*) ( (u8*) (dst) + job->dstPitch );
\r
294 static void executeBlit_TextureCopy_16_to_32( const SBlitJob * job )
\r
296 const u32 w = job->width;
\r
297 const u32 h = job->height;
\r
298 const u16 *src = static_cast<const u16*>(job->src);
\r
299 u32 *dst = static_cast<u32*>(job->dst);
\r
303 const float wscale = job->x_stretch;
\r
304 const float hscale = job->y_stretch;
\r
306 for ( u32 dy = 0; dy < h; ++dy )
\r
308 const u32 src_y = (u32)(dy*hscale);
\r
309 src = (u16*) ( (u8*) (job->src) + job->srcPitch*src_y );
\r
311 for ( u32 dx = 0; dx < w; ++dx )
\r
313 const u32 src_x = (u32)(dx*wscale);
\r
314 dst[dx] = video::A1R5G5B5toA8R8G8B8(src[src_x]);
\r
316 dst = (u32*) ( (u8*) (dst) + job->dstPitch );
\r
321 for ( u32 dy = 0; dy != h; ++dy )
\r
323 for ( u32 dx = 0; dx != w; ++dx )
\r
325 dst[dx] = video::A1R5G5B5toA8R8G8B8( src[dx] );
\r
328 src = (u16*) ( (u8*) (src) + job->srcPitch );
\r
329 dst = (u32*) ( (u8*) (dst) + job->dstPitch );
\r
334 static void executeBlit_TextureCopy_16_to_24( const SBlitJob * job )
\r
336 const u32 w = job->width;
\r
337 const u32 h = job->height;
\r
338 const u16 *src = static_cast<const u16*>(job->src);
\r
339 u8 *dst = static_cast<u8*>(job->dst);
\r
343 const float wscale = job->x_stretch;
\r
344 const float hscale = job->y_stretch;
\r
346 for ( u32 dy = 0; dy < h; ++dy )
\r
348 const u32 src_y = (u32)(dy*hscale);
\r
349 src = (u16*) ( (u8*) (job->src) + job->srcPitch*src_y );
\r
351 for ( u32 dx = 0; dx < w; ++dx )
\r
353 const u32 src_x = (u32)(dx*wscale);
\r
354 u32 color = video::A1R5G5B5toA8R8G8B8(src[src_x]);
\r
355 u8 * writeTo = &dst[dx * 3];
\r
356 *writeTo++ = (color >> 16)& 0xFF;
\r
357 *writeTo++ = (color >> 8) & 0xFF;
\r
358 *writeTo++ = color & 0xFF;
\r
360 dst += job->dstPitch;
\r
365 for ( u32 dy = 0; dy != h; ++dy )
\r
367 for ( u32 dx = 0; dx != w; ++dx )
\r
369 u32 color = video::A1R5G5B5toA8R8G8B8(src[dx]);
\r
370 u8 * writeTo = &dst[dx * 3];
\r
371 *writeTo++ = (color >> 16)& 0xFF;
\r
372 *writeTo++ = (color >> 8) & 0xFF;
\r
373 *writeTo++ = color & 0xFF;
\r
376 src = (u16*) ( (u8*) (src) + job->srcPitch );
\r
377 dst += job->dstPitch;
\r
384 static void executeBlit_TextureCopy_24_to_32( const SBlitJob * job )
\r
386 const u32 w = job->width;
\r
387 const u32 h = job->height;
\r
388 const u8 *src = static_cast<const u8*>(job->src);
\r
389 u32 *dst = static_cast<u32*>(job->dst);
\r
393 const float wscale = job->x_stretch * 3.f;
\r
394 const float hscale = job->y_stretch;
\r
396 for ( u32 dy = 0; dy < h; ++dy )
\r
398 const u32 src_y = (u32)(dy*hscale);
\r
399 src = (const u8*)job->src+(job->srcPitch*src_y);
\r
401 for ( u32 dx = 0; dx < w; ++dx )
\r
403 const u8* s = src+(u32)(dx*wscale);
\r
404 dst[dx] = 0xFF000000 | s[0] << 16 | s[1] << 8 | s[2];
\r
406 dst = (u32*) ( (u8*) (dst) + job->dstPitch );
\r
411 for ( u32 dy = 0; dy < job->height; ++dy )
\r
415 for ( u32 dx = 0; dx < job->width; ++dx )
\r
417 dst[dx] = 0xFF000000 | s[0] << 16 | s[1] << 8 | s[2];
\r
421 src = src + job->srcPitch;
\r
422 dst = (u32*) ( (u8*) (dst) + job->dstPitch );
\r
427 static void executeBlit_TextureCopy_32_to_24( const SBlitJob * job )
\r
429 const u32 w = job->width;
\r
430 const u32 h = job->height;
\r
431 const u32 *src = static_cast<const u32*>(job->src);
\r
432 u8 *dst = static_cast<u8*>(job->dst);
\r
436 const float wscale = job->x_stretch;
\r
437 const float hscale = job->y_stretch;
\r
439 for ( u32 dy = 0; dy < h; ++dy )
\r
441 const u32 src_y = (u32)(dy*hscale);
\r
442 src = (u32*) ( (u8*) (job->src) + job->srcPitch*src_y);
\r
444 for ( u32 dx = 0; dx < w; ++dx )
\r
446 const u32 src_x = src[(u32)(dx*wscale)];
\r
447 u8 * writeTo = &dst[dx * 3];
\r
448 *writeTo++ = (src_x >> 16)& 0xFF;
\r
449 *writeTo++ = (src_x >> 8) & 0xFF;
\r
450 *writeTo++ = src_x & 0xFF;
\r
452 dst += job->dstPitch;
\r
457 for ( u32 dy = 0; dy != h; ++dy )
\r
459 for ( u32 dx = 0; dx != w; ++dx )
\r
461 u8 * writeTo = &dst[dx * 3];
\r
462 *writeTo++ = (src[dx] >> 16)& 0xFF;
\r
463 *writeTo++ = (src[dx] >> 8) & 0xFF;
\r
464 *writeTo++ = src[dx] & 0xFF;
\r
467 src = (u32*) ( (u8*) (src) + job->srcPitch );
\r
468 dst += job->dstPitch;
\r
475 static void executeBlit_TextureBlend_16_to_16( const SBlitJob * job )
\r
477 const f18 wscale = f32_to_f18(job->x_stretch);
\r
478 const f18 hscale = f32_to_f18(job->y_stretch);
\r
480 f18 src_y = f18_zero;
\r
481 u16 *dst = (u16*)job->dst;
\r
483 for (u32 dy = 0; dy < job->height; ++dy, src_y += hscale)
\r
485 const u16* src = (u16*)((u8*)(job->src) + job->srcPitch*f18_floor(src_y));
\r
486 f18 src_x = f18_zero;
\r
487 for (u32 dx = 0; dx < job->width; ++dx, src_x += wscale)
\r
489 dst[dx] = PixelBlend16(dst[dx], src[f18_floor(src_x)]);
\r
491 dst = (u16*)((u8*)(dst)+job->dstPitch);
\r
497 static void executeBlit_TextureBlend_32_to_32( const SBlitJob * job )
\r
499 const f18 wscale = f32_to_f18(job->x_stretch);
\r
500 const f18 hscale = f32_to_f18(job->y_stretch);
\r
502 f18 src_y = f18_zero;
\r
503 u32 *dst = (u32*)job->dst;
\r
504 for (u32 dy = 0; dy < job->height; ++dy, src_y += hscale)
\r
506 const u32* src = (u32*)((u8*)(job->src) + job->srcPitch*f18_floor(src_y));
\r
508 f18 src_x = f18_zero;
\r
509 for (u32 dx = 0; dx < job->width; ++dx, src_x += wscale)
\r
511 dst[dx] = PixelBlend32(dst[dx], src[f18_floor(src_x)]);
\r
513 dst = (u32*)((u8*)(dst)+job->dstPitch);
\r
519 static void executeBlit_TextureBlendColor_16_to_16( const SBlitJob * job )
\r
521 const u16 blend = video::A8R8G8B8toA1R5G5B5(job->argb);
\r
523 const f18 wscale = f32_to_f18(job->x_stretch);
\r
524 const f18 hscale = f32_to_f18(job->y_stretch);
\r
526 f18 src_y = f18_zero;
\r
527 u16 *dst = (u16*)job->dst;
\r
528 for (u32 dy = 0; dy < job->height; ++dy, src_y += hscale)
\r
530 const u16* src = (u16*)((u8*)(job->src) + job->srcPitch*f18_floor(src_y));
\r
531 f18 src_x = f18_zero;
\r
532 for (u32 dx = 0; dx < job->width; ++dx, src_x += wscale)
\r
534 u16 c0 = src[f18_floor(src_x)];
\r
535 if (0 == (c0 & 0x8000))
\r
538 dst[dx] = PixelMul16_2(c0, blend);
\r
540 dst = (u16*)((u8*)(dst)+job->dstPitch);
\r
547 static void executeBlit_TextureBlendColor_32_to_32( const SBlitJob * job )
\r
549 const f18 wscale = f32_to_f18(job->x_stretch);
\r
550 const f18 hscale = f32_to_f18(job->y_stretch);
\r
552 u32* dst = (u32*)job->dst;
\r
553 f18 src_y = f18_zero;
\r
554 for (u32 dy = 0; dy < job->height; ++dy, src_y += hscale)
\r
556 const u32* src = (u32*)((u8*)(job->src) + job->srcPitch*f18_floor(src_y));
\r
558 f18 src_x = f18_zero;
\r
559 for (u32 dx = 0; dx < job->width; ++dx, src_x += wscale)
\r
561 dst[dx] = PixelBlend32(dst[dx], PixelMul32_2(src[f18_floor(src_x)], job->argb));
\r
563 dst = (u32*)((u8*)(dst)+job->dstPitch);
\r
569 static void executeBlit_Color_16_to_16( const SBlitJob * job )
\r
571 const u16 c = video::A8R8G8B8toA1R5G5B5(job->argb);
\r
572 u16 *dst = (u16*) job->dst;
\r
574 for ( u32 dy = 0; dy < job->height; ++dy )
\r
576 memset16(dst, c, job->srcPitch);
\r
577 dst = (u16*) ( (u8*) (dst) + job->dstPitch );
\r
583 static void executeBlit_Color_32_to_32( const SBlitJob * job )
\r
585 u32 *dst = (u32*) job->dst;
\r
587 for ( u32 dy = 0; dy < job->height; ++dy )
\r
589 memset32( dst, job->argb, job->srcPitch );
\r
590 dst = (u32*) ( (u8*) (dst) + job->dstPitch );
\r
596 static void executeBlit_ColorAlpha_16_to_16( const SBlitJob * job )
\r
598 u16 *dst = (u16*) job->dst;
\r
600 const u16 alpha = extractAlpha( job->argb ) >> 3;
\r
603 const u32 src = video::A8R8G8B8toA1R5G5B5( job->argb );
\r
605 for ( u32 dy = 0; dy != job->height; ++dy )
\r
607 for ( u32 dx = 0; dx != job->width; ++dx )
\r
609 dst[dx] = PixelBlend16( dst[dx], src, alpha );
\r
611 dst = (u16*) ( (u8*) (dst) + job->dstPitch );
\r
617 static void executeBlit_ColorAlpha_32_to_32( const SBlitJob * job )
\r
619 const u32 alpha = extractAlpha( job->argb );
\r
623 u32 *dst = (u32*)job->dst;
\r
624 for ( u32 dy = 0; dy < job->height; ++dy )
\r
626 for ( u32 dx = 0; dx < job->width; ++dx )
\r
628 dst[dx] = PixelBlend32( dst[dx], job->argb, alpha );
\r
630 dst = (u32*) ( (u8*) (dst) + job->dstPitch );
\r
637 color = sourceAlpha > 0 ? source, else dest
\r
638 alpha = max(destAlpha, sourceAlpha)
\r
640 inline u16 PixelCombine16(const u16 c2, const u16 c1)
\r
642 if (video::getAlpha(c1) > 0)
\r
649 Combine alpha channels (increases alpha / reduces transparency)
\r
651 static void executeBlit_TextureCombineColor_16_to_16( const SBlitJob * job )
\r
653 const u32 w = job->width * 2;
\r
654 const u32 h = job->height * 2;
\r
655 u16* src = (u16*) job->src;
\r
656 u16* dst = (u16*) job->dst;
\r
658 const u16 jobColor = video::A8R8G8B8toA1R5G5B5( job->argb );
\r
661 Stretch not supported.
\r
663 for ( u32 dy = 0; dy != h; dy++ )
\r
665 for ( u32 dx = 0; dx != w; dx++ )
\r
667 const u16 src_x = src[dx];
\r
668 const u16 dst_x = dst[dx];
\r
669 dst[dx] = PixelCombine16( dst_x, PixelMul16_2( src_x, jobColor ) );
\r
671 src = (u16*) ( (u8*) (src) + job->srcPitch );
\r
672 dst = (u16*) ( (u8*) (dst) + job->dstPitch );
\r
677 Combine alpha channels (increases alpha / reduces transparency)
\r
679 static void executeBlit_TextureCombineColor_16_to_24( const SBlitJob * job )
\r
681 const u32 w = job->width;
\r
682 const u32 h = job->height;
\r
683 const u16 *src = static_cast<const u16*>(job->src);
\r
684 u8 *dst = static_cast<u8*>(job->dst);
\r
686 const u16 jobColor = video::A8R8G8B8toA1R5G5B5( job->argb );
\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 = PixelMul16_2( video::A1R5G5B5toA8R8G8B8(src[src_x]), jobColor);
\r
702 u8 * writeTo = &dst[dx * 3];
\r
703 if ( video::getAlpha(src[src_x]) > 0 ) // only overlay if source has visible alpha (alpha == 1)
\r
705 *writeTo++ = (color >> 16)& 0xFF;
\r
706 *writeTo++ = (color >> 8) & 0xFF;
\r
707 *writeTo++ = color & 0xFF;
\r
710 dst += job->dstPitch;
\r
715 for ( u32 dy = 0; dy != h; ++dy )
\r
717 for ( u32 dx = 0; dx != w; ++dx )
\r
719 u32 color = PixelMul16_2( video::A1R5G5B5toA8R8G8B8(src[dx]), jobColor);
\r
720 u8 * writeTo = &dst[dx * 3];
\r
721 if ( video::getAlpha(src[dx]) > 0 ) // only overlay if source has visible alpha (alpha == 1)
\r
723 *writeTo++ = (color >> 16)& 0xFF;
\r
724 *writeTo++ = (color >> 8) & 0xFF;
\r
725 *writeTo++ = color & 0xFF;
\r
729 src = (u16*) ( (u8*) (src) + job->srcPitch );
\r
730 dst += job->dstPitch;
\r
737 color = dest * ( 1 - SourceAlpha ) + source * SourceAlpha,
\r
738 alpha = destAlpha * ( 1 - SourceAlpha ) + sourceAlpha
\r
740 where "1" means "full scale" (255)
\r
742 inline u32 PixelCombine32(const u32 c2, const u32 c1)
\r
745 u32 alpha = c1 & 0xFF000000;
\r
749 if (0xFF000000 == alpha)
\r
756 // add highbit alpha, if ( alpha > 127 ) alpha += 1;
\r
757 // stretches [0;255] to [0;256] to avoid division by 255. use division 256 == shr 8
\r
758 alpha += (alpha >> 7);
\r
760 u32 srcRB = c1 & 0x00FF00FF;
\r
761 u32 srcXG = c1 & 0x0000FF00;
\r
763 u32 dstRB = c2 & 0x00FF00FF;
\r
764 u32 dstXG = c2 & 0x0000FF00;
\r
767 u32 rb = srcRB - dstRB;
\r
768 u32 xg = srcXG - dstXG;
\r
783 u32 blendAlpha_fix8 = (sa * 256 + da * (256 - alpha)) >> 8;
\r
784 return blendAlpha_fix8 << 24 | rb | xg;
\r
788 Combine alpha channels (increases alpha / reduces transparency)
\r
789 Destination alpha is treated as full 255
\r
791 static void executeBlit_TextureCombineColor_32_to_24( const SBlitJob * job )
\r
793 const u32 w = job->width;
\r
794 const u32 h = job->height;
\r
795 const u32 *src = static_cast<const u32*>(job->src);
\r
796 u8 *dst = static_cast<u8*>(job->dst);
\r
800 const float wscale = job->x_stretch;
\r
801 const float hscale = job->y_stretch;
\r
803 for ( u32 dy = 0; dy < h; ++dy )
\r
805 const u32 src_y = (u32)(dy*hscale);
\r
806 src = (u32*) ( (u8*) (job->src) + job->srcPitch*src_y);
\r
808 for ( u32 dx = 0; dx < w; ++dx )
\r
810 const u32 src_x = src[(u32)(dx*wscale)];
\r
811 u8* writeTo = &dst[dx * 3];
\r
812 const u32 dst_x = 0xFF000000 | writeTo[0] << 16 | writeTo[1] << 8 | writeTo[2];
\r
813 const u32 combo = PixelCombine32( dst_x, PixelMul32_2( src_x, job->argb ) );
\r
814 *writeTo++ = (combo >> 16) & 0xFF;
\r
815 *writeTo++ = (combo >> 8) & 0xFF;
\r
816 *writeTo++ = combo & 0xFF;
\r
818 dst += job->dstPitch;
\r
823 for ( u32 dy = 0; dy != h; ++dy )
\r
825 for ( u32 dx = 0; dx != w; ++dx )
\r
827 u8* writeTo = &dst[dx * 3];
\r
828 const u32 dst_x = 0xFF000000 | writeTo[0] << 16 | writeTo[1] << 8 | writeTo[2];
\r
829 const u32 combo = PixelCombine32( dst_x, PixelMul32_2( src[dx], job->argb ) );
\r
830 *writeTo++ = (combo >> 16) & 0xFF;
\r
831 *writeTo++ = (combo >> 8) & 0xFF;
\r
832 *writeTo++ = combo & 0xFF;
\r
835 src = (u32*) ( (u8*) (src) + job->srcPitch );
\r
836 dst += job->dstPitch;
\r
842 Combine alpha channels (increases alpha / reduces transparency)
\r
844 static void executeBlit_TextureCombineColor_32_to_32( const SBlitJob * job )
\r
846 u32 *src = (u32*) job->src;
\r
847 u32 *dst = (u32*) job->dst;
\r
849 for ( u32 dy = 0; dy != job->height; ++dy )
\r
851 for (u32 dx = 0; dx != job->width; ++dx )
\r
853 dst[dx] = PixelCombine32( dst[dx], PixelMul32_2( src[dx], job->argb ) );
\r
855 src = (u32*) ( (u8*) (src) + job->srcPitch );
\r
856 dst = (u32*) ( (u8*) (dst) + job->dstPitch );
\r
860 // Blitter Operation
\r
863 BLITTER_INVALID = 0,
\r
865 BLITTER_COLOR_ALPHA,
\r
867 BLITTER_TEXTURE_ALPHA_BLEND,
\r
868 BLITTER_TEXTURE_ALPHA_COLOR_BLEND,
\r
869 BLITTER_TEXTURE_COMBINE_ALPHA,
\r
872 typedef void (*tExecuteBlit) ( const SBlitJob * job );
\r
877 struct blitterTable
\r
879 eBlitter operation;
\r
885 static const blitterTable blitTable[] =
\r
887 { BLITTER_TEXTURE, -2, -2, executeBlit_TextureCopy_x_to_x },
\r
888 { BLITTER_TEXTURE, video::ECF_A1R5G5B5, video::ECF_A8R8G8B8, executeBlit_TextureCopy_32_to_16 },
\r
889 { BLITTER_TEXTURE, video::ECF_A1R5G5B5, video::ECF_R8G8B8, executeBlit_TextureCopy_24_to_16 },
\r
890 { BLITTER_TEXTURE, video::ECF_A8R8G8B8, video::ECF_A1R5G5B5, executeBlit_TextureCopy_16_to_32 },
\r
891 { BLITTER_TEXTURE, video::ECF_A8R8G8B8, video::ECF_R8G8B8, executeBlit_TextureCopy_24_to_32 },
\r
892 { BLITTER_TEXTURE, video::ECF_R8G8B8, video::ECF_A1R5G5B5, executeBlit_TextureCopy_16_to_24 },
\r
893 { BLITTER_TEXTURE, video::ECF_R8G8B8, video::ECF_A8R8G8B8, executeBlit_TextureCopy_32_to_24 },
\r
894 { BLITTER_TEXTURE_ALPHA_BLEND, video::ECF_A1R5G5B5, video::ECF_A1R5G5B5, executeBlit_TextureBlend_16_to_16 },
\r
895 { BLITTER_TEXTURE_ALPHA_BLEND, video::ECF_A8R8G8B8, video::ECF_A8R8G8B8, executeBlit_TextureBlend_32_to_32 },
\r
896 { BLITTER_TEXTURE_ALPHA_COLOR_BLEND, video::ECF_A1R5G5B5, video::ECF_A1R5G5B5, executeBlit_TextureBlendColor_16_to_16 },
\r
897 { BLITTER_TEXTURE_ALPHA_COLOR_BLEND, video::ECF_A8R8G8B8, video::ECF_A8R8G8B8, executeBlit_TextureBlendColor_32_to_32 },
\r
898 { BLITTER_COLOR, video::ECF_A1R5G5B5, -1, executeBlit_Color_16_to_16 },
\r
899 { BLITTER_COLOR, video::ECF_A8R8G8B8, -1, executeBlit_Color_32_to_32 },
\r
900 { BLITTER_COLOR_ALPHA, video::ECF_A1R5G5B5, -1, executeBlit_ColorAlpha_16_to_16 },
\r
901 { BLITTER_COLOR_ALPHA, video::ECF_A8R8G8B8, -1, executeBlit_ColorAlpha_32_to_32 },
\r
902 { BLITTER_TEXTURE_COMBINE_ALPHA, video::ECF_A8R8G8B8, video::ECF_A8R8G8B8, executeBlit_TextureCombineColor_32_to_32 },
\r
903 { BLITTER_TEXTURE_COMBINE_ALPHA, video::ECF_A8R8G8B8, video::ECF_R8G8B8, executeBlit_TextureCopy_24_to_32 },
\r
904 { BLITTER_TEXTURE_COMBINE_ALPHA, video::ECF_R8G8B8, video::ECF_A8R8G8B8, executeBlit_TextureCombineColor_32_to_24 },
\r
905 { BLITTER_TEXTURE_COMBINE_ALPHA, video::ECF_R8G8B8, video::ECF_R8G8B8, executeBlit_TextureCopy_x_to_x },
\r
906 { BLITTER_TEXTURE_COMBINE_ALPHA, video::ECF_A1R5G5B5, video::ECF_R8G8B8, executeBlit_TextureCopy_24_to_16 },
\r
907 { BLITTER_TEXTURE_COMBINE_ALPHA, video::ECF_A1R5G5B5, video::ECF_A1R5G5B5, executeBlit_TextureCombineColor_16_to_16 },
\r
908 { BLITTER_TEXTURE_COMBINE_ALPHA, video::ECF_A1R5G5B5, video::ECF_R8G8B8, executeBlit_TextureCopy_24_to_16 },
\r
909 { BLITTER_TEXTURE_COMBINE_ALPHA, video::ECF_R8G8B8, video::ECF_A1R5G5B5, executeBlit_TextureCombineColor_16_to_24 },
\r
910 { BLITTER_INVALID, -1, -1, 0 }
\r
914 static inline tExecuteBlit getBlitter2( eBlitter operation,const video::IImage * dest,const video::IImage * source )
\r
916 video::ECOLOR_FORMAT sourceFormat = (video::ECOLOR_FORMAT) ( source ? source->getColorFormat() : -1 );
\r
917 video::ECOLOR_FORMAT destFormat = (video::ECOLOR_FORMAT) ( dest ? dest->getColorFormat() : -1 );
\r
919 const blitterTable * b = blitTable;
\r
921 while ( b->operation != BLITTER_INVALID )
\r
923 if ( b->operation == operation )
\r
925 if (( b->destFormat == -1 || b->destFormat == destFormat ) &&
\r
926 ( b->sourceFormat == -1 || b->sourceFormat == sourceFormat ) )
\r
929 if ( b->destFormat == -2 && ( sourceFormat == destFormat ) )
\r
938 // bounce clipping to texture
\r
939 inline void setClip(AbsRectangle &out, const core::rect<s32> *clip,
\r
940 const video::IImage* tex, s32 passnative, const core::dimension2d<u32>* tex_org)
\r
944 if (clip && passnative)
\r
946 out.x0 = clip->UpperLeftCorner.X;
\r
947 out.x1 = clip->LowerRightCorner.X;
\r
948 out.y0 = clip->UpperLeftCorner.Y;
\r
949 out.y1 = clip->LowerRightCorner.Y;
\r
961 const s32 w = tex->getDimension().Width;
\r
962 const s32 h = tex->getDimension().Height;
\r
964 //driver could have changed texture size.
\r
965 if (clip && tex_org && ((u32)w != tex_org->Width || (u32)h != tex_org->Height))
\r
967 out.x0 = core::s32_clamp((clip->UpperLeftCorner.X*w) / tex_org->Width, 0, w - 1);
\r
968 out.x1 = core::s32_clamp((clip->LowerRightCorner.X*w) / tex_org->Width, out.x0, w);
\r
969 out.y0 = core::s32_clamp((clip->UpperLeftCorner.Y*h) / tex_org->Height, 0, h - 1);
\r
970 out.y1 = core::s32_clamp((clip->LowerRightCorner.Y*h) / tex_org->Height, out.y0, h);
\r
974 //y-1 to prevent starting on illegal memory (not ideal!).
\r
975 out.x0 = core::s32_clamp(clip->UpperLeftCorner.X, 0, w - 1);
\r
976 out.x1 = core::s32_clamp(clip->LowerRightCorner.X, passnative ? 0 : out.x0, w);
\r
977 out.y0 = core::s32_clamp(clip->UpperLeftCorner.Y, 0, h - 1);
\r
978 out.y1 = core::s32_clamp(clip->LowerRightCorner.Y, passnative ? 0 : out.y0, h);
\r
991 a generic 2D Blitter
\r
993 static s32 Blit(eBlitter operation,
\r
994 video::IImage * dest,
\r
995 const core::rect<s32> *destClipping,
\r
996 const core::position2d<s32> *destPos,
\r
997 video::IImage * const source,
\r
998 const core::rect<s32> *sourceClipping,
\r
1001 tExecuteBlit blitter = getBlitter2( operation, dest, source );
\r
1002 if ( 0 == blitter )
\r
1008 AbsRectangle sourceClip;
\r
1009 AbsRectangle destClip;
\r
1014 setClip ( sourceClip, sourceClipping, source, 1,0 );
\r
1015 setClip ( destClip, destClipping, dest, 0,0 );
\r
1017 v.x0 = destPos ? destPos->X : 0;
\r
1018 v.y0 = destPos ? destPos->Y : 0;
\r
1019 v.x1 = v.x0 + ( sourceClip.x1 - sourceClip.x0 );
\r
1020 v.y1 = v.y0 + ( sourceClip.y1 - sourceClip.y0 );
\r
1022 if ( !intersect( job.Dest, destClip, v ) )
\r
1025 job.width = job.Dest.x1 - job.Dest.x0;
\r
1026 job.height = job.Dest.y1 - job.Dest.y0;
\r
1028 job.Source.x0 = sourceClip.x0 + ( job.Dest.x0 - v.x0 );
\r
1029 job.Source.x1 = job.Source.x0 + job.width;
\r
1030 job.Source.y0 = sourceClip.y0 + ( job.Dest.y0 - v.y0 );
\r
1031 job.Source.y1 = job.Source.y0 + job.height;
\r
1035 job.stretch = false;
\r
1036 job.x_stretch = 1.f;
\r
1037 job.y_stretch = 1.f;
\r
1041 job.srcPitch = source->getPitch();
\r
1042 job.srcPixelMul = source->getBytesPerPixel();
\r
1043 job.src = (void*) ( (u8*) source->getData() + ( job.Source.y0 * job.srcPitch ) + ( job.Source.x0 * job.srcPixelMul ) );
\r
1047 // use srcPitch for color operation on dest
\r
1048 job.srcPitch = job.width * dest->getBytesPerPixel();
\r
1051 job.dstPitch = dest->getPitch();
\r
1052 job.dstPixelMul = dest->getBytesPerPixel();
\r
1053 job.dst = (void*) ( (u8*) dest->getData() + ( job.Dest.y0 * job.dstPitch ) + ( job.Dest.x0 * job.dstPixelMul ) );
\r