diff --git a/src/mbgl/renderer/painter.cpp b/src/mbgl/renderer/painter.cpp index 724788f21..0fb99826c 100644 --- a/src/mbgl/renderer/painter.cpp +++ b/src/mbgl/renderer/painter.cpp @@ -232,7 +232,7 @@ void Painter::render(const Style& style, const std::set>& drawClippingMasks(sources); - frameHistory.record(time, state.getNormalizedZoom()); + recordZoom(time, state.getNormalizedZoom()); // Actually render the layers if (debug::renderTree) { std::cout << "{" << std::endl; indent++; } @@ -460,3 +460,26 @@ mat4 Painter::translatedMatrix(const mat4& matrix, const std::array &t return vtxMatrix; } } + +void Painter::recordZoom(const timestamp time, const float zoom) { + frameHistory.record(time, zoom); + + if (lastZoom < 0) { + // first frame ever + lastIntegerZoom = std::floor(zoom); + lastZoom = zoom; + } + + // check whether an integer zoom level was passed since the last frame + // and if yes, record it with the time. Used for transitioning patterns. + if (std::floor(lastZoom) < std::floor(zoom)) { + lastIntegerZoom = std::floor(zoom); + lastIntegerZoomTime = time; + + } else if (std::floor(lastZoom) > std::floor(zoom)) { + lastIntegerZoom = std::floor(zoom) + 1; + lastIntegerZoomTime = time; + } + + lastZoom = zoom; +} diff --git a/src/mbgl/renderer/painter.hpp b/src/mbgl/renderer/painter.hpp index 4d4876a6f..5a4207020 100644 --- a/src/mbgl/renderer/painter.hpp +++ b/src/mbgl/renderer/painter.hpp @@ -139,6 +139,7 @@ private: mat4 translatedMatrix(const mat4& matrix, const std::array &translation, const Tile::ID &id, TranslateAnchorType anchor); void prepareTile(const Tile& tile); + void recordZoom(const timestamp time, const float zoom); template void renderSDF(SymbolBucket &bucket, @@ -191,6 +192,10 @@ private: RenderPass pass = RenderPass::Opaque; const float strata_epsilon = 1.0f / (1 << 16); + int lastIntegerZoom; + timestamp lastIntegerZoomTime = 0; + float lastZoom = -1; + public: FrameHistory frameHistory; diff --git a/src/mbgl/renderer/painter_fill.cpp b/src/mbgl/renderer/painter_fill.cpp index 324dacfcd..5e8f46d34 100644 --- a/src/mbgl/renderer/painter_fill.cpp +++ b/src/mbgl/renderer/painter_fill.cpp @@ -60,8 +60,20 @@ void Painter::renderFill(FillBucket& bucket, util::ptr layer_desc, c // Image fill. if (pass == RenderPass::Translucent) { const SpriteAtlasPosition pos = spriteAtlas.getPosition(properties.image, true); - const float mix = std::fmod(float(state.getZoom()), 1.0f); - const float factor = 8.0 / std::pow(2, state.getIntegerZoom() - id.z); + float factor = 8.0 / std::pow(2, state.getIntegerZoom() - id.z); + + float mix; + float duration = 300 * 1_millisecond; + const float fraction = std::fmod(float(state.getZoom()), 1.0f); + float t = std::min((util::now() - lastIntegerZoomTime) / duration, 1.0f); + if (state.getZoom() > lastIntegerZoom) { + // zooming in + mix = fraction + (1.0f - fraction) * t; + factor *= 2.0; + } else { + // zooming out + mix = fraction - fraction * t; + } mat3 patternMatrix; matrix::identity(patternMatrix); diff --git a/src/mbgl/renderer/painter_line.cpp b/src/mbgl/renderer/painter_line.cpp index a28d30a52..4669b72fa 100644 --- a/src/mbgl/renderer/painter_line.cpp +++ b/src/mbgl/renderer/painter_line.cpp @@ -70,6 +70,10 @@ void Painter::renderLine(LineBucket& bucket, util::ptr layer_desc, c bucket.drawPoints(*linejoinShader); } + float duration = 300 * 1_millisecond; + const float fraction = std::fmod(float(state.getZoom()), 1.0f); + float t = std::min((util::now() - lastIntegerZoomTime) / duration, 1.0f); + if (properties.dash_array.size()) { useProgram(linesdfShader->program); @@ -88,10 +92,23 @@ void Painter::renderLine(LineBucket& bucket, util::ptr layer_desc, c float scaleX = patternratio / pos.width / properties.dash_line_width; float scaleY = -pos.height / 2.0; - linesdfShader->u_patternscale = {{ scaleX, scaleY }}; - linesdfShader->u_tex_y = pos.y; + float mix; + if (state.getZoom() > lastIntegerZoom) { + // zooming in + mix = fraction + (1.0f - fraction) * t; + scaleX /= 2.0; + } else { + // zooming out + mix = fraction - fraction * t; + } + + linesdfShader->u_patternscale_a = {{ scaleX, scaleY }}; + linesdfShader->u_tex_y_a = pos.y; + linesdfShader->u_patternscale_b = {{ scaleX * 2.0f, scaleY }}; + linesdfShader->u_tex_y_b = pos.y; linesdfShader->u_image = 0; linesdfShader->u_sdfgamma = lineAtlas.width / (properties.dash_line_width * pos.width * 256.0 * state.getPixelRatio()) / 2; + linesdfShader->u_mix = mix; bucket.drawLineSDF(*linesdfShader); @@ -99,7 +116,15 @@ void Painter::renderLine(LineBucket& bucket, util::ptr layer_desc, c SpriteAtlasPosition imagePos = spriteAtlas.getPosition(properties.image, true); float factor = 8.0 / std::pow(2, state.getIntegerZoom() - id.z); - float fade = std::fmod(state.getZoom(), 1.0); + float fade; + if (state.getZoom() > lastIntegerZoom) { + // zooming in + fade = fraction + (1.0f - fraction) * t; + factor *= 2.0; + } else { + // zooming out + fade = fraction - fraction * t; + } useProgram(linepatternShader->program); diff --git a/src/mbgl/shader/linesdf.fragment.glsl b/src/mbgl/shader/linesdf.fragment.glsl index 90a5eac3e..5d53dbe88 100644 --- a/src/mbgl/shader/linesdf.fragment.glsl +++ b/src/mbgl/shader/linesdf.fragment.glsl @@ -3,9 +3,11 @@ uniform vec4 u_color; uniform float u_blur; uniform sampler2D u_image; uniform float u_sdfgamma; +uniform float u_mix; varying vec2 v_normal; -varying vec2 v_tex; +varying vec2 v_tex_a; +varying vec2 v_tex_b; void main() { // Calculate the distance of the pixel from the line in pixels. @@ -16,7 +18,9 @@ void main() { // (v_linewidth.s) float alpha = clamp(min(dist - (u_linewidth.t - u_blur), u_linewidth.s - dist) / u_blur, 0.0, 1.0); - float sdfdist = texture2D(u_image, v_tex).a; + float sdfdist_a = texture2D(u_image, v_tex_a).a; + float sdfdist_b = texture2D(u_image, v_tex_b).a; + float sdfdist = mix(sdfdist_a, sdfdist_b, u_mix); alpha *= smoothstep(0.5 - u_sdfgamma, 0.5 + u_sdfgamma, sdfdist); gl_FragColor = u_color * alpha; diff --git a/src/mbgl/shader/linesdf.vertex.glsl b/src/mbgl/shader/linesdf.vertex.glsl index 0ab6804ab..7f246ced6 100644 --- a/src/mbgl/shader/linesdf.vertex.glsl +++ b/src/mbgl/shader/linesdf.vertex.glsl @@ -17,11 +17,14 @@ uniform mat4 u_exmatrix; // shared uniform float u_ratio; uniform vec2 u_linewidth; -uniform vec2 u_patternscale; -uniform float u_tex_y; +uniform vec2 u_patternscale_a; +uniform float u_tex_y_a; +uniform vec2 u_patternscale_b; +uniform float u_tex_y_b; varying vec2 v_normal; -varying vec2 v_tex; +varying vec2 v_tex_a; +varying vec2 v_tex_b; void main() { vec2 a_extrude = a_data.xy; @@ -45,5 +48,6 @@ void main() { // tile's zoom level. gl_Position = u_matrix * vec4(floor(a_pos * 0.5), 0.0, 1.0) + u_exmatrix * dist; - v_tex = vec2(a_linesofar * u_patternscale.x, normal.y * u_patternscale.y + u_tex_y); + v_tex_a = vec2(a_linesofar * u_patternscale_a.x, normal.y * u_patternscale_a.y + u_tex_y_a); + v_tex_b = vec2(a_linesofar * u_patternscale_b.x, normal.y * u_patternscale_b.y + u_tex_y_b); } diff --git a/src/mbgl/shader/linesdf_shader.hpp b/src/mbgl/shader/linesdf_shader.hpp index 918ed5cba..16b7f3cb1 100644 --- a/src/mbgl/shader/linesdf_shader.hpp +++ b/src/mbgl/shader/linesdf_shader.hpp @@ -18,10 +18,13 @@ public: Uniform> u_linewidth = {"u_linewidth", *this}; Uniform u_ratio = {"u_ratio", *this}; Uniform u_blur = {"u_blur", *this}; - Uniform> u_patternscale = { "u_patternscale", *this }; - Uniform u_tex_y = {"u_tex_y", *this}; + Uniform> u_patternscale_a = { "u_patternscale_a", *this }; + Uniform u_tex_y_a = {"u_tex_y_a", *this}; + Uniform> u_patternscale_b = { "u_patternscale_b", *this }; + Uniform u_tex_y_b = {"u_tex_y_b", *this}; Uniform u_image = {"u_image", *this}; Uniform u_sdfgamma = {"u_sdfgamma", *this}; + Uniform u_mix = {"u_mix", *this}; private: int32_t a_pos = -1;