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