summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorMikhail Pozdnyakov <mikhail.pozdnyakov@mapbox.com>2019-05-22 16:41:40 +0300
committerMikhail Pozdnyakov <mikhail.pozdnyakov@mapbox.com>2019-05-24 10:54:06 +0300
commitaa3a7cf02f2b5d0b99bec9d335c9681dcfa38426 (patch)
tree08d9826c1b419960a1e7a03b6fefb6d21aeab923
parentd8e9acd0f510a811f5c1fa87738be646ff83b715 (diff)
downloadqtlocation-mapboxgl-aa3a7cf02f2b5d0b99bec9d335c9681dcfa38426.tar.gz
[core] SymbolBucket updates complete at placement stage
`RenderSymbolLayer` does not have to update dynamic vertices of its buckets, this logic is moved to placement (which is already updates opacity vertices). * fixes clustering of labels when text variable placement enabled - as assignes `usesVariablePlacement` per bucket * simplifies the code in `RenderSymbolLayer` (the `RenderSymbolLayer::upload()` is now omitted). * symbol buckets are not modified after orchestration finishes
-rw-r--r--src/mbgl/layout/symbol_projection.cpp12
-rw-r--r--src/mbgl/layout/symbol_projection.hpp2
-rw-r--r--src/mbgl/renderer/bucket.hpp3
-rw-r--r--src/mbgl/renderer/buckets/symbol_bucket.cpp33
-rw-r--r--src/mbgl/renderer/buckets/symbol_bucket.hpp5
-rw-r--r--src/mbgl/renderer/layers/render_symbol_layer.cpp157
-rw-r--r--src/mbgl/renderer/layers/render_symbol_layer.hpp2
-rw-r--r--src/mbgl/renderer/renderer_impl.cpp7
-rw-r--r--src/mbgl/renderer/upload_parameters.hpp5
-rw-r--r--src/mbgl/text/placement.cpp105
-rw-r--r--src/mbgl/text/placement.hpp6
11 files changed, 143 insertions, 194 deletions
diff --git a/src/mbgl/layout/symbol_projection.cpp b/src/mbgl/layout/symbol_projection.cpp
index b7858f8deb..a58d90d4cf 100644
--- a/src/mbgl/layout/symbol_projection.cpp
+++ b/src/mbgl/layout/symbol_projection.cpp
@@ -361,15 +361,13 @@ namespace mbgl {
void reprojectLineLabels(gfx::VertexVector<gfx::Vertex<SymbolDynamicLayoutAttributes>>& dynamicVertexArray, const std::vector<PlacedSymbol>& placedSymbols,
- const mat4& posMatrix, const style::SymbolPropertyValues& values,
+ const mat4& posMatrix, bool pitchWithMap, bool rotateWithMap, bool keepUpright,
const RenderTile& tile, const SymbolSizeBinder& sizeBinder, const TransformState& state) {
const ZoomEvaluatedSize partiallyEvaluatedSize = sizeBinder.evaluateForZoom(state.getZoom());
const std::array<double, 2> clippingBuffer = {{ 256.0 / state.getSize().width * 2.0 + 1.0, 256.0 / state.getSize().height * 2.0 + 1.0 }};
-
- const bool pitchWithMap = values.pitchAlignment == style::AlignmentType::Map;
- const bool rotateWithMap = values.rotationAlignment == style::AlignmentType::Map;
+
const float pixelsToTileUnits = tile.id.pixelsToTileUnits(1, state.getZoom());
const mat4 labelPlaneMatrix = getLabelPlaneMatrix(posMatrix, pitchWithMap,
@@ -405,19 +403,19 @@ namespace mbgl {
const float perspectiveRatio = 0.5 + 0.5 * (cameraToAnchorDistance / state.getCameraToCenterDistance());
const float fontSize = evaluateSizeForFeature(partiallyEvaluatedSize, placedSymbol);
- const float pitchScaledFontSize = values.pitchAlignment == style::AlignmentType::Map ?
+ const float pitchScaledFontSize = pitchWithMap ?
fontSize * perspectiveRatio :
fontSize / perspectiveRatio;
const Point<float> anchorPoint = project(placedSymbol.anchorPoint, labelPlaneMatrix).first;
- PlacementResult placeUnflipped = placeGlyphsAlongLine(placedSymbol, pitchScaledFontSize, false /*unflipped*/, values.keepUpright, posMatrix, labelPlaneMatrix, glCoordMatrix, dynamicVertexArray, anchorPoint, state.getSize().aspectRatio());
+ PlacementResult placeUnflipped = placeGlyphsAlongLine(placedSymbol, pitchScaledFontSize, false /*unflipped*/, keepUpright, posMatrix, labelPlaneMatrix, glCoordMatrix, dynamicVertexArray, anchorPoint, state.getSize().aspectRatio());
useVertical = placeUnflipped == PlacementResult::UseVertical;
if (placeUnflipped == PlacementResult::NotEnoughRoom || useVertical ||
(placeUnflipped == PlacementResult::NeedsFlipping &&
- placeGlyphsAlongLine(placedSymbol, pitchScaledFontSize, true /*flipped*/, values.keepUpright, posMatrix, labelPlaneMatrix, glCoordMatrix, dynamicVertexArray, anchorPoint, state.getSize().aspectRatio()) == PlacementResult::NotEnoughRoom)) {
+ placeGlyphsAlongLine(placedSymbol, pitchScaledFontSize, true /*flipped*/, keepUpright, posMatrix, labelPlaneMatrix, glCoordMatrix, dynamicVertexArray, anchorPoint, state.getSize().aspectRatio()) == PlacementResult::NotEnoughRoom)) {
hideGlyphs(placedSymbol.glyphOffsets.size(), dynamicVertexArray);
}
}
diff --git a/src/mbgl/layout/symbol_projection.hpp b/src/mbgl/layout/symbol_projection.hpp
index 3699eee290..58c635eaae 100644
--- a/src/mbgl/layout/symbol_projection.hpp
+++ b/src/mbgl/layout/symbol_projection.hpp
@@ -47,7 +47,7 @@ namespace mbgl {
PointAndCameraDistance project(const Point<float>& point, const mat4& matrix);
void reprojectLineLabels(gfx::VertexVector<gfx::Vertex<SymbolDynamicLayoutAttributes>>&, const std::vector<PlacedSymbol>&,
- const mat4& posMatrix, const style::SymbolPropertyValues&,
+ const mat4& posMatrix, bool pitchWithMap, bool rotateWithMap, bool keepUpright,
const RenderTile&, const SymbolSizeBinder& sizeBinder, const TransformState&);
optional<std::pair<PlacedGlyph, PlacedGlyph>> placeFirstAndLastGlyph(const float fontScale,
diff --git a/src/mbgl/renderer/bucket.hpp b/src/mbgl/renderer/bucket.hpp
index c02e2ec341..665fc1bfa5 100644
--- a/src/mbgl/renderer/bucket.hpp
+++ b/src/mbgl/renderer/bucket.hpp
@@ -19,6 +19,7 @@ class PatternDependency;
using PatternLayerMap = std::map<std::string, PatternDependency>;
class Placement;
class BucketPlacementParameters;
+class RenderTile;
class Bucket {
public:
@@ -59,7 +60,7 @@ public:
}
// Places this bucket to the given placement. Returns bucket cross-tile id on success call; `0` otherwise.
virtual uint32_t place(Placement&, const BucketPlacementParameters&, std::set<uint32_t>&) { return 0u; }
- virtual void updateOpacities(Placement&, std::set<uint32_t>&) {}
+ virtual void updateVertices(Placement&, bool /*updateOpacities*/, const RenderTile&, std::set<uint32_t>&) {}
protected:
Bucket() = default;
diff --git a/src/mbgl/renderer/buckets/symbol_bucket.cpp b/src/mbgl/renderer/buckets/symbol_bucket.cpp
index 381ef5b24b..06fccb8ffd 100644
--- a/src/mbgl/renderer/buckets/symbol_bucket.cpp
+++ b/src/mbgl/renderer/buckets/symbol_bucket.cpp
@@ -10,7 +10,7 @@ namespace mbgl {
using namespace style;
namespace {
- std::atomic<uint32_t> maxBucketInstanceId;
+std::atomic<uint32_t> maxBucketInstanceId;
} // namespace
SymbolBucket::SymbolBucket(style::SymbolLayoutProperties::PossiblyEvaluated layout_,
@@ -62,7 +62,11 @@ void SymbolBucket::upload(gfx::UploadPass& uploadPass) {
}
if (!dynamicUploaded) {
- text.dynamicVertexBuffer = uploadPass.createVertexBuffer(std::move(text.dynamicVertices), gfx::BufferUsageType::StreamDraw);
+ if (!text.dynamicVertexBuffer) {
+ text.dynamicVertexBuffer = uploadPass.createVertexBuffer(std::move(text.dynamicVertices), gfx::BufferUsageType::StreamDraw);
+ } else {
+ uploadPass.updateVertexBuffer(*text.dynamicVertexBuffer, std::move(text.dynamicVertices));
+ }
}
if (!placementChangesUploaded) {
if (!text.opacityVertexBuffer) {
@@ -84,7 +88,11 @@ void SymbolBucket::upload(gfx::UploadPass& uploadPass) {
uploadPass.updateIndexBuffer(*icon.indexBuffer, std::move(icon.triangles));
}
if (!dynamicUploaded) {
- icon.dynamicVertexBuffer = uploadPass.createVertexBuffer(std::move(icon.dynamicVertices), gfx::BufferUsageType::StreamDraw);
+ if (!icon.dynamicVertexBuffer) {
+ icon.dynamicVertexBuffer = uploadPass.createVertexBuffer(std::move(icon.dynamicVertices), gfx::BufferUsageType::StreamDraw);
+ } else {
+ uploadPass.updateVertexBuffer(*icon.dynamicVertexBuffer, std::move(icon.dynamicVertices));
+ }
}
if (!placementChangesUploaded) {
if (!icon.opacityVertexBuffer) {
@@ -150,11 +158,6 @@ bool SymbolBucket::hasCollisionCircleData() const {
return !collisionCircle.segments.empty();
}
-void SymbolBucket::updateOpacity() {
- placementChangesUploaded = false;
- uploaded = false;
-}
-
void addPlacedSymbol(gfx::IndexVector<gfx::Triangles>& triangles, const PlacedSymbol& placedSymbol) {
auto endIndex = placedSymbol.vertexStartIndex + placedSymbol.glyphOffsets.size() * 4;
for (auto vertexIndex = placedSymbol.vertexStartIndex; vertexIndex < endIndex; vertexIndex += 4) {
@@ -242,8 +245,8 @@ bool SymbolBucket::hasFormatSectionOverrides() const {
}
std::pair<uint32_t, bool> SymbolBucket::registerAtCrossTileIndex(CrossTileSymbolLayerIndex& index, const OverscaledTileID& tileID, uint32_t& maxCrossTileID) {
- bool added = index.addBucket(tileID, *this, maxCrossTileID);
- return std::make_pair(bucketInstanceId, added);
+ bool firstTimeAdded = index.addBucket(tileID, *this, maxCrossTileID);
+ return std::make_pair(bucketInstanceId, firstTimeAdded);
}
uint32_t SymbolBucket::place(Placement& placement, const BucketPlacementParameters& params, std::set<uint32_t>& seenIds) {
@@ -251,8 +254,14 @@ uint32_t SymbolBucket::place(Placement& placement, const BucketPlacementParamete
return bucketInstanceId;
}
-void SymbolBucket::updateOpacities(Placement& placement, std::set<uint32_t>& seenIds) {
- placement.updateBucketOpacities(*this, seenIds);
+void SymbolBucket::updateVertices(Placement& placement, bool updateOpacities, const RenderTile& tile, std::set<uint32_t>& seenIds) {
+ if (updateOpacities) {
+ placement.updateBucketOpacities(*this, seenIds);
+ placementChangesUploaded = false;
+ }
+ placement.updateBucketDynamicVertices(*this, tile);
+ dynamicUploaded = false;
+ uploaded = false;
}
} // namespace mbgl
diff --git a/src/mbgl/renderer/buckets/symbol_bucket.hpp b/src/mbgl/renderer/buckets/symbol_bucket.hpp
index 3b61002890..e47672f1cd 100644
--- a/src/mbgl/renderer/buckets/symbol_bucket.hpp
+++ b/src/mbgl/renderer/buckets/symbol_bucket.hpp
@@ -60,14 +60,14 @@ public:
bool hasData() const override;
std::pair<uint32_t, bool> registerAtCrossTileIndex(CrossTileSymbolLayerIndex&, const OverscaledTileID&, uint32_t& maxCrossTileID) override;
uint32_t place(Placement&, const BucketPlacementParameters&, std::set<uint32_t>&) override;
- void updateOpacities(Placement&, std::set<uint32_t>&) override;
+ void updateVertices(Placement&, bool updateOpacities, const RenderTile&, std::set<uint32_t>&) override;
bool hasTextData() const;
bool hasIconData() const;
bool hasCollisionBoxData() const;
bool hasCollisionCircleData() const;
bool hasFormatSectionOverrides() const;
- void updateOpacity();
+
void sortFeatures(const float angle);
// The result contains references to the `symbolInstances` items, sorted by viewport Y.
std::vector<std::reference_wrapper<SymbolInstance>> getSortedSymbols(const float angle);
@@ -138,6 +138,7 @@ public:
const float tilePixelRatio;
uint32_t bucketInstanceId;
bool justReloaded = false;
+ bool hasVariablePlacement = false;
mutable optional<bool> hasFormatSectionOverrides_;
std::shared_ptr<std::vector<size_t>> featureSortOrder;
diff --git a/src/mbgl/renderer/layers/render_symbol_layer.cpp b/src/mbgl/renderer/layers/render_symbol_layer.cpp
index 7fc0e08b41..dc67dea7e3 100644
--- a/src/mbgl/renderer/layers/render_symbol_layer.cpp
+++ b/src/mbgl/renderer/layers/render_symbol_layer.cpp
@@ -15,9 +15,7 @@
#include <mbgl/tile/geometry_tile.hpp>
#include <mbgl/tile/geometry_tile_data.hpp>
#include <mbgl/style/layers/symbol_layer_impl.hpp>
-#include <mbgl/text/placement.hpp>
#include <mbgl/gfx/cull_face_mode.hpp>
-#include <mbgl/layout/symbol_projection.hpp>
#include <mbgl/layout/symbol_layout.hpp>
#include <mbgl/layout/symbol_layout.hpp>
#include <mbgl/util/math.hpp>
@@ -29,16 +27,6 @@ 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
- );
-}
style::SymbolPropertyValues iconPropertyValues(const style::SymbolPaintProperties::PossiblyEvaluated& evaluated_,
const style::SymbolLayoutProperties::PossiblyEvaluated& layout_) {
@@ -116,122 +104,6 @@ struct RenderableSegment {
}
};
-void uploadIcon(gfx::UploadPass& uploadPass,
- UploadParameters& uploadParameters,
- const RenderTile& tile,
- const LayerRenderData& renderData) {
- assert(tile.tile.kind == Tile::Kind::Geometry);
- auto& bucket = static_cast<SymbolBucket&>(*renderData.bucket);
- const auto& layout = bucket.layout;
-
- const bool alongLine = layout.get<SymbolPlacement>() != SymbolPlacementType::Point &&
- layout.get<IconRotationAlignment>() == AlignmentType::Map;
-
- if (alongLine) {
- const auto& evaluated = getEvaluated<SymbolLayerProperties>(renderData.layerProperties);
- reprojectLineLabels(bucket.icon.dynamicVertices, bucket.icon.placedSymbols, tile.matrix,
- iconPropertyValues(evaluated, layout), tile, *bucket.iconSizeBinder,
- uploadParameters.state);
-
- uploadPass.updateVertexBuffer(*bucket.icon.dynamicVertexBuffer,
- std::move(bucket.icon.dynamicVertices));
- }
-}
-
-void uploadText(gfx::UploadPass& uploadPass,
- UploadParameters& uploadParameters,
- const RenderTile& tile,
- const LayerRenderData& renderData,
- bool& hasVariablePlacement) {
- assert(tile.tile.kind == Tile::Kind::Geometry);
- auto& bucket = static_cast<SymbolBucket&>(*renderData.bucket);
- const auto& layout = bucket.layout;
-
- const bool alongLine = layout.get<SymbolPlacement>() != SymbolPlacementType::Point &&
- layout.get<TextRotationAlignment>() == AlignmentType::Map;
-
- if (alongLine) {
- const auto& evaluated = getEvaluated<SymbolLayerProperties>(renderData.layerProperties);
- reprojectLineLabels(bucket.text.dynamicVertices,
- bucket.text.placedSymbols,
- tile.matrix,
- textPropertyValues(evaluated, layout),
- tile,
- *bucket.textSizeBinder,
- uploadParameters.state);
-
- uploadPass.updateVertexBuffer(*bucket.text.dynamicVertexBuffer, std::move(bucket.text.dynamicVertices));
- } else if (!layout.get<TextVariableAnchor>().empty()) {
- bucket.text.dynamicVertices.clear();
-
- hasVariablePlacement = false;
-
- const auto partiallyEvaluatedSize = bucket.textSizeBinder->evaluateForZoom(uploadParameters.state.getZoom());
- const float tileScale = std::pow(2, uploadParameters.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, uploadParameters.state.getZoom());
- const auto labelPlaneMatrix = getLabelPlaneMatrix(tile.matrix, pitchWithMap, rotateWithMap, uploadParameters.state, pixelsToTileUnits);
-
- for (const PlacedSymbol& symbol : bucket.text.placedSymbols) {
- optional<VariableOffset> variableOffset;
- if (!symbol.hidden && symbol.crossTileID != 0u) {
- auto it = uploadParameters.variableOffsets.find(symbol.crossTileID);
- if (it != uploadParameters.variableOffsets.end()) {
- hasVariablePlacement |= true;
- variableOffset = it->second;
- }
- }
-
- 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 * (uploadParameters.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, -uploadParameters.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);
- }
- }
- }
- uploadPass.updateVertexBuffer(*bucket.text.dynamicVertexBuffer, std::move(bucket.text.dynamicVertices));
- }
-}
-
template <typename DrawFn>
void drawIcon(const DrawFn& draw,
const RenderTile& tile,
@@ -314,8 +186,7 @@ void drawText(const DrawFn& draw,
const LayerRenderData& renderData,
SegmentsWrapper textSegments,
const SymbolBucket::PaintProperties& bucketPaintProperties,
- const PaintParameters& parameters,
- bool hasVariablePlacement) {
+ const PaintParameters& parameters) {
assert(tile.tile.kind == Tile::Kind::Geometry);
auto& geometryTile = static_cast<GeometryTile&>(tile.tile);
auto& bucket = static_cast<SymbolBucket&>(*renderData.bucket);
@@ -335,7 +206,7 @@ void drawText(const DrawFn& draw,
if (values.hasHalo) {
draw(parameters.programs.getSymbolLayerPrograms().symbolGlyph,
- SymbolSDFTextProgram::layoutUniformValues(true, hasVariablePlacement, values, texsize, parameters.pixelsToGLUnits, parameters.pixelRatio, alongLine, tile, parameters.state, parameters.symbolFadeChange, SymbolSDFPart::Halo),
+ SymbolSDFTextProgram::layoutUniformValues(true, bucket.hasVariablePlacement, values, texsize, parameters.pixelsToGLUnits, parameters.pixelRatio, alongLine, tile, parameters.state, parameters.symbolFadeChange, SymbolSDFPart::Halo),
bucket.text,
textSegments,
bucket.textSizeBinder,
@@ -350,7 +221,7 @@ void drawText(const DrawFn& draw,
if (values.hasFill) {
draw(parameters.programs.getSymbolLayerPrograms().symbolGlyph,
- SymbolSDFTextProgram::layoutUniformValues(true, hasVariablePlacement, values, texsize, parameters.pixelsToGLUnits, parameters.pixelRatio, alongLine, tile, parameters.state, parameters.symbolFadeChange, SymbolSDFPart::Fill),
+ SymbolSDFTextProgram::layoutUniformValues(true, bucket.hasVariablePlacement, values, texsize, parameters.pixelsToGLUnits, parameters.pixelRatio, alongLine, tile, parameters.state, parameters.symbolFadeChange, SymbolSDFPart::Fill),
bucket.text,
textSegments,
bucket.textSizeBinder,
@@ -413,24 +284,6 @@ bool RenderSymbolLayer::hasCrossfade() const {
return false;
}
-void RenderSymbolLayer::upload(gfx::UploadPass& uploadPass, UploadParameters& uploadParameters) {
- for (const RenderTile& tile : renderTiles) {
- const LayerRenderData* renderData = tile.tile.getLayerRenderData(*baseImpl);
- if (!renderData) {
- continue;
- }
-
- auto& bucket = static_cast<SymbolBucket&>(*renderData->bucket);
- if (bucket.hasIconData()) {
- uploadIcon(uploadPass, uploadParameters, tile, *renderData);
- }
-
- if (bucket.hasTextData()) {
- uploadText(uploadPass, uploadParameters, tile, *renderData, hasVariablePlacement);
- }
- }
-}
-
void RenderSymbolLayer::render(PaintParameters& parameters) {
if (parameters.pass == RenderPass::Opaque) {
return;
@@ -537,7 +390,7 @@ void RenderSymbolLayer::render(PaintParameters& parameters) {
if (sortFeaturesByKey) {
addRenderables(bucket.text.segments, true /*isText*/);
} else {
- drawText(draw, tile, *renderData, std::ref(bucket.text.segments), bucketPaintProperties, parameters, hasVariablePlacement);
+ drawText(draw, tile, *renderData, std::ref(bucket.text.segments), bucketPaintProperties, parameters);
}
}
@@ -619,7 +472,7 @@ void RenderSymbolLayer::render(PaintParameters& parameters) {
if (sortFeaturesByKey) {
for (auto& renderable : renderableSegments) {
if (renderable.isText) {
- drawText(draw, renderable.tile, renderable.renderData, renderable.segment, renderable.bucketPaintProperties, parameters, hasVariablePlacement);
+ drawText(draw, renderable.tile, renderable.renderData, renderable.segment, renderable.bucketPaintProperties, parameters);
} else {
drawIcon(draw, renderable.tile, renderable.renderData, renderable.segment, renderable.bucketPaintProperties, parameters);
}
diff --git a/src/mbgl/renderer/layers/render_symbol_layer.hpp b/src/mbgl/renderer/layers/render_symbol_layer.hpp
index ffd05aa310..d9ce8c688d 100644
--- a/src/mbgl/renderer/layers/render_symbol_layer.hpp
+++ b/src/mbgl/renderer/layers/render_symbol_layer.hpp
@@ -65,7 +65,6 @@ private:
void evaluate(const PropertyEvaluationParameters&) override;
bool hasTransition() const override;
bool hasCrossfade() const override;
- void upload(gfx::UploadPass&, UploadParameters&) override;
void render(PaintParameters&) override;
void prepare(const LayerPrepareParameters&) override;
@@ -76,7 +75,6 @@ private:
float textSize = 16.0f;
bool hasFormatSectionOverrides = false;
- bool hasVariablePlacement = false;
};
} // namespace mbgl
diff --git a/src/mbgl/renderer/renderer_impl.cpp b/src/mbgl/renderer/renderer_impl.cpp
index f8e6b65f7f..a809fd843a 100644
--- a/src/mbgl/renderer/renderer_impl.cpp
+++ b/src/mbgl/renderer/renderer_impl.cpp
@@ -345,10 +345,8 @@ void Renderer::Impl::render(const UpdateParameters& updateParameters) {
placement->setStale();
}
- if (placementChanged || symbolBucketsChanged) {
- for (auto it = layersNeedPlacement.rbegin(); it != layersNeedPlacement.rend(); ++it) {
- placement->updateLayerOpacities(*it);
- }
+ for (auto it = layersNeedPlacement.rbegin(); it != layersNeedPlacement.rend(); ++it) {
+ placement->updateLayerBuckets(*it, placementChanged || symbolBucketsChanged);
}
}
@@ -385,7 +383,6 @@ void Renderer::Impl::render(const UpdateParameters& updateParameters) {
UploadParameters uploadParameters{
updateParameters.transformState,
- placement->getVariableOffsets(),
*imageManager,
*lineAtlas,
};
diff --git a/src/mbgl/renderer/upload_parameters.hpp b/src/mbgl/renderer/upload_parameters.hpp
index 0328309927..14da1026c6 100644
--- a/src/mbgl/renderer/upload_parameters.hpp
+++ b/src/mbgl/renderer/upload_parameters.hpp
@@ -7,23 +7,18 @@ namespace mbgl {
class TransformState;
class LineAtlas;
-class VariableOffset;
-using VariableOffsets = std::unordered_map<uint32_t, VariableOffset>;
class UploadParameters {
public:
UploadParameters(const TransformState& state_,
- const VariableOffsets& variableOffsets_,
ImageManager& imageManager_,
LineAtlas& lineAtlas_)
: state(state_),
- variableOffsets(variableOffsets_),
imageManager(imageManager_),
lineAtlas(lineAtlas_) {
}
const TransformState& state;
- const VariableOffsets& variableOffsets;
ImageManager& imageManager;
LineAtlas& lineAtlas;
};
diff --git a/src/mbgl/text/placement.cpp b/src/mbgl/text/placement.cpp
index 49a57ae7c0..8dbb7fe346 100644
--- a/src/mbgl/text/placement.cpp
+++ b/src/mbgl/text/placement.cpp
@@ -396,10 +396,110 @@ void Placement::commit(TimePoint now) {
fadeStartTime = placementChanged ? commitTime : prevPlacement->fadeStartTime;
}
-void Placement::updateLayerOpacities(const RenderLayer& layer) {
+void Placement::updateLayerBuckets(const RenderLayer& layer, bool updateOpacities) {
std::set<uint32_t> seenCrossTileIDs;
for (const auto& item : layer.getPlacementData()) {
- item.bucket.get().updateOpacities(*this, seenCrossTileIDs);
+ item.bucket.get().updateVertices(*this, updateOpacities, item.tile, seenCrossTileIDs);
+ }
+}
+
+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 { (shiftX / textBoxScale + offset.x) * renderTextSize,
+ (shiftY / textBoxScale + offset.y) * renderTextSize };
+}
+} // namespace
+
+void Placement::updateBucketDynamicVertices(SymbolBucket& bucket, const RenderTile& tile) {
+ using namespace style;
+ const auto& layout = bucket.layout;
+ const bool alongLine = layout.get<SymbolPlacement>() != SymbolPlacementType::Point;
+ if (alongLine) {
+ if (bucket.hasIconData() && layout.get<IconRotationAlignment>() == AlignmentType::Map) {
+ const bool pitchWithMap = layout.get<style::IconPitchAlignment>() == style::AlignmentType::Map;
+ const bool keepUpright = layout.get<style::IconKeepUpright>();
+ reprojectLineLabels(bucket.icon.dynamicVertices, bucket.icon.placedSymbols,
+ tile.matrix, pitchWithMap, true /*rotateWithMap*/, keepUpright,
+ tile, *bucket.iconSizeBinder, state);
+ }
+
+ if (bucket.hasTextData() && layout.get<TextRotationAlignment>() == AlignmentType::Map) {
+ const bool pitchWithMap = layout.get<style::TextPitchAlignment>() == style::AlignmentType::Map;
+ const bool keepUpright = layout.get<style::TextKeepUpright>();
+ reprojectLineLabels(bucket.text.dynamicVertices, bucket.text.placedSymbols,
+ tile.matrix, pitchWithMap, true /*rotateWithMap*/, keepUpright,
+ tile, *bucket.textSizeBinder, state);
+ }
+ } else if (!layout.get<TextVariableAnchor>().empty() && bucket.hasTextData()) {
+ bucket.text.dynamicVertices.clear();
+ bucket.hasVariablePlacement = false;
+
+ const auto partiallyEvaluatedSize = bucket.textSizeBinder->evaluateForZoom(state.getZoom());
+ const float tileScale = std::pow(2, 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, state.getZoom());
+ const auto labelPlaneMatrix = getLabelPlaneMatrix(tile.matrix, pitchWithMap, rotateWithMap, state, pixelsToTileUnits);
+
+ for (const PlacedSymbol& symbol : bucket.text.placedSymbols) {
+ optional<VariableOffset> variableOffset;
+ if (!symbol.hidden && symbol.crossTileID != 0u) {
+ auto it = variableOffsets.find(symbol.crossTileID);
+ if (it != variableOffsets.end()) {
+ bucket.hasVariablePlacement = true;
+ variableOffset = it->second;
+ }
+ }
+
+ 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 * (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, -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);
+ }
+ }
+ }
}
}
@@ -559,7 +659,6 @@ void Placement::updateBucketOpacities(SymbolBucket& bucket, std::set<uint32_t>&
}
}
- bucket.updateOpacity();
bucket.sortFeatures(state.getBearing());
auto retainedData = retainedQueryData.find(bucket.bucketInstanceId);
if (retainedData != retainedQueryData.end()) {
diff --git a/src/mbgl/text/placement.hpp b/src/mbgl/text/placement.hpp
index e0fcac3350..c159286a2b 100644
--- a/src/mbgl/text/placement.hpp
+++ b/src/mbgl/text/placement.hpp
@@ -105,7 +105,7 @@ public:
Placement(const TransformState&, MapMode, style::TransitionOptions, const bool crossSourceCollisions, std::unique_ptr<Placement> prevPlacementOrNull = nullptr);
void placeLayer(const RenderLayer&, const mat4&, bool showCollisionBoxes);
void commit(TimePoint);
- void updateLayerOpacities(const RenderLayer&);
+ void updateLayerBuckets(const RenderLayer&, bool updateOpacities);
float symbolFadeChange(TimePoint now) const;
bool hasTransitions(TimePoint now) const;
@@ -116,9 +116,6 @@ public:
void setStale();
const RetainedQueryData& getQueryData(uint32_t bucketInstanceId) const;
- using VariableOffsets = std::unordered_map<uint32_t, VariableOffset>;
- const VariableOffsets& getVariableOffsets() const { return variableOffsets; }
-
private:
friend SymbolBucket;
void placeLayerBucket(
@@ -126,6 +123,7 @@ private:
const BucketPlacementParameters&,
std::set<uint32_t>& seenCrossTileIDs);
+ void updateBucketDynamicVertices(SymbolBucket& bucket, const RenderTile& tile);
void updateBucketOpacities(SymbolBucket&, std::set<uint32_t>&);
void markUsedJustification(SymbolBucket&, style::TextVariableAnchorType, SymbolInstance&);