diff --git a/src/mbgl/renderer/frame_history.cpp b/src/mbgl/renderer/frame_history.cpp index bf339edc6fb..eb125201f48 100644 --- a/src/mbgl/renderer/frame_history.cpp +++ b/src/mbgl/renderer/frame_history.cpp @@ -3,82 +3,110 @@ using namespace mbgl; -// Record frame history that will be used to calculate fading params -void FrameHistory::record(const TimePoint& now, float zoom) { - // first frame ever - if (history.empty()) { - history.emplace_back(FrameSnapshot{TimePoint::min(), zoom}); - history.emplace_back(FrameSnapshot{TimePoint::min(), zoom}); - } +FrameHistory::FrameHistory() { + changeTimes.fill(TimePoint::min()); + changeOpacities.fill(0); + opacities.fill(0); +}; - if (!history.empty() || history.back().z != zoom) { - history.emplace_back(FrameSnapshot{now, zoom}); - } -} +void FrameHistory::record(const TimePoint& now, float zoom, const Duration& duration) { -bool FrameHistory::needsAnimation(const Duration& duration) const { - if (history.empty()) { - return false; - } + int16_t zoomIndex = std::floor(zoom * 10.0); - // If we have a value that is older than duration and whose z value is the - // same as the most current z value, and if all values inbetween have the - // same z value, we don't need animation, otherwise we probably do. - const FrameSnapshot& pivot = history.back(); + if (firstFrame) { - int i = -1; - while ((int)history.size() > i + 1 && history[i + 1].now + duration < pivot.now) { - ++i; + for (int16_t z = 0; z <= zoomIndex; z++) { + opacities[z] = 255u; + } + firstFrame = false; } - if (i < 0) { - // There is no frame that is older than the duration time, so we need to - // check all frames. - i = 0; + if (zoomIndex < previousZoomIndex) { + for (int16_t z = zoomIndex + 1; z <= previousZoomIndex; z++) { + changeTimes[z] = now; + changeOpacities[z] = opacities[z]; + } + } else { + for (int16_t z = zoomIndex; z > previousZoomIndex; z--) { + changeTimes[z] = now; + changeOpacities[z] = opacities[z]; + } } - // Make sure that all subsequent snapshots have the same zoom as the last - // pivot element. - for (; (int)history.size() > i; ++i) { - if (history[i].z != pivot.z) { - return true; + for (int16_t z = 0; z <= 255; z++) { + std::chrono::duration timeDiff = now - changeTimes[z]; + int32_t opacityChange = (duration == Milliseconds(0) ? 1 : (timeDiff / duration)) * 255; + if (z <= zoomIndex) { + opacities[z] = util::min(255, changeOpacities[z] + opacityChange); + } else { + opacities[z] = util::max(0, changeOpacities[z] - opacityChange); } } - return false; + changed = true; + + if (zoomIndex != previousZoomIndex) { + previousZoomIndex = zoomIndex; + previousTime = now; + } + + time = now; } -FadeProperties FrameHistory::getFadeProperties(const TimePoint& now, const Duration& duration) { - // Remove frames until only one is outside the duration, or until there are only three - while (history.size() > 3 && history[1].now + duration < now) { - history.pop_front(); +bool FrameHistory::needsAnimation(const Duration& duration) const { + return (time - previousTime) < duration; +} + +void FrameHistory::upload(gl::GLObjectStore& glObjectStore) { + + if (changed) { + const bool first = !texture; + bind(glObjectStore); + + if (first) { + MBGL_CHECK_ERROR(glTexImage2D( + GL_TEXTURE_2D, // GLenum target + 0, // GLint level + GL_ALPHA, // GLint internalformat + width, // GLsizei width + height, // GLsizei height + 0, // GLint border + GL_ALPHA, // GLenum format + GL_UNSIGNED_BYTE, // GLenum type + opacities.data() + )); + } else { + MBGL_CHECK_ERROR(glTexSubImage2D( + GL_TEXTURE_2D, // GLenum target + 0, // GLint level + 0, // GLint xoffset + 0, // GLint yoffset + width, // GLsizei width + height, // GLsizei height + GL_ALPHA, // GLenum format + GL_UNSIGNED_BYTE, // GLenum type + opacities.data() + )); + } + + changed = false; + } +} - if (history[1].now + duration < now) { - history[0].z = history[1].z; +void FrameHistory::bind(gl::GLObjectStore& glObjectStore) { + if (!texture) { + texture.create(glObjectStore); + MBGL_CHECK_ERROR(glBindTexture(GL_TEXTURE_2D, texture.getID())); +#ifndef GL_ES_VERSION_2_0 + MBGL_CHECK_ERROR(glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAX_LEVEL, 0)); +#endif + MBGL_CHECK_ERROR(glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE)); + MBGL_CHECK_ERROR(glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE)); + MBGL_CHECK_ERROR(glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST)); + MBGL_CHECK_ERROR(glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST)); + } else { + MBGL_CHECK_ERROR(glBindTexture(GL_TEXTURE_2D, texture.getID())); } - // Find the range of zoom levels we want to fade between - float startingZ = history.front().z; - const FrameSnapshot lastFrame = history.back(); - float endingZ = lastFrame.z; - float lowZ = util::min(startingZ, endingZ); - float highZ = util::max(startingZ, endingZ); - - // Calculate the speed of zooming, and how far it would zoom in terms of zoom levels in one - // duration - float zoomDiff = endingZ - history[1].z; - std::chrono::duration timeDiff = lastFrame.now - history[1].now; - float fadedist = zoomDiff / (timeDiff / duration); - - // At end of a zoom when the zoom stops changing continue pretending to zoom at that speed - // bump is how much farther it would have been if it had continued zooming at the same rate - float bump = std::chrono::duration(now - lastFrame.now) / duration * fadedist; - - return FadeProperties { - fadedist, - lowZ, - highZ, - bump - }; } diff --git a/src/mbgl/renderer/frame_history.hpp b/src/mbgl/renderer/frame_history.hpp index 13a953e681b..88c58d74a09 100644 --- a/src/mbgl/renderer/frame_history.hpp +++ b/src/mbgl/renderer/frame_history.hpp @@ -1,37 +1,38 @@ #ifndef MBGL_RENDERER_FRAME_HISTORY #define MBGL_RENDERER_FRAME_HISTORY -#include -#include -#include +#include #include +#include #include namespace mbgl { -struct FrameSnapshot { - const TimePoint now; - float z; -}; - -struct FadeProperties { - float fadedist; - float minfadezoom; - float maxfadezoom; - float bump; -}; - class FrameHistory { public: - // Record frame history that will be used to calculate fading params - void record(const TimePoint&, float zoom); + FrameHistory(); + void record(const TimePoint&, float zoom, const Duration&); bool needsAnimation(const Duration&) const; - FadeProperties getFadeProperties(const TimePoint&, const Duration&); + void bind(gl::GLObjectStore&); + void upload(gl::GLObjectStore&); private: - std::deque history; + const int width = 256; + const int height = 1; + + std::array changeTimes; + std::array changeOpacities; + std::array opacities; + + int16_t previousZoomIndex = 0; + TimePoint previousTime = TimePoint::min(); + TimePoint time = TimePoint::min(); + bool firstFrame = true; + bool changed = true; + + gl::TextureHolder texture; }; } // namespace mbgl diff --git a/src/mbgl/renderer/painter.cpp b/src/mbgl/renderer/painter.cpp index e993e3dddff..175770dbb14 100644 --- a/src/mbgl/renderer/painter.cpp +++ b/src/mbgl/renderer/painter.cpp @@ -107,6 +107,9 @@ void Painter::render(const Style& style, const FrameData& frame_, SpriteAtlas& a matrix::identity(nativeMatrix); matrix::multiply(nativeMatrix, projMatrix, nativeMatrix); + frameHistory.record(frame.timePoint, state.getZoom(), + frame.mapMode == MapMode::Continuous ? util::DEFAULT_FADE_DURATION : Milliseconds(0)); + // - UPLOAD PASS ------------------------------------------------------------------------------- // Uploads all required buffers and images before we do any actual rendering. { @@ -117,6 +120,7 @@ void Painter::render(const Style& style, const FrameData& frame_, SpriteAtlas& a spriteAtlas->upload(glObjectStore); lineAtlas->upload(glObjectStore); glyphAtlas->upload(glObjectStore); + frameHistory.upload(glObjectStore); annotationSpriteAtlas.upload(glObjectStore); for (const auto& item : order) { @@ -161,8 +165,6 @@ void Painter::render(const Style& style, const FrameData& frame_, SpriteAtlas& a drawClippingMasks(generator.getStencils()); } - frameHistory.record(frame.timePoint, state.getZoom()); - // Actually render the layers if (debug::renderTree) { Log::Info(Event::Render, "{"); indent++; } diff --git a/src/mbgl/renderer/painter_symbol.cpp b/src/mbgl/renderer/painter_symbol.cpp index 42355493a5f..611f0c53e78 100644 --- a/src/mbgl/renderer/painter_symbol.cpp +++ b/src/mbgl/renderer/painter_symbol.cpp @@ -71,18 +71,9 @@ void Painter::renderSDF(SymbolBucket &bucket, sdfShader.u_zoom = (state.getZoom() - zoomAdjust) * 10; // current zoom level - if (frame.mapMode == MapMode::Continuous) { - FadeProperties f = frameHistory.getFadeProperties(frame.timePoint, util::DEFAULT_FADE_DURATION); - sdfShader.u_fadedist = f.fadedist * 10; - sdfShader.u_minfadezoom = std::floor(f.minfadezoom * 10); - sdfShader.u_maxfadezoom = std::floor(f.maxfadezoom * 10); - sdfShader.u_fadezoom = (state.getZoom() + f.bump) * 10; - } else { // MapMode::Still - sdfShader.u_fadedist = 0; - sdfShader.u_minfadezoom = state.getZoom() * 10; - sdfShader.u_maxfadezoom = state.getZoom() * 10; - sdfShader.u_fadezoom = state.getZoom() * 10; - } + config.activeTexture = GL_TEXTURE1; + frameHistory.bind(glObjectStore); + sdfShader.u_fadetexture = 1; // The default gamma value has to be adjust for the current pixelratio so that we're not // drawing blurry font on retina screens. @@ -239,14 +230,13 @@ void Painter::renderSymbol(SymbolBucket& bucket, // adjust min/max zooms for variable font sies float zoomAdjust = std::log(fontSize / layout.iconSize) / std::log(2); - iconShader->u_zoom = (state.getZoom() - zoomAdjust) * 10; // current zoom level - iconShader->u_fadedist = 0 * 10; - iconShader->u_minfadezoom = state.getZoom() * 10; - iconShader->u_maxfadezoom = state.getZoom() * 10; - iconShader->u_fadezoom = state.getZoom() * 10; iconShader->u_opacity = paint.iconOpacity; + config.activeTexture = GL_TEXTURE1; + frameHistory.bind(glObjectStore); + iconShader->u_fadetexture = 1; + setDepthSublayer(0); bucket.drawIcons(*iconShader, glObjectStore); } diff --git a/src/mbgl/shader/icon.fragment.glsl b/src/mbgl/shader/icon.fragment.glsl index 45b56793eba..f9ed6e75ed1 100644 --- a/src/mbgl/shader/icon.fragment.glsl +++ b/src/mbgl/shader/icon.fragment.glsl @@ -1,8 +1,11 @@ uniform sampler2D u_texture; +uniform sampler2D u_fadetexture; +uniform float u_opacity; varying vec2 v_tex; -varying float v_alpha; +varying vec2 v_fade_tex; void main() { - gl_FragColor = texture2D(u_texture, v_tex) * v_alpha; + float alpha = texture2D(u_fadetexture, v_fade_tex).a * u_opacity; + gl_FragColor = texture2D(u_texture, v_tex) * alpha; } diff --git a/src/mbgl/shader/icon.vertex.glsl b/src/mbgl/shader/icon.vertex.glsl index 3850e01ab79..a6a423127ab 100644 --- a/src/mbgl/shader/icon.vertex.glsl +++ b/src/mbgl/shader/icon.vertex.glsl @@ -9,18 +9,13 @@ attribute vec4 a_data2; uniform mat4 u_matrix; uniform mat4 u_exmatrix; uniform float u_zoom; -uniform float u_fadedist; -uniform float u_minfadezoom; -uniform float u_maxfadezoom; -uniform float u_fadezoom; -uniform float u_opacity; uniform bool u_skewed; uniform float u_extra; uniform vec2 u_texsize; varying vec2 v_tex; -varying float v_alpha; +varying vec2 v_fade_tex; void main() { vec2 a_tex = a_data1.xy; @@ -30,29 +25,9 @@ void main() { float a_minzoom = a_zoom[0]; float a_maxzoom = a_zoom[1]; - float a_fadedist = 10.0; - // u_zoom is the current zoom level adjusted for the change in font size float z = 2.0 - step(a_minzoom, u_zoom) - (1.0 - step(a_maxzoom, u_zoom)); - // fade out labels - float alpha = clamp((u_fadezoom - a_labelminzoom) / u_fadedist, 0.0, 1.0); - - if (u_fadedist >= 0.0) { - v_alpha = alpha; - } else { - v_alpha = 1.0 - alpha; - } - if (u_maxfadezoom < a_labelminzoom) { - v_alpha = 0.0; - } - if (u_minfadezoom >= a_labelminzoom) { - v_alpha = 1.0; - } - - // if label has been faded out, clip it - z += step(v_alpha, 0.0); - if (u_skewed) { vec4 extrude = u_exmatrix * vec4(a_offset / 64.0, 0, 0); gl_Position = u_matrix * vec4(a_pos + extrude.xy, 0, 1); @@ -63,6 +38,5 @@ void main() { } v_tex = a_tex / u_texsize; - - v_alpha *= u_opacity; + v_fade_tex = vec2(a_labelminzoom / 255.0, 0.0); } diff --git a/src/mbgl/shader/icon_shader.hpp b/src/mbgl/shader/icon_shader.hpp index ec6311ea807..a7dcfe7a7e6 100644 --- a/src/mbgl/shader/icon_shader.hpp +++ b/src/mbgl/shader/icon_shader.hpp @@ -15,15 +15,12 @@ class IconShader : public Shader { UniformMatrix<4> u_matrix = {"u_matrix", *this}; UniformMatrix<4> u_exmatrix = {"u_exmatrix", *this}; Uniform u_zoom = {"u_zoom", *this}; - Uniform u_fadedist = {"u_fadedist", *this}; - Uniform u_minfadezoom = {"u_minfadezoom", *this}; - Uniform u_maxfadezoom = {"u_maxfadezoom", *this}; - Uniform u_fadezoom = {"u_fadezoom", *this}; Uniform u_opacity = {"u_opacity", *this}; Uniform> u_texsize = {"u_texsize", *this}; Uniform u_skewed = {"u_skewed", *this}; Uniform u_extra = {"u_extra", *this}; Uniform u_texture = {"u_texture", *this}; + Uniform u_fadetexture = {"u_fadetexture", *this}; protected: GLint a_offset = -1; diff --git a/src/mbgl/shader/sdf.fragment.glsl b/src/mbgl/shader/sdf.fragment.glsl index a77e959e53b..3a6a4a8c37e 100644 --- a/src/mbgl/shader/sdf.fragment.glsl +++ b/src/mbgl/shader/sdf.fragment.glsl @@ -1,15 +1,17 @@ uniform sampler2D u_texture; +uniform sampler2D u_fadetexture; uniform vec4 u_color; uniform float u_buffer; uniform float u_gamma; varying vec2 v_tex; -varying float v_alpha; +varying vec2 v_fade_tex; varying float v_gamma_scale; void main() { float dist = texture2D(u_texture, v_tex).a; + float fade_alpha = texture2D(u_fadetexture, v_fade_tex).a; float gamma = u_gamma * v_gamma_scale; - float alpha = smoothstep(u_buffer - gamma, u_buffer + gamma, dist) * v_alpha; + float alpha = smoothstep(u_buffer - gamma, u_buffer + gamma, dist) * fade_alpha; gl_FragColor = u_color * alpha; } diff --git a/src/mbgl/shader/sdf.vertex.glsl b/src/mbgl/shader/sdf.vertex.glsl index 0d538b24fdb..818378475e9 100644 --- a/src/mbgl/shader/sdf.vertex.glsl +++ b/src/mbgl/shader/sdf.vertex.glsl @@ -9,16 +9,12 @@ attribute vec4 a_data2; uniform mat4 u_matrix; uniform mat4 u_exmatrix; uniform float u_zoom; -uniform float u_fadedist; -uniform float u_minfadezoom; -uniform float u_maxfadezoom; -uniform float u_fadezoom; uniform bool u_skewed; uniform vec2 u_texsize; varying vec2 v_tex; -varying float v_alpha; +varying vec2 v_fade_tex; varying float v_gamma_scale; void main() { @@ -32,24 +28,6 @@ void main() { // u_zoom is the current zoom level adjusted for the change in font size float show = step(a_minzoom, u_zoom) * (1.0 - step(a_maxzoom, u_zoom)); - // fade out labels - float alpha = clamp((u_fadezoom - a_labelminzoom) / u_fadedist, 0.0, 1.0); - - if (u_fadedist >= 0.0) { - v_alpha = alpha; - } else { - v_alpha = 1.0 - alpha; - } - if (u_maxfadezoom < a_labelminzoom) { - v_alpha = 0.0; - } - if (u_minfadezoom >= a_labelminzoom) { - v_alpha = 1.0; - } - - // if label has been faded out, clip it - show *= (1.0 - step(v_alpha, 0.0)); - if (u_skewed) { vec4 extrude = u_exmatrix * vec4(a_offset * show / 64.0, 0, 0); gl_Position = u_matrix * vec4(a_pos + extrude.xy, 0, 1); @@ -61,4 +39,5 @@ void main() { v_gamma_scale = (gl_Position.w - 0.5); v_tex = a_tex / u_texsize; + v_fade_tex = vec2(a_labelminzoom / 255.0, 0.0); } diff --git a/src/mbgl/shader/sdf_shader.hpp b/src/mbgl/shader/sdf_shader.hpp index 402168de0c1..5fe6a443709 100644 --- a/src/mbgl/shader/sdf_shader.hpp +++ b/src/mbgl/shader/sdf_shader.hpp @@ -17,12 +17,9 @@ class SDFShader : public Shader { Uniform u_buffer = {"u_buffer", *this}; Uniform u_gamma = {"u_gamma", *this}; Uniform u_zoom = {"u_zoom", *this}; - Uniform u_fadedist = {"u_fadedist", *this}; - Uniform u_minfadezoom = {"u_minfadezoom", *this}; - Uniform u_maxfadezoom = {"u_maxfadezoom", *this}; - Uniform u_fadezoom = {"u_fadezoom", *this}; Uniform u_skewed = {"u_skewed", *this}; Uniform u_texture = {"u_texture", *this}; + Uniform u_fadetexture = {"u_fadetexture", *this}; protected: GLint a_offset = -1;