Example #1
0
void QSGDistanceFieldGlyphCache::populate(const QVector<glyph_t> &glyphs)
{
    QSet<glyph_t> referencedGlyphs;
    QSet<glyph_t> newGlyphs;
    int count = glyphs.count();
    for (int i = 0; i < count; ++i) {
        glyph_t glyphIndex = glyphs.at(i);
        if ((int) glyphIndex >= glyphCount()) {
            qWarning("Warning: distance-field glyph is not available with index %d", glyphIndex);
            continue;
        }

        GlyphData &gd = glyphData(glyphIndex);
        ++gd.ref;
        referencedGlyphs.insert(glyphIndex);

        if (gd.texCoord.isValid() || m_populatingGlyphs.contains(glyphIndex))
            continue;

        m_populatingGlyphs.insert(glyphIndex);

        if (gd.boundingRect.isEmpty()) {
            gd.texCoord.width = 0;
            gd.texCoord.height = 0;
        } else {
            newGlyphs.insert(glyphIndex);
        }
    }

    referenceGlyphs(referencedGlyphs);
    if (!newGlyphs.isEmpty())
        requestGlyphs(newGlyphs);
}
Example #2
0
void MagnumFontGLTest::layout() {
    MagnumFont font;
    CORRADE_VERIFY(font.openFile(Utility::Directory::join(MAGNUMFONT_TEST_DIR, "font.conf"), 0.0f));

    /* Fill the cache with some fake glyphs */
    GlyphCache cache(Vector2i(256));
    cache.insert(font.glyphId(U'W'), {25, 34}, {{0, 8}, {16, 128}});
    cache.insert(font.glyphId(U'e'), {25, 12}, {{16, 4}, {64, 32}});

    auto layouter = font.layout(cache, 0.5f, "Wave");
    CORRADE_VERIFY(layouter);
    CORRADE_COMPARE(layouter->glyphCount(), 4);

    Range2D rectangle;
    Range2D position;
    Range2D textureCoordinates;

    /* 'W' */
    Vector2 cursorPosition;
    std::tie(position, textureCoordinates) = layouter->renderGlyph(0, cursorPosition = {}, rectangle);
    CORRADE_COMPARE(position, Range2D({0.78125f, 1.0625f}, {1.28125f, 4.8125f}));
    CORRADE_COMPARE(textureCoordinates, Range2D({0, 0.03125f}, {0.0625f, 0.5f}));
    CORRADE_COMPARE(cursorPosition, Vector2(0.71875f, 0.0f));

    /* 'a' (not found) */
    std::tie(position, textureCoordinates) = layouter->renderGlyph(1, cursorPosition = {}, rectangle);
    CORRADE_COMPARE(position, Range2D());
    CORRADE_COMPARE(textureCoordinates, Range2D());
    CORRADE_COMPARE(cursorPosition, Vector2(0.25f, 0.0f));

    /* 'v' (not found) */
    std::tie(position, textureCoordinates) = layouter->renderGlyph(2, cursorPosition = {}, rectangle);
    CORRADE_COMPARE(position, Range2D());
    CORRADE_COMPARE(textureCoordinates, Range2D());
    CORRADE_COMPARE(cursorPosition, Vector2(0.25f, 0.0f));

    /* 'e' */
    std::tie(position, textureCoordinates) = layouter->renderGlyph(3, cursorPosition = {}, rectangle);
    CORRADE_COMPARE(position, Range2D({0.78125f, 0.375f}, {2.28125f, 1.25f}));
    CORRADE_COMPARE(textureCoordinates, Range2D({0.0625f, 0.015625f}, {0.25f, 0.125f}));
    CORRADE_COMPARE(cursorPosition, Vector2(0.375f, 0.0f));
}
Example #3
0
std::tuple<std::vector<Vertex>, Range2D> renderVerticesInternal(AbstractFont& font, const GlyphCache& cache, const Float size, const std::string& text, const Alignment alignment) {
    /* Output data, reserve memory as when the text would be ASCII-only. In
       reality the actual vertex count will be smaller, but allocating more at
       once is better than reallocating many times later. */
    std::vector<Vertex> vertices;
    vertices.reserve(text.size()*4);

    /* Total rendered bounds, intial line position, line increment, last+1
       vertex on previous line */
    Range2D rectangle;
    Vector2 linePosition;
    const Vector2 lineAdvance = Vector2::yAxis(font.lineHeight()*size/font.size());
    std::size_t lastLineLastVertex = 0;

    /* Temp buffer so we don't allocate for each new line */
    /**
     * @todo C++1z: use std::string_view to avoid the one allocation and all
     *      the copying altogether
     */
    std::string line;
    line.reserve(text.size());

    /* Render each line separately and align it horizontally */
    std::size_t pos, prevPos = 0;
    do {
        /* Empty line, nothing to do (the rest is done below in while expression) */
        if((pos = text.find('\n', prevPos)) == prevPos) continue;

        /* Copy the line into the temp buffer */
        line.assign(text, prevPos, pos-prevPos);

        /* Layout the line */
        const auto layouter = font.layout(cache, size, line);
        const UnsignedInt vertexCount = layouter->glyphCount()*4;

        /* Verify that we don't reallocate anything. The only problem might
           arise when the layouter decides to compose one character from more
           than one glyph (i.e. accents). Will remove the assert when this
           issue arises. */
        CORRADE_INTERNAL_ASSERT(vertices.size()+vertexCount <= vertices.capacity());

        /* Bounds of rendered line */
        Range2D lineRectangle;

        /* Render all glyphs */
        Vector2 cursorPosition(linePosition);
        for(UnsignedInt i = 0; i != layouter->glyphCount(); ++i) {
            Range2D quadPosition, textureCoordinates;
            std::tie(quadPosition, textureCoordinates) = layouter->renderGlyph(i, cursorPosition, lineRectangle);

            /* 0---2
               |   |
               |   |
               |   |
               1---3 */

            vertices.insert(vertices.end(), {
                {quadPosition.topLeft(), textureCoordinates.topLeft()},
                {quadPosition.bottomLeft(), textureCoordinates.bottomLeft()},
                {quadPosition.topRight(), textureCoordinates.topRight()},
                {quadPosition.bottomRight(), textureCoordinates.bottomRight()}
            });
        }

        /** @todo What about top-down text? */

        /* Horizontally align the rendered line */
        Float alignmentOffsetX = 0.0f;
        if((UnsignedByte(alignment) & Implementation::AlignmentHorizontal) == Implementation::AlignmentCenter)
            alignmentOffsetX = -lineRectangle.centerX();
        else if((UnsignedByte(alignment) & Implementation::AlignmentHorizontal) == Implementation::AlignmentRight)
            alignmentOffsetX = -lineRectangle.right();

        /* Integer alignment */
        if(UnsignedByte(alignment) & Implementation::AlignmentIntegral)
            alignmentOffsetX = Math::round(alignmentOffsetX);

        /* Align positions and bounds on current line */
        lineRectangle = lineRectangle.translated(Vector2::xAxis(alignmentOffsetX));
        for(auto it = vertices.begin()+lastLineLastVertex; it != vertices.end(); ++it)
            it->position.x() += alignmentOffsetX;

        /* Add final line bounds to total bounds, similarly to AbstractFont::renderGlyph() */
        if(!rectangle.size().isZero()) {
            rectangle.bottomLeft() = Math::min(rectangle.bottomLeft(), lineRectangle.bottomLeft());
            rectangle.topRight() = Math::max(rectangle.topRight(), lineRectangle.topRight());
        } else rectangle = lineRectangle;

    /* Move to next line */
    } while(prevPos = pos+1,
            linePosition -= lineAdvance,
            lastLineLastVertex = vertices.size(),
            pos != std::string::npos);

    /* Vertically align the rendered text */
    Float alignmentOffsetY = 0.0f;
    if((UnsignedByte(alignment) & Implementation::AlignmentVertical) == Implementation::AlignmentMiddle)
        alignmentOffsetY = -rectangle.centerY();
    else if((UnsignedByte(alignment) & Implementation::AlignmentVertical) == Implementation::AlignmentTop)
        alignmentOffsetY = -rectangle.top();

    /* Integer alignment */
    if(UnsignedByte(alignment) & Implementation::AlignmentIntegral)
        alignmentOffsetY = Math::round(alignmentOffsetY);

    /* Align positions and bounds */
    rectangle = rectangle.translated(Vector2::yAxis(alignmentOffsetY));
    for(auto& v: vertices) v.position.y() += alignmentOffsetY;

    return std::make_tuple(std::move(vertices), rectangle);
}