Text class refactor (improve memory footprint)

This commit is contained in:
Martín Lucas Golini
2023-09-11 22:35:03 -03:00
parent bfd49ea019
commit 648adb4d7f
8 changed files with 232 additions and 336 deletions

View File

@@ -31,6 +31,13 @@ class FontStyleConfig {
FontStyleConfig() {}
bool operator==( const FontStyleConfig& other ) {
return Font == other.Font && CharacterSize == other.CharacterSize && Style == other.Style &&
FontColor == other.FontColor && ShadowColor == other.ShadowColor &&
ShadowOffset == other.ShadowOffset && OutlineThickness == other.OutlineThickness &&
OutlineColor == other.OutlineColor;
}
virtual void updateFontStyleConfig( const FontStyleConfig& fontStyleConfig ) {
Font = fontStyleConfig.Font;
Style = fontStyleConfig.Style;
@@ -42,14 +49,14 @@ class FontStyleConfig {
OutlineColor = fontStyleConfig.OutlineColor;
}
Graphics::Font* Font = NULL;
Float CharacterSize = 12;
Uint32 Style = 0;
Color FontColor = Color( 255, 255, 255, 255 );
Color ShadowColor = Color( 50, 50, 50, 230 );
Graphics::Font* Font{ nullptr };
Float CharacterSize{ 12 };
Uint32 Style{ 0 };
Color FontColor{ 255, 255, 255, 255 };
Color ShadowColor{ 50, 50, 50, 230 };
Vector2f ShadowOffset{ PixelDensity::dpToPx( 1 ), PixelDensity::dpToPx( 1 ) };
Float OutlineThickness = 0;
Color OutlineColor = Color( 0, 0, 0, 255 );
Float OutlineThickness{ 0 };
Color OutlineColor{ 0, 0, 0, 255 };
};
}} // namespace EE::Graphics

View File

