1 #include <mbgl/renderer/layers/render_symbol_layer.hpp>
2 #include <mbgl/renderer/buckets/symbol_bucket.hpp>
3 #include <mbgl/renderer/bucket_parameters.hpp>
4 #include <mbgl/renderer/property_evaluation_parameters.hpp>
5 #include <mbgl/renderer/render_tile.hpp>
6 #include <mbgl/renderer/paint_parameters.hpp>
7 #include <mbgl/text/glyph_atlas.hpp>
8 #include <mbgl/programs/programs.hpp>
9 #include <mbgl/programs/symbol_program.hpp>
10 #include <mbgl/programs/collision_box_program.hpp>
11 #include <mbgl/tile/tile.hpp>
12 #include <mbgl/tile/geometry_tile.hpp>
13 #include <mbgl/tile/geometry_tile_data.hpp>
14 #include <mbgl/style/layers/symbol_layer_impl.hpp>
15 #include <mbgl/layout/symbol_layout.hpp>
16 #include <mbgl/layout/symbol_projection.hpp>
17 #include <mbgl/util/math.hpp>
18 
19 #include <cmath>
20 
21 namespace mbgl {
22 
23 using namespace style;
24 
RenderSymbolLayer(Immutable<style::SymbolLayer::Impl> _impl)25 RenderSymbolLayer::RenderSymbolLayer(Immutable<style::SymbolLayer::Impl> _impl)
26     : RenderLayer(style::LayerType::Symbol, _impl),
27       unevaluated(impl().paint.untransitioned()) {
28 }
29 
impl() const30 const style::SymbolLayer::Impl& RenderSymbolLayer::impl() const {
31     return static_cast<const style::SymbolLayer::Impl&>(*baseImpl);
32 }
33 
createBucket(const BucketParameters &,const std::vector<const RenderLayer * > &) const34 std::unique_ptr<Bucket> RenderSymbolLayer::createBucket(const BucketParameters&, const std::vector<const RenderLayer*>&) const {
35     assert(false); // Should be calling createLayout() instead.
36     return nullptr;
37 }
38 
createLayout(const BucketParameters & parameters,const std::vector<const RenderLayer * > & group,std::unique_ptr<GeometryTileLayer> layer,GlyphDependencies & glyphDependencies,ImageDependencies & imageDependencies) const39 std::unique_ptr<SymbolLayout> RenderSymbolLayer::createLayout(const BucketParameters& parameters,
40                                                               const std::vector<const RenderLayer*>& group,
41                                                               std::unique_ptr<GeometryTileLayer> layer,
42                                                               GlyphDependencies& glyphDependencies,
43                                                               ImageDependencies& imageDependencies) const {
44     return std::make_unique<SymbolLayout>(parameters,
45                                           group,
46                                           std::move(layer),
47                                           imageDependencies,
48                                           glyphDependencies);
49 }
50 
transition(const TransitionParameters & parameters)51 void RenderSymbolLayer::transition(const TransitionParameters& parameters) {
52     unevaluated = impl().paint.transitioned(parameters, std::move(unevaluated));
53 }
54 
evaluate(const PropertyEvaluationParameters & parameters)55 void RenderSymbolLayer::evaluate(const PropertyEvaluationParameters& parameters) {
56     evaluated = unevaluated.evaluate(parameters);
57 
58     auto hasIconOpacity = evaluated.get<style::IconColor>().constantOr(Color::black()).a > 0 ||
59                           evaluated.get<style::IconHaloColor>().constantOr(Color::black()).a > 0;
60     auto hasTextOpacity = evaluated.get<style::TextColor>().constantOr(Color::black()).a > 0 ||
61                           evaluated.get<style::TextHaloColor>().constantOr(Color::black()).a > 0;
62 
63     passes = ((evaluated.get<style::IconOpacity>().constantOr(1) > 0 && hasIconOpacity && iconSize > 0)
64               || (evaluated.get<style::TextOpacity>().constantOr(1) > 0 && hasTextOpacity && textSize > 0))
65              ? RenderPass::Translucent : RenderPass::None;
66 }
67 
hasTransition() const68 bool RenderSymbolLayer::hasTransition() const {
69     return unevaluated.hasTransition();
70 }
71 
render(PaintParameters & parameters,RenderSource *)72 void RenderSymbolLayer::render(PaintParameters& parameters, RenderSource*) {
73     if (parameters.pass == RenderPass::Opaque) {
74         return;
75     }
76 
77     for (const RenderTile& tile : renderTiles) {
78         auto bucket_ = tile.tile.getBucket<SymbolBucket>(*baseImpl);
79         if (!bucket_) {
80             continue;
81         }
82         SymbolBucket& bucket = *bucket_;
83 
84         const auto& layout = bucket.layout;
85 
86         auto draw = [&] (auto& program,
87                          auto&& uniformValues,
88                          const auto& buffers,
89                          const auto& symbolSizeBinder,
90                          const SymbolPropertyValues& values_,
91                          const auto& binders,
92                          const auto& paintProperties)
93         {
94             auto& programInstance = program.get(paintProperties);
95 
96             const auto allUniformValues = programInstance.computeAllUniformValues(
97                 std::move(uniformValues),
98                 *symbolSizeBinder,
99                 binders,
100                 paintProperties,
101                 parameters.state.getZoom()
102             );
103             const auto allAttributeBindings = programInstance.computeAllAttributeBindings(
104                 *buffers.vertexBuffer,
105                 *buffers.dynamicVertexBuffer,
106                 *buffers.opacityVertexBuffer,
107                 binders,
108                 paintProperties
109             );
110 
111             checkRenderability(parameters, programInstance.activeBindingCount(allAttributeBindings));
112 
113             programInstance.draw(
114                 parameters.context,
115                 gl::Triangles(),
116                 values_.pitchAlignment == AlignmentType::Map
117                     ? parameters.depthModeForSublayer(0, gl::DepthMode::ReadOnly)
118                     : gl::DepthMode::disabled(),
119                 gl::StencilMode::disabled(),
120                 parameters.colorModeForRenderPass(),
121                 *buffers.indexBuffer,
122                 buffers.segments,
123                 allUniformValues,
124                 allAttributeBindings,
125                 getID()
126             );
127         };
128 
129         assert(dynamic_cast<GeometryTile*>(&tile.tile));
130         GeometryTile& geometryTile = static_cast<GeometryTile&>(tile.tile);
131 
132         if (bucket.hasIconData()) {
133             auto values = iconPropertyValues(layout);
134             auto paintPropertyValues = iconPaintProperties();
135 
136             const bool alongLine = layout.get<SymbolPlacement>() != SymbolPlacementType::Point &&
137                 layout.get<IconRotationAlignment>() == AlignmentType::Map;
138 
139             if (alongLine) {
140                 reprojectLineLabels(bucket.icon.dynamicVertices,
141                                     bucket.icon.placedSymbols,
142                                     tile.matrix,
143                                     values,
144                                     tile,
145                                     *bucket.iconSizeBinder,
146                                     parameters.state);
147 
148                 parameters.context.updateVertexBuffer(*bucket.icon.dynamicVertexBuffer, std::move(bucket.icon.dynamicVertices));
149             }
150 
151             const bool iconScaled = layout.get<IconSize>().constantOr(1.0) != 1.0 || bucket.iconsNeedLinear;
152             const bool iconTransformed = values.rotationAlignment == AlignmentType::Map || parameters.state.getPitch() != 0;
153 
154             parameters.context.bindTexture(*geometryTile.iconAtlasTexture, 0,
155                 bucket.sdfIcons || parameters.state.isChanging() || iconScaled || iconTransformed
156                     ? gl::TextureFilter::Linear : gl::TextureFilter::Nearest);
157 
158             const Size texsize = geometryTile.iconAtlasTexture->size;
159 
160             if (bucket.sdfIcons) {
161                 if (values.hasHalo) {
162                     draw(parameters.programs.symbolIconSDF,
163                          SymbolSDFIconProgram::uniformValues(false, values, texsize, parameters.pixelsToGLUnits, alongLine, tile, parameters.state, parameters.symbolFadeChange, SymbolSDFPart::Halo),
164                          bucket.icon,
165                          bucket.iconSizeBinder,
166                          values,
167                          bucket.paintPropertyBinders.at(getID()).first,
168                          paintPropertyValues);
169                 }
170 
171                 if (values.hasFill) {
172                     draw(parameters.programs.symbolIconSDF,
173                          SymbolSDFIconProgram::uniformValues(false, values, texsize, parameters.pixelsToGLUnits, alongLine, tile, parameters.state, parameters.symbolFadeChange, SymbolSDFPart::Fill),
174                          bucket.icon,
175                          bucket.iconSizeBinder,
176                          values,
177                          bucket.paintPropertyBinders.at(getID()).first,
178                          paintPropertyValues);
179                 }
180             } else {
181                 draw(parameters.programs.symbolIcon,
182                      SymbolIconProgram::uniformValues(false, values, texsize, parameters.pixelsToGLUnits, alongLine, tile, parameters.state, parameters.symbolFadeChange),
183                      bucket.icon,
184                      bucket.iconSizeBinder,
185                      values,
186                      bucket.paintPropertyBinders.at(getID()).first,
187                      paintPropertyValues);
188             }
189         }
190 
191         if (bucket.hasTextData()) {
192             parameters.context.bindTexture(*geometryTile.glyphAtlasTexture, 0, gl::TextureFilter::Linear);
193 
194             auto values = textPropertyValues(layout);
195             auto paintPropertyValues = textPaintProperties();
196 
197             const bool alongLine = layout.get<SymbolPlacement>() != SymbolPlacementType::Point &&
198                 layout.get<TextRotationAlignment>() == AlignmentType::Map;
199 
200             if (alongLine) {
201                 reprojectLineLabels(bucket.text.dynamicVertices,
202                                     bucket.text.placedSymbols,
203                                     tile.matrix,
204                                     values,
205                                     tile,
206                                     *bucket.textSizeBinder,
207                                     parameters.state);
208 
209                 parameters.context.updateVertexBuffer(*bucket.text.dynamicVertexBuffer, std::move(bucket.text.dynamicVertices));
210             }
211 
212             const Size texsize = geometryTile.glyphAtlasTexture->size;
213 
214             if (values.hasHalo) {
215                 draw(parameters.programs.symbolGlyph,
216                      SymbolSDFTextProgram::uniformValues(true, values, texsize, parameters.pixelsToGLUnits, alongLine, tile, parameters.state, parameters.symbolFadeChange, SymbolSDFPart::Halo),
217                      bucket.text,
218                      bucket.textSizeBinder,
219                      values,
220                      bucket.paintPropertyBinders.at(getID()).second,
221                      paintPropertyValues);
222             }
223 
224             if (values.hasFill) {
225                 draw(parameters.programs.symbolGlyph,
226                      SymbolSDFTextProgram::uniformValues(true, values, texsize, parameters.pixelsToGLUnits, alongLine, tile, parameters.state, parameters.symbolFadeChange, SymbolSDFPart::Fill),
227                      bucket.text,
228                      bucket.textSizeBinder,
229                      values,
230                      bucket.paintPropertyBinders.at(getID()).second,
231                      paintPropertyValues);
232             }
233         }
234 
235         if (bucket.hasCollisionBoxData()) {
236             static const style::Properties<>::PossiblyEvaluated properties {};
237             static const CollisionBoxProgram::PaintPropertyBinders paintAttributeData(properties, 0);
238 
239             auto pixelRatio = tile.id.pixelsToTileUnits(1, parameters.state.getZoom());
240             const float scale = std::pow(2, parameters.state.getZoom() - tile.tile.id.overscaledZ);
241             std::array<float,2> extrudeScale =
242                 {{
243                     parameters.pixelsToGLUnits[0] / (pixelRatio * scale),
244                     parameters.pixelsToGLUnits[1] / (pixelRatio * scale)
245 
246                 }};
247             parameters.programs.collisionBox.draw(
248                 parameters.context,
249                 gl::Lines { 1.0f },
250                 gl::DepthMode::disabled(),
251                 gl::StencilMode::disabled(),
252                 parameters.colorModeForRenderPass(),
253                 CollisionBoxProgram::UniformValues {
254                     uniforms::u_matrix::Value{ tile.matrix },
255                     uniforms::u_extrude_scale::Value{ extrudeScale },
256                     uniforms::u_camera_to_center_distance::Value{ parameters.state.getCameraToCenterDistance() }
257                 },
258                 *bucket.collisionBox.vertexBuffer,
259                 *bucket.collisionBox.dynamicVertexBuffer,
260                 *bucket.collisionBox.indexBuffer,
261                 bucket.collisionBox.segments,
262                 paintAttributeData,
263                 properties,
264                 parameters.state.getZoom(),
265                 getID()
266             );
267         }
268         if (bucket.hasCollisionCircleData()) {
269             static const style::Properties<>::PossiblyEvaluated properties {};
270             static const CollisionBoxProgram::PaintPropertyBinders paintAttributeData(properties, 0);
271 
272             auto pixelRatio = tile.id.pixelsToTileUnits(1, parameters.state.getZoom());
273             const float scale = std::pow(2, parameters.state.getZoom() - tile.tile.id.overscaledZ);
274             std::array<float,2> extrudeScale =
275                 {{
276                     parameters.pixelsToGLUnits[0] / (pixelRatio * scale),
277                     parameters.pixelsToGLUnits[1] / (pixelRatio * scale)
278 
279                 }};
280 
281             parameters.programs.collisionCircle.draw(
282                 parameters.context,
283                 gl::Triangles(),
284                 gl::DepthMode::disabled(),
285                 gl::StencilMode::disabled(),
286                 parameters.colorModeForRenderPass(),
287                 CollisionCircleProgram::UniformValues {
288                     uniforms::u_matrix::Value{ tile.matrix },
289                     uniforms::u_extrude_scale::Value{ extrudeScale },
290                     uniforms::u_overscale_factor::Value{ float(tile.tile.id.overscaleFactor()) },
291                     uniforms::u_camera_to_center_distance::Value{ parameters.state.getCameraToCenterDistance() }
292                 },
293                 *bucket.collisionCircle.vertexBuffer,
294                 *bucket.collisionCircle.dynamicVertexBuffer,
295                 *bucket.collisionCircle.indexBuffer,
296                 bucket.collisionCircle.segments,
297                 paintAttributeData,
298                 properties,
299                 parameters.state.getZoom(),
300                 getID()
301             );
302 
303         }
304     }
305 }
306 
iconPaintProperties() const307 style::IconPaintProperties::PossiblyEvaluated RenderSymbolLayer::iconPaintProperties() const {
308     return style::IconPaintProperties::PossiblyEvaluated {
309             evaluated.get<style::IconOpacity>(),
310             evaluated.get<style::IconColor>(),
311             evaluated.get<style::IconHaloColor>(),
312             evaluated.get<style::IconHaloWidth>(),
313             evaluated.get<style::IconHaloBlur>(),
314             evaluated.get<style::IconTranslate>(),
315             evaluated.get<style::IconTranslateAnchor>()
316     };
317 }
318 
textPaintProperties() const319 style::TextPaintProperties::PossiblyEvaluated RenderSymbolLayer::textPaintProperties() const {
320     return style::TextPaintProperties::PossiblyEvaluated {
321             evaluated.get<style::TextOpacity>(),
322             evaluated.get<style::TextColor>(),
323             evaluated.get<style::TextHaloColor>(),
324             evaluated.get<style::TextHaloWidth>(),
325             evaluated.get<style::TextHaloBlur>(),
326             evaluated.get<style::TextTranslate>(),
327             evaluated.get<style::TextTranslateAnchor>()
328     };
329 }
330 
331 
iconPropertyValues(const style::SymbolLayoutProperties::PossiblyEvaluated & layout_) const332 style::SymbolPropertyValues RenderSymbolLayer::iconPropertyValues(const style::SymbolLayoutProperties::PossiblyEvaluated& layout_) const {
333     return style::SymbolPropertyValues {
334             layout_.get<style::IconPitchAlignment>(),
335             layout_.get<style::IconRotationAlignment>(),
336             layout_.get<style::IconKeepUpright>(),
337             evaluated.get<style::IconTranslate>(),
338             evaluated.get<style::IconTranslateAnchor>(),
339             evaluated.get<style::IconHaloColor>().constantOr(Color::black()).a > 0 &&
340             evaluated.get<style::IconHaloWidth>().constantOr(1),
341             evaluated.get<style::IconColor>().constantOr(Color::black()).a > 0
342     };
343 }
344 
textPropertyValues(const style::SymbolLayoutProperties::PossiblyEvaluated & layout_) const345 style::SymbolPropertyValues RenderSymbolLayer::textPropertyValues(const style::SymbolLayoutProperties::PossiblyEvaluated& layout_) const {
346     return style::SymbolPropertyValues {
347             layout_.get<style::TextPitchAlignment>(),
348             layout_.get<style::TextRotationAlignment>(),
349             layout_.get<style::TextKeepUpright>(),
350             evaluated.get<style::TextTranslate>(),
351             evaluated.get<style::TextTranslateAnchor>(),
352             evaluated.get<style::TextHaloColor>().constantOr(Color::black()).a > 0 &&
353             evaluated.get<style::TextHaloWidth>().constantOr(1),
354             evaluated.get<style::TextColor>().constantOr(Color::black()).a > 0
355     };
356 }
357 
358 } // namespace mbgl
359