mirror of
https://github.com/SpartanJ/eepp.git
synced 2026-10-01 18:50:16 +03:00
Handle downscaled LCD glyphs with a dedicated resize path before atlas upload. This preserves row stride and RGB coverage, fixing corrupted icon-font glyphs at small sizes.
Add a golden-image regression test covering scaled subpixel glyphs from the Nonicons font.
This commit is contained in:
@@ -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 ) {
|
||||
|
||||
@@ -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<Uint32, 8> 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,
|
||||
|
||||
Reference in New Issue
Block a user