IImage::copyToWithAlpha has a new parameter to allow combining alpha value instead of replacing them.
This uses new blitters called BLITTER_TEXTURE_COMBINE_ALPHA. Thx @chronologicaldot for providing this patch and @burningreggae for his feedback. git-svn-id: svn://svn.code.sf.net/p/irrlicht/code/trunk@5590 dfc29bdd-3216-0410-991c-e03cc46cb475master
parent
c0f0b50915
commit
c4247febe5
|
@ -1,5 +1,6 @@
|
|||
--------------------------
|
||||
Changes in 1.9 (not yet released)
|
||||
- IImage::copyToWithAlpha has a new parameter to allow combining alpha value instead of replacing them. This uses new blitters called BLITTER_TEXTURE_COMBINE_ALPHA. Thx @chronologicaldot for providing this patch and @burningreggae for his feedback.
|
||||
- Add _IRR_COMPILE_WITH_PARTICLES_ to control compilation of particle system
|
||||
- Add IGUIImage::setDrawBackground to allow disabling background drawing even when no texture is set.
|
||||
- Fix: IGUIContextMenu now raises sub-menu when they would otherwise be displayed below bottom-border of root gui element.
|
||||
|
|
|
@ -269,9 +269,12 @@ public:
|
|||
virtual void copyTo(IImage* target, const core::position2d<s32>& pos, const core::rect<s32>& sourceRect, const core::rect<s32>* clipRect=0) =0;
|
||||
|
||||
//! copies this surface into another, using the alpha mask and cliprect and a color to add with
|
||||
/** \param combineAlpha - When true then combine alpha channels. When false replace target image alpha with source image alpha.
|
||||
*/
|
||||
virtual void copyToWithAlpha(IImage* target, const core::position2d<s32>& pos,
|
||||
const core::rect<s32>& sourceRect, const SColor &color,
|
||||
const core::rect<s32>* clipRect = 0) =0;
|
||||
const core::rect<s32>* clipRect = 0,
|
||||
bool combineAlpha=false) =0;
|
||||
|
||||
//! copies this surface into another, scaling it to fit, applying a box filter
|
||||
virtual void copyToScalingBoxFilter(IImage* target, s32 bias = 0, bool blend = false) = 0;
|
||||
|
|
|
@ -981,6 +981,166 @@ static void executeBlit_ColorAlpha_32_to_32( const SBlitJob * job )
|
|||
}
|
||||
}
|
||||
|
||||
/*!
|
||||
Combine alpha channels (increases alpha / reduces transparency)
|
||||
*/
|
||||
static void executeBlit_TextureCombineColor_16_to_16( const SBlitJob * job )
|
||||
{
|
||||
const u32 w = job->width * 2;
|
||||
const u32 h = job->height * 2;
|
||||
u8* src = (u8*) job->src;
|
||||
u8* dst = (u8*) job->dst;
|
||||
|
||||
const u16 jobColor = video::A8R8G8B8toA1R5G5B5( job->argb );
|
||||
|
||||
/*
|
||||
Stretch not supported.
|
||||
*/
|
||||
for ( u32 dy = 0; dy != h; dy+=2 )
|
||||
{
|
||||
for ( u32 dx = 0; dx != w; dx+=2 )
|
||||
{
|
||||
const u16 src_x = src[dx] << 8 | src[dx+1];
|
||||
const u16 dst_x = dst[dx] << 8 | dst[dx+1];
|
||||
dst[dx] = PixelCombine16( dst_x, PixelMul16_2( src_x, jobColor ) );
|
||||
}
|
||||
src = (src) + job->srcPitch;
|
||||
dst = (dst) + job->dstPitch;
|
||||
}
|
||||
}
|
||||
|
||||
/*!
|
||||
Combine alpha channels (increases alpha / reduces transparency)
|
||||
*/
|
||||
static void executeBlit_TextureCombineColor_16_to_24( const SBlitJob * job )
|
||||
{
|
||||
const u32 w = job->width;
|
||||
const u32 h = job->height;
|
||||
const u16 *src = static_cast<const u16*>(job->src);
|
||||
u8 *dst = static_cast<u8*>(job->dst);
|
||||
|
||||
const u16 jobColor = video::A8R8G8B8toA1R5G5B5( job->argb );
|
||||
|
||||
if (job->stretch)
|
||||
{
|
||||
const float wscale = 1.f/job->x_stretch;
|
||||
const float hscale = 1.f/job->y_stretch;
|
||||
|
||||
for ( u32 dy = 0; dy < h; ++dy )
|
||||
{
|
||||
const u32 src_y = (u32)(dy*hscale);
|
||||
src = (u16*) ( (u8*) (job->src) + job->srcPitch*src_y );
|
||||
|
||||
for ( u32 dx = 0; dx < w; ++dx )
|
||||
{
|
||||
const u32 src_x = (u32)(dx*wscale);
|
||||
u32 color = PixelMul16_2( video::A1R5G5B5toA8R8G8B8(src[src_x]), jobColor);
|
||||
u8 * writeTo = &dst[dx * 3];
|
||||
if ( video::getAlpha(src[src_x]) > 0 ) // only overlay if source has visible alpha (alpha == 1)
|
||||
{
|
||||
*writeTo++ = (color >> 16)& 0xFF;
|
||||
*writeTo++ = (color >> 8) & 0xFF;
|
||||
*writeTo++ = color & 0xFF;
|
||||
}
|
||||
}
|
||||
dst += job->dstPitch;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
for ( u32 dy = 0; dy != h; ++dy )
|
||||
{
|
||||
for ( u32 dx = 0; dx != w; ++dx )
|
||||
{
|
||||
u32 color = PixelMul16_2( video::A1R5G5B5toA8R8G8B8(src[dx]), jobColor);
|
||||
u8 * writeTo = &dst[dx * 3];
|
||||
if ( video::getAlpha(src[dx]) > 0 ) // only overlay if source has visible alpha (alpha == 1)
|
||||
{
|
||||
*writeTo++ = (color >> 16)& 0xFF;
|
||||
*writeTo++ = (color >> 8) & 0xFF;
|
||||
*writeTo++ = color & 0xFF;
|
||||
}
|
||||
}
|
||||
|
||||
src = (u16*) ( (u8*) (src) + job->srcPitch );
|
||||
dst += job->dstPitch;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/*!
|
||||
Combine alpha channels (increases alpha / reduces transparency)
|
||||
Destination alpha is treated as full 255
|
||||
*/
|
||||
static void executeBlit_TextureCombineColor_32_to_24( const SBlitJob * job )
|
||||
{
|
||||
const u32 w = job->width;
|
||||
const u32 h = job->height;
|
||||
const u32 *src = static_cast<const u32*>(job->src);
|
||||
u8 *dst = static_cast<u8*>(job->dst);
|
||||
|
||||
if (job->stretch)
|
||||
{
|
||||
const float wscale = 1.f/job->x_stretch;
|
||||
const float hscale = 1.f/job->y_stretch;
|
||||
|
||||
for ( u32 dy = 0; dy < h; ++dy )
|
||||
{
|
||||
const u32 src_y = (u32)(dy*hscale);
|
||||
src = (u32*) ( (u8*) (job->src) + job->srcPitch*src_y);
|
||||
|
||||
for ( u32 dx = 0; dx < w; ++dx )
|
||||
{
|
||||
const u32 src_x = src[(u32)(dx*wscale)];
|
||||
u8* writeTo = &dst[dx * 3];
|
||||
const u32 dst_x = 0xFF000000 | writeTo[0] << 16 | writeTo[1] << 8 | writeTo[2];
|
||||
const u32 combo = PixelCombine32( dst_x, PixelMul32_2( src_x, job->argb ) );
|
||||
*writeTo++ = (combo >> 16) & 0xFF;
|
||||
*writeTo++ = (combo >> 8) & 0xFF;
|
||||
*writeTo++ = combo & 0xFF;
|
||||
}
|
||||
dst += job->dstPitch;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
for ( u32 dy = 0; dy != h; ++dy )
|
||||
{
|
||||
for ( u32 dx = 0; dx != w; ++dx )
|
||||
{
|
||||
u8* writeTo = &dst[dx * 3];
|
||||
const u32 dst_x = 0xFF000000 | writeTo[0] << 16 | writeTo[1] << 8 | writeTo[2];
|
||||
const u32 combo = PixelCombine32( dst_x, PixelMul32_2( src[dx], job->argb ) );
|
||||
*writeTo++ = (combo >> 16) & 0xFF;
|
||||
*writeTo++ = (combo >> 8) & 0xFF;
|
||||
*writeTo++ = combo & 0xFF;
|
||||
}
|
||||
|
||||
src = (u32*) ( (u8*) (src) + job->srcPitch );
|
||||
dst += job->dstPitch;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/*!
|
||||
Combine alpha channels (increases alpha / reduces transparency)
|
||||
*/
|
||||
static void executeBlit_TextureCombineColor_32_to_32( const SBlitJob * job )
|
||||
{
|
||||
u32 *src = (u32*) job->src;
|
||||
u32 *dst = (u32*) job->dst;
|
||||
|
||||
for ( s32 dy = 0; dy != job->height; ++dy )
|
||||
{
|
||||
for ( s32 dx = 0; dx != job->width; ++dx )
|
||||
{
|
||||
dst[dx] = PixelCombine32( dst[dx], PixelMul32_2( src[dx], job->argb ) );
|
||||
}
|
||||
src = (u32*) ( (u8*) (src) + job->srcPitch );
|
||||
dst = (u32*) ( (u8*) (dst) + job->dstPitch );
|
||||
}
|
||||
}
|
||||
|
||||
// Blitter Operation
|
||||
enum eBlitter
|
||||
{
|
||||
|
@ -989,7 +1149,8 @@ enum eBlitter
|
|||
BLITTER_COLOR_ALPHA,
|
||||
BLITTER_TEXTURE,
|
||||
BLITTER_TEXTURE_ALPHA_BLEND,
|
||||
BLITTER_TEXTURE_ALPHA_COLOR_BLEND
|
||||
BLITTER_TEXTURE_ALPHA_COLOR_BLEND,
|
||||
BLITTER_TEXTURE_COMBINE_ALPHA,
|
||||
};
|
||||
|
||||
typedef void (*tExecuteBlit) ( const SBlitJob * job );
|
||||
|
@ -1022,6 +1183,14 @@ static const blitterTable blitTable[] =
|
|||
{ BLITTER_COLOR, video::ECF_A8R8G8B8, -1, executeBlit_Color_32_to_32 },
|
||||
{ BLITTER_COLOR_ALPHA, video::ECF_A1R5G5B5, -1, executeBlit_ColorAlpha_16_to_16 },
|
||||
{ BLITTER_COLOR_ALPHA, video::ECF_A8R8G8B8, -1, executeBlit_ColorAlpha_32_to_32 },
|
||||
{ BLITTER_TEXTURE_COMBINE_ALPHA, video::ECF_A8R8G8B8, video::ECF_A8R8G8B8, executeBlit_TextureCombineColor_32_to_32 },
|
||||
{ BLITTER_TEXTURE_COMBINE_ALPHA, video::ECF_A8R8G8B8, video::ECF_R8G8B8, executeBlit_TextureCopy_24_to_32 },
|
||||
{ BLITTER_TEXTURE_COMBINE_ALPHA, video::ECF_R8G8B8, video::ECF_A8R8G8B8, executeBlit_TextureCombineColor_32_to_24 },
|
||||
{ BLITTER_TEXTURE_COMBINE_ALPHA, video::ECF_R8G8B8, video::ECF_R8G8B8, executeBlit_TextureCopy_x_to_x },
|
||||
{ BLITTER_TEXTURE_COMBINE_ALPHA, video::ECF_A1R5G5B5, video::ECF_R8G8B8, executeBlit_TextureCopy_24_to_16 },
|
||||
{ BLITTER_TEXTURE_COMBINE_ALPHA, video::ECF_A1R5G5B5, video::ECF_A1R5G5B5, executeBlit_TextureCombineColor_16_to_16 },
|
||||
{ BLITTER_TEXTURE_COMBINE_ALPHA, video::ECF_A1R5G5B5, video::ECF_R8G8B8, executeBlit_TextureCopy_24_to_16 },
|
||||
{ BLITTER_TEXTURE_COMBINE_ALPHA, video::ECF_R8G8B8, video::ECF_A1R5G5B5, executeBlit_TextureCombineColor_16_to_24 },
|
||||
{ BLITTER_INVALID, -1, -1, 0 }
|
||||
};
|
||||
|
||||
|
|
|
@ -149,7 +149,7 @@ void CImage::copyTo(IImage* target, const core::position2d<s32>& pos, const core
|
|||
|
||||
|
||||
//! copies this surface into another, using the alpha mask, a cliprect and a color to add with
|
||||
void CImage::copyToWithAlpha(IImage* target, const core::position2d<s32>& pos, const core::rect<s32>& sourceRect, const SColor &color, const core::rect<s32>* clipRect)
|
||||
void CImage::copyToWithAlpha(IImage* target, const core::position2d<s32>& pos, const core::rect<s32>& sourceRect, const SColor &color, const core::rect<s32>* clipRect, bool combineAlpha)
|
||||
{
|
||||
if (IImage::isCompressedFormat(Format))
|
||||
{
|
||||
|
@ -157,9 +157,16 @@ void CImage::copyToWithAlpha(IImage* target, const core::position2d<s32>& pos, c
|
|||
return;
|
||||
}
|
||||
|
||||
// color blend only necessary on not full spectrum aka. color.color != 0xFFFFFFFF
|
||||
Blit(color.color == 0xFFFFFFFF ? BLITTER_TEXTURE_ALPHA_BLEND: BLITTER_TEXTURE_ALPHA_COLOR_BLEND,
|
||||
target, clipRect, &pos, this, &sourceRect, color.color);
|
||||
if ( combineAlpha )
|
||||
{
|
||||
Blit(BLITTER_TEXTURE_COMBINE_ALPHA, target, clipRect, &pos, this, &sourceRect, color.color);
|
||||
}
|
||||
else
|
||||
{
|
||||
// color blend only necessary on not full spectrum aka. color.color != 0xFFFFFFFF
|
||||
Blit(color.color == 0xFFFFFFFF ? BLITTER_TEXTURE_ALPHA_BLEND: BLITTER_TEXTURE_ALPHA_COLOR_BLEND,
|
||||
target, clipRect, &pos, this, &sourceRect, color.color);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
|
|
@ -50,7 +50,7 @@ public:
|
|||
//! copies this surface into another, using the alpha mask, an cliprect and a color to add with
|
||||
virtual void copyToWithAlpha(IImage* target, const core::position2d<s32>& pos,
|
||||
const core::rect<s32>& sourceRect, const SColor &color,
|
||||
const core::rect<s32>* clipRect = 0) _IRR_OVERRIDE_;
|
||||
const core::rect<s32>* clipRect = 0, bool combineAlpha=false) _IRR_OVERRIDE_;
|
||||
|
||||
//! copies this surface into another, scaling it to fit, applying a box filter
|
||||
virtual void copyToScalingBoxFilter(IImage* target, s32 bias = 0, bool blend = false) _IRR_OVERRIDE_;
|
||||
|
|
|
@ -342,7 +342,7 @@ inline u32 PixelBlend16_simd ( const u32 c2, const u32 c1 )
|
|||
#endif
|
||||
|
||||
/*!
|
||||
Pixel = dest * ( 1 - SourceAlpha ) + source * SourceAlpha
|
||||
Pixel = dest * ( 1 - SourceAlpha ) + source * SourceAlpha (OpenGL blending)
|
||||
*/
|
||||
inline u32 PixelBlend32 ( const u32 c2, const u32 c1 )
|
||||
{
|
||||
|
@ -351,7 +351,6 @@ inline u32 PixelBlend32 ( const u32 c2, const u32 c1 )
|
|||
|
||||
if ( 0 == alpha )
|
||||
return c2;
|
||||
|
||||
if ( 0xFF000000 == alpha )
|
||||
{
|
||||
return c1;
|
||||
|
@ -386,6 +385,71 @@ inline u32 PixelBlend32 ( const u32 c2, const u32 c1 )
|
|||
return (c1 & 0xFF000000) | rb | xg;
|
||||
}
|
||||
|
||||
/*!
|
||||
Pixel =>
|
||||
color = sourceAlpha > 0 ? source, else dest
|
||||
alpha = max(destAlpha, sourceAlpha)
|
||||
*/
|
||||
inline u16 PixelCombine16 ( const u16 c2, const u16 c1 )
|
||||
{
|
||||
if ( video::getAlpha(c1) > 0 )
|
||||
return c1;
|
||||
else
|
||||
return c2;
|
||||
}
|
||||
|
||||
/*!
|
||||
Pixel =>
|
||||
color = dest * ( 1 - SourceAlpha ) + source * SourceAlpha,
|
||||
alpha = destAlpha * ( 1 - SourceAlpha ) + sourceAlpha
|
||||
|
||||
where "1" means "full scale" (255)
|
||||
*/
|
||||
inline u32 PixelCombine32 ( const u32 c2, const u32 c1 )
|
||||
{
|
||||
// alpha test
|
||||
u32 alpha = c1 & 0xFF000000;
|
||||
|
||||
if ( 0 == alpha )
|
||||
return c2;
|
||||
if ( 0xFF000000 == alpha )
|
||||
{
|
||||
return c1;
|
||||
}
|
||||
|
||||
alpha >>= 24;
|
||||
|
||||
// add highbit alpha, if ( alpha > 127 ) alpha += 1;
|
||||
// stretches [0;255] to [0;256] to avoid division by 255. use division 256 == shr 8
|
||||
alpha += ( alpha >> 7);
|
||||
|
||||
u32 srcRB = c1 & 0x00FF00FF;
|
||||
u32 srcXG = c1 & 0x0000FF00;
|
||||
|
||||
u32 dstRB = c2 & 0x00FF00FF;
|
||||
u32 dstXG = c2 & 0x0000FF00;
|
||||
|
||||
|
||||
u32 rb = srcRB - dstRB;
|
||||
u32 xg = srcXG - dstXG;
|
||||
|
||||
rb *= alpha;
|
||||
xg *= alpha;
|
||||
rb >>= 8;
|
||||
xg >>= 8;
|
||||
|
||||
rb += dstRB;
|
||||
xg += dstXG;
|
||||
|
||||
rb &= 0x00FF00FF;
|
||||
xg &= 0x0000FF00;
|
||||
|
||||
u32 sa = c1 >> 24;
|
||||
u32 da = c2 >> 24;
|
||||
u32 blendAlpha_fix8 = (sa*256 + da*(256-alpha))>>8;
|
||||
return blendAlpha_fix8 << 24 | rb | xg;
|
||||
}
|
||||
|
||||
|
||||
|
||||
// ------------------ Fix Point ----------------------------------
|
||||
|
|
Loading…
Reference in New Issue