summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorAlexander Shalamov <alexander.shalamov@mapbox.com>2019-03-13 23:17:14 +0200
committerMikhail Pozdnyakov <mikhail.pozdnyakov@mapbox.com>2019-04-01 20:42:09 +0300
commit3e6ab2236affbdf7d3e0cb892e504bad3c92c586 (patch)
tree59cad25140125cfb0703c672f804de9e9d9f7bce
parent872789945743f61fc56ca5495e291a2b0651799f (diff)
downloadqtlocation-mapboxgl-3e6ab2236affbdf7d3e0cb892e504bad3c92c586.tar.gz
[core] Introduce variable text placement for point labels - Render part
-rw-r--r--src/mbgl/programs/symbol_program.cpp7
-rw-r--r--src/mbgl/programs/symbol_program.hpp2
-rw-r--r--src/mbgl/renderer/layers/render_symbol_layer.cpp92
-rw-r--r--src/mbgl/renderer/paint_parameters.hpp2
-rw-r--r--src/mbgl/text/placement.hpp6
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