Browse Source

Text: round the flushed DistanceFieldGlyphCache image range.

To a multiple of the input/output size ratio to satisfy the
TextureTools::DistanceField assertion and to avoid potential strange
misalignments.
pull/168/head
Vladimír Vondruš 3 years ago
parent
commit
9a9ad483a3
  1. 34
      src/Magnum/Text/DistanceFieldGlyphCache.cpp
  2. 7
      src/Magnum/Text/Test/DistanceFieldGlyphCacheGLTest.cpp

34
src/Magnum/Text/DistanceFieldGlyphCache.cpp

@ -83,11 +83,14 @@ void DistanceFieldGlyphCache::doSetImage(const Vector2i& offset, const ImageView
.setMinificationFilter(GL::SamplerFilter::Linear) .setMinificationFilter(GL::SamplerFilter::Linear)
.setMagnificationFilter(GL::SamplerFilter::Linear); .setMagnificationFilter(GL::SamplerFilter::Linear);
/* Upload the input texture and create a distance field from it */ /* The constructor already checked that the ratio is an integer multiple,
const Vector2 scale = Vector2{_size}/Vector2{size().xy()}; so this division should lead to no information loss */
CORRADE_INTERNAL_ASSERT(size().xy() % _size == Vector2i{0});
/* On ES2 without EXT_unpack_subimage and on WebGL 1 there's no possibility const Vector2i ratio = size().xy()/_size;
to upload just a slice of the input, upload the whole image instead by
/* Upload the input texture and create a distance field from it. On ES2
without EXT_unpack_subimage and on WebGL 1 there's no possibility to
upload just a slice of the input, upload the whole image instead by
ignoring the PixelStorage properties of the input and also process it as ignoring the PixelStorage properties of the input and also process it as
a whole. */ a whole. */
#ifdef MAGNUM_TARGET_GLES2 #ifdef MAGNUM_TARGET_GLES2
@ -96,7 +99,7 @@ void DistanceFieldGlyphCache::doSetImage(const Vector2i& offset, const ImageView
#endif #endif
{ {
input.setImage(0, GL::textureFormat(image.format()), ImageView2D{image.format(), size().xy(), image.data()}); input.setImage(0, GL::textureFormat(image.format()), ImageView2D{image.format(), size().xy(), image.data()});
_distanceField(input, texture(), {{}, size().xy()*scale}, size().xy()); _distanceField(input, texture(), {{}, size().xy()/ratio}, size().xy());
#ifdef MAGNUM_TARGET_WEBGL #ifdef MAGNUM_TARGET_WEBGL
static_cast<void>(offset); static_cast<void>(offset);
#endif #endif
@ -122,15 +125,28 @@ void DistanceFieldGlyphCache::doSetImage(const Vector2i& offset, const ImageView
image.storage().skip().xy() - padding()); image.storage().skip().xy() - padding());
const Vector2i paddedMax = Math::min(size().xy(), const Vector2i paddedMax = Math::min(size().xy(),
image.size() + image.storage().skip().xy() + padding()); image.size() + image.storage().skip().xy() + padding());
/* TextureTools::DistanceField expects the input size and output
rectangle size ratio to be a multiple of 2 in order for the shader
to perform pixel addressing correctly. That might not always be the
case with the rectangle passed to flushImage(), so round the
paddedMin *down* to a multiple of the ratio and paddedMax *up* to a
multiple of the ratio. */
const Vector2i paddedMinRounded = ratio*(paddedMin/ratio);
const Vector2i paddedMaxRounded = ratio*((paddedMax + ratio - Vector2i{1})/ratio);
/* As the size is also a multiple of ratio, the resulting size should
not get larger. */
CORRADE_INTERNAL_ASSERT(paddedMaxRounded <= size().xy());
const ImageView2D paddedImage{ const ImageView2D paddedImage{
PixelStorage{image.storage()} PixelStorage{image.storage()}
.setSkip({paddedMin, image.storage().skip().z()}), .setSkip({paddedMinRounded, image.storage().skip().z()}),
image.format(), image.format(),
paddedMax - paddedMin, paddedMaxRounded - paddedMinRounded,
image.data()}; image.data()};
input.setImage(0, GL::textureFormat(paddedImage.format()), paddedImage); input.setImage(0, GL::textureFormat(paddedImage.format()), paddedImage);
_distanceField(input, texture(), Range2Di::fromSize(paddedMin*scale, paddedImage.size()*scale), paddedImage.size()); _distanceField(input, texture(), Range2Di::fromSize(paddedMinRounded/ratio, paddedImage.size()/ratio), paddedImage.size());
} }
#endif #endif
} }

7
src/Magnum/Text/Test/DistanceFieldGlyphCacheGLTest.cpp

@ -90,6 +90,13 @@ const struct {
distance field algorithm as if the whole image was processed. */ distance field algorithm as if the whole image was processed. */
{{48, 48}, {208, 208}}, {{48, 48}, {208, 208}},
{}}, {}},
{"tight flush rectangle, ratio not a multiple of 2",
/* Like above, but the flush range isn't satisfying the "multiple of 2"
assertion and the code needs to round it to a larger rectangle that
satisfies it */
{256, 256}, {64, 64}, {},
{{47, 48}, {208, 209}},
{}},
}; };
DistanceFieldGlyphCacheGLTest::DistanceFieldGlyphCacheGLTest() { DistanceFieldGlyphCacheGLTest::DistanceFieldGlyphCacheGLTest() {

Loading…
Cancel
Save