From 39dcc92f2a1e8ab20bba312f474d34f818be248e Mon Sep 17 00:00:00 2001 From: Alexander Shalamov Date: Mon, 4 Mar 2019 09:37:22 +0200 Subject: [core] Populate symbol layer paint properties for text sections --- src/mbgl/layout/symbol_layout.cpp | 126 +++++++++++++++------------- src/mbgl/layout/symbol_layout.hpp | 18 ++-- src/mbgl/renderer/buckets/symbol_bucket.hpp | 15 +--- src/mbgl/renderer/paint_property_binder.hpp | 38 +++++---- 4 files changed, 102 insertions(+), 95 deletions(-) diff --git a/src/mbgl/layout/symbol_layout.cpp b/src/mbgl/layout/symbol_layout.cpp index edacaf9dda..e95fb56c1d 100644 --- a/src/mbgl/layout/symbol_layout.cpp +++ b/src/mbgl/layout/symbol_layout.cpp @@ -1,25 +1,16 @@ -#include #include #include #include -#include #include #include #include -#include #include #include -#include #include -#include #include #include #include -#include -#include -#include #include -#include #include #include @@ -31,11 +22,23 @@ using namespace style; template static bool has(const style::SymbolLayoutProperties::PossiblyEvaluated& layout) { return layout.get().match( - [&] (const typename Property::Type& t) { return !t.empty(); }, - [&] (const auto&) { return true; } + [] (const typename Property::Type& t) { return !t.empty(); }, + [] (const auto&) { return true; } ); } +namespace { +expression::Value sectionOptionsToValue(const SectionOptions& options) { + if (options.id) { + return (*options.id).match( + [] (double t) -> expression::Value { return t; }, + [] (const std::string& t) -> expression::Value { return t; }, + [] (auto&) -> expression::Value { return {}; }); + } + return {}; +} +} // namespace + SymbolLayout::SymbolLayout(const BucketParameters& parameters, const std::vector& layers, std::unique_ptr sourceLayer_, @@ -108,7 +111,6 @@ SymbolLayout::SymbolLayout(const BucketParameters& parameters, auto formatted = layout.evaluate(zoom, ft); auto textTransform = layout.evaluate(zoom, ft); FontStack baseFontStack = layout.evaluate(zoom, ft); - FontStackHash baseFontStackHash = FontStackHasher()(baseFontStack); ft.formattedText = TaggedString(); for (std::size_t j = 0; j < formatted.sections.size(); j++) { @@ -122,8 +124,8 @@ SymbolLayout::SymbolLayout(const BucketParameters& parameters, ft.formattedText->addSection(applyArabicShaping(util::convertUTF8ToUTF16(u8string)), section.fontScale ? *section.fontScale : 1.0, - section.fontStack ? FontStackHasher()(*section.fontStack) : baseFontStackHash); - + section.fontStack ? *section.fontStack : baseFontStack, + section.id); } @@ -418,43 +420,57 @@ void SymbolLayout::createBucket(const ImagePositions&, std::unique_ptr sizeData = bucket->textSizeBinder->getVertexSizeData(feature); - bucket->text.placedSymbols.emplace_back(symbolInstance.anchor.point, symbolInstance.anchor.segment, sizeData.min, sizeData.max, - symbolInstance.textOffset, symbolInstance.writingModes, symbolInstance.line, CalculateTileDistances(symbolInstance.line, symbolInstance.anchor)); - symbolInstance.placedTextIndex = bucket->text.placedSymbols.size() - 1; - PlacedSymbol& horizontalSymbol = bucket->text.placedSymbols.back(); - - bool firstHorizontal = true; - for (const auto& symbol : symbolInstance.horizontalGlyphQuads) { - size_t index = addSymbol( - bucket->text, sizeData, symbol, - symbolInstance.anchor, horizontalSymbol); - if (firstHorizontal) { - horizontalSymbol.vertexStartIndex = index; - firstHorizontal = false; - } + if (hasText && feature.formattedText) { + const auto& formattedText = *feature.formattedText; + std::function updatePaintProperties; + if (formattedText.hasMultipleUniqueSections()) { + updatePaintProperties = [&, currentSectionIndex = optional{}](std::size_t symbolSectionIndex, bool updateLastSection) mutable { + if (currentSectionIndex && (updateLastSection || *currentSectionIndex != symbolSectionIndex)) { + const auto& formattedSection = sectionOptionsToValue(formattedText.sectionAt(*currentSectionIndex)); + for (auto& pair : bucket->paintProperties) { + pair.second.textBinders.populateVertexVectors(feature, bucket->text.vertices.vertexSize(), {}, {}, formattedSection); + } + } + currentSectionIndex = symbolSectionIndex; + }; + } else { + updatePaintProperties = [&](std::size_t, bool updateLastSection) { + if (updateLastSection) { + const auto& formattedSection = sectionOptionsToValue(formattedText.sectionAt(0)); + for (auto& pair : bucket->paintProperties) { + pair.second.textBinders.populateVertexVectors(feature, bucket->text.vertices.vertexSize(), {}, {}, formattedSection); + } + } + }; } - if (symbolInstance.writingModes & WritingModeType::Vertical) { + const Range sizeData = bucket->textSizeBinder->getVertexSizeData(feature); + auto addSymbolGlyphQuads = [&](WritingModeType writingMode, + optional& placedIndex, + const SymbolQuads& glyphQuads) { bucket->text.placedSymbols.emplace_back(symbolInstance.anchor.point, symbolInstance.anchor.segment, sizeData.min, sizeData.max, - symbolInstance.textOffset, WritingModeType::Vertical, symbolInstance.line, CalculateTileDistances(symbolInstance.line, symbolInstance.anchor)); - symbolInstance.placedVerticalTextIndex = bucket->text.placedSymbols.size() - 1; - - PlacedSymbol& verticalSymbol = bucket->text.placedSymbols.back(); - bool firstVertical = true; - - for (const auto& symbol : symbolInstance.verticalGlyphQuads) { - size_t index = addSymbol( - bucket->text, sizeData, symbol, - symbolInstance.anchor, verticalSymbol); - - if (firstVertical) { - verticalSymbol.vertexStartIndex = index; - firstVertical = false; + symbolInstance.textOffset, writingMode, symbolInstance.line, CalculateTileDistances(symbolInstance.line, symbolInstance.anchor)); + placedIndex = bucket->text.placedSymbols.size() - 1; + PlacedSymbol& placedSymbol = bucket->text.placedSymbols.back(); + + bool firstSymbol = true; + for (const auto& symbolQuad : glyphQuads) { + updatePaintProperties(symbolQuad.sectionIndex, false); + size_t index = addSymbol(bucket->text, sizeData, symbolQuad, symbolInstance.anchor, placedSymbol); + if (firstSymbol) { + placedSymbol.vertexStartIndex = index; + firstSymbol = false; } } + }; + + addSymbolGlyphQuads(symbolInstance.writingModes, symbolInstance.placedTextIndex, symbolInstance.horizontalGlyphQuads); + + if (symbolInstance.writingModes & WritingModeType::Vertical) { + addSymbolGlyphQuads(WritingModeType::Vertical, symbolInstance.placedVerticalTextIndex, symbolInstance.verticalGlyphQuads); } + + updatePaintProperties(0, true); } if (hasIcon) { @@ -466,12 +482,11 @@ void SymbolLayout::createBucket(const ImagePositions&, std::unique_ptricon.placedSymbols.back(); iconSymbol.vertexStartIndex = addSymbol(bucket->icon, sizeData, *symbolInstance.iconQuad, symbolInstance.anchor, iconSymbol); - } - } - for (auto& pair : bucket->paintProperties) { - pair.second.iconBinders.populateVertexVectors(feature, bucket->icon.vertices.vertexSize(), {}, {}); - pair.second.textBinders.populateVertexVectors(feature, bucket->text.vertices.vertexSize(), {}, {}); + for (auto& pair : bucket->paintProperties) { + pair.second.iconBinders.populateVertexVectors(feature, bucket->icon.vertices.vertexSize(), {}, {}); + } + } } } @@ -489,12 +504,11 @@ void SymbolLayout::createBucket(const ImagePositions&, std::unique_ptr -size_t SymbolLayout::addSymbol(Buffer& buffer, - const Range sizeData, - const SymbolQuad& symbol, - const Anchor& labelAnchor, - PlacedSymbol& placedSymbol) { +size_t SymbolLayout::addSymbol(SymbolBucket::Buffer& buffer, + const Range sizeData, + const SymbolQuad& symbol, + const Anchor& labelAnchor, + PlacedSymbol& placedSymbol) { constexpr const uint16_t vertexLength = 4; const auto &tl = symbol.tl; diff --git a/src/mbgl/layout/symbol_layout.hpp b/src/mbgl/layout/symbol_layout.hpp index ab6dc049a2..870ad4b415 100644 --- a/src/mbgl/layout/symbol_layout.hpp +++ b/src/mbgl/layout/symbol_layout.hpp @@ -6,18 +6,15 @@ #include #include #include -#include -#include +#include #include #include -#include #include namespace mbgl { class BucketParameters; -class SymbolBucket; class Anchor; class RenderLayer; class PlacedSymbol; @@ -26,7 +23,7 @@ namespace style { class Filter; } // namespace style -class SymbolLayout : public Layout { +class SymbolLayout final : public Layout { public: SymbolLayout(const BucketParameters&, const std::vector&, @@ -62,12 +59,11 @@ private: void addToDebugBuffers(SymbolBucket&); // Adds placed items to the buffer. - template - size_t addSymbol(Buffer&, - const Range sizeData, - const SymbolQuad&, - const Anchor& labelAnchor, - PlacedSymbol& placedSymbol); + size_t addSymbol(SymbolBucket::Buffer&, + const Range sizeData, + const SymbolQuad&, + const Anchor& labelAnchor, + PlacedSymbol& placedSymbol); // Stores the layer so that we can hold on to GeometryTileFeature instances in SymbolFeature, // which may reference data from this object. diff --git a/src/mbgl/renderer/buckets/symbol_bucket.hpp b/src/mbgl/renderer/buckets/symbol_bucket.hpp index 5b9b11cf4d..ecf9a861df 100644 --- a/src/mbgl/renderer/buckets/symbol_bucket.hpp +++ b/src/mbgl/renderer/buckets/symbol_bucket.hpp @@ -87,7 +87,7 @@ public: std::unique_ptr textSizeBinder; - struct TextBuffer { + struct Buffer { gl::VertexVector vertices; gl::VertexVector> dynamicVertices; gl::VertexVector> opacityVertices; @@ -103,19 +103,8 @@ public: std::unique_ptr iconSizeBinder; - struct IconBuffer { - gl::VertexVector vertices; - gl::VertexVector> dynamicVertices; - gl::VertexVector> opacityVertices; - gl::IndexVector triangles; - SegmentVector segments; - std::vector placedSymbols; + struct IconBuffer : public Buffer { PremultipliedImage atlasImage; - - optional> vertexBuffer; - optional>> dynamicVertexBuffer; - optional>> opacityVertexBuffer; - optional> indexBuffer; } icon; struct CollisionBuffer { diff --git a/src/mbgl/renderer/paint_property_binder.hpp b/src/mbgl/renderer/paint_property_binder.hpp index 56f187507f..9659384d33 100644 --- a/src/mbgl/renderer/paint_property_binder.hpp +++ b/src/mbgl/renderer/paint_property_binder.hpp @@ -95,7 +95,10 @@ public: virtual ~PaintPropertyBinder() = default; - virtual void populateVertexVector(const GeometryTileFeature& feature, std::size_t length, const ImagePositions&, const optional&) = 0; + virtual void populateVertexVector(const GeometryTileFeature& feature, + std::size_t length, const ImagePositions&, + const optional&, + const style::expression::Value&) = 0; virtual void upload(gl::Context& context) = 0; virtual void setPatternParameters(const optional&, const optional&, CrossfadeParameters&) = 0; virtual std::tuple>...> attributeBinding(const PossiblyEvaluatedType& currentValue) const = 0; @@ -108,13 +111,13 @@ public: }; template -class ConstantPaintPropertyBinder : public PaintPropertyBinder, A> { +class ConstantPaintPropertyBinder final : public PaintPropertyBinder, A> { public: ConstantPaintPropertyBinder(T constant_) : constant(std::move(constant_)) { } - void populateVertexVector(const GeometryTileFeature&, std::size_t, const ImagePositions&, const optional&) override {} + void populateVertexVector(const GeometryTileFeature&, std::size_t, const ImagePositions&, const optional&, const style::expression::Value&) override {} void upload(gl::Context&) override {} void setPatternParameters(const optional&, const optional&, CrossfadeParameters&) override {}; @@ -135,13 +138,13 @@ private: }; template -class ConstantCrossFadedPaintPropertyBinder : public PaintPropertyBinder,PossiblyEvaluatedPropertyValue>, As...> { +class ConstantCrossFadedPaintPropertyBinder final : public PaintPropertyBinder,PossiblyEvaluatedPropertyValue>, As...> { public: ConstantCrossFadedPaintPropertyBinder(Faded constant_) : constant(std::move(constant_)), constantPatternPositions({}) { } - void populateVertexVector(const GeometryTileFeature&, std::size_t, const ImagePositions&, const optional&) override {} + void populateVertexVector(const GeometryTileFeature&, std::size_t, const ImagePositions&, const optional&, const style::expression::Value&) override {} void upload(gl::Context&) override {} void setPatternParameters(const optional& posA, const optional& posB, CrossfadeParameters&) override { @@ -171,7 +174,7 @@ private: }; template -class SourceFunctionPaintPropertyBinder : public PaintPropertyBinder, A> { +class SourceFunctionPaintPropertyBinder final : public PaintPropertyBinder, A> { public: using BaseAttributeType = A; using BaseAttributeValue = typename A::Value; @@ -184,8 +187,9 @@ public: defaultValue(std::move(defaultValue_)) { } void setPatternParameters(const optional&, const optional&, CrossfadeParameters&) override {}; - void populateVertexVector(const GeometryTileFeature& feature, std::size_t length, const ImagePositions&, const optional&) override { - auto evaluated = expression.evaluate(feature, defaultValue); + void populateVertexVector(const GeometryTileFeature& feature, std::size_t length, const ImagePositions&, const optional&, const style::expression::Value& formattedSection) override { + using style::expression::EvaluationContext; + auto evaluated = expression.evaluate(EvaluationContext(&feature).withFormattedSection(&formattedSection), defaultValue); this->statistics.add(evaluated); auto value = attributeValue(evaluated); for (std::size_t i = vertexVector.vertexSize(); i < length; ++i) { @@ -226,7 +230,7 @@ private: }; template -class CompositeFunctionPaintPropertyBinder : public PaintPropertyBinder, A> { +class CompositeFunctionPaintPropertyBinder final : public PaintPropertyBinder, A> { public: using AttributeType = ZoomInterpolatedAttributeType; @@ -239,8 +243,12 @@ public: zoomRange({zoom, zoom + 1}) { } void setPatternParameters(const optional&, const optional&, CrossfadeParameters&) override {}; - void populateVertexVector(const GeometryTileFeature& feature, std::size_t length, const ImagePositions&, const optional&) override { - Range range = expression.evaluate(zoomRange, feature, defaultValue); + void populateVertexVector(const GeometryTileFeature& feature, std::size_t length, const ImagePositions&, const optional&, const style::expression::Value& formattedSection) override { + using style::expression::EvaluationContext; + Range range = { + expression.evaluate(EvaluationContext(zoomRange.min, &feature).withFormattedSection(&formattedSection), defaultValue), + expression.evaluate(EvaluationContext(zoomRange.max, &feature).withFormattedSection(&formattedSection), defaultValue), + }; this->statistics.add(range.min); this->statistics.add(range.max); AttributeValue value = zoomInterpolatedAttributeValue( @@ -289,7 +297,7 @@ private: }; template -class CompositeCrossFadedPaintPropertyBinder : public PaintPropertyBinder, PossiblyEvaluatedPropertyValue>, A1, A2> { +class CompositeCrossFadedPaintPropertyBinder final : public PaintPropertyBinder, PossiblyEvaluatedPropertyValue>, A1, A2> { public: using AttributeType = ZoomInterpolatedAttributeType; using AttributeType2 = ZoomInterpolatedAttributeType; @@ -313,7 +321,7 @@ public: crossfade = crossfade_; }; - void populateVertexVector(const GeometryTileFeature&, std::size_t length, const ImagePositions& patternPositions, const optional& patternDependencies) override { + void populateVertexVector(const GeometryTileFeature&, std::size_t length, const ImagePositions& patternPositions, const optional& patternDependencies, const style::expression::Value&) override { if (patternDependencies->mid.empty()) { // Unlike other propperties with expressions that evaluate to null, the default value for `*-pattern` properties is an empty @@ -475,9 +483,9 @@ public: PaintPropertyBinders(PaintPropertyBinders&&) = default; PaintPropertyBinders(const PaintPropertyBinders&) = delete; - void populateVertexVectors(const GeometryTileFeature& feature, std::size_t length, const ImagePositions& patternPositions, const optional& patternDependencies) { + void populateVertexVectors(const GeometryTileFeature& feature, std::size_t length, const ImagePositions& patternPositions, const optional& patternDependencies, const style::expression::Value& formattedSection = {}) { util::ignore({ - (binders.template get()->populateVertexVector(feature, length, patternPositions, patternDependencies), 0)... + (binders.template get()->populateVertexVector(feature, length, patternPositions, patternDependencies, formattedSection), 0)... }); } -- cgit v1.2.1