diff options
Diffstat (limited to 'src/mbgl/renderer/layers/render_symbol_layer.cpp')
-rw-r--r-- | src/mbgl/renderer/layers/render_symbol_layer.cpp | 121 |
1 files changed, 98 insertions, 23 deletions
diff --git a/src/mbgl/renderer/layers/render_symbol_layer.cpp b/src/mbgl/renderer/layers/render_symbol_layer.cpp index 31d92dd414..d7951c647a 100644 --- a/src/mbgl/renderer/layers/render_symbol_layer.cpp +++ b/src/mbgl/renderer/layers/render_symbol_layer.cpp @@ -5,6 +5,7 @@ #include <mbgl/renderer/render_tile.hpp> #include <mbgl/renderer/paint_parameters.hpp> #include <mbgl/text/glyph_atlas.hpp> +#include <mbgl/text/shaping.hpp> #include <mbgl/programs/programs.hpp> #include <mbgl/programs/symbol_program.hpp> #include <mbgl/programs/collision_box_program.hpp> @@ -13,8 +14,8 @@ #include <mbgl/tile/geometry_tile_data.hpp> #include <mbgl/style/layers/symbol_layer_impl.hpp> #include <mbgl/gfx/cull_face_mode.hpp> -#include <mbgl/gl/context.hpp> #include <mbgl/layout/symbol_projection.hpp> +#include <mbgl/layout/symbol_layout.hpp> #include <mbgl/util/math.hpp> #include <cmath> @@ -23,6 +24,19 @@ 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); + float shiftX = -(alignment.horizontalAlign - 0.5f) * width; + float shiftY = -(alignment.verticalAlign - 0.5f) * height; + Point<float> offset = SymbolLayout::evaluateRadialOffset(anchor, radialOffset); + return Point<float>( + (shiftX / textBoxScale + offset.x) * renderTextSize, + (shiftY / textBoxScale + offset.y) * renderTextSize + ); +} +} // namespace + RenderSymbolLayer::RenderSymbolLayer(Immutable<style::SymbolLayer::Impl> _impl) : RenderLayer(std::move(_impl)), unevaluated(impl().paint.untransitioned()) { @@ -89,17 +103,14 @@ void RenderSymbolLayer::render(PaintParameters& parameters, RenderSource*) { const auto& evaluated_ = bucketPaintProperties.evaluated; const auto& layout = bucket.layout; - auto draw = [&] (auto& program, + auto draw = [&] (auto& programInstance, auto&& uniformValues, const auto& buffers, const auto& symbolSizeBinder, const SymbolPropertyValues& values_, const auto& binders, const auto& paintProperties, - auto&& textureBindings) - { - auto& programInstance = program.get(paintProperties); - + auto&& textureBindings) { const auto allUniformValues = programInstance.computeAllUniformValues( std::move(uniformValues), *symbolSizeBinder, @@ -172,7 +183,7 @@ void RenderSymbolLayer::render(PaintParameters& parameters, RenderSource*) { if (bucket.sdfIcons) { if (values.hasHalo) { draw(parameters.programs.getSymbolLayerPrograms().symbolIconSDF, - SymbolSDFIconProgram::layoutUniformValues(false, values, texsize, parameters.pixelsToGLUnits, alongLine, tile, parameters.state, parameters.symbolFadeChange, SymbolSDFPart::Halo), + SymbolSDFIconProgram::layoutUniformValues(false, false, values, texsize, parameters.pixelsToGLUnits, alongLine, tile, parameters.state, parameters.symbolFadeChange, SymbolSDFPart::Halo), bucket.icon, bucket.iconSizeBinder, values, @@ -185,7 +196,7 @@ void RenderSymbolLayer::render(PaintParameters& parameters, RenderSource*) { if (values.hasFill) { draw(parameters.programs.getSymbolLayerPrograms().symbolIconSDF, - SymbolSDFIconProgram::layoutUniformValues(false, values, texsize, parameters.pixelsToGLUnits, alongLine, tile, parameters.state, parameters.symbolFadeChange, SymbolSDFPart::Fill), + SymbolSDFIconProgram::layoutUniformValues(false, false, values, texsize, parameters.pixelsToGLUnits, alongLine, tile, parameters.state, parameters.symbolFadeChange, SymbolSDFPart::Fill), bucket.icon, bucket.iconSizeBinder, values, @@ -197,7 +208,7 @@ void RenderSymbolLayer::render(PaintParameters& parameters, RenderSource*) { } } else { draw(parameters.programs.getSymbolLayerPrograms().symbolIcon, - SymbolIconProgram::layoutUniformValues(false, values, texsize, parameters.pixelsToGLUnits, alongLine, tile, parameters.state, parameters.symbolFadeChange), + SymbolIconProgram::layoutUniformValues(false, false, values, texsize, parameters.pixelsToGLUnits, alongLine, tile, parameters.state, parameters.symbolFadeChange), bucket.icon, bucket.iconSizeBinder, values, @@ -215,6 +226,7 @@ void RenderSymbolLayer::render(PaintParameters& parameters, RenderSource*) { 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; @@ -229,13 +241,79 @@ void RenderSymbolLayer::render(PaintParameters& parameters, RenderSource*) { 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, values, texsize, parameters.pixelsToGLUnits, alongLine, tile, parameters.state, parameters.symbolFadeChange, SymbolSDFPart::Halo), + SymbolSDFTextProgram::layoutUniformValues(true, hasVariablePacement, values, texsize, parameters.pixelsToGLUnits, alongLine, tile, parameters.state, parameters.symbolFadeChange, SymbolSDFPart::Halo), bucket.text, bucket.textSizeBinder, values, @@ -248,7 +326,7 @@ void RenderSymbolLayer::render(PaintParameters& parameters, RenderSource*) { if (values.hasFill) { draw(parameters.programs.getSymbolLayerPrograms().symbolGlyph, - SymbolSDFTextProgram::layoutUniformValues(true, values, texsize, parameters.pixelsToGLUnits, alongLine, tile, parameters.state, parameters.symbolFadeChange, SymbolSDFPart::Fill), + SymbolSDFTextProgram::layoutUniformValues(true, hasVariablePacement, values, texsize, parameters.pixelsToGLUnits, alongLine, tile, parameters.state, parameters.symbolFadeChange, SymbolSDFPart::Fill), bucket.text, bucket.textSizeBinder, values, @@ -280,9 +358,9 @@ void RenderSymbolLayer::render(PaintParameters& parameters, RenderSource*) { parameters.colorModeForRenderPass(), gfx::CullFaceMode::disabled(), CollisionBoxProgram::LayoutUniformValues { - uniforms::u_matrix::Value( tile.matrix ), - uniforms::u_extrude_scale::Value( extrudeScale ), - uniforms::u_camera_to_center_distance::Value( parameters.state.getCameraToCenterDistance() ) + uniforms::matrix::Value( tile.matrix ), + uniforms::extrude_scale::Value( extrudeScale ), + uniforms::camera_to_center_distance::Value( parameters.state.getCameraToCenterDistance() ) }, *bucket.collisionBox.vertexBuffer, *bucket.collisionBox.dynamicVertexBuffer, @@ -316,10 +394,10 @@ void RenderSymbolLayer::render(PaintParameters& parameters, RenderSource*) { parameters.colorModeForRenderPass(), gfx::CullFaceMode::disabled(), CollisionCircleProgram::LayoutUniformValues { - uniforms::u_matrix::Value( tile.matrix ), - uniforms::u_extrude_scale::Value( extrudeScale ), - uniforms::u_overscale_factor::Value( float(tile.tile.id.overscaleFactor()) ), - uniforms::u_camera_to_center_distance::Value( parameters.state.getCameraToCenterDistance() ) + uniforms::matrix::Value( tile.matrix ), + uniforms::extrude_scale::Value( extrudeScale ), + uniforms::overscale_factor::Value( float(tile.tile.id.overscaleFactor()) ), + uniforms::camera_to_center_distance::Value( parameters.state.getCameraToCenterDistance() ) }, *bucket.collisionCircle.vertexBuffer, *bucket.collisionCircle.dynamicVertexBuffer, @@ -392,12 +470,9 @@ style::SymbolPropertyValues RenderSymbolLayer::textPropertyValues(const style::S }; } -RenderLayer::RenderTiles RenderSymbolLayer::filterRenderTiles(RenderTiles tiles) const { +void RenderSymbolLayer::setRenderTiles(RenderTiles tiles, const TransformState& state) { auto filterFn = [](auto& tile){ return !tile.tile.isRenderable(); }; - return RenderLayer::filterRenderTiles(std::move(tiles), filterFn); -} - -void RenderSymbolLayer::sortRenderTiles(const TransformState& state) { + renderTiles = RenderLayer::filterRenderTiles(std::move(tiles), filterFn); // Sort symbol tiles in opposite y position, so tiles with overlapping symbols are drawn // on top of each other, with lower symbols being drawn on top of higher symbols. std::sort(renderTiles.begin(), renderTiles.end(), [&state](const auto& a, const auto& b) { |