See https://sourceforge.net/p/openil/patches/41/ This patch improves alpha-compositing in DevIL. --- src-IL/src/il_devil.c (revision 1654) +++ src-IL/src/il_devil.c (working copy) @@ -665,10 +665,10 @@ ILuint c; ILuint StartX, StartY, StartZ; ILboolean DestFlipped = IL_FALSE; + ILboolean DoAlphaBlend = IL_FALSE; ILubyte *SrcTemp; - ILfloat Back; - - // Check if the desiination image really exists + ILfloat ResultAlpha; + // Check if the destination image really exists if (DestName == 0 || iCurImage == NULL) { ilSetError(IL_ILLEGAL_OPERATION); return IL_FALSE; @@ -680,6 +680,9 @@ DestFlipped = IL_TRUE; ilFlipImage(); } + //determining destination alpha support + DoAlphaBlend = ilIsEnabled(IL_BLIT_BLEND); + //DestOrigin = Dest->Origin; ilBindImage(Source); @@ -688,7 +691,9 @@ ilSetError(IL_INVALID_PARAM); return IL_FALSE; } - + //determining source alpha support + DoAlphaBlend &= ilIsEnabled(IL_BLIT_BLEND); + Src = iCurImage; //@TODO test if coordinates are inside the images (hard limit for source) @@ -737,38 +742,49 @@ const ILuint SrcIndex = (z+SrcZ)*ConvSizePlane + (y+SrcY)*ConvBps + (x+SrcX)*Dest->Bpp; const ILuint DestIndex = (z+DestZ)*Dest->SizeOfPlane + (y+DestY)*Dest->Bps + (x+DestX)*Dest->Bpp; const ILuint AlphaIdx = SrcIndex + bpp_without_alpha; - ILfloat Front = 0; + ILfloat FrontAlpha = 0; // foreground opacity + ILfloat BackAlpha = 0; // background opacity switch (Dest->Type) { case IL_BYTE: case IL_UNSIGNED_BYTE: - Front = Converted[AlphaIdx]/((float)IL_MAX_UNSIGNED_BYTE); + FrontAlpha = Converted[AlphaIdx]/((float)IL_MAX_UNSIGNED_BYTE); + BackAlpha = Dest->Data[AlphaIdx]/((float)IL_MAX_UNSIGNED_BYTE); break; case IL_SHORT: case IL_UNSIGNED_SHORT: - Front = ((ILshort*)Converted)[AlphaIdx]/((float)IL_MAX_UNSIGNED_SHORT); + FrontAlpha = ((ILshort*)Converted)[AlphaIdx]/((float)IL_MAX_UNSIGNED_SHORT); + BackAlpha = ((ILshort*)Dest->Data)[AlphaIdx]/((float)IL_MAX_UNSIGNED_SHORT); break; case IL_INT: case IL_UNSIGNED_INT: - Front = ((ILint*)Converted)[AlphaIdx]/((float)IL_MAX_UNSIGNED_INT); + FrontAlpha = ((ILint*)Converted)[AlphaIdx]/((float)IL_MAX_UNSIGNED_INT); + BackAlpha = ((ILint*)Dest->Data)[AlphaIdx]/((float)IL_MAX_UNSIGNED_INT); break; case IL_FLOAT: - Front = ((ILfloat*)Converted)[AlphaIdx]; + FrontAlpha = ((ILfloat*)Converted)[AlphaIdx]; + BackAlpha = ((ILfloat*)Dest->Data)[AlphaIdx]; break; case IL_DOUBLE: - Front = (ILfloat)(((ILdouble*)Converted)[AlphaIdx]); + FrontAlpha = (ILfloat)(((ILdouble*)Converted)[AlphaIdx]); + BackAlpha = (ILfloat)(((ILdouble*)Dest->Data)[AlphaIdx]); break; } - Back = 1.0f - Front; - // In case of Alpha channel, the data is blended. Keeps the original alpha. - if (ilIsEnabled(IL_BLIT_BLEND)) { + + // In case of Alpha channel, the data is blended. + // Computes composite Alpha + if (DoAlphaBlend) + { + ResultAlpha = FrontAlpha + (1.0f - FrontAlpha) * BackAlpha; for (c = 0; c < bpp_without_alpha; c++) { - Dest->Data[DestIndex + c] = - (ILubyte)(Converted[SrcIndex + c] * Front - + Dest->Data[DestIndex + c] * Back); + Dest->Data[DestIndex + c] = (ILubyte)( 0.5f + + (Converted[SrcIndex + c] * FrontAlpha + + (1.0f - FrontAlpha) * Dest->Data[DestIndex + c] * BackAlpha) + / ResultAlpha); } + Dest->Data[AlphaIdx] = (ILubyte)(0.5f + ResultAlpha * (float)IL_MAX_UNSIGNED_BYTE); } else { for (c = 0; c < Dest->Bpp; c++)