diff options
author | Alexander Shalamov <alexander.shalamov@mapbox.com> | 2019-03-13 23:17:14 +0200 |
---|---|---|
committer | Mikhail Pozdnyakov <mikhail.pozdnyakov@mapbox.com> | 2019-04-01 20:42:09 +0300 |
commit | 3e6ab2236affbdf7d3e0cb892e504bad3c92c586 (patch) | |
tree | 59cad25140125cfb0703c672f804de9e9d9f7bce | |
parent | 872789945743f61fc56ca5495e291a2b0651799f (diff) | |
download | qtlocation-mapboxgl-3e6ab2236affbdf7d3e0cb892e504bad3c92c586.tar.gz |
[core] Introduce variable text placement for point labels - Render part
-rw-r--r-- | src/mbgl/programs/symbol_program.cpp | 7 | ||||
-rw-r--r-- | src/mbgl/programs/symbol_program.hpp | 2 | ||||
-rw-r--r-- | src/mbgl/renderer/layers/render_symbol_layer.cpp | 92 | ||||
-rw-r--r-- | src/mbgl/renderer/paint_parameters.hpp | 2 | ||||
-rw-r--r-- | src/mbgl/text/placement.hpp | 6 |
5 files changed, 103 insertions, 6 deletions
diff --git a/src/mbgl/programs/symbol_program.cpp b/src/mbgl/programs/symbol_program.cpp index 2300dedff3..43eae19cde 100644 --- a/src/mbgl/programs/symbol_program.cpp +++ b/src/mbgl/programs/symbol_program.cpp @@ -42,6 +42,7 @@ std::unique_ptr<SymbolSizeBinder> SymbolSizeBinder::create(const float tileZoom, template <class Values, class...Args> Values makeValues(const bool isText, + const bool hasVariablePacement, const style::SymbolPropertyValues& values, const Size& texsize, const std::array<float, 2>& pixelsToGLUnits, @@ -71,7 +72,7 @@ Values makeValues(const bool isText, const bool rotateInShader = rotateWithMap && !pitchWithMap && !alongLine; mat4 labelPlaneMatrix; - if (alongLine) { + if (alongLine || (isText && hasVariablePacement)) { // For labels that follow lines the first part of the projection is handled on the cpu. // Pass an identity matrix because no transformation needs to be done in the vertex shader. matrix::identity(labelPlaneMatrix); @@ -106,6 +107,7 @@ Values makeValues(const bool isText, SymbolIconProgram::LayoutUniformValues SymbolIconProgram::layoutUniformValues(const bool isText, + const bool hasVariablePacement, const style::SymbolPropertyValues& values, const Size& texsize, const std::array<float, 2>& pixelsToGLUnits, @@ -115,6 +117,7 @@ SymbolIconProgram::layoutUniformValues(const bool isText, const float symbolFadeChange) { return makeValues<SymbolIconProgram::LayoutUniformValues>( isText, + hasVariablePacement, values, texsize, pixelsToGLUnits, @@ -128,6 +131,7 @@ SymbolIconProgram::layoutUniformValues(const bool isText, template <class Name, class PaintProperties> typename SymbolSDFProgram<Name, PaintProperties>::LayoutUniformValues SymbolSDFProgram<Name, PaintProperties>::layoutUniformValues(const bool isText, + const bool hasVariablePacement, const style::SymbolPropertyValues& values, const Size& texsize, const std::array<float, 2>& pixelsToGLUnits, @@ -142,6 +146,7 @@ SymbolSDFProgram<Name, PaintProperties>::layoutUniformValues(const bool isText, return makeValues<SymbolSDFProgram<Name, PaintProperties>::LayoutUniformValues>( isText, + hasVariablePacement, values, texsize, pixelsToGLUnits, diff --git a/src/mbgl/programs/symbol_program.hpp b/src/mbgl/programs/symbol_program.hpp index 383f5162d8..14290fe348 100644 --- a/src/mbgl/programs/symbol_program.hpp +++ b/src/mbgl/programs/symbol_program.hpp @@ -368,6 +368,7 @@ public: using SymbolProgram::SymbolProgram; static LayoutUniformValues layoutUniformValues(const bool isText, + const bool hasVariablePacement, const style::SymbolPropertyValues&, const Size& texsize, const std::array<float, 2>& pixelsToGLUnits, @@ -437,6 +438,7 @@ public: using BaseProgram::BaseProgram; static LayoutUniformValues layoutUniformValues(const bool isText, + const bool hasVariablePacement, const style::SymbolPropertyValues&, const Size& texsize, const std::array<float, 2>& pixelsToGLUnits, diff --git a/src/mbgl/renderer/layers/render_symbol_layer.cpp b/src/mbgl/renderer/layers/render_symbol_layer.cpp index 31d92dd414..ef18a21005 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> @@ -15,6 +16,7 @@ #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 +25,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()) { @@ -172,7 +187,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 +200,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 +212,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 +230,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 +245,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.find(symbol.crossTileID); + if (it != parameters.variableOffsets.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 +330,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, diff --git a/src/mbgl/renderer/paint_parameters.hpp b/src/mbgl/renderer/paint_parameters.hpp index ea3b41adfe..0b729d102b 100644 --- a/src/mbgl/renderer/paint_parameters.hpp +++ b/src/mbgl/renderer/paint_parameters.hpp @@ -9,6 +9,7 @@ #include <mbgl/gfx/color_mode.hpp> #include <mbgl/util/mat4.hpp> #include <mbgl/algorithm/generate_clip_ids.hpp> +#include <mbgl/text/placement.hpp> #include <array> @@ -56,6 +57,7 @@ public: TimePoint timePoint; float pixelRatio; + std::unordered_map<uint32_t, VariableOffset> variableOffsets; std::array<float, 2> pixelsToGLUnits; algorithm::ClipIDGenerator clipIDGenerator; diff --git a/src/mbgl/text/placement.hpp b/src/mbgl/text/placement.hpp index 32310f723e..673ea59c24 100644 --- a/src/mbgl/text/placement.hpp +++ b/src/mbgl/text/placement.hpp @@ -138,4 +138,10 @@ private: CollisionGroups collisionGroups; }; +Point<float> calculateVariableLayoutOffset(style::SymbolAnchorType anchor, + float width, + float height, + float radialOffset, + float textBoxScale); + } // namespace mbgl |