@@ -134,7 +134,7 @@ class EE_API Text {
const Uint32& getAlign() const;
/** @return The number of lines that the cached text contains */
const int& getNumLines();
Uint32 getNumLines();
void setStyleConfig( const FontStyleConfig& styleConfig );
@@ -188,39 +188,26 @@ class EE_API Text {
};
String mString; ///< String to display
Font* mFont{ nullptr }; ///< FontTrueType used to display the string
unsigned int mFontSize; ///< Base size of characters, in pixels
unsigned int mRealFontSize;
Uint32 mStyle; ///< Text style (see Style enum)
Color mFillColor; ///< Text fill color
Color mOutlineColor; ///< Text outline color
FontStyleConfig mFontStyleConfig;
Uint32 mRealFontSize;
Color mBackgroundColor{ Color::Transparent };
Float mOutlineThickness; ///< Thickness of the text's outline
mutable Rectf mBounds; ///< Bounding rectangle of the text (in local coordinates)
mutable bool mGeometryNeedUpdate; ///< Does the geometry need to be recomputed?
mutable bool mCachedWidthNeedUpdate;
mutable bool mColorsNeedUpdate;
mutable bool mGeometryNeedUpdate{ false }; ///< Does the geometry need to be recomputed?
mutable bool mCachedWidthNeedUpdate{ false };
mutable bool mColorsNeedUpdate{ false };
mutable bool mContainsColorEmoji{ false };
bool mDisableCacheWidth{ false };
Float mCachedWidth;
int mNumLines;
int mLargestLineCharCount;
Color mShadowColor;
Vector2f mShadowOffset{ PixelDensity::dpToPx( 1 ), PixelDensity::dpToPx( 1 ) };
Float mCachedWidth{ 0 };
Uint32 mAlign{ TEXT_ALIGN_LEFT };
Uint32 mFontHeight;
Uint32 mTabWidth;
Uint32 mFontHeight{ 0 };
Uint32 mTabWidth{ 4 };
std::vector<VertexCoords> mVertices;
std::vector<Rectf> mGlyphCache;
std::vector<Color> mColors;
std::vector<VertexCoords> mOutlineVertices;
std::vector<Color> mOutlineColors;
std::vector<Float> mLinesWidth;
std::vector<Uint32> mLinesStartIndex;
void ensureGeometryUpdate();
@@ -239,7 +226,7 @@ class EE_API Text {
Uint32 getTotalVertices();
/** Cache the with of the current text */
void getWidthInfo();
void updateWidthCache();
void draw( const Float& X, const Float& Y, const Vector2f& scale, const Float& rotation,
BlendMode effect, const OriginPoint& rotationCenter, const OriginPoint& scaleCenter,

View File

@@ -73,7 +73,7 @@ class EE_API UITextView : public UIWidget {
Float getTextHeight();
const int& getNumLines() const;
Uint32 getNumLines();
Vector2f getAlignOffset() const;

View File

@@ -60,7 +60,7 @@ class EE_API UITooltip : public UIWidget {
Float getTextHeight();
const int& getNumLines() const;
Uint32 getNumLines();
Vector2f getAlignOffset();

View File

@@ -82,90 +82,39 @@ Text* Text::New( Font* font, unsigned int characterSize ) {
return eeNew( Text, ( font, characterSize ) );
}
Text::Text() :
mString(),
mFont( NULL ),
mFontSize( 12 ),
mRealFontSize( PixelDensity::dpToPxI( mFontSize ) ),
mStyle( Regular ),
mFillColor( 255, 255, 255, 255 ),
mOutlineColor( 0, 0, 0, 255 ),
mOutlineThickness( 0 ),
mGeometryNeedUpdate( false ),
mCachedWidthNeedUpdate( false ),
mColorsNeedUpdate( false ),
mCachedWidth( 0 ),
mNumLines( 0 ),
mLargestLineCharCount( 0 ),
mShadowColor( Color( 0, 0, 0, 255 ) ),
mAlign( TEXT_ALIGN_LEFT ),
mFontHeight( 0 ),
mTabWidth( 4 ) {}
Text::Text() {}
Text::Text( const String& string, Font* font, unsigned int characterSize ) :
mString( string ),
mFont( font ),
mFontSize( characterSize ),
mRealFontSize( PixelDensity::dpToPxI( mFontSize ) ),
mStyle( Regular ),
mFillColor( 255, 255, 255, 255 ),
mOutlineColor( 0, 0, 0, 255 ),
mOutlineThickness( 0 ),
mGeometryNeedUpdate( true ),
mCachedWidthNeedUpdate( true ),
mColorsNeedUpdate( true ),
mCachedWidth( 0 ),
mNumLines( 0 ),
mLargestLineCharCount( 0 ),
mShadowColor( Color( 0, 0, 0, 255 ) ),
mAlign( TEXT_ALIGN_LEFT ),
mFontHeight( mFont->getFontHeight( mRealFontSize ) ),
mTabWidth( 4 ) {
if ( !mFont->isScalable() ) {
mFontSize = mFontHeight;
mRealFontSize = mFontHeight;
}
Text( font, characterSize ) {
mString = string;
invalidate();
}
Text::Text( Font* font, unsigned int characterSize ) :
mFont( font ),
mFontSize( characterSize ),
mRealFontSize( PixelDensity::dpToPxI( mFontSize ) ),
mStyle( Regular ),
mFillColor( 255, 255, 255, 255 ),
mOutlineColor( 0, 0, 0, 255 ),
mOutlineThickness( 0 ),
mGeometryNeedUpdate( true ),
mCachedWidthNeedUpdate( true ),
mColorsNeedUpdate( true ),
mCachedWidth( 0 ),
mNumLines( 0 ),
mLargestLineCharCount( 0 ),
mShadowColor( Color( 0, 0, 0, 255 ) ),
mAlign( TEXT_ALIGN_LEFT ),
mFontHeight( mFont->getFontHeight( mRealFontSize ) ),
mTabWidth( 4 ) {
if ( !mFont->isScalable() ) {
mFontSize = mFontHeight;
mRealFontSize( PixelDensity::dpToPxI( characterSize ) ) {
mFontStyleConfig.Font = font;
mFontStyleConfig.CharacterSize = characterSize;
mFontHeight = mFontStyleConfig.Font->getFontHeight( mRealFontSize );
if ( !mFontStyleConfig.Font->isScalable() ) {
mFontStyleConfig.CharacterSize = mFontHeight;
mRealFontSize = mFontHeight;
}
}
void Text::create( Font* font, const String& text, Color FontColor, Color FontShadowColor,
Uint32 characterSize ) {
mFont = font;
mFontStyleConfig.Font = font;
mFontStyleConfig.CharacterSize = characterSize;
mRealFontSize = PixelDensity::dpToPxI( characterSize );
mFontHeight = mFontStyleConfig.Font->getFontHeight( mRealFontSize );
if ( !mFontStyleConfig.Font->isScalable() ) {
mFontStyleConfig.CharacterSize = mFontHeight;
mRealFontSize = mFontHeight;
}
mString = text;
mFontSize = characterSize;
mRealFontSize = PixelDensity::dpToPxI( mFontSize );
Float dp = PixelDensity::dpToPx( 1 );
mShadowOffset = { dp, dp };
setFillColor( FontColor );
setShadowColor( FontShadowColor );
mGeometryNeedUpdate = true;
mCachedWidthNeedUpdate = true;
mColorsNeedUpdate = true;
ensureColorUpdate();
ensureGeometryUpdate();
invalidate();
}
void Text::setString( const String& string ) {
@@ -176,8 +125,8 @@ void Text::setString( const String& string ) {
mCachedWidthNeedUpdate = true;
mContainsColorEmoji = false;
if ( FontManager::instance()->getColorEmojiFont() != nullptr ) {
if ( mFont->getType() == FontType::TTF ) {
FontTrueType* fontTrueType = static_cast<FontTrueType*>( mFont );
if ( mFontStyleConfig.Font->getType() == FontType::TTF ) {
FontTrueType* fontTrueType = static_cast<FontTrueType*>( mFontStyleConfig.Font );
if ( fontTrueType->isColorEmojiFont() || !fontTrueType->isEmojiFont() )
mContainsColorEmoji = Font::containsEmojiCodePoint( string );
}
@@ -186,13 +135,13 @@ void Text::setString( const String& string ) {
}
void Text::setFont( Font* font ) {
if ( NULL != font && mFont != font ) {
mFont = font;
if ( NULL != font && mFontStyleConfig.Font != font ) {
mFontStyleConfig.Font = font;
mRealFontSize = PixelDensity::dpToPxI( mFontSize );
mFontHeight = mFont->getFontHeight( mRealFontSize );
if ( !mFont->isScalable() ) {
mFontSize = mFontHeight;
mRealFontSize = PixelDensity::dpToPxI( mFontStyleConfig.CharacterSize );
mFontHeight = mFontStyleConfig.Font->getFontHeight( mRealFontSize );
if ( !mFontStyleConfig.Font->isScalable() ) {
mFontStyleConfig.CharacterSize = mFontHeight;
mRealFontSize = mFontHeight;
}
mGeometryNeedUpdate = true;
@@ -201,13 +150,13 @@ void Text::setFont( Font* font ) {
}
void Text::setFontSize( unsigned int size ) {
if ( NULL != mFont && mFontSize != size ) {
mFontSize = size;
if ( NULL != mFontStyleConfig.Font && mFontStyleConfig.CharacterSize != size ) {
mFontStyleConfig.CharacterSize = size;
mRealFontSize = PixelDensity::dpToPxI( mFontSize );
mFontHeight = mFont->getFontHeight( mRealFontSize );
if ( !mFont->isScalable() ) {
mFontSize = mFontHeight;
mRealFontSize = PixelDensity::dpToPxI( mFontStyleConfig.CharacterSize );
mFontHeight = mFontStyleConfig.Font->getFontHeight( mRealFontSize );
if ( !mFontStyleConfig.Font->isScalable() ) {
mFontStyleConfig.CharacterSize = mFontHeight;
mRealFontSize = mFontHeight;
}
@@ -217,8 +166,8 @@ void Text::setFontSize( unsigned int size ) {
}
void Text::setStyle( Uint32 style ) {
if ( mStyle != style ) {
mStyle = style;
if ( mFontStyleConfig.Style != style ) {
mFontStyleConfig.Style = style;
mColorsNeedUpdate = true;
mGeometryNeedUpdate = true;
mCachedWidthNeedUpdate = true;
@@ -230,22 +179,22 @@ void Text::setColor( const Color& color ) {
}
void Text::setFillColor( const Color& color ) {
if ( color != mFillColor ) {
mFillColor = color;
if ( color != mFontStyleConfig.FontColor ) {
mFontStyleConfig.FontColor = color;
mColorsNeedUpdate = true;
}
}
void Text::setOutlineColor( const Color& color ) {
if ( color != mOutlineColor ) {
mOutlineColor = color;
if ( color != mFontStyleConfig.OutlineColor ) {
mFontStyleConfig.OutlineColor = color;
mColorsNeedUpdate = true;
}
}
void Text::setOutlineThickness( Float thickness ) {
if ( thickness != mOutlineThickness ) {
mOutlineThickness = thickness;
if ( thickness != mFontStyleConfig.OutlineThickness ) {
mFontStyleConfig.OutlineThickness = thickness;
mColorsNeedUpdate = true;
mGeometryNeedUpdate = true;
mCachedWidthNeedUpdate = true;
@@ -273,11 +222,11 @@ String& Text::getString() {
}
Font* Text::getFont() const {
return mFont;
return mFontStyleConfig.Font;
}
unsigned int Text::getCharacterSize() const {
return mFontSize;
return mFontStyleConfig.CharacterSize;
}
unsigned int Text::getCharacterSizePx() const {
@@ -289,7 +238,7 @@ const Uint32& Text::getFontHeight() const {
}
Uint32 Text::getStyle() const {
return mStyle;
return mFontStyleConfig.Style;
}
void Text::setAlpha( const Uint8& alpha ) {
@@ -297,11 +246,11 @@ void Text::setAlpha( const Uint8& alpha ) {
for ( Uint32 i = 0; i < s; i++ ) {
mColors[i].a = alpha;
}
mFillColor.a = alpha;
mFontStyleConfig.FontColor.a = alpha;
}
const Color& Text::getFillColor() const {
return mFillColor;
return mFontStyleConfig.FontColor;
}
const Color& Text::getColor() const {
@@ -309,70 +258,34 @@ const Color& Text::getColor() const {
}
const Color& Text::getOutlineColor() const {
return mOutlineColor;
return mFontStyleConfig.OutlineColor;
}
Float Text::getOutlineThickness() const {
return mOutlineThickness;
return mFontStyleConfig.OutlineThickness;
}
Vector2f Text::findCharacterPos( std::size_t index ) const {
// Make sure that we have a valid font
if ( !mFont || mString.empty() )
if ( !mFontStyleConfig.Font || mString.empty() )
return Vector2f();
// Adjust the index if it's out of range
if ( index > mString.size() )
index = mString.size();
const_cast<Text*>( this )->ensureGeometryUpdate();
return Vector2f( mGlyphCache[index].Left, mGlyphCache[index].Top );
return Text::findCharacterPos( index, mFontStyleConfig.Font, mRealFontSize, mString,
mFontStyleConfig.Style, mTabWidth,
mFontStyleConfig.OutlineThickness );
}
Int32 Text::findCharacterFromPos( const Vector2i& pos, bool ) const {
if ( NULL == mFont || mString.empty() )
Int32 Text::findCharacterFromPos( const Vector2i& pos, bool nearest ) const {
if ( NULL == mFontStyleConfig.Font || mString.empty() )
return 0;
const_cast<Text*>( this )->ensureGeometryUpdate();
if ( mLinesStartIndex.empty() )
return 0;
Vector2f charCenter;
Int32 nearest = 0;
Int32 minDist = std::numeric_limits<Int32>::max();
Int32 curDist = -1;
Vector2f fpos( pos.asFloat() );
Float textHeight = mFont->getLineSpacing( mRealFontSize );
Int32 approximateSearchLine = static_cast<Int32>( eefloor( pos.y / textHeight ) );
approximateSearchLine = eemin(
eemax( 0, approximateSearchLine ),
static_cast<Int32>( mLinesStartIndex.size() > 1 ? mLinesStartIndex.size() : 1 ) - 1 );
size_t start = mLinesStartIndex[approximateSearchLine];
size_t end = approximateSearchLine == static_cast<Int32>( mLinesStartIndex.size() ) - 1
? mString.size()
: mLinesStartIndex[approximateSearchLine + 1];
if ( mString[start] == '\n' && start + 1 < mString.size() ) {
start++;
}
if ( end >= mGlyphCache.size() )
end = mGlyphCache.size() - 1;
for ( std::size_t i = start; i <= end; ++i ) {
charCenter.x = mGlyphCache[i].Left;
charCenter.y = mGlyphCache[i].Top + mGlyphCache[i].getHeight();
curDist = eeabs( fpos.distance( charCenter ) );
if ( curDist < minDist ) {
nearest = i;
minDist = curDist;
}
}
return nearest;
return Text::findCharacterFromPos( pos, nearest, mFontStyleConfig.Font, mRealFontSize, mString,
mFontStyleConfig.Style, mTabWidth,
mFontStyleConfig.OutlineThickness );
}
static bool isStopSelChar( Uint32 c ) {
@@ -429,14 +342,15 @@ Float Text::getTextWidth( Font* font, const Uint32& fontSize, const String& stri
Glyph glyph = font->getGlyph( rune, fontSize, bold, italic, outlineThickness );
if ( rune != '\r' && rune != '\t' ) {
width += font->getKerning( prevChar, rune, fontSize, bold, italic, outlineThickness );
prevChar = rune;
width += glyph.advance;
} else if ( rune == '\t' ) {
width += hspace * tabWidth;
} else if ( rune == '\n' ) {
}
if ( rune == '\n' ) {
width = 0;
}
maxWidth = eemax( width, maxWidth );
prevChar = rune;
}
return maxWidth;
}
@@ -527,7 +441,8 @@ Int32 Text::findCharacterFromPos( const Vector2i& pos, bool returnNearest, Font*
width += glyph.advance;
} else if ( rune == '\t' ) {
width += hspace * tabWidth;
} else if ( rune == '\n' ) {
}
if ( rune == '\n' ) {
lWidth = 0;
width = 0;
}
@@ -565,72 +480,55 @@ Int32 Text::findCharacterFromPos( const Vector2i& pos, bool returnNearest, Font*
return nearest;
}
void Text::getWidthInfo() {
if ( NULL == mFont || mString.empty() )
void Text::updateWidthCache() {
if ( NULL == mFontStyleConfig.Font || mString.empty() )
return;
mLinesWidth.clear();
mLinesStartIndex.clear();
Float Width = 0, MaxWidth = 0;
Uint32 CharID;
Int32 Lines = 1;
Int32 CharCount = 0;
Float width = 0;
Float maxWidth = 0;
Uint32 rune;
Uint32 prevChar = 0;
mLargestLineCharCount = 0;
bool bold = ( mStyle & Bold ) != 0;
bool italic = ( mStyle & Italic ) != 0;
mLinesStartIndex.push_back( 0 );
bool bold = ( mFontStyleConfig.Style & Bold ) != 0;
bool italic = ( mFontStyleConfig.Style & Italic ) != 0;
Float hspace = static_cast<Float>(
mFont->getGlyph( L' ', mRealFontSize, bold, italic, mOutlineThickness ).advance );
mFontStyleConfig.Font
->getGlyph( L' ', mRealFontSize, bold, italic, mFontStyleConfig.OutlineThickness )
.advance );
for ( std::size_t i = 0; i < mString.size(); ++i ) {
CharID = static_cast<Int32>( mString.at( i ) );
const Glyph& glyph =
mFont->getGlyph( CharID, mRealFontSize, bold, italic, mOutlineThickness );
if ( CharID != '\r' && CharID != '\t' ) {
Width += mFont->getKerning( prevChar, CharID, mRealFontSize, bold, italic,
mOutlineThickness );
prevChar = CharID;
Width += glyph.advance;
size_t size = mString.size();
for ( std::size_t i = 0; i < size; ++i ) {
rune = mString[i];
const Glyph& glyph = mFontStyleConfig.Font->getGlyph( rune, mRealFontSize, bold, italic,
mFontStyleConfig.OutlineThickness );
if ( rune != '\r' && rune != '\t' ) {
width += mFontStyleConfig.Font->getKerning( prevChar, rune, mRealFontSize, bold, italic,
mFontStyleConfig.OutlineThickness );
width += glyph.advance;
} else if ( rune == '\t' ) {
width += hspace * mTabWidth;
}
CharCount++;
if ( CharID == '\t' ) {
Width += hspace * mTabWidth;
}
if ( CharID == '\n' ) {
mLinesStartIndex.push_back( i );
Lines++;
mLinesWidth.push_back( Width - glyph.advance );
Width = 0;
CharCount = 0;
} else {
if ( CharCount > mLargestLineCharCount )
mLargestLineCharCount = CharCount;
if ( rune == '\n' ) {
mLinesWidth.push_back( width - glyph.advance );
width = 0;
}
if ( Width > MaxWidth )
MaxWidth = Width;
if ( width > maxWidth )
maxWidth = width;
prevChar = rune;
}
if ( mString.size() && mString.at( mString.size() - 1 ) != '\n' ) {
mLinesWidth.push_back( Width );
}
if ( !mString.empty() && mString[mString.size() - 1] != '\n' )
mLinesWidth.push_back( width );
mCachedWidth = MaxWidth;
mNumLines = Lines;
mCachedWidth = maxWidth;
}
void Text::wrapText( const Uint32& maxWidth ) {
if ( !mString.size() || NULL == mFont )
if ( !mString.size() || NULL == mFontStyleConfig.Font )
return;
Float tCurWidth = 0.f;
@@ -639,14 +537,17 @@ void Text::wrapText( const Uint32& maxWidth ) {
String::StringBaseType* tChar = &mString[0];
String::StringBaseType* tLastSpace = NULL;
Uint32 prevChar = 0;
bool bold = ( mStyle & Bold ) != 0;
bool italic = ( mStyle & Italic ) != 0;
bool bold = ( mFontStyleConfig.Style & Bold ) != 0;
bool italic = ( mFontStyleConfig.Style & Italic ) != 0;
Float hspace = static_cast<Float>(
mFont->getGlyph( L' ', mRealFontSize, bold, italic, mOutlineThickness ).advance );
mFontStyleConfig.Font
->getGlyph( L' ', mRealFontSize, bold, italic, mFontStyleConfig.OutlineThickness )
.advance );
while ( *tChar ) {
Glyph pChar = mFont->getGlyph( *tChar, mRealFontSize, bold, italic, mOutlineThickness );
Glyph pChar = mFontStyleConfig.Font->getGlyph( *tChar, mRealFontSize, bold, italic,
mFontStyleConfig.OutlineThickness );
Float fCharWidth = (Float)pChar.advance;
@@ -659,8 +560,8 @@ void Text::wrapText( const Uint32& maxWidth ) {
tWordWidth += fCharWidth;
if ( *tChar != '\r' ) {
tWordWidth += mFont->getKerning( prevChar, *tChar, mRealFontSize, bold, italic,
mOutlineThickness );
tWordWidth += mFontStyleConfig.Font->getKerning(
prevChar, *tChar, mRealFontSize, bold, italic, mFontStyleConfig.OutlineThickness );
prevChar = *tChar;
}
@@ -738,20 +639,12 @@ void Text::setBackgroundColor( const Color& backgroundColor ) {
mBackgroundColor = backgroundColor;
}
bool Text::getDisableCacheWidth() const {
return mDisableCacheWidth;
}
void Text::setDisableCacheWidth( bool newDisableCacheWidth ) {
mDisableCacheWidth = newDisableCacheWidth;
}
const Vector2f& Text::getShadowOffset() const {
return mShadowOffset;
return mFontStyleConfig.ShadowOffset;
}
void Text::setShadowOffset( const Vector2f& shadowOffset ) {
mShadowOffset = shadowOffset;
mFontStyleConfig.ShadowOffset = shadowOffset;
}
Rectf Text::getLocalBounds() {
@@ -769,13 +662,14 @@ Float Text::getTextWidth() {
Float Text::getTextHeight() {
cacheWidth();
return NULL != mFont
? mFont->getLineSpacing( mRealFontSize ) * ( 0 == mNumLines ? 1 : mNumLines )
: 0;
return NULL != mFontStyleConfig.Font ? mFontStyleConfig.Font->getLineSpacing( mRealFontSize ) *
( mLinesWidth.empty() ? 1 : mLinesWidth.size() )
: 0;
}
Float Text::getLineSpacing() {
return NULL != mFont ? mFont->getLineSpacing( mRealFontSize ) : 0;
return NULL != mFontStyleConfig.Font ? mFontStyleConfig.Font->getLineSpacing( mRealFontSize )
: 0;
}
void Text::draw( const Float& X, const Float& Y, const Vector2f& scale, const Float& rotation,
@@ -826,7 +720,7 @@ void Text::draw( const Float& X, const Float& Y, const Vector2f& scale, const Fl
p.drawRectangle( getLocalBounds() );
}
Texture* texture = mFont->getTexture( mRealFontSize );
Texture* texture = mFontStyleConfig.Font->getTexture( mRealFontSize );
if ( !texture )
return;
texture->bind();
@@ -835,7 +729,7 @@ void Text::draw( const Float& X, const Float& Y, const Vector2f& scale, const Fl
Uint32 alloc = numvert * sizeof( VertexCoords );
Uint32 allocC = numvert * GLi->quadVertexs();
if ( 0 != mOutlineThickness ) {
if ( 0 != mFontStyleConfig.OutlineThickness ) {
GLi->colorPointer( 4, GL_UNSIGNED_BYTE, 0,
reinterpret_cast<const char*>( outlineColors.data() ), allocC );
GLi->texCoordPointer( 2, GL_FP, sizeof( VertexCoords ),
@@ -874,21 +768,21 @@ void Text::draw( const Float& X, const Float& Y, const Vector2f& scale, const Fl
void Text::draw( const Float& X, const Float& Y, const Vector2f& scale, const Float& rotation,
BlendMode effect, const OriginPoint& rotationCenter,
const OriginPoint& scaleCenter ) {
if ( NULL == mFont )
if ( NULL == mFontStyleConfig.Font )
return;
ensureColorUpdate();
ensureGeometryUpdate();
if ( mStyle & Shadow ) {
if ( mFontStyleConfig.Style & Shadow ) {
std::vector<Color> colors;
Color shadowColor( getShadowColor() );
if ( getFillColor().a != 255 )
shadowColor.a =
(Uint8)( (Float)shadowColor.a * ( (Float)getFillColor().a / (Float)255 ) );
colors.assign( mColors.size(), shadowColor );
draw( X + mShadowOffset.x, Y + mShadowOffset.y, scale, rotation, effect, rotationCenter,
scaleCenter, colors, {}, Color::Transparent );
draw( X + mFontStyleConfig.ShadowOffset.x, Y + mFontStyleConfig.ShadowOffset.y, scale,
rotation, effect, rotationCenter, scaleCenter, colors, {}, Color::Transparent );
}
draw( X, Y, scale, rotation, effect, rotationCenter, scaleCenter, mColors, mOutlineColors,
@@ -896,7 +790,7 @@ void Text::draw( const Float& X, const Float& Y, const Vector2f& scale, const Fl
}
void Text::ensureGeometryUpdate() {
if ( !mDisableCacheWidth )
if ( mCachedWidthNeedUpdate && mAlign != TEXT_ALIGN_LEFT )
cacheWidth();
// Do nothing, if geometry has not changed
@@ -908,42 +802,45 @@ void Text::ensureGeometryUpdate() {
// Clear the previous geometry
mVertices.clear();
mGlyphCache.clear();
mOutlineVertices.clear();
if ( mCachedWidthNeedUpdate )
mLinesWidth.clear();
mBounds = Rectf();
// No font or text: nothing to draw
if ( !mFont || mString.empty() )
if ( !mFontStyleConfig.Font || mString.empty() )
return;
mVertices.reserve( mString.size() * GLi->quadVertexs() );
mGlyphCache.reserve( mString.size() );
if ( mOutlineThickness != 0.f )
if ( mFontStyleConfig.OutlineThickness != 0.f )
mOutlineVertices.reserve( mString.size() * GLi->quadVertexs() );
// Compute values related to the text style
bool bold = ( mStyle & Bold ) != 0;
bool reqItalic = ( mStyle & Italic ) != 0;
bool underlined = ( mStyle & Underlined ) != 0;
bool strikeThrough = ( mStyle & StrikeThrough ) != 0;
Float italic = reqItalic && !mFont->hasItalic() ? 0.208f : 0.f; // 12 degrees
Float underlineOffset = mFont->getUnderlinePosition( mRealFontSize );
Float underlineThickness = mFont->getUnderlineThickness( mRealFontSize );
bool bold = ( mFontStyleConfig.Style & Bold ) != 0;
bool reqItalic = ( mFontStyleConfig.Style & Italic ) != 0;
bool underlined = ( mFontStyleConfig.Style & Underlined ) != 0;
bool strikeThrough = ( mFontStyleConfig.Style & StrikeThrough ) != 0;
Float italic = reqItalic && !mFontStyleConfig.Font->hasItalic() ? 0.208f : 0.f; // 12 degrees
Float underlineOffset = mFontStyleConfig.Font->getUnderlinePosition( mRealFontSize );
Float underlineThickness = mFontStyleConfig.Font->getUnderlineThickness( mRealFontSize );
// Compute the location of the strike through dynamically
// We use the center point of the lowercase 'x' glyph as the reference
// We reuse the underline thickness as the thickness of the strike through as well
Float strikeThroughOffset = 0;
if ( strikeThrough ) {
Rectf xBounds = mFont->getGlyph( L'x', mRealFontSize, bold, reqItalic ).bounds;
Rectf xBounds =
mFontStyleConfig.Font->getGlyph( L'x', mRealFontSize, bold, reqItalic ).bounds;
strikeThroughOffset = xBounds.Top + xBounds.Bottom / 2.f;
}
// Precompute the variables needed by the algorithm
Float hspace =
static_cast<Float>( mFont->getGlyph( L' ', mRealFontSize, bold, reqItalic ).advance );
Float vspace = static_cast<Float>( mFont->getLineSpacing( mRealFontSize ) );
Float hspace = static_cast<Float>(
mFontStyleConfig.Font->getGlyph( L' ', mRealFontSize, bold, reqItalic ).advance );
Float vspace = static_cast<Float>( mFontStyleConfig.Font->getLineSpacing( mRealFontSize ) );
Float x = 0.f;
Float y = static_cast<Float>( mRealFontSize );
@@ -952,8 +849,10 @@ void Text::ensureGeometryUpdate() {
Float minY = static_cast<Float>( mRealFontSize );
Float maxX = 0.f;
Float maxY = 0.f;
Float maxW = 0.f;
Uint32 prevChar = 0;
size_t size = mString.size();
Float centerDiffX = 0;
unsigned int line = 0;
@@ -970,21 +869,21 @@ void Text::ensureGeometryUpdate() {
break;
}
for ( std::size_t i = 0; i < mString.size(); ++i ) {
for ( std::size_t i = 0; i < size; ++i ) {
Uint32 curChar = mString[i];
// Apply the kerning offset
x += mFont->getKerning( prevChar, curChar, mRealFontSize, bold, reqItalic,
mOutlineThickness );
x += mFontStyleConfig.Font->getKerning( prevChar, curChar, mRealFontSize, bold, reqItalic,
mFontStyleConfig.OutlineThickness );
prevChar = curChar;
// If we're using the underlined style and there's a new line, draw a line
if ( underlined && ( curChar == L'\n' ) ) {
addLine( mVertices, x, y, underlineOffset, underlineThickness, 0, centerDiffX );
if ( mOutlineThickness != 0 )
if ( mFontStyleConfig.OutlineThickness != 0 )
addLine( mOutlineVertices, x, y, underlineOffset, underlineThickness,
mOutlineThickness, centerDiffX );
mFontStyleConfig.OutlineThickness, centerDiffX );
}
// If we're using the strike through style and there's a new line, draw a line across all
@@ -992,9 +891,9 @@ void Text::ensureGeometryUpdate() {
if ( strikeThrough && ( curChar == L'\n' ) ) {
addLine( mVertices, x, y, strikeThroughOffset, underlineThickness, 0, centerDiffX );
if ( mOutlineThickness != 0 )
if ( mFontStyleConfig.OutlineThickness != 0 )
addLine( mOutlineVertices, x, y, strikeThroughOffset, underlineThickness,
mOutlineThickness, centerDiffX );
mFontStyleConfig.OutlineThickness, centerDiffX );
}
if ( curChar == L'\n' ) {
@@ -1015,27 +914,24 @@ void Text::ensureGeometryUpdate() {
}
// Handle special characters
if ( ( curChar == ' ' ) || ( curChar == '\t' ) || ( curChar == '\n' ) ||
( curChar == '\r' ) ) {
if ( curChar == ' ' || curChar == '\t' || curChar == '\n' || curChar == '\r' ) {
// Update the current bounds (min coordinates)
minX = std::min( minX, x );
minY = std::min( minY, y );
switch ( curChar ) {
case ' ':
mGlyphCache.emplace_back(
Rectf( Vector2f( x, y - mRealFontSize ), Sizef( hspace, vspace ) ) );
x += hspace;
break;
case '\t':
mGlyphCache.emplace_back( Rectf( Vector2f( x, y - mRealFontSize ),
Sizef( hspace * mTabWidth, vspace ) ) );
x += hspace * mTabWidth;
break;
case '\n':
mGlyphCache.emplace_back(
Rectf( Vector2f( x, y - mRealFontSize ), Sizef( 0, vspace ) ) );
y += vspace;
if ( mCachedWidthNeedUpdate )
mLinesWidth.push_back( x );
x = 0;
break;
case '\r':
@@ -1046,14 +942,17 @@ void Text::ensureGeometryUpdate() {
maxX = std::max( maxX, x );
maxY = std::max( maxY, y );
if ( mCachedWidthNeedUpdate )
maxW = std::max( maxW, x );
// Next glyph, no need to create a quad for whitespace
continue;
}
// Apply the outline
if ( mOutlineThickness != 0 ) {
const Glyph& glyph =
mFont->getGlyph( curChar, mRealFontSize, bold, italic, mOutlineThickness );
if ( mFontStyleConfig.OutlineThickness != 0 ) {
const Glyph& glyph = mFontStyleConfig.Font->getGlyph(
curChar, mRealFontSize, bold, italic, mFontStyleConfig.OutlineThickness );
Float left = glyph.bounds.Left;
Float top = glyph.bounds.Top;
@@ -1061,24 +960,28 @@ void Text::ensureGeometryUpdate() {
Float bottom = glyph.bounds.Top + glyph.bounds.Bottom;
// Add the outline glyph to the vertices
addGlyphQuad( mOutlineVertices, Vector2f( x, y ), glyph, italic, mOutlineThickness,
centerDiffX );
addGlyphQuad( mOutlineVertices, Vector2f( x, y ), glyph, italic,
mFontStyleConfig.OutlineThickness, centerDiffX );
// Update the current bounds with the outlined glyph bounds
minX = std::min( minX, x + left - italic * bottom - mOutlineThickness );
maxX = std::max( maxX, x + right - italic * top - mOutlineThickness );
minY = std::min( minY, y + top - mOutlineThickness );
maxY = std::max( maxY, y + bottom - mOutlineThickness );
minX = std::min( minX, x + left - italic * bottom - mFontStyleConfig.OutlineThickness );
maxX = std::max( maxX, x + right - italic * top - mFontStyleConfig.OutlineThickness );
minY = std::min( minY, y + top - mFontStyleConfig.OutlineThickness );
maxY = std::max( maxY, y + bottom - mFontStyleConfig.OutlineThickness );
if ( mCachedWidthNeedUpdate )
maxW = std::max( maxW, x + glyph.advance - italic * top -
mFontStyleConfig.OutlineThickness );
}
// Extract the current glyph's description
const Glyph& glyph = mFont->getGlyph( curChar, mRealFontSize, bold, reqItalic );
const Glyph& glyph =
mFontStyleConfig.Font->getGlyph( curChar, mRealFontSize, bold, reqItalic );
// Add the glyph to the vertices
addGlyphQuad( mVertices, Vector2f( x, y ), glyph, italic, 0, centerDiffX );
// Update the current bounds with the non outlined glyph bounds
if ( mOutlineThickness == 0 ) {
if ( mFontStyleConfig.OutlineThickness == 0 ) {
Float left = glyph.bounds.Left;
Float top = glyph.bounds.Top;
Float right = glyph.bounds.Left + glyph.bounds.Right;
@@ -1088,40 +991,46 @@ void Text::ensureGeometryUpdate() {
maxX = std::max( maxX, x + right - italic * top );
minY = std::min( minY, y + top );
maxY = std::max( maxY, y + bottom );
}
mGlyphCache.emplace_back(
Rectf( Vector2f( x, y - mRealFontSize ), Sizef( glyph.advance, vspace ) ) );
if ( mCachedWidthNeedUpdate )
maxW = std::max( maxW, x + glyph.advance - italic * top );
}
// Advance to the next character
x += glyph.advance;
}
mGlyphCache.emplace_back( Rectf( Vector2f( x, y - mRealFontSize ), Sizef( 0, vspace ) ) );
// If we're using the underlined style, add the last line
if ( underlined && ( x > 0 ) ) {
addLine( mVertices, x, y, underlineOffset, underlineThickness, 0, centerDiffX );
if ( mOutlineThickness != 0 )
addLine( mOutlineVertices, x, y, underlineOffset, underlineThickness, mOutlineThickness,
centerDiffX );
if ( mFontStyleConfig.OutlineThickness != 0 )
addLine( mOutlineVertices, x, y, underlineOffset, underlineThickness,
mFontStyleConfig.OutlineThickness, centerDiffX );
}
// If we're using the strike through style, add the last line across all characters
if ( strikeThrough && ( x > 0 ) ) {
addLine( mVertices, x, y, strikeThroughOffset, underlineThickness, 0, centerDiffX );
if ( mOutlineThickness != 0 )
if ( mFontStyleConfig.OutlineThickness != 0 )
addLine( mOutlineVertices, x, y, strikeThroughOffset, underlineThickness,
mOutlineThickness, centerDiffX );
mFontStyleConfig.OutlineThickness, centerDiffX );
}
if ( mCachedWidthNeedUpdate && !mString.empty() && mString[mString.size() - 1] != '\n' )
mLinesWidth.push_back( x );
// Update the bounding rectangle
mBounds.Left = minX;
mBounds.Top = minY;
mBounds.Right = maxX;
mBounds.Bottom = maxY;
if ( mCachedWidthNeedUpdate ) {
mCachedWidth = maxW;
mCachedWidthNeedUpdate = false;
}
}
void Text::ensureColorUpdate() {
@@ -1129,15 +1038,15 @@ void Text::ensureColorUpdate() {
Uint32 tv = getTotalVertices();
if ( mColors.size() < tv )
mColors.resize( tv, mFillColor );
mColors.resize( tv, mFontStyleConfig.FontColor );
mColors.assign( tv, mFillColor );
mColors.assign( tv, mFontStyleConfig.FontColor );
if ( 0 != mOutlineThickness ) {
if ( 0 != mFontStyleConfig.OutlineThickness ) {
if ( mOutlineColors.size() < tv )
mOutlineColors.resize( tv, mOutlineColor );
mOutlineColors.resize( tv, mFontStyleConfig.OutlineColor );
mOutlineColors.assign( tv, mOutlineColor );
mOutlineColors.assign( tv, mFontStyleConfig.OutlineColor );
}
mColorsNeedUpdate = false;
@@ -1145,23 +1054,24 @@ void Text::ensureColorUpdate() {
if ( mContainsColorEmoji ) {
auto positions = Font::emojiCodePointsPositions( mString );
for ( const auto& position : positions )
setFillColor( Color( 255, 255, 255, mFillColor.a ), position, position );
setFillColor( Color( 255, 255, 255, mFontStyleConfig.FontColor.a ), position,
position );
}
}
}
const Color& Text::getShadowColor() const {
return mShadowColor;
return mFontStyleConfig.ShadowColor;
}
void Text::setShadowColor( const Color& color ) {
mShadowColor = color;
mFontStyleConfig.ShadowColor = color;
}
const int& Text::getNumLines() {
cacheWidth();
return mNumLines;
Uint32 Text::getNumLines() {
if ( !mCachedWidthNeedUpdate )
return mLinesWidth.size();
return mString.countChar( '\n' ) + 1;
}
const std::vector<Float>& Text::getLinesWidth() {
@@ -1185,14 +1095,12 @@ void Text::cacheWidth() {
if ( !mCachedWidthNeedUpdate )
return;
if ( NULL != mFont && !mString.empty() ) {
getWidthInfo();
if ( NULL != mFontStyleConfig.Font && !mString.empty() ) {
updateWidthCache();
mCachedWidthNeedUpdate = false;
} else {
mCachedWidth = 0;
mNumLines = 0;
mLinesWidth.clear();
mLinesStartIndex.clear();
}
}
@@ -1204,14 +1112,11 @@ void Text::setStyleConfig( const FontStyleConfig& styleConfig ) {
setOutlineThickness( styleConfig.OutlineThickness );
setOutlineColor( styleConfig.OutlineColor );
setShadowColor( styleConfig.ShadowColor );
setShadowOffset( styleConfig.ShadowOffset );
}
bool Text::hasSameFontStyleConfig( const FontStyleConfig& styleConfig ) {
return styleConfig.Font == mFont && styleConfig.CharacterSize == mFontSize &&
styleConfig.Style == mStyle && styleConfig.FontColor == mFillColor &&
styleConfig.OutlineColor == mOutlineColor && styleConfig.ShadowColor == mShadowColor &&
styleConfig.ShadowOffset == mShadowOffset &&
styleConfig.OutlineThickness == mOutlineThickness;
return mFontStyleConfig == styleConfig;
}
void Text::setFillColor( const Color& color, Uint32 from, Uint32 to ) {
@@ -1220,8 +1125,8 @@ void Text::setFillColor( const Color& color, Uint32 from, Uint32 to ) {
ensureColorUpdate();
bool underlined = ( mStyle & Underlined ) != 0;
bool strikeThrough = ( mStyle & StrikeThrough ) != 0;
bool underlined = ( mFontStyleConfig.Style & Underlined ) != 0;
bool strikeThrough = ( mFontStyleConfig.Style & StrikeThrough ) != 0;
std::size_t s = mString.size();
if ( to >= s ) {
@@ -1463,8 +1368,8 @@ void Text::addGlyphQuad( std::vector<VertexCoords>& vertices, Vector2f position,
}
Uint32 Text::getTotalVertices() {
bool underlined = ( mStyle & Underlined ) != 0;
bool strikeThrough = ( mStyle & StrikeThrough ) != 0;
bool underlined = ( mFontStyleConfig.Style & Underlined ) != 0;
bool strikeThrough = ( mFontStyleConfig.Style & StrikeThrough ) != 0;
size_t sl = mString.size();
size_t sv = sl * GLi->quadVertexs();

View File

@@ -2884,9 +2884,6 @@ void UICodeEditor::drawLineText( const Int64& line, Vector2f position, const Flo
txt.setStyle( style.style );
txt.setColor( Color( style.color ).blendAlpha( mAlpha ) );
if ( isMonospace )
txt.setDisableCacheWidth( true );
if ( mHandShown && mLinkPosition.isValid() && mLinkPosition.inSameLine() &&
mLinkPosition.start().line() == line ) {
if ( mLinkPosition.start().column() >= curChar &&

View File

@@ -86,7 +86,7 @@ void UITextView::draw() {
mSize.getHeight() - mPaddingPx.Top - mPaddingPx.Bottom );
}
mTextCache->setAlign( getFlags() );
mTextCache->setAlign( Font::getHorizontalAlign( getFlags() ) );
mTextCache->draw( (Float)mScreenPosi.x + (int)mRealAlignOffset.x + (int)mPaddingPx.Left,
mFontLineCenter + (Float)mScreenPosi.y + (int)mRealAlignOffset.y +
(int)mPaddingPx.Top,
@@ -454,7 +454,7 @@ Float UITextView::getTextHeight() {
return mTextCache->getTextHeight();
}
const int& UITextView::getNumLines() const {
Uint32 UITextView::getNumLines() {
return mTextCache->getNumLines();
}

View File

@@ -312,7 +312,7 @@ Float UITooltip::getTextHeight() {
return mTextCache->getTextHeight();
}
const int& UITooltip::getNumLines() const {
Uint32 UITooltip::getNumLines() {
return mTextCache->getNumLines();
}