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 0f539c32..1bd7b2ba 100644 --- a/MOULOpenSourceClientPlugin/Plasma20/Sources/Plasma/FeatureLib/pfGameGUIMgr/pfGUIControlMod.cpp +++ b/MOULOpenSourceClientPlugin/Plasma20/Sources/Plasma/FeatureLib/pfGameGUIMgr/pfGUIControlMod.cpp @@ -56,6 +56,7 @@ You can contact Cyan Worlds, Inc. by email legal@cyan.com #include "../pnMessage/plRefMsg.h" #include "../pnMessage/plEnableMsg.h" #include "../pfMessage/pfGameGUIMsg.h" +#include "../plMessage/plDeviceRecreateMsg.h" #include "../pnSceneObject/plDrawInterface.h" #include "../pnSceneObject/plCoordinateInterface.h" #include "../pnSceneObject/plAudioInterface.h" @@ -584,14 +585,16 @@ plProfile_CreateTimer("Gui", "RenderSetup", GUITime); hsBool pfGUIControlMod::MsgReceive( plMessage *msg ) { plRenderMsg* rend = plRenderMsg::ConvertNoRef( msg ); + plDeviceRecreateMsg* device = plDeviceRecreateMsg::ConvertNoRef(msg); + if (rend || device) { + plPipeline* pipe = rend ? rend->Pipeline() : device->Pipeline(); - if( rend ) - { plProfile_BeginLap(GUITime, this->GetKey()->GetUoid().GetObjectName()); - // Only need it once - if( ISetUpDynTextMap( rend->Pipeline() ) ) - plgDispatch::Dispatch()->UnRegisterForExactType( plRenderMsg::Index(), GetKey() ); + ISetUpDynTextMap(pipe); plProfile_EndLap(GUITime, this->GetKey()->GetUoid().GetObjectName()); + + if (rend) + plgDispatch::Dispatch()->UnRegisterForExactType(plRenderMsg::Index(), GetKey()); return true; } @@ -603,12 +606,16 @@ hsBool pfGUIControlMod::MsgReceive( plMessage *msg ) if( refMsg->GetContext() & ( plRefMsg::kOnCreate | plRefMsg::kOnRequest | plRefMsg::kOnReplace ) ) { fDynTextMap = plDynamicTextMap::ConvertNoRef( refMsg->GetRef() ); - // Register for a render msg so we can leech the material when we finally - // have a pipeline to work with + + // These tell us when we need to (re-)initialize the DTM plgDispatch::Dispatch()->RegisterForExactType( plRenderMsg::Index(), GetKey() ); + plgDispatch::Dispatch()->RegisterForExactType( plDeviceRecreateMsg::Index(), GetKey() ); } else + { fDynTextMap = nil; + plgDispatch::Dispatch()->UnRegisterForExactType( plDeviceRecreateMsg::Index(), GetKey() ); + } return true; } else if( refMsg->fType == kRefDynTextLayer ) @@ -688,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 ); @@ -699,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/FeatureLib/pfGameGUIMgr/pfGUIControlMod.h b/MOULOpenSourceClientPlugin/Plasma20/Sources/Plasma/FeatureLib/pfGameGUIMgr/pfGUIControlMod.h index ad5f99ce..4cfacfd2 100644 --- a/MOULOpenSourceClientPlugin/Plasma20/Sources/Plasma/FeatureLib/pfGameGUIMgr/pfGUIControlMod.h +++ b/MOULOpenSourceClientPlugin/Plasma20/Sources/Plasma/FeatureLib/pfGameGUIMgr/pfGUIControlMod.h @@ -247,6 +247,8 @@ class pfGUIControlMod : public plSingleModifier virtual void SetColorScheme( pfGUIColorScheme *newScheme ); pfGUIColorScheme *GetColorScheme( void ) const; + virtual void UpdateColorScheme() { IPostSetUpDynTextMap(); IUpdate(); } + // should be override by specific GUIcontrol virtual void PurgeDynaTextMapImage() {;} diff --git a/MOULOpenSourceClientPlugin/Plasma20/Sources/Plasma/FeatureLib/pfGameGUIMgr/pfGUIEditBoxMod.cpp b/MOULOpenSourceClientPlugin/Plasma20/Sources/Plasma/FeatureLib/pfGameGUIMgr/pfGUIEditBoxMod.cpp index 10083906..df0c8fb6 100644 --- a/MOULOpenSourceClientPlugin/Plasma20/Sources/Plasma/FeatureLib/pfGameGUIMgr/pfGUIEditBoxMod.cpp +++ b/MOULOpenSourceClientPlugin/Plasma20/Sources/Plasma/FeatureLib/pfGameGUIMgr/pfGUIEditBoxMod.cpp @@ -197,9 +197,9 @@ void pfGUIEditBoxMod::IUpdate( void ) oldCursorPos = cursorPos; cursorPos -= (Int16)fScrollPos; - if( 4 + cursorPos > fDynTextMap->GetVisibleWidth() - 18 ) + if( 4 + cursorPos > fDynTextMap->GetVisibleWidth() - 4 - 2 ) { - fScrollPos += ( 4 + cursorPos ) - ( fDynTextMap->GetVisibleWidth() - 18 ); + fScrollPos += ( 4 + cursorPos ) - ( fDynTextMap->GetVisibleWidth() - 4 - 2 ); } else if( 4 + cursorPos < 4 ) { diff --git a/MOULOpenSourceClientPlugin/Plasma20/Sources/Plasma/FeatureLib/pfGameGUIMgr/pfGUIListBoxMod.cpp b/MOULOpenSourceClientPlugin/Plasma20/Sources/Plasma/FeatureLib/pfGameGUIMgr/pfGUIListBoxMod.cpp index 0fc191f9..4ab10cab 100644 --- a/MOULOpenSourceClientPlugin/Plasma20/Sources/Plasma/FeatureLib/pfGameGUIMgr/pfGUIListBoxMod.cpp +++ b/MOULOpenSourceClientPlugin/Plasma20/Sources/Plasma/FeatureLib/pfGameGUIMgr/pfGUIListBoxMod.cpp @@ -180,6 +180,10 @@ hsBool pfGUIListBoxMod::MsgReceive( plMessage *msg ) void pfGUIListBoxMod::IPostSetUpDynTextMap( void ) { + pfGUIColorScheme *scheme = GetColorScheme(); + fDynTextMap->SetFont( scheme->fFontFace, scheme->fFontSize, scheme->fFontFlags, + !HasFlag( kXparentBgnd )); + ICalcWrapStarts(); ICalcScrollRange(); fReadyToRoll = true; diff --git a/MOULOpenSourceClientPlugin/Plasma20/Sources/Plasma/FeatureLib/pfGameGUIMgr/pfGUIMultiLineEditCtrl.h b/MOULOpenSourceClientPlugin/Plasma20/Sources/Plasma/FeatureLib/pfGameGUIMgr/pfGUIMultiLineEditCtrl.h index 9d90d5c9..8b0afd6c 100644 --- a/MOULOpenSourceClientPlugin/Plasma20/Sources/Plasma/FeatureLib/pfGameGUIMgr/pfGUIMultiLineEditCtrl.h +++ b/MOULOpenSourceClientPlugin/Plasma20/Sources/Plasma/FeatureLib/pfGameGUIMgr/pfGUIMultiLineEditCtrl.h @@ -216,6 +216,8 @@ class pfGUIMultiLineEditCtrl : public pfGUIControlMod virtual void PurgeDynaTextMapImage(); + virtual void UpdateColorScheme() { fFontFlagsSet = 0; pfGUIControlMod::UpdateColorScheme(); } + // Extended event types enum ExtendedEvents { diff --git a/MOULOpenSourceClientPlugin/Plasma20/Sources/Plasma/FeatureLib/pfGameGUIMgr/pfGUITextBoxMod.h b/MOULOpenSourceClientPlugin/Plasma20/Sources/Plasma/FeatureLib/pfGameGUIMgr/pfGUITextBoxMod.h index 232ead11..202a7f6f 100644 --- a/MOULOpenSourceClientPlugin/Plasma20/Sources/Plasma/FeatureLib/pfGameGUIMgr/pfGUITextBoxMod.h +++ b/MOULOpenSourceClientPlugin/Plasma20/Sources/Plasma/FeatureLib/pfGameGUIMgr/pfGUITextBoxMod.h @@ -102,8 +102,6 @@ class pfGUITextBoxMod : public pfGUIControlMod void SetLocalizationPath(const wchar_t* path); void SetLocalizationPath(const char* path); void SetUseLocalizationPath(bool use); - - virtual void UpdateColorScheme() { IPostSetUpDynTextMap(); IUpdate(); } }; #endif // _pfGUITextBoxMod_h diff --git a/MOULOpenSourceClientPlugin/Plasma20/Sources/Plasma/FeatureLib/pfPython/pyDynamicTextGlue.cpp b/MOULOpenSourceClientPlugin/Plasma20/Sources/Plasma/FeatureLib/pfPython/pyDynamicTextGlue.cpp index 134809c6..bbdfbd60 100644 --- a/MOULOpenSourceClientPlugin/Plasma20/Sources/Plasma/FeatureLib/pfPython/pyDynamicTextGlue.cpp +++ b/MOULOpenSourceClientPlugin/Plasma20/Sources/Plasma/FeatureLib/pfPython/pyDynamicTextGlue.cpp @@ -491,4 +491,10 @@ void pyDynamicText::AddPlasmaConstantsClasses(PyObject *m) PYTHON_ENUM_ELEMENT(PtJustify, kLeftJustify, plDynamicTextMap::Justify::kLeftJustify); PYTHON_ENUM_ELEMENT(PtJustify, kRightJustify, plDynamicTextMap::Justify::kRightJustify); PYTHON_ENUM_END(m, PtJustify); + + PYTHON_ENUM_START(PtFontFlags); + PYTHON_ENUM_ELEMENT(PtFontFlags, kFontBold, plDynamicTextMap::kFontBold); + PYTHON_ENUM_ELEMENT(PtFontFlags, kFontItalic, plDynamicTextMap::kFontItalic); + PYTHON_ENUM_ELEMENT(PtFontFlags, kFontShadowed, plDynamicTextMap::kFontShadowed); + PYTHON_ENUM_END(m, PtFontFlags); } \ No newline at end of file diff --git a/MOULOpenSourceClientPlugin/Plasma20/Sources/Plasma/FeatureLib/pfPython/pyGUIControl.cpp b/MOULOpenSourceClientPlugin/Plasma20/Sources/Plasma/FeatureLib/pfPython/pyGUIControl.cpp index 2e9abc65..a7160ba4 100644 --- a/MOULOpenSourceClientPlugin/Plasma20/Sources/Plasma/FeatureLib/pfPython/pyGUIControl.cpp +++ b/MOULOpenSourceClientPlugin/Plasma20/Sources/Plasma/FeatureLib/pfPython/pyGUIControl.cpp @@ -278,7 +278,7 @@ PyObject* pyGUIControl::GetOwnerDlg( void ) } // get color schemes -PyObject* pyGUIControl::GetForeColor() +PyObject* pyGUIControl::GetForeColor() const { if ( fGCkey ) { @@ -292,7 +292,7 @@ PyObject* pyGUIControl::GetForeColor() PYTHON_RETURN_NONE; } -PyObject* pyGUIControl::GetSelColor() +PyObject* pyGUIControl::GetSelColor() const { if ( fGCkey ) { @@ -306,7 +306,7 @@ PyObject* pyGUIControl::GetSelColor() PYTHON_RETURN_NONE; } -PyObject* pyGUIControl::GetBackColor() +PyObject* pyGUIControl::GetBackColor() const { if ( fGCkey ) { @@ -320,7 +320,7 @@ PyObject* pyGUIControl::GetBackColor() PYTHON_RETURN_NONE; } -PyObject* pyGUIControl::GetBackSelColor() +PyObject* pyGUIControl::GetBackSelColor() const { if ( fGCkey ) { @@ -334,7 +334,7 @@ PyObject* pyGUIControl::GetBackSelColor() PYTHON_RETURN_NONE; } -UInt32 pyGUIControl::GetFontSize() +UInt32 pyGUIControl::GetFontSize() const { if ( fGCkey ) { @@ -444,3 +444,34 @@ void pyGUIControl::SetFontSize(UInt32 fontsize) } } } + +void pyGUIControl::SetFontFlags(UInt8 fontFlags) +{ + if (fGCkey) + { + // get the pointer to the modifier + pfGUIControlMod* pdmod = pfGUIControlMod::ConvertNoRef(fGCkey->ObjectIsLoaded()); + if (pdmod) + { + pfGUIColorScheme* colorscheme = pdmod->GetColorScheme(); + colorscheme->fFontFlags = fontFlags; + pdmod->UpdateColorScheme(); + } + } +} + +UInt8 pyGUIControl::GetFontFlags() const +{ + if (fGCkey) + { + // get the pointer to the modifier + pfGUIControlMod* pdmod = pfGUIControlMod::ConvertNoRef(fGCkey->ObjectIsLoaded()); + if (pdmod) + { + pfGUIColorScheme* colorscheme = pdmod->GetColorScheme(); + return colorscheme->fFontFlags; + } + } + return 0; +} + diff --git a/MOULOpenSourceClientPlugin/Plasma20/Sources/Plasma/FeatureLib/pfPython/pyGUIControl.h b/MOULOpenSourceClientPlugin/Plasma20/Sources/Plasma/FeatureLib/pfPython/pyGUIControl.h index 7444495b..d5b9ee46 100644 --- a/MOULOpenSourceClientPlugin/Plasma20/Sources/Plasma/FeatureLib/pfPython/pyGUIControl.h +++ b/MOULOpenSourceClientPlugin/Plasma20/Sources/Plasma/FeatureLib/pfPython/pyGUIControl.h @@ -116,17 +116,19 @@ public: virtual PyObject* GetOwnerDlg( void ); // returns pyGUIDialog // get color schemes - virtual PyObject* GetForeColor(); // returns pyColor - virtual PyObject* GetSelColor(); // returns pyColor - virtual PyObject* GetBackColor(); // returns pyColor - virtual PyObject* GetBackSelColor(); // returns pyColor - virtual UInt32 GetFontSize(); + virtual PyObject* GetForeColor() const; // returns pyColor + virtual PyObject* GetSelColor() const; // returns pyColor + virtual PyObject* GetBackColor() const; // returns pyColor + virtual PyObject* GetBackSelColor() const; // returns pyColor + virtual UInt32 GetFontSize() const; + virtual UInt8 GetFontFlags() const; // set color scheme virtual void SetForeColor( hsScalar r, hsScalar g, hsScalar b, hsScalar a ); virtual void SetSelColor( hsScalar r, hsScalar g, hsScalar b, hsScalar a ); virtual void SetBackColor( hsScalar r, hsScalar g, hsScalar b, hsScalar a ); virtual void SetBackSelColor( hsScalar r, hsScalar g, hsScalar b, hsScalar a ); virtual void SetFontSize(UInt32 fontsize); + virtual void SetFontFlags(UInt8 fontflags); }; diff --git a/MOULOpenSourceClientPlugin/Plasma20/Sources/Plasma/FeatureLib/pfPython/pyGUIControlGlue.cpp b/MOULOpenSourceClientPlugin/Plasma20/Sources/Plasma/FeatureLib/pfPython/pyGUIControlGlue.cpp index 935e8d06..932e771b 100644 --- a/MOULOpenSourceClientPlugin/Plasma20/Sources/Plasma/FeatureLib/pfPython/pyGUIControlGlue.cpp +++ b/MOULOpenSourceClientPlugin/Plasma20/Sources/Plasma/FeatureLib/pfPython/pyGUIControlGlue.cpp @@ -244,6 +244,23 @@ PYTHON_METHOD_DEFINITION_NOARGS(ptGUIControl, getFontSize) return PyLong_FromUnsignedLong(self->fThis->GetFontSize()); } +PYTHON_METHOD_DEFINITION_NOARGS(ptGUIControl, getFontFlags) +{ + return PyInt_FromLong(self->fThis->GetFontFlags()); +} + +PYTHON_METHOD_DEFINITION(ptGUIControl, setFontFlags, args) +{ + unsigned char fontflags; + if (!PyArg_ParseTuple(args, "b", &fontflags)) + { + PyErr_SetString(PyExc_TypeError, "setFontFlags expects an unsigned 8-bit int"); + PYTHON_RETURN_ERROR; + } + self->fThis->SetFontFlags(fontflags); + PYTHON_RETURN_NONE; +} + PYTHON_METHOD_DEFINITION(ptGUIControl, setForeColor, args) { float r, g, b, a; @@ -329,11 +346,13 @@ PYTHON_START_METHODS_TABLE(ptGUIControl) PYTHON_METHOD_NOARGS(ptGUIControl, getBackColor, "Returns the background color"), PYTHON_METHOD_NOARGS(ptGUIControl, getBackSelectColor, "Returns the background selection color"), PYTHON_METHOD_NOARGS(ptGUIControl, getFontSize, "Returns the font size"), + PYTHON_METHOD_NOARGS(ptGUIControl, getFontFlags, "Returns the current fontflags"), PYTHON_METHOD(ptGUIControl, setForeColor, "Params: r,g,b,a\nSets the foreground color"), PYTHON_METHOD(ptGUIControl, setSelectColor, "Params: r,g,b,a\nSets the selection color"), PYTHON_METHOD(ptGUIControl, setBackColor, "Params: r,g,b,a\nSets the background color"), PYTHON_METHOD(ptGUIControl, setBackSelectColor, "Params: r,g,b,a\nSets the selection background color"), PYTHON_METHOD(ptGUIControl, setFontSize, "Params: fontSize\nSets the font size"), + PYTHON_METHOD(ptGUIControl, setFontFlags, "Params: fontflags\nSets current fontflags"), PYTHON_END_METHODS_TABLE; // Type structure definition diff --git a/MOULOpenSourceClientPlugin/Plasma20/Sources/Plasma/FeatureLib/pfPython/pyGUIControlTextBox.cpp b/MOULOpenSourceClientPlugin/Plasma20/Sources/Plasma/FeatureLib/pfPython/pyGUIControlTextBox.cpp index ff625fe9..fecd6c43 100644 --- a/MOULOpenSourceClientPlugin/Plasma20/Sources/Plasma/FeatureLib/pfPython/pyGUIControlTextBox.cpp +++ b/MOULOpenSourceClientPlugin/Plasma20/Sources/Plasma/FeatureLib/pfPython/pyGUIControlTextBox.cpp @@ -214,3 +214,4 @@ UInt8 pyGUIControlTextBox::GetJustify() } return pfGUIListText::kLeftJustify; } + diff --git a/MOULOpenSourceClientPlugin/Plasma20/Sources/Plasma/FeatureLib/pfPython/pyGUIControlTextBox.h b/MOULOpenSourceClientPlugin/Plasma20/Sources/Plasma/FeatureLib/pfPython/pyGUIControlTextBox.h index a4e6f97a..fdc0565a 100644 --- a/MOULOpenSourceClientPlugin/Plasma20/Sources/Plasma/FeatureLib/pfPython/pyGUIControlTextBox.h +++ b/MOULOpenSourceClientPlugin/Plasma20/Sources/Plasma/FeatureLib/pfPython/pyGUIControlTextBox.h @@ -88,6 +88,7 @@ public: virtual void SetForeColor( pyColor& color ); virtual void SetBackColor( pyColor& color ); virtual void SetJustify( UInt8 justify ); + virtual UInt8 GetJustify(); virtual PyObject* GetForeColor(); // returns pyColor }; diff --git a/MOULOpenSourceClientPlugin/Plasma20/Sources/Plasma/FeatureLib/pfPython/pyGUIControlTextBoxGlue.cpp b/MOULOpenSourceClientPlugin/Plasma20/Sources/Plasma/FeatureLib/pfPython/pyGUIControlTextBoxGlue.cpp index 55d7f973..c20de702 100644 --- a/MOULOpenSourceClientPlugin/Plasma20/Sources/Plasma/FeatureLib/pfPython/pyGUIControlTextBoxGlue.cpp +++ b/MOULOpenSourceClientPlugin/Plasma20/Sources/Plasma/FeatureLib/pfPython/pyGUIControlTextBoxGlue.cpp @@ -185,6 +185,8 @@ PYTHON_METHOD_DEFINITION(ptGUIControlTextBox, setStringJustify, args) PYTHON_RETURN_NONE; } + + PYTHON_METHOD_DEFINITION_NOARGS(ptGUIControlTextBox, getStringJustify) { return PyInt_FromLong(self->fThis->GetJustify()); 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 262244a5..2ab6565c 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 ); @@ -388,6 +380,17 @@ void plDynamicTextMap::IClearFromBuffer( UInt32 *clearBuffer ) } } +//// IPropagateFlags ////////////////////////////////////////////////////////// + +void plDynamicTextMap::IPropagateFlags() +{ + SetJustify(fJustify); + fCurrFont->SetRenderFlag(plFont::kRenderShadow, fFontFlags & kFontShadowed); + fCurrFont->SetRenderFlag(plFont::kRenderIntoAlpha, fFontBlockRGB); + fCurrFont->SetRenderFlag(plFont::kRenderAlphaPremultiplied, fPremultipliedAlpha); + fCurrFont->SetRenderColor(fFontColor.ToARGB32()); +} + //// ClearToColor ///////////////////////////////////////////////////////////// void plDynamicTextMap::ClearToColor( hsColorRGBA &color ) @@ -395,7 +398,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 @@ -462,6 +465,8 @@ void plDynamicTextMap::SetFont( const char *face, UInt16 size, UInt8 fontFlags, // This will be nil if we're just running the page optimizer. if (fCurrFont) { + if (fFontFlags & kFontShadowed) + fCurrFont->SetRenderFlag(plFont::kRenderShadow, true); fCurrFont->SetRenderYJustify( plFont::kRenderJustYTop ); SetJustify( fJustify ); } @@ -515,10 +520,9 @@ void plDynamicTextMap::DrawString( UInt16 x, UInt16 y, const wchar_t *text ) if( !IIsValid() ) return; - SetJustify( fJustify ); + IPropagateFlags(); fCurrFont->SetRenderFlag( plFont::kRenderWrap | plFont::kRenderClip, false ); - fCurrFont->SetRenderColor( fFontColor.ToARGB32() ); - fCurrFont->SetRenderFlag( plFont::kRenderIntoAlpha, fFontBlockRGB ); + fCurrFont->SetRenderClipRect( 0, 0, fVisWidth, fVisHeight ); fCurrFont->RenderString( this, x, y, text ); } @@ -536,10 +540,8 @@ void plDynamicTextMap::DrawClippedString( Int16 x, Int16 y, const wchar_t *text, if( !IIsValid() ) return; - SetJustify( fJustify ); + IPropagateFlags(); fCurrFont->SetRenderClipping( x, y, width, height ); - fCurrFont->SetRenderColor( fFontColor.ToARGB32() ); - fCurrFont->SetRenderFlag( plFont::kRenderIntoAlpha, fFontBlockRGB ); fCurrFont->RenderString( this, x, y, text ); } @@ -557,9 +559,8 @@ void plDynamicTextMap::DrawClippedString( Int16 x, Int16 y, const wchar_t *text, if( !IIsValid() ) return; - SetJustify( fJustify ); + IPropagateFlags(); fCurrFont->SetRenderClipping( clipX, clipY, width, height ); - fCurrFont->SetRenderColor( fFontColor.ToARGB32() ); fCurrFont->RenderString( this, x, y, text ); } @@ -577,10 +578,8 @@ void plDynamicTextMap::DrawWrappedString( UInt16 x, UInt16 y, const wchar_t *tex if( !IIsValid() ) return; - SetJustify( fJustify ); + IPropagateFlags(); fCurrFont->SetRenderWrapping( x, y, width, height ); - fCurrFont->SetRenderColor( fFontColor.ToARGB32() ); - fCurrFont->SetRenderFlag( plFont::kRenderIntoAlpha, fFontBlockRGB ); fCurrFont->RenderString( this, x, y, text, lastX, lastY ); } @@ -664,7 +663,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; @@ -689,7 +688,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 ); @@ -724,6 +723,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 @@ -762,6 +764,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; @@ -908,6 +913,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..453a0afe 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,9 @@ class plDynamicTextMap : public plMipmap UInt32 *IAllocateOSSurface( UInt16 width, UInt16 height ); void IDestroyOSSurface( void ); - hsBool fHasAlpha, fShadowed; + void IPropagateFlags(); + + 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 efdf8384..4e8eacf3 100644 --- a/MOULOpenSourceClientPlugin/Plasma20/Sources/Plasma/PubUtilLib/plGImage/plFont.cpp +++ b/MOULOpenSourceClientPlugin/Plasma20/Sources/Plasma/PubUtilLib/plGImage/plFont.cpp @@ -345,7 +345,14 @@ 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 ) + { + if (fRenderInfo.fFlags & kRenderShadow) + fRenderInfo.fRenderFunc = &plFont::IRenderChar8To32AlphaPremShadow; + else + fRenderInfo.fRenderFunc = &plFont::IRenderChar8To32AlphaPremultiplied; + } + else if( ( fRenderInfo.fColor & 0xff000000 ) != 0xff000000 ) fRenderInfo.fRenderFunc = &plFont::IRenderChar8To32Alpha; else fRenderInfo.fRenderFunc = &plFont::IRenderChar8To32FullAlpha; @@ -659,24 +666,27 @@ void plFont::IRenderString( plMipmap *mip, UInt16 x, UInt16 y, const wchar_t *st // Advance left past any clipping area CharRenderFunc oldFunc = fRenderInfo.fRenderFunc; fRenderInfo.fRenderFunc = &plFont::IRenderCharNull; - while( fRenderInfo.fX < fRenderInfo.fClipRect.fX && *string != 0 ) + Int16 prevX; + do { + prevX = fRenderInfo.fX; IRenderLoop( string, 1 ); - string++; } + while( fRenderInfo.fX <= fRenderInfo.fClipRect.fX && *++string != 0 ); + fRenderInfo.fMaxWidth += fRenderInfo.fX - prevX; + fRenderInfo.fDestPtr -= (fRenderInfo.fX - prevX) * fRenderInfo.fDestBPP; + fRenderInfo.fX = prevX; fRenderInfo.fRenderFunc = oldFunc; } - // Adjust for left kern - if( ( fRenderInfo.fFlags & kRenderJustXMask ) == kRenderJustXForceLeft ) - { - // See note at top of file - plCharacter &ch = fCharacters[ (UInt16)string[ 0 ] - fFirstChar ]; - Int32 newX = x - (Int16)ch.fLeftKern; - if( newX < 0 ) - newX = 0; - fRenderInfo.fX = fRenderInfo.fFarthestX = (Int16)newX; - } + // There used to be an adjustment of the X coordinate by -ch.fLeftKern for the case + // of kRenderJustXForceLeft here, but it was buggy in that it neglected to adjust + // fRenderInfo.fDestPtr and therefore had no visible effect (or almost none - only + // at the end of the line). Fixing the bug however (making kRenderJustXForceLeft + // work as intended) causes the text shadow to be cut off in some places. To ensure + // enough space for the shadow, and considering that all content was developed and + // visually optimized with the bug in place, it seems better to preserve the buggy + // behavior and make kRenderJustXForceLeft work exactly like kRenderJustXLeft. fRenderInfo.fVolatileStringPtr = string; // Just so we can keep track of when we clip IRenderLoop( string, -1 ); @@ -715,9 +725,6 @@ void plFont::IRenderLoop( const wchar_t *string, Int32 maxCount ) if( fRenderInfo.fFlags & kRenderScaleAA ) thisWidth >>= 1; - if( thisWidth >= fRenderInfo.fMaxWidth ) - break; - (this->*(fRenderInfo.fRenderFunc))( fCharacters[ c ] ); fRenderInfo.fX += thisWidth; @@ -848,8 +855,8 @@ void plFont::IRenderChar8To32( const plFont::plCharacter &c ) { UInt8 *src = fBMapData + c.fBitmapOff; UInt32 *destPtr, *destBasePtr = (UInt32 *)( fRenderInfo.fDestPtr - c.fBaseline * fRenderInfo.fDestStride ); - UInt16 x, y; - UInt32 srcAlpha, oneMinusAlpha, r, g, b, dR, dG, dB, destAlpha, thisWidth; + Int16 x, y, thisHeight, xstart, thisWidth; + UInt32 srcAlpha, oneMinusAlpha, r, g, b, dR, dG, dB, destAlpha; UInt8 srcR, srcG, srcB; @@ -860,19 +867,35 @@ void plFont::IRenderChar8To32( const plFont::plCharacter &c ) // 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; + thisWidth = (Int16)fWidth;// + (Int32)c.fRightKern; + if( thisWidth >= fRenderInfo.fMaxWidth ) + thisWidth = fRenderInfo.fMaxWidth; - if( (Int32)c.fHeight - (Int32)c.fBaseline >= fRenderInfo.fMaxHeight || thisWidth >= fRenderInfo.fMaxWidth || c.fBaseline > fRenderInfo.fY ) - return; + xstart = fRenderInfo.fClipRect.fX - fRenderInfo.fX; + if( xstart < 0 ) + xstart = 0; srcR = (UInt8)(( fRenderInfo.fColor >> 16 ) & 0x000000ff); srcG = (UInt8)(( fRenderInfo.fColor >> 8 ) & 0x000000ff); srcB = (UInt8)(( fRenderInfo.fColor ) & 0x000000ff); - for( y = 0; y < c.fHeight; y++ ) + 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 = 0; x < thisWidth; x++ ) + for( x = xstart; x < thisWidth; x++ ) { if( src[ x ] == 255 ) destPtr[ x ] = fRenderInfo.fColor; @@ -907,8 +930,8 @@ void plFont::IRenderChar8To32FullAlpha( const plFont::plCharacter &c ) { UInt8 *src = fBMapData + c.fBitmapOff; UInt32 *destPtr, *destBasePtr = (UInt32 *)( fRenderInfo.fDestPtr - c.fBaseline * fRenderInfo.fDestStride ); - UInt16 x, y; - UInt32 destColorOnly, thisWidth; + Int16 x, y, thisHeight, xstart, thisWidth; + UInt32 destColorOnly; // Unfortunately for some fonts, their right kern value actually is @@ -918,17 +941,33 @@ void plFont::IRenderChar8To32FullAlpha( const plFont::plCharacter &c ) // 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; + thisWidth = (Int16)fWidth;// + (Int32)c.fRightKern; + if( thisWidth >= fRenderInfo.fMaxWidth ) + thisWidth = fRenderInfo.fMaxWidth; - if( (Int32)c.fHeight - (Int32)c.fBaseline >= fRenderInfo.fMaxHeight || thisWidth >= fRenderInfo.fMaxWidth || c.fBaseline > fRenderInfo.fY ) - return; + xstart = fRenderInfo.fClipRect.fX - fRenderInfo.fX; + if( xstart < 0 ) + xstart = 0; destColorOnly = fRenderInfo.fColor & 0x00ffffff; - for( y = 0; y < c.fHeight; y++ ) + 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 = 0; x < thisWidth; x++ ) + for( x = xstart; x < thisWidth; x++ ) { if( src[ x ] != 0 ) destPtr[ x ] = ( src[ x ] << 24 ) | destColorOnly; @@ -942,8 +981,8 @@ void plFont::IRenderChar8To32Alpha( const plFont::plCharacter &c ) { UInt8 val, *src = fBMapData + c.fBitmapOff; UInt32 *destPtr, *destBasePtr = (UInt32 *)( fRenderInfo.fDestPtr - c.fBaseline * fRenderInfo.fDestStride ); - UInt16 x, y; - UInt32 destColorOnly, alphaMult, fullAlpha, thisWidth; + Int16 x, y, thisHeight, xstart, thisWidth; + UInt32 destColorOnly, alphaMult, fullAlpha; // Unfortunately for some fonts, their right kern value actually is @@ -953,10 +992,13 @@ void plFont::IRenderChar8To32Alpha( const plFont::plCharacter &c ) // 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; + thisWidth = (Int16)fWidth;// + (Int32)c.fRightKern; + if( thisWidth >= fRenderInfo.fMaxWidth ) + thisWidth = fRenderInfo.fMaxWidth; - if( (Int32)c.fHeight - (Int32)c.fBaseline >= fRenderInfo.fMaxHeight || thisWidth >= fRenderInfo.fMaxWidth || c.fBaseline > fRenderInfo.fY ) - return; + xstart = fRenderInfo.fClipRect.fX - fRenderInfo.fX; + if( xstart < 0 ) + xstart = 0; destColorOnly = fRenderInfo.fColor & 0x00ffffff; // alphaMult should come out to be a value to satisfy (fontAlpha * alphaMult >> 8) as the right alpha, @@ -964,10 +1006,23 @@ void plFont::IRenderChar8To32Alpha( const plFont::plCharacter &c ) fullAlpha = fRenderInfo.fColor & 0xff000000; alphaMult = fullAlpha / 255; - for( y = 0; y < c.fHeight; y++ ) + 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 = 0; x < thisWidth; x++ ) + for( x = xstart; x < thisWidth; x++ ) { val = src[ x ]; if( val == 0xff ) @@ -982,6 +1037,145 @@ 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 = (Int16)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::IRenderChar8To32AlphaPremShadow( const plFont::plCharacter &c ) +{ + 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 = (Int16)fWidth + 2;// + (Int32)c.fRightKern; + if( thisWidth >= fRenderInfo.fMaxWidth ) + thisWidth = fRenderInfo.fMaxWidth; + + xstart = fRenderInfo.fClipRect.fX - fRenderInfo.fX; + if( xstart < -2 ) + xstart = -2; + + srcA = (UInt8)(( fRenderInfo.fColor >> 24 ) & 0x000000ff); + if (srcA == 0) + return; + srcR = (UInt8)(( fRenderInfo.fColor >> 16 ) & 0x000000ff); + srcG = (UInt8)(( fRenderInfo.fColor >> 8 ) & 0x000000ff); + srcB = (UInt8)(( fRenderInfo.fColor ) & 0x000000ff); + + static const UInt32 kernel[5][5] = { + {1, 2, 2, 2, 1}, + {1, 13, 13, 13, 1}, + {1, 10, 10, 10, 1}, + {1, 7, 7, 7, 1}, + {1, 1, 1, 1, 1} + }; + + UInt32 clamp = 220 - ((2 * srcR + 4 * srcG + srcB) >> 4); + + y = fRenderInfo.fClipRect.fY - fRenderInfo.fY + (Int16)c.fBaseline; + if( y < -2 ) + y = -2; + destBasePtr = (UInt32 *)( (UInt8 *)destBasePtr + y*fRenderInfo.fDestStride ); + + thisHeight = fRenderInfo.fMaxHeight + (Int16)c.fBaseline; + if( thisHeight > (Int16)c.fHeight + 2 ) + thisHeight = (Int16)c.fHeight + 2; + + for( ; y < thisHeight; y++ ) + { + destPtr = destBasePtr; + for( x = xstart; x < thisWidth; x++ ) + { + UInt32 sa = 0; + for (Int32 i = -2; i <= 2; i++) { + for (Int32 j = -2; j <= 2; j++) { + UInt32 m = kernel[j+2][i+2]; + if (m != 0) + sa += m * IGetCharPixel(c, x+i, y+j); + } + } + sa = (sa * clamp) >> 13; + if (sa > clamp) + sa = clamp; + UInt32 a = IGetCharPixel(c, x, y); + if (srcA != 0xff) + { + a = (srcA * a + 127) / 255; + sa = (srcA * sa + 127) / 255; + } + UInt32 ta = a + sa - ((a*sa + 127) / 255); + if (ta > (destPtr[ x ] >> 24)) + destPtr[ x ] = ( ta << 24 ) | (((srcR * a + 127) / 255) << 16) | + (((srcG * a + 127) / 255) << 8) | + (((srcB * a + 127) / 255) << 0); + } + destBasePtr = (UInt32 *)( (UInt8 *)destBasePtr + fRenderInfo.fDestStride ); + } +} + 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..58911f52 100644 --- a/MOULOpenSourceClientPlugin/Plasma20/Sources/Plasma/PubUtilLib/plGImage/plFont.h +++ b/MOULOpenSourceClientPlugin/Plasma20/Sources/Plasma/PubUtilLib/plGImage/plFont.h @@ -116,6 +116,8 @@ 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 + kRenderShadow = 0x00002000, // Render text shadows }; enum Flags @@ -231,8 +233,16 @@ 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 IRenderChar8To32AlphaPremShadow( const plCharacter &c ); void IRenderCharNull( const plCharacter &c ); + UInt32 IGetCharPixel( const plCharacter &c, Int32 x, Int32 y ) + { + // only for 8-bit characters + return (x < 0 || y < 0 || (UInt32)x >= fWidth || (UInt32)y >= c.fHeight) ? 0 : *(fBMapData + c.fBitmapOff + y*fWidth + x); + } + public: plFont(); 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/plMessage/plDeviceRecreateMsg.h b/MOULOpenSourceClientPlugin/Plasma20/Sources/Plasma/PubUtilLib/plMessage/plDeviceRecreateMsg.h index a83c0263..a97fa530 100644 --- a/MOULOpenSourceClientPlugin/Plasma20/Sources/Plasma/PubUtilLib/plMessage/plDeviceRecreateMsg.h +++ b/MOULOpenSourceClientPlugin/Plasma20/Sources/Plasma/PubUtilLib/plMessage/plDeviceRecreateMsg.h @@ -51,15 +51,26 @@ You can contact Cyan Worlds, Inc. by email legal@cyan.com #include "../pnMessage/plMessage.h" +class plPipeline; + class plDeviceRecreateMsg : public plMessage { + plPipeline* fPipe; + public: - plDeviceRecreateMsg() : plMessage( nil, nil, nil ) { SetBCastFlag( kBCastByExactType ); } + plDeviceRecreateMsg(plPipeline* pipe=nil) + : plMessage(nil, nil, nil), fPipe(pipe) + { + SetBCastFlag(kBCastByExactType); + } + ~plDeviceRecreateMsg() {} CLASSNAME_REGISTER( plDeviceRecreateMsg ); GETINTERFACE_ANY( plDeviceRecreateMsg, plMessage ); + plPipeline* Pipeline() const { return fPipe; } + // IO void Read(hsStream* stream, hsResMgr* mgr) { plMessage::IMsgRead( stream, mgr ); } void Write(hsStream* stream, hsResMgr* mgr) { plMessage::IMsgWrite( stream, mgr ); } diff --git a/MOULOpenSourceClientPlugin/Plasma20/Sources/Plasma/PubUtilLib/plPipeline/plDXPipeline.cpp b/MOULOpenSourceClientPlugin/Plasma20/Sources/Plasma/PubUtilLib/plPipeline/plDXPipeline.cpp index d7ed9043..0e1fd56c 100644 --- a/MOULOpenSourceClientPlugin/Plasma20/Sources/Plasma/PubUtilLib/plPipeline/plDXPipeline.cpp +++ b/MOULOpenSourceClientPlugin/Plasma20/Sources/Plasma/PubUtilLib/plPipeline/plDXPipeline.cpp @@ -2278,7 +2278,7 @@ hsBool plDXPipeline::IResetDevice() /// Broadcast a message letting everyone know that we were recreated and that /// all device-specific stuff needs to be recreated - plDeviceRecreateMsg* clean = TRACKED_NEW plDeviceRecreateMsg(); + plDeviceRecreateMsg* clean = TRACKED_NEW plDeviceRecreateMsg(this); plgDispatch::MsgSend(clean); } fDevWasLost = true; @@ -2552,7 +2552,7 @@ void plDXPipeline::Resize( UInt32 width, UInt32 height ) /// Broadcast a message letting everyone know that we were recreated and that /// all device-specific stuff needs to be recreated - plDeviceRecreateMsg* clean = TRACKED_NEW plDeviceRecreateMsg(); + plDeviceRecreateMsg* clean = TRACKED_NEW plDeviceRecreateMsg(this); plgDispatch::MsgSend(clean); } @@ -3834,7 +3834,7 @@ hsBool plDXPipeline::BeginRender() { /// Broadcast a message letting everyone know that we were recreated and that /// all device-specific stuff needs to be recreated -// plDeviceRecreateMsg* clean = TRACKED_NEW plDeviceRecreateMsg(); +// plDeviceRecreateMsg* clean = TRACKED_NEW plDeviceRecreateMsg(this); // plgDispatch::MsgSend(clean); fDevWasLost = false; @@ -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;