1 #include <mbgl/renderer/buckets/symbol_bucket.hpp>
2 #include <mbgl/renderer/layers/render_symbol_layer.hpp>
3 #include <mbgl/renderer/bucket_parameters.hpp>
4 #include <mbgl/style/layers/symbol_layer_impl.hpp>
5 #include <mbgl/text/glyph_atlas.hpp>
6 
7 namespace mbgl {
8 
9 using namespace style;
10 
SymbolBucket(style::SymbolLayoutProperties::PossiblyEvaluated layout_,const std::map<std::string,std::pair<style::IconPaintProperties::PossiblyEvaluated,style::TextPaintProperties::PossiblyEvaluated>> & layerPaintProperties,const style::DataDrivenPropertyValue<float> & textSize,const style::DataDrivenPropertyValue<float> & iconSize,float zoom,bool sdfIcons_,bool iconsNeedLinear_,bool sortFeaturesByY_,const std::string bucketName_,const std::vector<SymbolInstance> && symbolInstances_)11 SymbolBucket::SymbolBucket(style::SymbolLayoutProperties::PossiblyEvaluated layout_,
12                            const std::map<std::string, std::pair<
13                                style::IconPaintProperties::PossiblyEvaluated,
14                                style::TextPaintProperties::PossiblyEvaluated>>& layerPaintProperties,
15                            const style::DataDrivenPropertyValue<float>& textSize,
16                            const style::DataDrivenPropertyValue<float>& iconSize,
17                            float zoom,
18                            bool sdfIcons_,
19                            bool iconsNeedLinear_,
20                            bool sortFeaturesByY_,
21                            const std::string bucketName_,
22                            const std::vector<SymbolInstance>&& symbolInstances_)
23     : Bucket(LayerType::Symbol),
24       layout(std::move(layout_)),
25       sdfIcons(sdfIcons_),
26       iconsNeedLinear(iconsNeedLinear_ || iconSize.isDataDriven() || !iconSize.isZoomConstant()),
27       sortFeaturesByY(sortFeaturesByY_),
28       bucketLeaderID(std::move(bucketName_)),
29       symbolInstances(std::move(symbolInstances_)),
30       textSizeBinder(SymbolSizeBinder::create(zoom, textSize, TextSize::defaultValue())),
31       iconSizeBinder(SymbolSizeBinder::create(zoom, iconSize, IconSize::defaultValue())) {
32 
33     for (const auto& pair : layerPaintProperties) {
34         paintPropertyBinders.emplace(
35             std::piecewise_construct,
36             std::forward_as_tuple(pair.first),
37             std::forward_as_tuple(
38                 std::piecewise_construct,
39                 std::forward_as_tuple(pair.second.first, zoom),
40                 std::forward_as_tuple(pair.second.second, zoom)));
41     }
42 }
43 
upload(gl::Context & context)44 void SymbolBucket::upload(gl::Context& context) {
45     if (hasTextData()) {
46         if (!staticUploaded) {
47             text.indexBuffer = context.createIndexBuffer(std::move(text.triangles), sortFeaturesByY ? gl::BufferUsage::StreamDraw : gl::BufferUsage::StaticDraw);
48             text.vertexBuffer = context.createVertexBuffer(std::move(text.vertices));
49         } else if (!sortUploaded) {
50             context.updateIndexBuffer(*text.indexBuffer, std::move(text.triangles));
51         }
52 
53         if (!dynamicUploaded) {
54             text.dynamicVertexBuffer = context.createVertexBuffer(std::move(text.dynamicVertices), gl::BufferUsage::StreamDraw);
55         }
56         if (!placementChangesUploaded) {
57             if (!text.opacityVertexBuffer) {
58                 text.opacityVertexBuffer = context.createVertexBuffer(std::move(text.opacityVertices), gl::BufferUsage::StreamDraw);
59             } else {
60                 context.updateVertexBuffer(*text.opacityVertexBuffer, std::move(text.opacityVertices));
61             }
62         }
63     }
64 
65     if (hasIconData()) {
66         if (!staticUploaded) {
67             icon.indexBuffer = context.createIndexBuffer(std::move(icon.triangles), sortFeaturesByY ? gl::BufferUsage::StreamDraw : gl::BufferUsage::StaticDraw);
68             icon.vertexBuffer = context.createVertexBuffer(std::move(icon.vertices));
69         } else if (!sortUploaded) {
70             context.updateIndexBuffer(*icon.indexBuffer, std::move(icon.triangles));
71         }
72         if (!dynamicUploaded) {
73             icon.dynamicVertexBuffer = context.createVertexBuffer(std::move(icon.dynamicVertices), gl::BufferUsage::StreamDraw);
74         }
75         if (!placementChangesUploaded) {
76             if (!icon.opacityVertexBuffer) {
77                 icon.opacityVertexBuffer = context.createVertexBuffer(std::move(icon.opacityVertices), gl::BufferUsage::StreamDraw);
78             } else {
79                 context.updateVertexBuffer(*icon.opacityVertexBuffer, std::move(icon.opacityVertices));
80             }
81         }
82     }
83 
84     if (hasCollisionBoxData()) {
85         if (!staticUploaded) {
86             collisionBox.indexBuffer = context.createIndexBuffer(std::move(collisionBox.lines));
87             collisionBox.vertexBuffer = context.createVertexBuffer(std::move(collisionBox.vertices));
88         }
89         if (!placementChangesUploaded) {
90             if (!collisionBox.dynamicVertexBuffer) {
91                 collisionBox.dynamicVertexBuffer = context.createVertexBuffer(std::move(collisionBox.dynamicVertices), gl::BufferUsage::StreamDraw);
92             } else {
93                 context.updateVertexBuffer(*collisionBox.dynamicVertexBuffer, std::move(collisionBox.dynamicVertices));
94             }
95         }
96     }
97 
98     if (hasCollisionCircleData()) {
99         if (!staticUploaded) {
100             collisionCircle.indexBuffer = context.createIndexBuffer(std::move(collisionCircle.triangles));
101             collisionCircle.vertexBuffer = context.createVertexBuffer(std::move(collisionCircle.vertices));
102         }
103         if (!placementChangesUploaded) {
104             if (!collisionCircle.dynamicVertexBuffer) {
105                 collisionCircle.dynamicVertexBuffer = context.createVertexBuffer(std::move(collisionCircle.dynamicVertices), gl::BufferUsage::StreamDraw);
106             } else {
107                 context.updateVertexBuffer(*collisionCircle.dynamicVertexBuffer, std::move(collisionCircle.dynamicVertices));
108             }
109         }
110     }
111 
112     if (!staticUploaded) {
113         for (auto& pair : paintPropertyBinders) {
114             pair.second.first.upload(context);
115             pair.second.second.upload(context);
116         }
117     }
118 
119     uploaded = true;
120     staticUploaded = true;
121     placementChangesUploaded = true;
122     dynamicUploaded = true;
123     sortUploaded = true;
124 }
125 
hasData() const126 bool SymbolBucket::hasData() const {
127     return hasTextData() || hasIconData() || hasCollisionBoxData();
128 }
129 
hasTextData() const130 bool SymbolBucket::hasTextData() const {
131     return !text.segments.empty();
132 }
133 
hasIconData() const134 bool SymbolBucket::hasIconData() const {
135     return !icon.segments.empty();
136 }
137 
hasCollisionBoxData() const138 bool SymbolBucket::hasCollisionBoxData() const {
139     return !collisionBox.segments.empty();
140 }
141 
hasCollisionCircleData() const142 bool SymbolBucket::hasCollisionCircleData() const {
143     return !collisionCircle.segments.empty();
144 }
145 
updateOpacity()146 void SymbolBucket::updateOpacity() {
147     placementChangesUploaded = false;
148     uploaded = false;
149 }
150 
addPlacedSymbol(gl::IndexVector<gl::Triangles> & triangles,const PlacedSymbol & placedSymbol)151 void addPlacedSymbol(gl::IndexVector<gl::Triangles>& triangles, const PlacedSymbol& placedSymbol) {
152     auto endIndex = placedSymbol.vertexStartIndex + placedSymbol.glyphOffsets.size() * 4;
153     for (auto vertexIndex = placedSymbol.vertexStartIndex; vertexIndex < endIndex; vertexIndex += 4) {
154         triangles.emplace_back(vertexIndex + 0, vertexIndex + 1, vertexIndex + 2);
155         triangles.emplace_back(vertexIndex + 1, vertexIndex + 2, vertexIndex + 3);
156     }
157 }
158 
sortFeatures(const float angle)159 void SymbolBucket::sortFeatures(const float angle) {
160     if (!sortFeaturesByY) {
161         return;
162     }
163 
164     if (sortedAngle && *sortedAngle == angle) {
165         return;
166     }
167 
168     sortedAngle = angle;
169 
170     // The current approach to sorting doesn't sort across segments so don't try.
171     // Sorting within segments separately seemed not to be worth the complexity.
172     if (text.segments.size() > 1 || icon.segments.size() > 1) {
173         return;
174     }
175 
176     sortUploaded = false;
177     uploaded = false;
178 
179     // If the symbols are allowed to overlap sort them by their vertical screen position.
180     // The index array buffer is rewritten to reference the (unchanged) vertices in the
181     // sorted order.
182 
183     // To avoid sorting the actual symbolInstance array we sort an array of indexes.
184     std::vector<size_t> symbolInstanceIndexes;
185     symbolInstanceIndexes.reserve(symbolInstances.size());
186     for (size_t i = 0; i < symbolInstances.size(); i++) {
187         symbolInstanceIndexes.push_back(i);
188     }
189 
190     const float sin = std::sin(angle);
191     const float cos = std::cos(angle);
192 
193     std::sort(symbolInstanceIndexes.begin(), symbolInstanceIndexes.end(), [sin, cos, this](size_t &aIndex, size_t &bIndex) {
194         const SymbolInstance& a = symbolInstances[aIndex];
195         const SymbolInstance& b = symbolInstances[bIndex];
196         const int32_t aRotated = static_cast<int32_t>(::lround(sin * a.anchor.point.x + cos * a.anchor.point.y));
197         const int32_t bRotated = static_cast<int32_t>(::lround(sin * b.anchor.point.x + cos * b.anchor.point.y));
198         return aRotated != bRotated ?
199             aRotated < bRotated :
200             a.dataFeatureIndex > b.dataFeatureIndex;
201     });
202 
203     text.triangles.clear();
204     icon.triangles.clear();
205 
206     featureSortOrder = std::make_unique<std::vector<size_t>>();
207     featureSortOrder->reserve(symbolInstanceIndexes.size());
208 
209     for (auto i : symbolInstanceIndexes) {
210         const SymbolInstance& symbolInstance = symbolInstances[i];
211         featureSortOrder->push_back(symbolInstance.dataFeatureIndex);
212 
213         if (symbolInstance.placedTextIndex) {
214             addPlacedSymbol(text.triangles, text.placedSymbols[*symbolInstance.placedTextIndex]);
215         }
216         if (symbolInstance.placedVerticalTextIndex) {
217             addPlacedSymbol(text.triangles, text.placedSymbols[*symbolInstance.placedVerticalTextIndex]);
218         }
219         if (symbolInstance.placedIconIndex) {
220             addPlacedSymbol(icon.triangles, icon.placedSymbols[*symbolInstance.placedIconIndex]);
221         }
222     }
223 }
224 
225 } // namespace mbgl
226