From c675fbae68d225a1ffafa47f0620de5d32ccfb13 Mon Sep 17 00:00:00 2001 From: Ansis Brammanis Date: Sun, 22 Jun 2014 16:17:33 -0700 Subject: [PATCH 1/3] fix drawing patterned backgrounds --- js/render/drawbackground.js | 58 +++++++++++++++++++++++------------ js/render/drawcomposited.js | 2 +- js/render/painter.js | 10 +++--- shaders/pattern.fragment.glsl | 4 +-- shaders/pattern.vertex.glsl | 3 +- 5 files changed, 49 insertions(+), 28 deletions(-) diff --git a/js/render/drawbackground.js b/js/render/drawbackground.js index 4cf291e424c..ac247cfb138 100644 --- a/js/render/drawbackground.js +++ b/js/render/drawbackground.js @@ -1,5 +1,7 @@ 'use strict'; +var mat3 = require('../lib/glmatrix.js').mat3; + module.exports = drawFill; function drawFill(gl, painter, bucket, layerStyle, posMatrix, params, imageSprite, type) { @@ -11,10 +13,6 @@ function drawFill(gl, painter, bucket, layerStyle, posMatrix, params, imageSprit background = true; } - if (background) { - posMatrix = painter.projectionMatrix; - } - var color = layerStyle[type + '-color']; var image = layerStyle[type + '-image']; @@ -22,24 +20,16 @@ function drawFill(gl, painter, bucket, layerStyle, posMatrix, params, imageSprit if (imagePos) { // Draw texture fill - - var factor = 8 / Math.pow(2, painter.transform.tileZoom - params.z); - var mix = painter.transform.zoomFraction; - var imageSize = [imagePos.size[0] * factor, imagePos.size[1] * factor]; - - var patternOffset = [ - (params.x * 4096) % imageSize[0], - (params.y * 4096) % imageSize[1] - ]; - gl.switchShader(painter.patternShader, posMatrix); gl.uniform1i(painter.patternShader.u_image, 0); - gl.uniform2fv(painter.patternShader.u_pattern_size, imageSize); - gl.uniform2fv(painter.patternShader.u_offset, patternOffset); gl.uniform2fv(painter.patternShader.u_pattern_tl, imagePos.tl); gl.uniform2fv(painter.patternShader.u_pattern_br, imagePos.br); gl.uniform4fv(painter.patternShader.u_color, color); - gl.uniform1f(painter.patternShader.u_mix, mix); + gl.uniform1f(painter.patternShader.u_mix, painter.transform.zoomFraction); + + var patternMatrix = getPatternMatrix(background, painter.transform, params, imagePos, painter); + gl.uniformMatrix3fv(painter.patternShader.u_patternmatrix, false, patternMatrix); + imageSprite.bind(gl, true); } else { @@ -50,14 +40,16 @@ function drawFill(gl, painter, bucket, layerStyle, posMatrix, params, imageSprit if (background) { gl.disable(gl.STENCIL_TEST); + gl.bindBuffer(gl.ARRAY_BUFFER, painter.backgroundBuffer); + gl.vertexAttribPointer(painter.fillShader.a_pos, 2, gl.SHORT, false, 0, 0); } else { // Only draw regions that we marked gl.stencilFunc(gl.NOTEQUAL, 0x0, 0x3F); + gl.bindBuffer(gl.ARRAY_BUFFER, painter.tileExtentBuffer); + gl.vertexAttribPointer(painter.fillShader.a_pos, painter.bufferProperties.tileExtentItemSize, gl.SHORT, false, 0, 0); } // Draw a rectangle that covers the entire viewport. - gl.bindBuffer(gl.ARRAY_BUFFER, painter.tileExtentBuffer); - gl.vertexAttribPointer(painter.fillShader.a_pos, painter.bufferProperties.tileExtentItemSize, gl.SHORT, false, 0, 0); gl.drawArrays(gl.TRIANGLE_STRIP, 0, painter.bufferProperties.tileExtentNumItems); if (background) { @@ -67,3 +59,31 @@ function drawFill(gl, painter, bucket, layerStyle, posMatrix, params, imageSprit gl.stencilMask(0x00); gl.stencilFunc(gl.EQUAL, 0x80, 0x80); } + +// return a matrix that projects the position coords to pattern pos coords +function getPatternMatrix(background, transform, params, imagePos) { + var matrix = mat3.create(); + var size = imagePos.size; + + if (background) { + var center = transform.locationCoordinate(transform.center); + var offset = [ + (center.column * transform.tileSize) % size[0], + (center.row * transform.tileSize) % size[1], + 0 + ]; + var scale = 1 / Math.pow(2, transform.zoomFraction); + mat3.scale(matrix, matrix, [1 / size[0], 1 / size[1], 1]); + mat3.translate(matrix, matrix, offset); + mat3.rotate(matrix, matrix, -transform.angle); + mat3.scale(matrix, matrix, [scale * transform.width / 2, -1 * scale * transform.height / 2, 1]); + + } else { + var factor = 8 / Math.pow(2, transform.tileZoom - params.z) * 2; + var imageSize = [size[0] * factor, size[1] * factor]; + mat3.scale(matrix, matrix, [1 / imageSize[0], 1 / imageSize[1], 1, 1]); + + } + + return matrix; +} diff --git a/js/render/drawcomposited.js b/js/render/drawcomposited.js index 6411791927a..2fcc5565e6c 100644 --- a/js/render/drawcomposited.js +++ b/js/render/drawcomposited.js @@ -9,7 +9,7 @@ function drawComposited (gl, painter, buckets, layerStyle, params, style, layer) gl.disable(gl.STENCIL_TEST); gl.stencilMask(0x00); - gl.switchShader(painter.compositeShader, painter.projectionMatrix); + gl.switchShader(painter.compositeShader, painter.identityMatrix); gl.activeTexture(gl.TEXTURE0); gl.bindTexture(gl.TEXTURE_2D, texture); gl.uniform1i(painter.compositeShader.u_image, 0); diff --git a/js/render/painter.js b/js/render/painter.js index a7da80aaabe..5c3fd22b5cd 100644 --- a/js/render/painter.js +++ b/js/render/painter.js @@ -120,7 +120,7 @@ GLPainter.prototype.setup = function() { this.patternShader = gl.initializeShader('pattern', ['a_pos'], - ['u_posmatrix', 'u_color', 'u_pattern_tl', 'u_pattern_br', 'u_pattern_size', 'u_offset', 'u_mix'] + ['u_posmatrix', 'u_pattern_tl', 'u_pattern_br', 'u_mix', 'u_patternmatrix'] ); this.fillShader = gl.initializeShader('fill', @@ -129,7 +129,7 @@ GLPainter.prototype.setup = function() { ); // The backgroundBuffer is used when drawing to the full *canvas* - var background = [ -32768, -32768, 32766, -32768, -32768, 32766, 32766, 32766 ]; + var background = [ -1, -1, 1, -1, -1, 1, 1, 1 ]; var backgroundArray = new Int16Array(background); this.backgroundBuffer = gl.createBuffer(); this.bufferProperties.backgroundItemSize = 2; @@ -137,6 +137,8 @@ GLPainter.prototype.setup = function() { gl.bindBuffer(gl.ARRAY_BUFFER, this.backgroundBuffer); gl.bufferData(gl.ARRAY_BUFFER, backgroundArray, gl.STATIC_DRAW); + this.identityMatrix = mat4.create(); + // The tileExtentBuffer is used when drawing to a full *tile* var t = this.tileExtent; var maxInt16 = 32767; @@ -303,7 +305,7 @@ GLPainter.prototype.applyStyle = function(layer, style, buckets, params) { if (layer.layers) { drawComposited(gl, this, buckets, layerStyle, params, style, layer); } else if (params.background) { - drawBackground(gl, this, undefined, layerStyle, params, style.sprite); + drawBackground(gl, this, undefined, layerStyle, this.identityMatrix, params, style.sprite); } else { var bucket = buckets[layer.bucket]; @@ -352,7 +354,7 @@ GLPainter.prototype.applyStyle = function(layer, style, buckets, params) { // Draws non-opaque areas. This is for debugging purposes. GLPainter.prototype.drawStencilBuffer = function() { var gl = this.gl; - gl.switchShader(this.fillShader, this.projectionMatrix); + gl.switchShader(this.fillShader, this.identityMatrix); // Blend to the front, not the back. gl.blendFunc(gl.ONE, gl.ONE_MINUS_SRC_ALPHA); diff --git a/shaders/pattern.fragment.glsl b/shaders/pattern.fragment.glsl index 4ae6ce443f8..ea0f253b9aa 100644 --- a/shaders/pattern.fragment.glsl +++ b/shaders/pattern.fragment.glsl @@ -2,8 +2,6 @@ precision mediump float; uniform vec4 u_color; -uniform vec2 u_offset; -uniform vec2 u_pattern_size; uniform vec2 u_pattern_tl; uniform vec2 u_pattern_br; uniform float u_mix; @@ -15,7 +13,7 @@ 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); diff --git a/shaders/pattern.vertex.glsl b/shaders/pattern.vertex.glsl index 4c4c7cffdbb..bf863a68e99 100644 --- a/shaders/pattern.vertex.glsl +++ b/shaders/pattern.vertex.glsl @@ -1,12 +1,13 @@ precision mediump float; uniform mat4 u_posmatrix; +uniform mat3 u_patternmatrix; attribute vec2 a_pos; varying vec2 v_pos; void main() { - v_pos = a_pos; gl_Position = u_posmatrix * vec4(a_pos, 0, 1); + v_pos = (u_patternmatrix * vec3(a_pos, 1)).xy; } From 267f38b19b9bf96365ba390c967dcdd7090e4ba6 Mon Sep 17 00:00:00 2001 From: Ansis Brammanis Date: Sun, 22 Jun 2014 16:24:54 -0700 Subject: [PATCH 2/3] don't use `-color` for stroke if `-image` present --- js/render/drawfill.js | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/js/render/drawfill.js b/js/render/drawfill.js index 85848d1378f..c052d42b5c1 100644 --- a/js/render/drawfill.js +++ b/js/render/drawfill.js @@ -70,14 +70,14 @@ function drawFill(gl, painter, bucket, layerStyle, posMatrix, params, imageSprit gl.stencilOp(gl.KEEP, gl.KEEP, gl.KEEP); gl.stencilMask(0x0); + var strokeColor = layerStyle['fill-outline-color']; + // Because we're drawing top-to-bottom, and we update the stencil mask // below, we have to draw the outline first (!) - if (layerStyle['fill-antialias'] === true && params.antialiasing) { + if (layerStyle['fill-antialias'] === true && params.antialiasing && !(layerStyle['fill-image'] && !strokeColor)) { gl.switchShader(painter.outlineShader, posMatrix, painter.tile.exMatrix); gl.lineWidth(2 * window.devicePixelRatio); - var strokeColor = layerStyle['fill-outline-color']; - if (strokeColor) { // If we defined a different color for the fill outline, we are // going to ignore the bits in 0x3F and just care about the global From ad1321f125f6f6e6b3a9a7f23fa513de6805087a Mon Sep 17 00:00:00 2001 From: Ansis Brammanis Date: Sun, 22 Jun 2014 16:26:53 -0700 Subject: [PATCH 3/3] don't fall back to solid color for fill patterns --- js/render/drawbackground.js | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/js/render/drawbackground.js b/js/render/drawbackground.js index ac247cfb138..fa67a6024e9 100644 --- a/js/render/drawbackground.js +++ b/js/render/drawbackground.js @@ -16,10 +16,12 @@ function drawFill(gl, painter, bucket, layerStyle, posMatrix, params, imageSprit var color = layerStyle[type + '-color']; var image = layerStyle[type + '-image']; - var imagePos = image && imageSprite.getPosition(image, true); - if (imagePos) { + if (image) { // Draw texture fill + var imagePos = imageSprite.getPosition(image, true); + if (!imagePos) return; + gl.switchShader(painter.patternShader, posMatrix); gl.uniform1i(painter.patternShader.u_image, 0); gl.uniform2fv(painter.patternShader.u_pattern_tl, imagePos.tl);