Browse Source

Merge pull request #392 from Lunanne/textrendering-clean

Textrendering clean
Adam Johnson 11 years ago
parent
commit
45d26404c5
  1. 9
      Sources/Plasma/CoreLib/hsColorRGBA.h
  2. 26
      Sources/Plasma/FeatureLib/pfGameGUIMgr/pfGUIControlMod.cpp
  3. 2
      Sources/Plasma/FeatureLib/pfGameGUIMgr/pfGUIControlMod.h
  4. 4
      Sources/Plasma/FeatureLib/pfGameGUIMgr/pfGUIEditBoxMod.cpp
  5. 4
      Sources/Plasma/FeatureLib/pfGameGUIMgr/pfGUIListBoxMod.cpp
  6. 2
      Sources/Plasma/FeatureLib/pfGameGUIMgr/pfGUIMultiLineEditCtrl.h
  7. 2
      Sources/Plasma/FeatureLib/pfGameGUIMgr/pfGUITextBoxMod.h
  8. 6
      Sources/Plasma/FeatureLib/pfPython/pyDynamicTextGlue.cpp
  9. 41
      Sources/Plasma/FeatureLib/pfPython/pyGUIControl.cpp
  10. 12
      Sources/Plasma/FeatureLib/pfPython/pyGUIControl.h
  11. 19
      Sources/Plasma/FeatureLib/pfPython/pyGUIControlGlue.cpp
  12. 1
      Sources/Plasma/FeatureLib/pfPython/pyGUIControlTextBox.cpp
  13. 1
      Sources/Plasma/FeatureLib/pfPython/pyGUIControlTextBox.h
  14. 2
      Sources/Plasma/FeatureLib/pfPython/pyGUIControlTextBoxGlue.cpp
  15. 3
      Sources/Plasma/NucleusLib/inc/hsGMatState.h
  16. 51
      Sources/Plasma/PubUtilLib/plGImage/plDynamicTextMap.cpp
  17. 8
      Sources/Plasma/PubUtilLib/plGImage/plDynamicTextMap.h
  18. 257
      Sources/Plasma/PubUtilLib/plGImage/plFont.cpp
  19. 10
      Sources/Plasma/PubUtilLib/plGImage/plFont.h
  20. 20
      Sources/Plasma/PubUtilLib/plGImage/plMipmap.cpp
  21. 5
      Sources/Plasma/PubUtilLib/plGImage/plMipmap.h
  22. 13
      Sources/Plasma/PubUtilLib/plMessage/plDeviceRecreateMsg.h
  23. 20
      Sources/Plasma/PubUtilLib/plPipeline/DX/plDXPipeline.cpp

9
Sources/Plasma/CoreLib/hsColorRGBA.h

@ -103,6 +103,7 @@ struct hsColorRGBA {
hsColorRGBA& FromARGB32(uint32_t c); hsColorRGBA& FromARGB32(uint32_t c);
uint32_t ToARGB32() const; uint32_t ToARGB32() const;
uint32_t ToARGB32Premultiplied() const;
void Read(hsStream *stream); void Read(hsStream *stream);
void Write(hsStream *stream) const; void Write(hsStream *stream) const;
@ -141,6 +142,14 @@ inline uint32_t hsColorRGBA::ToARGB32() const
| (uint32_t(b * 255.99f) << 0); | (uint32_t(b * 255.99f) << 0);
} }
inline uint32_t hsColorRGBA::ToARGB32Premultiplied() const
{
return (uint32_t(a * 255.0f + 0.5f) << 24)
| (uint32_t(a * r * 255.0f + 0.5f) << 16)
| (uint32_t(a * g * 255.0f + 0.5f) << 8)
| (uint32_t(a * b * 255.0f + 0.5f) << 0);
}
inline hsColorRGBA operator+(const hsColorRGBA& s, const hsColorRGBA& t) inline hsColorRGBA operator+(const hsColorRGBA& s, const hsColorRGBA& t)
{ {
hsColorRGBA res; hsColorRGBA res;

26
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/plRefMsg.h"
#include "pnMessage/plEnableMsg.h" #include "pnMessage/plEnableMsg.h"
#include "pfMessage/pfGameGUIMsg.h" #include "pfMessage/pfGameGUIMsg.h"
#include "plMessage/plDeviceRecreateMsg.h"
#include "pnSceneObject/plDrawInterface.h" #include "pnSceneObject/plDrawInterface.h"
#include "pnSceneObject/plCoordinateInterface.h" #include "pnSceneObject/plCoordinateInterface.h"
#include "pnSceneObject/plAudioInterface.h" #include "pnSceneObject/plAudioInterface.h"
@ -572,14 +573,16 @@ plProfile_CreateTimer("Gui", "RenderSetup", GUITime);
bool pfGUIControlMod::MsgReceive( plMessage *msg ) bool pfGUIControlMod::MsgReceive( plMessage *msg )
{ {
plRenderMsg* rend = plRenderMsg::ConvertNoRef( 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().c_str()); plProfile_BeginLap(GUITime, this->GetKey()->GetUoid().GetObjectName().c_str());
// Only need it once ISetUpDynTextMap(pipe);
if( ISetUpDynTextMap( rend->Pipeline() ) )
plgDispatch::Dispatch()->UnRegisterForExactType( plRenderMsg::Index(), GetKey() );
plProfile_EndLap(GUITime, this->GetKey()->GetUoid().GetObjectName().c_str()); plProfile_EndLap(GUITime, this->GetKey()->GetUoid().GetObjectName().c_str());
if (rend)
plgDispatch::Dispatch()->UnRegisterForExactType(plRenderMsg::Index(), GetKey());
return true; return true;
} }
@ -591,12 +594,16 @@ bool pfGUIControlMod::MsgReceive( plMessage *msg )
if( refMsg->GetContext() & ( plRefMsg::kOnCreate | plRefMsg::kOnRequest | plRefMsg::kOnReplace ) ) if( refMsg->GetContext() & ( plRefMsg::kOnCreate | plRefMsg::kOnRequest | plRefMsg::kOnReplace ) )
{ {
fDynTextMap = plDynamicTextMap::ConvertNoRef( refMsg->GetRef() ); 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( plRenderMsg::Index(), GetKey() );
plgDispatch::Dispatch()->RegisterForExactType( plDeviceRecreateMsg::Index(), GetKey() );
} }
else else
fDynTextMap = nil; {
fDynTextMap = nullptr;
plgDispatch::Dispatch()->UnRegisterForExactType( plDeviceRecreateMsg::Index(), GetKey() );
}
return true; return true;
} }
else if( refMsg->fType == kRefDynTextLayer ) else if( refMsg->fType == kRefDynTextLayer )
@ -676,7 +683,7 @@ bool pfGUIControlMod::ISetUpDynTextMap( plPipeline *pipe )
extraH -= height; extraH -= height;
fDynTextMap->Reset(); 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, fDynTextMap->SetFont( GetColorScheme()->fFontFace, GetColorScheme()->fFontSize, GetColorScheme()->fFontFlags,
HasFlag( kXparentBgnd ) ? false : true ); HasFlag( kXparentBgnd ) ? false : true );
@ -687,6 +694,7 @@ bool pfGUIControlMod::ISetUpDynTextMap( plPipeline *pipe )
// out with 1:1 mapping from textel to pixel // out with 1:1 mapping from textel to pixel
plLayer *layer = (plLayer *)fDynTextLayer; plLayer *layer = (plLayer *)fDynTextLayer;
layer->SetTransform( fDynTextMap->GetLayerTransform() ); layer->SetTransform( fDynTextMap->GetLayerTransform() );
layer->SetBlendFlags( layer->GetBlendFlags() | hsGMatState::kBlendAlphaPremultiplied );
// Let the derived classes do their things // Let the derived classes do their things
IPostSetUpDynTextMap(); IPostSetUpDynTextMap();

