diff options
author | Ansis Brammanis <brammanis@gmail.com> | 2015-02-02 14:46:48 -0800 |
---|---|---|
committer | Ansis Brammanis <brammanis@gmail.com> | 2015-02-02 14:46:48 -0800 |
commit | d532824aec25e20efccb80860b990db0b85780ac (patch) | |
tree | 4210723832ad827f188bddf384c30d46d5819cb8 /src/mbgl | |
parent | 47966a143176a337733fe63b4121d2d00c48359a (diff) | |
download | qtlocation-mapboxgl-d532824aec25e20efccb80860b990db0b85780ac.tar.gz |
implement functions for patterns
It introduces a new function type, FadedStopsFunction, that transitions
between the stops values instead of interpolating between them.
Diffstat (limited to 'src/mbgl')
-rw-r--r-- | src/mbgl/renderer/painter.cpp | 6 | ||||
-rw-r--r-- | src/mbgl/renderer/painter_fill.cpp | 42 | ||||
-rw-r--r-- | src/mbgl/shader/pattern.fragment.glsl | 17 | ||||
-rw-r--r-- | src/mbgl/shader/pattern.vertex.glsl | 9 | ||||
-rw-r--r-- | src/mbgl/shader/pattern_shader.hpp | 9 | ||||
-rw-r--r-- | src/mbgl/style/fadedfunction_properties.cpp | 51 | ||||
-rw-r--r-- | src/mbgl/style/fadedfunction_properties.hpp | 24 | ||||
-rw-r--r-- | src/mbgl/style/property_value.hpp | 4 | ||||
-rw-r--r-- | src/mbgl/style/style.cpp | 4 | ||||
-rw-r--r-- | src/mbgl/style/style.hpp | 2 | ||||
-rw-r--r-- | src/mbgl/style/style_layer.cpp | 135 | ||||
-rw-r--r-- | src/mbgl/style/style_layer.hpp | 9 | ||||
-rw-r--r-- | src/mbgl/style/style_layer_group.cpp | 4 | ||||
-rw-r--r-- | src/mbgl/style/style_layer_group.hpp | 2 | ||||
-rw-r--r-- | src/mbgl/style/style_parser.cpp | 120 | ||||
-rw-r--r-- | src/mbgl/style/style_parser.hpp | 4 | ||||
-rw-r--r-- | src/mbgl/style/style_properties.hpp | 4 | ||||
-rw-r--r-- | src/mbgl/style/types.hpp | 10 | ||||
-rw-r--r-- | src/mbgl/style/zoom_history.hpp | 39 |
19 files changed, 353 insertions, 142 deletions
diff --git a/src/mbgl/renderer/painter.cpp b/src/mbgl/renderer/painter.cpp index 0fb99826c6..448b380743 100644 --- a/src/mbgl/renderer/painter.cpp +++ b/src/mbgl/renderer/painter.cpp @@ -385,8 +385,8 @@ void Painter::renderBackground(util::ptr<StyleLayer> layer_desc) { useProgram(patternShader->program); patternShader->u_matrix = identityMatrix; - patternShader->u_pattern_tl = imagePos.tl; - patternShader->u_pattern_br = imagePos.br; + patternShader->u_pattern_tl_a = imagePos.tl; + patternShader->u_pattern_br_a = imagePos.br; patternShader->u_mix = zoomFraction; patternShader->u_opacity = properties.opacity; @@ -408,7 +408,7 @@ void Painter::renderBackground(util::ptr<StyleLayer> layer_desc) { matrix::scale(matrix, matrix, scale * state.getWidth() / 2, -scale * state.getHeight() / 2); - patternShader->u_patternmatrix = matrix; + patternShader->u_patternmatrix_a = matrix; backgroundBuffer.bind(); patternShader->bind(0); diff --git a/src/mbgl/renderer/painter_fill.cpp b/src/mbgl/renderer/painter_fill.cpp index 5e8f46d340..10d4aa3320 100644 --- a/src/mbgl/renderer/painter_fill.cpp +++ b/src/mbgl/renderer/painter_fill.cpp @@ -33,7 +33,7 @@ void Painter::renderFill(FillBucket& bucket, util::ptr<StyleLayer> layer_desc, c stroke_color[3] *= properties.opacity; } - const bool pattern = properties.image.size(); + const bool pattern = properties.image.low.size(); bool outline = properties.antialias && !pattern && properties.stroke_color != properties.fill_color; bool fringeline = properties.antialias && !pattern && properties.stroke_color == properties.fill_color; @@ -59,34 +59,32 @@ void Painter::renderFill(FillBucket& bucket, util::ptr<StyleLayer> layer_desc, c if (pattern) { // Image fill. if (pass == RenderPass::Translucent) { - const SpriteAtlasPosition pos = spriteAtlas.getPosition(properties.image, true); + const SpriteAtlasPosition posA = spriteAtlas.getPosition(properties.image.low, true); + const SpriteAtlasPosition posB = spriteAtlas.getPosition(properties.image.high, true); 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); - matrix::scale(patternMatrix, patternMatrix, 1.0f / (pos.size[0] * factor), 1.0f / (pos.size[1] * factor)); + mat3 patternMatrixA; + matrix::identity(patternMatrixA); + matrix::scale(patternMatrixA, patternMatrixA, + 1.0f / (posA.size[0] * factor * properties.image.lowScale), + 1.0f / (posA.size[1] * factor * properties.image.lowScale)); + mat3 patternMatrixB; + matrix::identity(patternMatrixB); + matrix::scale(patternMatrixB, patternMatrixB, + 1.0f / (posB.size[0] * factor * properties.image.highScale), + 1.0f / (posB.size[1] * factor * properties.image.highScale)); useProgram(patternShader->program); patternShader->u_matrix = vtxMatrix; - patternShader->u_pattern_tl = pos.tl; - patternShader->u_pattern_br = pos.br; + patternShader->u_pattern_tl_a = posA.tl; + patternShader->u_pattern_br_a = posA.br; + patternShader->u_pattern_tl_b = posB.tl; + patternShader->u_pattern_br_b = posB.br; patternShader->u_opacity = properties.opacity; patternShader->u_image = 0; - patternShader->u_mix = mix; - patternShader->u_patternmatrix = patternMatrix; + patternShader->u_mix = properties.image.t; + patternShader->u_patternmatrix_a = patternMatrixA; + patternShader->u_patternmatrix_b = patternMatrixB; MBGL_CHECK_ERROR(glActiveTexture(GL_TEXTURE0)); spriteAtlas.bind(true); diff --git a/src/mbgl/shader/pattern.fragment.glsl b/src/mbgl/shader/pattern.fragment.glsl index ba6aed3023..a28a52ce36 100644 --- a/src/mbgl/shader/pattern.fragment.glsl +++ b/src/mbgl/shader/pattern.fragment.glsl @@ -1,20 +1,23 @@ uniform float u_opacity; -uniform vec2 u_pattern_tl; -uniform vec2 u_pattern_br; +uniform vec2 u_pattern_tl_a; +uniform vec2 u_pattern_br_a; +uniform vec2 u_pattern_tl_b; +uniform vec2 u_pattern_br_b; uniform float u_mix; uniform sampler2D u_image; -varying vec2 v_pos; +varying vec2 v_pos_a; +varying vec2 v_pos_b; void main() { - vec2 imagecoord = mod(v_pos, 1.0); - vec2 pos = mix(u_pattern_tl, u_pattern_br, imagecoord); + vec2 imagecoord = mod(v_pos_a, 1.0); + vec2 pos = mix(u_pattern_tl_a, u_pattern_br_a, imagecoord); vec4 color1 = texture2D(u_image, pos); - vec2 imagecoord2 = mod(imagecoord * 2.0, 1.0); - vec2 pos2 = mix(u_pattern_tl, u_pattern_br, imagecoord2); + vec2 imagecoord_b = mod(v_pos_b, 1.0); + vec2 pos2 = mix(u_pattern_tl_b, u_pattern_br_b, imagecoord_b); vec4 color2 = texture2D(u_image, pos2); gl_FragColor = mix(color1, color2, u_mix) * u_opacity; diff --git a/src/mbgl/shader/pattern.vertex.glsl b/src/mbgl/shader/pattern.vertex.glsl index f2de884ead..dff4469d2b 100644 --- a/src/mbgl/shader/pattern.vertex.glsl +++ b/src/mbgl/shader/pattern.vertex.glsl @@ -1,11 +1,14 @@ uniform mat4 u_matrix; -uniform mat3 u_patternmatrix; +uniform mat3 u_patternmatrix_a; +uniform mat3 u_patternmatrix_b; attribute vec2 a_pos; -varying vec2 v_pos; +varying vec2 v_pos_a; +varying vec2 v_pos_b; void main() { gl_Position = u_matrix * vec4(a_pos, 0, 1); - v_pos = (u_patternmatrix * vec3(a_pos, 1)).xy; + v_pos_a = (u_patternmatrix_a * vec3(a_pos, 1)).xy; + v_pos_b = (u_patternmatrix_b * vec3(a_pos, 1)).xy; } diff --git a/src/mbgl/shader/pattern_shader.hpp b/src/mbgl/shader/pattern_shader.hpp index 9fabd8e18a..9fc8dcfa01 100644 --- a/src/mbgl/shader/pattern_shader.hpp +++ b/src/mbgl/shader/pattern_shader.hpp @@ -13,12 +13,15 @@ public: void bind(char *offset); UniformMatrix<4> u_matrix = {"u_matrix", *this}; - Uniform<std::array<float, 2>> u_pattern_tl = {"u_pattern_tl", *this}; - Uniform<std::array<float, 2>> u_pattern_br = {"u_pattern_br", *this}; + Uniform<std::array<float, 2>> u_pattern_tl_a = {"u_pattern_tl_a", *this}; + Uniform<std::array<float, 2>> u_pattern_br_a = {"u_pattern_br_a", *this}; + Uniform<std::array<float, 2>> u_pattern_tl_b = {"u_pattern_tl_b", *this}; + Uniform<std::array<float, 2>> u_pattern_br_b = {"u_pattern_br_b", *this}; Uniform<float> u_opacity = {"u_opacity", *this}; Uniform<float> u_mix = {"u_mix", *this}; Uniform<int32_t> u_image = {"u_image", *this}; - UniformMatrix<3> u_patternmatrix = {"u_patternmatrix", *this}; + UniformMatrix<3> u_patternmatrix_a = {"u_patternmatrix_a", *this}; + UniformMatrix<3> u_patternmatrix_b = {"u_patternmatrix_b", *this}; private: int32_t a_pos = -1; diff --git a/src/mbgl/style/fadedfunction_properties.cpp b/src/mbgl/style/fadedfunction_properties.cpp new file mode 100644 index 0000000000..485bffd26c --- /dev/null +++ b/src/mbgl/style/fadedfunction_properties.cpp @@ -0,0 +1,51 @@ +#include <mbgl/style/fadedfunction_properties.hpp> +#include <mbgl/style/types.hpp> + +#include <cmath> + +namespace mbgl { + +template <typename T> +uint32_t getBiggestStopLessThan(std::vector<std::pair<float, T>> stops, float z) { + for (uint32_t i = 0; i < stops.size(); i++) { + if (stops[i].first > z) { + return i == 0 ? i : i - 1; + } + } + return stops.size() - 1; +} + +template <typename T> +T FadedStopsFunction<T>::evaluate(float z, const ZoomHistory &zh) const { + T result; + + float fraction = std::fmod(z, 1.0f); + float tDiff = (util::now() - zh.lastIntegerZoomTime) / 1_millisecond; + float fDuration = duration / 1_millisecond; + float t = std::min(tDiff / fDuration, 1.0f); + float scale = 1.0f; + uint32_t low, high; + + if (z > zh.lastIntegerZoom) { + result.t = fraction + (1.0f - fraction) * t; + scale *= 2.0f; + low = getBiggestStopLessThan(values, z - 1.0f); + high = getBiggestStopLessThan(values, z); + + } else { + result.t = fraction - fraction * t; + low = getBiggestStopLessThan(values, z); + high = getBiggestStopLessThan(values, z + 1.0f); + } + + + result.low = values[low].second.low; + result.high = values[high].second.low; + result.lowScale = scale; + result.highScale = scale / 2; + return result; +} + +template Faded<std::string> FadedStopsFunction<Faded<std::string>>::evaluate(float z, const ZoomHistory &zoomHistory) const; + +} diff --git a/src/mbgl/style/fadedfunction_properties.hpp b/src/mbgl/style/fadedfunction_properties.hpp new file mode 100644 index 0000000000..4d49dafb46 --- /dev/null +++ b/src/mbgl/style/fadedfunction_properties.hpp @@ -0,0 +1,24 @@ +#ifndef MBGL_STYLE_FADEDFUNCTION_PROPERTIES +#define MBGL_STYLE_FADEDFUNCTION_PROPERTIES + +#include <mbgl/style/zoom_history.hpp> + +#include <vector> + +namespace mbgl { + +template <typename T> +struct FadedStopsFunction { + inline FadedStopsFunction(const std::vector<std::pair<float, T>> &values_, timestamp duration_) : values(values_), duration(duration_) {} + inline FadedStopsFunction(T &value) : values({{ 0, value }}), duration(0.0f) {} + inline FadedStopsFunction() : values(), duration(0.0f) {} + T evaluate(float z, const ZoomHistory &zoomHistory) const; + +private: + const std::vector<std::pair<float, T>> values; + const timestamp duration; +}; + +} + +#endif diff --git a/src/mbgl/style/property_value.hpp b/src/mbgl/style/property_value.hpp index e017981dee..7b6c38e754 100644 --- a/src/mbgl/style/property_value.hpp +++ b/src/mbgl/style/property_value.hpp @@ -3,6 +3,7 @@ #include <mbgl/util/variant.hpp> #include <mbgl/style/function_properties.hpp> +#include <mbgl/style/fadedfunction_properties.hpp> #include <mbgl/style/types.hpp> #include <vector> @@ -16,7 +17,8 @@ typedef mapbox::util::variant< Function<bool>, Function<float>, Function<Color>, - Function<std::vector<float>> + Function<std::vector<float>>, + FadedStopsFunction<Faded<std::string>> > PropertyValue; } diff --git a/src/mbgl/style/style.cpp b/src/mbgl/style/style.cpp index ecff6fb5ff..dc764106ce 100644 --- a/src/mbgl/style/style.cpp +++ b/src/mbgl/style/style.cpp @@ -29,8 +29,10 @@ Style::~Style() {} void Style::updateProperties(float z, timestamp now) { uv::writelock lock(mtx); + zoomHistory.update(z, now); + if (layers) { - layers->updateProperties(z, now); + layers->updateProperties(z, now, zoomHistory); } // Apply transitions after the first time. diff --git a/src/mbgl/style/style.hpp b/src/mbgl/style/style.hpp index e9205712ef..434b394217 100644 --- a/src/mbgl/style/style.hpp +++ b/src/mbgl/style/style.hpp @@ -3,6 +3,7 @@ #include <mbgl/style/property_transition.hpp> #include <mbgl/style/style_source.hpp> +#include <mbgl/style/zoom_history.hpp> #include <mbgl/util/time.hpp> #include <mbgl/util/uv.hpp> @@ -49,6 +50,7 @@ private: PropertyTransition defaultTransition; bool initial_render_complete = false; std::unique_ptr<uv::rwlock> mtx; + ZoomHistory zoomHistory; }; } diff --git a/src/mbgl/style/style_layer.cpp b/src/mbgl/style/style_layer.cpp index 262ca23af8..bb9688e574 100644 --- a/src/mbgl/style/style_layer.cpp +++ b/src/mbgl/style/style_layer.cpp @@ -94,7 +94,7 @@ void StyleLayer::applyClassProperties(const ClassID class_id, template <typename T> struct PropertyEvaluator { typedef T result_type; - PropertyEvaluator(float z_) : z(z_) {} + PropertyEvaluator(float z_, const ZoomHistory &zoomHistory_) : z(z_), zoomHistory(zoomHistory_) {} template <typename P, typename std::enable_if<std::is_convertible<P, T>::value, int>::type = 0> T operator()(const P &value) const { @@ -105,6 +105,10 @@ struct PropertyEvaluator { return mapbox::util::apply_visitor(FunctionEvaluator<T>(z), value); } + T operator()(const FadedStopsFunction<T> &value) const { + return value.evaluate(z, zoomHistory); + } + template <typename P, typename std::enable_if<!std::is_convertible<P, T>::value, int>::type = 0> T operator()(const P &) const { return T(); @@ -112,15 +116,16 @@ struct PropertyEvaluator { private: const float z; + const ZoomHistory &zoomHistory; }; template <typename T> -void StyleLayer::applyStyleProperty(PropertyKey key, T &target, const float z, const timestamp now) { +void StyleLayer::applyStyleProperty(PropertyKey key, T &target, const float z, const timestamp now, const ZoomHistory &zoomHistory) { auto it = appliedStyle.find(key); if (it != appliedStyle.end()) { AppliedClassProperties &applied = it->second; // Iterate through all properties that we need to apply in order. - const PropertyEvaluator<T> evaluator(z); + const PropertyEvaluator<T> evaluator(z, zoomHistory); for (AppliedClassProperty &property : applied.properties) { if (now >= property.begin) { // We overwrite the current property with the new value. @@ -133,12 +138,12 @@ void StyleLayer::applyStyleProperty(PropertyKey key, T &target, const float z, c } template <typename T> -void StyleLayer::applyTransitionedStyleProperty(PropertyKey key, T &target, const float z, const timestamp now) { +void StyleLayer::applyTransitionedStyleProperty(PropertyKey key, T &target, const float z, const timestamp now, const ZoomHistory &zoomHistory) { auto it = appliedStyle.find(key); if (it != appliedStyle.end()) { AppliedClassProperties &applied = it->second; // Iterate through all properties that we need to apply in order. - const PropertyEvaluator<T> evaluator(z); + const PropertyEvaluator<T> evaluator(z, zoomHistory); for (AppliedClassProperty &property : applied.properties) { if (now >= property.end) { // We overwrite the current property with the new value. @@ -155,95 +160,95 @@ void StyleLayer::applyTransitionedStyleProperty(PropertyKey key, T &target, cons } template <> -void StyleLayer::applyStyleProperties<FillProperties>(const float z, const timestamp now) { +void StyleLayer::applyStyleProperties<FillProperties>(const float z, const timestamp now, const ZoomHistory &zoomHistory) { properties.set<FillProperties>(); FillProperties &fill = properties.get<FillProperties>(); - applyStyleProperty(PropertyKey::FillAntialias, fill.antialias, z, now); - applyTransitionedStyleProperty(PropertyKey::FillOpacity, fill.opacity, z, now); - applyTransitionedStyleProperty(PropertyKey::FillColor, fill.fill_color, z, now); - applyTransitionedStyleProperty(PropertyKey::FillOutlineColor, fill.stroke_color, z, now); - applyTransitionedStyleProperty(PropertyKey::FillTranslateX, fill.translate[0], z, now); - applyTransitionedStyleProperty(PropertyKey::FillTranslateY, fill.translate[1], z, now); - applyStyleProperty(PropertyKey::FillTranslateAnchor, fill.translateAnchor, z, now); - applyStyleProperty(PropertyKey::FillImage, fill.image, z, now); + applyStyleProperty(PropertyKey::FillAntialias, fill.antialias, z, now, zoomHistory); + applyTransitionedStyleProperty(PropertyKey::FillOpacity, fill.opacity, z, now, zoomHistory); + applyTransitionedStyleProperty(PropertyKey::FillColor, fill.fill_color, z, now, zoomHistory); + applyTransitionedStyleProperty(PropertyKey::FillOutlineColor, fill.stroke_color, z, now, zoomHistory); + applyTransitionedStyleProperty(PropertyKey::FillTranslateX, fill.translate[0], z, now, zoomHistory); + applyTransitionedStyleProperty(PropertyKey::FillTranslateY, fill.translate[1], z, now, zoomHistory); + applyStyleProperty(PropertyKey::FillTranslateAnchor, fill.translateAnchor, z, now, zoomHistory); + applyStyleProperty(PropertyKey::FillImage, fill.image, z, now, zoomHistory); } template <> -void StyleLayer::applyStyleProperties<LineProperties>(const float z, const timestamp now) { +void StyleLayer::applyStyleProperties<LineProperties>(const float z, const timestamp now, const ZoomHistory &zoomHistory) { properties.set<LineProperties>(); LineProperties &line = properties.get<LineProperties>(); - applyTransitionedStyleProperty(PropertyKey::LineOpacity, line.opacity, z, now); - applyTransitionedStyleProperty(PropertyKey::LineColor, line.color, z, now); - applyTransitionedStyleProperty(PropertyKey::LineTranslateX, line.translate[0], z, now); - applyTransitionedStyleProperty(PropertyKey::LineTranslateY, line.translate[1], z, now); - applyStyleProperty(PropertyKey::LineTranslateAnchor, line.translateAnchor, z, now); - applyTransitionedStyleProperty(PropertyKey::LineWidth, line.width, z, now); - applyTransitionedStyleProperty(PropertyKey::LineGapWidth, line.gap_width, z, now); - applyTransitionedStyleProperty(PropertyKey::LineBlur, line.blur, z, now); - applyStyleProperty(PropertyKey::LineDashArray, line.dash_array, z, now); - applyStyleProperty(PropertyKey::LineImage, line.image, z, now); + applyTransitionedStyleProperty(PropertyKey::LineOpacity, line.opacity, z, now, zoomHistory); + applyTransitionedStyleProperty(PropertyKey::LineColor, line.color, z, now, zoomHistory); + applyTransitionedStyleProperty(PropertyKey::LineTranslateX, line.translate[0], z, now, zoomHistory); + applyTransitionedStyleProperty(PropertyKey::LineTranslateY, line.translate[1], z, now, zoomHistory); + applyStyleProperty(PropertyKey::LineTranslateAnchor, line.translateAnchor, z, now, zoomHistory); + applyTransitionedStyleProperty(PropertyKey::LineWidth, line.width, z, now, zoomHistory); + applyTransitionedStyleProperty(PropertyKey::LineGapWidth, line.gap_width, z, now, zoomHistory); + applyTransitionedStyleProperty(PropertyKey::LineBlur, line.blur, z, now, zoomHistory); + applyStyleProperty(PropertyKey::LineDashArray, line.dash_array, z, now, zoomHistory); + applyStyleProperty(PropertyKey::LineImage, line.image, z, now, zoomHistory); // for scaling dasharrays - applyStyleProperty(PropertyKey::LineWidth, line.dash_line_width, std::floor(z), now + 10000); + applyStyleProperty(PropertyKey::LineWidth, line.dash_line_width, std::floor(z), now + 10000, zoomHistory); } template <> -void StyleLayer::applyStyleProperties<SymbolProperties>(const float z, const timestamp now) { +void StyleLayer::applyStyleProperties<SymbolProperties>(const float z, const timestamp now, const ZoomHistory &zoomHistory) { properties.set<SymbolProperties>(); SymbolProperties &symbol = properties.get<SymbolProperties>(); - applyTransitionedStyleProperty(PropertyKey::IconOpacity, symbol.icon.opacity, z, now); - applyTransitionedStyleProperty(PropertyKey::IconRotate, symbol.icon.rotate, z, now); - applyTransitionedStyleProperty(PropertyKey::IconSize, symbol.icon.size, z, now); - applyTransitionedStyleProperty(PropertyKey::IconColor, symbol.icon.color, z, now); - applyTransitionedStyleProperty(PropertyKey::IconHaloColor, symbol.icon.halo_color, z, now); - applyTransitionedStyleProperty(PropertyKey::IconHaloWidth, symbol.icon.halo_width, z, now); - applyTransitionedStyleProperty(PropertyKey::IconHaloBlur, symbol.icon.halo_blur, z, now); - applyTransitionedStyleProperty(PropertyKey::IconTranslateX, symbol.icon.translate[0], z, now); - applyTransitionedStyleProperty(PropertyKey::IconTranslateY, symbol.icon.translate[1], z, now); - applyStyleProperty(PropertyKey::IconTranslateAnchor, symbol.icon.translate_anchor, z, now); - - applyTransitionedStyleProperty(PropertyKey::TextOpacity, symbol.text.opacity, z, now); - applyTransitionedStyleProperty(PropertyKey::TextSize, symbol.text.size, z, now); - applyTransitionedStyleProperty(PropertyKey::TextColor, symbol.text.color, z, now); - applyTransitionedStyleProperty(PropertyKey::TextHaloColor, symbol.text.halo_color, z, now); - applyTransitionedStyleProperty(PropertyKey::TextHaloWidth, symbol.text.halo_width, z, now); - applyTransitionedStyleProperty(PropertyKey::TextHaloBlur, symbol.text.halo_blur, z, now); - applyTransitionedStyleProperty(PropertyKey::TextTranslateX, symbol.text.translate[0], z, now); - applyTransitionedStyleProperty(PropertyKey::TextTranslateY, symbol.text.translate[1], z, now); - applyStyleProperty(PropertyKey::TextTranslateAnchor, symbol.text.translate_anchor, z, now); + applyTransitionedStyleProperty(PropertyKey::IconOpacity, symbol.icon.opacity, z, now, zoomHistory); + applyTransitionedStyleProperty(PropertyKey::IconRotate, symbol.icon.rotate, z, now, zoomHistory); + applyTransitionedStyleProperty(PropertyKey::IconSize, symbol.icon.size, z, now, zoomHistory); + applyTransitionedStyleProperty(PropertyKey::IconColor, symbol.icon.color, z, now, zoomHistory); + applyTransitionedStyleProperty(PropertyKey::IconHaloColor, symbol.icon.halo_color, z, now, zoomHistory); + applyTransitionedStyleProperty(PropertyKey::IconHaloWidth, symbol.icon.halo_width, z, now, zoomHistory); + applyTransitionedStyleProperty(PropertyKey::IconHaloBlur, symbol.icon.halo_blur, z, now, zoomHistory); + applyTransitionedStyleProperty(PropertyKey::IconTranslateX, symbol.icon.translate[0], z, now, zoomHistory); + applyTransitionedStyleProperty(PropertyKey::IconTranslateY, symbol.icon.translate[1], z, now, zoomHistory); + applyStyleProperty(PropertyKey::IconTranslateAnchor, symbol.icon.translate_anchor, z, now, zoomHistory); + + applyTransitionedStyleProperty(PropertyKey::TextOpacity, symbol.text.opacity, z, now, zoomHistory); + applyTransitionedStyleProperty(PropertyKey::TextSize, symbol.text.size, z, now, zoomHistory); + applyTransitionedStyleProperty(PropertyKey::TextColor, symbol.text.color, z, now, zoomHistory); + applyTransitionedStyleProperty(PropertyKey::TextHaloColor, symbol.text.halo_color, z, now, zoomHistory); + applyTransitionedStyleProperty(PropertyKey::TextHaloWidth, symbol.text.halo_width, z, now, zoomHistory); + applyTransitionedStyleProperty(PropertyKey::TextHaloBlur, symbol.text.halo_blur, z, now, zoomHistory); + applyTransitionedStyleProperty(PropertyKey::TextTranslateX, symbol.text.translate[0], z, now, zoomHistory); + applyTransitionedStyleProperty(PropertyKey::TextTranslateY, symbol.text.translate[1], z, now, zoomHistory); + applyStyleProperty(PropertyKey::TextTranslateAnchor, symbol.text.translate_anchor, z, now, zoomHistory); } template <> -void StyleLayer::applyStyleProperties<RasterProperties>(const float z, const timestamp now) { +void StyleLayer::applyStyleProperties<RasterProperties>(const float z, const timestamp now, const ZoomHistory &zoomHistory) { properties.set<RasterProperties>(); RasterProperties &raster = properties.get<RasterProperties>(); - applyTransitionedStyleProperty(PropertyKey::RasterOpacity, raster.opacity, z, now); - applyTransitionedStyleProperty(PropertyKey::RasterHueRotate, raster.hue_rotate, z, now); - applyTransitionedStyleProperty(PropertyKey::RasterBrightnessLow, raster.brightness[0], z, now); - applyTransitionedStyleProperty(PropertyKey::RasterBrightnessHigh, raster.brightness[1], z, now); - applyTransitionedStyleProperty(PropertyKey::RasterSaturation, raster.saturation, z, now); - applyTransitionedStyleProperty(PropertyKey::RasterContrast, raster.contrast, z, now); - applyTransitionedStyleProperty(PropertyKey::RasterFade, raster.fade, z, now); + applyTransitionedStyleProperty(PropertyKey::RasterOpacity, raster.opacity, z, now, zoomHistory); + applyTransitionedStyleProperty(PropertyKey::RasterHueRotate, raster.hue_rotate, z, now, zoomHistory); + applyTransitionedStyleProperty(PropertyKey::RasterBrightnessLow, raster.brightness[0], z, now, zoomHistory); + applyTransitionedStyleProperty(PropertyKey::RasterBrightnessHigh, raster.brightness[1], z, now, zoomHistory); + applyTransitionedStyleProperty(PropertyKey::RasterSaturation, raster.saturation, z, now, zoomHistory); + applyTransitionedStyleProperty(PropertyKey::RasterContrast, raster.contrast, z, now, zoomHistory); + applyTransitionedStyleProperty(PropertyKey::RasterFade, raster.fade, z, now, zoomHistory); } template <> -void StyleLayer::applyStyleProperties<BackgroundProperties>(const float z, const timestamp now) { +void StyleLayer::applyStyleProperties<BackgroundProperties>(const float z, const timestamp now, const ZoomHistory &zoomHistory) { properties.set<BackgroundProperties>(); BackgroundProperties &background = properties.get<BackgroundProperties>(); - applyTransitionedStyleProperty(PropertyKey::BackgroundOpacity, background.opacity, z, now); - applyTransitionedStyleProperty(PropertyKey::BackgroundColor, background.color, z, now); - applyStyleProperty(PropertyKey::BackgroundImage, background.image, z, now); + applyTransitionedStyleProperty(PropertyKey::BackgroundOpacity, background.opacity, z, now, zoomHistory); + applyTransitionedStyleProperty(PropertyKey::BackgroundColor, background.color, z, now, zoomHistory); + applyStyleProperty(PropertyKey::BackgroundImage, background.image, z, now, zoomHistory); } -void StyleLayer::updateProperties(float z, const timestamp now) { +void StyleLayer::updateProperties(float z, const timestamp now, ZoomHistory &zoomHistory) { cleanupAppliedStyleProperties(now); switch (type) { - case StyleLayerType::Fill: applyStyleProperties<FillProperties>(z, now); break; - case StyleLayerType::Line: applyStyleProperties<LineProperties>(z, now); break; - case StyleLayerType::Symbol: applyStyleProperties<SymbolProperties>(z, now); break; - case StyleLayerType::Raster: applyStyleProperties<RasterProperties>(z, now); break; - case StyleLayerType::Background: applyStyleProperties<BackgroundProperties>(z, now); break; + case StyleLayerType::Fill: applyStyleProperties<FillProperties>(z, now, zoomHistory); break; + case StyleLayerType::Line: applyStyleProperties<LineProperties>(z, now, zoomHistory); break; + case StyleLayerType::Symbol: applyStyleProperties<SymbolProperties>(z, now, zoomHistory); break; + case StyleLayerType::Raster: applyStyleProperties<RasterProperties>(z, now, zoomHistory); break; + case StyleLayerType::Background: applyStyleProperties<BackgroundProperties>(z, now, zoomHistory); break; default: properties.set<std::false_type>(); break; } } diff --git a/src/mbgl/style/style_layer.hpp b/src/mbgl/style/style_layer.hpp index 7cf661ca33..8531ad3a05 100644 --- a/src/mbgl/style/style_layer.hpp +++ b/src/mbgl/style/style_layer.hpp @@ -5,6 +5,7 @@ #include <mbgl/style/class_properties.hpp> #include <mbgl/style/style_properties.hpp> #include <mbgl/style/applied_class_properties.hpp> +#include <mbgl/style/zoom_history.hpp> #include <mbgl/util/ptr.hpp> @@ -35,7 +36,7 @@ public: // Updates the StyleProperties information in this layer by evaluating all // pending transitions and applied classes in order. - void updateProperties(float z, timestamp now); + void updateProperties(float z, timestamp now, ZoomHistory &zoomHistory); // Sets the list of classes and creates transitions to the currently applied values. void setClasses(const std::vector<std::string> &class_names, timestamp now, @@ -50,9 +51,9 @@ private: // Sets the properties of this object by evaluating all pending transitions and // aplied classes in order. - template <typename T> void applyStyleProperties(float z, timestamp now); - template <typename T> void applyStyleProperty(PropertyKey key, T &, float z, timestamp now); - template <typename T> void applyTransitionedStyleProperty(PropertyKey key, T &, float z, timestamp now); + template <typename T> void applyStyleProperties(float z, timestamp now, const ZoomHistory &zoomHistory); + template <typename T> void applyStyleProperty(PropertyKey key, T &, float z, timestamp now, const ZoomHistory &zoomHistory); + template <typename T> void applyTransitionedStyleProperty(PropertyKey key, T &, float z, timestamp now, const ZoomHistory &zoomHistory); // Removes all expired style transitions. void cleanupAppliedStyleProperties(timestamp now); diff --git a/src/mbgl/style/style_layer_group.cpp b/src/mbgl/style/style_layer_group.cpp index 0ca0fa0cce..5ca020ee74 100644 --- a/src/mbgl/style/style_layer_group.cpp +++ b/src/mbgl/style/style_layer_group.cpp @@ -11,10 +11,10 @@ void StyleLayerGroup::setClasses(const std::vector<std::string> &class_names, ti } } -void StyleLayerGroup::updateProperties(float z, timestamp t) { +void StyleLayerGroup::updateProperties(float z, timestamp t, ZoomHistory &zoomHistory) { for (const util::ptr<StyleLayer> &layer: layers) { if (layer) { - layer->updateProperties(z, t); + layer->updateProperties(z, t, zoomHistory); } } } diff --git a/src/mbgl/style/style_layer_group.hpp b/src/mbgl/style/style_layer_group.hpp index 1af6e23bd7..85cfcc6dd6 100644 --- a/src/mbgl/style/style_layer_group.hpp +++ b/src/mbgl/style/style_layer_group.hpp @@ -11,7 +11,7 @@ class StyleLayerGroup { public: void setClasses(const std::vector<std::string> &class_names, timestamp now, const PropertyTransition &defaultTransition); - void updateProperties(float z, timestamp t); + void updateProperties(float z, timestamp t, ZoomHistory &zoomHistory); bool hasTransitions() const; public: diff --git a/src/mbgl/style/style_parser.cpp b/src/mbgl/style/style_parser.cpp index f048b24bd4..3f1fc64dab 100644 --- a/src/mbgl/style/style_parser.cpp +++ b/src/mbgl/style/style_parser.cpp @@ -263,6 +263,52 @@ std::vector<float> StyleParser::parseFunctionArgument(JSVal value) { return std::get<1>(parseFloatArray(rvalue)); } +template <> +Faded<std::string> StyleParser::parseFunctionArgument(JSVal value) { + JSVal rvalue = replaceConstant(value); + if (rvalue.IsString()) { + Faded<std::string> parsed; + parsed.low = { value.GetString(), value.GetStringLength() }; + return parsed; + } else { + Log::Warning(Event::ParseStyle, "function argument must be a string"); + return {}; + } +} + +template <typename T> +std::tuple<bool, std::vector<std::pair<float, T>>> StyleParser::parseStops(JSVal value_stops) { + + if (!value_stops.IsArray()) { + Log::Warning(Event::ParseStyle, "stops function must specify a stops array"); + return std::tuple<bool, std::vector<std::pair<float, T>>> { false, {}}; + } + + std::vector<std::pair<float, T>> stops; + + for (rapidjson::SizeType i = 0; i < value_stops.Size(); ++i) { + JSVal stop = value_stops[i]; + if (stop.IsArray()) { + if (stop.Size() != 2) { + Log::Warning(Event::ParseStyle, "stop must have zoom level and value specification"); + return std::tuple<bool, std::vector<std::pair<float, T>>> { false, {}}; + } + + JSVal z = stop[rapidjson::SizeType(0)]; + if (!z.IsNumber()) { + Log::Warning(Event::ParseStyle, "zoom level in stop must be a number"); + return std::tuple<bool, std::vector<std::pair<float, T>>> { false, {}}; + } + + stops.emplace_back(z.GetDouble(), parseFunctionArgument<T>(stop[rapidjson::SizeType(1)])); + } else { + Log::Warning(Event::ParseStyle, "function argument must be a numeric value"); + return std::tuple<bool, std::vector<std::pair<float, T>>> { false, {}}; + } + } + return { true, stops }; +} + template <typename T> inline float defaultBaseValue() { return 1.75; } template <> inline float defaultBaseValue<Color>() { return 1.0; } @@ -284,47 +330,52 @@ std::tuple<bool, Function<T>> StyleParser::parseFunction(JSVal value) { } } - JSVal value_stops = value["stops"]; - if (!value_stops.IsArray()) { - Log::Warning(Event::ParseStyle, "stops function must specify a stops array"); + auto stops = parseStops<T>(value["stops"]); + + if (!std::get<0>(stops)) { return std::tuple<bool, Function<T>> { false, ConstantFunction<T>(T()) }; } - std::vector<std::pair<float, T>> stops; - for (rapidjson::SizeType i = 0; i < value_stops.Size(); ++i) { - JSVal stop = value_stops[i]; - if (stop.IsArray()) { - if (stop.Size() != 2) { - Log::Warning(Event::ParseStyle, "stop must have zoom level and value specification"); - return std::tuple<bool, Function<T>> { false, ConstantFunction<T>(T()) }; - } + return std::tuple<bool, Function<T>> { true, StopsFunction<T>(std::get<1>(stops), base) }; +} - JSVal z = stop[rapidjson::SizeType(0)]; - if (!z.IsNumber()) { - Log::Warning(Event::ParseStyle, "zoom level in stop must be a number"); - return std::tuple<bool, Function<T>> { false, ConstantFunction<T>(T()) }; - } +template <typename T> inline timestamp defaultDurationValue() { return 300_milliseconds; } - stops.emplace_back(z.GetDouble(), parseFunctionArgument<T>(stop[rapidjson::SizeType(1)])); +template <typename T> +std::tuple<bool, FadedStopsFunction<T>> StyleParser::parseFadedStopsFunction(JSVal value) { + if (!value.HasMember("stops")) { + Log::Warning(Event::ParseStyle, "function must specify a function type"); + return std::tuple<bool, FadedStopsFunction<T>> { false, {} }; + } + + timestamp duration = defaultDurationValue<T>(); + + if (value.HasMember("duration")) { + JSVal value_duration = value["duration"]; + if (value_duration.IsNumber()) { + float duration_ = value_duration.GetDouble(); + duration = 1_millisecond * duration_; } else { - Log::Warning(Event::ParseStyle, "function argument must be a numeric value"); - return std::tuple<bool, Function<T>> { false, ConstantFunction<T>(T()) }; + Log::Warning(Event::ParseStyle, "duration must be numeric"); } } - return std::tuple<bool, Function<T>> { true, StopsFunction<T>(stops, base) }; -} + auto stops = parseStops<T>(value["stops"]); + + if (!std::get<0>(stops)) { + return std::tuple<bool, FadedStopsFunction<T>> { false, {} }; + } + return std::tuple<bool, FadedStopsFunction<T>> { true, { std::get<1>(stops), duration } }; +} template <typename T> bool StyleParser::setProperty(JSVal value, const char *property_name, PropertyKey key, ClassProperties &klass) { - bool parsed; - T result; - std::tie(parsed, result) = parseProperty<T>(value, property_name); - if (parsed) { - klass.set(key, result); + auto res = parseProperty<T>(value, property_name); + if (std::get<0>(res)) { + klass.set(key, std::get<1>(res)); } - return parsed; + return std::get<0>(res); } template<typename T> @@ -430,6 +481,19 @@ template<> std::tuple<bool, Function<std::vector<float>>> StyleParser::parseProp } } +template<> std::tuple<bool, FadedStopsFunction<Faded<std::string>>> StyleParser::parseProperty(JSVal value, const char *property_name) { + if (value.IsObject()) { + return parseFadedStopsFunction<Faded<std::string>>(value); + } else if (value.IsString()) { + Faded<std::string> parsed; + parsed.low = { value.GetString(), value.GetStringLength() }; + return std::tuple<bool, FadedStopsFunction<Faded<std::string>>> { true, parsed }; + } else { + Log::Warning(Event::ParseStyle, "value of '%s' must be string or a string function", property_name); + return std::tuple<bool, FadedStopsFunction<Faded<std::string>>> { false, {} }; + } +} + template <typename T> bool StyleParser::parseOptionalProperty(const char *property_name, const std::vector<PropertyKey> &keys, ClassProperties &klass, JSVal value) { if (value.HasMember(property_name)) { @@ -573,7 +637,7 @@ void StyleParser::parsePaint(JSVal value, ClassProperties &klass) { parseOptionalProperty<Function<float>>("fill-translate", { Key::FillTranslateX, Key::FillTranslateY }, klass, value); parseOptionalProperty<PropertyTransition>("fill-translate-transition", Key::FillTranslate, klass, value); parseOptionalProperty<TranslateAnchorType>("fill-translate-anchor", Key::FillTranslateAnchor, klass, value); - parseOptionalProperty<std::string>("fill-image", Key::FillImage, klass, value); + parseOptionalProperty<FadedStopsFunction<Faded<std::string>>>("fill-image", Key::FillImage, klass, value); parseOptionalProperty<Function<float>>("line-opacity", Key::LineOpacity, klass, value); parseOptionalProperty<PropertyTransition>("line-opacity-transition", Key::LineOpacity, klass, value); diff --git a/src/mbgl/style/style_parser.hpp b/src/mbgl/style/style_parser.hpp index 42e22f9458..482fa0a00b 100644 --- a/src/mbgl/style/style_parser.hpp +++ b/src/mbgl/style/style_parser.hpp @@ -77,7 +77,11 @@ private: template <typename T> std::tuple<bool, Function<T>> parseFunction(JSVal value); template <typename T> + std::tuple<bool, FadedStopsFunction<T>> parseFadedStopsFunction(JSVal value); + template <typename T> T parseFunctionArgument(JSVal value); + template <typename T> + std::tuple<bool, std::vector<std::pair<float, T>>> parseStops(JSVal value); FilterExpression parseFilter(JSVal); diff --git a/src/mbgl/style/style_properties.hpp b/src/mbgl/style/style_properties.hpp index c5149b2d1c..db9e4c34c9 100644 --- a/src/mbgl/style/style_properties.hpp +++ b/src/mbgl/style/style_properties.hpp @@ -3,7 +3,7 @@ #include <mbgl/util/variant.hpp> #include <mbgl/style/types.hpp> -#include <mbgl/style/function_properties.hpp> +#include <mbgl/style/fadedfunction_properties.hpp> #include <array> #include <string> @@ -21,7 +21,7 @@ struct FillProperties { Color stroke_color = {{ 0, 0, 0, -1 }}; std::array<float, 2> translate = {{ 0, 0 }}; TranslateAnchorType translateAnchor = TranslateAnchorType::Map; - std::string image; + Faded<std::string> image; inline bool isVisible() const { return opacity > 0 && (fill_color[3] > 0 || stroke_color[3] > 0); diff --git a/src/mbgl/style/types.hpp b/src/mbgl/style/types.hpp index c0b873dcd9..cd9c29d30a 100644 --- a/src/mbgl/style/types.hpp +++ b/src/mbgl/style/types.hpp @@ -11,6 +11,16 @@ namespace mbgl { // Stores a premultiplied color, with all four channels ranging from 0..1 typedef std::array<float, 4> Color; + +template <typename T> +struct Faded { + T low; + float lowScale; + T high; + float highScale; + float t; +}; + // ------------------------------------------------------------------------------------------------- enum class StyleLayerType : uint8_t { diff --git a/src/mbgl/style/zoom_history.hpp b/src/mbgl/style/zoom_history.hpp new file mode 100644 index 0000000000..7031068624 --- /dev/null +++ b/src/mbgl/style/zoom_history.hpp @@ -0,0 +1,39 @@ +#ifndef MBGL_STYLE_ZOOM_HISTORY +#define MBGL_STYLE_ZOOM_HISTORY + +#include <mbgl/util/time.hpp> + +#include <cmath> + +namespace mbgl { + +struct ZoomHistory { + float lastZoom; + float lastIntegerZoom; + timestamp lastIntegerZoomTime; + bool first = true; + + void update(float z, timestamp now) { + if (first) { + first = false; + + lastIntegerZoom = std::floor(z); + lastIntegerZoomTime = 0; + lastZoom = z; + } + + if (std::floor(lastZoom) < std::floor(z)) { + lastIntegerZoom = std::floor(z); + lastIntegerZoomTime = now; + + } else if (std::floor(lastZoom) > std::floor(z)) { + lastIntegerZoom = std::floor(z + 1); + lastIntegerZoomTime = now; + } + + lastZoom = z; + } +}; +} + +#endif |