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