diff options
Diffstat (limited to 'src/mbgl/renderer/buckets/symbol_bucket.cpp')
-rw-r--r-- | src/mbgl/renderer/buckets/symbol_bucket.cpp | 83 |
1 files changed, 80 insertions, 3 deletions
diff --git a/src/mbgl/renderer/buckets/symbol_bucket.cpp b/src/mbgl/renderer/buckets/symbol_bucket.cpp index 592c29eb15..cf8120739a 100644 --- a/src/mbgl/renderer/buckets/symbol_bucket.cpp +++ b/src/mbgl/renderer/buckets/symbol_bucket.cpp @@ -17,10 +17,12 @@ SymbolBucket::SymbolBucket(style::SymbolLayoutProperties::PossiblyEvaluated layo float zoom, bool sdfIcons_, bool iconsNeedLinear_, + bool sortFeaturesByY_, const std::vector<SymbolInstance>& symbolInstances_) : layout(std::move(layout_)), sdfIcons(sdfIcons_), iconsNeedLinear(iconsNeedLinear_ || iconSize.isDataDriven() || !iconSize.isZoomConstant()), + sortFeaturesByY(sortFeaturesByY_), symbolInstances(symbolInstances_), // TODO maybe not copy textSizeBinder(SymbolSizeBinder::create(zoom, textSize, TextSize::defaultValue())), iconSizeBinder(SymbolSizeBinder::create(zoom, iconSize, IconSize::defaultValue())) { @@ -39,9 +41,12 @@ SymbolBucket::SymbolBucket(style::SymbolLayoutProperties::PossiblyEvaluated layo void SymbolBucket::upload(gl::Context& context) { if (hasTextData()) { if (!staticUploaded) { - text.indexBuffer = context.createIndexBuffer(std::move(text.triangles)); + text.indexBuffer = context.createIndexBuffer(std::move(text.triangles), sortFeaturesByY ? gl::BufferUsage::StreamDraw : gl::BufferUsage::StaticDraw); text.vertexBuffer = context.createVertexBuffer(std::move(text.vertices)); + } else if (!sortUploaded) { + context.updateIndexBuffer(*text.indexBuffer, std::move(text.triangles)); } + if (!dynamicUploaded) { text.dynamicVertexBuffer = context.createVertexBuffer(std::move(text.dynamicVertices), gl::BufferUsage::StreamDraw); } @@ -56,8 +61,10 @@ void SymbolBucket::upload(gl::Context& context) { if (hasIconData()) { if (!staticUploaded) { - icon.indexBuffer = context.createIndexBuffer(std::move(icon.triangles)); + icon.indexBuffer = context.createIndexBuffer(std::move(icon.triangles), sortFeaturesByY ? gl::BufferUsage::StreamDraw : gl::BufferUsage::StaticDraw); icon.vertexBuffer = context.createVertexBuffer(std::move(icon.vertices)); + } else if (!sortUploaded) { + context.updateIndexBuffer(*icon.indexBuffer, std::move(icon.triangles)); } if (!dynamicUploaded) { icon.dynamicVertexBuffer = context.createVertexBuffer(std::move(icon.dynamicVertices), gl::BufferUsage::StreamDraw); @@ -105,11 +112,12 @@ void SymbolBucket::upload(gl::Context& context) { pair.second.second.upload(context); } } - + uploaded = true; staticUploaded = true; opacityUploaded = true; dynamicUploaded = true; + sortUploaded = true; } bool SymbolBucket::hasData() const { @@ -137,4 +145,73 @@ void SymbolBucket::updateOpacity() { uploaded = false; } +void SymbolBucket::sortFeatures(const float angle) { + if (!sortFeaturesByY) { + return; + } + + if (sortedAngle == angle) { + return; + } + + sortedAngle = angle; + + // The current approach to sorting doesn't sort across segments so don't try. + // Sorting within segments separately seemed not to be worth the complexity. + if (text.segments.size() > 1 || icon.segments.size() > 1) { + return; + } + + sortUploaded = false; + uploaded = false; + + // If the symbols are allowed to overlap sort them by their vertical screen position. + // The index array buffer is rewritten to reference the (unchanged) vertices in the + // sorted order. + + // To avoid sorting the actual symbolInstance array we sort an array of indexes. + std::vector<size_t> symbolInstanceIndexes; + for (size_t i = 0; i < symbolInstances.size(); i++) { + symbolInstanceIndexes.push_back(i); + } + + const float sin = std::sin(angle); + const float cos = std::cos(angle); + + std::sort(symbolInstanceIndexes.begin(), symbolInstanceIndexes.end(), [sin, cos, this](size_t &aIndex, size_t &bIndex) { + const SymbolInstance& a = symbolInstances[aIndex]; + const SymbolInstance& b = symbolInstances[bIndex]; + const int32_t aRotated = sin * a.anchor.point.x + cos * a.anchor.point.y; + const int32_t bRotated = sin * b.anchor.point.x + cos * b.anchor.point.y; + return aRotated != bRotated ? + aRotated < bRotated : + a.index > b.index; + }); + + text.triangles.clear(); + icon.triangles.clear(); + + for (auto i : symbolInstanceIndexes) { + const SymbolInstance& symbolInstance = symbolInstances[i]; + + for (auto& placedTextSymbolIndex : symbolInstance.placedTextIndices) { + const PlacedSymbol& placedSymbol = text.placedSymbols[placedTextSymbolIndex]; + + auto endIndex = placedSymbol.vertexStartIndex + placedSymbol.glyphOffsets.size() * 4; + for (auto vertexIndex = placedSymbol.vertexStartIndex; vertexIndex < endIndex; vertexIndex += 4) { + text.triangles.emplace_back(vertexIndex + 0, vertexIndex + 1, vertexIndex + 2); + text.triangles.emplace_back(vertexIndex + 1, vertexIndex + 2, vertexIndex + 3); + } + } + + for (auto& placedIconSymbolIndex : symbolInstance.placedIconIndices) { // TODO: This iteration is an awkward way to say "if the symbol has an icon" + const PlacedSymbol& placedIcon = icon.placedSymbols[placedIconSymbolIndex]; + + const auto vertexIndex = placedIcon.vertexStartIndex; + icon.triangles.emplace_back(vertexIndex + 0, vertexIndex + 1, vertexIndex + 2); + icon.triangles.emplace_back(vertexIndex + 1, vertexIndex + 2, vertexIndex + 3); + } + } +} + } // namespace mbgl |