From 7d028513949a77705a0d706bbfa58f5c4e2e0f8f Mon Sep 17 00:00:00 2001 From: Ansis Brammanis Date: Thu, 5 Oct 2017 12:54:23 -0400 Subject: start running new placement [skip ci] --- cmake/core-files.cmake | 4 +- src/mbgl/layout/symbol_instance.cpp | 4 +- src/mbgl/layout/symbol_instance.hpp | 16 +- src/mbgl/layout/symbol_layout.cpp | 11 +- src/mbgl/layout/symbol_layout.hpp | 5 +- src/mbgl/layout/symbol_projection.hpp | 1 + src/mbgl/renderer/buckets/symbol_bucket.cpp | 6 +- src/mbgl/renderer/buckets/symbol_bucket.hpp | 6 +- src/mbgl/renderer/placement_state.cpp | 103 ------------ src/mbgl/renderer/placement_state.hpp | 70 -------- src/mbgl/renderer/render_layer.hpp | 6 +- src/mbgl/renderer/renderer_impl.cpp | 38 +++-- src/mbgl/text/cross_tile_symbol_index.cpp | 12 +- src/mbgl/text/placement.cpp | 237 ++++++++++++++++++++++++++++ src/mbgl/text/placement.hpp | 68 ++++++++ src/mbgl/tile/geometry_tile.hpp | 4 +- src/mbgl/tile/geometry_tile_worker.cpp | 4 +- 17 files changed, 369 insertions(+), 226 deletions(-) delete mode 100644 src/mbgl/renderer/placement_state.cpp delete mode 100644 src/mbgl/renderer/placement_state.hpp create mode 100644 src/mbgl/text/placement.cpp create mode 100644 src/mbgl/text/placement.hpp 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 #include + 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 iconOffset; std::u16string key; bool isDuplicate; - OpacityState iconOpacityState; - OpacityState textOpacityState; + bool placedText; + bool placedIcon; + std::vector placedTextIndices; // TODO clean this up + std::vector 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 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 SymbolLayout::place(CollisionTile& collisionTile) { - auto bucket = std::make_unique(layout, layerPaintProperties, textSize, iconSize, zoom, sdfIcons, iconsNeedLinear); + auto bucket = std::make_unique(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 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 SymbolLayout::place(CollisionTile& collisionTile) const Range 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 SymbolLayout::place(CollisionTile& collisionTile) const Range 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> layerPaintProperties; + const std::string bucketName; + std::vector 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 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 symbolInstances; std::vector 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; }; + 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& iconSize, float zoom, bool sdfIcons_, - bool iconsNeedLinear_) + bool iconsNeedLinear_, + const std::vector& 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 #include #include +#include #include @@ -49,7 +50,8 @@ public: const style::DataDrivenPropertyValue& iconSize, float zoom, bool sdfIcons, - bool iconsNeedLinear); + bool iconsNeedLinear, + const std::vector&); void upload(gl::Context&) override; bool hasData() const override; @@ -61,6 +63,8 @@ public: const bool sdfIcons; const bool iconsNeedLinear; + std::vector symbolInstances; + std::map> 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 -#include -#include -#include -#include -#include - - -namespace mbgl { - -LayerPlacementState::LayerPlacementState() : currentTileIndex(0) -{ -} - -bool LayerPlacementState::continuePlacement(RenderSymbolLayer& layer, - CollisionIndex& collisionIndex, - const bool showCollisionBoxes, - std::function 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& order, - const bool forceFullPlacement_, - const bool showCollisionBoxes_, - Duration fadeDuration, - optional& 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& order, std::vector& 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()) { - if (inProgressLayer) { - inProgressLayer = LayerPlacementState(); - } - - bool pausePlacement = inProgressLayer->continuePlacement(*renderLayer.as(), - 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 -#include -#include -#include -#include -#include - -#include -#include -#include - -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 shouldPausePlacement); - -private: - size_t currentTileIndex; -}; - -class PlacementState -{ -public: - PlacementState(const TransformState& transformState, - const std::vector& order, - const bool forceFullPlacement, - const bool showCollisionBoxes, - Duration fadeDuration, - optional& previousPlacement); - - bool isDone() const { return done; } - bool stillFading() const; - - void continuePlacement(std::vector& order, std::vector& sources); - -private: - CollisionIndex collisionIndex; - bool done; - size_t currentLayerIndex; - bool forceFullPlacement; - bool showCollisionBoxes; - TimePoint delayUntil; - CollisionFadeTimes collisionFadeTimes; - optional 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> 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> 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 #include #include +#include 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()) { + bool showCollisionBoxes = false; // TODO + placement.placeLayer(*it->layer.as(), showCollisionBoxes); + } + } + + std::unique_ptr 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()) { + placement.updateLayerOpacities(*it->layer.as(), 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_ptrtextOpacityState; - 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 +#include +#include +#include +#include +#include +#include + +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(bucket)); + SymbolBucket& symbolBucket = *reinterpret_cast(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() == style::AlignmentType::Map, + layout.get() == style::AlignmentType::Map, + state, + pixelsToTileUnits); + + mat4 iconLabelPlaneMatrix = getLabelPlaneMatrix(renderTile.matrix, + layout.get() == style::AlignmentType::Map, + layout.get() == 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(&*symbolLayer.baseImpl)); + //const auto& impl = static_cast(*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(); + const bool textWithoutIcon = !bucket.hasIconData() || bucket.layout.get(); + 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(), + bucket.layout.get() == 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(), + bucket.layout.get() == 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()); + } + + if (placeIcon) { + collisionIndex.insertFeature(symbolInstance.iconCollisionFeature, bucket.layout.get()); + } + + if (symbolInstance.crossTileID == 0) { + // TODO properly assign these + symbolInstance.crossTileID = ++maxCrossTileID; + } + + placements.emplace(symbolInstance.crossTileID, PlacementPair(placeText, placeIcon)); + } + } +} + +void Placement::commit(std::unique_ptr 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(bucket)); + SymbolBucket& symbolBucket = *reinterpret_cast(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 +#include +#include +#include +#include + +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 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 placements; + std::unordered_map 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 #include #include +#include #include #include @@ -38,7 +39,7 @@ public: void setPlacementConfig(const PlacementConfig&) override; void setLayers(const std::vector>&) override; - + void onGlyphsAvailable(GlyphMap) override; void onImagesAvailable(ImageMap, uint64_t imageCorrelationID) override; @@ -132,6 +133,7 @@ private: optional iconAtlasImage; std::unordered_map> symbolBuckets; + std::unordered_map> symbolLayouts; std::unique_ptr 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: -- cgit v1.2.1