diff --git a/bin/assets/fontrendering/eepp-scaled-subpixel-glyph-atlas.webp b/bin/assets/fontrendering/eepp-scaled-subpixel-glyph-atlas.webp new file mode 100644 index 000000000..15ddbc5fa Binary files /dev/null and b/bin/assets/fontrendering/eepp-scaled-subpixel-glyph-atlas.webp differ diff --git a/src/eepp/graphics/fonttruetype.cpp b/src/eepp/graphics/fonttruetype.cpp index a402433b0..2a5f12308 100644 --- a/src/eepp/graphics/fonttruetype.cpp +++ b/src/eepp/graphics/fonttruetype.cpp @@ -1621,20 +1621,50 @@ Glyph FontTrueType::loadGlyphByIndex( Uint32 index, unsigned int characterSize, destHeight = dest.getHeight() + 2 * padding; } } else if ( bitmap.pixel_mode == FT_PIXEL_MODE_LCD ) { - for ( int y = padding; y < height - padding; ++y ) { - for ( int x = padding; x < width - padding; ++x ) { - const std::size_t index = ( x + y * width ) * 4; - const Uint8* px = &pixels[( x - padding ) * 3]; - mPixelBuffer[index + 0] = - glyph.renderMode == GlyphRenderMode::Subpixel ? px[0] : 255; - mPixelBuffer[index + 1] = - glyph.renderMode == GlyphRenderMode::Subpixel ? px[1] : 255; - mPixelBuffer[index + 2] = - glyph.renderMode == GlyphRenderMode::Subpixel ? px[2] : 255; - mPixelBuffer[index + 3] = - (Uint8)( ( (int)px[0] + (int)px[1] + (int)px[2] ) / 3.f ); + if ( scale < 1.f ) { + for ( int y = 0; y < height; ++y ) { + for ( int x = 0; x < width; ++x ) { + const std::size_t index = ( x + y * width ) * 4; + const Uint8* px = &pixels[x * 3]; + mPixelBuffer[index + 0] = + glyph.renderMode == GlyphRenderMode::Subpixel ? px[0] : 255; + mPixelBuffer[index + 1] = + glyph.renderMode == GlyphRenderMode::Subpixel ? px[1] : 255; + mPixelBuffer[index + 2] = + glyph.renderMode == GlyphRenderMode::Subpixel ? px[2] : 255; + mPixelBuffer[index + 3] = + (Uint8)( ( (int)px[0] + (int)px[1] + (int)px[2] ) / 3.f ); + } + pixels += bitmap.pitch; + } + + Image dest( &mPixelBuffer[0], width, height, 4 ); + dest.avoidFreeImage( true ); + dest.scale( scale ); + dest.avoidFreeImage( true ); + pixelPtr = dest.getPixels(); + glyph.bounds.Left *= scale; + glyph.bounds.Right *= scale; + glyph.bounds.Top *= scale; + glyph.bounds.Bottom *= scale; + destWidth = dest.getWidth() + 2 * padding; + destHeight = dest.getHeight() + 2 * padding; + } else { + for ( int y = padding; y < height - padding; ++y ) { + for ( int x = padding; x < width - padding; ++x ) { + const std::size_t index = ( x + y * width ) * 4; + const Uint8* px = &pixels[( x - padding ) * 3]; + mPixelBuffer[index + 0] = + glyph.renderMode == GlyphRenderMode::Subpixel ? px[0] : 255; + mPixelBuffer[index + 1] = + glyph.renderMode == GlyphRenderMode::Subpixel ? px[1] : 255; + mPixelBuffer[index + 2] = + glyph.renderMode == GlyphRenderMode::Subpixel ? px[2] : 255; + mPixelBuffer[index + 3] = + (Uint8)( ( (int)px[0] + (int)px[1] + (int)px[2] ) / 3.f ); + } + pixels += bitmap.pitch; } - pixels += bitmap.pitch; } } else { if ( scale < 1.f ) { diff --git a/src/tests/unit_tests/fontrendering_tests.cpp b/src/tests/unit_tests/fontrendering_tests.cpp index 523af25c8..c13dd3ba8 100644 --- a/src/tests/unit_tests/fontrendering_tests.cpp +++ b/src/tests/unit_tests/fontrendering_tests.cpp @@ -165,6 +165,36 @@ UTEST( FontRendering, subpixelCoverageCompositesPerChannel ) { "Subpixel text did not update a transparent target's alpha" ); } +UTEST( FontRendering, scaledSubpixelGlyphAtlas ) { + UIApplication app( + WindowSettings( 256, 64, "eepp - Scaled Subpixel Glyph Atlas", VisualTestWindowStyle, + WindowBackend::Default, 32 ), + UIApplication::Settings( Sys::getProcessPath() + ".." + FileSystem::getOSSlash(), 1 ) ); + ResourceScope& scope = *app.getUI()->getResourceScope(); + FontTrueTypePtr font = FontTrueType::New( "ScaledSubpixelNonicons", scope ); + ASSERT_TRUE( font->loadFromFile( Sys::getProcessPath() + "../assets/fonts/nonicons.ttf" ) ); + font->setAntialiasing( FontAntialiasing::Subpixel ); + font->setIsEmojiFont( true ); + + EE::Window::Window* window = app.getWindow(); + window->setClearColor( Color( 40, 44, 52 ) ); + window->clear(); + const std::array codePoints = { 61718, 61719, 61720, 61743, + 61752, 61775, 61789, 61799 }; + Float x = 8.f; + for ( Uint32 codePoint : codePoints ) { + GlyphDrawable* glyph = font->getGlyphDrawable( codePoint, 18 ); + ASSERT_TRUE( glyph ); + ASSERT_EQ( GlyphRenderMode::Subpixel, glyph->getGlyphRenderMode() ); + const Sizef size = glyph->getPixelsSize(); + glyph->setColor( Color::White ); + glyph->draw( { std::trunc( x + ( 24.f - size.getWidth() ) * 0.5f ), + std::trunc( ( 64.f - size.getHeight() ) * 0.5f ) } ); + x += 30.f; + } + compareImages( utest_state, utest_result, window, "eepp-scaled-subpixel-glyph-atlas" ); +} + UTEST( FontRendering, loadingFontFamilyDoesNotCreateTexturePages ) { UIApplication app( WindowSettings( 320, 240, "eepp - Font Family Metrics Test", WindowStyle::Default,