summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorAnsis Brammanis <ansis.brammanis@gmail.com>2016-05-20 15:19:56 -0400
committerJohn Firebaugh <john.firebaugh@gmail.com>2016-05-20 12:19:56 -0700
commit4c62a5508cfa96755b37850051871320d79748fb (patch)
treef808eae2da1c21184ec4b48eba4418274f8afa4d
parent99e2504f8de4a2da980c263c28f9f526abc297d9 (diff)
downloadqtlocation-mapboxgl-4c62a5508cfa96755b37850051871320d79748fb.tar.gz
[core] better symbol fading with texture lookups (#4579)
- this is simpler than predicting opacity based on current zooming speed - this is smoother: symbols don't flicker when changing zoom speed or when zooming in and out rapidly. https://github.com/mapbox/mapbox-gl-js/commit/1df146627092b58c8db64d45530c74cd12a3fa02 fix #4562
-rw-r--r--src/mbgl/renderer/frame_history.cpp150
-rw-r--r--src/mbgl/renderer/frame_history.hpp39
-rw-r--r--src/mbgl/renderer/painter.cpp6
-rw-r--r--src/mbgl/renderer/painter_symbol.cpp24
-rw-r--r--src/mbgl/shader/icon.fragment.glsl7
-rw-r--r--src/mbgl/shader/icon.vertex.glsl30
-rw-r--r--src/mbgl/shader/icon_shader.hpp5
-rw-r--r--src/mbgl/shader/sdf.fragment.glsl6
-rw-r--r--src/mbgl/shader/sdf.vertex.glsl25
-rw-r--r--src/mbgl/shader/sdf_shader.hpp5
10 files changed, 135 insertions, 162 deletions
diff --git a/src/mbgl/renderer/frame_history.cpp b/src/mbgl/renderer/frame_history.cpp
index bf339edc6f..eb125201f4 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<float> 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<float> 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<float>(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 13a953e681..88c58d74a0 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 <deque>
-#include <cassert>
-#include <cmath>
+#include <array>
#include <mbgl/platform/platform.hpp>
+#include <mbgl/gl/gl_object_store.hpp>
#include <mbgl/util/chrono.hpp>
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<FrameSnapshot> history;
+ const int width = 256;
+ const int height = 1;
+
+ std::array<TimePoint, 256> changeTimes;
+ std::array<uint8_t, 256> changeOpacities;
+ std::array<uint8_t, 256> 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 e993e3dddf..175770dbb1 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 42355493a5..611f0c53e7 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 45b56793eb..f9ed6e75ed 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 3850e01ab7..a6a423127a 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 ec6311ea80..a7dcfe7a7e 100644
--- a/src/mbgl/shader/icon_shader.hpp
+++ b/src/mbgl/shader/icon_shader.hpp
@@ -15,15 +15,12 @@ public:
UniformMatrix<4> u_matrix = {"u_matrix", *this};
UniformMatrix<4> u_exmatrix = {"u_exmatrix", *this};
Uniform<GLfloat> u_zoom = {"u_zoom", *this};
- Uniform<GLfloat> u_fadedist = {"u_fadedist", *this};
- Uniform<GLfloat> u_minfadezoom = {"u_minfadezoom", *this};
- Uniform<GLfloat> u_maxfadezoom = {"u_maxfadezoom", *this};
- Uniform<GLfloat> u_fadezoom = {"u_fadezoom", *this};
Uniform<GLfloat> u_opacity = {"u_opacity", *this};
Uniform<std::array<GLfloat, 2>> u_texsize = {"u_texsize", *this};
Uniform<GLint> u_skewed = {"u_skewed", *this};
Uniform<GLfloat> u_extra = {"u_extra", *this};
Uniform<GLint> u_texture = {"u_texture", *this};
+ Uniform<GLint> 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 a77e959e53..3a6a4a8c37 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 0d538b24fd..818378475e 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 402168de0c..5fe6a44370 100644
--- a/src/mbgl/shader/sdf_shader.hpp
+++ b/src/mbgl/shader/sdf_shader.hpp
@@ -17,12 +17,9 @@ public:
Uniform<GLfloat> u_buffer = {"u_buffer", *this};
Uniform<GLfloat> u_gamma = {"u_gamma", *this};
Uniform<GLfloat> u_zoom = {"u_zoom", *this};
- Uniform<GLfloat> u_fadedist = {"u_fadedist", *this};
- Uniform<GLfloat> u_minfadezoom = {"u_minfadezoom", *this};
- Uniform<GLfloat> u_maxfadezoom = {"u_maxfadezoom", *this};
- Uniform<GLfloat> u_fadezoom = {"u_fadezoom", *this};
Uniform<GLint> u_skewed = {"u_skewed", *this};
Uniform<GLint> u_texture = {"u_texture", *this};
+ Uniform<GLint> u_fadetexture = {"u_fadetexture", *this};
protected:
GLint a_offset = -1;