From e02141055a7336bb8bf617bfb985631ff2b22e44 Mon Sep 17 00:00:00 2001 From: Christian Walther Date: Fri, 30 Dec 2011 15:10:47 +0100 Subject: [PATCH] Use premultiplied alpha for plDynamicTextMaps on GUI controls. This fixes the irregular dark fringes around light text when not exactly pixel-aligned that are caused by independent interpolation of color and alpha. It also makes calculations simpler for things to come. --- .../Sources/Plasma/CoreLib/hsColorRGBA.h | 9 +++ .../pfGameGUIMgr/pfGUIControlMod.cpp | 3 +- .../Plasma/NucleusLib/inc/hsGMatState.h | 3 +- .../PubUtilLib/plGImage/plDynamicTextMap.cpp | 45 ++++++------- .../PubUtilLib/plGImage/plDynamicTextMap.h | 6 +- .../Plasma/PubUtilLib/plGImage/plFont.cpp | 63 ++++++++++++++++++- .../Plasma/PubUtilLib/plGImage/plFont.h | 2 + .../Plasma/PubUtilLib/plGImage/plMipmap.cpp | 22 ++++++- .../Plasma/PubUtilLib/plGImage/plMipmap.h | 13 ++-- .../PubUtilLib/plPipeline/plDXPipeline.cpp | 18 +++++- 10 files changed, 149 insertions(+), 35 deletions(-) diff --git a/MOULOpenSourceClientPlugin/Plasma20/Sources/Plasma/CoreLib/hsColorRGBA.h b/MOULOpenSourceClientPlugin/Plasma20/Sources/Plasma/CoreLib/hsColorRGBA.h index 115cb0a0..4522181f 100644 --- a/MOULOpenSourceClientPlugin/Plasma20/Sources/Plasma/CoreLib/hsColorRGBA.h +++ b/MOULOpenSourceClientPlugin/Plasma20/Sources/Plasma/CoreLib/hsColorRGBA.h @@ -71,6 +71,7 @@ struct hsColorRGBA { hsColorRGBA& FromARGB32(UInt32 c); UInt32 ToARGB32() const; + UInt32 ToARGB32Premultiplied() const; void Read(hsStream *stream); void Write(hsStream *stream) const; @@ -109,6 +110,14 @@ inline UInt32 hsColorRGBA::ToARGB32() const | (UInt32(b * 255.99f) << 0); } +inline UInt32 hsColorRGBA::ToARGB32Premultiplied() const +{ + return (UInt32(a * 255.0f + 0.5f) << 24) + | (UInt32(a * r * 255.0f + 0.5f) << 16) + | (UInt32(a * g * 255.0f + 0.5f) << 8) + | (UInt32(a * b * 255.0f + 0.5f) << 0); +} + inline hsColorRGBA operator+(const hsColorRGBA& s, const hsColorRGBA& t) { hsColorRGBA res; diff --git a/MOULOpenSourceClientPlugin/Plasma20/Sources/Plasma/FeatureLib/pfGameGUIMgr/pfGUIControlMod.cpp b/MOULOpenSourceClientPlugin/Plasma20/Sources/Plasma/FeatureLib/pfGameGUIMgr/pfGUIControlMod.cpp index 6742891f..1bd7b2ba 100644 --- a/MOULOpenSourceClientPlugin/Plasma20/Sources/Plasma/FeatureLib/pfGameGUIMgr/pfGUIControlMod.cpp +++ b/MOULOpenSourceClientPlugin/Plasma20/Sources/Plasma/FeatureLib/pfGameGUIMgr/pfGUIControlMod.cpp @@ -695,7 +695,7 @@ hsBool pfGUIControlMod::ISetUpDynTextMap( plPipeline *pipe ) extraH -= height; fDynTextMap->Reset(); - fDynTextMap->Create( width, height, HasFlag( kXparentBgnd ), extraW, extraH ); + fDynTextMap->Create( width, height, HasFlag( kXparentBgnd ), extraW, extraH, true ); fDynTextMap->SetFont( GetColorScheme()->fFontFace, GetColorScheme()->fFontSize, GetColorScheme()->fFontFlags, HasFlag( kXparentBgnd ) ? false : true ); @@ -706,6 +706,7 @@ hsBool pfGUIControlMod::ISetUpDynTextMap( plPipeline *pipe ) // out with 1:1 mapping from textel to pixel plLayer *layer = (plLayer *)fDynTextLayer; layer->SetTransform( fDynTextMap->GetLayerTransform() ); + layer->SetBlendFlags( layer->GetBlendFlags() | hsGMatState::kBlendAlphaPremultiplied ); // Let the derived classes do their things IPostSetUpDynTextMap(); diff --git a/MOULOpenSourceClientPlugin/Plasma20/Sources/Plasma/NucleusLib/inc/hsGMatState.h b/MOULOpenSourceClientPlugin/Plasma20/Sources/Plasma/NucleusLib/inc/hsGMatState.h index 4298f245..8b7288f3 100644 --- a/MOULOpenSourceClientPlugin/Plasma20/Sources/Plasma/NucleusLib/inc/hsGMatState.h +++ b/MOULOpenSourceClientPlugin/Plasma20/Sources/Plasma/NucleusLib/inc/hsGMatState.h @@ -85,7 +85,8 @@ enum hsGMatBlendFlags { kBlendEnvBumpNext = 0x800000, kBlendSubtract = 0x1000000, kBlendRevSubtract = 0x2000000, - kBlendAlphaTestHigh = 0x4000000 + kBlendAlphaTestHigh = 0x4000000, + kBlendAlphaPremultiplied = 0x8000000 }; enum hsGMatClampFlags { diff --git a/MOULOpenSourceClientPlugin/Plasma20/Sources/Plasma/PubUtilLib/plGImage/plDynamicTextMap.cpp b/MOULOpenSourceClientPlugin/Plasma20/Sources/Plasma/PubUtilLib/plGImage/plDynamicTextMap.cpp index c489e491..ca70c356 100644 --- a/MOULOpenSourceClientPlugin/Plasma20/Sources/Plasma/PubUtilLib/plGImage/plDynamicTextMap.cpp +++ b/MOULOpenSourceClientPlugin/Plasma20/Sources/Plasma/PubUtilLib/plGImage/plDynamicTextMap.cpp @@ -75,20 +75,12 @@ plProfile_Extern(MemMipmaps); //// Constructor & Destructor ///////////////////////////////////////////////// -plDynamicTextMap::plDynamicTextMap() : plMipmap() +plDynamicTextMap::plDynamicTextMap() + : fVisWidth(0), fVisHeight(0), fHasAlpha(false), fPremultipliedAlpha(false), fJustify(kLeftJustify), + fInitBuffer(nil), fFontFace(nil), fFontSize(0), fFontFlags(0), + fFontAntiAliasRGB(false), fFontBlockRGB(false), fHasCreateBeenCalled(false) { - fVisWidth = fVisHeight = 0; - fHasAlpha = false; - fJustify = kLeftJustify; - fInitBuffer = nil; - fFontFace = nil; - fFontSize = 0; - fFontFlags = 0; - fFontAntiAliasRGB = false; - fFontColor.Set( 0, 0, 0, 1 ); - fFontBlockRGB = false; - fHasCreateBeenCalled = false; - + fFontColor.Set(0, 0, 0, 1); } plDynamicTextMap::~plDynamicTextMap() @@ -96,11 +88,10 @@ plDynamicTextMap::~plDynamicTextMap() Reset(); } -plDynamicTextMap::plDynamicTextMap( UInt32 width, UInt32 height, hsBool hasAlpha, UInt32 extraWidth, UInt32 extraHeight ) : plMipmap() +plDynamicTextMap::plDynamicTextMap( UInt32 width, UInt32 height, hsBool hasAlpha, UInt32 extraWidth, UInt32 extraHeight, hsBool premultipliedAlpha ) + : fInitBuffer(nil), fFontFace(nil) { - fInitBuffer = nil; - fFontFace = nil; - Create( width, height, hasAlpha, extraWidth, extraHeight ); + Create( width, height, hasAlpha, extraWidth, extraHeight, premultipliedAlpha ); } //// SetNoCreate ////////////////////////////////////////////////////////////// @@ -122,7 +113,7 @@ void plDynamicTextMap::SetNoCreate( UInt32 width, UInt32 height, hsBool hasAlpha //// Create /////////////////////////////////////////////////////////////////// -void plDynamicTextMap::Create( UInt32 width, UInt32 height, hsBool hasAlpha, UInt32 extraWidth, UInt32 extraHeight ) +void plDynamicTextMap::Create( UInt32 width, UInt32 height, hsBool hasAlpha, UInt32 extraWidth, UInt32 extraHeight, hsBool premultipliedAlpha ) { SetConfig( hasAlpha ? kARGB32Config : kRGB32Config ); @@ -130,6 +121,7 @@ void plDynamicTextMap::Create( UInt32 width, UInt32 height, hsBool hasAlpha, UIn fVisWidth = (UInt16)width; fVisHeight = (UInt16)height; fHasAlpha = hasAlpha; + fPremultipliedAlpha = premultipliedAlpha; for( fWidth = 1; fWidth < width + extraWidth; fWidth <<= 1 ); for( fHeight = 1; fHeight < height + extraHeight; fHeight <<= 1 ); @@ -395,7 +387,7 @@ void plDynamicTextMap::ClearToColor( hsColorRGBA &color ) if( !IIsValid() ) return; - UInt32 i, hex = color.ToARGB32(); + UInt32 i, hex = fPremultipliedAlpha ? color.ToARGB32Premultiplied() : color.ToARGB32(); UInt32 *data = (UInt32 *)fImage; // Buffer is of size fVisWidth x fVisHeight, so we need a bit of work to do this right @@ -520,6 +512,7 @@ void plDynamicTextMap::DrawString( UInt16 x, UInt16 y, const wchar_t *text ) fCurrFont->SetRenderClipRect( 0, 0, fVisWidth, fVisHeight ); fCurrFont->SetRenderColor( fFontColor.ToARGB32() ); fCurrFont->SetRenderFlag( plFont::kRenderIntoAlpha, fFontBlockRGB ); + fCurrFont->SetRenderFlag( plFont::kRenderAlphaPremultiplied, fPremultipliedAlpha ); fCurrFont->RenderString( this, x, y, text ); } @@ -541,6 +534,7 @@ void plDynamicTextMap::DrawClippedString( Int16 x, Int16 y, const wchar_t *text, fCurrFont->SetRenderClipping( x, y, width, height ); fCurrFont->SetRenderColor( fFontColor.ToARGB32() ); fCurrFont->SetRenderFlag( plFont::kRenderIntoAlpha, fFontBlockRGB ); + fCurrFont->SetRenderFlag( plFont::kRenderAlphaPremultiplied, fPremultipliedAlpha ); fCurrFont->RenderString( this, x, y, text ); } @@ -561,6 +555,7 @@ void plDynamicTextMap::DrawClippedString( Int16 x, Int16 y, const wchar_t *text, SetJustify( fJustify ); fCurrFont->SetRenderClipping( clipX, clipY, width, height ); fCurrFont->SetRenderColor( fFontColor.ToARGB32() ); + fCurrFont->SetRenderFlag( plFont::kRenderAlphaPremultiplied, fPremultipliedAlpha ); fCurrFont->RenderString( this, x, y, text ); } @@ -582,6 +577,7 @@ void plDynamicTextMap::DrawWrappedString( UInt16 x, UInt16 y, const wchar_t *tex fCurrFont->SetRenderWrapping( x, y, width, height ); fCurrFont->SetRenderColor( fFontColor.ToARGB32() ); fCurrFont->SetRenderFlag( plFont::kRenderIntoAlpha, fFontBlockRGB ); + fCurrFont->SetRenderFlag( plFont::kRenderAlphaPremultiplied, fPremultipliedAlpha ); fCurrFont->RenderString( this, x, y, text, lastX, lastY ); } @@ -665,7 +661,7 @@ void plDynamicTextMap::FillRect( UInt16 x, UInt16 y, UInt16 width, UInt16 height width = (UInt16)(fWidth - x); // Gee, how hard can it REALLY be? - UInt32 i, hex = color.ToARGB32(); + UInt32 i, hex = fPremultipliedAlpha ? color.ToARGB32Premultiplied() : color.ToARGB32(); height += y; if( height > fHeight ) height = (UInt16)fHeight; @@ -690,7 +686,7 @@ void plDynamicTextMap::FrameRect( UInt16 x, UInt16 y, UInt16 width, UInt16 heigh height = (UInt16)(fHeight - y); // Shouldn't be much harder - UInt32 i, hex = color.ToARGB32(); + UInt32 i, hex = fPremultipliedAlpha ? color.ToARGB32Premultiplied() : color.ToARGB32(); UInt32 *dest1, *dest2; dest1 = GetAddr32( x, y ); @@ -725,6 +721,9 @@ void plDynamicTextMap::DrawImage( UInt16 x, UInt16 y, plMipmap *image, DrawMetho else if( method == kImgSprite ) opts.fFlags = plMipmap::kCopySrcAlpha; + if( fPremultipliedAlpha ) + opts.fFlags |= plMipmap::kDestPremultiplied; + Composite( image, x, y, &opts ); /// HACK for now, since the alpha in the mipmap gets copied straight into the @@ -763,6 +762,9 @@ void plDynamicTextMap::DrawClippedImage( UInt16 x, UInt16 y, plMipmap *image, else if( method == kImgSprite ) opts.fFlags = plMipmap::kCopySrcAlpha; + if( fPremultipliedAlpha ) + opts.fFlags |= plMipmap::kDestPremultiplied; + opts.fSrcClipX = srcClipX; opts.fSrcClipY = srcClipY; opts.fSrcClipWidth = srcClipWidth; @@ -909,6 +911,7 @@ void plDynamicTextMap::Swap( plDynamicTextMap *other ) // Swap DTMap info SWAP_ME( hsBool, fHasAlpha, other->fHasAlpha ); + SWAP_ME( hsBool, fPremultipliedAlpha, other->fPremultipliedAlpha ); SWAP_ME( hsBool, fShadowed, other->fShadowed ); SWAP_ME( Justify, fJustify, other->fJustify ); diff --git a/MOULOpenSourceClientPlugin/Plasma20/Sources/Plasma/PubUtilLib/plGImage/plDynamicTextMap.h b/MOULOpenSourceClientPlugin/Plasma20/Sources/Plasma/PubUtilLib/plGImage/plDynamicTextMap.h index 7b38c7fb..b8162ef7 100644 --- a/MOULOpenSourceClientPlugin/Plasma20/Sources/Plasma/PubUtilLib/plGImage/plDynamicTextMap.h +++ b/MOULOpenSourceClientPlugin/Plasma20/Sources/Plasma/PubUtilLib/plGImage/plDynamicTextMap.h @@ -113,14 +113,14 @@ class plDynamicTextMap : public plMipmap plDynamicTextMap(); - plDynamicTextMap( UInt32 width, UInt32 height, hsBool hasAlpha = false, UInt32 extraWidth = 0, UInt32 extraHeight = 0 ); + plDynamicTextMap( UInt32 width, UInt32 height, hsBool hasAlpha = false, UInt32 extraWidth = 0, UInt32 extraHeight = 0, hsBool premultipliedAlpha = false ); virtual ~plDynamicTextMap(); CLASSNAME_REGISTER( plDynamicTextMap ); GETINTERFACE_ANY( plDynamicTextMap, plMipmap ); - void Create( UInt32 width, UInt32 height, hsBool hasAlpha, UInt32 extraWidth = 0, UInt32 extraHeight = 0 ); + void Create( UInt32 width, UInt32 height, hsBool hasAlpha, UInt32 extraWidth = 0, UInt32 extraHeight = 0, hsBool premultipliedAlpha = false ); void SetNoCreate( UInt32 width, UInt32 height, hsBool hasAlpha ); virtual void Reset( void ); @@ -222,7 +222,7 @@ class plDynamicTextMap : public plMipmap UInt32 *IAllocateOSSurface( UInt16 width, UInt16 height ); void IDestroyOSSurface( void ); - hsBool fHasAlpha, fShadowed; + hsBool fHasAlpha, fPremultipliedAlpha, fShadowed; Justify fJustify; char *fFontFace; diff --git a/MOULOpenSourceClientPlugin/Plasma20/Sources/Plasma/PubUtilLib/plGImage/plFont.cpp b/MOULOpenSourceClientPlugin/Plasma20/Sources/Plasma/PubUtilLib/plGImage/plFont.cpp index 8e581617..ebc8fb6d 100644 --- a/MOULOpenSourceClientPlugin/Plasma20/Sources/Plasma/PubUtilLib/plGImage/plFont.cpp +++ b/MOULOpenSourceClientPlugin/Plasma20/Sources/Plasma/PubUtilLib/plGImage/plFont.cpp @@ -345,7 +345,9 @@ void plFont::IRenderString( plMipmap *mip, UInt16 x, UInt16 y, const wchar_t *st { if( fRenderInfo.fFlags & kRenderIntoAlpha ) { - if( ( fRenderInfo.fColor & 0xff000000 ) != 0xff000000 ) + if( fRenderInfo.fFlags & kRenderAlphaPremultiplied ) + fRenderInfo.fRenderFunc = &plFont::IRenderChar8To32AlphaPremultiplied; + else if( ( fRenderInfo.fColor & 0xff000000 ) != 0xff000000 ) fRenderInfo.fRenderFunc = &plFont::IRenderChar8To32Alpha; else fRenderInfo.fRenderFunc = &plFont::IRenderChar8To32FullAlpha; @@ -1032,6 +1034,65 @@ void plFont::IRenderChar8To32Alpha( const plFont::plCharacter &c ) } } +void plFont::IRenderChar8To32AlphaPremultiplied( const plFont::plCharacter &c ) +{ + UInt8 *src = fBMapData + c.fBitmapOff; + UInt32 *destPtr, *destBasePtr = (UInt32 *)( fRenderInfo.fDestPtr - c.fBaseline * fRenderInfo.fDestStride ); + Int16 x, y, thisHeight, xstart, thisWidth; + UInt8 srcA, srcR, srcG, srcB; + + + // Unfortunately for some fonts, their right kern value actually is + // farther left than the right edge of the bitmap (think of overlapping + // script fonts). Ideally, we should store the actual width of each char's + // bitmap and use that here. However, it really shouldn't make too big of a + // difference, especially since the dest pixels that we end up overlapping + // should already be in the cache. If it does, time to upgrade the font + // format (again) + thisWidth = fWidth;// + (Int32)c.fRightKern; + if( thisWidth >= fRenderInfo.fMaxWidth ) + thisWidth = fRenderInfo.fMaxWidth; + + xstart = fRenderInfo.fClipRect.fX - fRenderInfo.fX; + if( xstart < 0 ) + xstart = 0; + + srcA = (UInt8)(( fRenderInfo.fColor >> 24 ) & 0x000000ff); + srcR = (UInt8)(( fRenderInfo.fColor >> 16 ) & 0x000000ff); + srcG = (UInt8)(( fRenderInfo.fColor >> 8 ) & 0x000000ff); + srcB = (UInt8)(( fRenderInfo.fColor ) & 0x000000ff); + + y = fRenderInfo.fClipRect.fY - fRenderInfo.fY + (Int16)c.fBaseline; + if( y < 0 ) + y = 0; + else + { + destBasePtr = (UInt32 *)( (UInt8 *)destBasePtr + y*fRenderInfo.fDestStride ); + src += y*fRenderInfo.fNumCols; + } + + thisHeight = fRenderInfo.fMaxHeight + (Int16)c.fBaseline; + if( thisHeight > (Int16)c.fHeight ) + thisHeight = (Int16)c.fHeight; + + for( ; y < thisHeight; y++ ) + { + destPtr = destBasePtr; + for( x = xstart; x < thisWidth; x++ ) + { + UInt32 a = src[ x ]; + if (a != 0) + { + if (srcA != 0xff) + a = (srcA*a + 127)/255; + destPtr[ x ] = ( a << 24 ) | (((srcR*a + 127)/255) << 16) | (((srcG*a + 127)/255) << 8) | ((srcB*a + 127)/255); + } + } + destBasePtr = (UInt32 *)( (UInt8 *)destBasePtr + fRenderInfo.fDestStride ); + src += fWidth; + } +} + void plFont::IRenderCharNull( const plCharacter &c ) { diff --git a/MOULOpenSourceClientPlugin/Plasma20/Sources/Plasma/PubUtilLib/plGImage/plFont.h b/MOULOpenSourceClientPlugin/Plasma20/Sources/Plasma/PubUtilLib/plGImage/plFont.h index d2b7dd7a..11e38ca3 100644 --- a/MOULOpenSourceClientPlugin/Plasma20/Sources/Plasma/PubUtilLib/plGImage/plFont.h +++ b/MOULOpenSourceClientPlugin/Plasma20/Sources/Plasma/PubUtilLib/plGImage/plFont.h @@ -116,6 +116,7 @@ class plFont : public hsKeyedObject // value between the renderColor and the destColor and // leave the alpha as-is // This flag has no effect on monochrome fonts + kRenderAlphaPremultiplied = 0x00001000, // Destination has color values premultiplied by alpha }; enum Flags @@ -231,6 +232,7 @@ class plFont : public hsKeyedObject void IRenderChar8To32( const plCharacter &c ); void IRenderChar8To32Alpha( const plCharacter &c ); void IRenderChar8To32FullAlpha( const plCharacter &c ); + void IRenderChar8To32AlphaPremultiplied( const plCharacter &c ); void IRenderCharNull( const plCharacter &c ); public: diff --git a/MOULOpenSourceClientPlugin/Plasma20/Sources/Plasma/PubUtilLib/plGImage/plMipmap.cpp b/MOULOpenSourceClientPlugin/Plasma20/Sources/Plasma/PubUtilLib/plGImage/plMipmap.cpp index a7c30af0..93786dfa 100644 --- a/MOULOpenSourceClientPlugin/Plasma20/Sources/Plasma/PubUtilLib/plGImage/plMipmap.cpp +++ b/MOULOpenSourceClientPlugin/Plasma20/Sources/Plasma/PubUtilLib/plGImage/plMipmap.cpp @@ -1745,6 +1745,18 @@ void plMipmap::Composite( plMipmap *source, UInt16 x, UInt16 y, plMipmap::Compos for( pY = (UInt16)srcHeight; pY > 0; pY-- ) { memcpy( dstPtr, srcPtr, srcRowBytesToCopy ); + if( options->fFlags & kDestPremultiplied ) + { + // multiply color values by alpha + for( pX = 0; pX < srcWidth; pX++ ) + { + srcAlpha = ((dstPtr[ pX ] >> 24) & 0x000000ff); + dstPtr[ pX ] = ( srcAlpha << 24 ) + | (((((dstPtr[ pX ] >> 16) & 0xff)*srcAlpha + 127)/255) << 16) + | (((((dstPtr[ pX ] >> 8) & 0xff)*srcAlpha + 127)/255) << 8) + | (((((dstPtr[ pX ] ) & 0xff)*srcAlpha + 127)/255) ); + } + } dstPtr += dstRowBytes >> 2; srcPtr += srcRowBytes >> 2; } @@ -1776,7 +1788,15 @@ void plMipmap::Composite( plMipmap *source, UInt16 x, UInt16 y, plMipmap::Compos { srcAlpha = options->fOpacity * ( ( srcPtr[ pX ] >> 16 ) & 0x0000ff00 ) / 255 / 256; if( srcAlpha != 0 ) - dstPtr[ pX ] = ( srcPtr[ pX ] & 0x00ffffff ) | ( srcAlpha << 24 ); + { + if( options->fFlags & kDestPremultiplied ) + dstPtr[ pX ] = ( srcAlpha << 24 ) + | (((((srcPtr[ pX ] >> 16) & 0xff)*srcAlpha + 127)/255) << 16) + | (((((srcPtr[ pX ] >> 8) & 0xff)*srcAlpha + 127)/255) << 8) + | (((((srcPtr[ pX ] ) & 0xff)*srcAlpha + 127)/255) ); + else + dstPtr[ pX ] = ( srcPtr[ pX ] & 0x00ffffff ) | ( srcAlpha << 24 ); + } } dstPtr += dstRowBytes >> 2; srcPtr += srcRowBytes >> 2; diff --git a/MOULOpenSourceClientPlugin/Plasma20/Sources/Plasma/PubUtilLib/plGImage/plMipmap.h b/MOULOpenSourceClientPlugin/Plasma20/Sources/Plasma/PubUtilLib/plGImage/plMipmap.h index 720b8838..79b3568c 100644 --- a/MOULOpenSourceClientPlugin/Plasma20/Sources/Plasma/PubUtilLib/plGImage/plMipmap.h +++ b/MOULOpenSourceClientPlugin/Plasma20/Sources/Plasma/PubUtilLib/plGImage/plMipmap.h @@ -233,11 +233,14 @@ class plMipmap : public plBitmap enum CompositeFlags { - kForceOpaque = 0x0001, // Copy src pixels raw, force dest alphas to opaque - kCopySrcAlpha = 0x0002, // Copy the src pixels raw, including alphas, overwrite dest - kBlendSrcAlpha = 0x0004, // Blend src pixels onto dest using src alpha, dest alpha = src alpha - kMaskSrcAlpha = 0x0008, // Same as copySrcAlpha, but dest is untouched when src alpha = 0 - kBlendWriteAlpha= 0x0010 // Like default (0), but writes dest alpha values + kForceOpaque = 0x0001, // Copy src pixels raw, force dest alphas to opaque + kCopySrcAlpha = 0x0002, // Copy the src pixels raw, including alphas, overwrite dest + kBlendSrcAlpha = 0x0004, // Blend src pixels onto dest using src alpha, dest alpha = src alpha + kMaskSrcAlpha = 0x0008, // Same as copySrcAlpha, but dest is untouched when src alpha = 0 + kBlendWriteAlpha = 0x0010, // Like default (0), but writes dest alpha values + + kDestPremultiplied = 0x0020, // Dest has color premultiplied by alpha + // (src always assumed nonpremultiplied for now) }; class CompositeOptions diff --git a/MOULOpenSourceClientPlugin/Plasma20/Sources/Plasma/PubUtilLib/plPipeline/plDXPipeline.cpp b/MOULOpenSourceClientPlugin/Plasma20/Sources/Plasma/PubUtilLib/plPipeline/plDXPipeline.cpp index 684bea34..0e1fd56c 100644 --- a/MOULOpenSourceClientPlugin/Plasma20/Sources/Plasma/PubUtilLib/plPipeline/plDXPipeline.cpp +++ b/MOULOpenSourceClientPlugin/Plasma20/Sources/Plasma/PubUtilLib/plPipeline/plDXPipeline.cpp @@ -7229,12 +7229,26 @@ void plDXPipeline::IHandleFirstStageBlend() fD3DDevice->SetRenderState( D3DRS_ALPHABLENDENABLE, TRUE ); if( fLayerState[0].fBlendFlags & hsGMatState::kBlendInvertFinalAlpha ) { - fD3DDevice->SetRenderState( D3DRS_SRCBLEND, D3DBLEND_INVSRCALPHA ); + if( fLayerState[0].fBlendFlags & hsGMatState::kBlendAlphaPremultiplied ) + { + fD3DDevice->SetRenderState( D3DRS_SRCBLEND, D3DBLEND_ONE ); + } + else + { + fD3DDevice->SetRenderState( D3DRS_SRCBLEND, D3DBLEND_INVSRCALPHA ); + } fD3DDevice->SetRenderState( D3DRS_DESTBLEND, D3DBLEND_SRCALPHA ); } else { - fD3DDevice->SetRenderState( D3DRS_SRCBLEND, D3DBLEND_SRCALPHA ); + if( fLayerState[0].fBlendFlags & hsGMatState::kBlendAlphaPremultiplied ) + { + fD3DDevice->SetRenderState( D3DRS_SRCBLEND, D3DBLEND_ONE ); + } + else + { + fD3DDevice->SetRenderState( D3DRS_SRCBLEND, D3DBLEND_SRCALPHA ); + } fD3DDevice->SetRenderState( D3DRS_DESTBLEND, D3DBLEND_INVSRCALPHA ); } break;