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)
.setMagnificationFilter(GL::SamplerFilter::Linear);
/* Upload the input texture and create a distance field from it */
const Vector2 scale = Vector2{_size}/Vector2{size().xy()};
/* 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
/* The constructor already checked that the ratio is an integer multiple,
so this division should lead to no information loss */
CORRADE_INTERNAL_ASSERT(size().xy() % _size == Vector2i{0});
const Vector2i ratio = size().xy()/_size;
/* 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
a whole. */
#ifdef MAGNUM_TARGET_GLES2
@ -96,7 +99,7 @@ void DistanceFieldGlyphCache::doSetImage(const Vector2i& offset, const ImageView
#endif
{
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
static_cast<void>(offset);
#endif
@ -122,15 +125,28 @@ void DistanceFieldGlyphCache::doSetImage(const Vector2i& offset, const ImageView
image.storage().skip().xy() - padding());
const Vector2i paddedMax = Math::min(size().xy(),
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{
PixelStorage{image.storage()}
.setSkip({paddedMin, image.storage().skip().z()}),
.setSkip({paddedMinRounded, image.storage().skip().z()}),
image.format(),
paddedMax - paddedMin,
paddedMaxRounded - paddedMinRounded,
image.data()};
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
}

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

@ -90,6 +90,13 @@ const struct {
distance field algorithm as if the whole image was processed. */
{{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() {

Loading…
Cancel
Save