summaryrefslogtreecommitdiff
path: root/src/mbgl/renderer/buckets/symbol_bucket.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'src/mbgl/renderer/buckets/symbol_bucket.cpp')
-rw-r--r--src/mbgl/renderer/buckets/symbol_bucket.cpp83
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