From 202ac59f66891289303b6929094eab5add90a90d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Vladim=C3=ADr=20Vondru=C5=A1?= Date: Mon, 16 Oct 2023 22:58:38 +0200 Subject: [PATCH] Text: make DistanceFieldGlyphCache work with tight flush rectangles. Such as is the case with fillGlyphCache(), which just maintains the union of all glyph rectangles. Sorry for having that temporarily broken. Also I don't really like the solution here, but was the best I could come up with, after a bunch of failed attempts to try to do this directly in the TextureTools::DistanceField. --- src/Magnum/Text/DistanceFieldGlyphCache.cpp | 26 +++++++++++++++++-- .../Test/DistanceFieldGlyphCacheGLTest.cpp | 21 +++++++++++---- 2 files changed, 40 insertions(+), 7 deletions(-) diff --git a/src/Magnum/Text/DistanceFieldGlyphCache.cpp b/src/Magnum/Text/DistanceFieldGlyphCache.cpp index 993e2ed68..fcc902ed4 100644 --- a/src/Magnum/Text/DistanceFieldGlyphCache.cpp +++ b/src/Magnum/Text/DistanceFieldGlyphCache.cpp @@ -100,8 +100,30 @@ void DistanceFieldGlyphCache::doSetImage(const Vector2i& offset, const ImageView #endif #if !(defined(MAGNUM_TARGET_GLES2) && defined(MAGNUM_TARGET_WEBGL)) { - input.setImage(0, GL::textureFormat(image.format()), image); - _distanceField(input, texture(), Range2Di::fromSize(offset*scale, image.size()*scale), image.size()); + /* Create an image view that includes the distance field radius as + well, to be sure the edges are processed appropriately as well */ + /** @todo this feels more like a hack than a real solution, any better + idea? Tried to make TextureTools::DistanceField pad the processing + area on its own, but eventually gave up as it would (a) made the + processing do more work than necessary in many cases, with no easy + way to opt out of that, (b) wasn't really working if the input + didn't have a black strip around the edge on platforms that don't + support border clamp, (c) required the input texture to have + certain wrapping mode set */ + CORRADE_INTERNAL_ASSERT(image.storage().skip().xy() == offset); + const Vector2i paddedMin = Math::max(Vector2i{0}, + image.storage().skip().xy() - padding()); + const Vector2i paddedMax = Math::min(size().xy(), + image.size() + image.storage().skip().xy() + padding()); + const ImageView2D paddedImage{ + PixelStorage{image.storage()} + .setSkip({paddedMin, image.storage().skip().z()}), + image.format(), + paddedMax - paddedMin, + image.data()}; + + input.setImage(0, GL::textureFormat(paddedImage.format()), paddedImage); + _distanceField(input, texture(), Range2Di::fromSize(paddedMin*scale, paddedImage.size()*scale), paddedImage.size()); } #endif } diff --git a/src/Magnum/Text/Test/DistanceFieldGlyphCacheGLTest.cpp b/src/Magnum/Text/Test/DistanceFieldGlyphCacheGLTest.cpp index 77e6e275e..8401a145a 100644 --- a/src/Magnum/Text/Test/DistanceFieldGlyphCacheGLTest.cpp +++ b/src/Magnum/Text/Test/DistanceFieldGlyphCacheGLTest.cpp @@ -70,14 +70,25 @@ struct DistanceFieldGlyphCacheGLTest: GL::OpenGLTester { const struct { const char* name; Vector2i sourceSize, size, sourceOffset; + Range2Di flushRange; Containers::Size2D offset; } SetImageData[]{ {"", - {256, 256}, {64, 64}, - {}, {}}, + {256, 256}, {64, 64}, {}, + {{}, {256, 256}}, + {}}, {"upload with offset", - {512, 384}, {128, 96}, - {256, 128}, {128/4, 256/4}}, + {512, 384}, {128, 96}, {256, 128}, + {{256, 128}, {512, 384}}, + {128/4, 256/4}}, + {"tight flush rectangle", + {256, 256}, {64, 64}, {}, + /* The image is 256x256 with a black 48x48 border around. Even with the + border excluded from the flush rectangle, the doSetImage() should be + still called with a large enough padding to properly run the + distance field algorithm as if the whole image was processed. */ + {{48, 48}, {208, 208}}, + {}}, }; DistanceFieldGlyphCacheGLTest::DistanceFieldGlyphCacheGLTest() { @@ -158,7 +169,7 @@ void DistanceFieldGlyphCacheGLTest::setImage() { std::size_t(data.sourceOffset.y()), std::size_t(data.sourceOffset.x()), 0}, src.size())); - cache.flushImage(Range2Di::fromSize(data.sourceOffset, inputImage->size())); + cache.flushImage(data.flushRange); MAGNUM_VERIFY_NO_GL_ERROR(); /* On GLES processedImage() isn't implemented as it'd mean creating a