2
Sources/Plasma/FeatureLib/pfGameGUIMgr/pfGUIControlMod.h

@ -246,6 +246,8 @@ class pfGUIControlMod : public plSingleModifier
virtual void SetColorScheme( pfGUIColorScheme *newScheme ); virtual void SetColorScheme( pfGUIColorScheme *newScheme );
pfGUIColorScheme *GetColorScheme( void ) const; pfGUIColorScheme *GetColorScheme( void ) const;
virtual void UpdateColorScheme() { IPostSetUpDynTextMap(); IUpdate(); }
// should be override by specific GUIcontrol // should be override by specific GUIcontrol
virtual void PurgeDynaTextMapImage() {;} virtual void PurgeDynaTextMapImage() {;}

4
Sources/Plasma/FeatureLib/pfGameGUIMgr/pfGUIEditBoxMod.cpp

@ -138,9 +138,9 @@ void pfGUIEditBoxMod::IUpdate( void )
oldCursorPos = cursorPos; oldCursorPos = cursorPos;
cursorPos -= (int16_t)fScrollPos; cursorPos -= (int16_t)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 ) else if( 4 + cursorPos < 4 )
{ {

4
Sources/Plasma/FeatureLib/pfGameGUIMgr/pfGUIListBoxMod.cpp

@ -180,6 +180,10 @@ bool pfGUIListBoxMod::MsgReceive( plMessage *msg )
void pfGUIListBoxMod::IPostSetUpDynTextMap( void ) void pfGUIListBoxMod::IPostSetUpDynTextMap( void )
{ {
pfGUIColorScheme *scheme = GetColorScheme();
fDynTextMap->SetFont( scheme->fFontFace, scheme->fFontSize, scheme->fFontFlags,
!HasFlag( kXparentBgnd ));
ICalcWrapStarts(); ICalcWrapStarts();
ICalcScrollRange(); ICalcScrollRange();
fReadyToRoll = true; fReadyToRoll = true;

2
Sources/Plasma/FeatureLib/pfGameGUIMgr/pfGUIMultiLineEditCtrl.h

@ -211,6 +211,8 @@ class pfGUIMultiLineEditCtrl : public pfGUIControlMod
virtual void PurgeDynaTextMapImage(); virtual void PurgeDynaTextMapImage();
virtual void UpdateColorScheme() { fFontFlagsSet = 0; pfGUIControlMod::UpdateColorScheme(); }
// Extended event types // Extended event types
enum ExtendedEvents enum ExtendedEvents
{ {

2
Sources/Plasma/FeatureLib/pfGameGUIMgr/pfGUITextBoxMod.h

@ -101,8 +101,6 @@ class pfGUITextBoxMod : public pfGUIControlMod
void SetLocalizationPath(const plString& path); void SetLocalizationPath(const plString& path);
void SetUseLocalizationPath(bool use); void SetUseLocalizationPath(bool use);
virtual void UpdateColorScheme() { IPostSetUpDynTextMap(); IUpdate(); }
}; };
#endif // _pfGUITextBoxMod_h #endif // _pfGUITextBoxMod_h

6
Sources/Plasma/FeatureLib/pfPython/pyDynamicTextGlue.cpp

@ -493,4 +493,10 @@ void pyDynamicText::AddPlasmaConstantsClasses(PyObject *m)
PYTHON_ENUM_ELEMENT(PtJustify, kLeftJustify, plDynamicTextMap::kLeftJustify); PYTHON_ENUM_ELEMENT(PtJustify, kLeftJustify, plDynamicTextMap::kLeftJustify);
PYTHON_ENUM_ELEMENT(PtJustify, kRightJustify, plDynamicTextMap::kRightJustify); PYTHON_ENUM_ELEMENT(PtJustify, kRightJustify, plDynamicTextMap::kRightJustify);
PYTHON_ENUM_END(m, PtJustify); 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);
} }

41
Sources/Plasma/FeatureLib/pfPython/pyGUIControl.cpp

@ -279,7 +279,7 @@ PyObject* pyGUIControl::GetOwnerDlg( void )
} }
// get color schemes // get color schemes
PyObject* pyGUIControl::GetForeColor() PyObject* pyGUIControl::GetForeColor() const
{ {
if ( fGCkey ) if ( fGCkey )
{ {
@ -293,7 +293,7 @@ PyObject* pyGUIControl::GetForeColor()
PYTHON_RETURN_NONE; PYTHON_RETURN_NONE;
} }
PyObject* pyGUIControl::GetSelColor() PyObject* pyGUIControl::GetSelColor() const
{ {
if ( fGCkey ) if ( fGCkey )
{ {
@ -307,7 +307,7 @@ PyObject* pyGUIControl::GetSelColor()
PYTHON_RETURN_NONE; PYTHON_RETURN_NONE;
} }
PyObject* pyGUIControl::GetBackColor() PyObject* pyGUIControl::GetBackColor() const
{ {
if ( fGCkey ) if ( fGCkey )
{ {
@ -321,7 +321,7 @@ PyObject* pyGUIControl::GetBackColor()
PYTHON_RETURN_NONE; PYTHON_RETURN_NONE;
} }
PyObject* pyGUIControl::GetBackSelColor() PyObject* pyGUIControl::GetBackSelColor() const
{ {
if ( fGCkey ) if ( fGCkey )
{ {
@ -335,7 +335,7 @@ PyObject* pyGUIControl::GetBackSelColor()
PYTHON_RETURN_NONE; PYTHON_RETURN_NONE;
} }
uint32_t pyGUIControl::GetFontSize() uint32_t pyGUIControl::GetFontSize() const
{ {
if ( fGCkey ) if ( fGCkey )
{ {
@ -445,3 +445,34 @@ void pyGUIControl::SetFontSize(uint32_t fontsize)
} }
} }
} }
void pyGUIControl::SetFontFlags(uint8_t 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_t 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;
}

12
Sources/Plasma/FeatureLib/pfPython/pyGUIControl.h

@ -114,17 +114,19 @@ public:
virtual PyObject* GetOwnerDlg( void ); // returns pyGUIDialog virtual PyObject* GetOwnerDlg( void ); // returns pyGUIDialog
// get color schemes // get color schemes
virtual PyObject* GetForeColor(); // returns pyColor virtual PyObject* GetForeColor() const; // returns pyColor
virtual PyObject* GetSelColor(); // returns pyColor virtual PyObject* GetSelColor() const; // returns pyColor
virtual PyObject* GetBackColor(); // returns pyColor virtual PyObject* GetBackColor() const; // returns pyColor
virtual PyObject* GetBackSelColor(); // returns pyColor virtual PyObject* GetBackSelColor() const; // returns pyColor
virtual uint32_t GetFontSize(); virtual uint32_t GetFontSize() const;
virtual uint8_t GetFontFlags() const;
// set color scheme // set color scheme
virtual void SetForeColor( float r, float g, float b, float a ); virtual void SetForeColor( float r, float g, float b, float a );
virtual void SetSelColor( float r, float g, float b, float a ); virtual void SetSelColor( float r, float g, float b, float a );
virtual void SetBackColor( float r, float g, float b, float a ); virtual void SetBackColor( float r, float g, float b, float a );
virtual void SetBackSelColor( float r, float g, float b, float a ); virtual void SetBackSelColor( float r, float g, float b, float a );
virtual void SetFontSize(uint32_t fontsize); virtual void SetFontSize(uint32_t fontsize);
virtual void SetFontFlags(uint8_t fontflags);
}; };

19
Sources/Plasma/FeatureLib/pfPython/pyGUIControlGlue.cpp

@ -246,6 +246,23 @@ PYTHON_METHOD_DEFINITION_NOARGS(ptGUIControl, getFontSize)
return PyLong_FromUnsignedLong(self->fThis->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) PYTHON_METHOD_DEFINITION(ptGUIControl, setForeColor, args)
{ {
float r, g, b, a; float r, g, b, a;
@ -331,11 +348,13 @@ PYTHON_START_METHODS_TABLE(ptGUIControl)
PYTHON_METHOD_NOARGS(ptGUIControl, getBackColor, "Returns the background color"), PYTHON_METHOD_NOARGS(ptGUIControl, getBackColor, "Returns the background color"),
PYTHON_METHOD_NOARGS(ptGUIControl, getBackSelectColor, "Returns the background selection color"), PYTHON_METHOD_NOARGS(ptGUIControl, getBackSelectColor, "Returns the background selection color"),
PYTHON_METHOD_NOARGS(ptGUIControl, getFontSize, "Returns the font size"), 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, 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, 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, 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, setBackSelectColor, "Params: r,g,b,a\nSets the selection background color"),
PYTHON_METHOD(ptGUIControl, setFontSize, "Params: fontSize\nSets the font size"), PYTHON_METHOD(ptGUIControl, setFontSize, "Params: fontSize\nSets the font size"),
PYTHON_METHOD(ptGUIControl, setFontFlags, "Params: fontflags\nSets current fontflags"),
PYTHON_END_METHODS_TABLE; PYTHON_END_METHODS_TABLE;
// Type structure definition // Type structure definition

1
Sources/Plasma/FeatureLib/pfPython/pyGUIControlTextBox.cpp

@ -212,3 +212,4 @@ uint8_t pyGUIControlTextBox::GetJustify()
} }
return pfGUIListText::kLeftJustify; return pfGUIListText::kLeftJustify;
} }

1
Sources/Plasma/FeatureLib/pfPython/pyGUIControlTextBox.h

@ -86,6 +86,7 @@ public:
virtual void SetForeColor( pyColor& color ); virtual void SetForeColor( pyColor& color );
virtual void SetBackColor( pyColor& color ); virtual void SetBackColor( pyColor& color );
virtual void SetJustify( uint8_t justify ); virtual void SetJustify( uint8_t justify );
virtual uint8_t GetJustify(); virtual uint8_t GetJustify();
virtual PyObject* GetForeColor(); // returns pyColor virtual PyObject* GetForeColor(); // returns pyColor
}; };

