From d41bfa26796c955da65cccba48f2d9b697b18abf Mon Sep 17 00:00:00 2001 From: Ansis Brammanis Date: Wed, 20 May 2015 17:52:00 -0400 Subject: [PATCH] redo placement when map rotates --- src/mbgl/map/source.cpp | 8 +++++ src/mbgl/map/source.hpp | 1 + src/mbgl/map/tile_data.cpp | 1 + src/mbgl/map/tile_data.hpp | 3 ++ src/mbgl/map/vector_tile_data.cpp | 47 ++++++++++++++++++++++++++++- src/mbgl/map/vector_tile_data.hpp | 8 +++++ src/mbgl/renderer/bucket.hpp | 3 ++ src/mbgl/renderer/symbol_bucket.cpp | 41 ++++++++++++++++++------- src/mbgl/renderer/symbol_bucket.hpp | 37 ++++++++++++++--------- 9 files changed, 122 insertions(+), 27 deletions(-) diff --git a/src/mbgl/map/source.cpp b/src/mbgl/map/source.cpp index e8dc3468d..7ab089460 100644 --- a/src/mbgl/map/source.cpp +++ b/src/mbgl/map/source.cpp @@ -497,6 +497,8 @@ bool Source::update(MapData& data, updateTilePtrs(); + redoPlacement(transformState); + updated = data.getAnimationTime(); return allTilesUpdated; @@ -518,6 +520,12 @@ void Source::updateTilePtrs() { } } +void Source::redoPlacement(const TransformState& transformState) { + for (auto& tilePtr : tilePtrs) { + tilePtr->data->redoPlacement(transformState.getAngle()); + } +} + void Source::setCacheSize(size_t size) { cache.setSize(size); } diff --git a/src/mbgl/map/source.hpp b/src/mbgl/map/source.hpp index 9d3de81b7..2c5ac85f4 100644 --- a/src/mbgl/map/source.hpp +++ b/src/mbgl/map/source.hpp @@ -101,6 +101,7 @@ public: bool enabled; private: + void redoPlacement(const TransformState& transformState); void emitSourceLoaded(); void emitTileLoaded(bool isNewTile); diff --git a/src/mbgl/map/tile_data.cpp b/src/mbgl/map/tile_data.cpp index e9084bdff..83488ecb9 100644 --- a/src/mbgl/map/tile_data.cpp +++ b/src/mbgl/map/tile_data.cpp @@ -1,6 +1,7 @@ #include #include #include +#include #include #include diff --git a/src/mbgl/map/tile_data.hpp b/src/mbgl/map/tile_data.hpp index 3945a3214..d1ca10ddd 100644 --- a/src/mbgl/map/tile_data.hpp +++ b/src/mbgl/map/tile_data.hpp @@ -21,6 +21,7 @@ class StyleLayer; class Request; class Worker; class WorkRequest; +class TransformState; class TileData : private util::noncopyable { public: @@ -79,6 +80,8 @@ public: virtual void parse() = 0; virtual Bucket* getBucket(StyleLayer const &layer_desc) = 0; + virtual void redoPlacement(float) {} + const TileID id; const std::string name; std::atomic_flag parsing = ATOMIC_FLAG_INIT; diff --git a/src/mbgl/map/vector_tile_data.cpp b/src/mbgl/map/vector_tile_data.cpp index f040422e4..f8a928024 100644 --- a/src/mbgl/map/vector_tile_data.cpp +++ b/src/mbgl/map/vector_tile_data.cpp @@ -8,6 +8,9 @@ #include #include #include +#include +#include +#include using namespace mbgl; @@ -104,6 +107,48 @@ void VectorTileData::setState(const State& state_) { TileData::setState(state_); if (isImmutable()) { - collision.reset(); + collision->reset(0, 0); + } +} + +void VectorTileData::redoPlacement(float angle) { + if (angle != currentAngle) { + lastAngle = angle; + + if (getState() != State::parsed || redoingPlacement) { + redoWhenDone = true; + return; + } + + redoingPlacement = true; + currentAngle = angle; + + auto callback = std::bind(&VectorTileData::endRedoPlacement, this); + workRequest = style.workers.send([this, angle] { workerRedoPlacement(angle); }, callback); + + } +} + +void VectorTileData::workerRedoPlacement(float angle) { + collision->reset(angle, 0); + for (const auto& layer_desc : style.layers) { + auto bucket = getBucket(*layer_desc); + if (bucket) { + bucket->placeFeatures(); + } + } +} + +void VectorTileData::endRedoPlacement() { + for (const auto& layer_desc : style.layers) { + auto bucket = getBucket(*layer_desc); + if (bucket) { + bucket->swapRenderData(); + } + } + redoingPlacement = false; + if (redoWhenDone) { + redoPlacement(lastAngle); + redoWhenDone = false; } } diff --git a/src/mbgl/map/vector_tile_data.hpp b/src/mbgl/map/vector_tile_data.hpp index 09a6330ed..2cf419079 100644 --- a/src/mbgl/map/vector_tile_data.hpp +++ b/src/mbgl/map/vector_tile_data.hpp @@ -43,6 +43,7 @@ public: ~VectorTileData(); void parse() override; + void redoPlacement(float angle) override; virtual Bucket* getBucket(StyleLayer const &layer_desc) override; size_t countBuckets() const; @@ -81,6 +82,13 @@ private: mutable std::mutex bucketsMutex; std::unique_ptr collision; + + float lastAngle = 0; + float currentAngle = 0; + bool redoingPlacement = false; + bool redoWhenDone = false; + void endRedoPlacement(); + void workerRedoPlacement(float angle); }; } diff --git a/src/mbgl/renderer/bucket.hpp b/src/mbgl/renderer/bucket.hpp index 711fc4238..147895a09 100644 --- a/src/mbgl/renderer/bucket.hpp +++ b/src/mbgl/renderer/bucket.hpp @@ -27,6 +27,9 @@ public: return !uploaded; } + virtual void placeFeatures() {} + virtual void swapRenderData() {} + protected: bool uploaded = false; diff --git a/src/mbgl/renderer/symbol_bucket.cpp b/src/mbgl/renderer/symbol_bucket.cpp index a14f9a7a4..6995d7a04 100644 --- a/src/mbgl/renderer/symbol_bucket.cpp +++ b/src/mbgl/renderer/symbol_bucket.cpp @@ -63,12 +63,12 @@ SymbolBucket::~SymbolBucket() { void SymbolBucket::upload() { if (hasTextData()) { - text.vertices.upload(); - text.triangles.upload(); + renderData->text.vertices.upload(); + renderData->text.triangles.upload(); } if (hasIconData()) { - icon.vertices.upload(); - icon.triangles.upload(); + renderData->icon.vertices.upload(); + renderData->icon.triangles.upload(); } uploaded = true; @@ -83,11 +83,11 @@ void SymbolBucket::render(Painter& painter, bool SymbolBucket::hasData() const { return hasTextData() || hasIconData(); } -bool SymbolBucket::hasTextData() const { return !text.groups.empty(); } +bool SymbolBucket::hasTextData() const { return renderData && !renderData->text.groups.empty(); } -bool SymbolBucket::hasIconData() const { return !icon.groups.empty(); } +bool SymbolBucket::hasIconData() const { return renderData && !renderData->icon.groups.empty(); } -bool SymbolBucket::hasCollisionBoxData() const { return !collisionBox.groups.empty(); } +bool SymbolBucket::hasCollisionBoxData() const { return renderData && !renderData->collisionBox.groups.empty(); } bool SymbolBucket::needsDependencies(const GeometryTileLayer& layer, const FilterExpression& filter, @@ -263,7 +263,7 @@ void SymbolBucket::addFeatures(uintptr_t tileUID, features.clear(); - placeFeatures(); + placeFeatures(true); } @@ -317,6 +317,12 @@ void SymbolBucket::addFeature(const std::vector> &lines, } void SymbolBucket::placeFeatures() { + placeFeatures(false); +} + +void SymbolBucket::placeFeatures(bool swapImmediately) { + + renderDataInProgress = util::make_unique(); // Calculate which labels can be shown and when they can be shown and // create the bufers used for rendering. @@ -363,7 +369,8 @@ void SymbolBucket::placeFeatures() { collision.insertFeature(symbolInstance.textCollisionFeature, glyphScale); } if (glyphScale < collision.maxScale) { - addSymbols(text, symbolInstance.glyphQuads, glyphScale, layout.text.keep_upright, textAlongLine); + addSymbols(renderDataInProgress->text, + symbolInstance.glyphQuads, glyphScale, layout.text.keep_upright, textAlongLine); } } @@ -372,12 +379,15 @@ void SymbolBucket::placeFeatures() { collision.insertFeature(symbolInstance.iconCollisionFeature, iconScale); } if (iconScale < collision.maxScale) { - addSymbols(icon, symbolInstance.iconQuads, iconScale, layout.icon.keep_upright, iconAlongLine); + addSymbols(renderDataInProgress->icon, + symbolInstance.iconQuads, iconScale, layout.icon.keep_upright, iconAlongLine); } } } addToDebugBuffers(); + + if (swapImmediately) swapRenderData(); } template @@ -448,7 +458,7 @@ void SymbolBucket::addSymbols(Buffer &buffer, const SymbolQuads &symbols, float void SymbolBucket::addToDebugBuffers() { const float yStretch = 1.0f; - const float angle = 0.0f; + const float angle = collision.angle; const float zoom = collision.zoom; float angle_sin = std::sin(-angle); float angle_cos = std::cos(-angle); @@ -475,6 +485,7 @@ void SymbolBucket::addToDebugBuffers() { const float maxZoom = util::max(0.0f, util::min(25.0f, static_cast(zoom + log(box.maxScale) / log(2)))); const float placementZoom= util::max(0.0f, util::min(25.0f, static_cast(zoom + log(box.placementScale) / log(2)))); + auto& collisionBox = renderDataInProgress->collisionBox; if (!collisionBox.groups.size()) { // Move to a new group because the old one can't hold the geometry. collisionBox.groups.emplace_back(util::make_unique()); @@ -496,9 +507,14 @@ void SymbolBucket::addToDebugBuffers() { } } +void SymbolBucket::swapRenderData() { + renderData = std::move(renderDataInProgress); +} + void SymbolBucket::drawGlyphs(SDFShader &shader) { char *vertex_index = BUFFER_OFFSET(0); char *elements_index = BUFFER_OFFSET(0); + auto& text = renderData->text; for (auto &group : text.groups) { assert(group); group->array[0].bind(shader, text.vertices, text.triangles, vertex_index); @@ -511,6 +527,7 @@ void SymbolBucket::drawGlyphs(SDFShader &shader) { void SymbolBucket::drawIcons(SDFShader &shader) { char *vertex_index = BUFFER_OFFSET(0); char *elements_index = BUFFER_OFFSET(0); + auto& icon = renderData->icon; for (auto &group : icon.groups) { assert(group); group->array[0].bind(shader, icon.vertices, icon.triangles, vertex_index); @@ -523,6 +540,7 @@ void SymbolBucket::drawIcons(SDFShader &shader) { void SymbolBucket::drawIcons(IconShader &shader) { char *vertex_index = BUFFER_OFFSET(0); char *elements_index = BUFFER_OFFSET(0); + auto& icon = renderData->icon; for (auto &group : icon.groups) { assert(group); group->array[1].bind(shader, icon.vertices, icon.triangles, vertex_index); @@ -534,6 +552,7 @@ void SymbolBucket::drawIcons(IconShader &shader) { void SymbolBucket::drawCollisionBoxes(CollisionBoxShader &shader) { char *vertex_index = BUFFER_OFFSET(0); + auto& collisionBox = renderData->collisionBox; for (auto &group : collisionBox.groups) { group->array[0].bind(shader, collisionBox.vertices, vertex_index); MBGL_CHECK_ERROR(glDrawArrays(GL_LINES, 0, group->vertex_length)); diff --git a/src/mbgl/renderer/symbol_bucket.hpp b/src/mbgl/renderer/symbol_bucket.hpp index fb696b03b..43d91bf41 100644 --- a/src/mbgl/renderer/symbol_bucket.hpp +++ b/src/mbgl/renderer/symbol_bucket.hpp @@ -87,15 +87,18 @@ public: const FilterExpression&, GlyphStore&, Sprite&); + void placeFeatures(); private: void addFeature(const std::vector> &lines, const Shaping &shapedText, const PositionedIcon &shapedIcon, const GlyphPositions &face); - void placeFeatures(); void addToDebugBuffers(); + void placeFeatures(bool swapImmediately); + void swapRenderData(); + // Adds placed items to the buffer. template void addSymbols(Buffer &buffer, const SymbolQuads &symbols, float scale, const bool keepUpright, const bool alongLine); @@ -109,23 +112,27 @@ private: std::vector symbolInstances; std::vector features; - struct TextBuffer { - TextVertexBuffer vertices; - TriangleElementsBuffer triangles; - std::vector> groups; - } text; + struct SymbolRenderData { + struct TextBuffer { + TextVertexBuffer vertices; + TriangleElementsBuffer triangles; + std::vector> groups; + } text; - struct IconBuffer { - IconVertexBuffer vertices; - TriangleElementsBuffer triangles; - std::vector> groups; - } icon; + struct IconBuffer { + IconVertexBuffer vertices; + TriangleElementsBuffer triangles; + std::vector> groups; + } icon; - struct CollisionBoxBuffer { - CollisionBoxVertexBuffer vertices; - std::vector> groups; - } collisionBox; + struct CollisionBoxBuffer { + CollisionBoxVertexBuffer vertices; + std::vector> groups; + } collisionBox; + }; + std::unique_ptr renderData; + std::unique_ptr renderDataInProgress; }; }