diff options
-rw-r--r-- | include/mbgl/geometry/sprite_atlas.hpp | 1 | ||||
-rw-r--r-- | include/mbgl/shader/pattern_shader.hpp | 24 | ||||
-rw-r--r-- | include/mbgl/util/mat3.hpp | 40 | ||||
-rw-r--r-- | src/renderer/painter_fill.cpp | 99 | ||||
-rw-r--r-- | src/shader/pattern.fragment.glsl | 11 | ||||
-rw-r--r-- | src/shader/pattern.vertex.glsl | 3 | ||||
-rw-r--r-- | src/shader/pattern_shader.cpp | 54 | ||||
-rw-r--r-- | src/util/mat3.cpp | 51 |
8 files changed, 181 insertions, 102 deletions
diff --git a/include/mbgl/geometry/sprite_atlas.hpp b/include/mbgl/geometry/sprite_atlas.hpp index dc2378c2fb..bc123abe13 100644 --- a/include/mbgl/geometry/sprite_atlas.hpp +++ b/include/mbgl/geometry/sprite_atlas.hpp @@ -49,6 +49,7 @@ public: inline float getHeight() const { return height; } inline float getTextureWidth() const { return width * pixelRatio; } inline float getTextureHeight() const { return height * pixelRatio; } + inline float getPixelRatio() const { return pixelRatio; } private: void allocate(); diff --git a/include/mbgl/shader/pattern_shader.hpp b/include/mbgl/shader/pattern_shader.hpp index b1b49b54df..e574b755dc 100644 --- a/include/mbgl/shader/pattern_shader.hpp +++ b/include/mbgl/shader/pattern_shader.hpp @@ -11,33 +11,33 @@ public: void bind(char *offset); - void setColor(const std::array<float, 4>& color); - void setOffset(const std::array<float, 2>& offset); - void setPatternSize(const std::array<float, 2>& pattern_size); void setPatternTopLeft(const std::array<float, 2>& pattern_tl); void setPatternBottomRight(const std::array<float, 2>& pattern_br); + void setOpacity(float opacity); + void setImage(int image); void setMix(float mix); + void setPatternMatrix(const std::array<float, 9> &patternmatrix); private: int32_t a_pos = -1; - std::array<float, 4> color = {{}}; - int32_t u_color = -1; - - std::array<float, 2> offset = {{}}; - int32_t u_offset = -1; - - std::array<float, 2> pattern_size = {{}}; - int32_t u_pattern_size = -1; - std::array<float, 2> pattern_tl = {{}}; int32_t u_pattern_tl = -1; std::array<float, 2> pattern_br = {{}}; int32_t u_pattern_br = -1; + float opacity = 0; + int32_t u_opacity = -1; + + int image = 0; + int32_t u_image = -1; + float mix = 0; int32_t u_mix = -1; + + std::array<float, 9> patternmatrix = {{}}; + int32_t u_patternmatrix = -1; }; } diff --git a/include/mbgl/util/mat3.hpp b/include/mbgl/util/mat3.hpp new file mode 100644 index 0000000000..d44b1435d3 --- /dev/null +++ b/include/mbgl/util/mat3.hpp @@ -0,0 +1,40 @@ +// This is an incomplete port of http://glmatrix.net/ +// +// Copyright (c) 2013 Brandon Jones, Colin MacKenzie IV +// +// This software is provided 'as-is', without any express or implied warranty. +// In no event will the authors be held liable for any damages arising from the +// use of this software. +// +// Permission is granted to anyone to use this software for any purpose, +// including commercial applications, and to alter it and redistribute it +// freely, subject to the following restrictions: +// +// 1. The origin of this software must not be misrepresented; you must not claim +// that you wrote the original software. If you use this software in a +// product, an acknowledgment in the product documentation would be +// appreciated but is not required. +// +// 2. Altered source versions must be plainly marked as such, and must not be +// misrepresented as being the original software. +// +// 3. This notice may not be removed or altered from any source distribution. + +#ifndef MBGL_UTIL_MAT3 +#define MBGL_UTIL_MAT3 + +#include <array> + +namespace mbgl { + +typedef std::array<float, 9> mat3; + +namespace matrix { + +void identity(mat3& out); +void scale(mat3& out, const mat3& a, float x, float y); + +} +} + +#endif diff --git a/src/renderer/painter_fill.cpp b/src/renderer/painter_fill.cpp index f99cc93bbf..fe08d4c2fa 100644 --- a/src/renderer/painter_fill.cpp +++ b/src/renderer/painter_fill.cpp @@ -6,6 +6,7 @@ #include <mbgl/map/sprite.hpp> #include <mbgl/geometry/sprite_atlas.hpp> #include <mbgl/util/std.hpp> +#include <mbgl/util/mat3.hpp> using namespace mbgl; @@ -28,13 +29,10 @@ void Painter::renderFill(FillBucket& bucket, const FillProperties& properties, c stroke_color[3] *= properties.opacity; } - bool outline = properties.antialias && properties.stroke_color != properties.fill_color; - bool fringeline = properties.antialias && properties.stroke_color == properties.fill_color; - if (fringeline) { - outline = true; - stroke_color = fill_color; - } + const bool pattern = properties.image.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 (!) @@ -52,66 +50,59 @@ void Painter::renderFill(FillBucket& bucket, const FillProperties& properties, c }}); depthRange(strata, 1.0f); bucket.drawVertices(*outlineShader); - } else if (fringeline) { - // // We're only drawing to the first seven bits (== support a maximum of - // // 127 overlapping polygons in one place before we get rendering errors). - // glStencilMask(0x3F); - // glClear(GL_STENCIL_BUFFER_BIT); - - // // Draw front facing triangles. Wherever the 0x80 bit is 1, we are - // // increasing the lower 7 bits by one if the triangle is a front-facing - // // triangle. This means that all visible polygons should be in CCW - // // orientation, while all holes (see below) are in CW orientation. - // glStencilFunc(GL_EQUAL, 0x80, 0x80); - - // // When we do a nonzero fill, we count the number of times a pixel is - // // covered by a counterclockwise polygon, and subtract the number of - // // times it is "uncovered" by a clockwise polygon. - // glStencilOp(GL_KEEP, GL_KEEP, GL_INCR_WRAP); } - if ((fill_color[3] >= 1.0f) == (pass == RenderPass::Opaque)) { + if (pattern) { + // Image fill. Sprite &sprite = *map.getSprite(); - if (properties.image.size() && sprite) { + if (pass == RenderPass::Translucent && sprite) { SpriteAtlas &spriteAtlas = *map.getSpriteAtlas(); - Rect<uint16_t> imagePos = spriteAtlas.getImage(properties.image, sprite); - - - float factor = 8.0 / std::pow(2, map.getState().getIntegerZoom() - id.z); - float mix = std::fmod(map.getState().getZoom(), 1.0); - - std::array<float, 2> imageSize = {{ - imagePos.w * factor, - imagePos.h * factor - } - }; - - std::array<float, 2> offset = {{ - (float)std::fmod(id.x * 4096, imageSize[0]), - (float)std::fmod(id.y * 4096, imageSize[1]) - } - }; + const Rect<uint16_t> pos = spriteAtlas.getImage(properties.image, sprite); + + // `repeating` indicates that the image will be used in a repeating pattern + // repeating pattern images are assumed to have a 1px padding that mirrors the opposite edge + // positions for repeating images are adjusted to exclude the edge + const int repeating = 1; + const std::array<float, 2> size {{ + float(pos.w) / spriteAtlas.getPixelRatio(), + float(pos.h) / spriteAtlas.getPixelRatio(), + }}; + const std::array<float, 2> tl {{ + (float(pos.x + repeating) / spriteAtlas.getWidth()), + (float(pos.y + repeating) / spriteAtlas.getHeight()), + }}; + const std::array<float, 2> br {{ + (float(pos.x + pos.w - 2 * repeating) / spriteAtlas.getWidth()), + (float(pos.y + pos.h - 2 * repeating) / spriteAtlas.getHeight()), + }}; + const float mix = std::fmod(float(map.getState().getZoom()), 1.0f); + + const float factor = 8.0 / std::pow(2, map.getState().getIntegerZoom() - id.z); + + mat3 patternMatrix; + matrix::identity(patternMatrix); + matrix::scale(patternMatrix, patternMatrix, 1.0f / (size[0] * factor), 1.0f / (size[1] * factor)); useProgram(patternShader->program); patternShader->setMatrix(vtxMatrix); - patternShader->setOffset(offset); - patternShader->setPatternSize(imageSize); - patternShader->setPatternTopLeft({{ - float(imagePos.x) / spriteAtlas.getWidth(), - float(imagePos.y) / spriteAtlas.getHeight(), - }}); - patternShader->setPatternBottomRight({{ - float(imagePos.x + imagePos.w) / spriteAtlas.getWidth(), - float(imagePos.y + imagePos.h) / spriteAtlas.getHeight(), - }}); - patternShader->setColor(fill_color); + patternShader->setPatternTopLeft(tl); + patternShader->setPatternBottomRight(br); + patternShader->setOpacity(properties.opacity); + patternShader->setImage(0); patternShader->setMix(mix); + patternShader->setPatternMatrix(patternMatrix); + + glActiveTexture(GL_TEXTURE0); spriteAtlas.bind(true); // Draw the actual triangles into the color & stencil buffer. - depthRange(strata + strata_epsilon, 1.0f); + depthRange(strata, 1.0f); bucket.drawElements(*patternShader); - } else { + } + } + else { + // No image fill. + if ((fill_color[3] >= 1.0f) == (pass == RenderPass::Opaque)) { // Only draw the fill when it's either opaque and we're drawing opaque // fragments or when it's translucent and we're drawing translucent // fragments diff --git a/src/shader/pattern.fragment.glsl b/src/shader/pattern.fragment.glsl index 850c7afaff..ba6aed3023 100644 --- a/src/shader/pattern.fragment.glsl +++ b/src/shader/pattern.fragment.glsl @@ -1,19 +1,15 @@ -uniform vec4 u_color; - -uniform vec2 u_offset; -uniform vec2 u_pattern_size; +uniform float u_opacity; uniform vec2 u_pattern_tl; uniform vec2 u_pattern_br; uniform float u_mix; - uniform sampler2D u_image; varying vec2 v_pos; void main() { - vec2 imagecoord = mod((v_pos + u_offset) / u_pattern_size, 1.0); + vec2 imagecoord = mod(v_pos, 1.0); vec2 pos = mix(u_pattern_tl, u_pattern_br, imagecoord); vec4 color1 = texture2D(u_image, pos); @@ -21,6 +17,5 @@ void main() { vec2 pos2 = mix(u_pattern_tl, u_pattern_br, imagecoord2); vec4 color2 = texture2D(u_image, pos2); - vec4 color = mix(color1, color2, u_mix); - gl_FragColor = color + u_color * (1.0 - color.a); + gl_FragColor = mix(color1, color2, u_mix) * u_opacity; } diff --git a/src/shader/pattern.vertex.glsl b/src/shader/pattern.vertex.glsl index eeee39930f..f2de884ead 100644 --- a/src/shader/pattern.vertex.glsl +++ b/src/shader/pattern.vertex.glsl @@ -1,10 +1,11 @@ uniform mat4 u_matrix; +uniform mat3 u_patternmatrix; attribute vec2 a_pos; varying vec2 v_pos; void main() { - v_pos = a_pos; gl_Position = u_matrix * vec4(a_pos, 0, 1); + v_pos = (u_patternmatrix * vec3(a_pos, 1)).xy; } diff --git a/src/shader/pattern_shader.cpp b/src/shader/pattern_shader.cpp index f3943b964e..ec604290a6 100644 --- a/src/shader/pattern_shader.cpp +++ b/src/shader/pattern_shader.cpp @@ -19,21 +19,21 @@ PatternShader::PatternShader() a_pos = glGetAttribLocation(program, "a_pos"); u_matrix = glGetUniformLocation(program, "u_matrix"); - u_color = glGetUniformLocation(program, "u_color"); - u_offset = glGetUniformLocation(program, "u_offset"); - u_pattern_size = glGetUniformLocation(program, "u_pattern_size"); u_pattern_tl = glGetUniformLocation(program, "u_pattern_tl"); u_pattern_br = glGetUniformLocation(program, "u_pattern_br"); + u_opacity = glGetUniformLocation(program, "u_opacity"); + u_image = glGetUniformLocation(program, "u_image"); u_mix = glGetUniformLocation(program, "u_mix"); + u_patternmatrix = glGetUniformLocation(program, "u_patternmatrix"); // fprintf(stderr, "PatternShader:\n"); // fprintf(stderr, " - u_matrix: %d\n", u_matrix); - // fprintf(stderr, " - u_color: %d\n", u_color); - // fprintf(stderr, " - u_offset: %d\n", u_offset); - // fprintf(stderr, " - u_pattern_size: %d\n", u_pattern_size); // fprintf(stderr, " - u_pattern_tl: %d\n", u_pattern_tl); // fprintf(stderr, " - u_pattern_br: %d\n", u_pattern_br); + // fprintf(stderr, " - u_opacity: %d\n", u_opacity); + // fprintf(stderr, " - u_image: %d\n", u_image); // fprintf(stderr, " - u_mix: %d\n", u_mix); + // fprintf(stderr, " - u_patternmatrix: %d\n", u_patternmatrix); } void PatternShader::bind(char *offset) { @@ -41,27 +41,6 @@ void PatternShader::bind(char *offset) { glVertexAttribPointer(a_pos, 2, GL_SHORT, false, 0, offset); } -void PatternShader::setColor(const std::array<float, 4>& new_color) { - if (color != new_color) { - glUniform4fv(u_color, 1, new_color.data()); - color = new_color; - } -} - -void PatternShader::setOffset(const std::array<float, 2>& new_offset) { - if (offset != new_offset) { - glUniform2fv(u_offset, 1, new_offset.data()); - offset = new_offset; - } -} - -void PatternShader::setPatternSize(const std::array<float, 2>& new_pattern_size) { - if (pattern_size != new_pattern_size) { - glUniform2fv(u_pattern_size, 1, new_pattern_size.data()); - pattern_size = new_pattern_size; - } -} - void PatternShader::setPatternTopLeft(const std::array<float, 2>& new_pattern_tl) { if (pattern_tl != new_pattern_tl) { glUniform2fv(u_pattern_tl, 1, new_pattern_tl.data()); @@ -76,6 +55,20 @@ void PatternShader::setPatternBottomRight(const std::array<float, 2>& new_patter } } +void PatternShader::setOpacity(float new_opacity) { + if (opacity != new_opacity) { + glUniform1f(u_opacity, new_opacity); + opacity = new_opacity; + } +} + +void PatternShader::setImage(int new_image) { + if (image != new_image) { + glUniform1i(u_image, new_image); + image = new_image; + } +} + void PatternShader::setMix(float new_mix) { if (mix != new_mix) { glUniform1f(u_mix, new_mix); @@ -83,3 +76,10 @@ void PatternShader::setMix(float new_mix) { } } +void PatternShader::setPatternMatrix(const std::array<float, 9>& new_patternmatrix) { + if (patternmatrix != new_patternmatrix) { + glUniformMatrix3fv(u_patternmatrix, 1, GL_FALSE, new_patternmatrix.data()); + patternmatrix = new_patternmatrix; + } +} + diff --git a/src/util/mat3.cpp b/src/util/mat3.cpp new file mode 100644 index 0000000000..38858d2385 --- /dev/null +++ b/src/util/mat3.cpp @@ -0,0 +1,51 @@ +// This is an incomplete port of http://glmatrix.net/ +// +// Copyright (c) 2013 Brandon Jones, Colin MacKenzie IV +// +// This software is provided 'as-is', without any express or implied warranty. +// In no event will the authors be held liable for any damages arising from the +// use of this software. +// +// Permission is granted to anyone to use this software for any purpose, +// including commercial applications, and to alter it and redistribute it +// freely, subject to the following restrictions: +// +// 1. The origin of this software must not be misrepresented; you must not claim +// that you wrote the original software. If you use this software in a +// product, an acknowledgment in the product documentation would be +// appreciated but is not required. +// +// 2. Altered source versions must be plainly marked as such, and must not be +// misrepresented as being the original software. +// +// 3. This notice may not be removed or altered from any source distribution. + +#include <mbgl/util/mat3.hpp> + +#include <cmath> + +using namespace mbgl; + +void matrix::identity(mat3& out) { + out[0] = 1.0f; + out[1] = 0.0f; + out[2] = 0.0f; + out[3] = 0.0f; + out[4] = 1.0f; + out[5] = 0.0f; + out[6] = 0.0f; + out[7] = 0.0f; + out[8] = 1.0f; +} + +void matrix::scale(mat3& out, const mat3& a, const float x, const float y) { + out[0] = x * a[0]; + out[1] = x * a[1]; + out[2] = x * a[2]; + out[3] = y * a[3]; + out[4] = y * a[4]; + out[5] = y * a[5]; + out[6] = a[6]; + out[7] = a[7]; + out[8] = a[8]; +} |