From 32485baae8ed6814d9ea14884bc4f9b6c35280dc Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Vladim=C3=ADr=20Vondru=C5=A1?= Date: Wed, 25 Oct 2023 13:42:05 +0200 Subject: [PATCH] Text: add renderGlyphQuadsInto() overload taking cache-global glyph IDs. Which also allows the internals to be a bit simpler / potentially more efficient, as the implementation can now access the glyph cache contents directly, without a getter. --- src/Magnum/Text/Renderer.cpp | 67 ++++++++++++++------ src/Magnum/Text/Renderer.h | 61 +++++++++++++++---- src/Magnum/Text/Test/RendererTest.cpp | 88 +++++++++++++++++++++------ 3 files changed, 165 insertions(+), 51 deletions(-) diff --git a/src/Magnum/Text/Renderer.cpp b/src/Magnum/Text/Renderer.cpp index 2ffed6c6a..c76aa5b34 100644 --- a/src/Magnum/Text/Renderer.cpp +++ b/src/Magnum/Text/Renderer.cpp @@ -87,7 +87,7 @@ Range2D renderLineGlyphPositionsInto(const AbstractFont& font, const Float size, namespace { -Range2D renderGlyphQuadsInto(const AbstractFont& font, const Float size, const AbstractGlyphCache& cache, const Containers::StridedArrayView1D& glyphPositions, const Containers::StridedArrayView1D& glyphIds, const Containers::StridedArrayView1D& vertexPositions, const Containers::StridedArrayView1D& vertexTextureCoordinates, const Containers::StridedArrayView1D& vertexTextureLayers) { +Range2D renderGlyphQuadsInto(const AbstractGlyphCache& cache, const Float scale, const Containers::StridedArrayView1D& glyphPositions, const Containers::StridedArrayView1D& glyphIds, const Containers::StridedArrayView1D& vertexPositions, const Containers::StridedArrayView1D& vertexTextureCoordinates, const Containers::StridedArrayView1D& vertexTextureLayers) { CORRADE_ASSERT(glyphIds.size() == glyphPositions.size(), "Text::renderGlyphQuadsInto(): expected glyphIds and glyphPositions views to have the same size, got" << glyphIds.size() << "and" << glyphPositions.size(), {}); CORRADE_ASSERT(vertexPositions.size() == glyphPositions.size()*4 && @@ -96,32 +96,26 @@ Range2D renderGlyphQuadsInto(const AbstractFont& font, const Float size, const A /* Should be ensured by the callers below */ CORRADE_INTERNAL_ASSERT(!vertexTextureLayers || vertexTextureLayers.size() == vertexTextureCoordinates.size()); - CORRADE_ASSERT(font.isOpened(), - "Text::renderGlyphQuadsInto(): no font opened", {}); - const Float scale = size/font.size(); + /* Direct views on the cache data */ const Vector2 inverseCacheSize = 1.0f/Vector2{cache.size().xy()}; + const Containers::StridedArrayView1D cacheGlyphOffsets = cache.glyphOffsets(); + const Containers::StridedArrayView1D cacheGlyphLayers = cache.glyphLayers(); + const Containers::StridedArrayView1D cacheGlyphRectangles = cache.glyphRectangles(); - const Containers::Optional fontId = cache.findFont(&font); - CORRADE_ASSERT(fontId, - "Text::renderGlyphQuadsInto(): font not found among" << cache.fontCount() << "fonts in passed glyph cache", {}); - - /* Get all glyphs from the glyph cache, create quads for each and calculate - the glyph bound rectangle along the way. */ + /* Create quads for each glyph and calculate the glyph bound rectangle + along the way. */ Range2D rectangle; for(std::size_t i = 0; i != glyphIds.size(); ++i) { - /* Offset of the glyph rectangle relative to the cursor, layer, - texture coordinates */ - const Containers::Triple cacheGlyph = cache.glyph(*fontId, glyphIds[i]); - /* 2---3 | | | | | | 0---1 */ + const UnsignedInt glyphId = glyphIds[i]; const Range2D quad = Range2D::fromSize( - glyphPositions[i] + Vector2{cacheGlyph.first()}*scale, - Vector2{cacheGlyph.third().size()}*scale); - const Range2D texture = Range2D{cacheGlyph.third()} + glyphPositions[i] + Vector2{cacheGlyphOffsets[glyphId]}*scale, + Vector2{cacheGlyphRectangles[glyphId].size()}*scale); + const Range2D texture = Range2D{cacheGlyphRectangles[glyphId]} .scaled(inverseCacheSize); const std::size_t i4 = i*4; for(UnsignedByte j = 0; j != 4; ++j) { @@ -133,7 +127,7 @@ Range2D renderGlyphQuadsInto(const AbstractFont& font, const Float size, const A /* Fill also a texture layer if desirable. For 2D output the caller already checked that the cache is 2D. */ if(vertexTextureLayers) for(std::size_t j = 0; j != 4; ++j) - vertexTextureLayers[i4 + j] = cacheGlyph.second(); + vertexTextureLayers[i4 + j] = cacheGlyphLayers[glyphId]; /* Extend the rectangle with current glyph bounds */ rectangle = Math::join(rectangle, quad); @@ -142,6 +136,33 @@ Range2D renderGlyphQuadsInto(const AbstractFont& font, const Float size, const A return rectangle; } +Range2D renderGlyphQuadsInto(const AbstractFont& font, const Float size, const AbstractGlyphCache& cache, const Containers::StridedArrayView1D& glyphPositions, const Containers::StridedArrayView1D& fontGlyphIds, const Containers::StridedArrayView1D& vertexPositions, const Containers::StridedArrayView1D& vertexTextureCoordinates, const Containers::StridedArrayView1D& vertexTextureLayers) { + CORRADE_ASSERT(font.isOpened(), + "Text::renderGlyphQuadsInto(): no font opened", {}); + + const Containers::Optional fontId = cache.findFont(&font); + CORRADE_ASSERT(fontId, + "Text::renderGlyphQuadsInto(): font not found among" << cache.fontCount() << "fonts in passed glyph cache", {}); + + /* First map the font-local glyph IDs to cache-global, abusing the texture + coordinate output array as the storage. Not vertex positions, as those + are allowed to be aliased with glyphPositions by the caller and this + process would overwrite them. + + This also means we need to duplicate the size assertions here, to avoid + asserting inside glyphIdsInto() instead and confusing the user. */ + CORRADE_ASSERT(fontGlyphIds.size() == glyphPositions.size(), + "Text::renderGlyphQuadsInto(): expected fontGlyphIds and glyphPositions views to have the same size, got" << fontGlyphIds.size() << "and" << glyphPositions.size(), {}); + CORRADE_ASSERT(vertexPositions.size() == glyphPositions.size()*4 && + vertexTextureCoordinates.size() == glyphPositions.size()*4, + "Text::renderGlyphQuadsInto(): expected vertexPositions and vertexTextureCoordinates views to have" << glyphPositions.size()*4 << "elements, got" << vertexPositions.size() << "and" << vertexTextureCoordinates.size(), {}); + const Containers::StridedArrayView1D glyphIds = Containers::arrayCast(vertexTextureCoordinates.every(4)); + cache.glyphIdsInto(*fontId, fontGlyphIds, glyphIds); + + /* Delegate to the above */ + return renderGlyphQuadsInto(cache, size/font.size(), glyphPositions, glyphIds, vertexPositions, vertexTextureCoordinates, vertexTextureLayers); +} + } Range2D renderGlyphQuadsInto(const AbstractFont& font, const Float size, const AbstractGlyphCache& cache, const Containers::StridedArrayView1D& glyphPositions, const Containers::StridedArrayView1D& glyphIds, const Containers::StridedArrayView1D& vertexPositions, const Containers::StridedArrayView1D& vertexTextureCoordinates) { @@ -154,6 +175,16 @@ Range2D renderGlyphQuadsInto(const AbstractFont& font, const Float size, const A return renderGlyphQuadsInto(font, size, cache, glyphPositions, glyphIds, vertexPositions, vertexTextureCoordinates, nullptr); } +Range2D renderGlyphQuadsInto(const AbstractGlyphCache& cache, const Float scale, const Containers::StridedArrayView1D& glyphPositions, const Containers::StridedArrayView1D& glyphIds, const Containers::StridedArrayView1D& vertexPositions, const Containers::StridedArrayView1D& vertexTextureCoordinates) { + return renderGlyphQuadsInto(cache, scale, glyphPositions, glyphIds, vertexPositions, vertexTextureCoordinates.slice(&Vector3::xy), vertexTextureCoordinates.slice(&Vector3::z)); +} + +Range2D renderGlyphQuadsInto(const AbstractGlyphCache& cache, const Float scale, const Containers::StridedArrayView1D& glyphPositions, const Containers::StridedArrayView1D& glyphIds, const Containers::StridedArrayView1D& vertexPositions, const Containers::StridedArrayView1D& vertexTextureCoordinates) { + CORRADE_ASSERT(cache.size().z() == 1, + "Text::renderGlyphQuadsInto(): can't use this overload with an array glyph cache", {}); + return renderGlyphQuadsInto(cache, scale, glyphPositions, glyphIds, vertexPositions, vertexTextureCoordinates, nullptr); +} + Range2D alignRenderedLine(const Range2D& lineRectangle, const LayoutDirection direction, const Alignment alignment, const Containers::StridedArrayView1D& positions) { CORRADE_ASSERT(direction == LayoutDirection::HorizontalTopToBottom, "Text::alignRenderedLine(): only" << LayoutDirection::HorizontalTopToBottom << "is supported right now, got" << direction, {}); diff --git a/src/Magnum/Text/Renderer.h b/src/Magnum/Text/Renderer.h index c21f3f72d..8e9a501ba 100644 --- a/src/Magnum/Text/Renderer.h +++ b/src/Magnum/Text/Renderer.h @@ -107,14 +107,14 @@ together with positions for the whole text to @ref alignRenderedBlock(). MAGNUM_TEXT_EXPORT Range2D renderLineGlyphPositionsInto(const AbstractFont& font, Float size, LayoutDirection direction, const Containers::StridedArrayView1D& glyphOffsets, const Containers::StridedArrayView1D& glyphAdvances, Vector2& cursor, const Containers::StridedArrayView1D& glyphPositions); /** -@brief Render glyph quads for a (part of a) single line -@param[in] font Font to query metrics from +@brief Render glyph quads for a (part of a) single line from font-specific glyph IDs +@param[in] font Font the glyphs are coming from @param[in] size Size to render the glyphs at @param[in] cache Glyph cache to query for glyph rectangles @param[in] glyphPositions Glyph positions coming from an earlier call to @ref renderLineGlyphPositionsInto() -@param[in] glyphIds Matching glyph IDs coming from - @ref AbstractShaper instance(s) associated with @p font +@param[in] fontGlyphIds Glyph IDs coming from @ref AbstractShaper + instance(s) associated with @p font @param[out] vertexPositions Where to put output vertex positions @param[out] vertexTextureCoordinates Where to put output texture coordinates @return Rectangle spanning the rendered glyph quads @@ -125,11 +125,12 @@ as shown below. The @p glyphPositions and @p glyphIds views are expected to have the same size, the @p vertexPositions and @p vertexTextureCoordinates views are then expected to be four times larger than @p glyphPositions and @p glyphIds, in order to ultimately contain four corner vertices for each -glyph. To optimize memory use, it's possible to alias @p glyphPositions and -@p glyphIds with @cpp vertexPositions.every(4) @ce and -@cpp vertexTextureCoordinates.every(4) @ce --- the rendering is performed in a -way that first reads the position and ID for each glyph and only then fills in -the vertex data. +glyph. To optimize memory use, it's possible to alias @p glyphPositions with +@cpp vertexPositions.every(4) @ce and @p glyphIds with +@cpp vertexTextureCoordinates.every(4) @ce. The @p vertexTextureCoordinates are +temporarily used to store resolved cache-global glyph IDs, the rendering is +then performed in a way that first reads the position and ID for each glyph and +only then fills in the vertex data. @verbatim 2---3 @@ -149,20 +150,54 @@ then the @p vertexPositions passed further to @ref alignRenderedLine(). Expects that @p font is contained in @p cache. Glyph IDs not found in the cache are replaced with the cache-global invalid glyph. If the @p cache is only 2D, you can use the @ref renderGlyphQuadsInto(const AbstractFont&, Float, const AbstractGlyphCache&, const Containers::StridedArrayView1D&, const Containers::StridedArrayView1D&, const Containers::StridedArrayView1D&, const Containers::StridedArrayView1D&) -overload to get just 2D texture coordinates out. Use +overload to get just 2D texture coordinates out. Use the +@ref renderGlyphQuadsInto(const AbstractGlyphCache&, Float, const Containers::StridedArrayView1D&, const Containers::StridedArrayView1D&, const Containers::StridedArrayView1D&, const Containers::StridedArrayView1D&) +overload if you already have cache-global glyph IDs. Use @ref renderGlyphQuadIndicesInto() to populate the corresponding index array. */ -MAGNUM_TEXT_EXPORT Range2D renderGlyphQuadsInto(const AbstractFont& font, Float size, const AbstractGlyphCache& cache, const Containers::StridedArrayView1D& glyphPositions, const Containers::StridedArrayView1D& glyphIds, const Containers::StridedArrayView1D& vertexPositions, const Containers::StridedArrayView1D& vertexTextureCoordinates); +MAGNUM_TEXT_EXPORT Range2D renderGlyphQuadsInto(const AbstractFont& font, Float size, const AbstractGlyphCache& cache, const Containers::StridedArrayView1D& glyphPositions, const Containers::StridedArrayView1D& fontGlyphIds, const Containers::StridedArrayView1D& vertexPositions, const Containers::StridedArrayView1D& vertexTextureCoordinates); + +/** +@brief Render glyph quads for a (part of a) single line from font-specific glyph IDs and a 2D glyph cache +@m_since_latest + +Compared to @ref renderGlyphQuadsInto(const AbstractFont&, Float, const AbstractGlyphCache&, const Containers::StridedArrayView1D&, const Containers::StridedArrayView1D&, const Containers::StridedArrayView1D&, const Containers::StridedArrayView1D&) +outputs just 2D texture coordinates. Expects that @ref AbstractGlyphCache::size() +depth is @cpp 1 @ce. +*/ +MAGNUM_TEXT_EXPORT Range2D renderGlyphQuadsInto(const AbstractFont& font, Float size, const AbstractGlyphCache& cache, const Containers::StridedArrayView1D& glyphPositions, const Containers::StridedArrayView1D& fontGlyphIds, const Containers::StridedArrayView1D& vertexPositions, const Containers::StridedArrayView1D& vertexTextureCoordinates); /** -@brief Render glyph quads for a (part of a) single line and a 2D glyph cache +@brief Render glyph quads for a (part of a) single line from cache-global glyph IDs +@param[in] cache Glyph cache to query for glyph rectangles +@param[in] scale Size to render the glyphs at divided by size of + the input font +@param[in] glyphPositions Glyph positions coming from an earlier call to + @ref renderLineGlyphPositionsInto() +@param[in] glyphIds Cache-global glyph IDs +@param[out] vertexPositions Where to put output vertex positions +@param[out] vertexTextureCoordinates Where to put output texture coordinates +@return Rectangle spanning the rendered glyph quads @m_since_latest Compared to @ref renderGlyphQuadsInto(const AbstractFont&, Float, const AbstractGlyphCache&, const Containers::StridedArrayView1D&, const Containers::StridedArrayView1D&, const Containers::StridedArrayView1D&, const Containers::StridedArrayView1D&) +this function operates takes cache-global glyph IDs as an input, i.e. no +mapping from font-specific glyph IDs to cache-global IDs happens in this case. +As with the above overload, to optimize memory use, it's possible to alias +@p glyphPositions and @p glyphIds with @cpp vertexPositions.every(4) @ce and +@cpp vertexTextureCoordinates.every(4) @ce. +*/ +MAGNUM_TEXT_EXPORT Range2D renderGlyphQuadsInto(const AbstractGlyphCache& cache, Float scale, const Containers::StridedArrayView1D& glyphPositions, const Containers::StridedArrayView1D& glyphIds, const Containers::StridedArrayView1D& vertexPositions, const Containers::StridedArrayView1D& vertexTextureCoordinates); + +/** +@brief Render glyph quads for a (part of a) single line from cache-global glyph IDs and a 2D glyph cache +@m_since_latest + +Compared to @ref renderGlyphQuadsInto(const AbstractGlyphCache&, Float, const Containers::StridedArrayView1D&, const Containers::StridedArrayView1D&, const Containers::StridedArrayView1D&, const Containers::StridedArrayView1D&) outputs just 2D texture coordinates. Expects that @ref AbstractGlyphCache::size() depth is @cpp 1 @ce. */ -MAGNUM_TEXT_EXPORT Range2D renderGlyphQuadsInto(const AbstractFont& font, Float size, const AbstractGlyphCache& cache, const Containers::StridedArrayView1D& glyphPositions, const Containers::StridedArrayView1D& glyphIds, const Containers::StridedArrayView1D& vertexPositions, const Containers::StridedArrayView1D& vertexTextureCoordinates); +MAGNUM_TEXT_EXPORT Range2D renderGlyphQuadsInto(const AbstractGlyphCache& cache, Float scale, const Containers::StridedArrayView1D& glyphPositions, const Containers::StridedArrayView1D& glyphIds, const Containers::StridedArrayView1D& vertexPositions, const Containers::StridedArrayView1D& vertexTextureCoordinates); /** @brief Align a rendered line diff --git a/src/Magnum/Text/Test/RendererTest.cpp b/src/Magnum/Text/Test/RendererTest.cpp index 12957416a..76eedcd2a 100644 --- a/src/Magnum/Text/Test/RendererTest.cpp +++ b/src/Magnum/Text/Test/RendererTest.cpp @@ -80,6 +80,14 @@ struct RendererTest: TestSuite::Tester { #endif }; +const struct { + const char* name; + bool globalIds; +} GlyphQuadsData[]{ + {"font-specific glyph IDs", false}, + {"cache-global glyph IDs", true} +}; + const struct { const char* name; Alignment alignment; @@ -252,16 +260,20 @@ RendererTest::RendererTest() { &RendererTest::lineGlyphPositionsAliasedViews, &RendererTest::lineGlyphPositionsInvalidViewSizes, &RendererTest::lineGlyphPositionsInvalidDirection, - &RendererTest::lineGlyphPositionsNoFontOpened, + &RendererTest::lineGlyphPositionsNoFontOpened}); - &RendererTest::glyphQuads, - &RendererTest::glyphQuadsAliasedViews, - &RendererTest::glyphQuadsInvalidViewSizes, + addInstancedTests({&RendererTest::glyphQuads, + &RendererTest::glyphQuadsAliasedViews}, + Containers::arraySize(GlyphQuadsData)); + + addTests({&RendererTest::glyphQuadsInvalidViewSizes, &RendererTest::glyphQuadsNoFontOpened, - &RendererTest::glyphQuadsFontNotFoundInCache, + &RendererTest::glyphQuadsFontNotFoundInCache}); + + addInstancedTests({&RendererTest::glyphQuads2D}, + Containers::arraySize(GlyphQuadsData)); - &RendererTest::glyphQuads2D, - &RendererTest::glyphQuads2DArrayGlyphCache}); + addTests({&RendererTest::glyphQuads2DArrayGlyphCache}); addInstancedTests({&RendererTest::alignLine}, Containers::arraySize(AlignLineData)); @@ -355,10 +367,12 @@ DummyGlyphCache testGlyphCache(AbstractFont& font) { cache.addFont(96); UnsignedInt fontId = cache.addFont(font.glyphCount(), &font); - /* Three glyphs, covering bottom, top left and top right of the cache */ + /* Three glyphs, covering bottom, top right and top left of the cache. + Adding them in a shuffled order to verify non-trivial font-specific to + cache-global glyph mapping in glyphQuads() below. */ cache.addGlyph(fontId, 3, {5, 10}, {{}, {20, 10}}); - cache.addGlyph(fontId, 7, {10, 5}, {{0, 10}, {10, 20}}); cache.addGlyph(fontId, 9, {5, 5}, {{10, 10}, {20, 20}}); + cache.addGlyph(fontId, 7, {10, 5}, {{0, 10}, {10, 20}}); return cache; } @@ -370,10 +384,12 @@ DummyGlyphCache testGlyphCacheArray(AbstractFont& font) { cache.addFont(96); UnsignedInt fontId = cache.addFont(font.glyphCount(), &font); - /* Three glyphs, covering bottom, top left and top right of the cache */ + /* Three glyphs, covering bottom, top right and top left of the cache. + Adding them in a shuffled order to verify non-trivial font-specific to + cache-global glyph mapping in glyphQuads() below. */ cache.addGlyph(fontId, 3, {5, 10}, 2, {{}, {20, 10}}); - cache.addGlyph(fontId, 7, {10, 5}, 0, {{0, 10}, {10, 20}}); cache.addGlyph(fontId, 9, {5, 5}, 1, {{10, 10}, {20, 20}}); + cache.addGlyph(fontId, 7, {10, 5}, 0, {{0, 10}, {10, 20}}); return cache; } @@ -481,6 +497,9 @@ void RendererTest::lineGlyphPositionsNoFontOpened() { } void RendererTest::glyphQuads() { + auto&& data = GlyphQuadsData[testCaseInstanceId()]; + setTestCaseDescription(data.name); + TestFont font; font.openFile({}, 2.5f); DummyGlyphCache cache = testGlyphCacheArray(font); @@ -490,15 +509,21 @@ void RendererTest::glyphQuads() { {103.0f, 202.0f}, {107.0f, 196.0f} }; - UnsignedInt glyphIds[]{ + UnsignedInt fontGlyphIds[]{ 3, 7, 9 }; + UnsignedInt glyphIds[]{ + /* Glyph 0 is the cache-global invalid glyph */ + 1, 3, 2 + }; Vector2 positions[3*4]; Vector3 textureCoordinates[3*4]; /* The font is opened at 2.5, rendering at 1.25, so everything will be scaled by 0.5 */ - Range2D rectangle = renderGlyphQuadsInto(font, 1.25f, cache, glyphPositions, glyphIds, positions, textureCoordinates); + Range2D rectangle = data.globalIds ? + renderGlyphQuadsInto(cache, 1.25f/2.5f, glyphPositions, glyphIds, positions, textureCoordinates) : + renderGlyphQuadsInto(font, 1.25f, cache, glyphPositions, fontGlyphIds, positions, textureCoordinates); CORRADE_COMPARE(rectangle, (Range2D{{102.5f, 198.5f}, {114.5f, 210.0f}})); /* 2---3 @@ -548,6 +573,9 @@ void RendererTest::glyphQuads() { } void RendererTest::glyphQuadsAliasedViews() { + auto&& data = GlyphQuadsData[testCaseInstanceId()]; + setTestCaseDescription(data.name); + /* Like lineGlyphPositions(), but with the input data stored in the output array. The internals should be written in a way that doesn't overwrite the input before it's read. */ @@ -567,11 +595,13 @@ void RendererTest::glyphQuadsAliasedViews() { }, glyphPositions); Containers::StridedArrayView1D glyphIds = Containers::arrayCast(Containers::stridedArrayView(textureCoordinates).every(4)); - Utility::copy({ - 3, 7, 9 - }, glyphIds); + data.globalIds ? + Utility::copy({1, 3, 2}, glyphIds) : + Utility::copy({3, 7, 9}, glyphIds); - Range2D rectangle = renderGlyphQuadsInto(font, 1.25f, cache, glyphPositions, glyphIds, positions, textureCoordinates); + Range2D rectangle = data.globalIds ? + renderGlyphQuadsInto(cache, 1.25f/2.5f, glyphPositions, glyphIds, positions, textureCoordinates) : + renderGlyphQuadsInto(font, 1.25f, cache, glyphPositions, glyphIds, positions, textureCoordinates); CORRADE_COMPARE(rectangle, (Range2D{{102.5f, 198.5f}, {114.5f, 210.0f}})); CORRADE_COMPARE_AS(Containers::arrayView(positions), Containers::arrayView({ @@ -613,10 +643,12 @@ void RendererTest::glyphQuadsInvalidViewSizes() { CORRADE_SKIP_IF_NO_ASSERT(); TestFont font; + font.openFile({}, 5.0f); DummyGlyphCache cache{PixelFormat::R8Unorm, {20, 20}}; + cache.addFont(96, &font); Vector2 glyphPositions[4]; Vector2 glyphPositionsInvalid[5]; - UnsignedInt glyphIds[4]; + UnsignedInt glyphIds[4]{}; UnsignedInt glyphIdsInvalid[3]; Vector2 positions[16]; Vector2 positionsInvalid[15]; @@ -626,13 +658,21 @@ void RendererTest::glyphQuadsInvalidViewSizes() { std::ostringstream out; Error redirectError{&out}; renderGlyphQuadsInto(font, 10.0f, cache, glyphPositions, glyphIdsInvalid, positions, textureCoordinates); + renderGlyphQuadsInto(cache, 2.0f, glyphPositions, glyphIdsInvalid, positions, textureCoordinates); renderGlyphQuadsInto(font, 10.0f, cache, glyphPositionsInvalid, glyphIds, positions, textureCoordinates); + renderGlyphQuadsInto(cache, 2.0f, glyphPositionsInvalid, glyphIds, positions, textureCoordinates); renderGlyphQuadsInto(font, 10.0f, cache, glyphPositions, glyphIds, positions, textureCoordinatesInvalid); + renderGlyphQuadsInto(cache, 2.0f, glyphPositions, glyphIds, positions, textureCoordinatesInvalid); renderGlyphQuadsInto(font, 10.0f, cache, glyphPositions, glyphIds, positionsInvalid, textureCoordinates); + renderGlyphQuadsInto(cache, 10.0f, glyphPositions, glyphIds, positionsInvalid, textureCoordinates); CORRADE_COMPARE_AS(out.str(), + "Text::renderGlyphQuadsInto(): expected fontGlyphIds and glyphPositions views to have the same size, got 3 and 4\n" "Text::renderGlyphQuadsInto(): expected glyphIds and glyphPositions views to have the same size, got 3 and 4\n" + "Text::renderGlyphQuadsInto(): expected fontGlyphIds and glyphPositions views to have the same size, got 4 and 5\n" "Text::renderGlyphQuadsInto(): expected glyphIds and glyphPositions views to have the same size, got 4 and 5\n" "Text::renderGlyphQuadsInto(): expected vertexPositions and vertexTextureCoordinates views to have 16 elements, got 16 and 17\n" + "Text::renderGlyphQuadsInto(): expected vertexPositions and vertexTextureCoordinates views to have 16 elements, got 16 and 17\n" + "Text::renderGlyphQuadsInto(): expected vertexPositions and vertexTextureCoordinates views to have 16 elements, got 15 and 16\n" "Text::renderGlyphQuadsInto(): expected vertexPositions and vertexTextureCoordinates views to have 16 elements, got 15 and 16\n", TestSuite::Compare::String); } @@ -665,6 +705,9 @@ void RendererTest::glyphQuadsFontNotFoundInCache() { } void RendererTest::glyphQuads2D() { + auto&& data = GlyphQuadsData[testCaseInstanceId()]; + setTestCaseDescription(data.name); + /* Like lineGlyphPositions(), but with just a 2D glyph cache and using the three-component overload. */ @@ -677,13 +720,18 @@ void RendererTest::glyphQuads2D() { {103.0f, 202.0f}, {107.0f, 196.0f} }; - UnsignedInt glyphIds[]{ + UnsignedInt fontGlyphIds[]{ 3, 7, 9 }; + UnsignedInt glyphIds[]{ + 1, 3, 2 + }; Vector2 positions[3*4]; Vector2 textureCoordinates[3*4]; - Range2D rectangle = renderGlyphQuadsInto(font, 1.25f, cache, glyphPositions, glyphIds, positions, textureCoordinates); + Range2D rectangle = data.globalIds ? + renderGlyphQuadsInto(cache, 1.25f/2.5f, glyphPositions, glyphIds, positions, textureCoordinates) : + renderGlyphQuadsInto(font, 1.25f, cache, glyphPositions, fontGlyphIds, positions, textureCoordinates); CORRADE_COMPARE(rectangle, (Range2D{{102.5f, 198.5f}, {114.5f, 210.0f}})); CORRADE_COMPARE_AS(Containers::arrayView(positions), Containers::arrayView({