summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorAnsis Brammanis <ansis@mapbox.com>2017-10-05 12:54:23 -0400
committerAnsis Brammanis <ansis@mapbox.com>2017-10-24 16:57:54 -0400
commit7d028513949a77705a0d706bbfa58f5c4e2e0f8f (patch)
treec91148beeb208afb762b3a96b6d9d22a1cb732b3
parentcc061a1f763eb338055a7a7efd3aec1eebad124c (diff)
downloadqtlocation-mapboxgl-upstream/start-collision-dynamic-buffer.tar.gz
start running new placement [skip ci]upstream/start-collision-dynamic-buffer
-rw-r--r--cmake/core-files.cmake4
-rw-r--r--src/mbgl/layout/symbol_instance.cpp4
-rw-r--r--src/mbgl/layout/symbol_instance.hpp16
-rw-r--r--src/mbgl/layout/symbol_layout.cpp11
-rw-r--r--src/mbgl/layout/symbol_layout.hpp5
-rw-r--r--src/mbgl/layout/symbol_projection.hpp1
-rw-r--r--src/mbgl/renderer/buckets/symbol_bucket.cpp6
-rw-r--r--src/mbgl/renderer/buckets/symbol_bucket.hpp6
-rw-r--r--src/mbgl/renderer/placement_state.cpp103
-rw-r--r--src/mbgl/renderer/placement_state.hpp70
-rw-r--r--src/mbgl/renderer/render_layer.hpp6
-rw-r--r--src/mbgl/renderer/renderer_impl.cpp38
-rw-r--r--src/mbgl/text/cross_tile_symbol_index.cpp12
-rw-r--r--src/mbgl/text/placement.cpp237
-rw-r--r--src/mbgl/text/placement.hpp68
-rw-r--r--src/mbgl/tile/geometry_tile.hpp4
-rw-r--r--src/mbgl/tile/geometry_tile_worker.cpp4
17 files changed, 369 insertions, 226 deletions
diff --git a/cmake/core-files.cmake b/cmake/core-files.cmake
index bdaa5ccca5..f9c3614f10 100644
--- a/cmake/core-files.cmake
+++ b/cmake/core-files.cmake
@@ -177,8 +177,6 @@ set(MBGL_CORE_FILES
src/mbgl/renderer/paint_parameters.hpp
src/mbgl/renderer/paint_property_binder.hpp
src/mbgl/renderer/paint_property_statistics.hpp
- src/mbgl/renderer/placement_state.hpp
- src/mbgl/renderer/placement_state.cpp
src/mbgl/renderer/possibly_evaluated_property_value.hpp
src/mbgl/renderer/property_evaluation_parameters.hpp
src/mbgl/renderer/property_evaluator.hpp
@@ -485,6 +483,8 @@ set(MBGL_CORE_FILES
src/mbgl/text/glyph_pbf.cpp
src/mbgl/text/glyph_pbf.hpp
src/mbgl/text/glyph_range.hpp
+ src/mbgl/text/placement.cpp
+ src/mbgl/text/placement.hpp
src/mbgl/text/placement_config.hpp
src/mbgl/text/quads.cpp
src/mbgl/text/quads.hpp
diff --git a/src/mbgl/layout/symbol_instance.cpp b/src/mbgl/layout/symbol_instance.cpp
index 8a83cc4b90..901200731e 100644
--- a/src/mbgl/layout/symbol_instance.cpp
+++ b/src/mbgl/layout/symbol_instance.cpp
@@ -37,7 +37,9 @@ SymbolInstance::SymbolInstance(Anchor& anchor_,
featureIndex(featureIndex_),
textOffset(textOffset_),
iconOffset(iconOffset_),
- key(key_) {
+ key(key_),
+ placedText(false),
+ placedIcon(false) {
// Create the quads used for rendering the icon and glyphs.
if (addToBuffers) {
diff --git a/src/mbgl/layout/symbol_instance.hpp b/src/mbgl/layout/symbol_instance.hpp
index 0ad97edf87..b9217c44ae 100644
--- a/src/mbgl/layout/symbol_instance.hpp
+++ b/src/mbgl/layout/symbol_instance.hpp
@@ -5,19 +5,12 @@
#include <mbgl/text/collision_feature.hpp>
#include <mbgl/style/layers/symbol_layer_properties.hpp>
+
namespace mbgl {
class Anchor;
class IndexedSubfeature;
-class OpacityState {
- public:
- OpacityState() : opacity(0), targetOpacity(0) {}
- float opacity;
- float targetOpacity;
- TimePoint time;
-};
-
class SymbolInstance {
public:
SymbolInstance(Anchor& anchor,
@@ -56,8 +49,11 @@ public:
std::array<float, 2> iconOffset;
std::u16string key;
bool isDuplicate;
- OpacityState iconOpacityState;
- OpacityState textOpacityState;
+ bool placedText;
+ bool placedIcon;
+ std::vector<size_t> placedTextIndices; // TODO clean this up
+ std::vector<size_t> placedIconIndices;
+ uint32_t crossTileID = 0;
};
} // namespace mbgl
diff --git a/src/mbgl/layout/symbol_layout.cpp b/src/mbgl/layout/symbol_layout.cpp
index 017188cbf9..1032088e70 100644
--- a/src/mbgl/layout/symbol_layout.cpp
+++ b/src/mbgl/layout/symbol_layout.cpp
@@ -43,8 +43,8 @@ SymbolLayout::SymbolLayout(const BucketParameters& parameters,
std::unique_ptr<GeometryTileLayer> sourceLayer_,
ImageDependencies& imageDependencies,
GlyphDependencies& glyphDependencies)
- : sourceLayer(std::move(sourceLayer_)),
- bucketName(layers.at(0)->getID()),
+ : bucketName(layers.at(0)->getID()),
+ sourceLayer(std::move(sourceLayer_)),
overscaling(parameters.tileID.overscaleFactor()),
zoom(parameters.tileID.overscaledZ),
mode(parameters.mode),
@@ -393,7 +393,7 @@ bool SymbolLayout::anchorIsTooClose(const std::u16string& text, const float repe
}
std::unique_ptr<SymbolBucket> SymbolLayout::place(CollisionTile& collisionTile) {
- auto bucket = std::make_unique<SymbolBucket>(layout, layerPaintProperties, textSize, iconSize, zoom, sdfIcons, iconsNeedLinear);
+ auto bucket = std::make_unique<SymbolBucket>(layout, layerPaintProperties, textSize, iconSize, zoom, sdfIcons, iconsNeedLinear, symbolInstances);
// Calculate which labels can be shown and when they can be shown and
// create the bufers used for rendering.
@@ -427,7 +427,8 @@ std::unique_ptr<SymbolBucket> SymbolLayout::place(CollisionTile& collisionTile)
});
}
- for (SymbolInstance &symbolInstance : symbolInstances) {
+ // this iterates over the *bucket's* symbol instances so that it can set the placedsymbol index. TODO cleanup
+ for (SymbolInstance &symbolInstance : bucket->symbolInstances) {
const bool hasText = symbolInstance.hasText;
const bool hasIcon = symbolInstance.hasIcon;
@@ -475,6 +476,7 @@ std::unique_ptr<SymbolBucket> SymbolLayout::place(CollisionTile& collisionTile)
const Range<float> sizeData = bucket->textSizeBinder->getVertexSizeData(feature);
bucket->text.placedSymbols.emplace_back(symbolInstance.anchor.point, symbolInstance.anchor.segment, sizeData.min, sizeData.max,
symbolInstance.textOffset, placementZoom, useVerticalMode, symbolInstance.line);
+ symbolInstance.placedTextIndices.push_back(bucket->text.placedSymbols.size() - 1);
for (const auto& symbol : symbolInstance.glyphQuads) {
addSymbol(
@@ -491,6 +493,7 @@ std::unique_ptr<SymbolBucket> SymbolLayout::place(CollisionTile& collisionTile)
const Range<float> sizeData = bucket->iconSizeBinder->getVertexSizeData(feature);
bucket->icon.placedSymbols.emplace_back(symbolInstance.anchor.point, symbolInstance.anchor.segment, sizeData.min, sizeData.max,
symbolInstance.iconOffset, placementZoom, false, symbolInstance.line);
+ symbolInstance.placedIconIndices.push_back(bucket->icon.placedSymbols.size() - 1);
addSymbol(
bucket->icon, sizeData, *symbolInstance.iconQuad,
keepUpright, iconPlacement, symbolInstance.anchor, bucket->icon.placedSymbols.back());
diff --git a/src/mbgl/layout/symbol_layout.hpp b/src/mbgl/layout/symbol_layout.hpp
index c5026040cf..8cd5e7ec05 100644
--- a/src/mbgl/layout/symbol_layout.hpp
+++ b/src/mbgl/layout/symbol_layout.hpp
@@ -44,6 +44,9 @@ public:
std::map<std::string,
std::pair<style::IconPaintProperties::PossiblyEvaluated, style::TextPaintProperties::PossiblyEvaluated>> layerPaintProperties;
+ const std::string bucketName;
+ std::vector<SymbolInstance> symbolInstances;
+
private:
void addFeature(const size_t,
const SymbolFeature&,
@@ -69,7 +72,6 @@ private:
// Stores the layer so that we can hold on to GeometryTileFeature instances in SymbolFeature,
// which may reference data from this object.
const std::unique_ptr<GeometryTileLayer> sourceLayer;
- const std::string bucketName;
const float overscaling;
const float zoom;
const MapMode mode;
@@ -86,7 +88,6 @@ private:
style::TextSize::UnevaluatedType textSize;
style::IconSize::UnevaluatedType iconSize;
- std::vector<SymbolInstance> symbolInstances;
std::vector<SymbolFeature> features;
BiDi bidi; // Consider moving this up to geometry tile worker to reduce reinstantiation costs; use of BiDi/ubiditransform object must be constrained to one thread
diff --git a/src/mbgl/layout/symbol_projection.hpp b/src/mbgl/layout/symbol_projection.hpp
index 51b3896edf..5f4f919c93 100644
--- a/src/mbgl/layout/symbol_projection.hpp
+++ b/src/mbgl/layout/symbol_projection.hpp
@@ -31,6 +31,7 @@ namespace mbgl {
optional<TileDistance> tileDistance;
};
+ float evaluateSizeForFeature(const ZoomEvaluatedSize& zoomEvaluatedSize, const PlacedSymbol& placedSymbol);
mat4 getLabelPlaneMatrix(const mat4& posMatrix, const bool pitchWithMap, const bool rotateWithMap, const TransformState& state, const float pixelsToTileUnits);
mat4 getGlCoordMatrix(const mat4& posMatrix, const bool pitchWithMap, const bool rotateWithMap, const TransformState& state, const float pixelsToTileUnits);
diff --git a/src/mbgl/renderer/buckets/symbol_bucket.cpp b/src/mbgl/renderer/buckets/symbol_bucket.cpp
index ee225b0c6c..d01f94e271 100644
--- a/src/mbgl/renderer/buckets/symbol_bucket.cpp
+++ b/src/mbgl/renderer/buckets/symbol_bucket.cpp
@@ -16,10 +16,12 @@ SymbolBucket::SymbolBucket(style::SymbolLayoutProperties::PossiblyEvaluated layo
const style::DataDrivenPropertyValue<float>& iconSize,
float zoom,
bool sdfIcons_,
- bool iconsNeedLinear_)
+ bool iconsNeedLinear_,
+ const std::vector<SymbolInstance>& symbolInstances_)
: layout(std::move(layout_)),
sdfIcons(sdfIcons_),
iconsNeedLinear(iconsNeedLinear_ || iconSize.isDataDriven() || !iconSize.isZoomConstant()),
+ symbolInstances(symbolInstances_), // TODO maybe not copy
textSizeBinder(SymbolSizeBinder::create(zoom, textSize, TextSize::defaultValue())),
iconSizeBinder(SymbolSizeBinder::create(zoom, iconSize, IconSize::defaultValue())) {
@@ -45,7 +47,7 @@ void SymbolBucket::upload(gl::Context& context) {
if (hasIconData()) {
icon.vertexBuffer = context.createVertexBuffer(std::move(icon.vertices));
icon.dynamicVertexBuffer = context.createVertexBuffer(std::move(icon.dynamicVertices), gl::BufferUsage::StreamDraw);
- icon.opacityVertexBuffer = context.createVertexBuffer(std::move(text.opacityVertices), gl::BufferUsage::StreamDraw);
+ icon.opacityVertexBuffer = context.createVertexBuffer(std::move(icon.opacityVertices), gl::BufferUsage::StreamDraw);
icon.indexBuffer = context.createIndexBuffer(std::move(icon.triangles));
}
diff --git a/src/mbgl/renderer/buckets/symbol_bucket.hpp b/src/mbgl/renderer/buckets/symbol_bucket.hpp
index 2e91f02ea1..fd7d03a806 100644
--- a/src/mbgl/renderer/buckets/symbol_bucket.hpp
+++ b/src/mbgl/renderer/buckets/symbol_bucket.hpp
@@ -10,6 +10,7 @@
#include <mbgl/text/glyph_range.hpp>
#include <mbgl/style/layers/symbol_layer_properties.hpp>
#include <mbgl/layout/symbol_feature.hpp>
+#include <mbgl/layout/symbol_instance.hpp>
#include <vector>
@@ -49,7 +50,8 @@ public:
const style::DataDrivenPropertyValue<float>& iconSize,
float zoom,
bool sdfIcons,
- bool iconsNeedLinear);
+ bool iconsNeedLinear,
+ const std::vector<SymbolInstance>&);
void upload(gl::Context&) override;
bool hasData() const override;
@@ -61,6 +63,8 @@ public:
const bool sdfIcons;
const bool iconsNeedLinear;
+ std::vector<SymbolInstance> symbolInstances;
+
std::map<std::string, std::pair<
SymbolIconProgram::PaintPropertyBinders,
SymbolSDFTextProgram::PaintPropertyBinders>> paintPropertyBinders;
diff --git a/src/mbgl/renderer/placement_state.cpp b/src/mbgl/renderer/placement_state.cpp
deleted file mode 100644
index f00001ec23..0000000000
--- a/src/mbgl/renderer/placement_state.cpp
+++ /dev/null
@@ -1,103 +0,0 @@
-#include <mbgl/renderer/placement_state.hpp>
-#include <mbgl/renderer/layers/render_symbol_layer.hpp>
-#include <mbgl/renderer/render_layer.hpp>
-#include <mbgl/renderer/render_source.hpp>
-#include <mbgl/renderer/render_tile.hpp>
-#include <mbgl/tile/tile.hpp>
-
-
-namespace mbgl {
-
-LayerPlacementState::LayerPlacementState() : currentTileIndex(0)
-{
-}
-
-bool LayerPlacementState::continuePlacement(RenderSymbolLayer& layer,
- CollisionIndex& collisionIndex,
- const bool showCollisionBoxes,
- std::function<bool()> shouldPausePlacement) {
- while (currentTileIndex < layer.renderTiles.size()) {
- RenderTile& tile = layer.renderTiles[currentTileIndex++];
- tile.tile.placeLayer(showCollisionBoxes, collisionIndex, layer.impl());
-
- if (shouldPausePlacement()) {
- return true;
- }
- }
- return false;
-}
-
-PlacementState::PlacementState(const TransformState& transformState,
- const std::vector<RenderLayer>& order,
- const bool forceFullPlacement_,
- const bool showCollisionBoxes_,
- Duration fadeDuration,
- optional<PlacementState>& previousPlacement)
- : collisionIndex(transformState)
- , currentLayerIndex(order.size() - 1)
- , forceFullPlacement(forceFullPlacement_)
- , showCollisionBoxes(showCollisionBoxes_)
-{
- if (forceFullPlacement || !previousPlacement) {
- delayUntil = TimePoint();
- } else {
- delayUntil = previousPlacement->delayUntil + Milliseconds(300);
- }
-
- if (previousPlacement) {
- collisionFadeTimes = previousPlacement->collisionFadeTimes;
- } else {
- collisionFadeTimes = { TimePoint::min(), fadeDuration };
- }
-}
-
-void PlacementState::continuePlacement(std::vector<RenderLayer>& order, std::vector<RenderSource>& sources) {
- const TimePoint startTime;
-
- if (startTime < delayUntil) return;
-
- auto shouldPausePlacement = [&] () {
- const Duration elapsedTime = TimePoint() - startTime;
- return forceFullPlacement ? false : elapsedTime > Milliseconds(2);
- };
-
- do {
- RenderLayer& renderLayer = order[currentLayerIndex];
- if (renderLayer.is<RenderSymbolLayer>()) {
- if (inProgressLayer) {
- inProgressLayer = LayerPlacementState();
- }
-
- bool pausePlacement = inProgressLayer->continuePlacement(*renderLayer.as<RenderSymbolLayer>(),
- collisionIndex,
- showCollisionBoxes,
- shouldPausePlacement);
-
- if (pausePlacement) {
- // We didn't finish placing all layers within 2ms,
- // but we can keep rendering with a partial placement
- // We'll resume here on the next frame
- return;
- }
-
- inProgressLayer = std::experimental::nullopt;
- }
-
- currentLayerIndex--;
- } while (currentLayerIndex > 0);
-
- for (RenderSource& source : sources) {
- auto tiles = source.getRenderTiles();
- for (RenderTile& tile : tiles) {
- tile.tile.commitPlacement(collisionIndex, collisionFadeTimes);
- }
- }
-
- done = true;
-}
-
-bool PlacementState::stillFading() const {
- return TimePoint() < collisionFadeTimes.latestStart + collisionFadeTimes.fadeDuration;
-}
-
-}; // mbgl
diff --git a/src/mbgl/renderer/placement_state.hpp b/src/mbgl/renderer/placement_state.hpp
deleted file mode 100644
index 07c655ca03..0000000000
--- a/src/mbgl/renderer/placement_state.hpp
+++ /dev/null
@@ -1,70 +0,0 @@
-#pragma once
-
-#include <mbgl/map/transform_state.hpp>
-#include <mbgl/style/collection.hpp>
-#include <mbgl/style/layer.hpp>
-#include <mbgl/tile/tile_id.hpp>
-#include <mbgl/util/chrono.hpp>
-#include <mbgl/util/optional.hpp>
-
-#include <functional>
-#include <map>
-#include <string>
-
-namespace mbgl {
-
-// TODO: Placeholder
-class CollisionIndex {
-public:
- CollisionIndex(const TransformState&) {}
-};
-
-class RenderLayer;
-class RenderSymbolLayer;
-class RenderSource;
-
-struct CollisionFadeTimes {
- TimePoint latestStart;
- Duration fadeDuration;
-};
-
-class LayerPlacementState {
-public:
- LayerPlacementState();
- bool continuePlacement(RenderSymbolLayer& renderLayer,
- CollisionIndex& collisionIndex,
- const bool showCollisionBoxes,
- std::function<bool()> shouldPausePlacement);
-
-private:
- size_t currentTileIndex;
-};
-
-class PlacementState
-{
-public:
- PlacementState(const TransformState& transformState,
- const std::vector<RenderLayer>& order,
- const bool forceFullPlacement,
- const bool showCollisionBoxes,
- Duration fadeDuration,
- optional<PlacementState>& previousPlacement);
-
- bool isDone() const { return done; }
- bool stillFading() const;
-
- void continuePlacement(std::vector<RenderLayer>& order, std::vector<RenderSource>& sources);
-
-private:
- CollisionIndex collisionIndex;
- bool done;
- size_t currentLayerIndex;
- bool forceFullPlacement;
- bool showCollisionBoxes;
- TimePoint delayUntil;
- CollisionFadeTimes collisionFadeTimes;
- optional<LayerPlacementState> inProgressLayer;
-
-};
-
-}; // mbgl
diff --git a/src/mbgl/renderer/render_layer.hpp b/src/mbgl/renderer/render_layer.hpp
index afd1e9546b..79c8bcccf7 100644
--- a/src/mbgl/renderer/render_layer.hpp
+++ b/src/mbgl/renderer/render_layer.hpp
@@ -81,6 +81,10 @@ public:
friend std::string layoutKey(const RenderLayer&);
+ // TODO should this not be public?
+ //Stores current set of tiles to be rendered for this layer.
+ std::vector<std::reference_wrapper<RenderTile>> renderTiles;
+
protected:
// Stores what render passes this layer is currently enabled for. This depends on the
// evaluated StyleProperties object and is updated accordingly.
@@ -89,8 +93,6 @@ protected:
// TODO: Placement needs access to the renderTiles -- figure out how best to coordinate
friend class LayerPlacementState;
- //Stores current set of tiles to be rendered for this layer.
- std::vector<std::reference_wrapper<RenderTile>> renderTiles;
};
diff --git a/src/mbgl/renderer/renderer_impl.cpp b/src/mbgl/renderer/renderer_impl.cpp
index 5aac64b552..3baa386313 100644
--- a/src/mbgl/renderer/renderer_impl.cpp
+++ b/src/mbgl/renderer/renderer_impl.cpp
@@ -27,6 +27,7 @@
#include <mbgl/util/math.hpp>
#include <mbgl/util/string.hpp>
#include <mbgl/util/logging.hpp>
+#include <mbgl/text/placement.hpp>
namespace mbgl {
@@ -345,26 +346,6 @@ void Renderer::Impl::render(const UpdateParameters& updateParameters) {
continue;
}
- // We're not clipping symbol layers, so when we have both parents and children of symbol
- // layers, we drop all children in favor of their parent to avoid duplicate labels.
- // See https://github.com/mapbox/mapbox-gl-native/issues/2482
- if (symbolLayer) {
- bool skip = false;
- // Look back through the buckets we decided to render to find out whether there is
- // already a bucket from this layer that is a parent of this tile. Tiles are ordered
- // by zoom level when we obtain them from getTiles().
- for (auto it = sortedTilesForInsertion.rbegin();
- it != sortedTilesForInsertion.rend(); ++it) {
- if (tile.tile.id.isChildOf(it->get().tile.id)) {
- skip = true;
- break;
- }
- }
- if (skip) {
- continue;
- }
- }
-
auto bucket = tile.tile.getBucket(*layer->baseImpl);
if (bucket) {
sortedTilesForInsertion.emplace_back(tile);
@@ -382,6 +363,17 @@ void Renderer::Impl::render(const UpdateParameters& updateParameters) {
order.emplace_back(RenderItem { *layer, source });
}
+ Placement placement(parameters.state);
+ for (auto it = order.rbegin(); it != order.rend(); ++it) {
+ if (it->layer.is<RenderSymbolLayer>()) {
+ bool showCollisionBoxes = false; // TODO
+ placement.placeLayer(*it->layer.as<RenderSymbolLayer>(), showCollisionBoxes);
+ }
+ }
+
+ std::unique_ptr<Placement> prevPlacement;
+ placement.commit(std::move(prevPlacement), Clock::now());
+
// - UPLOAD PASS -------------------------------------------------------------------------------
// Uploads all required buffers and images before we do any actual rendering.
{
@@ -398,6 +390,12 @@ void Renderer::Impl::render(const UpdateParameters& updateParameters) {
}
}
+ for (auto it = order.rbegin(); it != order.rend(); ++it) {
+ if (it->layer.is<RenderSymbolLayer>()) {
+ placement.updateLayerOpacities(*it->layer.as<RenderSymbolLayer>(), parameters.context);
+ }
+ }
+
// - 3D PASS -------------------------------------------------------------------------------------
// Renders any 3D layers bottom-to-top to unique FBOs with texture attachments, but share the same
// depth rbo between them.
diff --git a/src/mbgl/text/cross_tile_symbol_index.cpp b/src/mbgl/text/cross_tile_symbol_index.cpp
index 6c51fb1ead..0d19ba83cd 100644
--- a/src/mbgl/text/cross_tile_symbol_index.cpp
+++ b/src/mbgl/text/cross_tile_symbol_index.cpp
@@ -18,8 +18,8 @@ TileLayerIndex::TileLayerIndex(OverscaledTileID coord, std::shared_ptr<std::vect
// If we don't pick up an opacity from our parent or child tiles
// Reset so that symbols in cached tiles fade in the same
// way as freshly loaded tiles
- symbolInstance.textOpacityState = OpacityState();
- symbolInstance.iconOpacityState = OpacityState();
+ //symbolInstance.textOpacityState = OpacityState();
+ //symbolInstance.iconOpacityState = OpacityState();
}
}
@@ -139,8 +139,8 @@ void CrossTileSymbolLayerIndex::blockLabels(TileLayerIndex& childIndex, TileLaye
// If the child label is the one being added to the index,
// copy the parent's opacity to the child
if (copyParentOpacity) {
- symbolInstance.textOpacityState = parentSymbolInstance->textOpacityState;
- symbolInstance.iconOpacityState = parentSymbolInstance->iconOpacityState;
+ //symbolInstance.textOpacityState = parentSymbolInstance->textOpacityState;
+ //symbolInstance.iconOpacityState = parentSymbolInstance->iconOpacityState;
}
}
}
@@ -157,8 +157,8 @@ void CrossTileSymbolLayerIndex::unblockLabels(TileLayerIndex& childIndex, TileLa
if (parentSymbolInstance) {
// this label is now unblocked, copy its opacity state
parentSymbolInstance->isDuplicate = false;
- parentSymbolInstance->textOpacityState = symbolInstance.textOpacityState;
- parentSymbolInstance->iconOpacityState = symbolInstance.iconOpacityState;
+ //parentSymbolInstance->textOpacityState = symbolInstance.textOpacityState;
+ //parentSymbolInstance->iconOpacityState = symbolInstance.iconOpacityState;
// mark child as duplicate so that it doesn't unblock further tiles at lower res
// in the remaining calls to unblockLabels before it's fully removed
diff --git a/src/mbgl/text/placement.cpp b/src/mbgl/text/placement.cpp
new file mode 100644
index 0000000000..af0724bf80
--- /dev/null
+++ b/src/mbgl/text/placement.cpp
@@ -0,0 +1,237 @@
+#include <mbgl/text/placement.hpp>
+#include <mbgl/renderer/render_layer.hpp>
+#include <mbgl/renderer/layers/render_symbol_layer.hpp>
+#include <mbgl/renderer/render_tile.hpp>
+#include <mbgl/tile/geometry_tile.cpp>
+#include <mbgl/renderer/buckets/symbol_bucket.hpp>
+#include <mbgl/renderer/bucket.hpp>
+
+namespace mbgl {
+
+OpacityState::OpacityState(float targetOpacity_) : opacity(0), targetOpacity(targetOpacity_) {}
+
+OpacityState::OpacityState(OpacityState& prevState, float increment, float targetOpacity) :
+ opacity(std::fmax(0, std::fmin(1, prevState.opacity + prevState.targetOpacity == 1.0 ? increment : -increment))),
+ targetOpacity(targetOpacity) {}
+
+bool OpacityState::isHidden() const {
+ return opacity == 0 && targetOpacity == 0;
+}
+
+JointOpacityState::JointOpacityState(float iconOpacity_, float textOpacity_) :
+ icon(OpacityState(iconOpacity_)),
+ text(OpacityState(textOpacity_)) {}
+
+JointOpacityState::JointOpacityState(JointOpacityState& prevOpacityState, float increment, float iconOpacity, float textOpacity) :
+ icon(OpacityState(prevOpacityState.icon, increment, iconOpacity)),
+ text(OpacityState(prevOpacityState.text, increment, textOpacity)) {}
+
+
+Placement::Placement(const TransformState& state_) : collisionIndex(state_), state(state_) {}
+
+void Placement::placeLayer(RenderSymbolLayer& symbolLayer, bool showCollisionBoxes) {
+ for (RenderTile& renderTile : symbolLayer.renderTiles) {
+ if (!renderTile.tile.isRenderable()) {
+ continue;
+ }
+
+ auto bucket = renderTile.tile.getBucket(*symbolLayer.baseImpl);
+ assert(dynamic_cast<SymbolBucket*>(bucket));
+ SymbolBucket& symbolBucket = *reinterpret_cast<SymbolBucket*>(bucket);
+
+ auto& layout = symbolBucket.layout;
+
+ const float pixelsToTileUnits = renderTile.id.pixelsToTileUnits(1, state.getZoom());
+
+ const float scale = std::pow(2, state.getZoom() - renderTile.id.canonical.z);
+
+ mat4 textLabelPlaneMatrix = getLabelPlaneMatrix(renderTile.matrix,
+ layout.get<TextPitchAlignment>() == style::AlignmentType::Map,
+ layout.get<TextRotationAlignment>() == style::AlignmentType::Map,
+ state,
+ pixelsToTileUnits);
+
+ mat4 iconLabelPlaneMatrix = getLabelPlaneMatrix(renderTile.matrix,
+ layout.get<IconPitchAlignment>() == style::AlignmentType::Map,
+ layout.get<IconRotationAlignment>() == style::AlignmentType::Map,
+ state,
+ pixelsToTileUnits);
+
+ placeLayerBucket(symbolLayer, symbolBucket, renderTile.matrix, textLabelPlaneMatrix, iconLabelPlaneMatrix, scale, showCollisionBoxes);
+ }
+}
+
+void Placement::placeLayerBucket(
+ RenderSymbolLayer&,
+ SymbolBucket& bucket,
+ const mat4& posMatrix,
+ const mat4& textLabelPlaneMatrix,
+ const mat4& iconLabelPlaneMatrix,
+ const float scale,
+ const bool showCollisionBoxes) {
+ //assert(dynamic_cast<const SymbolLayer::Impl*>(&*symbolLayer.baseImpl));
+ //const auto& impl = static_cast<const style::SymbolLayer::Impl&>(*symbolLayer.baseImpl);
+
+ // TODO collision debug array clearing
+
+ auto partiallyEvaluatedTextSize = bucket.textSizeBinder->evaluateForZoom(state.getZoom());
+ auto partiallyEvaluatedIconSize = bucket.iconSizeBinder->evaluateForZoom(state.getZoom());
+
+ const bool iconWithoutText = !bucket.hasTextData() || bucket.layout.get<TextOptional>();
+ const bool textWithoutIcon = !bucket.hasIconData() || bucket.layout.get<IconOptional>();
+ float pixelRatio = util::EXTENT / util::tileSize;
+
+ for (auto& symbolInstance : bucket.symbolInstances) {
+
+
+ bool placeText = false;
+ bool placeIcon = false;
+
+ if (!symbolInstance.isDuplicate) {
+
+ if (symbolInstance.placedTextIndices.size()) {
+ assert(symbolInstance.placedTextIndices.size() != 0);
+
+ PlacedSymbol& placedSymbol = bucket.text.placedSymbols.at(symbolInstance.placedTextIndices.at(0));
+ const float fontSize = evaluateSizeForFeature(partiallyEvaluatedTextSize, placedSymbol);
+
+ placeText = collisionIndex.placeFeature(symbolInstance.textCollisionFeature,
+ posMatrix, textLabelPlaneMatrix, pixelRatio,
+ placedSymbol,scale, fontSize,
+ bucket.layout.get<TextAllowOverlap>(),
+ bucket.layout.get<TextPitchAlignment>() == style::AlignmentType::Map,
+ showCollisionBoxes);
+ }
+
+ if (symbolInstance.placedIconIndices.size()) {
+
+ PlacedSymbol& placedSymbol = bucket.icon.placedSymbols.at(symbolInstance.placedIconIndices.at(0));
+ const float fontSize = evaluateSizeForFeature(partiallyEvaluatedIconSize, placedSymbol);
+
+ placeIcon = collisionIndex.placeFeature(symbolInstance.iconCollisionFeature,
+ posMatrix, iconLabelPlaneMatrix, pixelRatio,
+ placedSymbol, scale, fontSize,
+ bucket.layout.get<IconAllowOverlap>(),
+ bucket.layout.get<IconPitchAlignment>() == style::AlignmentType::Map,
+ showCollisionBoxes);
+ }
+
+ // combine placements for icon and text
+ if (!iconWithoutText && !textWithoutIcon) {
+ placeText = placeIcon = placeText && placeIcon;
+ } else if (!textWithoutIcon) {
+ placeText = placeText && placeIcon;
+ } else if (!iconWithoutText) {
+ placeIcon = placeText && placeIcon;
+ }
+
+ if (placeText) {
+ collisionIndex.insertFeature(symbolInstance.textCollisionFeature, bucket.layout.get<TextIgnorePlacement>());
+ }
+
+ if (placeIcon) {
+ collisionIndex.insertFeature(symbolInstance.iconCollisionFeature, bucket.layout.get<IconIgnorePlacement>());
+ }
+
+ if (symbolInstance.crossTileID == 0) {
+ // TODO properly assign these
+ symbolInstance.crossTileID = ++maxCrossTileID;
+ }
+
+ placements.emplace(symbolInstance.crossTileID, PlacementPair(placeText, placeIcon));
+ }
+ }
+}
+
+void Placement::commit(std::unique_ptr<Placement> prevPlacement, TimePoint now) {
+ commitTime = now;
+
+ if (!prevPlacement) {
+ // First time doing placement. Fade in all labels from 0.
+ for (auto& placementPair : placements) {
+ opacities.emplace(placementPair.first, JointOpacityState(placementPair.second.icon, placementPair.second.text));
+ }
+
+ } else {
+ const Duration symbolFadeDuration(300);
+ float increment = (commitTime - prevPlacement->commitTime) / symbolFadeDuration;
+
+ // add the opacities from the current placement, and copy their current values from the previous placement
+ for (auto& placementPair : placements) {
+ auto prevOpacity = prevPlacement->opacities.find(placementPair.first);
+ if (prevOpacity != prevPlacement->opacities.end()) {
+ opacities.emplace(placementPair.first, JointOpacityState(prevOpacity->second, increment, placementPair.second.icon, placementPair.second.text));
+ } else {
+ opacities.emplace(placementPair.first, JointOpacityState(placementPair.second.icon, placementPair.second.text));
+ }
+ }
+
+ // copy and update values from the previous placement that aren't in the current placement but haven't finished fading
+ for (auto& prevOpacity : prevPlacement->opacities) {
+ if (opacities.find(prevOpacity.first) != opacities.end()) {
+ JointOpacityState jointOpacity(prevOpacity.second, increment, 0, 0);
+ if (jointOpacity.icon.opacity != jointOpacity.icon.targetOpacity ||
+ jointOpacity.text.opacity != jointOpacity.text.targetOpacity) {
+ opacities.emplace(prevOpacity.first, jointOpacity);
+ }
+ }
+ }
+ }
+}
+
+void Placement::updateLayerOpacities(RenderSymbolLayer& symbolLayer, gl::Context& context) {
+ for (RenderTile& renderTile : symbolLayer.renderTiles) {
+ if (!renderTile.tile.isRenderable()) {
+ continue;
+ }
+
+ auto bucket = renderTile.tile.getBucket(*symbolLayer.baseImpl);
+ assert(dynamic_cast<SymbolBucket*>(bucket));
+ SymbolBucket& symbolBucket = *reinterpret_cast<SymbolBucket*>(bucket);
+ updateBucketOpacities(symbolBucket, context);
+ }
+}
+
+void Placement::updateBucketOpacities(SymbolBucket& bucket, gl::Context& context) {
+ // TODO check if this clear is necessary, whether the vector has been moved out
+ if (bucket.hasTextData()) bucket.text.opacityVertices.clear();
+ if (bucket.hasIconData()) bucket.icon.opacityVertices.clear();
+
+ for (SymbolInstance& symbolInstance : bucket.symbolInstances) {
+ auto opacityState = getOpacity(symbolInstance.crossTileID);
+
+ // TODO check if hasText is the right thing here, or if there are cases where hasText is true but it's not added to the buffers
+ if (symbolInstance.hasText) {
+ // TODO mark PlacedSymbols as hidden so that they don't need to be projected at render time
+ auto opacityVertex = SymbolOpacityAttributes::vertex(opacityState.text.targetOpacity, opacityState.text.opacity);
+ for (size_t i = 0; i < symbolInstance.glyphQuads.size() * 4; i++) {
+ bucket.text.opacityVertices.emplace_back(opacityVertex);
+ }
+ }
+ if (symbolInstance.hasIcon) {
+ // TODO mark PlacedSymbols as hidden so that they don't need to be projected at render time
+ auto opacityVertex = SymbolOpacityAttributes::vertex(opacityState.icon.targetOpacity, opacityState.icon.opacity);
+ if (symbolInstance.iconQuad) {
+ bucket.icon.opacityVertices.emplace_back(opacityVertex);
+ bucket.icon.opacityVertices.emplace_back(opacityVertex);
+ bucket.icon.opacityVertices.emplace_back(opacityVertex);
+ bucket.icon.opacityVertices.emplace_back(opacityVertex);
+ }
+ }
+ }
+
+ if (bucket.hasTextData()) context.updateVertexBuffer(*bucket.text.opacityVertexBuffer, std::move(bucket.text.opacityVertices));
+ if (bucket.hasIconData()) context.updateVertexBuffer(*bucket.icon.opacityVertexBuffer, std::move(bucket.icon.opacityVertices));
+}
+
+JointOpacityState Placement::getOpacity(uint32_t crossTileSymbolID) const {
+ auto it = opacities.find(crossTileSymbolID);
+ if (it != opacities.end()) {
+ return it->second;
+ } else {
+ return JointOpacityState(0, 0);
+ }
+
+}
+
+} // namespace mbgl
diff --git a/src/mbgl/text/placement.hpp b/src/mbgl/text/placement.hpp
new file mode 100644
index 0000000000..50831e0d1c
--- /dev/null
+++ b/src/mbgl/text/placement.hpp
@@ -0,0 +1,68 @@
+#pragma once
+
+#include <string>
+#include <unordered_map>
+#include <mbgl/util/chrono.hpp>
+#include <mbgl/text/collision_index.hpp>
+#include <mbgl/layout/symbol_projection.hpp>
+
+namespace mbgl {
+
+ class RenderSymbolLayer;
+ class SymbolBucket;
+
+ class OpacityState {
+ public:
+ OpacityState(float targetOpacity);
+ OpacityState(OpacityState& prevOpacityState, float increment, float targetOpacity);
+ float opacity;
+ float targetOpacity;
+
+ bool isHidden() const;
+ };
+
+ class JointOpacityState {
+ public:
+ JointOpacityState(float iconOpacity, float textOpacity);
+ JointOpacityState(JointOpacityState& prevOpacityState, float increment, float iconOpacity, float textOpacity);
+ OpacityState icon;
+ OpacityState text;
+ };
+
+ class PlacementPair {
+ public:
+ PlacementPair(bool text_, bool icon_) : text(text_), icon(icon_) {}
+ bool text;
+ bool icon;
+ };
+
+ class Placement {
+ public:
+ Placement(const TransformState&);
+ void placeLayer(RenderSymbolLayer&, bool showCollisionBoxes);
+ void commit(std::unique_ptr<Placement> prevPlacement, TimePoint);
+ void updateLayerOpacities(RenderSymbolLayer&, gl::Context&);
+ JointOpacityState getOpacity(uint32_t crossTileSymbolID) const;
+
+ private:
+
+ void placeLayerBucket(
+ RenderSymbolLayer&,
+ SymbolBucket&,
+ const mat4& posMatrix,
+ const mat4& textLabelPlaneMatrix,
+ const mat4& iconLabelPlaneMatrix,
+ const float scale,
+ const bool showCollisionBoxes);
+
+ void updateBucketOpacities(SymbolBucket&, gl::Context&);
+
+ CollisionIndex collisionIndex;
+ TransformState state;
+ TimePoint commitTime;
+
+ uint32_t maxCrossTileID = 0;
+ std::unordered_map<uint32_t,PlacementPair> placements;
+ std::unordered_map<uint32_t,JointOpacityState> opacities;
+ };
+} // namespace mbgl
diff --git a/src/mbgl/tile/geometry_tile.hpp b/src/mbgl/tile/geometry_tile.hpp
index a478aad504..23a68c0a1c 100644
--- a/src/mbgl/tile/geometry_tile.hpp
+++ b/src/mbgl/tile/geometry_tile.hpp
@@ -10,6 +10,7 @@
#include <mbgl/util/throttler.hpp>
#include <mbgl/actor/actor.hpp>
#include <mbgl/geometry/feature_index.hpp>
+#include <mbgl/layout/symbol_layout.hpp>
#include <atomic>
#include <memory>
@@ -38,7 +39,7 @@ public:
void setPlacementConfig(const PlacementConfig&) override;
void setLayers(const std::vector<Immutable<style::Layer::Impl>>&) override;
-
+
void onGlyphsAvailable(GlyphMap) override;
void onImagesAvailable(ImageMap, uint64_t imageCorrelationID) override;
@@ -132,6 +133,7 @@ private:
optional<PremultipliedImage> iconAtlasImage;
std::unordered_map<std::string, std::shared_ptr<Bucket>> symbolBuckets;
+ std::unordered_map<std::string, std::unique_ptr<SymbolLayout>> symbolLayouts;
std::unique_ptr<CollisionTile> collisionTile;
float lastYStretch;
diff --git a/src/mbgl/tile/geometry_tile_worker.cpp b/src/mbgl/tile/geometry_tile_worker.cpp
index 50429420c3..1d3c200c8a 100644
--- a/src/mbgl/tile/geometry_tile_worker.cpp
+++ b/src/mbgl/tile/geometry_tile_worker.cpp
@@ -123,12 +123,12 @@ void GeometryTileWorker::setPlacementConfig(PlacementConfig placementConfig_, ui
switch (state) {
case Idle:
- attemptPlacement();
+ //attemptPlacement();
coalesce();
break;
case Coalescing:
- state = NeedPlacement;
+ //state = NeedPlacement;
break;
case NeedPlacement: