From 8f6bab98c133aa9dc4316a27e517ccefc3e570a7 Mon Sep 17 00:00:00 2001 From: Stefan Karschti Date: Thu, 29 Jun 2023 22:34:22 +0300 Subject: [PATCH] Line Layer (#1142) Co-authored-by: pre-commit-ci[bot] <66853113+pre-commit-ci[bot]@users.noreply.github.com> Co-authored-by: Tim Sylvester Co-authored-by: mwilsnd --- CMakeLists.txt | 21 +- bazel/core.bzl | 7 + include/mbgl/gfx/texture2d.hpp | 2 +- include/mbgl/gfx/vertex_attribute.hpp | 2 +- include/mbgl/gl/texture2d.hpp | 2 +- include/mbgl/shaders/gl/drawable_line.hpp | 235 ++++++++++ .../shaders/gl/drawable_line_gradient.hpp | 229 +++++++++ .../mbgl/shaders/gl/drawable_line_pattern.hpp | 309 +++++++++++++ include/mbgl/shaders/gl/drawable_line_sdf.hpp | 288 ++++++++++++ include/mbgl/shaders/shader_manifest.hpp | 4 + include/mbgl/shaders/shader_source.hpp | 4 + platform/ios/app/MBXViewController.m | 58 +++ shaders/drawable.line.fragment.glsl | 58 +++ shaders/drawable.line.vertex.glsl | 110 +++++ shaders/drawable.line_gradient.fragment.glsl | 62 +++ shaders/drawable.line_gradient.vertex.glsl | 111 +++++ shaders/drawable.line_pattern.fragment.glsl | 105 +++++ shaders/drawable.line_pattern.vertex.glsl | 126 +++++ shaders/drawable.line_sdf.fragment.glsl | 79 ++++ shaders/drawable.line_sdf.vertex.glsl | 126 +++++ shaders/manifest.json | 28 ++ src/mbgl/geometry/line_atlas.cpp | 7 + src/mbgl/geometry/line_atlas.hpp | 3 + src/mbgl/gfx/line_drawable_data.hpp | 23 + src/mbgl/gfx/vertex_attribute.cpp | 4 + src/mbgl/gl/drawable_gl.cpp | 3 + src/mbgl/gl/renderer_backend.cpp | 4 + .../renderer/layers/line_layer_tweaker.cpp | 286 ++++++++++++ .../renderer/layers/line_layer_tweaker.hpp | 28 ++ .../renderer/layers/render_line_layer.cpp | 437 +++++++++++++++++- .../renderer/layers/render_line_layer.hpp | 35 +- src/mbgl/renderer/render_orchestrator.cpp | 1 - src/mbgl/renderer/render_orchestrator.hpp | 1 + 33 files changed, 2785 insertions(+), 13 deletions(-) create mode 100644 include/mbgl/shaders/gl/drawable_line.hpp create mode 100644 include/mbgl/shaders/gl/drawable_line_gradient.hpp create mode 100644 include/mbgl/shaders/gl/drawable_line_pattern.hpp create mode 100644 include/mbgl/shaders/gl/drawable_line_sdf.hpp create mode 100644 shaders/drawable.line.fragment.glsl create mode 100644 shaders/drawable.line.vertex.glsl create mode 100644 shaders/drawable.line_gradient.fragment.glsl create mode 100644 shaders/drawable.line_gradient.vertex.glsl create mode 100644 shaders/drawable.line_pattern.fragment.glsl create mode 100644 shaders/drawable.line_pattern.vertex.glsl create mode 100644 shaders/drawable.line_sdf.fragment.glsl create mode 100644 shaders/drawable.line_sdf.vertex.glsl create mode 100644 src/mbgl/gfx/line_drawable_data.hpp create mode 100644 src/mbgl/renderer/layers/line_layer_tweaker.cpp create mode 100644 src/mbgl/renderer/layers/line_layer_tweaker.hpp diff --git a/CMakeLists.txt b/CMakeLists.txt index 872e9b4be..9eb4b39d8 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -169,6 +169,8 @@ if(MLN_DRAWABLE_RENDERER) ${PROJECT_SOURCE_DIR}/src/mbgl/gfx/drawable_builder.cpp ${PROJECT_SOURCE_DIR}/src/mbgl/gfx/drawable_builder_impl.hpp ${PROJECT_SOURCE_DIR}/src/mbgl/gfx/drawable_tweaker.cpp + ${PROJECT_SOURCE_DIR}/src/mbgl/gfx/image_drawable_data.hpp + ${PROJECT_SOURCE_DIR}/src/mbgl/gfx/line_drawable_data.hpp ${PROJECT_SOURCE_DIR}/src/mbgl/gfx/shader_group.cpp ${PROJECT_SOURCE_DIR}/src/mbgl/gfx/symbol_drawable_data.hpp ${PROJECT_SOURCE_DIR}/src/mbgl/gfx/uniform_block.cpp @@ -252,6 +254,7 @@ list(APPEND INCLUDE_FILES ${PROJECT_SOURCE_DIR}/include/mbgl/platform/thread.hpp ${PROJECT_SOURCE_DIR}/include/mbgl/renderer/query.hpp ${PROJECT_SOURCE_DIR}/include/mbgl/renderer/renderer.hpp + ${PROJECT_SOURCE_DIR}/include/mbgl/renderer/layer_tweaker.hpp ${PROJECT_SOURCE_DIR}/include/mbgl/renderer/renderer_frontend.hpp ${PROJECT_SOURCE_DIR}/include/mbgl/renderer/renderer_observer.hpp ${PROJECT_SOURCE_DIR}/include/mbgl/renderer/renderer_state.hpp @@ -442,7 +445,6 @@ list(APPEND SRC_FILES ${PROJECT_SOURCE_DIR}/src/mbgl/gfx/depth_mode.hpp ${PROJECT_SOURCE_DIR}/src/mbgl/gfx/draw_mode.hpp ${PROJECT_SOURCE_DIR}/src/mbgl/gfx/draw_scope.hpp - ${PROJECT_SOURCE_DIR}/src/mbgl/gfx/image_drawable_data.hpp ${PROJECT_SOURCE_DIR}/src/mbgl/gfx/index_buffer.hpp ${PROJECT_SOURCE_DIR}/src/mbgl/gfx/index_vector.hpp ${PROJECT_SOURCE_DIR}/src/mbgl/gfx/offscreen_texture.hpp @@ -577,6 +579,19 @@ list(APPEND SRC_FILES ${PROJECT_SOURCE_DIR}/src/mbgl/renderer/image_manager.cpp ${PROJECT_SOURCE_DIR}/src/mbgl/renderer/image_manager.hpp ${PROJECT_SOURCE_DIR}/src/mbgl/renderer/image_manager_observer.hpp + ${PROJECT_SOURCE_DIR}/src/mbgl/renderer/layer_group.cpp + ${PROJECT_SOURCE_DIR}/src/mbgl/renderer/tile_layer_group.cpp + ${PROJECT_SOURCE_DIR}/src/mbgl/renderer/layer_tweaker.cpp + ${PROJECT_SOURCE_DIR}/src/mbgl/renderer/layers/line_layer_tweaker.cpp + ${PROJECT_SOURCE_DIR}/src/mbgl/renderer/layers/line_layer_tweaker.hpp + ${PROJECT_SOURCE_DIR}/src/mbgl/renderer/layers/background_layer_tweaker.cpp + ${PROJECT_SOURCE_DIR}/src/mbgl/renderer/layers/background_layer_tweaker.hpp + ${PROJECT_SOURCE_DIR}/src/mbgl/renderer/layers/circle_layer_tweaker.cpp + ${PROJECT_SOURCE_DIR}/src/mbgl/renderer/layers/circle_layer_tweaker.hpp + ${PROJECT_SOURCE_DIR}/src/mbgl/renderer/layers/fill_layer_tweaker.cpp + ${PROJECT_SOURCE_DIR}/src/mbgl/renderer/layers/fill_layer_tweaker.hpp + ${PROJECT_SOURCE_DIR}/src/mbgl/renderer/layers/raster_layer_tweaker.cpp + ${PROJECT_SOURCE_DIR}/src/mbgl/renderer/layers/raster_layer_tweaker.hpp ${PROJECT_SOURCE_DIR}/src/mbgl/renderer/layers/render_background_layer.cpp ${PROJECT_SOURCE_DIR}/src/mbgl/renderer/layers/render_background_layer.hpp ${PROJECT_SOURCE_DIR}/src/mbgl/renderer/layers/render_circle_layer.cpp @@ -985,6 +1000,10 @@ if(MLN_WITH_OPENGL) ${PROJECT_SOURCE_DIR}/include/mbgl/shaders/gl/drawable_circle.hpp ${PROJECT_SOURCE_DIR}/include/mbgl/shaders/gl/drawable_fill.hpp ${PROJECT_SOURCE_DIR}/include/mbgl/shaders/gl/drawable_fill_outline.hpp + ${PROJECT_SOURCE_DIR}/include/mbgl/shaders/gl/drawable_line.hpp + ${PROJECT_SOURCE_DIR}/include/mbgl/shaders/gl/drawable_line_gradient.hpp + ${PROJECT_SOURCE_DIR}/include/mbgl/shaders/gl/drawable_line_pattern.hpp + ${PROJECT_SOURCE_DIR}/include/mbgl/shaders/gl/drawable_line_sdf.hpp ${PROJECT_SOURCE_DIR}/include/mbgl/shaders/gl/drawable_fill_outline_pattern.hpp ${PROJECT_SOURCE_DIR}/include/mbgl/shaders/gl/drawable_fill_pattern.hpp ${PROJECT_SOURCE_DIR}/include/mbgl/shaders/gl/drawable_raster.hpp diff --git a/bazel/core.bzl b/bazel/core.bzl index d2d153976..a1b38d1d6 100644 --- a/bazel/core.bzl +++ b/bazel/core.bzl @@ -844,6 +844,10 @@ MLN_OPENGL_HEADERS = [ "include/mbgl/shaders/gl/drawable_fill_outline.hpp", "include/mbgl/shaders/gl/drawable_fill_outline_pattern.hpp", "include/mbgl/shaders/gl/drawable_fill_pattern.hpp", + "include/mbgl/shaders/gl/drawable_line_gradient.hpp", + "include/mbgl/shaders/gl/drawable_line_pattern.hpp", + "include/mbgl/shaders/gl/drawable_line_sdf.hpp", + "include/mbgl/shaders/gl/drawable_line.hpp", "include/mbgl/shaders/gl/drawable_raster.hpp", "include/mbgl/shaders/gl/drawable_symbol_icon.hpp", "include/mbgl/shaders/gl/drawable_symbol_sdf_text.hpp", @@ -878,6 +882,7 @@ MLN_DRAWABLES_SOURCE = [ "src/mbgl/gfx/drawable_builder_impl.hpp", "src/mbgl/gfx/drawable_tweaker.cpp", "src/mbgl/gfx/image_drawable_data.hpp", + "src/mbgl/gfx/line_drawable_data.hpp", "src/mbgl/gfx/symbol_drawable_data.hpp", "src/mbgl/gfx/uniform_block.cpp", "src/mbgl/gfx/uniform_buffer.cpp", @@ -892,6 +897,8 @@ MLN_DRAWABLES_SOURCE = [ "src/mbgl/renderer/layers/circle_layer_tweaker.hpp", "src/mbgl/renderer/layers/fill_layer_tweaker.cpp", "src/mbgl/renderer/layers/fill_layer_tweaker.hpp", + "src/mbgl/renderer/layers/line_layer_tweaker.cpp", + "src/mbgl/renderer/layers/line_layer_tweaker.hpp", "src/mbgl/renderer/layers/raster_layer_tweaker.cpp", "src/mbgl/renderer/layers/raster_layer_tweaker.hpp", "src/mbgl/renderer/layers/symbol_layer_tweaker.cpp", diff --git a/include/mbgl/gfx/texture2d.hpp b/include/mbgl/gfx/texture2d.hpp index ba5137c46..9f5c14a9b 100644 --- a/include/mbgl/gfx/texture2d.hpp +++ b/include/mbgl/gfx/texture2d.hpp @@ -105,7 +105,7 @@ public: /// @brief Get the underlying GL texture resource /// @note: Compat with legacy textures, to be refactored /// @return gfx::TextureResource - virtual gfx::TextureResource& getResource() = 0; + virtual gfx::TextureResource& getResource() const = 0; /// @brief Check whether the texture needs upload virtual bool needsUpload() const noexcept = 0; diff --git a/include/mbgl/gfx/vertex_attribute.hpp b/include/mbgl/gfx/vertex_attribute.hpp index 124a40329..ae749bd67 100644 --- a/include/mbgl/gfx/vertex_attribute.hpp +++ b/include/mbgl/gfx/vertex_attribute.hpp @@ -146,7 +146,7 @@ public: VertexAttributeArray(int initCapacity = 10); VertexAttributeArray(VertexAttributeArray&&); // Would need to use the virtual assignment operator - VertexAttributeArray(const VertexAttributeArray&) = delete; + VertexAttributeArray(const VertexAttributeArray&); virtual ~VertexAttributeArray() = default; /// Number of elements diff --git a/include/mbgl/gl/texture2d.hpp b/include/mbgl/gl/texture2d.hpp index e9d7c96e6..18b30959c 100644 --- a/include/mbgl/gl/texture2d.hpp +++ b/include/mbgl/gl/texture2d.hpp @@ -40,7 +40,7 @@ public: // gfx::Texture2D void uploadSubRegion(const void* pixelData, const Size& size, uint16_t xOffset, uint16_t yOffset) noexcept override; void upload() noexcept override; - gfx::TextureResource& getResource() override { + gfx::TextureResource& getResource() const override { assert(textureResource); return *textureResource; } diff --git a/include/mbgl/shaders/gl/drawable_line.hpp b/include/mbgl/shaders/gl/drawable_line.hpp new file mode 100644 index 000000000..186c394ca --- /dev/null +++ b/include/mbgl/shaders/gl/drawable_line.hpp @@ -0,0 +1,235 @@ +// Generated code, do not modify this file! +#pragma once +#include + +namespace mbgl { +namespace shaders { + +template <> +struct ShaderSource { + static constexpr const char* name = "LineShader"; + static constexpr const char* vertex = R"(// floor(127 / 2) == 63.0 +// the maximum allowed miter limit is 2.0 at the moment. the extrude normal is +// stored in a byte (-128..127). we scale regular normals up to length 63, but +// there are also "special" normals that have a bigger length (of up to 126 in +// this case). +// #define scale 63.0 +#define scale 0.015873016 + +layout (location = 0) in vec2 a_pos_normal; +layout (location = 1) in vec4 a_data; + +layout (std140) uniform LineUBO { + highp mat4 u_matrix; + highp vec2 u_units_to_pixels; + mediump float u_ratio; + lowp float u_device_pixel_ratio; +}; + +layout (std140) uniform LinePropertiesUBO { + highp vec4 u_color; + lowp float u_blur; + lowp float u_opacity; + mediump float u_gapwidth; + lowp float u_offset; + mediump float u_width; + + highp float pad1; + highp vec2 pad2; +}; + +layout (std140) uniform LineInterpolationUBO { + lowp float u_color_t; + lowp float u_blur_t; + lowp float u_opacity_t; + lowp float u_gapwidth_t; + lowp float u_offset_t; + lowp float u_width_t; + + highp vec2 pad3; +}; + +out vec2 v_normal; +out vec2 v_width2; +out float v_gamma_scale; +out highp float v_linesofar; + +#ifndef HAS_UNIFORM_u_color +layout (location = 2) in highp vec4 a_color; +out highp vec4 color; +#endif +#ifndef HAS_UNIFORM_u_blur +layout (location = 3) in lowp vec2 a_blur; +out lowp float blur; +#endif +#ifndef HAS_UNIFORM_u_opacity +layout (location = 4) in lowp vec2 a_opacity; +out lowp float opacity; +#endif +#ifndef HAS_UNIFORM_u_gapwidth +layout (location = 5) in mediump vec2 a_gapwidth; +#endif +#ifndef HAS_UNIFORM_u_offset +layout (location = 6) in lowp vec2 a_offset; +#endif +#ifndef HAS_UNIFORM_u_width +layout (location = 7) in mediump vec2 a_width; +#endif + +void main() { + #ifndef HAS_UNIFORM_u_color +color = unpack_mix_color(a_color, u_color_t); +#else +highp vec4 color = u_color; +#endif + #ifndef HAS_UNIFORM_u_blur +blur = unpack_mix_vec2(a_blur, u_blur_t); +#else +lowp float blur = u_blur; +#endif + #ifndef HAS_UNIFORM_u_opacity +opacity = unpack_mix_vec2(a_opacity, u_opacity_t); +#else +lowp float opacity = u_opacity; +#endif + #ifndef HAS_UNIFORM_u_gapwidth +mediump float gapwidth = unpack_mix_vec2(a_gapwidth, u_gapwidth_t); +#else +mediump float gapwidth = u_gapwidth; +#endif + #ifndef HAS_UNIFORM_u_offset +lowp float offset = unpack_mix_vec2(a_offset, u_offset_t); +#else +lowp float offset = u_offset; +#endif + #ifndef HAS_UNIFORM_u_width +mediump float width = unpack_mix_vec2(a_width, u_width_t); +#else +mediump float width = u_width; +#endif + + // the distance over which the line edge fades out. + // Retina devices need a smaller distance to avoid aliasing. + float ANTIALIASING = 1.0 / u_device_pixel_ratio / 2.0; + + vec2 a_extrude = a_data.xy - 128.0; + float a_direction = mod(a_data.z, 4.0) - 1.0; + + v_linesofar = (floor(a_data.z / 4.0) + a_data.w * 64.0) * 2.0; + + vec2 pos = floor(a_pos_normal * 0.5); + + // x is 1 if it's a round cap, 0 otherwise + // y is 1 if the normal points up, and -1 if it points down + // We store these in the least significant bit of a_pos_normal + mediump vec2 normal = a_pos_normal - 2.0 * pos; + normal.y = normal.y * 2.0 - 1.0; + v_normal = normal; + + // these transformations used to be applied in the JS and native code bases. + // moved them into the shader for clarity and simplicity. + gapwidth = gapwidth / 2.0; + float halfwidth = width / 2.0; + offset = -1.0 * offset; + + float inset = gapwidth + (gapwidth > 0.0 ? ANTIALIASING : 0.0); + float outset = gapwidth + halfwidth * (gapwidth > 0.0 ? 2.0 : 1.0) + (halfwidth == 0.0 ? 0.0 : ANTIALIASING); + + // Scale the extrusion vector down to a normal and then up by the line width + // of this vertex. + mediump vec2 dist = outset * a_extrude * scale; + + // Calculate the offset when drawing a line that is to the side of the actual line. + // We do this by creating a vector that points towards the extrude, but rotate + // it when we're drawing round end points (a_direction = -1 or 1) since their + // extrude vector points in another direction. + mediump float u = 0.5 * a_direction; + mediump float t = 1.0 - abs(u); + mediump vec2 offset2 = offset * a_extrude * scale * normal.y * mat2(t, -u, u, t); + + vec4 projected_extrude = u_matrix * vec4(dist / u_ratio, 0.0, 0.0); + gl_Position = u_matrix * vec4(pos + offset2 / u_ratio, 0.0, 1.0) + projected_extrude; + + // calculate how much the perspective view squishes or stretches the extrude + float extrude_length_without_perspective = length(dist); + float extrude_length_with_perspective = length(projected_extrude.xy / gl_Position.w * u_units_to_pixels); + v_gamma_scale = extrude_length_without_perspective / extrude_length_with_perspective; + + v_width2 = vec2(outset, inset); +} +)"; + static constexpr const char* fragment = R"(layout (std140) uniform LineUBO { + highp mat4 u_matrix; + highp vec2 u_units_to_pixels; + mediump float u_ratio; + lowp float u_device_pixel_ratio; +}; + +layout (std140) uniform LinePropertiesUBO { + highp vec4 u_color; + lowp float u_blur; + lowp float u_opacity; + mediump float u_gapwidth; + lowp float u_offset; + mediump float u_width; + + highp float pad1; + highp vec2 pad2; +}; + +layout (std140) uniform LineInterpolationUBO { + lowp float u_color_t; + lowp float u_blur_t; + lowp float u_opacity_t; + lowp float u_gapwidth_t; + lowp float u_offset_t; + lowp float u_width_t; + + highp vec2 pad3; +}; + +in vec2 v_width2; +in vec2 v_normal; +in float v_gamma_scale; + +#ifndef HAS_UNIFORM_u_color +in highp vec4 color; +#endif +#ifndef HAS_UNIFORM_u_blur +in lowp float blur; +#endif +#ifndef HAS_UNIFORM_u_opacity +in lowp float opacity; +#endif + +void main() { + #ifdef HAS_UNIFORM_u_color +highp vec4 color = u_color; +#endif + #ifdef HAS_UNIFORM_u_blur +lowp float blur = u_blur; +#endif + #ifdef HAS_UNIFORM_u_opacity +lowp float opacity = u_opacity; +#endif + + // Calculate the distance of the pixel from the line in pixels. + float dist = length(v_normal) * v_width2.s; + + // Calculate the antialiasing fade factor. This is either when fading in + // the line in case of an offset line (v_width2.t) or when fading out + // (v_width2.s) + float blur2 = (blur + 1.0 / u_device_pixel_ratio) * v_gamma_scale; + float alpha = clamp(min(dist - (v_width2.t - blur2), v_width2.s - dist) / blur2, 0.0, 1.0); + + fragColor = color * (alpha * opacity); + +#ifdef OVERDRAW_INSPECTOR + fragColor = vec4(1.0); +#endif +} +)"; +}; + +} // namespace shaders +} // namespace mbgl diff --git a/include/mbgl/shaders/gl/drawable_line_gradient.hpp b/include/mbgl/shaders/gl/drawable_line_gradient.hpp new file mode 100644 index 000000000..c1c44aa5a --- /dev/null +++ b/include/mbgl/shaders/gl/drawable_line_gradient.hpp @@ -0,0 +1,229 @@ +// Generated code, do not modify this file! +#pragma once +#include + +namespace mbgl { +namespace shaders { + +template <> +struct ShaderSource { + static constexpr const char* name = "LineGradientShader"; + static constexpr const char* vertex = R"( +// the attribute conveying progress along a line is scaled to [0, 2^15) +#define MAX_LINE_DISTANCE 32767.0 + +// floor(127 / 2) == 63.0 +// the maximum allowed miter limit is 2.0 at the moment. the extrude normal is +// stored in a byte (-128..127). we scale regular normals up to length 63, but +// there are also "special" normals that have a bigger length (of up to 126 in +// this case). +// #define scale 63.0 +#define scale 0.015873016 + +layout (location = 0) in vec2 a_pos_normal; +layout (location = 1) in vec4 a_data; + +layout (std140) uniform LineGradientUBO { + highp mat4 u_matrix; + highp vec2 u_units_to_pixels; + mediump float u_ratio; + lowp float u_device_pixel_ratio; +}; + +layout (std140) uniform LineGradientPropertiesUBO { + lowp float u_blur; + lowp float u_opacity; + mediump float u_gapwidth; + lowp float u_offset; + mediump float u_width; + + highp float pad1; + highp vec2 pad2; +}; + +layout (std140) uniform LineGradientInterpolationUBO { + lowp float u_blur_t; + lowp float u_opacity_t; + lowp float u_gapwidth_t; + lowp float u_offset_t; + lowp float u_width_t; + + highp float pad3; + highp vec2 pad4; +}; + +out vec2 v_normal; +out vec2 v_width2; +out float v_gamma_scale; +out highp float v_lineprogress; + +#ifndef HAS_UNIFORM_u_blur +layout (location = 2) in lowp vec2 a_blur; +out lowp float blur; +#endif +#ifndef HAS_UNIFORM_u_opacity +layout (location = 3) in lowp vec2 a_opacity; +out lowp float opacity; +#endif +#ifndef HAS_UNIFORM_u_gapwidth +layout (location = 4) in mediump vec2 a_gapwidth; +#endif +#ifndef HAS_UNIFORM_u_offset +layout (location = 5) in lowp vec2 a_offset; +#endif +#ifndef HAS_UNIFORM_u_width +layout (location = 6) in mediump vec2 a_width; +#endif + +void main() { + #ifndef HAS_UNIFORM_u_blur +blur = unpack_mix_vec2(a_blur, u_blur_t); +#else +lowp float blur = u_blur; +#endif + #ifndef HAS_UNIFORM_u_opacity +opacity = unpack_mix_vec2(a_opacity, u_opacity_t); +#else +lowp float opacity = u_opacity; +#endif + #ifndef HAS_UNIFORM_u_gapwidth +mediump float gapwidth = unpack_mix_vec2(a_gapwidth, u_gapwidth_t); +#else +mediump float gapwidth = u_gapwidth; +#endif + #ifndef HAS_UNIFORM_u_offset +lowp float offset = unpack_mix_vec2(a_offset, u_offset_t); +#else +lowp float offset = u_offset; +#endif + #ifndef HAS_UNIFORM_u_width +mediump float width = unpack_mix_vec2(a_width, u_width_t); +#else +mediump float width = u_width; +#endif + + // the distance over which the line edge fades out. + // Retina devices need a smaller distance to avoid aliasing. + float ANTIALIASING = 1.0 / u_device_pixel_ratio / 2.0; + + vec2 a_extrude = a_data.xy - 128.0; + float a_direction = mod(a_data.z, 4.0) - 1.0; + + v_lineprogress = (floor(a_data.z / 4.0) + a_data.w * 64.0) * 2.0 / MAX_LINE_DISTANCE; + + vec2 pos = floor(a_pos_normal * 0.5); + + // x is 1 if it's a round cap, 0 otherwise + // y is 1 if the normal points up, and -1 if it points down + // We store these in the least significant bit of a_pos_normal + mediump vec2 normal = a_pos_normal - 2.0 * pos; + normal.y = normal.y * 2.0 - 1.0; + v_normal = normal; + + // these transformations used to be applied in the JS and native code bases. + // moved them into the shader for clarity and simplicity. + gapwidth = gapwidth / 2.0; + float halfwidth = width / 2.0; + offset = -1.0 * offset; + + float inset = gapwidth + (gapwidth > 0.0 ? ANTIALIASING : 0.0); + float outset = gapwidth + halfwidth * (gapwidth > 0.0 ? 2.0 : 1.0) + (halfwidth == 0.0 ? 0.0 : ANTIALIASING); + + // Scale the extrusion vector down to a normal and then up by the line width + // of this vertex. + mediump vec2 dist = outset * a_extrude * scale; + + // Calculate the offset when drawing a line that is to the side of the actual line. + // We do this by creating a vector that points towards the extrude, but rotate + // it when we're drawing round end points (a_direction = -1 or 1) since their + // extrude vector points in another direction. + mediump float u = 0.5 * a_direction; + mediump float t = 1.0 - abs(u); + mediump vec2 offset2 = offset * a_extrude * scale * normal.y * mat2(t, -u, u, t); + + vec4 projected_extrude = u_matrix * vec4(dist / u_ratio, 0.0, 0.0); + gl_Position = u_matrix * vec4(pos + offset2 / u_ratio, 0.0, 1.0) + projected_extrude; + + // calculate how much the perspective view squishes or stretches the extrude + float extrude_length_without_perspective = length(dist); + float extrude_length_with_perspective = length(projected_extrude.xy / gl_Position.w * u_units_to_pixels); + v_gamma_scale = extrude_length_without_perspective / extrude_length_with_perspective; + + v_width2 = vec2(outset, inset); +} +)"; + static constexpr const char* fragment = R"(layout (std140) uniform LineGradientUBO { + highp mat4 u_matrix; + highp vec2 u_units_to_pixels; + mediump float u_ratio; + lowp float u_device_pixel_ratio; +}; + +layout (std140) uniform LineGradientPropertiesUBO { + lowp float u_blur; + lowp float u_opacity; + mediump float u_gapwidth; + lowp float u_offset; + mediump float u_width; + + highp float pad1; + highp vec2 pad2; +}; + +layout (std140) uniform LineGradientInterpolationUBO { + lowp float u_blur_t; + lowp float u_opacity_t; + lowp float u_gapwidth_t; + lowp float u_offset_t; + lowp float u_width_t; + + highp float pad3; + highp vec2 pad4; +}; + +uniform sampler2D u_image; + +in vec2 v_width2; +in vec2 v_normal; +in float v_gamma_scale; +in highp float v_lineprogress; + +#ifndef HAS_UNIFORM_u_blur +in lowp float blur; +#endif +#ifndef HAS_UNIFORM_u_opacity +in lowp float opacity; +#endif + +void main() { + #ifdef HAS_UNIFORM_u_blur +lowp float blur = u_blur; +#endif + #ifdef HAS_UNIFORM_u_opacity +lowp float opacity = u_opacity; +#endif + + // Calculate the distance of the pixel from the line in pixels. + float dist = length(v_normal) * v_width2.s; + + // Calculate the antialiasing fade factor. This is either when fading in + // the line in case of an offset line (v_width2.t) or when fading out + // (v_width2.s) + float blur2 = (blur + 1.0 / u_device_pixel_ratio) * v_gamma_scale; + float alpha = clamp(min(dist - (v_width2.t - blur2), v_width2.s - dist) / blur2, 0.0, 1.0); + + // For gradient lines, v_lineprogress is the ratio along the entire line, + // scaled to [0, 2^15), and the gradient ramp is stored in a texture. + vec4 color = texture(u_image, vec2(v_lineprogress, 0.5)); + + fragColor = color * (alpha * opacity); + +#ifdef OVERDRAW_INSPECTOR + fragColor = vec4(1.0); +#endif +} +)"; +}; + +} // namespace shaders +} // namespace mbgl diff --git a/include/mbgl/shaders/gl/drawable_line_pattern.hpp b/include/mbgl/shaders/gl/drawable_line_pattern.hpp new file mode 100644 index 000000000..391df59c9 --- /dev/null +++ b/include/mbgl/shaders/gl/drawable_line_pattern.hpp @@ -0,0 +1,309 @@ +// Generated code, do not modify this file! +#pragma once +#include + +namespace mbgl { +namespace shaders { + +template <> +struct ShaderSource { + static constexpr const char* name = "LinePatternShader"; + static constexpr const char* vertex = R"(// floor(127 / 2) == 63.0 +// the maximum allowed miter limit is 2.0 at the moment. the extrude normal is +// stored in a byte (-128..127). we scale regular normals up to length 63, but +// there are also "special" normals that have a bigger length (of up to 126 in +// this case). +// #define scale 63.0 +#define scale 0.015873016 + +// We scale the distance before adding it to the buffers so that we can store +// long distances for long segments. Use this value to unscale the distance. +#define LINE_DISTANCE_SCALE 2.0 + +layout (location = 0) in vec2 a_pos_normal; +layout (location = 1) in vec4 a_data; + +layout (std140) uniform LinePatternUBO { + highp mat4 u_matrix; + mediump vec4 u_scale; + highp vec2 u_texsize; + highp vec2 u_units_to_pixels; + mediump float u_ratio; + lowp float u_device_pixel_ratio; + highp float u_fade; + + highp float pad1; +}; + +layout (std140) uniform LinePatternPropertiesUBO { + lowp float u_blur; + lowp float u_opacity; + lowp float u_offset; + mediump float u_gapwidth; + mediump float u_width; + + highp float pad2; + highp vec2 pad3; +}; + +layout (std140) uniform LinePatternTilePropertiesUBO { + lowp vec4 u_pattern_from; + lowp vec4 u_pattern_to; +}; + +layout (std140) uniform LinePatternInterpolationUBO { + lowp float u_blur_t; + lowp float u_opacity_t; + lowp float u_offset_t; + lowp float u_gapwidth_t; + lowp float u_width_t; + lowp float u_pattern_from_t; + lowp float u_pattern_to_t; + + highp float pad4; +}; + +out vec2 v_normal; +out vec2 v_width2; +out float v_linesofar; +out float v_gamma_scale; + +#ifndef HAS_UNIFORM_u_blur +layout (location = 2) in lowp vec2 a_blur; +out lowp float blur; +#endif +#ifndef HAS_UNIFORM_u_opacity +layout (location = 3) in lowp vec2 a_opacity; +out lowp float opacity; +#endif +#ifndef HAS_UNIFORM_u_offset +layout (location = 4) in lowp vec2 a_offset; +#endif +#ifndef HAS_UNIFORM_u_gapwidth +layout (location = 5) in mediump vec2 a_gapwidth; +#endif +#ifndef HAS_UNIFORM_u_width +layout (location = 6) in mediump vec2 a_width; +#endif +#ifndef HAS_UNIFORM_u_pattern_from +layout (location = 7) in lowp vec4 a_pattern_from; +out lowp vec4 pattern_from; +#endif +#ifndef HAS_UNIFORM_u_pattern_to +layout (location = 8) in lowp vec4 a_pattern_to; +out lowp vec4 pattern_to; +#endif + +void main() { + #ifndef HAS_UNIFORM_u_blur +blur = unpack_mix_vec2(a_blur, u_blur_t); +#else +lowp float blur = u_blur; +#endif + #ifndef HAS_UNIFORM_u_opacity +opacity = unpack_mix_vec2(a_opacity, u_opacity_t); +#else +lowp float opacity = u_opacity; +#endif + #ifndef HAS_UNIFORM_u_offset +lowp float offset = unpack_mix_vec2(a_offset, u_offset_t); +#else +lowp float offset = u_offset; +#endif + #ifndef HAS_UNIFORM_u_gapwidth +mediump float gapwidth = unpack_mix_vec2(a_gapwidth, u_gapwidth_t); +#else +mediump float gapwidth = u_gapwidth; +#endif + #ifndef HAS_UNIFORM_u_width +mediump float width = unpack_mix_vec2(a_width, u_width_t); +#else +mediump float width = u_width; +#endif + #ifndef HAS_UNIFORM_u_pattern_from +pattern_from = a_pattern_from; +#else +mediump vec4 pattern_from = u_pattern_from; +#endif + #ifndef HAS_UNIFORM_u_pattern_to +pattern_to = a_pattern_to; +#else +mediump vec4 pattern_to = u_pattern_to; +#endif + + // the distance over which the line edge fades out. + // Retina devices need a smaller distance to avoid aliasing. + float ANTIALIASING = 1.0 / u_device_pixel_ratio / 2.0; + + vec2 a_extrude = a_data.xy - 128.0; + float a_direction = mod(a_data.z, 4.0) - 1.0; + float a_linesofar = (floor(a_data.z / 4.0) + a_data.w * 64.0) * LINE_DISTANCE_SCALE; + // float tileRatio = u_scale.y; + vec2 pos = floor(a_pos_normal * 0.5); + + // x is 1 if it's a round cap, 0 otherwise + // y is 1 if the normal points up, and -1 if it points down + // We store these in the least significant bit of a_pos_normal + mediump vec2 normal = a_pos_normal - 2.0 * pos; + normal.y = normal.y * 2.0 - 1.0; + v_normal = normal; + + // these transformations used to be applied in the JS and native code bases. + // moved them into the shader for clarity and simplicity. + gapwidth = gapwidth / 2.0; + float halfwidth = width / 2.0; + offset = -1.0 * offset; + + float inset = gapwidth + (gapwidth > 0.0 ? ANTIALIASING : 0.0); + float outset = gapwidth + halfwidth * (gapwidth > 0.0 ? 2.0 : 1.0) + (halfwidth == 0.0 ? 0.0 : ANTIALIASING); + + // Scale the extrusion vector down to a normal and then up by the line width + // of this vertex. + mediump vec2 dist = outset * a_extrude * scale; + + // Calculate the offset when drawing a line that is to the side of the actual line. + // We do this by creating a vector that points towards the extrude, but rotate + // it when we're drawing round end points (a_direction = -1 or 1) since their + // extrude vector points in another direction. + mediump float u = 0.5 * a_direction; + mediump float t = 1.0 - abs(u); + mediump vec2 offset2 = offset * a_extrude * scale * normal.y * mat2(t, -u, u, t); + + vec4 projected_extrude = u_matrix * vec4(dist / u_ratio, 0.0, 0.0); + gl_Position = u_matrix * vec4(pos + offset2 / u_ratio, 0.0, 1.0) + projected_extrude; + + // calculate how much the perspective view squishes or stretches the extrude + float extrude_length_without_perspective = length(dist); + float extrude_length_with_perspective = length(projected_extrude.xy / gl_Position.w * u_units_to_pixels); + v_gamma_scale = extrude_length_without_perspective / extrude_length_with_perspective; + + v_linesofar = a_linesofar; + v_width2 = vec2(outset, inset); +} +)"; + static constexpr const char* fragment = R"(layout (std140) uniform LinePatternUBO { + highp mat4 u_matrix; + mediump vec4 u_scale; + highp vec2 u_texsize; + highp vec2 u_units_to_pixels; + mediump float u_ratio; + lowp float u_device_pixel_ratio; + highp float u_fade; + + highp float pad1; +}; + +layout (std140) uniform LinePatternPropertiesUBO { + lowp float u_blur; + lowp float u_opacity; + lowp float u_offset; + mediump float u_gapwidth; + mediump float u_width; + + highp float pad2; + highp vec2 pad3; +}; + +layout (std140) uniform LinePatternTilePropertiesUBO { + lowp vec4 u_pattern_from; + lowp vec4 u_pattern_to; +}; + +layout (std140) uniform LinePatternInterpolationUBO { + lowp float u_blur_t; + lowp float u_opacity_t; + lowp float u_offset_t; + lowp float u_gapwidth_t; + lowp float u_width_t; + lowp float u_pattern_from_t; + lowp float u_pattern_to_t; + + highp float pad4; +}; + +uniform sampler2D u_image; + +in vec2 v_normal; +in vec2 v_width2; +in float v_linesofar; +in float v_gamma_scale; + +#ifndef HAS_UNIFORM_u_pattern_from +in lowp vec4 pattern_from; +#endif +#ifndef HAS_UNIFORM_u_pattern_to +in lowp vec4 pattern_to; +#endif +#ifndef HAS_UNIFORM_u_blur +in lowp float blur; +#endif +#ifndef HAS_UNIFORM_u_opacity +in lowp float opacity; +#endif + +void main() { + #ifdef HAS_UNIFORM_u_pattern_from +mediump vec4 pattern_from = u_pattern_from; +#endif + #ifdef HAS_UNIFORM_u_pattern_to +mediump vec4 pattern_to = u_pattern_to; +#endif + + #ifdef HAS_UNIFORM_u_blur +lowp float blur = u_blur; +#endif + #ifdef HAS_UNIFORM_u_opacity +lowp float opacity = u_opacity; +#endif + + vec2 pattern_tl_a = pattern_from.xy; + vec2 pattern_br_a = pattern_from.zw; + vec2 pattern_tl_b = pattern_to.xy; + vec2 pattern_br_b = pattern_to.zw; + + float pixelRatio = u_scale.x; + float tileZoomRatio = u_scale.y; + float fromScale = u_scale.z; + float toScale = u_scale.w; + + vec2 display_size_a = vec2((pattern_br_a.x - pattern_tl_a.x) / pixelRatio, (pattern_br_a.y - pattern_tl_a.y) / pixelRatio); + vec2 display_size_b = vec2((pattern_br_b.x - pattern_tl_b.x) / pixelRatio, (pattern_br_b.y - pattern_tl_b.y) / pixelRatio); + + vec2 pattern_size_a = vec2(display_size_a.x * fromScale / tileZoomRatio, display_size_a.y); + vec2 pattern_size_b = vec2(display_size_b.x * toScale / tileZoomRatio, display_size_b.y); + + // Calculate the distance of the pixel from the line in pixels. + float dist = length(v_normal) * v_width2.s; + + // Calculate the antialiasing fade factor. This is either when fading in + // the line in case of an offset line (v_width2.t) or when fading out + // (v_width2.s) + float blur2 = (blur + 1.0 / u_device_pixel_ratio) * v_gamma_scale; + float alpha = clamp(min(dist - (v_width2.t - blur2), v_width2.s - dist) / blur2, 0.0, 1.0); + + float x_a = mod(v_linesofar / pattern_size_a.x, 1.0); + float x_b = mod(v_linesofar / pattern_size_b.x, 1.0); + + // v_normal.y is 0 at the midpoint of the line, -1 at the lower edge, 1 at the upper edge + // we clamp the line width outset to be between 0 and half the pattern height plus padding (2.0) + // to ensure we don't sample outside the designated symbol on the sprite sheet. + // 0.5 is added to shift the component to be bounded between 0 and 1 for interpolation of + // the texture coordinate + float y_a = 0.5 + (v_normal.y * clamp(v_width2.s, 0.0, (pattern_size_a.y + 2.0) / 2.0) / pattern_size_a.y); + float y_b = 0.5 + (v_normal.y * clamp(v_width2.s, 0.0, (pattern_size_b.y + 2.0) / 2.0) / pattern_size_b.y); + vec2 pos_a = mix(pattern_tl_a / u_texsize, pattern_br_a / u_texsize, vec2(x_a, y_a)); + vec2 pos_b = mix(pattern_tl_b / u_texsize, pattern_br_b / u_texsize, vec2(x_b, y_b)); + + vec4 color = mix(texture(u_image, pos_a), texture(u_image, pos_b), u_fade); + + fragColor = color * alpha * opacity; + +#ifdef OVERDRAW_INSPECTOR + fragColor = vec4(1.0); +#endif +} +)"; +}; + +} // namespace shaders +} // namespace mbgl diff --git a/include/mbgl/shaders/gl/drawable_line_sdf.hpp b/include/mbgl/shaders/gl/drawable_line_sdf.hpp new file mode 100644 index 000000000..43c2fb016 --- /dev/null +++ b/include/mbgl/shaders/gl/drawable_line_sdf.hpp @@ -0,0 +1,288 @@ +// Generated code, do not modify this file! +#pragma once +#include + +namespace mbgl { +namespace shaders { + +template <> +struct ShaderSource { + static constexpr const char* name = "LineSDFShader"; + static constexpr const char* vertex = R"(// floor(127 / 2) == 63.0 +// the maximum allowed miter limit is 2.0 at the moment. the extrude normal is +// stored in a byte (-128..127). we scale regular normals up to length 63, but +// there are also "special" normals that have a bigger length (of up to 126 in +// this case). +// #define scale 63.0 +#define scale 0.015873016 + +// We scale the distance before adding it to the buffers so that we can store +// long distances for long segments. Use this value to unscale the distance. +#define LINE_DISTANCE_SCALE 2.0 + +layout (location = 0) in vec2 a_pos_normal; +layout (location = 1) in vec4 a_data; + +layout (std140) uniform LineSDFUBO { + highp mat4 u_matrix; + highp vec2 u_units_to_pixels; + highp vec2 u_patternscale_a; + highp vec2 u_patternscale_b; + mediump float u_ratio; + lowp float u_device_pixel_ratio; + highp float u_tex_y_a; + highp float u_tex_y_b; + highp float u_sdfgamma; + highp float u_mix; +}; + +layout (std140) uniform LineSDFPropertiesUBO { + highp vec4 u_color; + lowp float u_blur; + lowp float u_opacity; + mediump float u_gapwidth; + lowp float u_offset; + mediump float u_width; + lowp float u_floorwidth; + + highp vec2 pad1; +}; + +layout (std140) uniform LineSDFInterpolationUBO { + lowp float u_color_t; + lowp float u_blur_t; + lowp float u_opacity_t; + lowp float u_gapwidth_t; + lowp float u_offset_t; + lowp float u_width_t; + lowp float u_floorwidth_t; + + highp float pad2; +}; + +out vec2 v_normal; +out vec2 v_width2; +out vec2 v_tex_a; +out vec2 v_tex_b; +out float v_gamma_scale; + +#ifndef HAS_UNIFORM_u_color +layout (location = 2) in highp vec4 a_color; +out highp vec4 color; +#endif +#ifndef HAS_UNIFORM_u_blur +layout (location = 3) in lowp vec2 a_blur; +out lowp float blur; +#endif +#ifndef HAS_UNIFORM_u_opacity +layout (location = 4) in lowp vec2 a_opacity; +out lowp float opacity; +#endif +#ifndef HAS_UNIFORM_u_gapwidth +layout (location = 5) in mediump vec2 a_gapwidth; +#endif +#ifndef HAS_UNIFORM_u_offset +layout (location = 6) in lowp vec2 a_offset; +#endif +#ifndef HAS_UNIFORM_u_width +layout (location = 7) in mediump vec2 a_width; +out mediump float width; +#endif +#ifndef HAS_UNIFORM_u_floorwidth +layout (location = 8) in lowp vec2 a_floorwidth; +out lowp float floorwidth; +#endif + +void main() { + #ifndef HAS_UNIFORM_u_color +color = unpack_mix_color(a_color, u_color_t); +#else +highp vec4 color = u_color; +#endif + #ifndef HAS_UNIFORM_u_blur +blur = unpack_mix_vec2(a_blur, u_blur_t); +#else +lowp float blur = u_blur; +#endif + #ifndef HAS_UNIFORM_u_opacity +opacity = unpack_mix_vec2(a_opacity, u_opacity_t); +#else +lowp float opacity = u_opacity; +#endif + #ifndef HAS_UNIFORM_u_gapwidth +mediump float gapwidth = unpack_mix_vec2(a_gapwidth, u_gapwidth_t); +#else +mediump float gapwidth = u_gapwidth; +#endif + #ifndef HAS_UNIFORM_u_offset +lowp float offset = unpack_mix_vec2(a_offset, u_offset_t); +#else +lowp float offset = u_offset; +#endif + #ifndef HAS_UNIFORM_u_width +width = unpack_mix_vec2(a_width, u_width_t); +#else +mediump float width = u_width; +#endif + #ifndef HAS_UNIFORM_u_floorwidth +floorwidth = unpack_mix_vec2(a_floorwidth, u_floorwidth_t); +#else +lowp float floorwidth = u_floorwidth; +#endif + + // the distance over which the line edge fades out. + // Retina devices need a smaller distance to avoid aliasing. + float ANTIALIASING = 1.0 / u_device_pixel_ratio / 2.0; + + vec2 a_extrude = a_data.xy - 128.0; + float a_direction = mod(a_data.z, 4.0) - 1.0; + float a_linesofar = (floor(a_data.z / 4.0) + a_data.w * 64.0) * LINE_DISTANCE_SCALE; + + vec2 pos = floor(a_pos_normal * 0.5); + + // x is 1 if it's a round cap, 0 otherwise + // y is 1 if the normal points up, and -1 if it points down + // We store these in the least significant bit of a_pos_normal + mediump vec2 normal = a_pos_normal - 2.0 * pos; + normal.y = normal.y * 2.0 - 1.0; + v_normal = normal; + + // these transformations used to be applied in the JS and native code bases. + // moved them into the shader for clarity and simplicity. + gapwidth = gapwidth / 2.0; + float halfwidth = width / 2.0; + offset = -1.0 * offset; + + float inset = gapwidth + (gapwidth > 0.0 ? ANTIALIASING : 0.0); + float outset = gapwidth + halfwidth * (gapwidth > 0.0 ? 2.0 : 1.0) + (halfwidth == 0.0 ? 0.0 : ANTIALIASING); + + // Scale the extrusion vector down to a normal and then up by the line width + // of this vertex. + mediump vec2 dist =outset * a_extrude * scale; + + // Calculate the offset when drawing a line that is to the side of the actual line. + // We do this by creating a vector that points towards the extrude, but rotate + // it when we're drawing round end points (a_direction = -1 or 1) since their + // extrude vector points in another direction. + mediump float u = 0.5 * a_direction; + mediump float t = 1.0 - abs(u); + mediump vec2 offset2 = offset * a_extrude * scale * normal.y * mat2(t, -u, u, t); + + vec4 projected_extrude = u_matrix * vec4(dist / u_ratio, 0.0, 0.0); + gl_Position = u_matrix * vec4(pos + offset2 / u_ratio, 0.0, 1.0) + projected_extrude; + + // calculate how much the perspective view squishes or stretches the extrude + float extrude_length_without_perspective = length(dist); + float extrude_length_with_perspective = length(projected_extrude.xy / gl_Position.w * u_units_to_pixels); + v_gamma_scale = extrude_length_without_perspective / extrude_length_with_perspective; + + v_tex_a = vec2(a_linesofar * u_patternscale_a.x / floorwidth, normal.y * u_patternscale_a.y + u_tex_y_a); + v_tex_b = vec2(a_linesofar * u_patternscale_b.x / floorwidth, normal.y * u_patternscale_b.y + u_tex_y_b); + + v_width2 = vec2(outset, inset); +} +)"; + static constexpr const char* fragment = R"( +layout (std140) uniform LineSDFUBO { + highp mat4 u_matrix; + highp vec2 u_units_to_pixels; + highp vec2 u_patternscale_a; + highp vec2 u_patternscale_b; + mediump float u_ratio; + lowp float u_device_pixel_ratio; + highp float u_tex_y_a; + highp float u_tex_y_b; + highp float u_sdfgamma; + highp float u_mix; +}; + +layout (std140) uniform LineSDFPropertiesUBO { + highp vec4 u_color; + lowp float u_blur; + lowp float u_opacity; + mediump float u_gapwidth; + lowp float u_offset; + mediump float u_width; + lowp float u_floorwidth; + + highp vec2 pad1; +}; + +layout (std140) uniform LineSDFInterpolationUBO { + lowp float u_color_t; + lowp float u_blur_t; + lowp float u_opacity_t; + lowp float u_gapwidth_t; + lowp float u_offset_t; + lowp float u_width_t; + lowp float u_floorwidth_t; + + highp float pad2; +}; + +uniform sampler2D u_image; + +in vec2 v_normal; +in vec2 v_width2; +in vec2 v_tex_a; +in vec2 v_tex_b; +in float v_gamma_scale; + +#ifndef HAS_UNIFORM_u_color +in highp vec4 color; +#endif +#ifndef HAS_UNIFORM_u_blur +in lowp float blur; +#endif +#ifndef HAS_UNIFORM_u_opacity +in lowp float opacity; +#endif +#ifndef HAS_UNIFORM_u_width +in mediump float width; +#endif +#ifndef HAS_UNIFORM_u_floorwidth +in lowp float floorwidth; +#endif + +void main() { + #ifdef HAS_UNIFORM_u_color +highp vec4 color = u_color; +#endif + #ifdef HAS_UNIFORM_u_blur +lowp float blur = u_blur; +#endif + #ifdef HAS_UNIFORM_u_opacity +lowp float opacity = u_opacity; +#endif + #ifdef HAS_UNIFORM_u_width +mediump float width = u_width; +#endif + #ifdef HAS_UNIFORM_u_floorwidth +lowp float floorwidth = u_floorwidth; +#endif + + // Calculate the distance of the pixel from the line in pixels. + float dist = length(v_normal) * v_width2.s; + + // Calculate the antialiasing fade factor. This is either when fading in + // the line in case of an offset line (v_width2.t) or when fading out + // (v_width2.s) + float blur2 = (blur + 1.0 / u_device_pixel_ratio) * v_gamma_scale; + float alpha = clamp(min(dist - (v_width2.t - blur2), v_width2.s - dist) / blur2, 0.0, 1.0); + + float sdfdist_a = texture(u_image, v_tex_a).a; + float sdfdist_b = texture(u_image, v_tex_b).a; + float sdfdist = mix(sdfdist_a, sdfdist_b, u_mix); + alpha *= smoothstep(0.5 - u_sdfgamma / floorwidth, 0.5 + u_sdfgamma / floorwidth, sdfdist); + + fragColor = color * (alpha * opacity); + +#ifdef OVERDRAW_INSPECTOR + fragColor = vec4(1.0); +#endif +} +)"; +}; + +} // namespace shaders +} // namespace mbgl diff --git a/include/mbgl/shaders/shader_manifest.hpp b/include/mbgl/shaders/shader_manifest.hpp index 3a8185a72..f1d3d974a 100644 --- a/include/mbgl/shaders/shader_manifest.hpp +++ b/include/mbgl/shaders/shader_manifest.hpp @@ -8,6 +8,10 @@ #include #include #include +#include +#include +#include +#include #include #include #include diff --git a/include/mbgl/shaders/shader_source.hpp b/include/mbgl/shaders/shader_source.hpp index e96be4572..08607a680 100644 --- a/include/mbgl/shaders/shader_source.hpp +++ b/include/mbgl/shaders/shader_source.hpp @@ -14,6 +14,10 @@ enum class BuiltIn { CircleShader, FillShader, FillOutlineShader, + LineGradientShader, + LinePatternShader, + LineSDFShader, + LineShader, FillPatternShader, FillOutlinePatternShader, RasterShader, diff --git a/platform/ios/app/MBXViewController.m b/platform/ios/app/MBXViewController.m index 419edfbfb..e0177ecad 100644 --- a/platform/ios/app/MBXViewController.m +++ b/platform/ios/app/MBXViewController.m @@ -101,6 +101,7 @@ typedef NS_ENUM(NSInteger, MBXSettingsRuntimeStylingRows) { MBXSettingsRuntimeStylingAddLimeGreenTriangleLayer, MBXSettingsRuntimeStylingDDSPolygon, MBXSettingsRuntimeStylingCustomLatLonGrid, + MBXSettingsRuntimeStylingLineGradient, }; typedef NS_ENUM(NSInteger, MBXSettingsMiscellaneousRows) { @@ -430,6 +431,7 @@ CLLocationCoordinate2D randomWorldCoordinate(void) { @"Add Lime Green Triangle Layer", @"Dynamically Style Polygon", @"Add Custom Lat/Lon Grid", + @"Style Route line with gradient", ]]; break; case MBXSettingsMiscellaneous: @@ -647,6 +649,9 @@ CLLocationCoordinate2D randomWorldCoordinate(void) { case MBXSettingsRuntimeStylingCustomLatLonGrid: [self addLatLonGrid]; break; + case MBXSettingsRuntimeStylingLineGradient: + [self styleLineGradient]; + break; default: NSAssert(NO, @"All runtime styling setting rows should be implemented"); break; @@ -1487,6 +1492,59 @@ CLLocationCoordinate2D randomWorldCoordinate(void) { [self.mapView.style localizeLabelsIntoLocale:_localizingLabels ? [NSLocale localeWithLocaleIdentifier:@"mul"] : nil]; } +- (void)styleLineGradient +{ + CLLocationCoordinate2D coords[] = { + { 43.84455590478528, 10.504238605499268 }, + { 43.84385562343126, 10.504125952720642 }, + { 43.84388657526694, 10.503299832344055 }, + { 43.84332557075269, 10.503235459327698 }, + { 43.843441641085036, 10.502264499664307 }, + { 43.84396395478592, 10.50242006778717 }, + { 43.84406067904351, 10.501744151115416 }, + { 43.84422317544319, 10.501792430877686 } + }; + NSInteger count = sizeof(coords) / sizeof(coords[0]); + + [self.mapView setCenterCoordinate:coords[0] zoomLevel:16 animated:YES]; + + MLNPolylineFeature *routeLine = [MLNPolylineFeature polylineWithCoordinates:coords count:count]; + + NSDictionary *sourceOptions = @{ MLNShapeSourceOptionLineDistanceMetrics: @YES }; + + MLNShapeSource *routeSource = [[MLNShapeSource alloc] initWithIdentifier:@"style-route-source" shape:routeLine options:sourceOptions]; + [self.mapView.style addSource:routeSource]; + + MLNLineStyleLayer *baseRouteLayer = [[MLNLineStyleLayer alloc] initWithIdentifier:@"style-base-route-layer" source:routeSource]; + baseRouteLayer.lineColor = [NSExpression expressionForConstantValue:[UIColor orangeColor]]; + baseRouteLayer.lineWidth = [NSExpression expressionForConstantValue:@20]; + baseRouteLayer.lineOpacity = [NSExpression expressionForConstantValue:@0.95]; + baseRouteLayer.lineCap = [NSExpression expressionForConstantValue:@"round"]; + baseRouteLayer.lineJoin = [NSExpression expressionForConstantValue:@"round"]; + [self.mapView.style addLayer:baseRouteLayer]; + + MLNLineStyleLayer *routeLayer = [[MLNLineStyleLayer alloc] initWithIdentifier:@"style-route-layer" source:routeSource]; + routeLayer.lineColor = [NSExpression expressionForConstantValue:[UIColor whiteColor]]; + routeLayer.lineWidth = [NSExpression expressionForConstantValue:@15]; + routeLayer.lineOpacity = [NSExpression expressionForConstantValue:@0.8]; + routeLayer.lineCap = [NSExpression expressionForConstantValue:@"round"]; + routeLayer.lineJoin = [NSExpression expressionForConstantValue:@"round"]; + // Create stops dictionary + NSDictionary *stops = @{ + @0: [UIColor blueColor], + @0.1: [UIColor colorWithRed:25 / 255.0 green:41 /255.0 blue:88 / 255.0 alpha:1.0], + @0.3: [UIColor cyanColor], + @0.5: [UIColor greenColor], + @0.7: [UIColor yellowColor], + @1: [UIColor redColor], + }; + // Create an expression that will interpolate the color of the line + // (mgl_interpolate:withCurveType:parameters:stops:($lineProgress, 'linear', nil, %@)) + NSExpression *lineGradientExpression = [NSExpression expressionWithFormat:@"mgl_interpolate:withCurveType:parameters:stops:($lineProgress, 'linear', nil, %@)", stops]; + routeLayer.lineGradient = lineGradientExpression; + [self.mapView.style addLayer:routeLayer]; +} + - (void)styleRouteLine { CLLocationCoordinate2D coords[] = { diff --git a/shaders/drawable.line.fragment.glsl b/shaders/drawable.line.fragment.glsl new file mode 100644 index 000000000..88167104f --- /dev/null +++ b/shaders/drawable.line.fragment.glsl @@ -0,0 +1,58 @@ +layout (std140) uniform LineUBO { + highp mat4 u_matrix; + highp vec2 u_units_to_pixels; + mediump float u_ratio; + lowp float u_device_pixel_ratio; +}; + +layout (std140) uniform LinePropertiesUBO { + highp vec4 u_color; + lowp float u_blur; + lowp float u_opacity; + mediump float u_gapwidth; + lowp float u_offset; + mediump float u_width; + + highp float pad1; + highp vec2 pad2; +}; + +layout (std140) uniform LineInterpolationUBO { + lowp float u_color_t; + lowp float u_blur_t; + lowp float u_opacity_t; + lowp float u_gapwidth_t; + lowp float u_offset_t; + lowp float u_width_t; + + highp vec2 pad3; +}; + +in vec2 v_width2; +in vec2 v_normal; +in float v_gamma_scale; + +#pragma mapbox: define highp vec4 color +#pragma mapbox: define lowp float blur +#pragma mapbox: define lowp float opacity + +void main() { + #pragma mapbox: initialize highp vec4 color + #pragma mapbox: initialize lowp float blur + #pragma mapbox: initialize lowp float opacity + + // Calculate the distance of the pixel from the line in pixels. + float dist = length(v_normal) * v_width2.s; + + // Calculate the antialiasing fade factor. This is either when fading in + // the line in case of an offset line (v_width2.t) or when fading out + // (v_width2.s) + float blur2 = (blur + 1.0 / u_device_pixel_ratio) * v_gamma_scale; + float alpha = clamp(min(dist - (v_width2.t - blur2), v_width2.s - dist) / blur2, 0.0, 1.0); + + fragColor = color * (alpha * opacity); + +#ifdef OVERDRAW_INSPECTOR + fragColor = vec4(1.0); +#endif +} diff --git a/shaders/drawable.line.vertex.glsl b/shaders/drawable.line.vertex.glsl new file mode 100644 index 000000000..e68edd525 --- /dev/null +++ b/shaders/drawable.line.vertex.glsl @@ -0,0 +1,110 @@ +// floor(127 / 2) == 63.0 +// the maximum allowed miter limit is 2.0 at the moment. the extrude normal is +// stored in a byte (-128..127). we scale regular normals up to length 63, but +// there are also "special" normals that have a bigger length (of up to 126 in +// this case). +// #define scale 63.0 +#define scale 0.015873016 + +layout (location = 0) in vec2 a_pos_normal; +layout (location = 1) in vec4 a_data; + +layout (std140) uniform LineUBO { + highp mat4 u_matrix; + highp vec2 u_units_to_pixels; + mediump float u_ratio; + lowp float u_device_pixel_ratio; +}; + +layout (std140) uniform LinePropertiesUBO { + highp vec4 u_color; + lowp float u_blur; + lowp float u_opacity; + mediump float u_gapwidth; + lowp float u_offset; + mediump float u_width; + + highp float pad1; + highp vec2 pad2; +}; + +layout (std140) uniform LineInterpolationUBO { + lowp float u_color_t; + lowp float u_blur_t; + lowp float u_opacity_t; + lowp float u_gapwidth_t; + lowp float u_offset_t; + lowp float u_width_t; + + highp vec2 pad3; +}; + +out vec2 v_normal; +out vec2 v_width2; +out float v_gamma_scale; +out highp float v_linesofar; + +#pragma mapbox: define highp vec4 color +#pragma mapbox: define lowp float blur +#pragma mapbox: define lowp float opacity +#pragma mapbox: define mediump float gapwidth +#pragma mapbox: define lowp float offset +#pragma mapbox: define mediump float width + +void main() { + #pragma mapbox: initialize highp vec4 color + #pragma mapbox: initialize lowp float blur + #pragma mapbox: initialize lowp float opacity + #pragma mapbox: initialize mediump float gapwidth + #pragma mapbox: initialize lowp float offset + #pragma mapbox: initialize mediump float width + + // the distance over which the line edge fades out. + // Retina devices need a smaller distance to avoid aliasing. + float ANTIALIASING = 1.0 / u_device_pixel_ratio / 2.0; + + vec2 a_extrude = a_data.xy - 128.0; + float a_direction = mod(a_data.z, 4.0) - 1.0; + + v_linesofar = (floor(a_data.z / 4.0) + a_data.w * 64.0) * 2.0; + + vec2 pos = floor(a_pos_normal * 0.5); + + // x is 1 if it's a round cap, 0 otherwise + // y is 1 if the normal points up, and -1 if it points down + // We store these in the least significant bit of a_pos_normal + mediump vec2 normal = a_pos_normal - 2.0 * pos; + normal.y = normal.y * 2.0 - 1.0; + v_normal = normal; + + // these transformations used to be applied in the JS and native code bases. + // moved them into the shader for clarity and simplicity. + gapwidth = gapwidth / 2.0; + float halfwidth = width / 2.0; + offset = -1.0 * offset; + + float inset = gapwidth + (gapwidth > 0.0 ? ANTIALIASING : 0.0); + float outset = gapwidth + halfwidth * (gapwidth > 0.0 ? 2.0 : 1.0) + (halfwidth == 0.0 ? 0.0 : ANTIALIASING); + + // Scale the extrusion vector down to a normal and then up by the line width + // of this vertex. + mediump vec2 dist = outset * a_extrude * scale; + + // Calculate the offset when drawing a line that is to the side of the actual line. + // We do this by creating a vector that points towards the extrude, but rotate + // it when we're drawing round end points (a_direction = -1 or 1) since their + // extrude vector points in another direction. + mediump float u = 0.5 * a_direction; + mediump float t = 1.0 - abs(u); + mediump vec2 offset2 = offset * a_extrude * scale * normal.y * mat2(t, -u, u, t); + + vec4 projected_extrude = u_matrix * vec4(dist / u_ratio, 0.0, 0.0); + gl_Position = u_matrix * vec4(pos + offset2 / u_ratio, 0.0, 1.0) + projected_extrude; + + // calculate how much the perspective view squishes or stretches the extrude + float extrude_length_without_perspective = length(dist); + float extrude_length_with_perspective = length(projected_extrude.xy / gl_Position.w * u_units_to_pixels); + v_gamma_scale = extrude_length_without_perspective / extrude_length_with_perspective; + + v_width2 = vec2(outset, inset); +} diff --git a/shaders/drawable.line_gradient.fragment.glsl b/shaders/drawable.line_gradient.fragment.glsl new file mode 100644 index 000000000..1f1465b9d --- /dev/null +++ b/shaders/drawable.line_gradient.fragment.glsl @@ -0,0 +1,62 @@ +layout (std140) uniform LineGradientUBO { + highp mat4 u_matrix; + highp vec2 u_units_to_pixels; + mediump float u_ratio; + lowp float u_device_pixel_ratio; +}; + +layout (std140) uniform LineGradientPropertiesUBO { + lowp float u_blur; + lowp float u_opacity; + mediump float u_gapwidth; + lowp float u_offset; + mediump float u_width; + + highp float pad1; + highp vec2 pad2; +}; + +layout (std140) uniform LineGradientInterpolationUBO { + lowp float u_blur_t; + lowp float u_opacity_t; + lowp float u_gapwidth_t; + lowp float u_offset_t; + lowp float u_width_t; + + highp float pad3; + highp vec2 pad4; +}; + +uniform sampler2D u_image; + +in vec2 v_width2; +in vec2 v_normal; +in float v_gamma_scale; +in highp float v_lineprogress; + +#pragma mapbox: define lowp float blur +#pragma mapbox: define lowp float opacity + +void main() { + #pragma mapbox: initialize lowp float blur + #pragma mapbox: initialize lowp float opacity + + // Calculate the distance of the pixel from the line in pixels. + float dist = length(v_normal) * v_width2.s; + + // Calculate the antialiasing fade factor. This is either when fading in + // the line in case of an offset line (v_width2.t) or when fading out + // (v_width2.s) + float blur2 = (blur + 1.0 / u_device_pixel_ratio) * v_gamma_scale; + float alpha = clamp(min(dist - (v_width2.t - blur2), v_width2.s - dist) / blur2, 0.0, 1.0); + + // For gradient lines, v_lineprogress is the ratio along the entire line, + // scaled to [0, 2^15), and the gradient ramp is stored in a texture. + vec4 color = texture(u_image, vec2(v_lineprogress, 0.5)); + + fragColor = color * (alpha * opacity); + +#ifdef OVERDRAW_INSPECTOR + fragColor = vec4(1.0); +#endif +} diff --git a/shaders/drawable.line_gradient.vertex.glsl b/shaders/drawable.line_gradient.vertex.glsl new file mode 100644 index 000000000..d56c52a0e --- /dev/null +++ b/shaders/drawable.line_gradient.vertex.glsl @@ -0,0 +1,111 @@ + +// the attribute conveying progress along a line is scaled to [0, 2^15) +#define MAX_LINE_DISTANCE 32767.0 + +// floor(127 / 2) == 63.0 +// the maximum allowed miter limit is 2.0 at the moment. the extrude normal is +// stored in a byte (-128..127). we scale regular normals up to length 63, but +// there are also "special" normals that have a bigger length (of up to 126 in +// this case). +// #define scale 63.0 +#define scale 0.015873016 + +layout (location = 0) in vec2 a_pos_normal; +layout (location = 1) in vec4 a_data; + +layout (std140) uniform LineGradientUBO { + highp mat4 u_matrix; + highp vec2 u_units_to_pixels; + mediump float u_ratio; + lowp float u_device_pixel_ratio; +}; + +layout (std140) uniform LineGradientPropertiesUBO { + lowp float u_blur; + lowp float u_opacity; + mediump float u_gapwidth; + lowp float u_offset; + mediump float u_width; + + highp float pad1; + highp vec2 pad2; +}; + +layout (std140) uniform LineGradientInterpolationUBO { + lowp float u_blur_t; + lowp float u_opacity_t; + lowp float u_gapwidth_t; + lowp float u_offset_t; + lowp float u_width_t; + + highp float pad3; + highp vec2 pad4; +}; + +out vec2 v_normal; +out vec2 v_width2; +out float v_gamma_scale; +out highp float v_lineprogress; + +#pragma mapbox: define lowp float blur +#pragma mapbox: define lowp float opacity +#pragma mapbox: define mediump float gapwidth +#pragma mapbox: define lowp float offset +#pragma mapbox: define mediump float width + +void main() { + #pragma mapbox: initialize lowp float blur + #pragma mapbox: initialize lowp float opacity + #pragma mapbox: initialize mediump float gapwidth + #pragma mapbox: initialize lowp float offset + #pragma mapbox: initialize mediump float width + + // the distance over which the line edge fades out. + // Retina devices need a smaller distance to avoid aliasing. + float ANTIALIASING = 1.0 / u_device_pixel_ratio / 2.0; + + vec2 a_extrude = a_data.xy - 128.0; + float a_direction = mod(a_data.z, 4.0) - 1.0; + + v_lineprogress = (floor(a_data.z / 4.0) + a_data.w * 64.0) * 2.0 / MAX_LINE_DISTANCE; + + vec2 pos = floor(a_pos_normal * 0.5); + + // x is 1 if it's a round cap, 0 otherwise + // y is 1 if the normal points up, and -1 if it points down + // We store these in the least significant bit of a_pos_normal + mediump vec2 normal = a_pos_normal - 2.0 * pos; + normal.y = normal.y * 2.0 - 1.0; + v_normal = normal; + + // these transformations used to be applied in the JS and native code bases. + // moved them into the shader for clarity and simplicity. + gapwidth = gapwidth / 2.0; + float halfwidth = width / 2.0; + offset = -1.0 * offset; + + float inset = gapwidth + (gapwidth > 0.0 ? ANTIALIASING : 0.0); + float outset = gapwidth + halfwidth * (gapwidth > 0.0 ? 2.0 : 1.0) + (halfwidth == 0.0 ? 0.0 : ANTIALIASING); + + // Scale the extrusion vector down to a normal and then up by the line width + // of this vertex. + mediump vec2 dist = outset * a_extrude * scale; + + // Calculate the offset when drawing a line that is to the side of the actual line. + // We do this by creating a vector that points towards the extrude, but rotate + // it when we're drawing round end points (a_direction = -1 or 1) since their + // extrude vector points in another direction. + mediump float u = 0.5 * a_direction; + mediump float t = 1.0 - abs(u); + mediump vec2 offset2 = offset * a_extrude * scale * normal.y * mat2(t, -u, u, t); + + vec4 projected_extrude = u_matrix * vec4(dist / u_ratio, 0.0, 0.0); + gl_Position = u_matrix * vec4(pos + offset2 / u_ratio, 0.0, 1.0) + projected_extrude; + + // calculate how much the perspective view squishes or stretches the extrude + float extrude_length_without_perspective = length(dist); + float extrude_length_with_perspective = length(projected_extrude.xy / gl_Position.w * u_units_to_pixels); + v_gamma_scale = extrude_length_without_perspective / extrude_length_with_perspective; + + v_width2 = vec2(outset, inset); +} diff --git a/shaders/drawable.line_pattern.fragment.glsl b/shaders/drawable.line_pattern.fragment.glsl new file mode 100644 index 000000000..a6548afb9 --- /dev/null +++ b/shaders/drawable.line_pattern.fragment.glsl @@ -0,0 +1,105 @@ +layout (std140) uniform LinePatternUBO { + highp mat4 u_matrix; + mediump vec4 u_scale; + highp vec2 u_texsize; + highp vec2 u_units_to_pixels; + mediump float u_ratio; + lowp float u_device_pixel_ratio; + highp float u_fade; + + highp float pad1; +}; + +layout (std140) uniform LinePatternPropertiesUBO { + lowp float u_blur; + lowp float u_opacity; + lowp float u_offset; + mediump float u_gapwidth; + mediump float u_width; + + highp float pad2; + highp vec2 pad3; +}; + +layout (std140) uniform LinePatternTilePropertiesUBO { + lowp vec4 u_pattern_from; + lowp vec4 u_pattern_to; +}; + +layout (std140) uniform LinePatternInterpolationUBO { + lowp float u_blur_t; + lowp float u_opacity_t; + lowp float u_offset_t; + lowp float u_gapwidth_t; + lowp float u_width_t; + lowp float u_pattern_from_t; + lowp float u_pattern_to_t; + + highp float pad4; +}; + +uniform sampler2D u_image; + +in vec2 v_normal; +in vec2 v_width2; +in float v_linesofar; +in float v_gamma_scale; + +#pragma mapbox: define lowp vec4 pattern_from +#pragma mapbox: define lowp vec4 pattern_to +#pragma mapbox: define lowp float blur +#pragma mapbox: define lowp float opacity + +void main() { + #pragma mapbox: initialize mediump vec4 pattern_from + #pragma mapbox: initialize mediump vec4 pattern_to + + #pragma mapbox: initialize lowp float blur + #pragma mapbox: initialize lowp float opacity + + vec2 pattern_tl_a = pattern_from.xy; + vec2 pattern_br_a = pattern_from.zw; + vec2 pattern_tl_b = pattern_to.xy; + vec2 pattern_br_b = pattern_to.zw; + + float pixelRatio = u_scale.x; + float tileZoomRatio = u_scale.y; + float fromScale = u_scale.z; + float toScale = u_scale.w; + + vec2 display_size_a = vec2((pattern_br_a.x - pattern_tl_a.x) / pixelRatio, (pattern_br_a.y - pattern_tl_a.y) / pixelRatio); + vec2 display_size_b = vec2((pattern_br_b.x - pattern_tl_b.x) / pixelRatio, (pattern_br_b.y - pattern_tl_b.y) / pixelRatio); + + vec2 pattern_size_a = vec2(display_size_a.x * fromScale / tileZoomRatio, display_size_a.y); + vec2 pattern_size_b = vec2(display_size_b.x * toScale / tileZoomRatio, display_size_b.y); + + // Calculate the distance of the pixel from the line in pixels. + float dist = length(v_normal) * v_width2.s; + + // Calculate the antialiasing fade factor. This is either when fading in + // the line in case of an offset line (v_width2.t) or when fading out + // (v_width2.s) + float blur2 = (blur + 1.0 / u_device_pixel_ratio) * v_gamma_scale; + float alpha = clamp(min(dist - (v_width2.t - blur2), v_width2.s - dist) / blur2, 0.0, 1.0); + + float x_a = mod(v_linesofar / pattern_size_a.x, 1.0); + float x_b = mod(v_linesofar / pattern_size_b.x, 1.0); + + // v_normal.y is 0 at the midpoint of the line, -1 at the lower edge, 1 at the upper edge + // we clamp the line width outset to be between 0 and half the pattern height plus padding (2.0) + // to ensure we don't sample outside the designated symbol on the sprite sheet. + // 0.5 is added to shift the component to be bounded between 0 and 1 for interpolation of + // the texture coordinate + float y_a = 0.5 + (v_normal.y * clamp(v_width2.s, 0.0, (pattern_size_a.y + 2.0) / 2.0) / pattern_size_a.y); + float y_b = 0.5 + (v_normal.y * clamp(v_width2.s, 0.0, (pattern_size_b.y + 2.0) / 2.0) / pattern_size_b.y); + vec2 pos_a = mix(pattern_tl_a / u_texsize, pattern_br_a / u_texsize, vec2(x_a, y_a)); + vec2 pos_b = mix(pattern_tl_b / u_texsize, pattern_br_b / u_texsize, vec2(x_b, y_b)); + + vec4 color = mix(texture(u_image, pos_a), texture(u_image, pos_b), u_fade); + + fragColor = color * alpha * opacity; + +#ifdef OVERDRAW_INSPECTOR + fragColor = vec4(1.0); +#endif +} diff --git a/shaders/drawable.line_pattern.vertex.glsl b/shaders/drawable.line_pattern.vertex.glsl new file mode 100644 index 000000000..21b2d3e00 --- /dev/null +++ b/shaders/drawable.line_pattern.vertex.glsl @@ -0,0 +1,126 @@ +// floor(127 / 2) == 63.0 +// the maximum allowed miter limit is 2.0 at the moment. the extrude normal is +// stored in a byte (-128..127). we scale regular normals up to length 63, but +// there are also "special" normals that have a bigger length (of up to 126 in +// this case). +// #define scale 63.0 +#define scale 0.015873016 + +// We scale the distance before adding it to the buffers so that we can store +// long distances for long segments. Use this value to unscale the distance. +#define LINE_DISTANCE_SCALE 2.0 + +layout (location = 0) in vec2 a_pos_normal; +layout (location = 1) in vec4 a_data; + +layout (std140) uniform LinePatternUBO { + highp mat4 u_matrix; + mediump vec4 u_scale; + highp vec2 u_texsize; + highp vec2 u_units_to_pixels; + mediump float u_ratio; + lowp float u_device_pixel_ratio; + highp float u_fade; + + highp float pad1; +}; + +layout (std140) uniform LinePatternPropertiesUBO { + lowp float u_blur; + lowp float u_opacity; + lowp float u_offset; + mediump float u_gapwidth; + mediump float u_width; + + highp float pad2; + highp vec2 pad3; +}; + +layout (std140) uniform LinePatternTilePropertiesUBO { + lowp vec4 u_pattern_from; + lowp vec4 u_pattern_to; +}; + +layout (std140) uniform LinePatternInterpolationUBO { + lowp float u_blur_t; + lowp float u_opacity_t; + lowp float u_offset_t; + lowp float u_gapwidth_t; + lowp float u_width_t; + lowp float u_pattern_from_t; + lowp float u_pattern_to_t; + + highp float pad4; +}; + +out vec2 v_normal; +out vec2 v_width2; +out float v_linesofar; +out float v_gamma_scale; + +#pragma mapbox: define lowp float blur +#pragma mapbox: define lowp float opacity +#pragma mapbox: define lowp float offset +#pragma mapbox: define mediump float gapwidth +#pragma mapbox: define mediump float width +#pragma mapbox: define lowp vec4 pattern_from +#pragma mapbox: define lowp vec4 pattern_to + +void main() { + #pragma mapbox: initialize lowp float blur + #pragma mapbox: initialize lowp float opacity + #pragma mapbox: initialize lowp float offset + #pragma mapbox: initialize mediump float gapwidth + #pragma mapbox: initialize mediump float width + #pragma mapbox: initialize mediump vec4 pattern_from + #pragma mapbox: initialize mediump vec4 pattern_to + + // the distance over which the line edge fades out. + // Retina devices need a smaller distance to avoid aliasing. + float ANTIALIASING = 1.0 / u_device_pixel_ratio / 2.0; + + vec2 a_extrude = a_data.xy - 128.0; + float a_direction = mod(a_data.z, 4.0) - 1.0; + float a_linesofar = (floor(a_data.z / 4.0) + a_data.w * 64.0) * LINE_DISTANCE_SCALE; + // float tileRatio = u_scale.y; + vec2 pos = floor(a_pos_normal * 0.5); + + // x is 1 if it's a round cap, 0 otherwise + // y is 1 if the normal points up, and -1 if it points down + // We store these in the least significant bit of a_pos_normal + mediump vec2 normal = a_pos_normal - 2.0 * pos; + normal.y = normal.y * 2.0 - 1.0; + v_normal = normal; + + // these transformations used to be applied in the JS and native code bases. + // moved them into the shader for clarity and simplicity. + gapwidth = gapwidth / 2.0; + float halfwidth = width / 2.0; + offset = -1.0 * offset; + + float inset = gapwidth + (gapwidth > 0.0 ? ANTIALIASING : 0.0); + float outset = gapwidth + halfwidth * (gapwidth > 0.0 ? 2.0 : 1.0) + (halfwidth == 0.0 ? 0.0 : ANTIALIASING); + + // Scale the extrusion vector down to a normal and then up by the line width + // of this vertex. + mediump vec2 dist = outset * a_extrude * scale; + + // Calculate the offset when drawing a line that is to the side of the actual line. + // We do this by creating a vector that points towards the extrude, but rotate + // it when we're drawing round end points (a_direction = -1 or 1) since their + // extrude vector points in another direction. + mediump float u = 0.5 * a_direction; + mediump float t = 1.0 - abs(u); + mediump vec2 offset2 = offset * a_extrude * scale * normal.y * mat2(t, -u, u, t); + + vec4 projected_extrude = u_matrix * vec4(dist / u_ratio, 0.0, 0.0); + gl_Position = u_matrix * vec4(pos + offset2 / u_ratio, 0.0, 1.0) + projected_extrude; + + // calculate how much the perspective view squishes or stretches the extrude + float extrude_length_without_perspective = length(dist); + float extrude_length_with_perspective = length(projected_extrude.xy / gl_Position.w * u_units_to_pixels); + v_gamma_scale = extrude_length_without_perspective / extrude_length_with_perspective; + + v_linesofar = a_linesofar; + v_width2 = vec2(outset, inset); +} diff --git a/shaders/drawable.line_sdf.fragment.glsl b/shaders/drawable.line_sdf.fragment.glsl new file mode 100644 index 000000000..027ce2728 --- /dev/null +++ b/shaders/drawable.line_sdf.fragment.glsl @@ -0,0 +1,79 @@ + +layout (std140) uniform LineSDFUBO { + highp mat4 u_matrix; + highp vec2 u_units_to_pixels; + highp vec2 u_patternscale_a; + highp vec2 u_patternscale_b; + mediump float u_ratio; + lowp float u_device_pixel_ratio; + highp float u_tex_y_a; + highp float u_tex_y_b; + highp float u_sdfgamma; + highp float u_mix; +}; + +layout (std140) uniform LineSDFPropertiesUBO { + highp vec4 u_color; + lowp float u_blur; + lowp float u_opacity; + mediump float u_gapwidth; + lowp float u_offset; + mediump float u_width; + lowp float u_floorwidth; + + highp vec2 pad1; +}; + +layout (std140) uniform LineSDFInterpolationUBO { + lowp float u_color_t; + lowp float u_blur_t; + lowp float u_opacity_t; + lowp float u_gapwidth_t; + lowp float u_offset_t; + lowp float u_width_t; + lowp float u_floorwidth_t; + + highp float pad2; +}; + +uniform sampler2D u_image; + +in vec2 v_normal; +in vec2 v_width2; +in vec2 v_tex_a; +in vec2 v_tex_b; +in float v_gamma_scale; + +#pragma mapbox: define highp vec4 color +#pragma mapbox: define lowp float blur +#pragma mapbox: define lowp float opacity +#pragma mapbox: define mediump float width +#pragma mapbox: define lowp float floorwidth + +void main() { + #pragma mapbox: initialize highp vec4 color + #pragma mapbox: initialize lowp float blur + #pragma mapbox: initialize lowp float opacity + #pragma mapbox: initialize mediump float width + #pragma mapbox: initialize lowp float floorwidth + + // Calculate the distance of the pixel from the line in pixels. + float dist = length(v_normal) * v_width2.s; + + // Calculate the antialiasing fade factor. This is either when fading in + // the line in case of an offset line (v_width2.t) or when fading out + // (v_width2.s) + float blur2 = (blur + 1.0 / u_device_pixel_ratio) * v_gamma_scale; + float alpha = clamp(min(dist - (v_width2.t - blur2), v_width2.s - dist) / blur2, 0.0, 1.0); + + float sdfdist_a = texture(u_image, v_tex_a).a; + float sdfdist_b = texture(u_image, v_tex_b).a; + float sdfdist = mix(sdfdist_a, sdfdist_b, u_mix); + alpha *= smoothstep(0.5 - u_sdfgamma / floorwidth, 0.5 + u_sdfgamma / floorwidth, sdfdist); + + fragColor = color * (alpha * opacity); + +#ifdef OVERDRAW_INSPECTOR + fragColor = vec4(1.0); +#endif +} diff --git a/shaders/drawable.line_sdf.vertex.glsl b/shaders/drawable.line_sdf.vertex.glsl new file mode 100644 index 000000000..6629e8b0f --- /dev/null +++ b/shaders/drawable.line_sdf.vertex.glsl @@ -0,0 +1,126 @@ +// floor(127 / 2) == 63.0 +// the maximum allowed miter limit is 2.0 at the moment. the extrude normal is +// stored in a byte (-128..127). we scale regular normals up to length 63, but +// there are also "special" normals that have a bigger length (of up to 126 in +// this case). +// #define scale 63.0 +#define scale 0.015873016 + +// We scale the distance before adding it to the buffers so that we can store +// long distances for long segments. Use this value to unscale the distance. +#define LINE_DISTANCE_SCALE 2.0 + +layout (location = 0) in vec2 a_pos_normal; +layout (location = 1) in vec4 a_data; + +layout (std140) uniform LineSDFUBO { + highp mat4 u_matrix; + highp vec2 u_units_to_pixels; + highp vec2 u_patternscale_a; + highp vec2 u_patternscale_b; + mediump float u_ratio; + lowp float u_device_pixel_ratio; + highp float u_tex_y_a; + highp float u_tex_y_b; + highp float u_sdfgamma; + highp float u_mix; +}; + +layout (std140) uniform LineSDFPropertiesUBO { + highp vec4 u_color; + lowp float u_blur; + lowp float u_opacity; + mediump float u_gapwidth; + lowp float u_offset; + mediump float u_width; + lowp float u_floorwidth; + + highp vec2 pad1; +}; + +layout (std140) uniform LineSDFInterpolationUBO { + lowp float u_color_t; + lowp float u_blur_t; + lowp float u_opacity_t; + lowp float u_gapwidth_t; + lowp float u_offset_t; + lowp float u_width_t; + lowp float u_floorwidth_t; + + highp float pad2; +}; + +out vec2 v_normal; +out vec2 v_width2; +out vec2 v_tex_a; +out vec2 v_tex_b; +out float v_gamma_scale; + +#pragma mapbox: define highp vec4 color +#pragma mapbox: define lowp float blur +#pragma mapbox: define lowp float opacity +#pragma mapbox: define mediump float gapwidth +#pragma mapbox: define lowp float offset +#pragma mapbox: define mediump float width +#pragma mapbox: define lowp float floorwidth + +void main() { + #pragma mapbox: initialize highp vec4 color + #pragma mapbox: initialize lowp float blur + #pragma mapbox: initialize lowp float opacity + #pragma mapbox: initialize mediump float gapwidth + #pragma mapbox: initialize lowp float offset + #pragma mapbox: initialize mediump float width + #pragma mapbox: initialize lowp float floorwidth + + // the distance over which the line edge fades out. + // Retina devices need a smaller distance to avoid aliasing. + float ANTIALIASING = 1.0 / u_device_pixel_ratio / 2.0; + + vec2 a_extrude = a_data.xy - 128.0; + float a_direction = mod(a_data.z, 4.0) - 1.0; + float a_linesofar = (floor(a_data.z / 4.0) + a_data.w * 64.0) * LINE_DISTANCE_SCALE; + + vec2 pos = floor(a_pos_normal * 0.5); + + // x is 1 if it's a round cap, 0 otherwise + // y is 1 if the normal points up, and -1 if it points down + // We store these in the least significant bit of a_pos_normal + mediump vec2 normal = a_pos_normal - 2.0 * pos; + normal.y = normal.y * 2.0 - 1.0; + v_normal = normal; + + // these transformations used to be applied in the JS and native code bases. + // moved them into the shader for clarity and simplicity. + gapwidth = gapwidth / 2.0; + float halfwidth = width / 2.0; + offset = -1.0 * offset; + + float inset = gapwidth + (gapwidth > 0.0 ? ANTIALIASING : 0.0); + float outset = gapwidth + halfwidth * (gapwidth > 0.0 ? 2.0 : 1.0) + (halfwidth == 0.0 ? 0.0 : ANTIALIASING); + + // Scale the extrusion vector down to a normal and then up by the line width + // of this vertex. + mediump vec2 dist =outset * a_extrude * scale; + + // Calculate the offset when drawing a line that is to the side of the actual line. + // We do this by creating a vector that points towards the extrude, but rotate + // it when we're drawing round end points (a_direction = -1 or 1) since their + // extrude vector points in another direction. + mediump float u = 0.5 * a_direction; + mediump float t = 1.0 - abs(u); + mediump vec2 offset2 = offset * a_extrude * scale * normal.y * mat2(t, -u, u, t); + + vec4 projected_extrude = u_matrix * vec4(dist / u_ratio, 0.0, 0.0); + gl_Position = u_matrix * vec4(pos + offset2 / u_ratio, 0.0, 1.0) + projected_extrude; + + // calculate how much the perspective view squishes or stretches the extrude + float extrude_length_without_perspective = length(dist); + float extrude_length_with_perspective = length(projected_extrude.xy / gl_Position.w * u_units_to_pixels); + v_gamma_scale = extrude_length_without_perspective / extrude_length_with_perspective; + + v_tex_a = vec2(a_linesofar * u_patternscale_a.x / floorwidth, normal.y * u_patternscale_a.y + u_tex_y_a); + v_tex_b = vec2(a_linesofar * u_patternscale_b.x / floorwidth, normal.y * u_patternscale_b.y + u_tex_y_b); + + v_width2 = vec2(outset, inset); +} diff --git a/shaders/manifest.json b/shaders/manifest.json index 0f7312381..74f6fc18d 100644 --- a/shaders/manifest.json +++ b/shaders/manifest.json @@ -34,6 +34,34 @@ "glsl_frag": "drawable.fill_outline.fragment.glsl", "uses_ubos": true }, + { + "name": "LineGradientShader", + "header": "drawable_line_gradient", + "glsl_vert": "drawable.line_gradient.vertex.glsl", + "glsl_frag": "drawable.line_gradient.fragment.glsl", + "uses_ubos": true + }, + { + "name": "LinePatternShader", + "header": "drawable_line_pattern", + "glsl_vert": "drawable.line_pattern.vertex.glsl", + "glsl_frag": "drawable.line_pattern.fragment.glsl", + "uses_ubos": true + }, + { + "name": "LineSDFShader", + "header": "drawable_line_sdf", + "glsl_vert": "drawable.line_sdf.vertex.glsl", + "glsl_frag": "drawable.line_sdf.fragment.glsl", + "uses_ubos": true + }, + { + "name": "LineShader", + "header": "drawable_line", + "glsl_vert": "drawable.line.vertex.glsl", + "glsl_frag": "drawable.line.fragment.glsl", + "uses_ubos": true + }, { "name": "FillPatternShader", "header": "drawable_fill_pattern", diff --git a/src/mbgl/geometry/line_atlas.cpp b/src/mbgl/geometry/line_atlas.cpp index e22e10208..e92e5e7ca 100644 --- a/src/mbgl/geometry/line_atlas.cpp +++ b/src/mbgl/geometry/line_atlas.cpp @@ -241,6 +241,13 @@ gfx::TextureBinding DashPatternTexture::textureBinding() const { #endif } +#if MLN_DRAWABLE_RENDERER +static const gfx::Texture2DPtr noTexture; +const std::shared_ptr& DashPatternTexture::getTexture() const { + return (std::holds_alternative(texture)) ? std::get(texture) : noTexture; +} +#endif + Size DashPatternTexture::getSize() const { #if MLN_DRAWABLE_RENDERER if (std::holds_alternative(texture)) { diff --git a/src/mbgl/geometry/line_atlas.hpp b/src/mbgl/geometry/line_atlas.hpp index 57fac0d25..7472a52b1 100644 --- a/src/mbgl/geometry/line_atlas.hpp +++ b/src/mbgl/geometry/line_atlas.hpp @@ -52,6 +52,9 @@ public: // Binds the atlas texture to the GPU, and uploads data if it is out of date. gfx::TextureBinding textureBinding() const; +#if MLN_DRAWABLE_RENDERER + const std::shared_ptr& getTexture() const; +#endif // Returns the size of the texture image. Size getSize() const; diff --git a/src/mbgl/gfx/line_drawable_data.hpp b/src/mbgl/gfx/line_drawable_data.hpp new file mode 100644 index 000000000..3210801b8 --- /dev/null +++ b/src/mbgl/gfx/line_drawable_data.hpp @@ -0,0 +1,23 @@ +#pragma once + +#include +#include + +#include + +namespace mbgl { + +namespace gfx { + +class LineDrawableData : public DrawableData { +public: + LineDrawableData(LinePatternCap linePatternCap_) + : linePatternCap(linePatternCap_) {} + + LinePatternCap linePatternCap; +}; + +using UniqueLineDrawableData = std::unique_ptr; + +} // namespace gfx +} // namespace mbgl diff --git a/src/mbgl/gfx/vertex_attribute.cpp b/src/mbgl/gfx/vertex_attribute.cpp index f20b2c1e4..367ae6979 100644 --- a/src/mbgl/gfx/vertex_attribute.cpp +++ b/src/mbgl/gfx/vertex_attribute.cpp @@ -12,6 +12,10 @@ std::unique_ptr VertexAttributeArray::nullref = nullptr; VertexAttributeArray::VertexAttributeArray(int initCapacity) : attrs(initCapacity) {} +VertexAttributeArray::VertexAttributeArray(const VertexAttributeArray& other) { + operator=(other); +} + VertexAttributeArray::VertexAttributeArray(VertexAttributeArray&& other) : attrs(std::move(other.attrs)) {} diff --git a/src/mbgl/gl/drawable_gl.cpp b/src/mbgl/gl/drawable_gl.cpp index fbbcd687d..01e4039e4 100644 --- a/src/mbgl/gl/drawable_gl.cpp +++ b/src/mbgl/gl/drawable_gl.cpp @@ -112,6 +112,9 @@ void DrawableGL::bindUniformBuffers() const { for (const auto& element : shaderGL.getUniformBlocks().getMap()) { const auto& uniformBuffer = getUniformBuffers().get(element.first); if (!uniformBuffer) { + using namespace std::string_literals; + Log::Error(Event::General, + "DrawableGL::bindUniformBuffers: UBO "s + element.first + " not found. skipping."); assert(false); continue; } diff --git a/src/mbgl/gl/renderer_backend.cpp b/src/mbgl/gl/renderer_backend.cpp index 54c89edb7..67ccb1bf6 100644 --- a/src/mbgl/gl/renderer_backend.cpp +++ b/src/mbgl/gl/renderer_backend.cpp @@ -98,6 +98,10 @@ void RendererBackend::initShaders(gfx::ShaderRegistry& shaders, const ProgramPar shaders::BuiltIn::CircleShader, shaders::BuiltIn::FillShader, shaders::BuiltIn::FillOutlineShader, + shaders::BuiltIn::LineShader, + shaders::BuiltIn::LineSDFShader, + shaders::BuiltIn::LinePatternShader, + shaders::BuiltIn::LineGradientShader, shaders::BuiltIn::FillOutlinePatternShader, shaders::BuiltIn::FillPatternShader, shaders::BuiltIn::RasterShader, diff --git a/src/mbgl/renderer/layers/line_layer_tweaker.cpp b/src/mbgl/renderer/layers/line_layer_tweaker.cpp new file mode 100644 index 000000000..8ec1f8e61 --- /dev/null +++ b/src/mbgl/renderer/layers/line_layer_tweaker.cpp @@ -0,0 +1,286 @@ +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +namespace mbgl { + +using namespace style; + +struct alignas(16) LineUBO { + std::array matrix; + std::array units_to_pixels; + float ratio; + float device_pixel_ratio; +}; +static_assert(sizeof(LineUBO) % 16 == 0); +static constexpr std::string_view LineUBOName = "LineUBO"; + +struct alignas(16) LinePropertiesUBO { + Color color; + float blur; + float opacity; + float gapwidth; + float offset; + float width; + + float pad1; + std::array pad2; +}; +static_assert(sizeof(LinePropertiesUBO) % 16 == 0); +static constexpr std::string_view LinePropertiesUBOName = "LinePropertiesUBO"; + +struct alignas(16) LineGradientUBO { + std::array matrix; + std::array units_to_pixels; + float ratio; + float device_pixel_ratio; +}; +static_assert(sizeof(LineGradientUBO) % 16 == 0); +static constexpr std::string_view LineGradientUBOName = "LineGradientUBO"; + +struct alignas(16) LineGradientPropertiesUBO { + float blur; + float opacity; + float gapwidth; + float offset; + float width; + + float pad1; + std::array pad2; +}; +static_assert(sizeof(LineGradientPropertiesUBO) % 16 == 0); +static constexpr std::string_view LineGradientPropertiesUBOName = "LineGradientPropertiesUBO"; + +struct alignas(16) LinePatternUBO { + std::array matrix; + std::array scale; + std::array texsize; + std::array units_to_pixels; + float ratio; + float device_pixel_ratio; + float fade; + + float pad1; +}; +static_assert(sizeof(LinePatternUBO) % 16 == 0); +static constexpr std::string_view LinePatternUBOName = "LinePatternUBO"; + +struct alignas(16) LinePatternPropertiesUBO { + float blur; + float opacity; + float offset; + float gapwidth; + float width; + + float pad1; + std::array pad2; +}; +static_assert(sizeof(LinePatternPropertiesUBO) % 16 == 0); +static constexpr std::string_view LinePatternPropertiesUBOName = "LinePatternPropertiesUBO"; + +struct alignas(16) LineSDFUBO { + std::array matrix; + std::array units_to_pixels; + std::array patternscale_a; + std::array patternscale_b; + float ratio; + float device_pixel_ratio; + float tex_y_a; + float tex_y_b; + float sdfgamma; + float mix; +}; +static_assert(sizeof(LineSDFUBO) % 16 == 0); +static constexpr std::string_view LineSDFUBOName = "LineSDFUBO"; + +struct alignas(16) LineSDFPropertiesUBO { + Color color; + float blur; + float opacity; + float gapwidth; + float offset; + float width; + float floorwidth; + + std::array pad1; +}; +static_assert(sizeof(LineSDFPropertiesUBO) % 16 == 0); +static constexpr std::string_view LineSDFPropertiesUBOName = "LineSDFPropertiesUBO"; + +void LineLayerTweaker::execute(LayerGroupBase& layerGroup, + const RenderTree& renderTree, + const PaintParameters& parameters) { + const auto& evaluated = static_cast(*evaluatedProperties).evaluated; + const auto& crossfade = static_cast(*evaluatedProperties).crossfade; + + LinePropertiesUBO linePropertiesUBO{ + /*color =*/evaluated.get().constantOr(LineColor::defaultValue()), + /*blur =*/evaluated.get().constantOr(LineBlur::defaultValue()), + /*opacity =*/evaluated.get().constantOr(LineOpacity::defaultValue()), + /*gapwidth =*/evaluated.get().constantOr(LineGapWidth::defaultValue()), + /*offset =*/evaluated.get().constantOr(LineOffset::defaultValue()), + /*width =*/evaluated.get().constantOr(LineWidth::defaultValue()), + 0, + {0, 0}}; + LineGradientPropertiesUBO lineGradientPropertiesUBO{ + /*blur =*/evaluated.get().constantOr(LineBlur::defaultValue()), + /*opacity =*/evaluated.get().constantOr(LineOpacity::defaultValue()), + /*gapwidth =*/evaluated.get().constantOr(LineGapWidth::defaultValue()), + /*offset =*/evaluated.get().constantOr(LineOffset::defaultValue()), + /*width =*/evaluated.get().constantOr(LineWidth::defaultValue()), + 0, + {0, 0}}; + LineSDFPropertiesUBO lineSDFPropertiesUBO{ + /*color =*/evaluated.get().constantOr(LineColor::defaultValue()), + /*blur =*/evaluated.get().constantOr(LineBlur::defaultValue()), + /*opacity =*/evaluated.get().constantOr(LineOpacity::defaultValue()), + /*gapwidth =*/evaluated.get().constantOr(LineGapWidth::defaultValue()), + /*offset =*/evaluated.get().constantOr(LineOffset::defaultValue()), + /*width =*/evaluated.get().constantOr(LineWidth::defaultValue()), + /*floorwidth =*/evaluated.get().constantOr(LineFloorWidth::defaultValue()), + {0, 0}}; + + layerGroup.observeDrawables([&](gfx::Drawable& drawable) { + if (!drawable.getTileID()) return; + + const UnwrappedTileID tileID = drawable.getTileID()->toUnwrapped(); + const auto& translation = evaluated.get(); + const auto anchor = evaluated.get(); + constexpr bool inViewportPixelUnits = false; // from RenderTile::translatedMatrix + const auto matrix = getTileMatrix( + tileID, renderTree, parameters.state, translation, anchor, inViewportPixelUnits); + + // simple line + if (drawable.getShader()->getUniformBlocks().get(std::string(LineUBOName))) { + // main UBO + LineUBO lineUBO{ + /*matrix = */ util::cast(matrix), + /*units_to_pixels = */ {1.0f / parameters.pixelsToGLUnits[0], 1.0f / parameters.pixelsToGLUnits[1]}, + /*ratio = */ 1.0f / tileID.pixelsToTileUnits(1.0f, static_cast(parameters.state.getZoom())), + /*device_pixel_ratio = */ parameters.pixelRatio}; + drawable.mutableUniformBuffers().createOrUpdate(LineUBOName, &lineUBO, sizeof(lineUBO), parameters.context); + + // properties UBO + drawable.mutableUniformBuffers().createOrUpdate( + LinePropertiesUBOName, &linePropertiesUBO, sizeof(linePropertiesUBO), parameters.context); + } + // gradient line + else if (drawable.getShader()->getUniformBlocks().get(std::string(LineGradientUBOName))) { + // main UBO + LineGradientUBO lineGradientUBO{ + /*matrix = */ util::cast(matrix), + /*units_to_pixels = */ {1.0f / parameters.pixelsToGLUnits[0], 1.0f / parameters.pixelsToGLUnits[1]}, + /*ratio = */ 1.0f / tileID.pixelsToTileUnits(1.0f, static_cast(parameters.state.getZoom())), + /*device_pixel_ratio = */ parameters.pixelRatio}; + drawable.mutableUniformBuffers().createOrUpdate( + LineGradientUBOName, &lineGradientUBO, sizeof(lineGradientUBO), parameters.context); + + // properties UBO + drawable.mutableUniformBuffers().createOrUpdate(LineGradientPropertiesUBOName, + &lineGradientPropertiesUBO, + sizeof(lineGradientPropertiesUBO), + parameters.context); + } + // pattern line + else if (drawable.getShader()->getUniformBlocks().get(std::string(LinePatternUBOName))) { + // main UBO + Size textureSize{0, 0}; + if (const auto shader = drawable.getShader()) { + if (const auto index = shader->getSamplerLocation("u_image")) { + if (const auto& texture = drawable.getTexture(index.value())) { + textureSize = texture->getSize(); + } + } + } + LinePatternUBO linePatternUBO{ + /*matrix =*/util::cast(matrix), + /*scale =*/ + {parameters.pixelRatio, + 1 / tileID.pixelsToTileUnits(1, parameters.state.getIntegerZoom()), + crossfade.fromScale, + crossfade.toScale}, + /*texsize =*/{static_cast(textureSize.width), static_cast(textureSize.height)}, + /*units_to_pixels =*/{1.0f / parameters.pixelsToGLUnits[0], 1.0f / parameters.pixelsToGLUnits[1]}, + /*ratio =*/1.0f / tileID.pixelsToTileUnits(1.0f, static_cast(parameters.state.getZoom())), + /*device_pixel_ratio =*/parameters.pixelRatio, + /*fade =*/crossfade.t, + 0}; + drawable.mutableUniformBuffers().createOrUpdate( + LinePatternUBOName, &linePatternUBO, sizeof(linePatternUBO), parameters.context); + + // properties UBO + LinePatternPropertiesUBO linePatternPropertiesUBO{ + /*blur =*/evaluated.get().constantOr(LineBlur::defaultValue()), + /*opacity =*/evaluated.get().constantOr(LineOpacity::defaultValue()), + /*offset =*/evaluated.get().constantOr(LineOffset::defaultValue()), + /*gapwidth =*/evaluated.get().constantOr(LineGapWidth::defaultValue()), + /*width =*/evaluated.get().constantOr(LineWidth::defaultValue()), + 0, + {0, 0}}; + drawable.mutableUniformBuffers().createOrUpdate(LinePatternPropertiesUBOName, + &linePatternPropertiesUBO, + sizeof(linePatternPropertiesUBO), + parameters.context); + } + // SDF line + else if (drawable.getShader()->getUniformBlocks().get(std::string(LineSDFUBOName))) { + if (const auto& data = drawable.getData()) { + const gfx::LineDrawableData& lineData = static_cast(*data); + const auto& dashPatternTexture = parameters.lineAtlas.getDashPatternTexture( + evaluated.get().from, evaluated.get().to, lineData.linePatternCap); + + // texture + if (const auto shader = drawable.getShader()) { + if (const auto index = shader->getSamplerLocation("u_image")) { + if (!drawable.getTexture(index.value())) { + const auto& texture = dashPatternTexture.getTexture(); + drawable.setEnabled(!!texture); + if (texture) { + drawable.setTexture(texture, index.value()); + } + } + } + } + + // main UBO + const LinePatternPos& posA = dashPatternTexture.getFrom(); + const LinePatternPos& posB = dashPatternTexture.getTo(); + const float widthA = posA.width * crossfade.fromScale; + const float widthB = posB.width * crossfade.toScale; + LineSDFUBO lineSDFUBO{ + /* matrix = */ util::cast(matrix), + /* units_to_pixels = */ + {1.0f / parameters.pixelsToGLUnits[0], 1.0f / parameters.pixelsToGLUnits[1]}, + /* patternscale_a = */ + {1.0f / tileID.pixelsToTileUnits(widthA, parameters.state.getIntegerZoom()), -posA.height / 2.0f}, + /* patternscale_b = */ + {1.0f / tileID.pixelsToTileUnits(widthB, parameters.state.getIntegerZoom()), -posB.height / 2.0f}, + /* ratio = */ 1.0f / tileID.pixelsToTileUnits(1.0f, static_cast(parameters.state.getZoom())), + /* device_pixel_ratio = */ parameters.pixelRatio, + /* tex_y_a = */ posA.y, + /* tex_y_b = */ posB.y, + /* sdfgamma = */ static_cast(dashPatternTexture.getSize().width) / + (std::min(widthA, widthB) * 256.0f * parameters.pixelRatio) / 2.0f, + /* mix = */ crossfade.t}; + drawable.mutableUniformBuffers().createOrUpdate( + LineSDFUBOName, &lineSDFUBO, sizeof(lineSDFUBO), parameters.context); + + // properties UBO + drawable.mutableUniformBuffers().createOrUpdate( + LineSDFPropertiesUBOName, &lineSDFPropertiesUBO, sizeof(lineSDFPropertiesUBO), parameters.context); + } + } + }); +} + +} // namespace mbgl diff --git a/src/mbgl/renderer/layers/line_layer_tweaker.hpp b/src/mbgl/renderer/layers/line_layer_tweaker.hpp new file mode 100644 index 000000000..de45922f7 --- /dev/null +++ b/src/mbgl/renderer/layers/line_layer_tweaker.hpp @@ -0,0 +1,28 @@ +#pragma once + +#include + +#include + +namespace mbgl { + +namespace gfx { +class UniformBuffer; +using UniformBufferPtr = std::shared_ptr; +} // namespace gfx + +/** + Line layer specific tweaker + */ +class LineLayerTweaker : public LayerTweaker { +public: + LineLayerTweaker(Immutable properties) + : LayerTweaker(properties){}; + +public: + ~LineLayerTweaker() override = default; + + void execute(LayerGroupBase&, const RenderTree&, const PaintParameters&) override; +}; + +} // namespace mbgl diff --git a/src/mbgl/renderer/layers/render_line_layer.cpp b/src/mbgl/renderer/layers/render_line_layer.cpp index 5efc5d546..f31a68787 100644 --- a/src/mbgl/renderer/layers/render_line_layer.cpp +++ b/src/mbgl/renderer/layers/render_line_layer.cpp @@ -9,6 +9,7 @@ #include #include #include +#include #include #include #include @@ -16,6 +17,15 @@ #include #include #include +#include + +#if MLN_DRAWABLE_RENDERER +#include +#include +#include +#include +#include +#endif namespace mbgl { @@ -33,7 +43,7 @@ inline const LineLayer::Impl& impl_cast(const Immutable& imp RenderLineLayer::RenderLineLayer(Immutable _impl) : RenderLayer(makeMutable(std::move(_impl))), unevaluated(impl_cast(baseImpl).paint.untransitioned()), - colorRamp({256, 1}) {} + colorRamp(std::make_shared(Size(256, 1))) {} RenderLineLayer::~RenderLineLayer() = default; @@ -55,6 +65,12 @@ void RenderLineLayer::evaluate(const PropertyEvaluationParameters& parameters) { : RenderPass::None; properties->renderPasses = mbgl::underlying_type(passes); evaluatedProperties = std::move(properties); + +#if MLN_DRAWABLE_RENDERER + if (layerGroup && layerGroup->getLayerTweaker()) { + layerGroup->setLayerTweaker(std::make_shared(evaluatedProperties)); + } +#endif } bool RenderLineLayer::hasTransition() const { @@ -85,7 +101,7 @@ void RenderLineLayer::prepare(const LayerPrepareParameters& params) { void RenderLineLayer::upload(gfx::UploadPass& uploadPass) { if (!unevaluated.get().getValue().isUndefined() && !colorRampTexture) { - colorRampTexture = uploadPass.createTexture(colorRamp); + colorRampTexture = uploadPass.createTexture(*colorRamp); } } @@ -284,19 +300,31 @@ void RenderLineLayer::updateColorRamp() { return; } - const auto length = colorRamp.bytes(); + const auto length = colorRamp->bytes(); for (uint32_t i = 0; i < length; i += 4) { const auto color = colorValue.evaluate(static_cast(i) / length); - colorRamp.data[i] = static_cast(std::floor(color.r * 255.f)); - colorRamp.data[i + 1] = static_cast(std::floor(color.g * 255.f)); - colorRamp.data[i + 2] = static_cast(std::floor(color.b * 255.f)); - colorRamp.data[i + 3] = static_cast(std::floor(color.a * 255.f)); + colorRamp->data[i] = static_cast(std::floor(color.r * 255.f)); + colorRamp->data[i + 1] = static_cast(std::floor(color.g * 255.f)); + colorRamp->data[i + 2] = static_cast(std::floor(color.b * 255.f)); + colorRamp->data[i + 3] = static_cast(std::floor(color.a * 255.f)); } if (colorRampTexture) { colorRampTexture = std::nullopt; } + +#if MLN_DRAWABLE_RENDERER + if (colorRampTexture2D) { + colorRampTexture2D.reset(); + + // delete all gradient drawables + if (layerGroup) { + stats.drawablesRemoved += layerGroup->getDrawableCount(); + layerGroup->clearDrawables(); + } + } +#endif } float RenderLineLayer::getLineWidth(const GeometryTileFeature& feature, @@ -314,4 +342,399 @@ float RenderLineLayer::getLineWidth(const GeometryTileFeature& feature, } } +#if MLN_DRAWABLE_RENDERER +/// Property interpolation UBOs +struct alignas(16) LineInterpolationUBO { + float color_t; + float blur_t; + float opacity_t; + float gapwidth_t; + float offset_t; + float width_t; + + float pad1; + float pad2; +}; +static_assert(sizeof(LineInterpolationUBO) % 16 == 0); +static constexpr std::string_view LineInterpolationUBOName = "LineInterpolationUBO"; + +struct alignas(16) LineGradientInterpolationUBO { + float blur_t; + float opacity_t; + float gapwidth_t; + float offset_t; + float width_t; + + float pad1; + std::array pad2; +}; +static_assert(sizeof(LineGradientInterpolationUBO) % 16 == 0); +static constexpr std::string_view LineGradientInterpolationUBOName = "LineGradientInterpolationUBO"; + +struct alignas(16) LinePatternInterpolationUBO { + float blur_t; + float opacity_t; + float offset_t; + float gapwidth_t; + float width_t; + float pattern_from_t; + float pattern_to_t; + + float pad1; +}; +static_assert(sizeof(LinePatternInterpolationUBO) % 16 == 0); +static constexpr std::string_view LinePatternInterpolationUBOName = "LinePatternInterpolationUBO"; + +struct alignas(16) LineSDFInterpolationUBO { + float color_t; + float blur_t; + float opacity_t; + float gapwidth_t; + float offset_t; + float width_t; + float floorwidth_t; + + float pad1; +}; +static_assert(sizeof(LineSDFInterpolationUBO) % 16 == 0); +static constexpr std::string_view LineSDFInterpolationUBOName = "LineSDFInterpolationUBO"; + +/// Evaluated properties that depend on the tile +struct alignas(16) LinePatternTilePropertiesUBO { + std::array pattern_from; + std::array pattern_to; +}; +static_assert(sizeof(LinePatternTilePropertiesUBO) % 16 == 0); +static constexpr std::string_view LinePatternTilePropertiesUBOName = "LinePatternTilePropertiesUBO"; + +void RenderLineLayer::update(gfx::ShaderRegistry& shaders, + gfx::Context& context, + const TransformState& state, + [[maybe_unused]] const RenderTree& renderTree, + [[maybe_unused]] UniqueChangeRequestVec& changes) { + std::unique_lock guard(mutex); + + if (!renderTiles || renderTiles->empty()) { + removeAllDrawables(); + return; + } + + // Set up a layer group + if (!layerGroup) { + if (auto layerGroup_ = context.createTileLayerGroup(layerIndex, /*initialCapacity=*/64, getID())) { + layerGroup_->setLayerTweaker(std::make_shared(evaluatedProperties)); + setLayerGroup(std::move(layerGroup_), changes); + } + } + auto* tileLayerGroup = static_cast(layerGroup.get()); + + if (!lineShaderGroup) { + lineShaderGroup = shaders.getShaderGroup("LineShader"); + } + if (!lineGradientShaderGroup) { + lineGradientShaderGroup = shaders.getShaderGroup("LineGradientShader"); + } + if (!linePatternShaderGroup) { + linePatternShaderGroup = shaders.getShaderGroup("LinePatternShader"); + } + if (!lineSDFShaderGroup) { + lineSDFShaderGroup = shaders.getShaderGroup("LineSDFShader"); + } + + std::unordered_set newTileIDs(renderTiles->size()); + std::transform(renderTiles->begin(), + renderTiles->end(), + std::inserter(newTileIDs, newTileIDs.begin()), + [](const auto& renderTile) -> OverscaledTileID { return renderTile.get().getOverscaledTileID(); }); + + const auto renderPass = static_cast(evaluatedProperties->renderPasses); + + tileLayerGroup->observeDrawables([&](gfx::UniqueDrawable& drawable) { + // If the render pass has changed or the tile has dropped out of the cover set, remove it. + const auto tileID = drawable->getTileID(); + if (drawable->getRenderPass() != renderPass || (tileID && newTileIDs.find(*tileID) == newTileIDs.end())) { + drawable.reset(); + ++stats.drawablesRemoved; + } + }); + + auto createLineBuilder = [&](const std::string& name, + gfx::ShaderPtr shader) -> std::unique_ptr { + std::unique_ptr builder = context.createDrawableBuilder(name); + builder->setShader(std::static_pointer_cast(shader)); + builder->setRenderPass(renderPass); + builder->setDepthType((renderPass == RenderPass::Opaque) ? gfx::DepthMaskType::ReadWrite + : gfx::DepthMaskType::ReadOnly); + builder->setCullFaceMode(gfx::CullFaceMode::disabled()); + builder->setNeedsStencil(true); + builder->setVertexAttrName("a_pos_normal"); + + return builder; + }; + + auto addVertices = [&](std::unique_ptr& builder, const LineBucket& bucket) { + std::vector> vertices; + vertices.resize(bucket.vertices.vector().size()); + std::transform( + bucket.vertices.vector().begin(), bucket.vertices.vector().end(), vertices.begin(), [](const auto& x) { + return x.a1; + }); + builder->addVertices(vertices, 0, vertices.size()); + }; + + auto addAttributes = [&](std::unique_ptr& builder, + const LineBucket& bucket, + gfx::VertexAttributeArray& vertexAttrs) { + if (auto& attr = vertexAttrs.getOrAdd("a_data")) { + size_t index{0}; + for (const auto& vert : bucket.vertices.vector()) { + attr->set(index++, gfx::VertexAttribute::int4{vert.a2[0], vert.a2[1], vert.a2[2], vert.a2[3]}); + } + } + builder->setVertexAttributes(std::move(vertexAttrs)); + }; + + auto setSegments = [&](std::unique_ptr& builder, const LineBucket& bucket) { + builder->setSegments( + gfx::Triangles(), bucket.triangles.vector(), bucket.segments.data(), bucket.segments.size()); + }; + + for (const RenderTile& tile : *renderTiles) { + const auto& tileID = tile.getOverscaledTileID(); + + const LayerRenderData* renderData = getRenderDataForPass(tile, renderPass); + if (!renderData) { + removeTile(renderPass, tileID); + continue; + } + + auto& bucket = static_cast(*renderData->bucket); + const auto& paintPropertyBinders = bucket.paintPropertyBinders.at(getID()); + const auto& evaluated = getEvaluated(renderData->layerProperties); + const auto& crossfade = getCrossfade(renderData->layerProperties); + + // interpolation UBOs + float zoom = static_cast(state.getZoom()); + LineInterpolationUBO lineInterpolationUBO{ + /*color_t =*/std::get<0>(paintPropertyBinders.get()->interpolationFactor(zoom)), + /*blur_t =*/std::get<0>(paintPropertyBinders.get()->interpolationFactor(zoom)), + /*opacity_t =*/std::get<0>(paintPropertyBinders.get()->interpolationFactor(zoom)), + /*gapwidth_t =*/std::get<0>(paintPropertyBinders.get()->interpolationFactor(zoom)), + /*offset_t =*/std::get<0>(paintPropertyBinders.get()->interpolationFactor(zoom)), + /*width_t =*/std::get<0>(paintPropertyBinders.get()->interpolationFactor(zoom)), + 0, + 0}; + LineGradientInterpolationUBO lineGradientInterpolationUBO{ + /*blur_t =*/std::get<0>(paintPropertyBinders.get()->interpolationFactor(zoom)), + /*opacity_t =*/std::get<0>(paintPropertyBinders.get()->interpolationFactor(zoom)), + /*gapwidth_t =*/std::get<0>(paintPropertyBinders.get()->interpolationFactor(zoom)), + /*offset_t =*/std::get<0>(paintPropertyBinders.get()->interpolationFactor(zoom)), + /*width_t =*/std::get<0>(paintPropertyBinders.get()->interpolationFactor(zoom)), + 0, + {0, 0}}; + LinePatternInterpolationUBO linePatternInterpolationUBO{ + /*blur_t =*/std::get<0>(paintPropertyBinders.get()->interpolationFactor(zoom)), + /*opacity_t =*/std::get<0>(paintPropertyBinders.get()->interpolationFactor(zoom)), + /*offset_t =*/std::get<0>(paintPropertyBinders.get()->interpolationFactor(zoom)), + /*gapwidth_t =*/std::get<0>(paintPropertyBinders.get()->interpolationFactor(zoom)), + /*width_t =*/std::get<0>(paintPropertyBinders.get()->interpolationFactor(zoom)), + /*pattern_from_t =*/std::get<0>(paintPropertyBinders.get()->interpolationFactor(zoom)), + /*pattern_to_t =*/std::get<1>(paintPropertyBinders.get()->interpolationFactor(zoom)), + 0}; + LineSDFInterpolationUBO lineSDFInterpolationUBO{ + /*color_t =*/std::get<0>(paintPropertyBinders.get()->interpolationFactor(zoom)), + /*blur_t =*/std::get<0>(paintPropertyBinders.get()->interpolationFactor(zoom)), + /*opacity_t =*/std::get<0>(paintPropertyBinders.get()->interpolationFactor(zoom)), + /*gapwidth_t =*/std::get<0>(paintPropertyBinders.get()->interpolationFactor(zoom)), + /*offset_t =*/std::get<0>(paintPropertyBinders.get()->interpolationFactor(zoom)), + /*width_t =*/std::get<0>(paintPropertyBinders.get()->interpolationFactor(zoom)), + /*floorwidth_t =*/std::get<0>(paintPropertyBinders.get()->interpolationFactor(zoom)), + 0}; + + // tile dependent properties UBOs: + const auto& linePatternValue = evaluated.get().constantOr(Faded{"", ""}); + std::optional patternPosA = tile.getPattern(linePatternValue.from.id()); + std::optional patternPosB = tile.getPattern(linePatternValue.to.id()); + LinePatternTilePropertiesUBO linePatternTilePropertiesUBO{ + /*pattern_from =*/patternPosA ? util::cast(patternPosA->tlbr()) : std::array{0}, + /*pattern_to =*/patternPosB ? util::cast(patternPosB->tlbr()) : std::array{0}}; + + // update existing drawables + tileLayerGroup->observeDrawables(renderPass, tileID, [&](gfx::Drawable& drawable) { + // simple line interpolation UBO + if (drawable.getShader()->getUniformBlocks().get(std::string(LineInterpolationUBOName))) { + drawable.mutableUniformBuffers().createOrUpdate( + LineInterpolationUBOName, &lineInterpolationUBO, context); + } + // gradient line interpolation UBO + else if (drawable.getShader()->getUniformBlocks().get(std::string(LineGradientInterpolationUBOName))) { + drawable.mutableUniformBuffers().createOrUpdate( + LineGradientInterpolationUBOName, &lineGradientInterpolationUBO, context); + } + // pattern line interpolation UBO + else if (drawable.getShader()->getUniformBlocks().get(std::string(LinePatternInterpolationUBOName))) { + // interpolation + drawable.mutableUniformBuffers().createOrUpdate( + LinePatternInterpolationUBOName, &linePatternInterpolationUBO, context); + // tile properties + drawable.mutableUniformBuffers().createOrUpdate( + LinePatternTilePropertiesUBOName, &linePatternTilePropertiesUBO, context); + } + // SDF line interpolation UBO + else if (drawable.getShader()->getUniformBlocks().get(std::string(LineSDFInterpolationUBOName))) { + drawable.mutableUniformBuffers().createOrUpdate( + LineSDFInterpolationUBOName, &lineSDFInterpolationUBO, context); + } + }); + + if (tileLayerGroup->getDrawableCount(renderPass, tileID) > 0) continue; + + if (!evaluated.get().from.empty()) { + // dash array line (SDF) + gfx::VertexAttributeArray vertexAttrs; + auto propertiesAsUniforms = vertexAttrs.readDataDrivenPaintProperties(paintPropertyBinders, + evaluated); + auto builder = createLineBuilder("lineSDF", + lineSDFShaderGroup->getOrCreateShader(context, propertiesAsUniforms)); + + // vertices, attributes and segments + addVertices(builder, bucket); + addAttributes(builder, bucket, vertexAttrs); + setSegments(builder, bucket); + + // finish + builder->flush(); + const LinePatternCap cap = bucket.layout.get() == LineCapType::Round ? LinePatternCap::Round + : LinePatternCap::Square; + for (auto& drawable : builder->clearDrawables()) { + drawable->setTileID(tileID); + drawable->setData(std::make_unique(cap)); + drawable->mutableUniformBuffers().createOrUpdate( + LineSDFInterpolationUBOName, &lineSDFInterpolationUBO, context); + + tileLayerGroup->addDrawable(renderPass, tileID, std::move(drawable)); + ++stats.drawablesAdded; + } + } else if (!unevaluated.get().isUndefined()) { + // pattern line + gfx::VertexAttributeArray vertexAttrs; + paintPropertyBinders.setPatternParameters(patternPosA, patternPosB, crossfade); + auto propertiesAsUniforms = vertexAttrs.readDataDrivenPaintProperties(paintPropertyBinders, + evaluated); + auto builder = createLineBuilder("linePattern", + linePatternShaderGroup->getOrCreateShader(context, propertiesAsUniforms)); + + // vertices and attributes + addVertices(builder, bucket); + addAttributes(builder, bucket, vertexAttrs); + + // texture + if (const auto& atlases = tile.getAtlasTextures(); atlases && atlases->icon) { + if (const auto samplerLocation = builder->getShader()->getSamplerLocation("u_image")) { + builder->setTexture(atlases->icon, samplerLocation.value()); + + // segments + setSegments(builder, bucket); + + // finish + builder->flush(); + for (auto& drawable : builder->clearDrawables()) { + drawable->setTileID(tileID); + drawable->mutableUniformBuffers().createOrUpdate( + LinePatternInterpolationUBOName, &linePatternInterpolationUBO, context); + drawable->mutableUniformBuffers().createOrUpdate( + LinePatternTilePropertiesUBOName, &linePatternTilePropertiesUBO, context); + + tileLayerGroup->addDrawable(renderPass, tileID, std::move(drawable)); + ++stats.drawablesAdded; + } + } + } + + } else if (!unevaluated.get().getValue().isUndefined()) { + // gradient line + gfx::VertexAttributeArray vertexAttrs; + auto propertiesAsUniforms = + vertexAttrs.readDataDrivenPaintProperties( + paintPropertyBinders, evaluated); + + auto builder = createLineBuilder("lineGradient", + lineGradientShaderGroup->getOrCreateShader(context, propertiesAsUniforms)); + + // vertices and attributes + addVertices(builder, bucket); + addAttributes(builder, bucket, vertexAttrs); + + // texture + if (const auto samplerLocation = builder->getShader()->getSamplerLocation("u_image")) { + if (!colorRampTexture2D && colorRamp->valid()) { + // create texture. to be reused for all the tiles of the layer + colorRampTexture2D = context.createTexture2D(); + colorRampTexture2D->setImage(colorRamp); + colorRampTexture2D->setSamplerConfiguration( + {gfx::TextureFilterType::Linear, gfx::TextureWrapType::Clamp, gfx::TextureWrapType::Clamp}); + } + + if (colorRampTexture2D) { + builder->setTexture(colorRampTexture2D, samplerLocation.value()); + + // segments + setSegments(builder, bucket); + + // finish + builder->flush(); + for (auto& drawable : builder->clearDrawables()) { + drawable->setTileID(tileID); + drawable->mutableUniformBuffers().createOrUpdate( + LineGradientInterpolationUBOName, &lineGradientInterpolationUBO, context); + + tileLayerGroup->addDrawable(renderPass, tileID, std::move(drawable)); + ++stats.drawablesAdded; + } + } + } + + } else { + // simple line + gfx::VertexAttributeArray vertexAttrs; + auto propertiesAsUniforms = vertexAttrs.readDataDrivenPaintProperties(paintPropertyBinders, + evaluated); + auto builder = createLineBuilder("line", lineShaderGroup->getOrCreateShader(context, propertiesAsUniforms)); + + // vertices, attributes and segments + addVertices(builder, bucket); + addAttributes(builder, bucket, vertexAttrs); + setSegments(builder, bucket); + + // finish + builder->flush(); + for (auto& drawable : builder->clearDrawables()) { + drawable->setTileID(tileID); + drawable->mutableUniformBuffers().createOrUpdate( + LineInterpolationUBOName, &lineInterpolationUBO, context); + + tileLayerGroup->addDrawable(renderPass, tileID, std::move(drawable)); + ++stats.drawablesAdded; + } + } + } +} +#endif + } // namespace mbgl diff --git a/src/mbgl/renderer/layers/render_line_layer.hpp b/src/mbgl/renderer/layers/render_line_layer.hpp index 40be3a237..863d72b05 100644 --- a/src/mbgl/renderer/layers/render_line_layer.hpp +++ b/src/mbgl/renderer/layers/render_line_layer.hpp @@ -8,18 +8,41 @@ #include #include +#include +#include + namespace mbgl { +#if MLN_LEGACY_RENDERER class LineProgram; class LineGradientProgram; class LineSDFProgram; class LinePatternProgram; +#endif + +#if MLN_DRAWABLE_RENDERER +namespace gfx { +class ShaderGroup; +class UniformBuffer; +using ShaderGroupPtr = std::shared_ptr; +using UniformBufferPtr = std::shared_ptr; +} // namespace gfx +#endif class RenderLineLayer final : public RenderLayer { public: explicit RenderLineLayer(Immutable); ~RenderLineLayer() override; +#if MLN_DRAWABLE_RENDERER + /// Generate any changes needed by the layer + void update(gfx::ShaderRegistry&, + gfx::Context&, + const TransformState&, + const RenderTree&, + UniqueChangeRequestVec&) override; +#endif + private: void transition(const TransitionParameters&) override; void evaluate(const PropertyEvaluationParameters&) override; @@ -46,9 +69,13 @@ private: float getLineWidth(const GeometryTileFeature&, float, const FeatureState&) const; void updateColorRamp(); - PremultipliedImage colorRamp; + std::shared_ptr colorRamp; std::optional colorRampTexture; +#if MLN_DRAWABLE_RENDERER + gfx::Texture2DPtr colorRampTexture2D; +#endif + #if MLN_LEGACY_RENDERER // Programs std::shared_ptr lineProgram; @@ -56,6 +83,12 @@ private: std::shared_ptr lineSDFProgram; std::shared_ptr linePatternProgram; #endif +#if MLN_DRAWABLE_RENDERER + gfx::ShaderGroupPtr lineShaderGroup; + gfx::ShaderGroupPtr lineGradientShaderGroup; + gfx::ShaderGroupPtr lineSDFShaderGroup; + gfx::ShaderGroupPtr linePatternShaderGroup; +#endif }; } // namespace mbgl diff --git a/src/mbgl/renderer/render_orchestrator.cpp b/src/mbgl/renderer/render_orchestrator.cpp index 995459261..6a120bee1 100644 --- a/src/mbgl/renderer/render_orchestrator.cpp +++ b/src/mbgl/renderer/render_orchestrator.cpp @@ -879,7 +879,6 @@ void RenderOrchestrator::updateLayers(gfx::ShaderRegistry& shaders, auto& renderLayer = static_cast(item.get()).layer.get(); renderLayer.update(shaders, context, state, renderTree, changes); } - addChanges(changes); } diff --git a/src/mbgl/renderer/render_orchestrator.hpp b/src/mbgl/renderer/render_orchestrator.hpp index f775ea572..b169ef057 100644 --- a/src/mbgl/renderer/render_orchestrator.hpp +++ b/src/mbgl/renderer/render_orchestrator.hpp @@ -14,6 +14,7 @@ #include #include #include +#include #include #include