void Text::GetBatches(ea::vector<UIBatch>& batches, ea::vector<float>& vertexData, const IntRect& currentScissor) { FontFace* face = font_ ? font_->GetFace(fontSize_) : nullptr; if (!face) { hovering_ = false; return; } // If face has changed or char locations are not valid anymore, update before rendering if (charLocationsDirty_ || !fontFace_ || face != fontFace_) UpdateCharLocations(); // If face uses mutable glyphs mechanism, reacquire glyphs before rendering to make sure they are in the texture else if (face->HasMutableGlyphs()) { for (unsigned i = 0; i < printText_.size(); ++i) face->GetGlyph(printText_[i]); } // Hovering and/or whole selection batch UISelectable::GetBatches(batches, vertexData, currentScissor); // Partial selection batch if (!selected_ && selectionLength_ && charLocations_.size() >= selectionStart_ + selectionLength_ && selectionColor_.a_ > 0.0f) { UIBatch batch(this, BLEND_ALPHA, currentScissor, nullptr, &vertexData); batch.SetColor(selectionColor_); Vector2 currentStart = charLocations_[selectionStart_].position_; Vector2 currentEnd = currentStart; for (unsigned i = selectionStart_; i < selectionStart_ + selectionLength_; ++i) { // Check if row changes, and start a new quad in that case if (charLocations_[i].size_ != Vector2::ZERO) { if (charLocations_[i].position_.y_ != currentStart.y_) { batch.AddQuad(currentStart.x_, currentStart.y_, currentEnd.x_ - currentStart.x_, currentEnd.y_ - currentStart.y_, 0, 0); currentStart = charLocations_[i].position_; currentEnd = currentStart + charLocations_[i].size_; } else { currentEnd.x_ += charLocations_[i].size_.x_; currentEnd.y_ = Max(currentStart.y_ + charLocations_[i].size_.y_, currentEnd.y_); } } } if (currentEnd != currentStart) { batch.AddQuad(currentStart.x_, currentStart.y_, currentEnd.x_ - currentStart.x_, currentEnd.y_ - currentStart.y_, 0, 0); } UIBatch::AddOrMerge(batch, batches); } // Text batch TextEffect textEffect = font_->IsSDFFont() ? TE_NONE : textEffect_; const ea::vector<ea::shared_ptr<Texture2D> >& textures = face->GetTextures(); for (unsigned n = 0; n < textures.size() && n < pageGlyphLocations_.size(); ++n) { // One batch per texture/page UIBatch pageBatch(this, BLEND_ALPHA, currentScissor, textures[n], &vertexData); const ea::vector<GlyphLocation>& pageGlyphLocation = pageGlyphLocations_[n]; switch (textEffect) { case TE_NONE: ConstructBatch(pageBatch, pageGlyphLocation, 0, 0); break; case TE_SHADOW: ConstructBatch(pageBatch, pageGlyphLocation, shadowOffset_.x_, shadowOffset_.y_, &effectColor_, effectDepthBias_); ConstructBatch(pageBatch, pageGlyphLocation, 0, 0); break; case TE_STROKE: if (roundStroke_) { // Samples should be even or glyph may be redrawn in wrong x y pos making stroke corners rough // Adding to thickness helps with thickness of 1 not having enought samples for this formula // or certain fonts with reflex corners requiring more glyph samples for a smooth stroke when large int thickness = Min(strokeThickness_, fontSize_); int samples = thickness * thickness + (thickness % 2 == 0 ? 4 : 3); float angle = 360.f / samples; auto floatThickness = (float)thickness; for (int i = 0; i < samples; ++i) { float x = Cos(angle * i) * floatThickness; float y = Sin(angle * i) * floatThickness; ConstructBatch(pageBatch, pageGlyphLocation, x, y, &effectColor_, effectDepthBias_); } } else { int thickness = Min(strokeThickness_, fontSize_); int x, y; for (x = -thickness; x <= thickness; ++x) { for (y = -thickness; y <= thickness; ++y) { // Don't draw glyphs that aren't on the edges if (x > -thickness && x < thickness && y > -thickness && y < thickness) continue; ConstructBatch(pageBatch, pageGlyphLocation, x, y, &effectColor_, effectDepthBias_); } } } ConstructBatch(pageBatch, pageGlyphLocation, 0, 0); break; } UIBatch::AddOrMerge(pageBatch, batches); } }
void Text::GetBatches(PODVector<UIBatch>& batches, PODVector<float>& vertexData, const IntRect& currentScissor) { FontFace* face = font_ ? font_->GetFace(fontSize_) : (FontFace*)0; if (!face) { hovering_ = false; return; } // If face has changed or char locations are not valid anymore, update before rendering if (charLocationsDirty_ || !fontFace_ || face != fontFace_) UpdateCharLocations(); // If face uses mutable glyphs mechanism, reacquire glyphs before rendering to make sure they are in the texture else if (face->HasMutableGlyphs()) { for (unsigned i = 0; i < printText_.Size(); ++i) face->GetGlyph(printText_[i]); } // 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.SetColor(both ? selectionColor_.Lerp(hoverColor_, 0.5f) : (selected_ && selectionColor_.a_ > 0.0f ? selectionColor_ : hoverColor_)); batch.AddQuad(0, 0, GetWidth(), GetHeight(), 0, 0); UIBatch::AddOrMerge(batch, batches); } // Partial selection batch if (!selected_ && selectionLength_ && charLocations_.Size() >= selectionStart_ + selectionLength_ && selectionColor_.a_ > 0.0f) { UIBatch batch(this, BLEND_ALPHA, currentScissor, 0, &vertexData); batch.SetColor(selectionColor_); IntVector2 currentStart = charLocations_[selectionStart_].position_; IntVector2 currentEnd = currentStart; for (unsigned i = selectionStart_; i < selectionStart_ + selectionLength_; ++i) { // Check if row changes, and start a new quad in that case if (charLocations_[i].size_ != IntVector2::ZERO) { if (charLocations_[i].position_.y_ != currentStart.y_) { batch.AddQuad(currentStart.x_, currentStart.y_, currentEnd.x_ - currentStart.x_, currentEnd.y_ - currentStart.y_, 0, 0); currentStart = charLocations_[i].position_; currentEnd = currentStart + charLocations_[i].size_; } else { currentEnd.x_ += charLocations_[i].size_.x_; currentEnd.y_ = Max(currentStart.y_ + charLocations_[i].size_.y_, currentEnd.y_); } } } if (currentEnd != currentStart) { batch.AddQuad(currentStart.x_, currentStart.y_, currentEnd.x_ - currentStart.x_, currentEnd.y_ - currentStart.y_, 0, 0); } UIBatch::AddOrMerge(batch, batches); } // Text batch TextEffect textEffect = font_->IsSDFFont() ? TE_NONE : textEffect_; const Vector<SharedPtr<Texture2D> >& textures = face->GetTextures(); for (unsigned n = 0; n < textures.Size() && n < pageGlyphLocations_.Size(); ++n) { // One batch per texture/page UIBatch pageBatch(this, BLEND_ALPHA, currentScissor, textures[n], &vertexData); const PODVector<GlyphLocation>& pageGlyphLocation = pageGlyphLocations_[n]; switch (textEffect) { case TE_NONE: ConstructBatch(pageBatch, pageGlyphLocation, 0, 0); break; case TE_SHADOW: ConstructBatch(pageBatch, pageGlyphLocation, 1, 1, &effectColor_, effectDepthBias_); ConstructBatch(pageBatch, pageGlyphLocation, 0, 0); break; case TE_STROKE: ConstructBatch(pageBatch, pageGlyphLocation, -1, -1, &effectColor_, effectDepthBias_); ConstructBatch(pageBatch, pageGlyphLocation, 0, -1, &effectColor_, effectDepthBias_); ConstructBatch(pageBatch, pageGlyphLocation, 1, -1, &effectColor_, effectDepthBias_); ConstructBatch(pageBatch, pageGlyphLocation, -1, 0, &effectColor_, effectDepthBias_); ConstructBatch(pageBatch, pageGlyphLocation, 1, 0, &effectColor_, effectDepthBias_); ConstructBatch(pageBatch, pageGlyphLocation, -1, 1, &effectColor_, effectDepthBias_); ConstructBatch(pageBatch, pageGlyphLocation, 0, 1, &effectColor_, effectDepthBias_); ConstructBatch(pageBatch, pageGlyphLocation, 1, 1, &effectColor_, effectDepthBias_); ConstructBatch(pageBatch, pageGlyphLocation, 0, 0); break; } UIBatch::AddOrMerge(pageBatch, batches); } // Reset hovering for next frame hovering_ = false; }