diff options
author | Ansis Brammanis <brammanis@gmail.com> | 2015-02-10 15:21:36 -0800 |
---|---|---|
committer | Ansis Brammanis <brammanis@gmail.com> | 2015-02-10 15:21:36 -0800 |
commit | b53b24a6bca870e9b4b72ba94f5feaf8fb4a73cf (patch) | |
tree | ce3a0503f099dee777b8b9e1900d407172cc83c9 /src | |
parent | 8e459c2a73e7dcdb4cf660cfe61d5c945d7a2513 (diff) | |
parent | c3d41828b6d95fa959088d1c37bb5c17fbc1e8c3 (diff) | |
download | qtlocation-mapboxgl-b53b24a6bca870e9b4b72ba94f5feaf8fb4a73cf.tar.gz |
Merge remote-tracking branch 'origin/master' into line-label-density
Diffstat (limited to 'src')
28 files changed, 643 insertions, 389 deletions
diff --git a/src/mbgl/map/tile_parser.cpp b/src/mbgl/map/tile_parser.cpp index c3e7a8244b..6118d90a10 100644 --- a/src/mbgl/map/tile_parser.cpp +++ b/src/mbgl/map/tile_parser.cpp @@ -161,8 +161,7 @@ void TileParser::applyLayoutProperties<SymbolProperties>(StyleBucket &bucket_des applyLayoutProperty(PropertyKey::IconPadding, bucket_desc.layout, symbol.icon.padding, z); applyLayoutProperty(PropertyKey::IconRotate, bucket_desc.layout, symbol.icon.rotate, z); applyLayoutProperty(PropertyKey::IconKeepUpright, bucket_desc.layout, symbol.icon.keep_upright, z); - applyLayoutProperty(PropertyKey::IconOffsetX, bucket_desc.layout, symbol.icon.offset[0], z); - applyLayoutProperty(PropertyKey::IconOffsetY, bucket_desc.layout, symbol.icon.offset[1], z); + applyLayoutProperty(PropertyKey::IconOffset, bucket_desc.layout, symbol.icon.offset, z); applyLayoutProperty(PropertyKey::TextRotationAlignment, bucket_desc.layout, symbol.text.rotation_alignment, z); applyLayoutProperty(PropertyKey::TextField, bucket_desc.layout, symbol.text.field, z); @@ -180,8 +179,7 @@ void TileParser::applyLayoutProperties<SymbolProperties>(StyleBucket &bucket_des applyLayoutProperty(PropertyKey::TextAnchor, bucket_desc.layout, symbol.text.anchor, z); applyLayoutProperty(PropertyKey::TextKeepUpright, bucket_desc.layout, symbol.text.keep_upright, z); applyLayoutProperty(PropertyKey::TextTransform, bucket_desc.layout, symbol.text.transform, z); - applyLayoutProperty(PropertyKey::TextOffsetX, bucket_desc.layout, symbol.text.offset[0], z); - applyLayoutProperty(PropertyKey::TextOffsetY, bucket_desc.layout, symbol.text.offset[1], z); + applyLayoutProperty(PropertyKey::TextOffset, bucket_desc.layout, symbol.text.offset, z); applyLayoutProperty(PropertyKey::TextAllowOverlap, bucket_desc.layout, symbol.text.allow_overlap, z); } diff --git a/src/mbgl/renderer/painter.cpp b/src/mbgl/renderer/painter.cpp index 3f30e6d0f5..116ae3ad2f 100644 --- a/src/mbgl/renderer/painter.cpp +++ b/src/mbgl/renderer/painter.cpp @@ -231,7 +231,7 @@ void Painter::render(const Style& style, const std::set<util::ptr<StyleSource>>& drawClippingMasks(sources); - recordZoom(time, state.getNormalizedZoom()); + frameHistory.record(time, state.getNormalizedZoom()); // Actually render the layers if (debug::renderTree) { std::cout << "{" << std::endl; indent++; } @@ -375,39 +375,58 @@ void Painter::renderTileLayer(const Tile& tile, util::ptr<StyleLayer> layer_desc void Painter::renderBackground(util::ptr<StyleLayer> layer_desc) { const BackgroundProperties& properties = layer_desc->getProperties<BackgroundProperties>(); - if (properties.image.size()) { + if (properties.image.to.size()) { if ((properties.opacity >= 1.0f) != (pass == RenderPass::Opaque)) return; - SpriteAtlasPosition imagePos = spriteAtlas.getPosition(properties.image, true); + SpriteAtlasPosition imagePosA = spriteAtlas.getPosition(properties.image.from, true); + SpriteAtlasPosition imagePosB = spriteAtlas.getPosition(properties.image.to, true); float zoomFraction = state.getZoomFraction(); useProgram(patternShader->program); patternShader->u_matrix = identityMatrix; - patternShader->u_pattern_tl = imagePos.tl; - patternShader->u_pattern_br = imagePos.br; - patternShader->u_mix = zoomFraction; + patternShader->u_pattern_tl_a = imagePosA.tl; + patternShader->u_pattern_br_a = imagePosA.br; + patternShader->u_pattern_tl_b = imagePosB.tl; + patternShader->u_pattern_br_b = imagePosB.br; + patternShader->u_mix = properties.image.t; patternShader->u_opacity = properties.opacity; - std::array<float, 2> size = imagePos.size; double lon, lat; state.getLonLat(lon, lat); std::array<float, 2> center = state.locationCoordinate(lon, lat); float scale = 1 / std::pow(2, zoomFraction); - mat3 matrix; - matrix::identity(matrix); - matrix::scale(matrix, matrix, - 1.0f / size[0], - 1.0f / size[1]); - matrix::translate(matrix, matrix, - std::fmod(center[0] * 512, size[0]), - std::fmod(center[1] * 512, size[1])); - matrix::rotate(matrix, matrix, -state.getAngle()); - matrix::scale(matrix, matrix, + std::array<float, 2> sizeA = imagePosA.size; + mat3 matrixA; + matrix::identity(matrixA); + matrix::scale(matrixA, matrixA, + 1.0f / (sizeA[0] * properties.image.fromScale), + 1.0f / (sizeA[1] * properties.image.fromScale)); + matrix::translate(matrixA, matrixA, + std::fmod(center[0] * 512, sizeA[0] * properties.image.fromScale), + std::fmod(center[1] * 512, sizeA[1] * properties.image.fromScale)); + matrix::rotate(matrixA, matrixA, -state.getAngle()); + matrix::scale(matrixA, matrixA, scale * state.getWidth() / 2, -scale * state.getHeight() / 2); - patternShader->u_patternmatrix = matrix; + + std::array<float, 2> sizeB = imagePosB.size; + mat3 matrixB; + matrix::identity(matrixB); + matrix::scale(matrixB, matrixB, + 1.0f / (sizeB[0] * properties.image.toScale), + 1.0f / (sizeB[1] * properties.image.toScale)); + matrix::translate(matrixB, matrixB, + std::fmod(center[0] * 512, sizeB[0] * properties.image.toScale), + std::fmod(center[1] * 512, sizeB[1] * properties.image.toScale)); + matrix::rotate(matrixB, matrixB, -state.getAngle()); + matrix::scale(matrixB, matrixB, + scale * state.getWidth() / 2, + -scale * state.getHeight() / 2); + + patternShader->u_patternmatrix_a = matrixA; + patternShader->u_patternmatrix_b = matrixB; backgroundBuffer.bind(); patternShader->bind(0); @@ -459,26 +478,3 @@ mat4 Painter::translatedMatrix(const mat4& matrix, const std::array<float, 2> &t return vtxMatrix; } } - -void Painter::recordZoom(const std::chrono::steady_clock::time_point 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 bbce588642..f38a9f0559 100644 --- a/src/mbgl/renderer/painter.hpp +++ b/src/mbgl/renderer/painter.hpp @@ -140,7 +140,6 @@ private: mat4 translatedMatrix(const mat4& matrix, const std::array<float, 2> &translation, const Tile::ID &id, TranslateAnchorType anchor); void prepareTile(const Tile& tile); - void recordZoom(const std::chrono::steady_clock::time_point time, const float zoom); template <typename BucketProperties, typename StyleProperties> void renderSDF(SymbolBucket &bucket, @@ -193,10 +192,6 @@ private: RenderPass pass = RenderPass::Opaque; const float strata_epsilon = 1.0f / (1 << 16); - int lastIntegerZoom; - std::chrono::steady_clock::time_point lastIntegerZoomTime = std::chrono::steady_clock::time_point::min(); - float lastZoom = -1; - public: FrameHistory frameHistory; diff --git a/src/mbgl/renderer/painter_fill.cpp b/src/mbgl/renderer/painter_fill.cpp index 45de66201c..9cfe26222b 100644 --- a/src/mbgl/renderer/painter_fill.cpp +++ b/src/mbgl/renderer/painter_fill.cpp @@ -33,13 +33,13 @@ 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.from.size(); bool outline = properties.antialias && !pattern && properties.stroke_color != properties.fill_color; bool fringeline = properties.antialias && !pattern && properties.stroke_color == properties.fill_color; // Because we're drawing top-to-bottom, and we update the stencil mask - // below, we have to draw the outline first (!) + // befrom, we have to draw the outline first (!) if (outline && pass == RenderPass::Translucent) { useProgram(outlineShader->program); outlineShader->u_matrix = vtxMatrix; @@ -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.from, true); + const SpriteAtlasPosition posB = spriteAtlas.getPosition(properties.image.to, true); float factor = 8.0 / std::pow(2, state.getIntegerZoom() - id.z); - float mix; - std::chrono::steady_clock::duration duration = std::chrono::milliseconds(300); - const float fraction = std::fmod(float(state.getZoom()), 1.0f); - float t = std::min(static_cast<float>((std::chrono::steady_clock::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.fromScale), + 1.0f / (posA.size[1] * factor * properties.image.fromScale)); + mat3 patternMatrixB; + matrix::identity(patternMatrixB); + matrix::scale(patternMatrixB, patternMatrixB, + 1.0f / (posB.size[0] * factor * properties.image.toScale), + 1.0f / (posB.size[1] * factor * properties.image.toScale)); 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/renderer/painter_line.cpp b/src/mbgl/renderer/painter_line.cpp index 1f69a05511..a66da1fcd6 100644 --- a/src/mbgl/renderer/painter_line.cpp +++ b/src/mbgl/renderer/painter_line.cpp @@ -70,11 +70,7 @@ void Painter::renderLine(LineBucket& bucket, util::ptr<StyleLayer> layer_desc, c bucket.drawPoints(*linejoinShader); } - std::chrono::steady_clock::duration duration = std::chrono::milliseconds(300); - const float fraction = std::fmod(float(state.getZoom()), 1.0f); - float t = std::min(static_cast<float>(std::chrono::duration<float>(std::chrono::steady_clock::now() - lastIntegerZoomTime) / duration), 1.0f); - - if (properties.dash_array.size()) { + if (properties.dash_array.from.size()) { useProgram(linesdfShader->program); @@ -85,46 +81,31 @@ void Painter::renderLine(LineBucket& bucket, util::ptr<StyleLayer> layer_desc, c linesdfShader->u_blur = blur; linesdfShader->u_color = color; - LinePatternPos pos = lineAtlas.getDashPosition(properties.dash_array, bucket.properties.cap == CapType::Round); + LinePatternPos posA = lineAtlas.getDashPosition(properties.dash_array.from, bucket.properties.cap == CapType::Round); + LinePatternPos posB = lineAtlas.getDashPosition(properties.dash_array.to, bucket.properties.cap == CapType::Round); lineAtlas.bind(); float patternratio = std::pow(2.0, std::floor(std::log2(state.getScale())) - id.z) / 8.0; - float scaleX = patternratio / pos.width / properties.dash_line_width; - float scaleY = -pos.height / 2.0; - - 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; + float scaleXA = patternratio / posA.width / properties.dash_line_width / properties.dash_array.fromScale; + float scaleYA = -posA.height / 2.0; + float scaleXB = patternratio / posB.width / properties.dash_line_width / properties.dash_array.toScale; + float scaleYB = -posB.height / 2.0; + + linesdfShader->u_patternscale_a = {{ scaleXA, scaleYA }}; + linesdfShader->u_tex_y_a = posA.y; + linesdfShader->u_patternscale_b = {{ scaleXB, scaleYB }}; + linesdfShader->u_tex_y_b = posB.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; + linesdfShader->u_sdfgamma = lineAtlas.width / (properties.dash_line_width * std::min(posA.width, posB.width) * 256.0 * state.getPixelRatio()) / 2; + linesdfShader->u_mix = properties.dash_array.t; bucket.drawLineSDF(*linesdfShader); - } else if (properties.image.size()) { - SpriteAtlasPosition imagePos = spriteAtlas.getPosition(properties.image, true); + } else if (properties.image.from.size()) { + SpriteAtlasPosition imagePosA = spriteAtlas.getPosition(properties.image.from, true); + SpriteAtlasPosition imagePosB = spriteAtlas.getPosition(properties.image.to, true); float factor = 8.0 / std::pow(2, state.getIntegerZoom() - id.z); - 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); @@ -134,10 +115,13 @@ void Painter::renderLine(LineBucket& bucket, util::ptr<StyleLayer> layer_desc, c linepatternShader->u_ratio = ratio; linepatternShader->u_blur = blur; - linepatternShader->u_pattern_size = {{imagePos.size[0] * factor, imagePos.size[1]}}; - linepatternShader->u_pattern_tl = imagePos.tl; - linepatternShader->u_pattern_br = imagePos.br; - linepatternShader->u_fade = fade; + linepatternShader->u_pattern_size_a = {{imagePosA.size[0] * factor * properties.image.fromScale, imagePosA.size[1]}}; + linepatternShader->u_pattern_tl_a = imagePosA.tl; + linepatternShader->u_pattern_br_a = imagePosA.br; + linepatternShader->u_pattern_size_b = {{imagePosB.size[0] * factor * properties.image.toScale, imagePosB.size[1]}}; + linepatternShader->u_pattern_tl_b = imagePosB.tl; + linepatternShader->u_pattern_br_b = imagePosB.br; + linepatternShader->u_fade = properties.image.t; linepatternShader->u_opacity = properties.opacity; MBGL_CHECK_ERROR(glActiveTexture(GL_TEXTURE0)); diff --git a/src/mbgl/shader/linepattern.fragment.glsl b/src/mbgl/shader/linepattern.fragment.glsl index 45be7c8c2f..08feff4396 100644 --- a/src/mbgl/shader/linepattern.fragment.glsl +++ b/src/mbgl/shader/linepattern.fragment.glsl @@ -2,9 +2,12 @@ uniform vec2 u_linewidth; uniform float u_point; uniform float u_blur; -uniform vec2 u_pattern_size; -uniform vec2 u_pattern_tl; -uniform vec2 u_pattern_br; +uniform vec2 u_pattern_size_a; +uniform vec2 u_pattern_tl_a; +uniform vec2 u_pattern_br_a; +uniform vec2 u_pattern_size_b; +uniform vec2 u_pattern_tl_b; +uniform vec2 u_pattern_br_b; uniform float u_fade; uniform float u_opacity; @@ -24,13 +27,14 @@ 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 x = mod(v_linesofar / u_pattern_size.x, 1.0); - float y = 0.5 + (v_normal.y * u_linewidth.s / u_pattern_size.y); - vec2 pos = mix(u_pattern_tl, u_pattern_br, vec2(x, y)); - float x2 = mod(x * 2.0, 1.0); - vec2 pos2 = mix(u_pattern_tl, u_pattern_br, vec2(x2, y)); + float x_a = mod(v_linesofar / u_pattern_size_a.x, 1.0); + float y_a = 0.5 + (v_normal.y * u_linewidth.s / u_pattern_size_a.y); + vec2 pos_a = mix(u_pattern_tl_a, u_pattern_br_a, vec2(x_a, y_a)); + float x_b = mod(v_linesofar / u_pattern_size_b.x, 1.0); + float y_b = 0.5 + (v_normal.y * u_linewidth.s / u_pattern_size_b.y); + vec2 pos_b = mix(u_pattern_tl_b, u_pattern_br_b, vec2(x_b, y_b)); - vec4 color = texture2D(u_image, pos) * (1.0 - u_fade) + u_fade * texture2D(u_image, pos2); + vec4 color = mix(texture2D(u_image, pos_a), texture2D(u_image, pos_b), u_fade); alpha *= u_opacity; diff --git a/src/mbgl/shader/linepattern_shader.hpp b/src/mbgl/shader/linepattern_shader.hpp index 388cff17d2..16d9ff8be7 100644 --- a/src/mbgl/shader/linepattern_shader.hpp +++ b/src/mbgl/shader/linepattern_shader.hpp @@ -15,9 +15,12 @@ public: UniformMatrix<4> u_matrix = {"u_matrix", *this}; UniformMatrix<4> u_exmatrix = {"u_exmatrix", *this}; Uniform<std::array<float, 2>> u_linewidth = {"u_linewidth", *this}; - Uniform<std::array<float, 2>> u_pattern_size = {"u_pattern_size", *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_size_a = {"u_pattern_size_a", *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_size_b = {"u_pattern_size_b", *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_ratio = {"u_ratio", *this}; Uniform<float> u_point = {"u_point", *this}; Uniform<float> u_blur = {"u_blur", *this}; 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/function_properties.cpp b/src/mbgl/style/function_properties.cpp index 81b1c85c72..1ac2863a7c 100644 --- a/src/mbgl/style/function_properties.cpp +++ b/src/mbgl/style/function_properties.cpp @@ -13,7 +13,18 @@ template <> inline bool defaultStopsValue() { return true; } template <> inline float defaultStopsValue() { return 1.0f; } template <> inline Color defaultStopsValue() { return {{ 0, 0, 0, 1 }}; } template <> inline std::vector<float> defaultStopsValue() { return {{ 1, 0 }}; } +template <> inline std::array<float, 2> defaultStopsValue() { return {{ 0, 0 }}; } +template <> inline std:: string defaultStopsValue() { return {}; } +template <> inline TranslateAnchorType defaultStopsValue() { return {}; }; +template <> inline RotateAnchorType defaultStopsValue() { return {}; }; +template <> inline CapType defaultStopsValue() { return {}; }; +template <> inline JoinType defaultStopsValue() { return {}; }; +template <> inline PlacementType defaultStopsValue() { return {}; }; +template <> inline TextAnchorType defaultStopsValue() { return {}; }; +template <> inline TextJustifyType defaultStopsValue() { return {}; }; +template <> inline TextTransformType defaultStopsValue() { return {}; }; +template <> inline RotationAlignmentType defaultStopsValue() { return {}; }; template <typename T> T StopsFunction<T>::evaluate(float z) const { @@ -66,5 +77,16 @@ template bool StopsFunction<bool>::evaluate(float z) const; template float StopsFunction<float>::evaluate(float z) const; template Color StopsFunction<Color>::evaluate(float z) const; template std::vector<float> StopsFunction<std::vector<float>>::evaluate(float z) const; +template std::array<float, 2> StopsFunction<std::array<float, 2>>::evaluate(float z) const; +template std::string StopsFunction<std::string>::evaluate(float z) const; +template TranslateAnchorType StopsFunction<TranslateAnchorType>::evaluate(float z) const; +template RotateAnchorType StopsFunction<RotateAnchorType>::evaluate(float z) const; +template CapType StopsFunction<CapType>::evaluate(float z) const; +template JoinType StopsFunction<JoinType>::evaluate(float z) const; +template PlacementType StopsFunction<PlacementType>::evaluate(float z) const; +template TextAnchorType StopsFunction<TextAnchorType>::evaluate(float z) const; +template TextJustifyType StopsFunction<TextJustifyType>::evaluate(float z) const; +template TextTransformType StopsFunction<TextTransformType>::evaluate(float z) const; +template RotationAlignmentType StopsFunction<RotationAlignmentType>::evaluate(float z) const; } diff --git a/src/mbgl/style/piecewisefunction_properties.cpp b/src/mbgl/style/piecewisefunction_properties.cpp new file mode 100644 index 0000000000..72ed0b8f73 --- /dev/null +++ b/src/mbgl/style/piecewisefunction_properties.cpp @@ -0,0 +1,52 @@ +#include <mbgl/style/piecewisefunction_properties.hpp> +#include <mbgl/style/types.hpp> + +#include <cmath> + +namespace mbgl { + +template <typename T> +size_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 PiecewiseConstantFunction<T>::evaluate(float z, const ZoomHistory &zh) const { + T result; + + float fraction = std::fmod(z, 1.0f); + float t = std::min((std::chrono::steady_clock::now() - zh.lastIntegerZoomTime) / duration, 1.0f); + float fromScale = 1.0f; + float toScale = 1.0f; + size_t from, to; + + if (z > zh.lastIntegerZoom) { + result.t = fraction + (1.0f - fraction) * t; + from = getBiggestStopLessThan(values, z - 1.0f); + to = getBiggestStopLessThan(values, z); + fromScale *= 2.0f; + + } else { + result.t = 1 - (1 - t) * fraction; + to = getBiggestStopLessThan(values, z); + from = getBiggestStopLessThan(values, z + 1.0f); + fromScale /= 2.0f; + } + + + result.from = values[from].second.to; + result.to = values[to].second.to; + result.fromScale = fromScale; + result.toScale = toScale; + return result; +} + +template Faded<std::string> PiecewiseConstantFunction<Faded<std::string>>::evaluate(float z, const ZoomHistory &zoomHistory) const; +template Faded<std::vector<float>> PiecewiseConstantFunction<Faded<std::vector<float>>>::evaluate(float z, const ZoomHistory &zoomHistory) const; + +} diff --git a/src/mbgl/style/piecewisefunction_properties.hpp b/src/mbgl/style/piecewisefunction_properties.hpp new file mode 100644 index 0000000000..0440655ba5 --- /dev/null +++ b/src/mbgl/style/piecewisefunction_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 PiecewiseConstantFunction { + inline PiecewiseConstantFunction(const std::vector<std::pair<float, T>> &values_, std::chrono::duration<float> duration_) : values(values_), duration(duration_) {} + inline PiecewiseConstantFunction(T &value, std::chrono::duration<float> duration_) : values({{ 0, value }}), duration(duration_) {} + inline PiecewiseConstantFunction() : values(), duration(std::chrono::milliseconds(300)) {} + T evaluate(float z, const ZoomHistory &zoomHistory) const; + +private: + const std::vector<std::pair<float, T>> values; + const std::chrono::duration<float> duration; +}; + +} + +#endif diff --git a/src/mbgl/style/property_fallback.cpp b/src/mbgl/style/property_fallback.cpp index 5fc3ce1f04..2827fd6149 100644 --- a/src/mbgl/style/property_fallback.cpp +++ b/src/mbgl/style/property_fallback.cpp @@ -9,14 +9,12 @@ const std::map<PropertyKey, PropertyValue> PropertyFallbackValue::properties = { { PropertyKey::FillOpacity, defaultStyleProperties<FillProperties>().opacity }, { PropertyKey::FillColor, defaultStyleProperties<FillProperties>().fill_color }, // no FillOutlineColor on purpose. - { PropertyKey::FillTranslateX, defaultStyleProperties<FillProperties>().translate[0] }, - { PropertyKey::FillTranslateY, defaultStyleProperties<FillProperties>().translate[1] }, + { PropertyKey::FillTranslate, defaultStyleProperties<FillProperties>().translate }, { PropertyKey::FillTranslateAnchor, defaultStyleProperties<FillProperties>().translateAnchor }, { PropertyKey::LineOpacity, defaultStyleProperties<LineProperties>().opacity }, { PropertyKey::LineColor, defaultStyleProperties<LineProperties>().color }, - { PropertyKey::LineTranslateX, defaultStyleProperties<LineProperties>().translate[0] }, - { PropertyKey::LineTranslateY, defaultStyleProperties<LineProperties>().translate[1] }, + { PropertyKey::LineTranslate, defaultStyleProperties<LineProperties>().translate }, { PropertyKey::LineTranslateAnchor, defaultStyleProperties<LineProperties>().translateAnchor }, { PropertyKey::LineWidth, defaultStyleProperties<LineProperties>().width }, { PropertyKey::LineGapWidth, defaultStyleProperties<LineProperties>().gap_width }, @@ -29,8 +27,7 @@ const std::map<PropertyKey, PropertyValue> PropertyFallbackValue::properties = { { PropertyKey::IconHaloColor, defaultStyleProperties<SymbolProperties>().icon.halo_color }, { PropertyKey::IconHaloWidth, defaultStyleProperties<SymbolProperties>().icon.halo_width }, { PropertyKey::IconHaloBlur, defaultStyleProperties<SymbolProperties>().icon.halo_blur }, - { PropertyKey::IconTranslateX, defaultStyleProperties<SymbolProperties>().icon.translate[0] }, - { PropertyKey::IconTranslateY, defaultStyleProperties<SymbolProperties>().icon.translate[1] }, + { PropertyKey::IconTranslate, defaultStyleProperties<SymbolProperties>().icon.translate }, { PropertyKey::IconTranslateAnchor, defaultStyleProperties<SymbolProperties>().icon.translate_anchor }, { PropertyKey::TextOpacity, defaultStyleProperties<SymbolProperties>().text.opacity }, @@ -39,8 +36,7 @@ const std::map<PropertyKey, PropertyValue> PropertyFallbackValue::properties = { { PropertyKey::TextHaloColor, defaultStyleProperties<SymbolProperties>().text.halo_color }, { PropertyKey::TextHaloWidth, defaultStyleProperties<SymbolProperties>().text.halo_width }, { PropertyKey::TextHaloBlur, defaultStyleProperties<SymbolProperties>().text.halo_blur }, - { PropertyKey::TextTranslateX, defaultStyleProperties<SymbolProperties>().text.translate[0] }, - { PropertyKey::TextTranslateY, defaultStyleProperties<SymbolProperties>().text.translate[1] }, + { PropertyKey::TextTranslate, defaultStyleProperties<SymbolProperties>().text.translate }, { PropertyKey::TextTranslateAnchor, defaultStyleProperties<SymbolProperties>().text.translate_anchor }, { PropertyKey::RasterOpacity, defaultStyleProperties<RasterProperties>().opacity }, @@ -72,8 +68,7 @@ const std::map<PropertyKey, PropertyValue> PropertyFallbackValue::properties = { { PropertyKey::IconRotate, defaultLayoutProperties<StyleBucketSymbol>().icon.rotate }, { PropertyKey::IconPadding, defaultLayoutProperties<StyleBucketSymbol>().icon.padding }, { PropertyKey::IconKeepUpright, defaultLayoutProperties<StyleBucketSymbol>().icon.keep_upright }, - { PropertyKey::IconOffsetX, defaultLayoutProperties<StyleBucketSymbol>().icon.offset[0] }, - { PropertyKey::IconOffsetY, defaultLayoutProperties<StyleBucketSymbol>().icon.offset[1] }, + { PropertyKey::IconOffset, defaultLayoutProperties<StyleBucketSymbol>().icon.offset }, { PropertyKey::TextRotationAlignment, defaultLayoutProperties<StyleBucketSymbol>().text.rotation_alignment }, { PropertyKey::TextField, defaultLayoutProperties<StyleBucketSymbol>().text.field }, @@ -89,8 +84,7 @@ const std::map<PropertyKey, PropertyValue> PropertyFallbackValue::properties = { { PropertyKey::TextPadding, defaultLayoutProperties<StyleBucketSymbol>().text.padding }, { PropertyKey::TextKeepUpright, defaultLayoutProperties<StyleBucketSymbol>().text.keep_upright }, { PropertyKey::TextTransform, defaultLayoutProperties<StyleBucketSymbol>().text.transform }, - { PropertyKey::TextOffsetX, defaultLayoutProperties<StyleBucketSymbol>().text.offset[0] }, - { PropertyKey::TextOffsetY, defaultLayoutProperties<StyleBucketSymbol>().text.offset[1] }, + { PropertyKey::TextOffset, defaultLayoutProperties<StyleBucketSymbol>().text.offset }, { PropertyKey::TextAllowOverlap, defaultLayoutProperties<StyleBucketSymbol>().text.allow_overlap }, { PropertyKey::TextIgnorePlacement, defaultLayoutProperties<StyleBucketSymbol>().text.ignore_placement }, { PropertyKey::TextOptional, defaultLayoutProperties<StyleBucketSymbol>().text.optional }, diff --git a/src/mbgl/style/property_key.hpp b/src/mbgl/style/property_key.hpp index f10607a7af..dfe82e4bb0 100644 --- a/src/mbgl/style/property_key.hpp +++ b/src/mbgl/style/property_key.hpp @@ -9,16 +9,12 @@ enum class PropertyKey { FillColor, FillOutlineColor, FillTranslate, // for transitions only - FillTranslateX, - FillTranslateY, FillTranslateAnchor, FillImage, LineOpacity, LineColor, LineTranslate, // for transitions only - LineTranslateX, - LineTranslateY, LineTranslateAnchor, LineWidth, LineGapWidth, @@ -41,9 +37,7 @@ enum class PropertyKey { IconHaloColor, IconHaloWidth, IconHaloBlur, - IconTranslate, // for transitions only - IconTranslateX, - IconTranslateY, + IconTranslate, IconTranslateAnchor, IconAllowOverlap, @@ -52,11 +46,10 @@ enum class PropertyKey { IconRotationAlignment, IconMaxSize, IconImage, + IconOffset, IconPadding, IconRotate, IconKeepUpright, - IconOffsetX, - IconOffsetY, TextOpacity, TextSize, @@ -64,9 +57,7 @@ enum class PropertyKey { TextHaloColor, TextHaloWidth, TextHaloBlur, - TextTranslate, // for transitions only - TextTranslateX, - TextTranslateY, + TextTranslate, TextTranslateAnchor, TextRotationAlignment, @@ -85,8 +76,7 @@ enum class PropertyKey { TextAnchor, TextKeepUpright, TextTransform, - TextOffsetX, - TextOffsetY, + TextOffset, TextAllowOverlap, RasterOpacity, diff --git a/src/mbgl/style/property_value.hpp b/src/mbgl/style/property_value.hpp index ff5a2f8685..fbc3f3bd6a 100644 --- a/src/mbgl/style/property_value.hpp +++ b/src/mbgl/style/property_value.hpp @@ -3,29 +3,32 @@ #include <mbgl/util/variant.hpp> #include <mbgl/style/function_properties.hpp> +#include <mbgl/style/piecewisefunction_properties.hpp> #include <mbgl/style/types.hpp> #include <vector> +#include <array> namespace mbgl { typedef mapbox::util::variant< - std::string, - TranslateAnchorType, - RotateAnchorType, - bool, - CapType, - JoinType, + Function<std::string>, + Function<TranslateAnchorType>, + Function<RotateAnchorType>, + Function<CapType>, + Function<JoinType>, VisibilityType, - PlacementType, - RotationAlignmentType, - TextTransformType, - TextJustifyType, - TextAnchorType, + Function<PlacementType>, + Function<RotationAlignmentType>, + Function<TextTransformType>, + Function<TextJustifyType>, + Function<TextAnchorType>, + Function<std::array<float, 2>>, Function<bool>, Function<float>, Function<Color>, - Function<std::vector<float>> + PiecewiseConstantFunction<Faded<std::vector<float>>>, + PiecewiseConstantFunction<Faded<std::string>> > PropertyValue; } diff --git a/src/mbgl/style/style.cpp b/src/mbgl/style/style.cpp index 01781afe3c..45217950f6 100644 --- a/src/mbgl/style/style.cpp +++ b/src/mbgl/style/style.cpp @@ -28,8 +28,10 @@ Style::~Style() {} void Style::updateProperties(float z, std::chrono::steady_clock::time_point 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 751a91be62..4de827a38c 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/uv.hpp> #include <mbgl/util/ptr.hpp> @@ -50,6 +51,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 3b82d7f94a..1a4354be27 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 PiecewiseConstantFunction<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 std::chrono::steady_clock::time_point now) { +void StyleLayer::applyStyleProperty(PropertyKey key, T &target, const float z, const std::chrono::steady_clock::time_point 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 std::chrono::steady_clock::time_point now) { +void StyleLayer::applyTransitionedStyleProperty(PropertyKey key, T &target, const float z, const std::chrono::steady_clock::time_point 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,91 @@ void StyleLayer::applyTransitionedStyleProperty(PropertyKey key, T &target, cons } template <> -void StyleLayer::applyStyleProperties<FillProperties>(const float z, const std::chrono::steady_clock::time_point now) { +void StyleLayer::applyStyleProperties<FillProperties>(const float z, const std::chrono::steady_clock::time_point 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::FillTranslate, fill.translate, 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 std::chrono::steady_clock::time_point now) { +void StyleLayer::applyStyleProperties<LineProperties>(const float z, const std::chrono::steady_clock::time_point 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::LineTranslate, line.translate, 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), std::chrono::steady_clock::time_point::max()); + applyStyleProperty(PropertyKey::LineWidth, line.dash_line_width, std::floor(z), std::chrono::steady_clock::time_point::max(), zoomHistory); } template <> -void StyleLayer::applyStyleProperties<SymbolProperties>(const float z, const std::chrono::steady_clock::time_point now) { +void StyleLayer::applyStyleProperties<SymbolProperties>(const float z, const std::chrono::steady_clock::time_point 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::IconTranslate, symbol.icon.translate, 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::TextTranslate, symbol.text.translate, z, now, zoomHistory); + applyStyleProperty(PropertyKey::TextTranslateAnchor, symbol.text.translate_anchor, z, now, zoomHistory); } template <> -void StyleLayer::applyStyleProperties<RasterProperties>(const float z, const std::chrono::steady_clock::time_point now) { +void StyleLayer::applyStyleProperties<RasterProperties>(const float z, const std::chrono::steady_clock::time_point 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 std::chrono::steady_clock::time_point now) { +void StyleLayer::applyStyleProperties<BackgroundProperties>(const float z, const std::chrono::steady_clock::time_point 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 std::chrono::steady_clock::time_point now) { +void StyleLayer::updateProperties(float z, const std::chrono::steady_clock::time_point 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 b6cfe779c7..69af1dc230 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> @@ -36,7 +37,7 @@ public: // Updates the StyleProperties information in this layer by evaluating all // pending transitions and applied classes in order. - void updateProperties(float z, std::chrono::steady_clock::time_point now); + void updateProperties(float z, std::chrono::steady_clock::time_point 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, std::chrono::steady_clock::time_point now, @@ -51,9 +52,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, std::chrono::steady_clock::time_point now); - template <typename T> void applyStyleProperty(PropertyKey key, T &, float z, std::chrono::steady_clock::time_point now); - template <typename T> void applyTransitionedStyleProperty(PropertyKey key, T &, float z, std::chrono::steady_clock::time_point now); + template <typename T> void applyStyleProperties(float z, std::chrono::steady_clock::time_point now, const ZoomHistory &zoomHistory); + template <typename T> void applyStyleProperty(PropertyKey key, T &, float z, std::chrono::steady_clock::time_point now, const ZoomHistory &zoomHistory); + template <typename T> void applyTransitionedStyleProperty(PropertyKey key, T &, float z, std::chrono::steady_clock::time_point now, const ZoomHistory &zoomHistory); // Removes all expired style transitions. void cleanupAppliedStyleProperties(std::chrono::steady_clock::time_point now); diff --git a/src/mbgl/style/style_layer_group.cpp b/src/mbgl/style/style_layer_group.cpp index 3f1a4a5111..f57ec5cc7b 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, st } } -void StyleLayerGroup::updateProperties(float z, std::chrono::steady_clock::time_point now) { +void StyleLayerGroup::updateProperties(float z, std::chrono::steady_clock::time_point now, ZoomHistory &zoomHistory) { for (const util::ptr<StyleLayer> &layer: layers) { if (layer) { - layer->updateProperties(z, now); + layer->updateProperties(z, now, zoomHistory); } } } diff --git a/src/mbgl/style/style_layer_group.hpp b/src/mbgl/style/style_layer_group.hpp index 3f5a20073d..79b75a55e9 100644 --- a/src/mbgl/style/style_layer_group.hpp +++ b/src/mbgl/style/style_layer_group.hpp @@ -12,7 +12,7 @@ class StyleLayerGroup { public: void setClasses(const std::vector<std::string> &class_names, std::chrono::steady_clock::time_point now, const PropertyTransition &defaultTransition); - void updateProperties(float z, std::chrono::steady_clock::time_point now); + void updateProperties(float z, std::chrono::steady_clock::time_point now, ZoomHistory &zoomHistory); bool hasTransitions() const; public: diff --git a/src/mbgl/style/style_parser.cpp b/src/mbgl/style/style_parser.cpp index 15aedd8ead..af6a84492d 100644 --- a/src/mbgl/style/style_parser.cpp +++ b/src/mbgl/style/style_parser.cpp @@ -209,7 +209,7 @@ Color parseColor(JSVal value) { css_color.a}}; } -std::tuple<bool,std::vector<float>> parseFloatArray(JSVal value) { +std::tuple<bool,std::vector<float>> StyleParser::parseFloatArray(JSVal value) { if (!value.IsArray()) { Log::Warning(Event::ParseStyle, "dasharray value must be an array of numbers"); return std::tuple<bool, std::vector<float>> { false, std::vector<float>() }; @@ -217,7 +217,7 @@ std::tuple<bool,std::vector<float>> parseFloatArray(JSVal value) { std::vector<float> vec; for (rapidjson::SizeType i = 0; i < value.Size(); ++i) { - JSVal part = value[i]; + JSVal part = replaceConstant(value[i]); if (!part.IsNumber()) { Log::Warning(Event::ParseStyle, "dasharray value must be an array of numbers"); return std::tuple<bool, std::vector<float>> { false, std::vector<float>() }; @@ -228,46 +228,101 @@ std::tuple<bool,std::vector<float>> parseFloatArray(JSVal value) { } template <> -bool StyleParser::parseFunctionArgument(JSVal value) { - JSVal rvalue = replaceConstant(value); - if (rvalue.IsBool()) { - return rvalue.GetBool(); - } else if (rvalue.IsNumber()) { - return rvalue.GetDouble(); +std::tuple<bool, std::array<float, 2>> StyleParser::parseProperty(JSVal value, const char*) { + if (value.IsArray() && value.Size() == 2 && + value[rapidjson::SizeType(0)].IsNumber() && + value[rapidjson::SizeType(1)].IsNumber()) { + + float first = value[rapidjson::SizeType(0)].GetDouble(); + float second = value[rapidjson::SizeType(1)].GetDouble(); + return std::tuple<bool, std::array<float, 2>> { false, {{ first, second }} }; } else { - Log::Warning(Event::ParseStyle, "function argument must be a boolean or numeric value"); - return false; + Log::Warning(Event::ParseStyle, "value must be array of two numbers"); + return std::tuple<bool, std::array<float, 2>> { false, {{ 0.0f, 0.0f }} }; } } template <> -float StyleParser::parseFunctionArgument(JSVal value) { +std::tuple<bool, float> StyleParser::parseProperty(JSVal value, const char* property_name) { JSVal rvalue = replaceConstant(value); if (rvalue.IsNumber()) { - return rvalue.GetDouble(); + return std::tuple<bool, float> { true, rvalue.GetDouble() }; } else { - Log::Warning(Event::ParseStyle, "function argument must be a numeric value"); - return 0.0f; + Log::Warning(Event::ParseStyle, "value of '%s' must be a number, or a number function", property_name); + return std::tuple<bool, float> { false, 0.0f }; } } template <> -Color StyleParser::parseFunctionArgument(JSVal value) { +std::tuple<bool, Color> StyleParser::parseProperty(JSVal value, const char*) { + JSVal rvalue = replaceConstant(value); + return std::tuple<bool, Color> { true, parseColor(rvalue) }; +} + +template <> +std::tuple<bool, Faded<std::vector<float>>> StyleParser::parseProperty(JSVal value, const char*) { + Faded<std::vector<float>> parsed; JSVal rvalue = replaceConstant(value); - return parseColor(rvalue); + parsed.to = std::get<1>(parseFloatArray(rvalue)); + return std::tuple<bool, Faded<std::vector<float>>> { true, parsed }; } template <> -std::vector<float> StyleParser::parseFunctionArgument(JSVal value) { +std::tuple<bool, Faded<std::string>> StyleParser::parseProperty(JSVal value, const char *property_name) { JSVal rvalue = replaceConstant(value); - return std::get<1>(parseFloatArray(rvalue)); + Faded<std::string> parsed; + if (rvalue.IsString()) { + parsed.to = { value.GetString(), value.GetStringLength() }; + return std::tuple<bool, Faded<std::string>> { true, parsed }; + } else { + Log::Warning(Event::ParseStyle, "value of '%s' must be a string, or a string function", property_name); + return std::tuple<bool, Faded<std::string>> { false, parsed }; + } +} + +template <typename T> +std::tuple<bool, std::vector<std::pair<float, T>>> StyleParser::parseStops(JSVal value_stops, const char *property_name) { + + 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(), std::get<1>(parseProperty<T>(replaceConstant(stop[rapidjson::SizeType(1)]), property_name))); + } else { + Log::Warning(Event::ParseStyle, "function argument must be a numeric value"); + return std::tuple<bool, std::vector<std::pair<float, T>>> { false, {}}; + } + } + return std::tuple<bool, std::vector<std::pair<float, T>>>(true, stops); } template <typename T> inline float defaultBaseValue() { return 1.75; } template <> inline float defaultBaseValue<Color>() { return 1.0; } template <typename T> -std::tuple<bool, Function<T>> StyleParser::parseFunction(JSVal value) { +std::tuple<bool, Function<T>> StyleParser::parseFunction(JSVal value, const char *property_name) { + + if (!value.IsObject()) { + return std::tuple<bool, Function<T>> { true, ConstantFunction<T>(std::get<1>(parseProperty<T>(value, property_name))) }; + } + if (!value.HasMember("stops")) { Log::Warning(Event::ParseStyle, "function must specify a function type"); return std::tuple<bool, Function<T>> { false, ConstantFunction<T>(T()) }; @@ -284,47 +339,47 @@ 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"], property_name); + + 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> +std::tuple<bool, PiecewiseConstantFunction<T>> StyleParser::parsePiecewiseConstantFunction(JSVal value, std::chrono::steady_clock::duration duration) { + if (!value.HasMember("stops")) { + Log::Warning(Event::ParseStyle, "function must specify a function type"); + return std::tuple<bool, PiecewiseConstantFunction<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, Function<T>> { false, ConstantFunction<T>(T()) }; - } + auto stops = parseStops<T>(value["stops"], ""); + + if (!std::get<0>(stops)) { + return std::tuple<bool, PiecewiseConstantFunction<T>> { false, {} }; } - return std::tuple<bool, Function<T>> { true, StopsFunction<T>(stops, base) }; + return std::tuple<bool, PiecewiseConstantFunction<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 std::get<0>(res); +} + +template <typename T> +bool StyleParser::setProperty(JSVal value, const char *property_name, PropertyKey key, ClassProperties &klass, JSVal transition) { + auto res = parseProperty<T>(value, property_name, transition); + if (std::get<0>(res)) { + klass.set(key, std::get<1>(res)); } - return parsed; + return std::get<0>(res); } template<typename T> @@ -348,6 +403,21 @@ bool StyleParser::parseOptionalProperty(const char *property_name, PropertyKey k } } +template<typename T> +bool StyleParser::parseOptionalProperty(const char *property_name, PropertyKey key, ClassProperties &klass, JSVal value, const char *transition_name) { + if (!value.HasMember(property_name)) { + return false; + } else { + if (value.HasMember(transition_name)) { + return setProperty<T>(replaceConstant(value[property_name]), property_name, key, klass, value[transition_name]); + } else { + JSVal val = JSVal(rapidjson::kObjectType); + return setProperty<T>(replaceConstant(value[property_name]), property_name, key, klass, val); + } + } +} + + template<> std::tuple<bool, std::string> StyleParser::parseProperty(JSVal value, const char *property_name) { if (!value.IsString()) { Log::Warning(Event::ParseStyle, "value of '%s' must be a string", property_name); @@ -465,72 +535,99 @@ template<> std::tuple<bool, PropertyTransition> StyleParser::parseProperty(JSVal return std::tuple<bool, PropertyTransition> { true, std::move(transition) }; } +template<> std::tuple<bool, Function<std::array<float, 2>>> StyleParser::parseProperty(JSVal value, const char *property_name) { + return parseFunction<std::array<float, 2>>(value, property_name); +} + +template<> std::tuple<bool, Function<std::string>> StyleParser::parseProperty(JSVal value, const char *property_name) { + return parseFunction<std::string>(value, property_name); +} + +template<> std::tuple<bool, Function<TranslateAnchorType>> StyleParser::parseProperty(JSVal value, const char *property_name) { + return parseFunction<TranslateAnchorType>(value, property_name); +} + +template<> std::tuple<bool, Function<RotateAnchorType>> StyleParser::parseProperty(JSVal value, const char *property_name) { + return parseFunction<RotateAnchorType>(value, property_name); +} + +template<> std::tuple<bool, Function<CapType>> StyleParser::parseProperty(JSVal value, const char *property_name) { + return parseFunction<CapType>(value, property_name); +} + +template<> std::tuple<bool, Function<JoinType>> StyleParser::parseProperty(JSVal value, const char *property_name) { + return parseFunction<JoinType>(value, property_name); +} + +template<> std::tuple<bool, Function<PlacementType>> StyleParser::parseProperty(JSVal value, const char *property_name) { + return parseFunction<PlacementType>(value, property_name); +} + +template<> std::tuple<bool, Function<TextAnchorType>> StyleParser::parseProperty(JSVal value, const char *property_name) { + return parseFunction<TextAnchorType>(value, property_name); +} + +template<> std::tuple<bool, Function<TextJustifyType>> StyleParser::parseProperty(JSVal value, const char *property_name) { + return parseFunction<TextJustifyType>(value, property_name); +} + +template<> std::tuple<bool, Function<TextTransformType>> StyleParser::parseProperty(JSVal value, const char *property_name) { + return parseFunction<TextTransformType>(value, property_name); +} + +template<> std::tuple<bool, Function<RotationAlignmentType>> StyleParser::parseProperty(JSVal value, const char *property_name) { + return parseFunction<RotationAlignmentType>(value, property_name); +} + + template<> std::tuple<bool, Function<bool>> StyleParser::parseProperty(JSVal value, const char *property_name) { - if (value.IsObject()) { - return parseFunction<bool>(value); - } else if (value.IsNumber()) { - return std::tuple<bool, Function<bool>> { true, ConstantFunction<bool>(value.GetDouble()) }; - } else if (value.IsBool()) { - return std::tuple<bool, Function<bool>> { true, ConstantFunction<bool>(value.GetBool()) }; - } else { - Log::Warning(Event::ParseStyle, "value of '%s' must be convertible to boolean, or a boolean function", property_name); - return std::tuple<bool, Function<bool>> { false, ConstantFunction<bool>(false) }; - } + return parseFunction<bool>(value, property_name); } template<> std::tuple<bool, Function<float>> StyleParser::parseProperty(JSVal value, const char *property_name) { - if (value.IsObject()) { - return parseFunction<float>(value); - } else if (value.IsNumber()) { - return std::tuple<bool, Function<float>> { true, ConstantFunction<float>(value.GetDouble()) }; - } else if (value.IsBool()) { - return std::tuple<bool, Function<float>> { true, ConstantFunction<float>(value.GetBool()) }; - } else { - Log::Warning(Event::ParseStyle, "value of '%s' must be a number, or a number function", property_name); - return std::tuple<bool, Function<float>> { false, ConstantFunction<float>(0) }; - } + return parseFunction<float>(value, property_name); } template<> std::tuple<bool, Function<Color>> StyleParser::parseProperty(JSVal value, const char *property_name) { - if (value.IsObject()) { - return parseFunction<Color>(value); - } else if (value.IsString()) { - return std::tuple<bool, Function<Color>> { true, ConstantFunction<Color>(parseColor(value)) }; - } else { - Log::Warning(Event::ParseStyle, "value of '%s' must be a color, or a color function", property_name); - return std::tuple<bool, Function<Color>> { false, ConstantFunction<Color>(Color {{ 0, 0, 0, 0 }}) }; - } + return parseFunction<Color>(value, property_name); } -template<> std::tuple<bool, Function<std::vector<float>>> StyleParser::parseProperty(JSVal value, const char *property_name) { +template<> std::tuple<bool, PiecewiseConstantFunction<Faded<std::vector<float>>>> StyleParser::parseProperty(JSVal value, const char *property_name, JSVal transition) { + std::chrono::steady_clock::duration duration = std::chrono::milliseconds(300); + if (transition.HasMember("duration")) { + duration = std::chrono::milliseconds(transition["duration"].GetUint()); + } + if (value.IsObject()) { - return parseFunction<std::vector<float>>(value); + return parsePiecewiseConstantFunction<Faded<std::vector<float>>>(value, duration); } else if (value.IsArray()) { - std::tuple<bool, std::vector<float>> parsed = parseFloatArray(value); - return std::tuple<bool, Function<std::vector<float>>> { std::get<0>(parsed), ConstantFunction<std::vector<float>>(std::get<1>(parsed)) }; + Faded<std::vector<float>> parsed; + std::tuple<bool, std::vector<float>> floatarray = parseFloatArray(value); + parsed.to = std::get<1>(floatarray); + return std::tuple<bool, PiecewiseConstantFunction<Faded<std::vector<float>>>> { std::get<0>(floatarray), { parsed, duration } }; } else { Log::Warning(Event::ParseStyle, "value of '%s' must be an array of numbers, or a number array function", property_name); - return std::tuple<bool, Function<std::vector<float>>> { false, ConstantFunction<std::vector<float>>(std::vector<float>()) }; + return std::tuple<bool, PiecewiseConstantFunction<Faded<std::vector<float>>>> { 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)) { - JSVal rvalue = replaceConstant(value[property_name]); - if (!rvalue.IsArray()) { - Log::Warning(Event::ParseStyle, "array value must be an array"); - } +template<> std::tuple<bool, PiecewiseConstantFunction<Faded<std::string>>> StyleParser::parseProperty(JSVal value, const char *property_name, JSVal transition) { - if (rvalue.Size() != keys.size()) { - Log::Warning(Event::ParseStyle, "array value has unexpected number of elements"); - } + std::chrono::steady_clock::duration duration = std::chrono::milliseconds(300); + if (transition.HasMember("duration")) { + duration = std::chrono::milliseconds(transition["duration"].GetUint()); + } - for (uint16_t i = 0; i < keys.size(); i++) { - setProperty<T>(rvalue[(rapidjson::SizeType)i], property_name, keys[i], klass); - } + if (value.IsObject()) { + return parsePiecewiseConstantFunction<Faded<std::string>>(value, duration); + } else if (value.IsString()) { + Faded<std::string> parsed; + parsed.to = { value.GetString(), value.GetStringLength() }; + return std::tuple<bool, PiecewiseConstantFunction<Faded<std::string>>> { true, { parsed, duration } }; + } else { + Log::Warning(Event::ParseStyle, "value of '%s' must be string or a string function", property_name); + return std::tuple<bool, PiecewiseConstantFunction<Faded<std::string>>> { false, {} }; } - return true; } #pragma mark - Parse Layers @@ -654,26 +751,26 @@ void StyleParser::parsePaint(JSVal value, ClassProperties &klass) { parseOptionalProperty<PropertyTransition>("fill-color-transition", Key::FillColor, klass, value); parseOptionalProperty<Function<Color>>("fill-outline-color", Key::FillOutlineColor, klass, value); parseOptionalProperty<PropertyTransition>("fill-outline-color-transition", Key::FillOutlineColor, klass, value); - parseOptionalProperty<Function<float>>("fill-translate", { Key::FillTranslateX, Key::FillTranslateY }, klass, value); + parseOptionalProperty<Function<std::array<float, 2>>>("fill-translate", Key::FillTranslate, 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<Function<TranslateAnchorType>>("fill-translate-anchor", Key::FillTranslateAnchor, klass, value); + parseOptionalProperty<PiecewiseConstantFunction<Faded<std::string>>>("fill-image", Key::FillImage, klass, value, "fill-image-transition"); parseOptionalProperty<Function<float>>("line-opacity", Key::LineOpacity, klass, value); parseOptionalProperty<PropertyTransition>("line-opacity-transition", Key::LineOpacity, klass, value); parseOptionalProperty<Function<Color>>("line-color", Key::LineColor, klass, value); parseOptionalProperty<PropertyTransition>("line-color-transition", Key::LineColor, klass, value); - parseOptionalProperty<Function<float>>("line-translate", { Key::LineTranslateX, Key::LineTranslateY }, klass, value); + parseOptionalProperty<Function<std::array<float,2>>>("line-translate", Key::LineTranslate, klass, value); parseOptionalProperty<PropertyTransition>("line-translate-transition", Key::LineTranslate, klass, value); - parseOptionalProperty<TranslateAnchorType>("line-translate-anchor", Key::LineTranslateAnchor, klass, value); + parseOptionalProperty<Function<TranslateAnchorType>>("line-translate-anchor", Key::LineTranslateAnchor, klass, value); parseOptionalProperty<Function<float>>("line-width", Key::LineWidth, klass, value); parseOptionalProperty<PropertyTransition>("line-width-transition", Key::LineWidth, klass, value); parseOptionalProperty<Function<float>>("line-gap-width", Key::LineGapWidth, klass, value); parseOptionalProperty<PropertyTransition>("line-gap-width-transition", Key::LineGapWidth, klass, value); parseOptionalProperty<Function<float>>("line-blur", Key::LineBlur, klass, value); parseOptionalProperty<PropertyTransition>("line-blur-transition", Key::LineBlur, klass, value); - parseOptionalProperty<Function<std::vector<float>>>("line-dasharray", Key::LineDashArray, klass, value); - parseOptionalProperty<std::string>("line-image", Key::LineImage, klass, value); + parseOptionalProperty<PiecewiseConstantFunction<Faded<std::vector<float>>>>("line-dasharray", Key::LineDashArray, klass, value, "line-dasharray-transition"); + parseOptionalProperty<PiecewiseConstantFunction<Faded<std::string>>>("line-image", Key::LineImage, klass, value, "line-image-transition"); parseOptionalProperty<Function<float>>("icon-opacity", Key::IconOpacity, klass, value); parseOptionalProperty<PropertyTransition>("icon-opacity-transition", Key::IconOpacity, klass, value); @@ -688,9 +785,9 @@ void StyleParser::parsePaint(JSVal value, ClassProperties &klass) { parseOptionalProperty<PropertyTransition>("icon-halo-width-transition", Key::IconHaloWidth, klass, value); parseOptionalProperty<Function<float>>("icon-halo-blur", Key::IconHaloBlur, klass, value); parseOptionalProperty<PropertyTransition>("icon-halo-blur-transition", Key::IconHaloBlur, klass, value); - parseOptionalProperty<Function<float>>("icon-translate", { Key::IconTranslateX, Key::IconTranslateY }, klass, value); + parseOptionalProperty<Function<std::array<float, 2>>>("icon-translate", Key::IconTranslate, klass, value); parseOptionalProperty<PropertyTransition>("icon-translate-transition", Key::IconTranslate, klass, value); - parseOptionalProperty<TranslateAnchorType>("icon-translate-anchor", Key::IconTranslateAnchor, klass, value); + parseOptionalProperty<Function<TranslateAnchorType>>("icon-translate-anchor", Key::IconTranslateAnchor, klass, value); parseOptionalProperty<Function<float>>("text-opacity", Key::TextOpacity, klass, value); parseOptionalProperty<PropertyTransition>("text-opacity-transition", Key::TextOpacity, klass, value); @@ -704,15 +801,16 @@ void StyleParser::parsePaint(JSVal value, ClassProperties &klass) { parseOptionalProperty<PropertyTransition>("text-halo-width-transition", Key::TextHaloWidth, klass, value); parseOptionalProperty<Function<float>>("text-halo-blur", Key::TextHaloBlur, klass, value); parseOptionalProperty<PropertyTransition>("text-halo-blur-transition", Key::TextHaloBlur, klass, value); - parseOptionalProperty<Function<float>>("text-translate", { Key::TextTranslateX, Key::TextTranslateY }, klass, value); + parseOptionalProperty<Function<std::array<float, 2>>>("text-translate", Key::TextTranslate, klass, value); parseOptionalProperty<PropertyTransition>("text-translate-transition", Key::TextTranslate, klass, value); - parseOptionalProperty<TranslateAnchorType>("text-translate-anchor", Key::TextTranslateAnchor, klass, value); + parseOptionalProperty<Function<TranslateAnchorType>>("text-translate-anchor", Key::TextTranslateAnchor, klass, value); parseOptionalProperty<Function<float>>("raster-opacity", Key::RasterOpacity, klass, value); parseOptionalProperty<PropertyTransition>("raster-opacity-transition", Key::RasterOpacity, klass, value); parseOptionalProperty<Function<float>>("raster-hue-rotate", Key::RasterHueRotate, klass, value); parseOptionalProperty<PropertyTransition>("raster-hue-rotate-transition", Key::RasterHueRotate, klass, value); - parseOptionalProperty<Function<float>>("raster-brightness", { Key::RasterBrightnessLow, Key::RasterBrightnessHigh }, klass, value); + parseOptionalProperty<Function<float>>("raster-brightness-min", Key::RasterBrightnessLow, klass, value); + parseOptionalProperty<Function<float>>("raster-brightness-max", Key::RasterBrightnessHigh, klass, value); parseOptionalProperty<PropertyTransition>("raster-brightness-transition", Key::RasterBrightness, klass, value); parseOptionalProperty<Function<float>>("raster-saturation", Key::RasterSaturation, klass, value); parseOptionalProperty<PropertyTransition>("raster-saturation-transition", Key::RasterSaturation, klass, value); @@ -723,7 +821,7 @@ void StyleParser::parsePaint(JSVal value, ClassProperties &klass) { parseOptionalProperty<Function<float>>("background-opacity", Key::BackgroundOpacity, klass, value); parseOptionalProperty<Function<Color>>("background-color", Key::BackgroundColor, klass, value); - parseOptionalProperty<std::string>("background-image", Key::BackgroundImage, klass, value); + parseOptionalProperty<PiecewiseConstantFunction<Faded<std::string>>>("background-image", Key::BackgroundImage, klass, value, "background-image-transition"); } void StyleParser::parseLayout(JSVal value, util::ptr<StyleBucket> &bucket) { @@ -731,42 +829,42 @@ void StyleParser::parseLayout(JSVal value, util::ptr<StyleBucket> &bucket) { parseVisibility<VisibilityType>(*bucket, value); - parseOptionalProperty<CapType>("line-cap", Key::LineCap, bucket->layout, value); - parseOptionalProperty<JoinType>("line-join", Key::LineJoin, bucket->layout, value); + parseOptionalProperty<Function<CapType>>("line-cap", Key::LineCap, bucket->layout, value); + parseOptionalProperty<Function<JoinType>>("line-join", Key::LineJoin, bucket->layout, value); parseOptionalProperty<Function<float>>("line-miter-limit", Key::LineMiterLimit, bucket->layout, value); parseOptionalProperty<Function<float>>("line-round-limit", Key::LineRoundLimit, bucket->layout, value); - parseOptionalProperty<PlacementType>("symbol-placement", Key::SymbolPlacement, bucket->layout, value); + parseOptionalProperty<Function<PlacementType>>("symbol-placement", Key::SymbolPlacement, bucket->layout, value); parseOptionalProperty<Function<float>>("symbol-min-distance", Key::SymbolMinDistance, bucket->layout, value); - parseOptionalProperty<bool>("symbol-avoid-edges", Key::SymbolAvoidEdges, bucket->layout, value); - parseOptionalProperty<bool>("icon-allow-overlap", Key::IconAllowOverlap, bucket->layout, value); - parseOptionalProperty<bool>("icon-ignore-placement", Key::IconIgnorePlacement, bucket->layout, value); - parseOptionalProperty<bool>("icon-optional", Key::IconOptional, bucket->layout, value); - parseOptionalProperty<RotationAlignmentType>("icon-rotation-alignment", Key::IconRotationAlignment, bucket->layout, value); + parseOptionalProperty<Function<bool>>("symbol-avoid-edges", Key::SymbolAvoidEdges, bucket->layout, value); + parseOptionalProperty<Function<bool>>("icon-allow-overlap", Key::IconAllowOverlap, bucket->layout, value); + parseOptionalProperty<Function<bool>>("icon-ignore-placement", Key::IconIgnorePlacement, bucket->layout, value); + parseOptionalProperty<Function<bool>>("icon-optional", Key::IconOptional, bucket->layout, value); + parseOptionalProperty<Function<RotationAlignmentType>>("icon-rotation-alignment", Key::IconRotationAlignment, bucket->layout, value); parseOptionalProperty<Function<float>>("icon-max-size", Key::IconMaxSize, bucket->layout, value); - parseOptionalProperty<std::string>("icon-image", Key::IconImage, bucket->layout, value); + parseOptionalProperty<Function<std::string>>("icon-image", Key::IconImage, bucket->layout, value); parseOptionalProperty<Function<float>>("icon-rotate", Key::IconRotate, bucket->layout, value); parseOptionalProperty<Function<float>>("icon-padding", Key::IconPadding, bucket->layout, value); - parseOptionalProperty<bool>("icon-keep-upright", Key::IconKeepUpright, bucket->layout, value); - parseOptionalProperty<Function<float>>("icon-offset", { Key::IconOffsetX, Key::IconOffsetY }, bucket->layout, value); - parseOptionalProperty<RotationAlignmentType>("text-rotation-alignment", Key::TextRotationAlignment, bucket->layout, value); - parseOptionalProperty<std::string>("text-field", Key::TextField, bucket->layout, value); - parseOptionalProperty<std::string>("text-font", Key::TextFont, bucket->layout, value); + parseOptionalProperty<Function<bool>>("icon-keep-upright", Key::IconKeepUpright, bucket->layout, value); + parseOptionalProperty<Function<std::array<float, 2>>>("icon-offset", Key::IconOffset, bucket->layout, value); + parseOptionalProperty<Function<RotationAlignmentType>>("text-rotation-alignment", Key::TextRotationAlignment, bucket->layout, value); + parseOptionalProperty<Function<std::string>>("text-field", Key::TextField, bucket->layout, value); + parseOptionalProperty<Function<std::string>>("text-font", Key::TextFont, bucket->layout, value); parseOptionalProperty<Function<float>>("text-max-size", Key::TextMaxSize, bucket->layout, value); parseOptionalProperty<Function<float>>("text-max-width", Key::TextMaxWidth, bucket->layout, value); parseOptionalProperty<Function<float>>("text-line-height", Key::TextLineHeight, bucket->layout, value); parseOptionalProperty<Function<float>>("text-letter-spacing", Key::TextLetterSpacing, bucket->layout, value); - parseOptionalProperty<TextJustifyType>("text-justify", Key::TextJustify, bucket->layout, value); - parseOptionalProperty<TextAnchorType>("text-anchor", Key::TextAnchor, bucket->layout, value); + parseOptionalProperty<Function<TextJustifyType>>("text-justify", Key::TextJustify, bucket->layout, value); + parseOptionalProperty<Function<TextAnchorType>>("text-anchor", Key::TextAnchor, bucket->layout, value); parseOptionalProperty<Function<float>>("text-max-angle", Key::TextMaxAngle, bucket->layout, value); parseOptionalProperty<Function<float>>("text-rotate", Key::TextRotate, bucket->layout, value); parseOptionalProperty<Function<float>>("text-padding", Key::TextPadding, bucket->layout, value); - parseOptionalProperty<bool>("text-keep-upright", Key::TextKeepUpright, bucket->layout, value); - parseOptionalProperty<TextTransformType>("text-transform", Key::TextTransform, bucket->layout, value); - parseOptionalProperty<Function<float>>("text-offset", { Key::TextOffsetX, Key::TextOffsetY }, bucket->layout, value); - parseOptionalProperty<bool>("text-allow-overlap", Key::TextAllowOverlap, bucket->layout, value); - parseOptionalProperty<bool>("text-ignore-placement", Key::TextIgnorePlacement, bucket->layout, value); - parseOptionalProperty<bool>("text-optional", Key::TextOptional, bucket->layout, value); + parseOptionalProperty<Function<bool>>("text-keep-upright", Key::TextKeepUpright, bucket->layout, value); + parseOptionalProperty<Function<TextTransformType>>("text-transform", Key::TextTransform, bucket->layout, value); + parseOptionalProperty<Function<std::array<float, 2>>>("text-offset", Key::TextOffset, bucket->layout, value); + parseOptionalProperty<Function<bool>>("text-allow-overlap", Key::TextAllowOverlap, bucket->layout, value); + parseOptionalProperty<Function<bool>>("text-ignore-placement", Key::TextIgnorePlacement, bucket->layout, value); + parseOptionalProperty<Function<bool>>("text-optional", Key::TextOptional, bucket->layout, value); } diff --git a/src/mbgl/style/style_parser.hpp b/src/mbgl/style/style_parser.hpp index 24fd4292a0..736cb9e9fa 100644 --- a/src/mbgl/style/style_parser.hpp +++ b/src/mbgl/style/style_parser.hpp @@ -69,17 +69,25 @@ private: template <typename T> bool parseOptionalProperty(const char *property_name, PropertyKey key, ClassProperties &klass, JSVal value); template <typename T> - bool parseOptionalProperty(const char *property_name, const std::vector<PropertyKey> &keys, ClassProperties &klass, JSVal value); + bool parseOptionalProperty(const char *property_name, PropertyKey key, ClassProperties &klass, JSVal value, const char *transition_name); template <typename T> bool setProperty(JSVal value, const char *property_name, PropertyKey key, ClassProperties &klass); + template <typename T> + bool setProperty(JSVal value, const char *property_name, PropertyKey key, ClassProperties &klass, JSVal transition); template <typename T> std::tuple<bool, T> parseProperty(JSVal value, const char *property_name); + template <typename T> + std::tuple<bool, T> parseProperty(JSVal value, const char *property_name, JSVal transition); template <typename T> - std::tuple<bool, Function<T>> parseFunction(JSVal value); + std::tuple<bool, Function<T>> parseFunction(JSVal value, const char *); template <typename T> - T parseFunctionArgument(JSVal value); + std::tuple<bool, PiecewiseConstantFunction<T>> parsePiecewiseConstantFunction(JSVal value, std::chrono::steady_clock::duration duration); + template <typename T> + std::tuple<bool, std::vector<std::pair<float, T>>> parseStops(JSVal value, const char *property_name); + + std::tuple<bool,std::vector<float>> parseFloatArray(JSVal value); FilterExpression parseFilter(JSVal); diff --git a/src/mbgl/style/style_properties.hpp b/src/mbgl/style/style_properties.hpp index c5149b2d1c..f50722542d 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/piecewisefunction_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); @@ -37,9 +37,9 @@ struct LineProperties { float width = 1; float gap_width = 0; float blur = 0; - std::vector<float> dash_array; + Faded<std::vector<float>> dash_array; float dash_line_width = 1; - std::string image; + Faded<std::string> image; inline bool isVisible() const { return opacity > 0 && color[3] > 0 && width > 0; @@ -96,7 +96,7 @@ struct BackgroundProperties { inline BackgroundProperties() {} float opacity = 1.0f; Color color = {{ 0, 0, 0, 1 }}; - std::string image; + Faded<std::string> image; }; typedef mapbox::util::variant< diff --git a/src/mbgl/style/types.hpp b/src/mbgl/style/types.hpp index 6149270170..78938a2823 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 from; + float fromScale; + T to; + float toScale; + 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..2488687108 --- /dev/null +++ b/src/mbgl/style/zoom_history.hpp @@ -0,0 +1,38 @@ +#ifndef MBGL_STYLE_ZOOM_HISTORY +#define MBGL_STYLE_ZOOM_HISTORY + +#include <chrono> +#include <cmath> + +namespace mbgl { + +struct ZoomHistory { + float lastZoom; + float lastIntegerZoom; + std::chrono::steady_clock::time_point lastIntegerZoomTime; + bool first = true; + + void update(float z, std::chrono::steady_clock::time_point now) { + if (first) { + first = false; + + lastIntegerZoom = std::floor(z); + lastIntegerZoomTime = std::chrono::steady_clock::time_point(std::chrono::steady_clock::duration(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 diff --git a/src/mbgl/util/interpolate.hpp b/src/mbgl/util/interpolate.hpp index 952d7b9c10..55b1e2add4 100644 --- a/src/mbgl/util/interpolate.hpp +++ b/src/mbgl/util/interpolate.hpp @@ -4,6 +4,8 @@ #include <array> #include <vector> +#include <mbgl/style/types.hpp> + namespace mbgl { namespace util { @@ -22,10 +24,30 @@ inline std::array<T, 4> interpolate(const std::array<T, 4>& a, const std::array< }}; } -inline std::vector<float> interpolate(const std::vector<float> &a, const std::vector<float>, const double) { - return a; +template <typename T> +inline std::array<T, 2> interpolate(const std::array<T, 2>& a, const std::array<T, 2>& b, const double t) { + return {{ + interpolate(a[0], b[0], t), + interpolate(a[1], b[1], t) + }}; } +// fake interpolations that just return the first value +template<> inline bool interpolate(const bool a, const bool, const double) { return a; } +template<> inline std::vector<float> interpolate(const std::vector<float> a, const std::vector<float>, const double) { return a; } +template<> inline std::string interpolate(const std::string a, const std::string, const double) { return a; } +template<> inline TranslateAnchorType interpolate(const TranslateAnchorType a, const TranslateAnchorType, const double) { return a; } +template<> inline RotateAnchorType interpolate(const RotateAnchorType a, const RotateAnchorType, const double) { return a; } +template<> inline CapType interpolate(const CapType a, const CapType, const double) { return a; } +template<> inline JoinType interpolate(const JoinType a, const JoinType, const double) { return a; } +template<> inline PlacementType interpolate(const PlacementType a, const PlacementType, const double) { return a; } +template<> inline TextAnchorType interpolate(const TextAnchorType a, const TextAnchorType, const double) { return a; } +template<> inline TextJustifyType interpolate(const TextJustifyType a, const TextJustifyType, const double) { return a; } +template<> inline TextTransformType interpolate(const TextTransformType a, const TextTransformType, const double) { return a; } +template<> inline RotationAlignmentType interpolate(const RotationAlignmentType a, const RotationAlignmentType, const double) { return a; } + + + } } |