diff options
author | Alexander Shalamov <alexander.shalamov@mapbox.com> | 2019-03-13 23:17:14 +0200 |
---|---|---|
committer | Mikhail Pozdnyakov <mikhail.pozdnyakov@mapbox.com> | 2019-03-29 16:18:41 +0200 |
commit | cb64dbe0d63bafd3fda7488be9d8253b480b2ce5 (patch) | |
tree | 6589ed57960ad68f393fde1250c414ef7a873c5f | |
parent | dbbfc4a494c78124ce218a6624ede795456e9ff5 (diff) | |
download | qtlocation-mapboxgl-cb64dbe0d63bafd3fda7488be9d8253b480b2ce5.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 0195506129..d6a7a10368 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 9c00caef84..d640eb74da 100644 --- a/src/mbgl/programs/symbol_program.hpp +++ b/src/mbgl/programs/symbol_program.hpp @@ -367,6 +367,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, @@ -436,6 +437,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 72c641e95a..8375275376 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> @@ -14,6 +15,7 @@ #include <mbgl/style/layers/symbol_layer_impl.hpp> #include <mbgl/gfx/cull_face_mode.hpp> #include <mbgl/layout/symbol_projection.hpp> +#include <mbgl/layout/symbol_layout.hpp> #include <mbgl/util/math.hpp> #include <cmath> @@ -22,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()) { @@ -168,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, @@ -181,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, @@ -193,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, @@ -211,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; @@ -225,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.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, @@ -244,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, diff --git a/src/mbgl/renderer/paint_parameters.hpp b/src/mbgl/renderer/paint_parameters.hpp index 847093166a..cb257a656e 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 |