From e8657becc56c2aee5b070357092da028e752d461 Mon Sep 17 00:00:00 2001 From: Chris Loer Date: Tue, 11 Jul 2017 11:22:39 -0700 Subject: [core] Update shaders. Implements 'icon-pitch-alignment' (issue #9345) Fixes issue #9456 (map-aligned point label regression) --- src/mbgl/layout/symbol_layout.cpp | 5 ++++- src/mbgl/programs/symbol_program.cpp | 7 +++++++ src/mbgl/programs/symbol_program.hpp | 10 +++++++++- src/mbgl/renderer/layers/render_symbol_layer.cpp | 2 +- src/mbgl/shaders/symbol_icon.cpp | 17 +++++++++++++++-- src/mbgl/shaders/symbol_sdf.cpp | 19 +++++++++++++++++-- src/mbgl/style/layers/symbol_layer.cpp | 16 ++++++++++++++++ src/mbgl/style/layers/symbol_layer_properties.hpp | 6 ++++++ 8 files changed, 75 insertions(+), 7 deletions(-) (limited to 'src') diff --git a/src/mbgl/layout/symbol_layout.cpp b/src/mbgl/layout/symbol_layout.cpp index e308da618f..956ba770dd 100644 --- a/src/mbgl/layout/symbol_layout.cpp +++ b/src/mbgl/layout/symbol_layout.cpp @@ -75,10 +75,13 @@ SymbolLayout::SymbolLayout(const BucketParameters& parameters, } } - // If unspecified `text-pitch-alignment` inherits `text-rotation-alignment` + // If unspecified `*-pitch-alignment` inherits `*-rotation-alignment` if (layout.get() == AlignmentType::Auto) { layout.get() = layout.get(); } + if (layout.get() == AlignmentType::Auto) { + layout.get() = layout.get(); + } const bool hasText = has(layout) && !layout.get().empty(); const bool hasIcon = has(layout); diff --git a/src/mbgl/programs/symbol_program.cpp b/src/mbgl/programs/symbol_program.cpp index 8790adcc63..58174ff8a7 100644 --- a/src/mbgl/programs/symbol_program.cpp +++ b/src/mbgl/programs/symbol_program.cpp @@ -52,6 +52,11 @@ Values makeValues(const bool isText, const float pixelsToTileUnits = tile.id.pixelsToTileUnits(1.0, state.getZoom()); const bool pitchWithMap = values.pitchAlignment == style::AlignmentType::Map; const bool rotateWithMap = values.rotationAlignment == style::AlignmentType::Map; + + // Line label rotation happens in `updateLineLabels` + // Pitched point labels are automatically rotated by the labelPlaneMatrix projection + // Unpitched point labels need to have their rotation applied after projection + const bool rotateInShader = rotateWithMap && !pitchWithMap && !alongLine; mat4 labelPlaneMatrix; if (alongLine) { @@ -84,6 +89,8 @@ Values makeValues(const bool isText, uniforms::u_pitch::Value{ state.getPitch() }, uniforms::u_pitch_with_map::Value{ pitchWithMap }, uniforms::u_max_camera_distance::Value{ values.maxCameraDistance }, + uniforms::u_rotate_symbol::Value{ rotateInShader }, + uniforms::u_aspect_ratio::Value{ state.getSize().aspectRatio() }, std::forward(args)... }; } diff --git a/src/mbgl/programs/symbol_program.hpp b/src/mbgl/programs/symbol_program.hpp index 79a961ad21..c74837b121 100644 --- a/src/mbgl/programs/symbol_program.hpp +++ b/src/mbgl/programs/symbol_program.hpp @@ -41,6 +41,8 @@ MBGL_DEFINE_UNIFORM_SCALAR(bool, u_is_size_feature_constant); MBGL_DEFINE_UNIFORM_SCALAR(float, u_size_t); MBGL_DEFINE_UNIFORM_SCALAR(float, u_size); MBGL_DEFINE_UNIFORM_SCALAR(float, u_max_camera_distance); +MBGL_DEFINE_UNIFORM_SCALAR(bool, u_rotate_symbol); +MBGL_DEFINE_UNIFORM_SCALAR(float, u_aspect_ratio); } // namespace uniforms struct SymbolLayoutAttributes : gl::Attributes< @@ -348,7 +350,9 @@ class SymbolIconProgram : public SymbolProgram< uniforms::u_camera_to_center_distance, uniforms::u_pitch, uniforms::u_pitch_with_map, - uniforms::u_max_camera_distance>, + uniforms::u_max_camera_distance, + uniforms::u_rotate_symbol, + uniforms::u_aspect_ratio>, style::IconPaintProperties> { public: @@ -387,6 +391,8 @@ class SymbolSDFProgram : public SymbolProgram< uniforms::u_pitch, uniforms::u_pitch_with_map, uniforms::u_max_camera_distance, + uniforms::u_rotate_symbol, + uniforms::u_aspect_ratio, uniforms::u_gamma_scale, uniforms::u_is_halo>, PaintProperties> @@ -409,6 +415,8 @@ public: uniforms::u_pitch, uniforms::u_pitch_with_map, uniforms::u_max_camera_distance, + uniforms::u_rotate_symbol, + uniforms::u_aspect_ratio, uniforms::u_gamma_scale, uniforms::u_is_halo>, PaintProperties>; diff --git a/src/mbgl/renderer/layers/render_symbol_layer.cpp b/src/mbgl/renderer/layers/render_symbol_layer.cpp index 2fe6dd971e..2af7b2f7ca 100644 --- a/src/mbgl/renderer/layers/render_symbol_layer.cpp +++ b/src/mbgl/renderer/layers/render_symbol_layer.cpp @@ -82,7 +82,7 @@ style::TextPaintProperties::PossiblyEvaluated RenderSymbolLayer::textPaintProper style::SymbolPropertyValues RenderSymbolLayer::iconPropertyValues(const style::SymbolLayoutProperties::PossiblyEvaluated& layout_) const { return style::SymbolPropertyValues { - layout_.get(), // icon-pitch-alignment is not yet implemented; inherit the rotation alignment + layout_.get(), layout_.get(), layout_.get(), evaluated.get(), diff --git a/src/mbgl/shaders/symbol_icon.cpp b/src/mbgl/shaders/symbol_icon.cpp index cb00cdad05..c0e3a0ac01 100644 --- a/src/mbgl/shaders/symbol_icon.cpp +++ b/src/mbgl/shaders/symbol_icon.cpp @@ -19,6 +19,8 @@ uniform highp float u_size_t; // used to interpolate between zoom stops when siz uniform highp float u_size; // used when size is both zoom and feature constant uniform highp float u_camera_to_center_distance; uniform highp float u_pitch; +uniform bool u_rotate_symbol; +uniform highp float u_aspect_ratio; uniform highp float u_collision_y_stretch; @@ -83,8 +85,19 @@ void main() { float fontScale = u_is_text ? size / 24.0 : size; - highp float angle_sin = sin(segment_angle); - highp float angle_cos = cos(segment_angle); + highp float symbol_rotation = 0.0; + if (u_rotate_symbol) { + // See comments in symbol_sdf.vertex + vec4 offsetProjectedPoint = u_matrix * vec4(a_pos + vec2(1, 0), 0, 1); + + vec2 a = projectedPoint.xy / projectedPoint.w; + vec2 b = offsetProjectedPoint.xy / offsetProjectedPoint.w; + + symbol_rotation = atan((b.y - a.y) / u_aspect_ratio, b.x - a.x); + } + + highp float angle_sin = sin(segment_angle + symbol_rotation); + highp float angle_cos = cos(segment_angle + symbol_rotation); mat2 rotation_matrix = mat2(angle_cos, -1.0 * angle_sin, angle_sin, angle_cos); vec4 projected_pos = u_label_plane_matrix * vec4(a_projected_pos.xy, 0.0, 1.0); diff --git a/src/mbgl/shaders/symbol_sdf.cpp b/src/mbgl/shaders/symbol_sdf.cpp index b4158bacc5..2050886957 100644 --- a/src/mbgl/shaders/symbol_sdf.cpp +++ b/src/mbgl/shaders/symbol_sdf.cpp @@ -73,6 +73,8 @@ uniform mat4 u_gl_coord_matrix; uniform bool u_is_text; uniform bool u_pitch_with_map; uniform highp float u_pitch; +uniform bool u_rotate_symbol; +uniform highp float u_aspect_ratio; uniform highp float u_camera_to_center_distance; uniform highp float u_collision_y_stretch; @@ -151,8 +153,21 @@ void main() { float fontScale = u_is_text ? size / 24.0 : size; - highp float angle_sin = sin(segment_angle); - highp float angle_cos = cos(segment_angle); + highp float symbol_rotation = 0.0; + if (u_rotate_symbol) { + // Point labels with 'rotation-alignment: map' are horizontal with respect to tile units + // To figure out that angle in projected space, we draw a short horizontal line in tile + // space, project it, and measure its angle in projected space. + vec4 offsetProjectedPoint = u_matrix * vec4(a_pos + vec2(1, 0), 0, 1); + + vec2 a = projectedPoint.xy / projectedPoint.w; + vec2 b = offsetProjectedPoint.xy / offsetProjectedPoint.w; + + symbol_rotation = atan((b.y - a.y) / u_aspect_ratio, b.x - a.x); + } + + highp float angle_sin = sin(segment_angle + symbol_rotation); + highp float angle_cos = cos(segment_angle + symbol_rotation); mat2 rotation_matrix = mat2(angle_cos, -1.0 * angle_sin, angle_sin, angle_cos); vec4 projected_pos = u_label_plane_matrix * vec4(a_projected_pos.xy, 0.0, 1.0); diff --git a/src/mbgl/style/layers/symbol_layer.cpp b/src/mbgl/style/layers/symbol_layer.cpp index 182b4b0a48..c102c64a94 100644 --- a/src/mbgl/style/layers/symbol_layer.cpp +++ b/src/mbgl/style/layers/symbol_layer.cpp @@ -332,6 +332,22 @@ void SymbolLayer::setIconOffset(DataDrivenPropertyValue> va baseImpl = std::move(impl_); observer->onLayerChanged(*this); } +PropertyValue SymbolLayer::getDefaultIconPitchAlignment() { + return IconPitchAlignment::defaultValue(); +} + +PropertyValue SymbolLayer::getIconPitchAlignment() const { + return impl().layout.get(); +} + +void SymbolLayer::setIconPitchAlignment(PropertyValue value) { + if (value == getIconPitchAlignment()) + return; + auto impl_ = mutableImpl(); + impl_->layout.get() = value; + baseImpl = std::move(impl_); + observer->onLayerChanged(*this); +} PropertyValue SymbolLayer::getDefaultTextPitchAlignment() { return TextPitchAlignment::defaultValue(); } diff --git a/src/mbgl/style/layers/symbol_layer_properties.hpp b/src/mbgl/style/layers/symbol_layer_properties.hpp index f7ceaecdaa..4b2bff01b8 100644 --- a/src/mbgl/style/layers/symbol_layer_properties.hpp +++ b/src/mbgl/style/layers/symbol_layer_properties.hpp @@ -87,6 +87,11 @@ struct IconOffset : DataDrivenLayoutProperty> { static std::array defaultValue() { return {{ 0, 0 }}; } }; +struct IconPitchAlignment : LayoutProperty { + static constexpr const char * key = "icon-pitch-alignment"; + static AlignmentType defaultValue() { return AlignmentType::Auto; } +}; + struct TextPitchAlignment : LayoutProperty { static constexpr const char * key = "text-pitch-alignment"; static AlignmentType defaultValue() { return AlignmentType::Auto; } @@ -254,6 +259,7 @@ class SymbolLayoutProperties : public Properties< IconPadding, IconKeepUpright, IconOffset, + IconPitchAlignment, TextPitchAlignment, TextRotationAlignment, TextField, -- cgit v1.2.1