1 #pragma once
2 
3 #include <mbgl/gl/context.hpp>
4 #include <mbgl/gl/program.hpp>
5 #include <mbgl/math/clamp.hpp>
6 #include <mbgl/util/interpolate.hpp>
7 
8 #include <mbgl/programs/attributes.hpp>
9 #include <mbgl/programs/uniforms.hpp>
10 #include <mbgl/programs/segment.hpp>
11 #include <mbgl/shaders/symbol_icon.hpp>
12 #include <mbgl/shaders/symbol_sdf.hpp>
13 #include <mbgl/util/geometry.hpp>
14 #include <mbgl/util/size.hpp>
15 #include <mbgl/style/layers/symbol_layer_properties.hpp>
16 #include <mbgl/style/layers/symbol_layer_impl.hpp>
17 #include <mbgl/renderer/layers/render_symbol_layer.hpp>
18 
19 
20 #include <cmath>
21 #include <array>
22 
23 namespace mbgl {
24 
25 namespace style {
26 class SymbolPropertyValues;
27 } // namespace style
28 
29 class RenderTile;
30 class TransformState;
31 
32 namespace uniforms {
33 MBGL_DEFINE_UNIFORM_MATRIX(double, 4, u_gl_coord_matrix);
34 MBGL_DEFINE_UNIFORM_MATRIX(double, 4, u_label_plane_matrix);
35 MBGL_DEFINE_UNIFORM_SCALAR(gl::TextureUnit, u_texture);
36 MBGL_DEFINE_UNIFORM_SCALAR(bool, u_is_halo);
37 MBGL_DEFINE_UNIFORM_SCALAR(float, u_gamma_scale);
38 
39 MBGL_DEFINE_UNIFORM_SCALAR(bool, u_is_text);
40 MBGL_DEFINE_UNIFORM_SCALAR(bool, u_is_size_zoom_constant);
41 MBGL_DEFINE_UNIFORM_SCALAR(bool, u_is_size_feature_constant);
42 MBGL_DEFINE_UNIFORM_SCALAR(float, u_size_t);
43 MBGL_DEFINE_UNIFORM_SCALAR(float, u_size);
44 MBGL_DEFINE_UNIFORM_SCALAR(bool, u_rotate_symbol);
45 MBGL_DEFINE_UNIFORM_SCALAR(float, u_aspect_ratio);
46 } // namespace uniforms
47 
48 struct SymbolLayoutAttributes : gl::Attributes<
49     attributes::a_pos_offset,
50     attributes::a_data<uint16_t, 4>>
51 {
vertexmbgl::SymbolLayoutAttributes52     static Vertex vertex(Point<float> labelAnchor,
53                          Point<float> o,
54                          float glyphOffsetY,
55                          uint16_t tx,
56                          uint16_t ty,
57                          const Range<float>& sizeData) {
58         return Vertex {
59             // combining pos and offset to reduce number of vertex attributes passed to shader (8 max for some devices)
60             {{
61                 static_cast<int16_t>(labelAnchor.x),
62                 static_cast<int16_t>(labelAnchor.y),
63                 static_cast<int16_t>(::round(o.x * 32)),  // use 1/32 pixels for placement
64                 static_cast<int16_t>(::round((o.y + glyphOffsetY) * 32))
65             }},
66             {{
67                 tx,
68                 ty,
69                 static_cast<uint16_t>(sizeData.min * 10),
70                 static_cast<uint16_t>(sizeData.max * 10)
71             }}
72         };
73     }
74 };
75 
76 struct SymbolDynamicLayoutAttributes : gl::Attributes<attributes::a_projected_pos> {
vertexmbgl::SymbolDynamicLayoutAttributes77     static Vertex vertex(Point<float> anchorPoint, float labelAngle) {
78         return Vertex {
79             {{
80                  anchorPoint.x,
81                  anchorPoint.y,
82                  labelAngle
83              }}
84         };
85     }
86 };
87 
88 struct SymbolOpacityAttributes : gl::Attributes<attributes::a_fade_opacity> {
vertexmbgl::SymbolOpacityAttributes89     static Vertex vertex(bool placed, float opacity) {
90         return Vertex {
91             {{ static_cast<uint8_t>((static_cast<uint8_t>(opacity * 127) << 1) | static_cast<uint8_t>(placed)) }}
92         };
93     }
94 };
95 
96 struct ZoomEvaluatedSize {
97     bool isZoomConstant;
98     bool isFeatureConstant;
99     float sizeT;
100     float size;
101     float layoutSize;
102 };
103 // Mimic the PaintPropertyBinder technique specifically for the {text,icon}-size layout properties
104 // in order to provide a 'custom' scheme for encoding the necessary attribute data.  As with
105 // PaintPropertyBinder, SymbolSizeBinder is an abstract class whose implementations handle the
106 // particular attribute & uniform logic needed by each possible type of the {Text,Icon}Size properties.
107 class SymbolSizeBinder {
108 public:
109     virtual ~SymbolSizeBinder() = default;
110 
111     using Uniforms = gl::Uniforms<
112         uniforms::u_is_size_zoom_constant,
113         uniforms::u_is_size_feature_constant,
114         uniforms::u_size_t,
115         uniforms::u_size>;
116     using UniformValues = Uniforms::Values;
117 
118     static std::unique_ptr<SymbolSizeBinder> create(const float tileZoom,
119                                                     const style::DataDrivenPropertyValue<float>& sizeProperty,
120                                                     const float defaultValue);
121 
122     virtual Range<float> getVertexSizeData(const GeometryTileFeature& feature) = 0;
123     virtual ZoomEvaluatedSize evaluateForZoom(float currentZoom) const = 0;
124 
uniformValues(float currentZoom) const125     UniformValues uniformValues(float currentZoom) const {
126         const ZoomEvaluatedSize u = evaluateForZoom(currentZoom);
127         return UniformValues {
128             uniforms::u_is_size_zoom_constant::Value{ u.isZoomConstant },
129             uniforms::u_is_size_feature_constant::Value{ u.isFeatureConstant},
130             uniforms::u_size_t::Value{ u.sizeT },
131             uniforms::u_size::Value{ u.size }
132         };
133     }
134 };
135 
136 
137 class ConstantSymbolSizeBinder final : public SymbolSizeBinder {
138 public:
ConstantSymbolSizeBinder(const float,const float & size,const float)139     ConstantSymbolSizeBinder(const float /*tileZoom*/, const float& size, const float /*defaultValue*/)
140       : layoutSize(size) {}
141 
ConstantSymbolSizeBinder(const float,const style::Undefined &,const float defaultValue)142     ConstantSymbolSizeBinder(const float /*tileZoom*/, const style::Undefined&, const float defaultValue)
143       : layoutSize(defaultValue) {}
144 
ConstantSymbolSizeBinder(const float tileZoom,const style::PropertyExpression<float> & expression_,const float)145     ConstantSymbolSizeBinder(const float tileZoom, const style::PropertyExpression<float>& expression_, const float /*defaultValue*/)
146       : layoutSize(expression_.evaluate(tileZoom + 1)),
147         expression(expression_) {
148         const Range<float> zoomLevels = expression_.getCoveringStops(tileZoom, tileZoom + 1);
149         coveringRanges = std::make_tuple(
150             zoomLevels,
151             Range<float> { expression_.evaluate(zoomLevels.min), expression_.evaluate(zoomLevels.max) }
152         );
153     }
154 
getVertexSizeData(const GeometryTileFeature &)155     Range<float> getVertexSizeData(const GeometryTileFeature&) override { return { 0.0f, 0.0f }; };
156 
evaluateForZoom(float currentZoom) const157     ZoomEvaluatedSize evaluateForZoom(float currentZoom) const override {
158         float size = layoutSize;
159         bool isZoomConstant = !(coveringRanges || expression);
160         if (coveringRanges) {
161             // Even though we could get the exact value of the camera function
162             // at z = currentZoom, we intentionally do not: instead, we interpolate
163             // between the camera function values at a pair of zoom stops covering
164             // [tileZoom, tileZoom + 1] in order to be consistent with this
165             // restriction on composite functions.
166             const Range<float>& zoomLevels = std::get<0>(*coveringRanges);
167             const Range<float>& sizeLevels = std::get<1>(*coveringRanges);
168             float t = util::clamp(
169                 expression->interpolationFactor(zoomLevels, currentZoom),
170                 0.0f, 1.0f
171             );
172             size = sizeLevels.min + t * (sizeLevels.max - sizeLevels.min);
173         } else if (expression) {
174             size = expression->evaluate(currentZoom);
175         }
176 
177         const float unused = 0.0f;
178         return { isZoomConstant, true, unused, size, layoutSize };
179     }
180 
181     float layoutSize;
182     optional<std::tuple<Range<float>, Range<float>>> coveringRanges;
183     optional<style::PropertyExpression<float>> expression;
184 };
185 
186 class SourceFunctionSymbolSizeBinder final : public SymbolSizeBinder {
187 public:
188     using Vertex = gl::detail::Vertex<gl::Attribute<uint16_t, 1>>;
189     using VertexVector = gl::VertexVector<Vertex>;
190     using VertexBuffer = gl::VertexBuffer<Vertex>;
191 
SourceFunctionSymbolSizeBinder(const float,style::PropertyExpression<float> expression_,const float defaultValue_)192     SourceFunctionSymbolSizeBinder(const float /*tileZoom*/, style::PropertyExpression<float> expression_, const float defaultValue_)
193         : expression(std::move(expression_)),
194           defaultValue(defaultValue_) {
195     }
196 
getVertexSizeData(const GeometryTileFeature & feature)197     Range<float> getVertexSizeData(const GeometryTileFeature& feature) override {
198         const float size = expression.evaluate(feature, defaultValue);
199         return { size, size };
200     };
201 
evaluateForZoom(float) const202     ZoomEvaluatedSize evaluateForZoom(float) const override {
203         const float unused = 0.0f;
204         return { true, false, unused, unused, unused };
205     }
206 
207     style::PropertyExpression<float> expression;
208     const float defaultValue;
209 };
210 
211 class CompositeFunctionSymbolSizeBinder final : public SymbolSizeBinder {
212 public:
213 
CompositeFunctionSymbolSizeBinder(const float tileZoom,style::PropertyExpression<float> expression_,const float defaultValue_)214     CompositeFunctionSymbolSizeBinder(const float tileZoom, style::PropertyExpression<float> expression_, const float defaultValue_)
215         : expression(std::move(expression_)),
216           defaultValue(defaultValue_),
217           layoutZoom(tileZoom + 1),
218           coveringZoomStops(expression.getCoveringStops(tileZoom, tileZoom + 1))
219     {}
220 
getVertexSizeData(const GeometryTileFeature & feature)221     Range<float> getVertexSizeData(const GeometryTileFeature& feature) override {
222         return {
223             expression.evaluate(coveringZoomStops.min, feature, defaultValue),
224             expression.evaluate(coveringZoomStops.max, feature, defaultValue)
225         };
226     };
227 
evaluateForZoom(float currentZoom) const228     ZoomEvaluatedSize evaluateForZoom(float currentZoom) const override {
229         float sizeInterpolationT = util::clamp(
230             expression.interpolationFactor(coveringZoomStops, currentZoom),
231             0.0f, 1.0f
232         );
233 
234         const float unused = 0.0f;
235         return { false, false, sizeInterpolationT, unused, unused };
236     }
237 
238     style::PropertyExpression<float> expression;
239     const float defaultValue;
240     float layoutZoom;
241     Range<float> coveringZoomStops;
242 };
243 
244 
245 template <class Shaders,
246           class Primitive,
247           class LayoutAttrs,
248           class Uniforms,
249           class PaintProps>
250 class SymbolProgram {
251 public:
252     using LayoutAttributes = LayoutAttrs;
253     using LayoutVertex = typename LayoutAttributes::Vertex;
254 
255     using LayoutAndSizeAttributes = gl::ConcatenateAttributes<LayoutAttributes, gl::ConcatenateAttributes<SymbolDynamicLayoutAttributes, SymbolOpacityAttributes>>;
256 
257     using PaintProperties = PaintProps;
258     using PaintPropertyBinders = typename PaintProperties::Binders;
259     using PaintAttributes = typename PaintPropertyBinders::Attributes;
260     using Attributes = gl::ConcatenateAttributes<LayoutAndSizeAttributes, PaintAttributes>;
261 
262     using UniformValues = typename Uniforms::Values;
263     using SizeUniforms = typename SymbolSizeBinder::Uniforms;
264     using PaintUniforms = typename PaintPropertyBinders::Uniforms;
265     using AllUniforms = gl::ConcatenateUniforms<Uniforms, gl::ConcatenateUniforms<SizeUniforms, PaintUniforms>>;
266 
267     using ProgramType = gl::Program<Primitive, Attributes, AllUniforms>;
268 
269     ProgramType program;
270 
SymbolProgram(gl::Context & context,const ProgramParameters & programParameters)271     SymbolProgram(gl::Context& context, const ProgramParameters& programParameters)
272         : program(ProgramType::createProgram(
273             context,
274             programParameters,
275             Shaders::name,
276             Shaders::vertexSource,
277             Shaders::fragmentSource)) {
278     }
279 
computeAllUniformValues(const UniformValues & uniformValues,const SymbolSizeBinder & symbolSizeBinder,const PaintPropertyBinders & paintPropertyBinders,const typename PaintProperties::PossiblyEvaluated & currentProperties,float currentZoom)280     static typename AllUniforms::Values computeAllUniformValues(
281         const UniformValues& uniformValues,
282         const SymbolSizeBinder& symbolSizeBinder,
283         const PaintPropertyBinders& paintPropertyBinders,
284         const typename PaintProperties::PossiblyEvaluated& currentProperties,
285         float currentZoom) {
286         return uniformValues.concat(symbolSizeBinder.uniformValues(currentZoom))
287             .concat(paintPropertyBinders.uniformValues(currentZoom, currentProperties));
288     }
289 
computeAllAttributeBindings(const gl::VertexBuffer<LayoutVertex> & layoutVertexBuffer,const gl::VertexBuffer<SymbolDynamicLayoutAttributes::Vertex> & dynamicLayoutVertexBuffer,const gl::VertexBuffer<SymbolOpacityAttributes::Vertex> & opacityVertexBuffer,const PaintPropertyBinders & paintPropertyBinders,const typename PaintProperties::PossiblyEvaluated & currentProperties)290     static typename Attributes::Bindings computeAllAttributeBindings(
291         const gl::VertexBuffer<LayoutVertex>& layoutVertexBuffer,
292         const gl::VertexBuffer<SymbolDynamicLayoutAttributes::Vertex>& dynamicLayoutVertexBuffer,
293         const gl::VertexBuffer<SymbolOpacityAttributes::Vertex>& opacityVertexBuffer,
294         const PaintPropertyBinders& paintPropertyBinders,
295         const typename PaintProperties::PossiblyEvaluated& currentProperties) {
296         assert(layoutVertexBuffer.vertexCount == dynamicLayoutVertexBuffer.vertexCount &&
297                layoutVertexBuffer.vertexCount == opacityVertexBuffer.vertexCount);
298         return LayoutAttributes::bindings(layoutVertexBuffer)
299             .concat(SymbolDynamicLayoutAttributes::bindings(dynamicLayoutVertexBuffer))
300             .concat(SymbolOpacityAttributes::bindings(opacityVertexBuffer))
301             .concat(paintPropertyBinders.attributeBindings(currentProperties));
302     }
303 
activeBindingCount(const typename Attributes::Bindings & allAttributeBindings)304     static uint32_t activeBindingCount(const typename Attributes::Bindings& allAttributeBindings) {
305         return Attributes::activeBindingCount(allAttributeBindings);
306     }
307 
308     template <class DrawMode>
draw(gl::Context & context,DrawMode drawMode,gl::DepthMode depthMode,gl::StencilMode stencilMode,gl::ColorMode colorMode,const gl::IndexBuffer<DrawMode> & indexBuffer,const SegmentVector<Attributes> & segments,const typename AllUniforms::Values & allUniformValues,const typename Attributes::Bindings & allAttributeBindings,const std::string & layerID)309     void draw(gl::Context& context,
310               DrawMode drawMode,
311               gl::DepthMode depthMode,
312               gl::StencilMode stencilMode,
313               gl::ColorMode colorMode,
314               const gl::IndexBuffer<DrawMode>& indexBuffer,
315               const SegmentVector<Attributes>& segments,
316               const typename AllUniforms::Values& allUniformValues,
317               const typename Attributes::Bindings& allAttributeBindings,
318               const std::string& layerID) {
319         for (auto& segment : segments) {
320             auto vertexArrayIt = segment.vertexArrays.find(layerID);
321 
322             if (vertexArrayIt == segment.vertexArrays.end()) {
323                 vertexArrayIt = segment.vertexArrays.emplace(layerID, context.createVertexArray()).first;
324             }
325 
326             program.draw(
327                 context,
328                 std::move(drawMode),
329                 std::move(depthMode),
330                 std::move(stencilMode),
331                 std::move(colorMode),
332                 allUniformValues,
333                 vertexArrayIt->second,
334                 Attributes::offsetBindings(allAttributeBindings, segment.vertexOffset),
335                 indexBuffer,
336                 segment.indexOffset,
337                 segment.indexLength);
338         }
339     }
340 };
341 
342 class SymbolIconProgram : public SymbolProgram<
343     shaders::symbol_icon,
344     gl::Triangle,
345     SymbolLayoutAttributes,
346     gl::Uniforms<
347         uniforms::u_matrix,
348         uniforms::u_label_plane_matrix,
349         uniforms::u_gl_coord_matrix,
350         uniforms::u_extrude_scale,
351         uniforms::u_texsize,
352         uniforms::u_texture,
353         uniforms::u_fade_change,
354         uniforms::u_is_text,
355         uniforms::u_camera_to_center_distance,
356         uniforms::u_pitch,
357         uniforms::u_pitch_with_map,
358         uniforms::u_rotate_symbol,
359         uniforms::u_aspect_ratio>,
360     style::IconPaintProperties>
361 {
362 public:
363     using SymbolProgram::SymbolProgram;
364 
365     static UniformValues uniformValues(const bool isText,
366                                        const style::SymbolPropertyValues&,
367                                        const Size& texsize,
368                                        const std::array<float, 2>& pixelsToGLUnits,
369                                        const bool alongLine,
370                                        const RenderTile&,
371                                        const TransformState&,
372                                        const float symbolFadeChange);
373 };
374 
375 enum class SymbolSDFPart {
376     Fill = 1,
377     Halo = 0
378 };
379 
380 template <class PaintProperties>
381 class SymbolSDFProgram : public SymbolProgram<
382     shaders::symbol_sdf,
383     gl::Triangle,
384     SymbolLayoutAttributes,
385     gl::Uniforms<
386         uniforms::u_matrix,
387         uniforms::u_label_plane_matrix,
388         uniforms::u_gl_coord_matrix,
389         uniforms::u_extrude_scale,
390         uniforms::u_texsize,
391         uniforms::u_texture,
392         uniforms::u_fade_change,
393         uniforms::u_is_text,
394         uniforms::u_camera_to_center_distance,
395         uniforms::u_pitch,
396         uniforms::u_pitch_with_map,
397         uniforms::u_rotate_symbol,
398         uniforms::u_aspect_ratio,
399         uniforms::u_gamma_scale,
400         uniforms::u_is_halo>,
401     PaintProperties>
402 {
403 public:
404     using BaseProgram = SymbolProgram<shaders::symbol_sdf,
405         gl::Triangle,
406         SymbolLayoutAttributes,
407         gl::Uniforms<
408             uniforms::u_matrix,
409             uniforms::u_label_plane_matrix,
410             uniforms::u_gl_coord_matrix,
411             uniforms::u_extrude_scale,
412             uniforms::u_texsize,
413             uniforms::u_texture,
414             uniforms::u_fade_change,
415             uniforms::u_is_text,
416             uniforms::u_camera_to_center_distance,
417             uniforms::u_pitch,
418             uniforms::u_pitch_with_map,
419             uniforms::u_rotate_symbol,
420             uniforms::u_aspect_ratio,
421             uniforms::u_gamma_scale,
422             uniforms::u_is_halo>,
423         PaintProperties>;
424 
425     using UniformValues = typename BaseProgram::UniformValues;
426 
427 
428 
429     using BaseProgram::BaseProgram;
430 
431     static UniformValues uniformValues(const bool isText,
432                                        const style::SymbolPropertyValues&,
433                                        const Size& texsize,
434                                        const std::array<float, 2>& pixelsToGLUnits,
435                                        const bool alongLine,
436                                        const RenderTile&,
437                                        const TransformState&,
438                                        const float SymbolFadeChange,
439                                        const SymbolSDFPart);
440 };
441 
442 using SymbolSDFIconProgram = SymbolSDFProgram<style::IconPaintProperties>;
443 using SymbolSDFTextProgram = SymbolSDFProgram<style::TextPaintProperties>;
444 
445 using SymbolLayoutVertex = SymbolLayoutAttributes::Vertex;
446 using SymbolIconAttributes = SymbolIconProgram::Attributes;
447 using SymbolTextAttributes = SymbolSDFTextProgram::Attributes;
448 
449 } // namespace mbgl
450