예제 #1
0
파일: Text.cpp 프로젝트: rokups/Urho3D
void Text::UpdateCharLocations()
{
    // Remember the font face to see if it's still valid when it's time to render
    FontFace* face = font_ ? font_->GetFace(fontSize_) : nullptr;
    if (!face)
        return;
    fontFace_ = face;

    auto rowHeight = RoundToInt(rowSpacing_ * rowHeight_);

    // Store position & size of each character, and locations per texture page
    unsigned numChars = unicodeText_.size();
    charLocations_.resize(numChars + 1);
    pageGlyphLocations_.resize(face->GetTextures().size());
    for (unsigned i = 0; i < pageGlyphLocations_.size(); ++i)
        pageGlyphLocations_[i].clear();

    IntVector2 offset = font_->GetTotalGlyphOffset(fontSize_);

    unsigned rowIndex = 0;
    unsigned lastFilled = 0;
    float x = Round(GetRowStartPosition(rowIndex) + offset.x_);
    float y = Round(offset.y_);

    for (unsigned i = 0; i < printText_.size(); ++i)
    {
        CharLocation loc;
        loc.position_ = Vector2(x, y);

        unsigned c = printText_[i];
        if (c != '\n')
        {
            const FontGlyph* glyph = face->GetGlyph(c);
            loc.size_ = Vector2(glyph ? glyph->advanceX_ : 0, rowHeight_);
            if (glyph)
            {
                // Store glyph's location for rendering. Verify that glyph page is valid
                if (glyph->page_ < pageGlyphLocations_.size())
                    pageGlyphLocations_[glyph->page_].push_back(GlyphLocation(x, y, glyph));
                x += glyph->advanceX_;
                if (i < printText_.size() - 1)
                    x += face->GetKerning(c, printText_[i + 1]);
            }
        }
        else
        {
            loc.size_ = Vector2::ZERO;
            x = GetRowStartPosition(++rowIndex);
            y += rowHeight;
        }

        if (lastFilled > printToText_[i])
            lastFilled = printToText_[i];

        // Fill gaps in case characters were skipped from printing
        for (unsigned j = lastFilled; j <= printToText_[i]; ++j)
            charLocations_[j] = loc;
        lastFilled = printToText_[i] + 1;
    }
    // Store the ending position
    charLocations_[numChars].position_ = Vector2(x, y);
    charLocations_[numChars].size_ = Vector2::ZERO;

    charLocationsDirty_ = false;
}
예제 #2
0
파일: Text.cpp 프로젝트: jjiezheng/urho3d
void Text::GetBatches(PODVector<UIBatch>& batches, PODVector<float>& vertexData, const IntRect& currentScissor)
{
    // Hovering and/or whole selection batch
    if ((hovering_ && hoverColor_.a_ > 0.0) || (selected_ && selectionColor_.a_ > 0.0f))
    {
        bool both = hovering_ && selected_ && hoverColor_.a_ > 0.0 && selectionColor_.a_ > 0.0f;
        UIBatch batch(this, BLEND_ALPHA, currentScissor, 0, &vertexData);
        batch.AddQuad(0, 0, GetWidth(), GetHeight(), 0, 0, 0, 0, both ? selectionColor_.Lerp(hoverColor_, 0.5f) :
                      (selected_ && selectionColor_.a_ > 0.0f ? selectionColor_ : hoverColor_));
        UIBatch::AddOrMerge(batch, batches);
    }

    // Partial selection batch
    if (!selected_ && selectionLength_ && charSizes_.Size() >= selectionStart_ + selectionLength_ && selectionColor_.a_ > 0.0f)
    {
        UIBatch batch(this, BLEND_ALPHA, currentScissor, 0, &vertexData);

        IntVector2 currentStart = charPositions_[selectionStart_];
        IntVector2 currentEnd = currentStart;
        for (unsigned i = selectionStart_; i < selectionStart_ + selectionLength_; ++i)
        {
            // Check if row changes, and start a new quad in that case
            if (charSizes_[i].x_ && charSizes_[i].y_)
            {
                if (charPositions_[i].y_ != currentStart.y_)
                {
                    batch.AddQuad(currentStart.x_, currentStart.y_, currentEnd.x_ - currentStart.x_, currentEnd.y_ - currentStart.y_,
                                  0, 0, 0, 0, selectionColor_);
                    currentStart = charPositions_[i];
                    currentEnd = currentStart + charSizes_[i];
                }
                else
                {
                    currentEnd.x_ += charSizes_[i].x_;
                    currentEnd.y_ = Max(currentStart.y_ + charSizes_[i].y_, currentEnd.y_);
                }
            }
        }
        if (currentEnd != currentStart)
        {
            batch.AddQuad(currentStart.x_, currentStart.y_, currentEnd.x_ - currentStart.x_, currentEnd.y_ - currentStart.y_,
                          0, 0, 0, 0, selectionColor_);
        }

        UIBatch::AddOrMerge(batch, batches);
    }

    // Text batch
    if (font_)
    {
        const FontFace* face = font_->GetFace(fontSize_);
        if (!face)
            return;

        if (face->textures_.Size() > 1)
        {
            // Only traversing thru the printText once regardless of number of textures/pages in the font
            Vector<PODVector<GlyphLocation> > pageGlyphLocations(face->textures_.Size());

            unsigned rowIndex = 0;
            int x = GetRowStartPosition(rowIndex);
            int y = 0;

            for (unsigned i = 0; i < printText_.Size(); ++i)
            {
                unsigned c = printText_[i];

                if (c != '\n')
                {
                    const FontGlyph* p = face->GetGlyph(c);
                    if (!p)
                        continue;

                    pageGlyphLocations[p->page_].Push(GlyphLocation(x, y, p));

                    x += p->advanceX_;
                    if (i < printText_.Size() - 1)
                        x += face->GetKerning(c, printText_[i + 1]);
                }
                else
                {
                    x = GetRowStartPosition(++rowIndex);
                    y += rowHeight_;
                }
            }

            for (unsigned n = 0; n < face->textures_.Size(); ++n)
            {
                // One batch per texture/page
                UIBatch pageBatch(this, BLEND_ALPHA, currentScissor, face->textures_[n], &vertexData);

                const PODVector<GlyphLocation>& pageGlyphLocation = pageGlyphLocations[n];
                for (unsigned i = 0; i < pageGlyphLocation.Size(); ++i)
                {
                    const GlyphLocation& glyphLocation = pageGlyphLocation[i];
                    const FontGlyph& glyph = *glyphLocation.glyph_;
                    pageBatch.AddQuad(glyphLocation.x_ + glyph.offsetX_, glyphLocation.y_ + glyph.offsetY_, glyph.width_, glyph.height_, glyph.x_, glyph.y_);
                }

                batches.Push(pageBatch);
            }
        }
        else
        {
            // If only one texture page, construct the UI batch directly
            unsigned rowIndex = 0;
            int x = GetRowStartPosition(rowIndex);
            int y = 0;

            UIBatch batch(this, BLEND_ALPHA, currentScissor, face->textures_[0], &vertexData);

            for (unsigned i = 0; i < printText_.Size(); ++i)
            {
                unsigned c = printText_[i];

                if (c != '\n')
                {
                    const FontGlyph* p = face->GetGlyph(c);
                    if (!p)
                        continue;

                    batch.AddQuad(x + p->offsetX_, y + p->offsetY_, p->width_, p->height_, p->x_, p->y_);

                    x += p->advanceX_;
                    if (i < printText_.Size() - 1)
                        x += face->GetKerning(c, printText_[i + 1]);
                }
                else
                {
                    x = GetRowStartPosition(++rowIndex);
                    y += rowHeight_;
                }
            }

            UIBatch::AddOrMerge(batch, batches);
        }
    }

    // Reset hovering for next frame
    hovering_ = false;
}
예제 #3
0
파일: Text.cpp 프로젝트: jjiezheng/urho3d
void Text::UpdateText()
{
    int width = 0;
    int height = 0;

    rowWidths_.Clear();
    printText_.Clear();

    PODVector<unsigned> printToText;

    if (font_)
    {
        const FontFace* face = font_->GetFace(fontSize_);
        if (!face)
            return;

        rowHeight_ = face->rowHeight_;
        int rowWidth = 0;
        int rowHeight = (int)(rowSpacing_ * rowHeight_);

        // First see if the text must be split up
        if (!wordWrap_)
        {
            printText_ = unicodeText_;
            printToText.Resize(printText_.Size());
            for (unsigned i = 0; i < printText_.Size(); ++i)
                printToText[i] = i;
        }
        else
        {
            int maxWidth = GetWidth();
            unsigned nextBreak = 0;
            unsigned lineStart = 0;
            for (unsigned i = 0; i < unicodeText_.Size(); ++i)
            {
                unsigned j;
                unsigned c = unicodeText_[i];

                if (c != '\n')
                {
                    bool ok = true;

                    if (nextBreak <= i)
                    {
                        int futureRowWidth = rowWidth;
                        for (j = i; j < unicodeText_.Size(); ++j)
                        {
                            unsigned d = unicodeText_[j];
                            if (d == ' ' || d == '\n')
                            {
                                nextBreak = j;
                                break;
                            }
                            const FontGlyph* glyph = face->GetGlyph(d);
                            if (glyph)
                            {
                                futureRowWidth += glyph->advanceX_;
                                if (j < unicodeText_.Size() - 1)
                                    futureRowWidth += face->GetKerning(d, unicodeText_[j + 1]);
                            }
                            if (d == '-' && futureRowWidth <= maxWidth)
                            {
                                nextBreak = j + 1;
                                break;
                            }
                            if (futureRowWidth > maxWidth)
                            {
                                ok = false;
                                break;
                            }
                        }
                    }

                    if (!ok)
                    {
                        // If did not find any breaks on the line, copy until j, or at least 1 char, to prevent infinite loop
                        if (nextBreak == lineStart)
                        {
                            while (i < j)
                            {
                                printText_.Push(unicodeText_[i]);
                                printToText.Push(i);
                                ++i;
                            }
                        }
                        printText_.Push('\n');
                        printToText.Push(Min((int)i, (int)unicodeText_.Size() - 1));
                        rowWidth = 0;
                        nextBreak = lineStart = i;
                    }

                    if (i < unicodeText_.Size())
                    {
                        // When copying a space, position is allowed to be over row width
                        c = unicodeText_[i];
                        const FontGlyph* glyph = face->GetGlyph(c);
                        if (glyph)
                        {
                            rowWidth += glyph->advanceX_;
                            if (i < text_.Length() - 1)
                                rowWidth += face->GetKerning(c, unicodeText_[i + 1]);
                        }
                        if (rowWidth <= maxWidth)
                        {
                            printText_.Push(c);
                            printToText.Push(i);
                        }
                    }
                }
                else
                {
                    printText_.Push('\n');
                    printToText.Push(Min((int)i, (int)unicodeText_.Size() - 1));
                    rowWidth = 0;
                    nextBreak = lineStart = i;
                }
            }
        }

        rowWidth = 0;

        for (unsigned i = 0; i < printText_.Size(); ++i)
        {
            unsigned c = printText_[i];

            if (c != '\n')
            {
                const FontGlyph* glyph = face->GetGlyph(c);
                if (glyph)
                {
                    rowWidth += glyph->advanceX_;
                    if (i < printText_.Size() - 1)
                        rowWidth += face->GetKerning(c, printText_[i + 1]);
                }
            }
            else
            {
                width = Max(width, rowWidth);
                height += rowHeight;
                rowWidths_.Push(rowWidth);
                rowWidth = 0;
            }
        }

        if (rowWidth)
        {
            width = Max(width, rowWidth);
            height += rowHeight;
            rowWidths_.Push(rowWidth);
        }

        // Set row height even if text is empty
        if (!height)
            height = rowHeight;

        // Store position & size of each character
        charPositions_.Resize(unicodeText_.Size() + 1);
        charSizes_.Resize(unicodeText_.Size());

        unsigned rowIndex = 0;
        int x = GetRowStartPosition(rowIndex);
        int y = 0;
        for (unsigned i = 0; i < printText_.Size(); ++i)
        {
            charPositions_[printToText[i]] = IntVector2(x, y);
            unsigned c = printText_[i];
            if (c != '\n')
            {
                const FontGlyph* glyph = face->GetGlyph(c);
                charSizes_[printToText[i]] = IntVector2(glyph ? glyph->advanceX_ : 0, rowHeight_);
                if (glyph)
                {
                    x += glyph->advanceX_;
                    if (i < printText_.Size() - 1)
                        x += face->GetKerning(c, printText_[i + 1]);
                }
            }
            else
            {
                charSizes_[printToText[i]] = IntVector2::ZERO;
                x = GetRowStartPosition(++rowIndex);
                y += rowHeight;
            }
        }
        // Store the ending position
        charPositions_[unicodeText_.Size()] = IntVector2(x, y);
    }

    // Set minimum and current size according to the text size, but respect fixed width if set
    if (!IsFixedWidth())
    {
        SetMinWidth(wordWrap_ ? 0 : width);
        SetWidth(width);
    }
    SetFixedHeight(height);
}
예제 #4
0
파일: Text.cpp 프로젝트: acremean/urho3d
void Text::GetBatches(PODVector<UIBatch>& batches, PODVector<UIQuad>& quads, const IntRect& currentScissor)
{
    // Hovering or whole selection batch
    if ((hovering_ && hoverColor_.a_ > 0.0) || (selected_ && selectionColor_.a_ > 0.0f))
    {
        UIBatch batch(BLEND_ALPHA, currentScissor, 0, &quads);
        batch.AddQuad(*this, 0, 0, GetWidth(), GetHeight(), 0, 0, 0, 0, selected_ && selectionColor_.a_ > 0.0f ? selectionColor_ :
            hoverColor_);
        UIBatch::AddOrMerge(batch, batches);
    }
    
    // Partial selection batch
    if (!selected_ && selectionLength_ && charSizes_.Size() >= selectionStart_ + selectionLength_ && selectionColor_.a_ > 0.0f)
    {
        UIBatch batch(BLEND_ALPHA, currentScissor, 0, &quads);
        
        IntVector2 currentStart = charPositions_[selectionStart_];
        IntVector2 currentEnd = currentStart;
        for (unsigned i = selectionStart_; i < selectionStart_ + selectionLength_; ++i)
        {
            // Check if row changes, and start a new quad in that case
            if (charSizes_[i].x_ && charSizes_[i].y_)
            {
                if (charPositions_[i].y_ != currentStart.y_)
                {
                    batch.AddQuad(*this, currentStart.x_, currentStart.y_, currentEnd.x_ - currentStart.x_, currentEnd.y_ - currentStart.y_,
                        0, 0, 0, 0, selectionColor_);
                    currentStart = charPositions_[i];
                    currentEnd = currentStart + charSizes_[i];
                }
                else
                {
                    currentEnd.x_ += charSizes_[i].x_;
                    currentEnd.y_ = Max(currentStart.y_ + charSizes_[i].y_, currentEnd.y_);
                }
            }
        }
        if (currentEnd != currentStart)
        {
            batch.AddQuad(*this, currentStart.x_, currentStart.y_, currentEnd.x_ - currentStart.x_, currentEnd.y_ - currentStart.y_,
                0, 0, 0, 0, selectionColor_);
        }
        
        UIBatch::AddOrMerge(batch, batches);
    }
    
    // Text batch
    if (font_)
    {
        const FontFace* face = font_->GetFace(fontSize_);
        if (!face)
            return;
        
        UIBatch batch(BLEND_ALPHA, currentScissor, face->texture_, &quads);
        
        unsigned rowIndex = 0;
        int x = GetRowStartPosition(rowIndex);
        int y = 0;
        
        for (unsigned i = 0; i < printText_.Size(); ++i)
        {
            unsigned c = printText_[i];
            
            if (c != '\n')
            {
                const FontGlyph& glyph = face->GetGlyph(c);
                if (c != ' ')
                    batch.AddQuad(*this, x + glyph.offsetX_, y + glyph.offsetY_, glyph.width_, glyph.height_, glyph.x_, glyph.y_);
                
                x += glyph.advanceX_;
                if (i < printText_.Size() - 1)
                    x += face->GetKerning(c, printText_[i + 1]);
            }
            else
            {
                x = GetRowStartPosition(++rowIndex);
                y += rowHeight_;
            }
        }
        
        UIBatch::AddOrMerge(batch, batches);
    }
    
    // Reset hovering for next frame
    hovering_ = false;
}