2
Sources/Plasma/FeatureLib/pfPython/pyGUIControlTextBoxGlue.cpp

@ -188,6 +188,8 @@ PYTHON_METHOD_DEFINITION(ptGUIControlTextBox, setStringJustify, args)
PYTHON_RETURN_NONE; PYTHON_RETURN_NONE;
} }
PYTHON_METHOD_DEFINITION_NOARGS(ptGUIControlTextBox, getStringJustify) PYTHON_METHOD_DEFINITION_NOARGS(ptGUIControlTextBox, getStringJustify)
{ {
return PyInt_FromLong(self->fThis->GetJustify()); return PyInt_FromLong(self->fThis->GetJustify());

3
Sources/Plasma/NucleusLib/inc/hsGMatState.h

@ -85,7 +85,8 @@ enum hsGMatBlendFlags {
kBlendEnvBumpNext = 0x800000, kBlendEnvBumpNext = 0x800000,
kBlendSubtract = 0x1000000, kBlendSubtract = 0x1000000,
kBlendRevSubtract = 0x2000000, kBlendRevSubtract = 0x2000000,
kBlendAlphaTestHigh = 0x4000000 kBlendAlphaTestHigh = 0x4000000,
kBlendAlphaPremultiplied = 0x8000000
}; };
enum hsGMatClampFlags { enum hsGMatClampFlags {

51
Sources/Plasma/PubUtilLib/plGImage/plDynamicTextMap.cpp

@ -76,7 +76,7 @@ plProfile_Extern(MemMipmaps);
//// Constructor & Destructor ///////////////////////////////////////////////// //// Constructor & Destructor /////////////////////////////////////////////////
plDynamicTextMap::plDynamicTextMap() plDynamicTextMap::plDynamicTextMap()
: fVisWidth(0), fVisHeight(0), fHasAlpha(false), fJustify(kLeftJustify), : fVisWidth(0), fVisHeight(0), fHasAlpha(false), fPremultipliedAlpha(false), fJustify(kLeftJustify),
fInitBuffer(nullptr), fFontSize(0), fFontFlags(0), fInitBuffer(nullptr), fFontSize(0), fFontFlags(0),
fFontAntiAliasRGB(false), fFontBlockRGB(false), fHasCreateBeenCalled(false) fFontAntiAliasRGB(false), fFontBlockRGB(false), fHasCreateBeenCalled(false)
{ {
@ -88,10 +88,10 @@ plDynamicTextMap::~plDynamicTextMap()
Reset(); Reset();
} }
plDynamicTextMap::plDynamicTextMap( uint32_t width, uint32_t height, bool hasAlpha, uint32_t extraWidth, uint32_t extraHeight ) plDynamicTextMap::plDynamicTextMap( uint32_t width, uint32_t height, bool hasAlpha, uint32_t extraWidth, uint32_t extraHeight, bool premultipliedAlpha )
: fInitBuffer(nullptr) : fInitBuffer(nullptr)
{ {
Create( width, height, hasAlpha, extraWidth, extraHeight ); Create( width, height, hasAlpha, extraWidth, extraHeight, premultipliedAlpha );
} }
//// SetNoCreate ////////////////////////////////////////////////////////////// //// SetNoCreate //////////////////////////////////////////////////////////////
@ -113,7 +113,7 @@ void plDynamicTextMap::SetNoCreate( uint32_t width, uint32_t height, bool has
//// Create /////////////////////////////////////////////////////////////////// //// Create ///////////////////////////////////////////////////////////////////
void plDynamicTextMap::Create( uint32_t width, uint32_t height, bool hasAlpha, uint32_t extraWidth, uint32_t extraHeight ) void plDynamicTextMap::Create( uint32_t width, uint32_t height, bool hasAlpha, uint32_t extraWidth, uint32_t extraHeight, bool premultipliedAlpha )
{ {
SetConfig( hasAlpha ? kARGB32Config : kRGB32Config ); SetConfig( hasAlpha ? kARGB32Config : kRGB32Config );
@ -121,6 +121,7 @@ void plDynamicTextMap::Create( uint32_t width, uint32_t height, bool hasAlpha
fVisWidth = (uint16_t)width; fVisWidth = (uint16_t)width;
fVisHeight = (uint16_t)height; fVisHeight = (uint16_t)height;
fHasAlpha = hasAlpha; fHasAlpha = hasAlpha;
fPremultipliedAlpha = premultipliedAlpha;
for( fWidth = 1; fWidth < width + extraWidth; fWidth <<= 1 ); for( fWidth = 1; fWidth < width + extraWidth; fWidth <<= 1 );
for( fHeight = 1; fHeight < height + extraHeight; fHeight <<= 1 ); for( fHeight = 1; fHeight < height + extraHeight; fHeight <<= 1 );
@ -378,6 +379,17 @@ void plDynamicTextMap::IClearFromBuffer( uint32_t *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 ///////////////////////////////////////////////////////////// //// ClearToColor /////////////////////////////////////////////////////////////
void plDynamicTextMap::ClearToColor( hsColorRGBA &color ) void plDynamicTextMap::ClearToColor( hsColorRGBA &color )
@ -385,7 +397,7 @@ void plDynamicTextMap::ClearToColor( hsColorRGBA &color )
if( !IIsValid() ) if( !IIsValid() )
return; return;
uint32_t i, hex = color.ToARGB32(); uint32_t i, hex = fPremultipliedAlpha ? color.ToARGB32Premultiplied() : color.ToARGB32();
uint32_t *data = (uint32_t *)fImage; uint32_t *data = (uint32_t *)fImage;
// Buffer is of size fVisWidth x fVisHeight, so we need a bit of work to do this right // Buffer is of size fVisWidth x fVisHeight, so we need a bit of work to do this right
@ -449,6 +461,8 @@ void plDynamicTextMap::SetFont( const plString &face, uint16_t size, uint8_t
// This will be nil if we're just running the page optimizer. // This will be nil if we're just running the page optimizer.
if (fCurrFont) if (fCurrFont)
{ {
if (fFontFlags & kFontShadowed)
fCurrFont->SetRenderFlag(plFont::kRenderShadow, true);
fCurrFont->SetRenderYJustify( plFont::kRenderJustYTop ); fCurrFont->SetRenderYJustify( plFont::kRenderJustYTop );
SetJustify( fJustify ); SetJustify( fJustify );
} }
@ -495,10 +509,9 @@ void plDynamicTextMap::DrawString( uint16_t x, uint16_t y, const wchar_t *tex
if( !IIsValid() ) if( !IIsValid() )
return; return;
SetJustify( fJustify ); IPropagateFlags();
fCurrFont->SetRenderFlag( plFont::kRenderWrap | plFont::kRenderClip, false ); fCurrFont->SetRenderFlag( plFont::kRenderWrap | plFont::kRenderClip, false );
fCurrFont->SetRenderColor( fFontColor.ToARGB32() ); fCurrFont->SetRenderClipRect( 0, 0, fVisWidth, fVisHeight );
fCurrFont->SetRenderFlag( plFont::kRenderIntoAlpha, fFontBlockRGB );
fCurrFont->RenderString( this, x, y, text ); fCurrFont->RenderString( this, x, y, text );
} }
@ -515,10 +528,8 @@ void plDynamicTextMap::DrawClippedString( int16_t x, int16_t y, const wchar_t
if( !IIsValid() ) if( !IIsValid() )
return; return;
SetJustify( fJustify ); IPropagateFlags();
fCurrFont->SetRenderClipping( x, y, width, height ); fCurrFont->SetRenderClipping( x, y, width, height );
fCurrFont->SetRenderColor( fFontColor.ToARGB32() );
fCurrFont->SetRenderFlag( plFont::kRenderIntoAlpha, fFontBlockRGB );
fCurrFont->RenderString( this, x, y, text ); fCurrFont->RenderString( this, x, y, text );
} }
@ -535,9 +546,8 @@ void plDynamicTextMap::DrawClippedString( int16_t x, int16_t y, const wchar_t
if( !IIsValid() ) if( !IIsValid() )
return; return;
SetJustify( fJustify ); IPropagateFlags();
fCurrFont->SetRenderClipping( clipX, clipY, width, height ); fCurrFont->SetRenderClipping( clipX, clipY, width, height );
fCurrFont->SetRenderColor( fFontColor.ToARGB32() );
fCurrFont->RenderString( this, x, y, text ); fCurrFont->RenderString( this, x, y, text );
} }
@ -554,10 +564,8 @@ void plDynamicTextMap::DrawWrappedString( uint16_t x, uint16_t y, const wchar
if( !IIsValid() ) if( !IIsValid() )
return; return;
SetJustify( fJustify ); IPropagateFlags();
fCurrFont->SetRenderWrapping( x, y, width, height ); fCurrFont->SetRenderWrapping( x, y, width, height );
fCurrFont->SetRenderColor( fFontColor.ToARGB32() );
fCurrFont->SetRenderFlag( plFont::kRenderIntoAlpha, fFontBlockRGB );
fCurrFont->RenderString( this, x, y, text, lastX, lastY ); fCurrFont->RenderString( this, x, y, text, lastX, lastY );
} }
@ -638,7 +646,7 @@ void plDynamicTextMap::FillRect( uint16_t x, uint16_t y, uint16_t width, uint
width = (uint16_t)(fWidth - x); width = (uint16_t)(fWidth - x);
// Gee, how hard can it REALLY be? // Gee, how hard can it REALLY be?
uint32_t i, hex = color.ToARGB32(); uint32_t i, hex = fPremultipliedAlpha ? color.ToARGB32Premultiplied() : color.ToARGB32();
height += y; height += y;
if( height > fHeight ) if( height > fHeight )
height = (uint16_t)fHeight; height = (uint16_t)fHeight;
@ -663,7 +671,7 @@ void plDynamicTextMap::FrameRect( uint16_t x, uint16_t y, uint16_t width, uin
height = (uint16_t)(fHeight - y); height = (uint16_t)(fHeight - y);
// Shouldn't be much harder // Shouldn't be much harder
uint32_t i, hex = color.ToARGB32(); uint32_t i, hex = fPremultipliedAlpha ? color.ToARGB32Premultiplied() : color.ToARGB32();
uint32_t *dest1, *dest2; uint32_t *dest1, *dest2;
dest1 = GetAddr32( x, y ); dest1 = GetAddr32( x, y );
@ -698,6 +706,9 @@ void plDynamicTextMap::DrawImage( uint16_t x, uint16_t y, plMipmap *image, Dr
else if( method == kImgSprite ) else if( method == kImgSprite )
opts.fFlags = plMipmap::kCopySrcAlpha; opts.fFlags = plMipmap::kCopySrcAlpha;
if( fPremultipliedAlpha )
opts.fFlags |= plMipmap::kDestPremultiplied;
Composite( image, x, y, &opts ); Composite( image, x, y, &opts );
/// HACK for now, since the alpha in the mipmap gets copied straight into the /// HACK for now, since the alpha in the mipmap gets copied straight into the
@ -736,6 +747,9 @@ void plDynamicTextMap::DrawClippedImage( uint16_t x, uint16_t y, plMipmap *im
else if( method == kImgSprite ) else if( method == kImgSprite )
opts.fFlags = plMipmap::kCopySrcAlpha; opts.fFlags = plMipmap::kCopySrcAlpha;
if( fPremultipliedAlpha )
opts.fFlags |= plMipmap::kDestPremultiplied;
opts.fSrcClipX = srcClipX; opts.fSrcClipX = srcClipX;
opts.fSrcClipY = srcClipY; opts.fSrcClipY = srcClipY;
opts.fSrcClipWidth = srcClipWidth; opts.fSrcClipWidth = srcClipWidth;
@ -882,6 +896,7 @@ void plDynamicTextMap::Swap( plDynamicTextMap *other )
// Swap DTMap info // Swap DTMap info
SWAP_ME( bool, fHasAlpha, other->fHasAlpha ); SWAP_ME( bool, fHasAlpha, other->fHasAlpha );
SWAP_ME( bool, fPremultipliedAlpha, other->fPremultipliedAlpha );
SWAP_ME( bool, fShadowed, other->fShadowed ); SWAP_ME( bool, fShadowed, other->fShadowed );
SWAP_ME( Justify, fJustify, other->fJustify ); SWAP_ME( Justify, fJustify, other->fJustify );

8
Sources/Plasma/PubUtilLib/plGImage/plDynamicTextMap.h

@ -113,14 +113,14 @@ class plDynamicTextMap : public plMipmap
plDynamicTextMap(); plDynamicTextMap();
plDynamicTextMap( uint32_t width, uint32_t height, bool hasAlpha = false, uint32_t extraWidth = 0, uint32_t extraHeight = 0 ); plDynamicTextMap( uint32_t width, uint32_t height, bool hasAlpha = false, uint32_t extraWidth = 0, uint32_t extraHeight = 0, bool premultipliedAlpha = false );
virtual ~plDynamicTextMap(); virtual ~plDynamicTextMap();
CLASSNAME_REGISTER( plDynamicTextMap ); CLASSNAME_REGISTER( plDynamicTextMap );
GETINTERFACE_ANY( plDynamicTextMap, plMipmap ); GETINTERFACE_ANY( plDynamicTextMap, plMipmap );
void Create( uint32_t width, uint32_t height, bool hasAlpha, uint32_t extraWidth = 0, uint32_t extraHeight = 0 ); void Create( uint32_t width, uint32_t height, bool hasAlpha, uint32_t extraWidth = 0, uint32_t extraHeight = 0, bool premultipliedAlpha = false );
void SetNoCreate( uint32_t width, uint32_t height, bool hasAlpha ); void SetNoCreate( uint32_t width, uint32_t height, bool hasAlpha );
virtual void Reset( void ); virtual void Reset( void );
@ -221,7 +221,9 @@ class plDynamicTextMap : public plMipmap
uint32_t *IAllocateOSSurface( uint16_t width, uint16_t height ); uint32_t *IAllocateOSSurface( uint16_t width, uint16_t height );
void IDestroyOSSurface( void ); void IDestroyOSSurface( void );
bool fHasAlpha, fShadowed; void IPropagateFlags();
bool fHasAlpha, fPremultipliedAlpha, fShadowed;
Justify fJustify; Justify fJustify;
plString fFontFace; plString fFontFace;

257
Sources/Plasma/PubUtilLib/plGImage/plFont.cpp

@ -334,7 +334,14 @@ void plFont::IRenderString( plMipmap *mip, uint16_t x, uint16_t y, const wcha
{ {
if( fRenderInfo.fFlags & kRenderIntoAlpha ) 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; fRenderInfo.fRenderFunc = &plFont::IRenderChar8To32Alpha;
else else
fRenderInfo.fRenderFunc = &plFont::IRenderChar8To32FullAlpha; fRenderInfo.fRenderFunc = &plFont::IRenderChar8To32FullAlpha;
@ -648,24 +655,27 @@ void plFont::IRenderString( plMipmap *mip, uint16_t x, uint16_t y, const wcha
// Advance left past any clipping area // Advance left past any clipping area
CharRenderFunc oldFunc = fRenderInfo.fRenderFunc; CharRenderFunc oldFunc = fRenderInfo.fRenderFunc;
fRenderInfo.fRenderFunc = &plFont::IRenderCharNull; fRenderInfo.fRenderFunc = &plFont::IRenderCharNull;
while( fRenderInfo.fX < fRenderInfo.fClipRect.fX && *string != 0 ) int16_t prevX;
do
{ {
prevX = fRenderInfo.fX;
IRenderLoop( string, 1 ); 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; fRenderInfo.fRenderFunc = oldFunc;
} }
// Adjust for left kern // There used to be an adjustment of the X coordinate by -ch.fLeftKern for the case
if( ( fRenderInfo.fFlags & kRenderJustXMask ) == kRenderJustXForceLeft ) // 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
// See note at top of file // at the end of the line). Fixing the bug however (making kRenderJustXForceLeft
plCharacter &ch = fCharacters[ (uint16_t)string[ 0 ] - fFirstChar ]; // work as intended) causes the text shadow to be cut off in some places. To ensure
int32_t newX = x - (int16_t)ch.fLeftKern; // enough space for the shadow, and considering that all content was developed and
if( newX < 0 ) // visually optimized with the bug in place, it seems better to preserve the buggy
newX = 0; // behavior and make kRenderJustXForceLeft work exactly like kRenderJustXLeft.
fRenderInfo.fX = fRenderInfo.fFarthestX = (int16_t)newX;
}
fRenderInfo.fVolatileStringPtr = string; // Just so we can keep track of when we clip fRenderInfo.fVolatileStringPtr = string; // Just so we can keep track of when we clip
IRenderLoop( string, -1 ); IRenderLoop( string, -1 );
@ -704,9 +714,6 @@ void plFont::IRenderLoop( const wchar_t *string, int32_t maxCount )
if( fRenderInfo.fFlags & kRenderScaleAA ) if( fRenderInfo.fFlags & kRenderScaleAA )
thisWidth >>= 1; thisWidth >>= 1;
if( thisWidth >= fRenderInfo.fMaxWidth )
break;
(this->*(fRenderInfo.fRenderFunc))( fCharacters[ c ] ); (this->*(fRenderInfo.fRenderFunc))( fCharacters[ c ] );
fRenderInfo.fX += thisWidth; fRenderInfo.fX += thisWidth;
@ -837,8 +844,8 @@ void plFont::IRenderChar8To32( const plFont::plCharacter &c )
{ {
uint8_t *src = fBMapData + c.fBitmapOff; uint8_t *src = fBMapData + c.fBitmapOff;
uint32_t *destPtr, *destBasePtr = (uint32_t *)( fRenderInfo.fDestPtr - c.fBaseline * fRenderInfo.fDestStride ); uint32_t *destPtr, *destBasePtr = (uint32_t *)( fRenderInfo.fDestPtr - c.fBaseline * fRenderInfo.fDestStride );
uint16_t x, y; int16_t x, y, thisHeight, xstart, thisWidth;
uint32_t srcAlpha, oneMinusAlpha, r, g, b, dR, dG, dB, destAlpha, thisWidth; uint32_t srcAlpha, oneMinusAlpha, r, g, b, dR, dG, dB, destAlpha;
uint8_t srcR, srcG, srcB; uint8_t srcR, srcG, srcB;
@ -850,18 +857,34 @@ void plFont::IRenderChar8To32( const plFont::plCharacter &c )
// should already be in the cache. If it does, time to upgrade the font // should already be in the cache. If it does, time to upgrade the font
// format (again) // format (again)
thisWidth = fWidth;// + (int32_t)c.fRightKern; thisWidth = fWidth;// + (int32_t)c.fRightKern;
if( thisWidth >= fRenderInfo.fMaxWidth )
thisWidth = fRenderInfo.fMaxWidth;
if( (int32_t)c.fHeight - (int32_t)c.fBaseline >= fRenderInfo.fMaxHeight || thisWidth >= fRenderInfo.fMaxWidth || c.fBaseline > fRenderInfo.fY ) xstart = fRenderInfo.fClipRect.fX - fRenderInfo.fX;
return; if( xstart < 0 )
xstart = 0;
srcR = (uint8_t)(( fRenderInfo.fColor >> 16 ) & 0x000000ff); srcR = (uint8_t)(( fRenderInfo.fColor >> 16 ) & 0x000000ff);
srcG = (uint8_t)(( fRenderInfo.fColor >> 8 ) & 0x000000ff); srcG = (uint8_t)(( fRenderInfo.fColor >> 8 ) & 0x000000ff);
srcB = (uint8_t)(( fRenderInfo.fColor ) & 0x000000ff); srcB = (uint8_t)(( fRenderInfo.fColor ) & 0x000000ff);
for( y = 0; y < c.fHeight; y++ ) y = fRenderInfo.fClipRect.fY - fRenderInfo.fY + (int16_t)c.fBaseline;
if( y < 0 )
y = 0;
else
{
destBasePtr = (uint32_t *)( (uint8_t *)destBasePtr + y*fRenderInfo.fDestStride );
src += y*fRenderInfo.fNumCols;
}
thisHeight = fRenderInfo.fMaxHeight + (int16_t)c.fBaseline;
if( thisHeight > (int16_t)c.fHeight )
thisHeight = (int16_t)c.fHeight;
for( ; y < thisHeight; y++ )
{ {
destPtr = destBasePtr; destPtr = destBasePtr;
for( x = 0; x < thisWidth; x++ ) for( x = xstart; x < thisWidth; x++ )
{ {
if( src[ x ] == 255 ) if( src[ x ] == 255 )
destPtr[ x ] = fRenderInfo.fColor; destPtr[ x ] = fRenderInfo.fColor;
@ -896,8 +919,8 @@ void plFont::IRenderChar8To32FullAlpha( const plFont::plCharacter &c )
{ {
uint8_t *src = fBMapData + c.fBitmapOff; uint8_t *src = fBMapData + c.fBitmapOff;
uint32_t *destPtr, *destBasePtr = (uint32_t *)( fRenderInfo.fDestPtr - c.fBaseline * fRenderInfo.fDestStride ); uint32_t *destPtr, *destBasePtr = (uint32_t *)( fRenderInfo.fDestPtr - c.fBaseline * fRenderInfo.fDestStride );
uint16_t x, y; int16_t x, y, thisHeight, xstart, thisWidth;
uint32_t destColorOnly, thisWidth; uint32_t destColorOnly;
// Unfortunately for some fonts, their right kern value actually is // Unfortunately for some fonts, their right kern value actually is
@ -908,16 +931,32 @@ void plFont::IRenderChar8To32FullAlpha( const plFont::plCharacter &c )
// should already be in the cache. If it does, time to upgrade the font // should already be in the cache. If it does, time to upgrade the font
// format (again) // format (again)
thisWidth = fWidth;// + (int32_t)c.fRightKern; thisWidth = fWidth;// + (int32_t)c.fRightKern;
if( thisWidth >= fRenderInfo.fMaxWidth )
thisWidth = fRenderInfo.fMaxWidth;
if( (int32_t)c.fHeight - (int32_t)c.fBaseline >= fRenderInfo.fMaxHeight || thisWidth >= fRenderInfo.fMaxWidth || c.fBaseline > fRenderInfo.fY ) xstart = fRenderInfo.fClipRect.fX - fRenderInfo.fX;
return; if( xstart < 0 )
xstart = 0;
destColorOnly = fRenderInfo.fColor & 0x00ffffff; destColorOnly = fRenderInfo.fColor & 0x00ffffff;
for( y = 0; y < c.fHeight; y++ ) y = fRenderInfo.fClipRect.fY - fRenderInfo.fY + (int16_t)c.fBaseline;
if( y < 0 )
y = 0;
else
{
destBasePtr = (uint32_t *)( (uint8_t *)destBasePtr + y*fRenderInfo.fDestStride );
src += y*fRenderInfo.fNumCols;
}
thisHeight = fRenderInfo.fMaxHeight + (int16_t)c.fBaseline;
if( thisHeight > (int16_t)c.fHeight )
thisHeight = (int16_t)c.fHeight;
for( ; y < thisHeight; y++ )
{ {
destPtr = destBasePtr; destPtr = destBasePtr;
for( x = 0; x < thisWidth; x++ ) for( x = xstart; x < thisWidth; x++ )
{ {
if( src[ x ] != 0 ) if( src[ x ] != 0 )
destPtr[ x ] = ( src[ x ] << 24 ) | destColorOnly; destPtr[ x ] = ( src[ x ] << 24 ) | destColorOnly;
@ -931,8 +970,8 @@ void plFont::IRenderChar8To32Alpha( const plFont::plCharacter &c )
{ {
uint8_t val, *src = fBMapData + c.fBitmapOff; uint8_t val, *src = fBMapData + c.fBitmapOff;
uint32_t *destPtr, *destBasePtr = (uint32_t *)( fRenderInfo.fDestPtr - c.fBaseline * fRenderInfo.fDestStride ); uint32_t *destPtr, *destBasePtr = (uint32_t *)( fRenderInfo.fDestPtr - c.fBaseline * fRenderInfo.fDestStride );
uint16_t x, y; int16_t x, y, thisHeight, xstart, thisWidth;
uint32_t destColorOnly, alphaMult, fullAlpha, thisWidth; uint32_t destColorOnly, alphaMult, fullAlpha;
// Unfortunately for some fonts, their right kern value actually is // Unfortunately for some fonts, their right kern value actually is
@ -943,9 +982,12 @@ void plFont::IRenderChar8To32Alpha( const plFont::plCharacter &c )
// should already be in the cache. If it does, time to upgrade the font // should already be in the cache. If it does, time to upgrade the font
// format (again) // format (again)
thisWidth = fWidth;// + (int32_t)c.fRightKern; thisWidth = fWidth;// + (int32_t)c.fRightKern;
if( thisWidth >= fRenderInfo.fMaxWidth )
thisWidth = fRenderInfo.fMaxWidth;
if( (int32_t)c.fHeight - (int32_t)c.fBaseline >= fRenderInfo.fMaxHeight || thisWidth >= fRenderInfo.fMaxWidth || c.fBaseline > fRenderInfo.fY ) xstart = fRenderInfo.fClipRect.fX - fRenderInfo.fX;
return; if( xstart < 0 )
xstart = 0;
destColorOnly = fRenderInfo.fColor & 0x00ffffff; destColorOnly = fRenderInfo.fColor & 0x00ffffff;
// alphaMult should come out to be a value to satisfy (fontAlpha * alphaMult >> 8) as the right alpha, // alphaMult should come out to be a value to satisfy (fontAlpha * alphaMult >> 8) as the right alpha,
@ -953,10 +995,23 @@ void plFont::IRenderChar8To32Alpha( const plFont::plCharacter &c )
fullAlpha = fRenderInfo.fColor & 0xff000000; fullAlpha = fRenderInfo.fColor & 0xff000000;
alphaMult = fullAlpha / 255; alphaMult = fullAlpha / 255;
for( y = 0; y < c.fHeight; y++ ) y = fRenderInfo.fClipRect.fY - fRenderInfo.fY + (int16_t)c.fBaseline;
if( y < 0 )
y = 0;
else
{
destBasePtr = (uint32_t *)( (uint8_t *)destBasePtr + y*fRenderInfo.fDestStride );
src += y*fRenderInfo.fNumCols;
}
thisHeight = fRenderInfo.fMaxHeight + (int16_t)c.fBaseline;
if( thisHeight > (int16_t)c.fHeight )
thisHeight = (int16_t)c.fHeight;
for( ; y < thisHeight; y++ )
{ {
destPtr = destBasePtr; destPtr = destBasePtr;
for( x = 0; x < thisWidth; x++ ) for( x = xstart; x < thisWidth; x++ )
{ {
val = src[ x ]; val = src[ x ];
if( val == 0xff ) if( val == 0xff )
@ -971,6 +1026,140 @@ void plFont::IRenderChar8To32Alpha( const plFont::plCharacter &c )
} }
} }
void plFont::IRenderChar8To32AlphaPremultiplied( const plFont::plCharacter &c )
{
uint8_t *src = fBMapData + c.fBitmapOff;
uint32_t *destPtr, *destBasePtr = (uint32_t *)( fRenderInfo.fDestPtr - c.fBaseline * fRenderInfo.fDestStride );
int16_t x, y, thisHeight, xstart, thisWidth;
uint8_t 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_t)c.fRightKern;
if( thisWidth >= fRenderInfo.fMaxWidth )
thisWidth = fRenderInfo.fMaxWidth;
xstart = fRenderInfo.fClipRect.fX - fRenderInfo.fX;
if( xstart < 0 )
xstart = 0;
srcA = (uint8_t)(( fRenderInfo.fColor >> 24 ) & 0x000000ff);
srcR = (uint8_t)(( fRenderInfo.fColor >> 16 ) & 0x000000ff);
srcG = (uint8_t)(( fRenderInfo.fColor >> 8 ) & 0x000000ff);
srcB = (uint8_t)(( fRenderInfo.fColor ) & 0x000000ff);
y = fRenderInfo.fClipRect.fY - fRenderInfo.fY + (int16_t)c.fBaseline;
if( y < 0 )
y = 0;
else
{
destBasePtr = (uint32_t *)( (uint8_t *)destBasePtr + y*fRenderInfo.fDestStride );
src += y*fRenderInfo.fNumCols;
}
thisHeight = fRenderInfo.fMaxHeight + (int16_t)c.fBaseline;
if( thisHeight > (int16_t)c.fHeight )
thisHeight = (int16_t)c.fHeight;
for( ; y < thisHeight; y++ )
{
destPtr = destBasePtr;
for( x = xstart; x < thisWidth; x++ )
{
uint32_t 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_t *)( (uint8_t *)destBasePtr + fRenderInfo.fDestStride );
src += fWidth;
}
}
void plFont::IRenderChar8To32AlphaPremShadow( const plFont::plCharacter &c )
{
uint32_t *destPtr, *destBasePtr = (uint32_t *)( fRenderInfo.fDestPtr - c.fBaseline * fRenderInfo.fDestStride );
int16_t x, y, thisHeight, xstart, thisWidth;
uint8_t 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 + 2;// + (int32_t)c.fRightKern;
if( thisWidth >= fRenderInfo.fMaxWidth )
thisWidth = fRenderInfo.fMaxWidth;
xstart = fRenderInfo.fClipRect.fX - fRenderInfo.fX;
if( xstart < -2 )
xstart = -2;
srcA = (uint8_t)(( fRenderInfo.fColor >> 24 ) & 0x000000ff);
srcR = (uint8_t)(( fRenderInfo.fColor >> 16 ) & 0x000000ff);
srcG = (uint8_t)(( fRenderInfo.fColor >> 8 ) & 0x000000ff);
srcB = (uint8_t)(( fRenderInfo.fColor ) & 0x000000ff);
static const uint32_t 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_t clamp = 220 - ((2 * srcR + 4 * srcG + srcB) >> 4);
y = fRenderInfo.fClipRect.fY - fRenderInfo.fY + (int16_t)c.fBaseline;
if( y < -2 )
y = -2;
destBasePtr = (uint32_t *)( (uint8_t *)destBasePtr + y*fRenderInfo.fDestStride );
thisHeight = fRenderInfo.fMaxHeight + (int16_t)c.fBaseline;
if( thisHeight > (int16_t)c.fHeight + 2 )
thisHeight = (int16_t)c.fHeight + 2;
for( ; y < thisHeight; y++ )
{
destPtr = destBasePtr;
for( x = xstart; x < thisWidth; x++ )
{
uint32_t sa = 0;
for (int32_t i = -2; i <= 2; i++) {
for (int32_t j = -2; j <= 2; j++) {
uint32_t 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_t a = IGetCharPixel(c, x, y);
if (srcA != 0xff)
a = (srcA * a + 127) / 255;
uint32_t 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_t *)( (uint8_t *)destBasePtr + fRenderInfo.fDestStride );
}
}
void plFont::IRenderCharNull( const plCharacter &c ) void plFont::IRenderCharNull( const plCharacter &c )
{ {

10
Sources/Plasma/PubUtilLib/plGImage/plFont.h

@ -116,6 +116,8 @@ class plFont : public hsKeyedObject
// value between the renderColor and the destColor and // value between the renderColor and the destColor and
// leave the alpha as-is // leave the alpha as-is
// This flag has no effect on monochrome fonts // This flag has no effect on monochrome fonts
kRenderAlphaPremultiplied = 0x00001000, // Destination has color values premultiplied by alpha
kRenderShadow = 0x00002000, // Render text shadows
}; };
enum Flags enum Flags
@ -231,8 +233,16 @@ class plFont : public hsKeyedObject
void IRenderChar8To32( const plCharacter &c ); void IRenderChar8To32( const plCharacter &c );
void IRenderChar8To32Alpha( const plCharacter &c ); void IRenderChar8To32Alpha( const plCharacter &c );
void IRenderChar8To32FullAlpha( const plCharacter &c ); void IRenderChar8To32FullAlpha( const plCharacter &c );
void IRenderChar8To32AlphaPremultiplied( const plCharacter &c );
void IRenderChar8To32AlphaPremShadow( const plCharacter &c );
void IRenderCharNull( const plCharacter &c ); void IRenderCharNull( const plCharacter &c );
uint32_t IGetCharPixel( const plCharacter &c, int32_t x, int32_t y )
{
// only for 8-bit characters
return (x < 0 || y < 0 || (uint32_t)x >= fWidth || (uint32_t)y >= c.fHeight) ? 0 : *(fBMapData + c.fBitmapOff + y*fWidth + x);
}
public: public:
plFont(); plFont();

20
Sources/Plasma/PubUtilLib/plGImage/plMipmap.cpp

@ -1746,6 +1746,18 @@ void plMipmap::Composite( plMipmap *source, uint16_t x, uint16_t y, plMipmap:
for( pY = (uint16_t)srcHeight; pY > 0; pY-- ) for( pY = (uint16_t)srcHeight; pY > 0; pY-- )
{ {
memcpy( dstPtr, srcPtr, srcRowBytesToCopy ); 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; dstPtr += dstRowBytes >> 2;
srcPtr += srcRowBytes >> 2; srcPtr += srcRowBytes >> 2;
} }
@ -1777,8 +1789,16 @@ void plMipmap::Composite( plMipmap *source, uint16_t x, uint16_t y, plMipmap:
{ {
srcAlpha = options->fOpacity * ( ( srcPtr[ pX ] >> 16 ) & 0x0000ff00 ) / 255 / 256; srcAlpha = options->fOpacity * ( ( srcPtr[ pX ] >> 16 ) & 0x0000ff00 ) / 255 / 256;
if( srcAlpha != 0 ) if( srcAlpha != 0 )
{
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[ pX ] = ( srcPtr[ pX ] & 0x00ffffff ) | ( srcAlpha << 24 );
} }
}
dstPtr += dstRowBytes >> 2; dstPtr += dstRowBytes >> 2;
srcPtr += srcRowBytes >> 2; srcPtr += srcRowBytes >> 2;
} }

5
Sources/Plasma/PubUtilLib/plGImage/plMipmap.h

@ -238,7 +238,10 @@ class plMipmap : public plBitmap
kCopySrcAlpha = 0x0002, // Copy the src pixels raw, including alphas, overwrite dest 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 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 kMaskSrcAlpha = 0x0008, // Same as copySrcAlpha, but dest is untouched when src alpha = 0
kBlendWriteAlpha= 0x0010 // Like default (0), but writes dest alpha values 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 class CompositeOptions

13
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" #include "pnMessage/plMessage.h"
class plPipeline;
class plDeviceRecreateMsg : public plMessage class plDeviceRecreateMsg : public plMessage
{ {
plPipeline* fPipe;
public: public:
plDeviceRecreateMsg() : plMessage( nil, nil, nil ) { SetBCastFlag( kBCastByExactType ); } plDeviceRecreateMsg(plPipeline* pipe=nullptr)
: plMessage(nullptr, nullptr, nullptr), fPipe(pipe)
{
SetBCastFlag(kBCastByExactType);
}
~plDeviceRecreateMsg() {} ~plDeviceRecreateMsg() {}
CLASSNAME_REGISTER( plDeviceRecreateMsg ); CLASSNAME_REGISTER( plDeviceRecreateMsg );
GETINTERFACE_ANY( plDeviceRecreateMsg, plMessage ); GETINTERFACE_ANY( plDeviceRecreateMsg, plMessage );
plPipeline* Pipeline() const { return fPipe; }
// IO // IO
void Read(hsStream* stream, hsResMgr* mgr) { plMessage::IMsgRead( stream, mgr ); } void Read(hsStream* stream, hsResMgr* mgr) { plMessage::IMsgRead( stream, mgr ); }
void Write(hsStream* stream, hsResMgr* mgr) { plMessage::IMsgWrite( stream, mgr ); } void Write(hsStream* stream, hsResMgr* mgr) { plMessage::IMsgWrite( stream, mgr ); }

20
Sources/Plasma/PubUtilLib/plPipeline/DX/plDXPipeline.cpp

@ -2264,7 +2264,7 @@ bool plDXPipeline::IResetDevice()
/// Broadcast a message letting everyone know that we were recreated and that /// Broadcast a message letting everyone know that we were recreated and that
/// all device-specific stuff needs to be recreated /// all device-specific stuff needs to be recreated
plDeviceRecreateMsg* clean = new plDeviceRecreateMsg(); plDeviceRecreateMsg* clean = new plDeviceRecreateMsg(this);
plgDispatch::MsgSend(clean); plgDispatch::MsgSend(clean);
} }
fDevWasLost = true; fDevWasLost = true;
@ -2533,7 +2533,7 @@ void plDXPipeline::Resize( uint32_t width, uint32_t height )
/// Broadcast a message letting everyone know that we were recreated and that /// Broadcast a message letting everyone know that we were recreated and that
/// all device-specific stuff needs to be recreated /// all device-specific stuff needs to be recreated
plDeviceRecreateMsg* clean = new plDeviceRecreateMsg(); plDeviceRecreateMsg* clean = new plDeviceRecreateMsg(this);
plgDispatch::MsgSend(clean); plgDispatch::MsgSend(clean);
} }
@ -3815,7 +3815,7 @@ bool plDXPipeline::BeginRender()
{ {
/// Broadcast a message letting everyone know that we were recreated and that /// Broadcast a message letting everyone know that we were recreated and that
/// all device-specific stuff needs to be recreated /// all device-specific stuff needs to be recreated
// plDeviceRecreateMsg* clean = new plDeviceRecreateMsg(); // plDeviceRecreateMsg* clean = new plDeviceRecreateMsg(this);
// plgDispatch::MsgSend(clean); // plgDispatch::MsgSend(clean);
fDevWasLost = false; fDevWasLost = false;
@ -7210,13 +7210,27 @@ void plDXPipeline::IHandleFirstStageBlend()
case hsGMatState::kBlendAlpha: case hsGMatState::kBlendAlpha:
fD3DDevice->SetRenderState( D3DRS_ALPHABLENDENABLE, TRUE ); fD3DDevice->SetRenderState( D3DRS_ALPHABLENDENABLE, TRUE );
if( fLayerState[0].fBlendFlags & hsGMatState::kBlendInvertFinalAlpha ) if( fLayerState[0].fBlendFlags & hsGMatState::kBlendInvertFinalAlpha )
{
if( fLayerState[0].fBlendFlags & hsGMatState::kBlendAlphaPremultiplied )
{
fD3DDevice->SetRenderState( D3DRS_SRCBLEND, D3DBLEND_ONE );
}
else
{ {
fD3DDevice->SetRenderState( D3DRS_SRCBLEND, D3DBLEND_INVSRCALPHA ); fD3DDevice->SetRenderState( D3DRS_SRCBLEND, D3DBLEND_INVSRCALPHA );
}
fD3DDevice->SetRenderState( D3DRS_DESTBLEND, D3DBLEND_SRCALPHA ); fD3DDevice->SetRenderState( D3DRS_DESTBLEND, D3DBLEND_SRCALPHA );
} }
else else
{
if( fLayerState[0].fBlendFlags & hsGMatState::kBlendAlphaPremultiplied )
{
fD3DDevice->SetRenderState( D3DRS_SRCBLEND, D3DBLEND_ONE );
}
else
{ {
fD3DDevice->SetRenderState( D3DRS_SRCBLEND, D3DBLEND_SRCALPHA ); fD3DDevice->SetRenderState( D3DRS_SRCBLEND, D3DBLEND_SRCALPHA );
}
fD3DDevice->SetRenderState( D3DRS_DESTBLEND, D3DBLEND_INVSRCALPHA ); fD3DDevice->SetRenderState( D3DRS_DESTBLEND, D3DBLEND_INVSRCALPHA );
} }
break; break;

Loading…
Cancel
Save