mirror of
https://github.com/SpartanJ/eepp.git
synced 2026-05-28 17:16:29 +03:00
Text::setFillColor improvements for shaped text.
This commit is contained in:
Binary file not shown.
|
After Width: | Height: | Size: 4.9 KiB |
Binary file not shown.
|
After Width: | Height: | Size: 5.2 KiB |
@@ -1 +1 @@
|
||||
مَرْحَبًا بِالْعَالَم
|
||||
مرحباً بالعالم
|
||||
@@ -188,6 +188,8 @@ class EE_API Text {
|
||||
|
||||
void setFillColor( const Color& color, Uint32 from, Uint32 to );
|
||||
|
||||
void setFillColor( const std::vector<Color>& colors );
|
||||
|
||||
void setOutlineColor( const Color& color );
|
||||
|
||||
void setOutlineThickness( Float thickness );
|
||||
|
||||
@@ -1561,8 +1561,8 @@ void Text::draw( const Float& X, const Float& Y, const Vector2f& scale, const Fl
|
||||
invalidate();
|
||||
}
|
||||
|
||||
ensureColorUpdate();
|
||||
ensureGeometryUpdate();
|
||||
ensureColorUpdate();
|
||||
|
||||
if ( mFontStyleConfig.Style & Shadow ) {
|
||||
std::vector<Color> colors;
|
||||
@@ -2087,8 +2087,15 @@ void Text::setFillColor( const Color& color, Uint32 from, Uint32 to ) {
|
||||
if ( mString.empty() )
|
||||
return;
|
||||
|
||||
ensureGeometryUpdate();
|
||||
ensureColorUpdate();
|
||||
|
||||
size_t numVerts = mVertices.size();
|
||||
if ( mColors.size() < numVerts ) {
|
||||
mColors.resize( numVerts, mFontStyleConfig.FontColor );
|
||||
mColorsNeedUpdate = false;
|
||||
}
|
||||
|
||||
bool underlined = ( mFontStyleConfig.Style & Underlined ) != 0;
|
||||
bool strikeThrough = ( mFontStyleConfig.Style & StrikeThrough ) != 0;
|
||||
std::size_t s = mString.size();
|
||||
@@ -2098,6 +2105,41 @@ void Text::setFillColor( const Color& color, Uint32 from, Uint32 to ) {
|
||||
}
|
||||
|
||||
if ( from <= to && from < s && to <= s ) {
|
||||
#ifdef EE_TEXT_SHAPER_ENABLED
|
||||
if ( TextShaperEnabled && mFontStyleConfig.Font->getType() == FontType::TTF &&
|
||||
!canSkipShaping( mTextHints ) ) {
|
||||
FontTrueType* rFont = static_cast<FontTrueType*>( mFontStyleConfig.Font );
|
||||
auto layout = TextLayout::layout( mString, rFont, mFontStyleConfig.CharacterSize,
|
||||
mFontStyleConfig.Style, mTabWidth,
|
||||
mFontStyleConfig.OutlineThickness );
|
||||
size_t vIdx = 0;
|
||||
bool bold = ( mFontStyleConfig.Style & Bold ) != 0;
|
||||
bool italic = ( mFontStyleConfig.Style & Italic ) != 0;
|
||||
|
||||
for ( const ShapedGlyph& sg : layout->shapedGlyphs ) {
|
||||
if ( mString[sg.stringIndex] == '\t' )
|
||||
continue;
|
||||
|
||||
Glyph glyph =
|
||||
sg.font->getGlyphByIndex( sg.glyphIndex, mFontStyleConfig.CharacterSize, bold,
|
||||
italic, mFontStyleConfig.OutlineThickness,
|
||||
rFont->getPage( mFontStyleConfig.CharacterSize ) );
|
||||
|
||||
if ( glyph.bounds.Right > 0 && glyph.bounds.Bottom > 0 ) {
|
||||
if ( vIdx + GLi->quadVertex() <= mColors.size() && sg.stringIndex >= from &&
|
||||
sg.stringIndex <= to ) {
|
||||
for ( int i = 0; i < GLi->quadVertex(); ++i )
|
||||
mColors[vIdx + i] = color;
|
||||
}
|
||||
vIdx += GLi->quadVertex();
|
||||
}
|
||||
}
|
||||
|
||||
mColorsNeedUpdate = false;
|
||||
return;
|
||||
}
|
||||
#endif
|
||||
|
||||
size_t realTo = to + 1;
|
||||
Int32 rpos = from;
|
||||
Int32 lpos = 0;
|
||||
@@ -2178,6 +2220,78 @@ void Text::setFillColor( const Color& color, Uint32 from, Uint32 to ) {
|
||||
}
|
||||
}
|
||||
|
||||
void Text::setFillColor( const std::vector<Color>& colors ) {
|
||||
if ( mString.empty() || colors.empty() )
|
||||
return;
|
||||
|
||||
ensureGeometryUpdate();
|
||||
ensureColorUpdate();
|
||||
|
||||
size_t numVerts = mVertices.size();
|
||||
if ( mColors.size() < numVerts ) {
|
||||
mColors.resize( numVerts, mFontStyleConfig.FontColor );
|
||||
mColorsNeedUpdate = false;
|
||||
}
|
||||
|
||||
#ifdef EE_TEXT_SHAPER_ENABLED
|
||||
if ( TextShaperEnabled && mFontStyleConfig.Font->getType() == FontType::TTF &&
|
||||
!canSkipShaping( mTextHints ) ) {
|
||||
FontTrueType* rFont = static_cast<FontTrueType*>( mFontStyleConfig.Font );
|
||||
auto layout = TextLayout::layout( mString, rFont, mFontStyleConfig.CharacterSize,
|
||||
mFontStyleConfig.Style, mTabWidth,
|
||||
mFontStyleConfig.OutlineThickness );
|
||||
size_t vIdx = 0;
|
||||
bool bold = ( mFontStyleConfig.Style & Bold ) != 0;
|
||||
bool italic = ( mFontStyleConfig.Style & Italic ) != 0;
|
||||
|
||||
for ( const ShapedGlyph& sg : layout->shapedGlyphs ) {
|
||||
if ( mString[sg.stringIndex] == '\t' )
|
||||
continue;
|
||||
|
||||
Glyph glyph =
|
||||
sg.font->getGlyphByIndex( sg.glyphIndex, mFontStyleConfig.CharacterSize, bold,
|
||||
italic, mFontStyleConfig.OutlineThickness,
|
||||
rFont->getPage( mFontStyleConfig.CharacterSize ) );
|
||||
|
||||
if ( glyph.bounds.Right > 0 && glyph.bounds.Bottom > 0 ) {
|
||||
if ( vIdx + GLi->quadVertex() <= mColors.size() &&
|
||||
sg.stringIndex < colors.size() ) {
|
||||
Color color = colors[sg.stringIndex];
|
||||
if ( mContainsColorEmoji && Font::isEmojiCodePoint( mString[sg.stringIndex] ) )
|
||||
color = Color( 255, 255, 255, color.a );
|
||||
for ( int i = 0; i < GLi->quadVertex(); ++i )
|
||||
mColors[vIdx + i] = color;
|
||||
vIdx += GLi->quadVertex();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
mColorsNeedUpdate = false;
|
||||
return;
|
||||
}
|
||||
#endif
|
||||
|
||||
size_t s = mString.size();
|
||||
size_t vIdx = 0;
|
||||
|
||||
for ( size_t i = 0; i < s; i++ ) {
|
||||
String::StringBaseType curChar = mString[i];
|
||||
if ( ' ' == curChar || '\n' == curChar || '\t' == curChar || '\r' == curChar )
|
||||
continue;
|
||||
|
||||
if ( vIdx + GLi->quadVertex() <= mColors.size() && i < colors.size() ) {
|
||||
Color color = colors[i];
|
||||
if ( mContainsColorEmoji && Font::isEmojiCodePoint( curChar ) )
|
||||
color = Color( 255, 255, 255, color.a );
|
||||
for ( int v = 0; v < GLi->quadVertex(); v++ )
|
||||
mColors[vIdx + v] = color;
|
||||
vIdx += GLi->quadVertex();
|
||||
}
|
||||
}
|
||||
|
||||
mColorsNeedUpdate = false;
|
||||
}
|
||||
|
||||
// Add an underline or strikethrough line to the vertex array
|
||||
void Text::addLine( std::vector<VertexCoords>& vertices, Float lineLength, Float lineTop,
|
||||
Float offset, Float thickness, Float outlineThickness, Int32 centerDiffX ) {
|
||||
|
||||
@@ -951,17 +951,24 @@ Text* SyntaxTokenizer::tokenizeText( const SyntaxDefinition& syntax,
|
||||
text->setString( txt );
|
||||
}
|
||||
|
||||
std::vector<Color> colors( text->getString().size(), text->getFillColor() );
|
||||
size_t start = startIndex;
|
||||
for ( const auto& token : tokens ) {
|
||||
if ( start < endIndex ) {
|
||||
if ( token.len > 0 )
|
||||
text->setFillColor( colorScheme.getSyntaxStyle( token.type ).color, start,
|
||||
std::min( start + token.len, endIndex ) );
|
||||
if ( token.len > 0 ) {
|
||||
Color color = colorScheme.getSyntaxStyle( token.type ).color;
|
||||
size_t end = std::min( start + token.len, endIndex );
|
||||
if ( end > colors.size() )
|
||||
end = colors.size();
|
||||
for ( size_t i = start; i < end; i++ )
|
||||
colors[i] = color;
|
||||
}
|
||||
start += token.len;
|
||||
} else {
|
||||
break;
|
||||
}
|
||||
}
|
||||
text->setFillColor( colors );
|
||||
|
||||
return text;
|
||||
}
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
@@ -728,3 +728,70 @@ cupidatat non proident👽, sunt in culpa qui officia deserunt mollit anim id es
|
||||
|
||||
Engine::destroySingleton();
|
||||
}
|
||||
|
||||
UTEST( FontRendering, textSetFillColor ) {
|
||||
auto win = Engine::instance()->createWindow(
|
||||
WindowSettings( 1024, 230, "eepp - Text Set Fill Color", WindowStyle::Default,
|
||||
WindowBackend::Default, 32, {}, 1, false, true ) );
|
||||
|
||||
ASSERT_TRUE_MSG( win->isOpen(), "Failed to create Window" );
|
||||
|
||||
UTEST_PRINT_INFO( GLi->getRenderer().c_str() );
|
||||
|
||||
win->setClearColor( RGB( 230, 230, 230 ) );
|
||||
|
||||
FontTrueType* arabicFont =
|
||||
FontTrueType::New( "NotoNaskhArabic-Regular", "assets/fonts/NotoNaskhArabic-Regular.ttf" );
|
||||
|
||||
Text text;
|
||||
text.setFont( arabicFont );
|
||||
text.setFontSize( 64 );
|
||||
text.setAlign( TEXT_ALIGN_CENTER );
|
||||
std::string arabicTxtUtf8;
|
||||
FileSystem::fileGet( "assets/textfiles/test-arabic-simple.uext", arabicTxtUtf8 );
|
||||
String arabicTxt( arabicTxtUtf8 );
|
||||
text.setString( arabicTxt );
|
||||
text.setFillColor( Color::Black );
|
||||
|
||||
const auto runTest = [&]( std::string_view testName ) {
|
||||
win->clear();
|
||||
text.draw( 0, win->getHeight() * 0.5f - text.getTextHeight() * 0.5f );
|
||||
compareImages( utest_state, utest_result, win,
|
||||
std::string( "eepp-text-set-fill-color-" ) + std::string( testName ) );
|
||||
};
|
||||
|
||||
UTEST_PRINT_STEP( "Text Shaper enabled" );
|
||||
{
|
||||
BoolScopedOp op( Text::TextShaperEnabled, true );
|
||||
|
||||
// Test Vector Fill
|
||||
{
|
||||
std::vector<Color> colors;
|
||||
for ( size_t i = 0; i < arabicTxt.size(); i++ ) {
|
||||
// Alternating colors
|
||||
if ( i % 3 == 0 )
|
||||
colors.push_back( Color::Red );
|
||||
else if ( i % 3 == 1 )
|
||||
colors.push_back( Color::Green );
|
||||
else
|
||||
colors.push_back( Color::Blue );
|
||||
}
|
||||
text.setFillColor( colors );
|
||||
runTest( "vector" );
|
||||
}
|
||||
|
||||
// Test Range Fill
|
||||
{
|
||||
text.setFillColor( Color::Black );
|
||||
// Color "World" (بالعالم) in Red. It's at the end of the string.
|
||||
// "مرحباً" (Hello) is 6 chars + space = 7.
|
||||
// "بالعالم" (World) starts at index 7.
|
||||
if ( arabicTxt.size() > 7 ) {
|
||||
text.setFillColor( Color::Red, 7, arabicTxt.size() );
|
||||
}
|
||||
runTest( "range" );
|
||||
}
|
||||
}
|
||||
|
||||
Engine::destroySingleton();
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user