diff --git a/src/mbgl/programs/symbol_program.hpp b/src/mbgl/programs/symbol_program.hpp index 56477166d8e..2ad446ae2ab 100644 --- a/src/mbgl/programs/symbol_program.hpp +++ b/src/mbgl/programs/symbol_program.hpp @@ -298,6 +298,48 @@ class SymbolProgram : public SymbolProgramBase { return allAttributeBindings.activeCount(); } + template + void draw(gfx::Context& context, + gfx::RenderPass& renderPass, + const DrawMode& drawMode, + const gfx::DepthMode& depthMode, + const gfx::StencilMode& stencilMode, + const gfx::ColorMode& colorMode, + const gfx::CullFaceMode& cullFaceMode, + const gfx::IndexBuffer& indexBuffer, + const Segment& segment, + const UniformValues& uniformValues, + const AttributeBindings& allAttributeBindings, + const TextureBindings& textureBindings, + const std::string& layerID) { + static_assert(Primitive == gfx::PrimitiveTypeOf::value, "incompatible draw mode"); + + if (!program) { + return; + } + + auto drawScopeIt = segment.drawScopes.find(layerID); + if (drawScopeIt == segment.drawScopes.end()) { + drawScopeIt = segment.drawScopes.emplace(layerID, context.createDrawScope()).first; + } + + program->draw( + context, + renderPass, + drawMode, + depthMode, + stencilMode, + colorMode, + cullFaceMode, + uniformValues, + drawScopeIt->second, + allAttributeBindings.offset(segment.vertexOffset), + textureBindings, + indexBuffer, + segment.indexOffset, + segment.indexLength); + } + template void draw(gfx::Context& context, gfx::RenderPass& renderPass, @@ -318,28 +360,20 @@ class SymbolProgram : public SymbolProgramBase { return; } - for (auto& segment : segments) { - auto drawScopeIt = segment.drawScopes.find(layerID); - - if (drawScopeIt == segment.drawScopes.end()) { - drawScopeIt = segment.drawScopes.emplace(layerID, context.createDrawScope()).first; - } - - program->draw( - context, - renderPass, - drawMode, - depthMode, - stencilMode, - colorMode, - cullFaceMode, - uniformValues, - drawScopeIt->second, - allAttributeBindings.offset(segment.vertexOffset), - textureBindings, - indexBuffer, - segment.indexOffset, - segment.indexLength); + for (const auto& segment : segments) { + draw(context, + renderPass, + drawMode, + depthMode, + stencilMode, + colorMode, + cullFaceMode, + indexBuffer, + segment, + uniformValues, + allAttributeBindings, + textureBindings, + layerID); } } }; diff --git a/src/mbgl/renderer/layers/render_symbol_layer.cpp b/src/mbgl/renderer/layers/render_symbol_layer.cpp index 17bb08c0ea6..634e0cf01bf 100644 --- a/src/mbgl/renderer/layers/render_symbol_layer.cpp +++ b/src/mbgl/renderer/layers/render_symbol_layer.cpp @@ -19,11 +19,11 @@ #include #include +#include namespace mbgl { using namespace style; - namespace { Point calculateVariableRenderShift(style::SymbolAnchorType anchor, float width, float height, float radialOffset, float textBoxScale, float renderTextSize) { AnchorAlignment alignment = AnchorAlignment::getAnchorAlignment(anchor); @@ -35,6 +35,277 @@ Point calculateVariableRenderShift(style::SymbolAnchorType anchor, float (shiftY / textBoxScale + offset.y) * renderTextSize ); } + +style::SymbolPropertyValues iconPropertyValues(const style::SymbolPaintProperties::PossiblyEvaluated& evaluated_, + const style::SymbolLayoutProperties::PossiblyEvaluated& layout_) { + return style::SymbolPropertyValues { + layout_.get(), + layout_.get(), + layout_.get(), + evaluated_.get(), + evaluated_.get(), + evaluated_.get().constantOr(Color::black()).a > 0 && + evaluated_.get().constantOr(1), + evaluated_.get().constantOr(Color::black()).a > 0 + }; +} + + +style::SymbolPropertyValues textPropertyValues(const style::SymbolPaintProperties::PossiblyEvaluated& evaluated_, + const style::SymbolLayoutProperties::PossiblyEvaluated& layout_) { + return style::SymbolPropertyValues { + layout_.get(), + layout_.get(), + layout_.get(), + evaluated_.get(), + evaluated_.get(), + evaluated_.get().constantOr(Color::black()).a > 0 && + evaluated_.get().constantOr(1), + evaluated_.get().constantOr(Color::black()).a > 0 + }; +} + +using SegmentWrapper = std::reference_wrapper>; +using SegmentVectorWrapper = std::reference_wrapper>; +using SegmentsWrapper = variant; + +struct RenderableSegment { + RenderableSegment(SegmentWrapper segment_, + const RenderTile& tile_, + SymbolBucket& bucket_, + const SymbolBucket::PaintProperties& bucketPaintProperties_, + float sortKey_) : + segment(std::move(segment_)), + tile(tile_), + bucket(bucket_), + bucketPaintProperties(bucketPaintProperties_), + sortKey(sortKey_) {} + + SegmentWrapper segment; + const RenderTile& tile; + SymbolBucket& bucket; + const SymbolBucket::PaintProperties& bucketPaintProperties; + float sortKey; + + friend bool operator < (const RenderableSegment& lhs, const RenderableSegment& rhs) { + return lhs.sortKey < rhs.sortKey; + } +}; + +template +void drawIcon(const DrawFn& draw, + const RenderTile& tile, + SymbolBucket& bucket, + SegmentsWrapper iconSegments, + const SymbolBucket::PaintProperties& bucketPaintProperties, + const PaintParameters& parameters) { + assert(tile.tile.kind == Tile::Kind::Geometry); + auto& geometryTile = static_cast(tile.tile); + const auto& evaluated_ = bucketPaintProperties.evaluated; + const auto& layout = bucket.layout; + auto values = iconPropertyValues(evaluated_, layout); + const auto& paintPropertyValues = RenderSymbolLayer::iconPaintProperties(evaluated_); + + const bool alongLine = layout.get() != SymbolPlacementType::Point && + layout.get() == AlignmentType::Map; + + if (alongLine) { + reprojectLineLabels(bucket.icon.dynamicVertices, + bucket.icon.placedSymbols, + tile.matrix, + values, + tile, + *bucket.iconSizeBinder, + parameters.state); + + parameters.context.updateVertexBuffer(*bucket.icon.dynamicVertexBuffer, std::move(bucket.icon.dynamicVertices)); + } + + const bool iconScaled = layout.get().constantOr(1.0) != 1.0 || bucket.iconsNeedLinear; + const bool iconTransformed = values.rotationAlignment == AlignmentType::Map || parameters.state.getPitch() != 0; + + const gfx::TextureBinding textureBinding{ geometryTile.iconAtlasTexture->getResource(), + bucket.sdfIcons || + parameters.state.isChanging() || + iconScaled || iconTransformed + ? gfx::TextureFilterType::Linear + : gfx::TextureFilterType::Nearest }; + + const Size iconSize = geometryTile.iconAtlasTexture->size; + + if (bucket.sdfIcons) { + if (values.hasHalo) { + draw(parameters.programs.getSymbolLayerPrograms().symbolIconSDF, + SymbolSDFIconProgram::layoutUniformValues(false, false, values, iconSize, parameters.pixelsToGLUnits, alongLine, tile, parameters.state, parameters.symbolFadeChange, SymbolSDFPart::Halo), + bucket.icon, + iconSegments, + bucket.iconSizeBinder, + values, + bucketPaintProperties.iconBinders, + paintPropertyValues, + SymbolSDFIconProgram::TextureBindings{ + textureBinding + }); + } + + if (values.hasFill) { + draw(parameters.programs.getSymbolLayerPrograms().symbolIconSDF, + SymbolSDFIconProgram::layoutUniformValues(false, false, values, iconSize, parameters.pixelsToGLUnits, alongLine, tile, parameters.state, parameters.symbolFadeChange, SymbolSDFPart::Fill), + bucket.icon, + iconSegments, + bucket.iconSizeBinder, + values, + bucketPaintProperties.iconBinders, + paintPropertyValues, + SymbolSDFIconProgram::TextureBindings{ + textureBinding + }); + } + } else { + draw(parameters.programs.getSymbolLayerPrograms().symbolIcon, + SymbolIconProgram::layoutUniformValues(false, false, values, iconSize, parameters.pixelsToGLUnits, alongLine, tile, parameters.state, parameters.symbolFadeChange), + bucket.icon, + iconSegments, + bucket.iconSizeBinder, + values, + bucketPaintProperties.iconBinders, + paintPropertyValues, + SymbolIconProgram::TextureBindings{ + textureBinding + }); + } +} + +template +void drawText(const DrawFn& draw, + const RenderTile& tile, + SymbolBucket& bucket, + SegmentsWrapper textSegments, + const SymbolBucket::PaintProperties& bucketPaintProperties, + const PaintParameters& parameters) { + assert(tile.tile.kind == Tile::Kind::Geometry); + auto& geometryTile = static_cast(tile.tile); + const auto& evaluated_ = bucketPaintProperties.evaluated; + const auto& layout = bucket.layout; + + const gfx::TextureBinding textureBinding{ geometryTile.glyphAtlasTexture->getResource(), + gfx::TextureFilterType::Linear }; + + auto values = textPropertyValues(evaluated_, layout); + const auto& paintPropertyValues = RenderSymbolLayer::textPaintProperties(evaluated_); + bool hasVariablePacement = false; + + const bool alongLine = layout.get() != SymbolPlacementType::Point && + layout.get() == AlignmentType::Map; + + if (alongLine) { + reprojectLineLabels(bucket.text.dynamicVertices, + bucket.text.placedSymbols, + tile.matrix, + values, + tile, + *bucket.textSizeBinder, + parameters.state); + + parameters.context.updateVertexBuffer(*bucket.text.dynamicVertexBuffer, std::move(bucket.text.dynamicVertices)); + } else if (!layout.get().empty()) { + bucket.text.dynamicVertices.clear(); + + const auto partiallyEvaluatedSize = bucket.textSizeBinder->evaluateForZoom(parameters.state.getZoom()); + const float tileScale = std::pow(2, parameters.state.getZoom() - tile.tile.id.overscaledZ); + const bool rotateWithMap = layout.get() == AlignmentType::Map; + const bool pitchWithMap = layout.get() == AlignmentType::Map; + const float pixelsToTileUnits = tile.id.pixelsToTileUnits(1.0, parameters.state.getZoom()); + const auto labelPlaneMatrix = getLabelPlaneMatrix(tile.matrix, pitchWithMap, rotateWithMap, parameters.state, pixelsToTileUnits); + + for (const PlacedSymbol& symbol : bucket.text.placedSymbols) { + optional variableOffset; + if (!symbol.hidden && symbol.crossTileID != 0u) { + auto it = parameters.variableOffsets.get().find(symbol.crossTileID); + if (it != parameters.variableOffsets.get().end()) { + variableOffset = it->second; + hasVariablePacement |= true; + } + } + + if (!variableOffset) { + // These symbols are from a justification that is not being used, or a label that wasn't placed + // so we don't need to do the extra math to figure out what incremental shift to apply. + hideGlyphs(symbol.glyphOffsets.size(), bucket.text.dynamicVertices); + } else { + const Point tileAnchor = symbol.anchorPoint; + const auto projectedAnchor = project(tileAnchor, pitchWithMap ? tile.matrix : labelPlaneMatrix); + const float perspectiveRatio = 0.5f + 0.5f * (parameters.state.getCameraToCenterDistance() / projectedAnchor.second); + float renderTextSize = evaluateSizeForFeature(partiallyEvaluatedSize, symbol) * perspectiveRatio / util::ONE_EM; + if (pitchWithMap) { + // Go from size in pixels to equivalent size in tile units + renderTextSize *= bucket.tilePixelRatio / tileScale; + } + + auto shift = calculateVariableRenderShift( + (*variableOffset).anchor, + (*variableOffset).width, + (*variableOffset).height, + (*variableOffset).radialOffset, + (*variableOffset).textBoxScale, + renderTextSize); + + // Usual case is that we take the projected anchor and add the pixel-based shift + // calculated above. In the (somewhat weird) case of pitch-aligned text, we add an equivalent + // tile-unit based shift to the anchor before projecting to the label plane. + Point shiftedAnchor; + if (pitchWithMap) { + shiftedAnchor = project(Point(tileAnchor.x + shift.x, tileAnchor.y + shift.y), + labelPlaneMatrix).first; + } else { + if (rotateWithMap) { + auto rotated = util::rotate(shift, -parameters.state.getPitch()); + shiftedAnchor = Point(projectedAnchor.first.x + rotated.x, + projectedAnchor.first.y + rotated.y); + } else { + shiftedAnchor = Point(projectedAnchor.first.x + shift.x, + projectedAnchor.first.y + shift.y); + } + } + + for (std::size_t i = 0; i < symbol.glyphOffsets.size(); i++) { + addDynamicAttributes(shiftedAnchor, 0, bucket.text.dynamicVertices); + } + } + } + parameters.context.updateVertexBuffer(*bucket.text.dynamicVertexBuffer, std::move(bucket.text.dynamicVertices)); + } + + const Size texsize = geometryTile.glyphAtlasTexture->size; + + if (values.hasHalo) { + draw(parameters.programs.getSymbolLayerPrograms().symbolGlyph, + SymbolSDFTextProgram::layoutUniformValues(true, hasVariablePacement, values, texsize, parameters.pixelsToGLUnits, alongLine, tile, parameters.state, parameters.symbolFadeChange, SymbolSDFPart::Halo), + bucket.text, + textSegments, + bucket.textSizeBinder, + values, + bucketPaintProperties.textBinders, + paintPropertyValues, + SymbolSDFTextProgram::TextureBindings{ + textureBinding + }); + } + + if (values.hasFill) { + draw(parameters.programs.getSymbolLayerPrograms().symbolGlyph, + SymbolSDFTextProgram::layoutUniformValues(true, hasVariablePacement, values, texsize, parameters.pixelsToGLUnits, alongLine, tile, parameters.state, parameters.symbolFadeChange, SymbolSDFPart::Fill), + bucket.text, + textSegments, + bucket.textSizeBinder, + values, + bucketPaintProperties.textBinders, + paintPropertyValues, + SymbolSDFTextProgram::TextureBindings{ + textureBinding + }); + } +} } // namespace RenderSymbolLayer::RenderSymbolLayer(Immutable _impl) @@ -92,250 +363,106 @@ void RenderSymbolLayer::render(PaintParameters& parameters, RenderSource*) { return; } + const bool sortFeaturesByKey = !impl().layout.get().isUndefined(); + std::set renderableSegments; + + const auto draw = [¶meters, this] (auto& programInstance, + const auto& uniformValues, + const auto& buffers, + auto& segments, + const auto& symbolSizeBinder, + const SymbolPropertyValues& values_, + const auto& binders, + const auto& paintProperties, + const auto& textureBindings) { + const auto allUniformValues = programInstance.computeAllUniformValues( + uniformValues, + *symbolSizeBinder, + binders, + paintProperties, + parameters.state.getZoom() + ); + + const auto allAttributeBindings = programInstance.computeAllAttributeBindings( + *buffers.vertexBuffer, + *buffers.dynamicVertexBuffer, + *buffers.opacityVertexBuffer, + binders, + paintProperties + ); + + this->checkRenderability(parameters, programInstance.activeBindingCount(allAttributeBindings)); + + segments.match( + [&](const std::reference_wrapper>& segment) { + programInstance.draw( + parameters.context, + *parameters.renderPass, + gfx::Triangles(), + values_.pitchAlignment == AlignmentType::Map + ? parameters.depthModeForSublayer(0, gfx::DepthMaskType::ReadOnly) + : gfx::DepthMode::disabled(), + gfx::StencilMode::disabled(), + parameters.colorModeForRenderPass(), + gfx::CullFaceMode::disabled(), + *buffers.indexBuffer, + segment, + allUniformValues, + allAttributeBindings, + textureBindings, + this->getID() + ); + }, + [&](const std::reference_wrapper>& segmentVector) { + programInstance.draw( + parameters.context, + *parameters.renderPass, + gfx::Triangles(), + values_.pitchAlignment == AlignmentType::Map + ? parameters.depthModeForSublayer(0, gfx::DepthMaskType::ReadOnly) + : gfx::DepthMode::disabled(), + gfx::StencilMode::disabled(), + parameters.colorModeForRenderPass(), + gfx::CullFaceMode::disabled(), + *buffers.indexBuffer, + segmentVector, + allUniformValues, + allAttributeBindings, + textureBindings, + this->getID() + ); + } + ); + }; + for (const RenderTile& tile : renderTiles) { auto bucket_ = tile.tile.getBucket(*baseImpl); if (!bucket_) { continue; } + SymbolBucket& bucket = *bucket_; assert(bucket.paintProperties.find(getID()) != bucket.paintProperties.end()); const auto& bucketPaintProperties = bucket.paintProperties.at(getID()); - const auto& evaluated_ = bucketPaintProperties.evaluated; - const auto& layout = bucket.layout; - - auto draw = [&] (auto& programInstance, - auto&& uniformValues, - const auto& buffers, - const auto& symbolSizeBinder, - const SymbolPropertyValues& values_, - const auto& binders, - const auto& paintProperties, - auto&& textureBindings) { - const auto allUniformValues = programInstance.computeAllUniformValues( - std::move(uniformValues), - *symbolSizeBinder, - binders, - paintProperties, - parameters.state.getZoom() - ); - const auto allAttributeBindings = programInstance.computeAllAttributeBindings( - *buffers.vertexBuffer, - *buffers.dynamicVertexBuffer, - *buffers.opacityVertexBuffer, - binders, - paintProperties - ); - - checkRenderability(parameters, programInstance.activeBindingCount(allAttributeBindings)); - - programInstance.draw( - parameters.context, - *parameters.renderPass, - gfx::Triangles(), - values_.pitchAlignment == AlignmentType::Map - ? parameters.depthModeForSublayer(0, gfx::DepthMaskType::ReadOnly) - : gfx::DepthMode::disabled(), - gfx::StencilMode::disabled(), - parameters.colorModeForRenderPass(), - gfx::CullFaceMode::disabled(), - *buffers.indexBuffer, - buffers.segments, - allUniformValues, - allAttributeBindings, - std::move(textureBindings), - getID() - ); + auto addRenderables = [&renderableSegments, &tile, &bucket, &bucketPaintProperties, it = renderableSegments.begin()] (auto& segments) mutable { + for (auto& segment : segments) { + it = renderableSegments.emplace_hint(it, SegmentWrapper{std::ref(segment)}, tile, bucket, bucketPaintProperties, segment.sortKey); + } }; - assert(tile.tile.kind == Tile::Kind::Geometry); - auto& geometryTile = static_cast(tile.tile); - if (bucket.hasIconData()) { - auto values = iconPropertyValues(evaluated_, layout); - const auto& paintPropertyValues = iconPaintProperties(evaluated_); - - const bool alongLine = layout.get() != SymbolPlacementType::Point && - layout.get() == AlignmentType::Map; - - if (alongLine) { - reprojectLineLabels(bucket.icon.dynamicVertices, - bucket.icon.placedSymbols, - tile.matrix, - values, - tile, - *bucket.iconSizeBinder, - parameters.state); - - parameters.context.updateVertexBuffer(*bucket.icon.dynamicVertexBuffer, std::move(bucket.icon.dynamicVertices)); - } - - const bool iconScaled = layout.get().constantOr(1.0) != 1.0 || bucket.iconsNeedLinear; - const bool iconTransformed = values.rotationAlignment == AlignmentType::Map || parameters.state.getPitch() != 0; - - const gfx::TextureBinding textureBinding{ geometryTile.iconAtlasTexture->getResource(), - bucket.sdfIcons || - parameters.state.isChanging() || - iconScaled || iconTransformed - ? gfx::TextureFilterType::Linear - : gfx::TextureFilterType::Nearest }; - - const Size texsize = geometryTile.iconAtlasTexture->size; - - if (bucket.sdfIcons) { - if (values.hasHalo) { - draw(parameters.programs.getSymbolLayerPrograms().symbolIconSDF, - SymbolSDFIconProgram::layoutUniformValues(false, false, values, texsize, parameters.pixelsToGLUnits, alongLine, tile, parameters.state, parameters.symbolFadeChange, SymbolSDFPart::Halo), - bucket.icon, - bucket.iconSizeBinder, - values, - bucketPaintProperties.iconBinders, - paintPropertyValues, - SymbolSDFIconProgram::TextureBindings{ - textureBinding, - }); - } - - if (values.hasFill) { - draw(parameters.programs.getSymbolLayerPrograms().symbolIconSDF, - SymbolSDFIconProgram::layoutUniformValues(false, false, values, texsize, parameters.pixelsToGLUnits, alongLine, tile, parameters.state, parameters.symbolFadeChange, SymbolSDFPart::Fill), - bucket.icon, - bucket.iconSizeBinder, - values, - bucketPaintProperties.iconBinders, - paintPropertyValues, - SymbolSDFIconProgram::TextureBindings{ - textureBinding, - }); - } + if (sortFeaturesByKey) { + addRenderables(bucket.icon.segments); } else { - draw(parameters.programs.getSymbolLayerPrograms().symbolIcon, - SymbolIconProgram::layoutUniformValues(false, false, values, texsize, parameters.pixelsToGLUnits, alongLine, tile, parameters.state, parameters.symbolFadeChange), - bucket.icon, - bucket.iconSizeBinder, - values, - bucketPaintProperties.iconBinders, - paintPropertyValues, - SymbolIconProgram::TextureBindings{ - textureBinding, - }); + drawIcon(draw, tile, bucket, std::ref(bucket.icon.segments), bucketPaintProperties, parameters); } } if (bucket.hasTextData()) { - const gfx::TextureBinding textureBinding{ geometryTile.glyphAtlasTexture->getResource(), - gfx::TextureFilterType::Linear }; - - auto values = textPropertyValues(evaluated_, layout); - const auto& paintPropertyValues = textPaintProperties(evaluated_); - bool hasVariablePacement = false; - - const bool alongLine = layout.get() != SymbolPlacementType::Point && - layout.get() == AlignmentType::Map; - - if (alongLine) { - reprojectLineLabels(bucket.text.dynamicVertices, - bucket.text.placedSymbols, - tile.matrix, - values, - tile, - *bucket.textSizeBinder, - parameters.state); - - parameters.context.updateVertexBuffer(*bucket.text.dynamicVertexBuffer, std::move(bucket.text.dynamicVertices)); - } else if (!layout.get().empty()) { - bucket.text.dynamicVertices.clear(); - - const auto partiallyEvaluatedSize = bucket.textSizeBinder->evaluateForZoom(parameters.state.getZoom()); - const float tileScale = std::pow(2, parameters.state.getZoom() - tile.tile.id.overscaledZ); - const bool rotateWithMap = layout.get() == AlignmentType::Map; - const bool pitchWithMap = layout.get() == AlignmentType::Map; - const float pixelsToTileUnits = tile.id.pixelsToTileUnits(1.0, parameters.state.getZoom()); - const auto labelPlaneMatrix = getLabelPlaneMatrix(tile.matrix, pitchWithMap, rotateWithMap, parameters.state, pixelsToTileUnits); - - for (const PlacedSymbol& symbol : bucket.text.placedSymbols) { - optional variableOffset; - if (!symbol.hidden && symbol.crossTileID != 0u) { - auto it = parameters.variableOffsets.get().find(symbol.crossTileID); - if (it != parameters.variableOffsets.get().end()) { - variableOffset = it->second; - hasVariablePacement |= true; - } - } - - if (!variableOffset) { - // These symbols are from a justification that is not being used, or a label that wasn't placed - // so we don't need to do the extra math to figure out what incremental shift to apply. - hideGlyphs(symbol.glyphOffsets.size(), bucket.text.dynamicVertices); - } else { - const Point tileAnchor = symbol.anchorPoint; - const auto projectedAnchor = project(tileAnchor, pitchWithMap ? tile.matrix : labelPlaneMatrix); - const float perspectiveRatio = 0.5f + 0.5f * (parameters.state.getCameraToCenterDistance() / projectedAnchor.second); - float renderTextSize = evaluateSizeForFeature(partiallyEvaluatedSize, symbol) * perspectiveRatio / util::ONE_EM; - if (pitchWithMap) { - // Go from size in pixels to equivalent size in tile units - renderTextSize *= bucket.tilePixelRatio / tileScale; - } - - auto shift = calculateVariableRenderShift( - (*variableOffset).anchor, - (*variableOffset).width, - (*variableOffset).height, - (*variableOffset).radialOffset, - (*variableOffset).textBoxScale, - renderTextSize); - - // Usual case is that we take the projected anchor and add the pixel-based shift - // calculated above. In the (somewhat weird) case of pitch-aligned text, we add an equivalent - // tile-unit based shift to the anchor before projecting to the label plane. - Point shiftedAnchor; - if (pitchWithMap) { - shiftedAnchor = project(Point(tileAnchor.x + shift.x, tileAnchor.y + shift.y), - labelPlaneMatrix).first; - } else { - if (rotateWithMap) { - auto rotated = util::rotate(shift, -parameters.state.getPitch()); - shiftedAnchor = Point(projectedAnchor.first.x + rotated.x, - projectedAnchor.first.y + rotated.y); - } else { - shiftedAnchor = Point(projectedAnchor.first.x + shift.x, - projectedAnchor.first.y + shift.y); - } - } - - for (std::size_t i = 0; i < symbol.glyphOffsets.size(); i++) { - addDynamicAttributes(shiftedAnchor, 0, bucket.text.dynamicVertices); - } - } - } - parameters.context.updateVertexBuffer(*bucket.text.dynamicVertexBuffer, std::move(bucket.text.dynamicVertices)); - } - - const Size texsize = geometryTile.glyphAtlasTexture->size; - - if (values.hasHalo) { - draw(parameters.programs.getSymbolLayerPrograms().symbolGlyph, - SymbolSDFTextProgram::layoutUniformValues(true, hasVariablePacement, values, texsize, parameters.pixelsToGLUnits, alongLine, tile, parameters.state, parameters.symbolFadeChange, SymbolSDFPart::Halo), - bucket.text, - bucket.textSizeBinder, - values, - bucketPaintProperties.textBinders, - paintPropertyValues, - SymbolSDFTextProgram::TextureBindings{ - textureBinding, - }); - } - - if (values.hasFill) { - draw(parameters.programs.getSymbolLayerPrograms().symbolGlyph, - SymbolSDFTextProgram::layoutUniformValues(true, hasVariablePacement, values, texsize, parameters.pixelsToGLUnits, alongLine, tile, parameters.state, parameters.symbolFadeChange, SymbolSDFPart::Fill), - bucket.text, - bucket.textSizeBinder, - values, - bucketPaintProperties.textBinders, - paintPropertyValues, - SymbolSDFTextProgram::TextureBindings{ - textureBinding, - }); + if (sortFeaturesByKey) { + addRenderables(bucket.text.segments); + } else { + drawText(draw, tile, bucket, std::ref(bucket.text.segments), bucketPaintProperties, parameters); } } @@ -375,6 +502,7 @@ void RenderSymbolLayer::render(PaintParameters& parameters, RenderSource*) { getID() ); } + if (bucket.hasCollisionCircleData()) { static const style::Properties<>::PossiblyEvaluated properties {}; static const CollisionBoxProgram::Binders paintAttributeData(properties, 0); @@ -412,7 +540,16 @@ void RenderSymbolLayer::render(PaintParameters& parameters, RenderSource*) { parameters.state.getZoom(), getID() ); + } + } + if (sortFeaturesByKey) { + for (auto& renderable : renderableSegments) { + if (renderable.bucket.hasIconData()) { + drawIcon(draw, renderable.tile, renderable.bucket, renderable.segment, renderable.bucketPaintProperties, parameters); + } else { + drawText(draw, renderable.tile, renderable.bucket, renderable.segment, renderable.bucketPaintProperties, parameters); + } } } } @@ -443,36 +580,6 @@ style::TextPaintProperties::PossiblyEvaluated RenderSymbolLayer::textPaintProper }; } -// static -style::SymbolPropertyValues RenderSymbolLayer::iconPropertyValues(const style::SymbolPaintProperties::PossiblyEvaluated& evaluated_, - const style::SymbolLayoutProperties::PossiblyEvaluated& layout_) { - return style::SymbolPropertyValues { - layout_.get(), - layout_.get(), - layout_.get(), - evaluated_.get(), - evaluated_.get(), - evaluated_.get().constantOr(Color::black()).a > 0 && - evaluated_.get().constantOr(1), - evaluated_.get().constantOr(Color::black()).a > 0 - }; -} - -// static -style::SymbolPropertyValues RenderSymbolLayer::textPropertyValues(const style::SymbolPaintProperties::PossiblyEvaluated& evaluated_, - const style::SymbolLayoutProperties::PossiblyEvaluated& layout_) { - return style::SymbolPropertyValues { - layout_.get(), - layout_.get(), - layout_.get(), - evaluated_.get(), - evaluated_.get(), - evaluated_.get().constantOr(Color::black()).a > 0 && - evaluated_.get().constantOr(1), - evaluated_.get().constantOr(Color::black()).a > 0 - }; -} - void RenderSymbolLayer::setRenderTiles(RenderTiles tiles, const TransformState& state) { auto filterFn = [](auto& tile){ return !tile.tile.isRenderable(); }; renderTiles = RenderLayer::filterRenderTiles(std::move(tiles), filterFn); diff --git a/src/mbgl/renderer/layers/render_symbol_layer.hpp b/src/mbgl/renderer/layers/render_symbol_layer.hpp index 4de5c8538a7..7b6d249b2eb 100644 --- a/src/mbgl/renderer/layers/render_symbol_layer.hpp +++ b/src/mbgl/renderer/layers/render_symbol_layer.hpp @@ -88,10 +88,6 @@ class RenderSymbolLayer final: public RenderLayer, public RenderLayerSymbolInter const style::SymbolLayer::Impl& impl() const; protected: - static style::SymbolPropertyValues iconPropertyValues(const style::SymbolPaintProperties::PossiblyEvaluated&, - const style::SymbolLayoutProperties::PossiblyEvaluated&); - static style::SymbolPropertyValues textPropertyValues(const style::SymbolPaintProperties::PossiblyEvaluated&, - const style::SymbolLayoutProperties::PossiblyEvaluated&); void updateBucketPaintProperties(Bucket*) const final; };