summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorAlexander Shalamov <alexander.shalamov@mapbox.com>2019-04-10 11:57:11 +0300
committerAlexander Shalamov <alexander.shalamov@mapbox.com>2019-04-17 15:04:08 +0300
commit113e96e03c1ad923f481f9215f6cac83451263ef (patch)
treeccf1ba7529a8e3a711d596678e658f15b35293ec
parent2a169b07e8d47dec018c2429bcfcb1e6ff0a4ead (diff)
downloadqtlocation-mapboxgl-113e96e03c1ad923f481f9215f6cac83451263ef.tar.gz
[core] Sort cross-tile symbol segments using symbol-sort-key
-rw-r--r--src/mbgl/programs/symbol_program.hpp78
-rw-r--r--src/mbgl/renderer/layers/render_symbol_layer.cpp625
-rw-r--r--src/mbgl/renderer/layers/render_symbol_layer.hpp4
3 files changed, 422 insertions, 285 deletions
diff --git a/src/mbgl/programs/symbol_program.hpp b/src/mbgl/programs/symbol_program.hpp
index 56477166d8..2ad446ae2a 100644
--- a/src/mbgl/programs/symbol_program.hpp
+++ b/src/mbgl/programs/symbol_program.hpp
@@ -307,6 +307,48 @@ public:
const gfx::ColorMode& colorMode,
const gfx::CullFaceMode& cullFaceMode,
const gfx::IndexBuffer& indexBuffer,
+ const Segment<AttributeList>& segment,
+ const UniformValues& uniformValues,
+ const AttributeBindings& allAttributeBindings,
+ const TextureBindings& textureBindings,
+ const std::string& layerID) {
+ static_assert(Primitive == gfx::PrimitiveTypeOf<DrawMode>::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 <class DrawMode>
+ 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 SegmentVector<AttributeList>& segments,
const UniformValues& uniformValues,
const AttributeBindings& allAttributeBindings,
@@ -318,28 +360,20 @@ public:
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 17bb08c0ea..634e0cf01b 100644
--- a/src/mbgl/renderer/layers/render_symbol_layer.cpp
+++ b/src/mbgl/renderer/layers/render_symbol_layer.cpp
@@ -19,11 +19,11 @@
#include <mbgl/util/math.hpp>
#include <cmath>
+#include <set>
namespace mbgl {
using namespace style;
-
namespace {
Point<float> calculateVariableRenderShift(style::SymbolAnchorType anchor, float width, float height, float radialOffset, float textBoxScale, float renderTextSize) {
AnchorAlignment alignment = AnchorAlignment::getAnchorAlignment(anchor);
@@ -35,6 +35,277 @@ Point<float> 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<style::IconPitchAlignment>(),
+ layout_.get<style::IconRotationAlignment>(),
+ layout_.get<style::IconKeepUpright>(),
+ evaluated_.get<style::IconTranslate>(),
+ evaluated_.get<style::IconTranslateAnchor>(),
+ evaluated_.get<style::IconHaloColor>().constantOr(Color::black()).a > 0 &&
+ evaluated_.get<style::IconHaloWidth>().constantOr(1),
+ evaluated_.get<style::IconColor>().constantOr(Color::black()).a > 0
+ };
+}
+
+
+style::SymbolPropertyValues textPropertyValues(const style::SymbolPaintProperties::PossiblyEvaluated& evaluated_,
+ const style::SymbolLayoutProperties::PossiblyEvaluated& layout_) {
+ return style::SymbolPropertyValues {
+ layout_.get<style::TextPitchAlignment>(),
+ layout_.get<style::TextRotationAlignment>(),
+ layout_.get<style::TextKeepUpright>(),
+ evaluated_.get<style::TextTranslate>(),
+ evaluated_.get<style::TextTranslateAnchor>(),
+ evaluated_.get<style::TextHaloColor>().constantOr(Color::black()).a > 0 &&
+ evaluated_.get<style::TextHaloWidth>().constantOr(1),
+ evaluated_.get<style::TextColor>().constantOr(Color::black()).a > 0
+ };
+}
+
+using SegmentWrapper = std::reference_wrapper<Segment<SymbolTextAttributes>>;
+using SegmentVectorWrapper = std::reference_wrapper<SegmentVector<SymbolTextAttributes>>;
+using SegmentsWrapper = variant<SegmentWrapper, SegmentVectorWrapper>;
+
+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 <typename DrawFn>
+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<GeometryTile&>(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<SymbolPlacement>() != SymbolPlacementType::Point &&
+ layout.get<IconRotationAlignment>() == 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<IconSize>().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 <typename DrawFn>
+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<GeometryTile&>(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<SymbolPlacement>() != SymbolPlacementType::Point &&
+ layout.get<TextRotationAlignment>() == 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<TextVariableAnchor>().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<TextRotationAlignment>() == AlignmentType::Map;
+ const bool pitchWithMap = layout.get<TextPitchAlignment>() == 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> 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<float> 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<float> shiftedAnchor;
+ if (pitchWithMap) {
+ shiftedAnchor = project(Point<float>(tileAnchor.x + shift.x, tileAnchor.y + shift.y),
+ labelPlaneMatrix).first;
+ } else {
+ if (rotateWithMap) {
+ auto rotated = util::rotate(shift, -parameters.state.getPitch());
+ shiftedAnchor = Point<float>(projectedAnchor.first.x + rotated.x,
+ projectedAnchor.first.y + rotated.y);
+ } else {
+ shiftedAnchor = Point<float>(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<style::SymbolLayer::Impl> _impl)
@@ -92,250 +363,106 @@ void RenderSymbolLayer::render(PaintParameters& parameters, RenderSource*) {
return;
}
+ const bool sortFeaturesByKey = !impl().layout.get<SymbolSortKey>().isUndefined();
+ std::set<RenderableSegment> renderableSegments;
+
+ const auto draw = [&parameters, 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<SymbolTextAttributes>>& 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<SymbolTextAttributes>>& 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<SymbolBucket>(*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<GeometryTile&>(tile.tile);
-
if (bucket.hasIconData()) {
- auto values = iconPropertyValues(evaluated_, layout);
- const auto& paintPropertyValues = iconPaintProperties(evaluated_);
-
- const bool alongLine = layout.get<SymbolPlacement>() != SymbolPlacementType::Point &&
- layout.get<IconRotationAlignment>() == 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<IconSize>().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<SymbolPlacement>() != SymbolPlacementType::Point &&
- layout.get<TextRotationAlignment>() == 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<TextVariableAnchor>().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<TextRotationAlignment>() == AlignmentType::Map;
- const bool pitchWithMap = layout.get<TextPitchAlignment>() == 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> 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<float> 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<float> shiftedAnchor;
- if (pitchWithMap) {
- shiftedAnchor = project(Point<float>(tileAnchor.x + shift.x, tileAnchor.y + shift.y),
- labelPlaneMatrix).first;
- } else {
- if (rotateWithMap) {
- auto rotated = util::rotate(shift, -parameters.state.getPitch());
- shiftedAnchor = Point<float>(projectedAnchor.first.x + rotated.x,
- projectedAnchor.first.y + rotated.y);
- } else {
- shiftedAnchor = Point<float>(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<style::IconPitchAlignment>(),
- layout_.get<style::IconRotationAlignment>(),
- layout_.get<style::IconKeepUpright>(),
- evaluated_.get<style::IconTranslate>(),
- evaluated_.get<style::IconTranslateAnchor>(),
- evaluated_.get<style::IconHaloColor>().constantOr(Color::black()).a > 0 &&
- evaluated_.get<style::IconHaloWidth>().constantOr(1),
- evaluated_.get<style::IconColor>().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<style::TextPitchAlignment>(),
- layout_.get<style::TextRotationAlignment>(),
- layout_.get<style::TextKeepUpright>(),
- evaluated_.get<style::TextTranslate>(),
- evaluated_.get<style::TextTranslateAnchor>(),
- evaluated_.get<style::TextHaloColor>().constantOr(Color::black()).a > 0 &&
- evaluated_.get<style::TextHaloWidth>().constantOr(1),
- evaluated_.get<style::TextColor>().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 4de5c8538a..7b6d249b2e 100644
--- a/src/mbgl/renderer/layers/render_symbol_layer.hpp
+++ b/src/mbgl/renderer/layers/render_symbol_layer.hpp
@@ -88,10 +88,6 @@ public:
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;
};