From e4c7367cbfe06b9b4c06809b2719beee9875b5b8 Mon Sep 17 00:00:00 2001 From: Lucas Wojciechowski Date: Mon, 1 Aug 2016 12:35:45 -0700 Subject: [PATCH] Add basic support for line-color property functions --- js/data/bucket/line_bucket.js | 22 +++++- js/render/draw_line.js | 126 ++++++++++++++++++------------- package.json | 4 +- test/js/data/line_bucket.test.js | 8 +- 4 files changed, 101 insertions(+), 59 deletions(-) diff --git a/js/data/bucket/line_bucket.js b/js/data/bucket/line_bucket.js index 02dcabfc777..9bb934cce35 100644 --- a/js/data/bucket/line_bucket.js +++ b/js/data/bucket/line_bucket.js @@ -79,6 +79,16 @@ LineBucket.prototype.programInterfaces = { components: 4, type: 'Uint8' }]), + paintAttributes: [{ + name: 'a_color', + components: 4, + type: 'Uint8', + getValue: function(layer, globalProperties, featureProperties) { + return layer.getPaintValue("line-color", globalProperties, featureProperties); + }, + multiplier: 255, + paintProperty: 'line-color' + }], elementArrayType: new Bucket.ElementArrayType() } }; @@ -88,6 +98,7 @@ LineBucket.prototype.addFeature = function(feature) { for (var i = 0; i < lines.length; i++) { this.addLine( lines[i], + feature.properties, this.layer.layout['line-join'], this.layer.layout['line-cap'], this.layer.layout['line-miter-limit'], @@ -96,7 +107,7 @@ LineBucket.prototype.addFeature = function(feature) { } }; -LineBucket.prototype.addLine = function(vertices, join, cap, miterLimit, roundLimit) { +LineBucket.prototype.addLine = function(vertices, featureProperties, join, cap, miterLimit, roundLimit) { var len = vertices.length; // If the line has duplicate vertices at the end, adjust length to remove them. @@ -116,7 +127,8 @@ LineBucket.prototype.addLine = function(vertices, join, cap, miterLimit, roundLi closed = firstVertex.equals(lastVertex); // we could be more precise, but it would only save a negligible amount of space - this.prepareArrayGroup('line', len * 10); + var group = this.prepareArrayGroup('line', len * 10); + var startIndex = group.layoutVertexArray.length; // a line may not have coincident points if (len === 2 && closed) return; @@ -347,6 +359,12 @@ LineBucket.prototype.addLine = function(vertices, join, cap, miterLimit, roundLi startOfLine = false; } + this.populatePaintArrays( + 'line', {zoom: this.zoom}, + featureProperties, + group, + startIndex + ); }; /** diff --git a/js/render/draw_line.js b/js/render/draw_line.js index 908f7573b84..d420a458fbe 100644 --- a/js/render/draw_line.js +++ b/js/render/draw_line.js @@ -25,6 +25,23 @@ module.exports = function drawLine(painter, source, layer, coords) { // don't draw zero-width lines if (layer.paint['line-width'] <= 0) return; + for (var k = 0; k < coords.length; k++) { + drawLineTile(painter, source, layer, coords[k]); + } + +}; + +function drawLineTile(painter, source, layer, coord) { + var tile = source.getTile(coord); + var bucket = tile.getBucket(layer); + if (!bucket) return; + var bufferGroups = bucket.bufferGroups.line; + if (!bufferGroups) return; + + var gl = painter.gl; + + var programOptions = bucket.paintAttributes.line[layer.id]; + // the distance over which the line edge fades out. // Retina devices need a smaller distance to avoid aliasing. var antialiasing = 1 / browser.devicePixelRatio; @@ -49,7 +66,12 @@ module.exports = function drawLine(painter, source, layer, coords) { var program, posA, posB, imagePosA, imagePosB; if (dasharray) { - program = painter.useProgram('linesdfpattern'); + program = painter.useProgram( + 'linesdfpattern', + programOptions.defines, + programOptions.vertexPragmas, + programOptions.fragmentPragmas + ); gl.uniform1f(program.u_linewidth, layer.paint['line-width'] / 2); gl.uniform1f(program.u_gapwidth, layer.paint['line-gap-width'] / 2); @@ -77,7 +99,12 @@ module.exports = function drawLine(painter, source, layer, coords) { imagePosB = painter.spriteAtlas.getPosition(image.to, true); if (!imagePosA || !imagePosB) return; - program = painter.useProgram('linepattern'); + program = painter.useProgram( + 'linepattern', + programOptions.defines, + programOptions.vertexPragmas, + programOptions.fragmentPragmas + ); gl.uniform1i(program.u_image, 0); gl.activeTexture(gl.TEXTURE0); @@ -98,7 +125,12 @@ module.exports = function drawLine(painter, source, layer, coords) { gl.uniformMatrix2fv(program.u_antialiasingmatrix, false, antialiasingMatrix); } else { - program = painter.useProgram('line'); + program = painter.useProgram( + 'line', + programOptions.defines, + programOptions.vertexPragmas, + programOptions.fragmentPragmas + ); gl.uniform1f(program.u_linewidth, layer.paint['line-width'] / 2); gl.uniform1f(program.u_gapwidth, layer.paint['line-gap-width'] / 2); @@ -111,53 +143,45 @@ module.exports = function drawLine(painter, source, layer, coords) { gl.uniform1f(program.u_opacity, layer.paint['line-opacity']); } - for (var k = 0; k < coords.length; k++) { - var coord = coords[k]; - var tile = source.getTile(coord); - var bucket = tile.getBucket(layer); - if (!bucket) continue; - var bufferGroups = bucket.bufferGroups.line; - if (!bufferGroups) continue; - - painter.enableTileClippingMask(coord); - - // set uniforms that are different for each tile - var posMatrix = painter.translatePosMatrix(coord.posMatrix, tile, layer.paint['line-translate'], layer.paint['line-translate-anchor']); - gl.uniformMatrix4fv(program.u_matrix, false, posMatrix); - - var ratio = 1 / pixelsToTileUnits(tile, 1, painter.transform.zoom); - - if (dasharray) { - var widthA = posA.width * dasharray.fromScale; - var widthB = posB.width * dasharray.toScale; - var scaleA = [1 / pixelsToTileUnits(tile, widthA, painter.transform.tileZoom), -posA.height / 2]; - var scaleB = [1 / pixelsToTileUnits(tile, widthB, painter.transform.tileZoom), -posB.height / 2]; - var gamma = painter.lineAtlas.width / (Math.min(widthA, widthB) * 256 * browser.devicePixelRatio) / 2; - gl.uniform1f(program.u_ratio, ratio); - gl.uniform2fv(program.u_patternscale_a, scaleA); - gl.uniform2fv(program.u_patternscale_b, scaleB); - gl.uniform1f(program.u_sdfgamma, gamma); - - } else if (image) { - gl.uniform1f(program.u_ratio, ratio); - gl.uniform2fv(program.u_pattern_size_a, [ - pixelsToTileUnits(tile, imagePosA.size[0] * image.fromScale, painter.transform.tileZoom), - imagePosB.size[1] - ]); - gl.uniform2fv(program.u_pattern_size_b, [ - pixelsToTileUnits(tile, imagePosB.size[0] * image.toScale, painter.transform.tileZoom), - imagePosB.size[1] - ]); - - } else { - gl.uniform1f(program.u_ratio, ratio); - } - - for (var i = 0; i < bufferGroups.length; i++) { - var group = bufferGroups[i]; - group.vaos[layer.id].bind(gl, program, group.layoutVertexBuffer, group.elementBuffer); - gl.drawElements(gl.TRIANGLES, group.elementBuffer.length * 3, gl.UNSIGNED_SHORT, 0); - } + painter.enableTileClippingMask(coord); + + // set uniforms that are different for each tile + var posMatrix = painter.translatePosMatrix(coord.posMatrix, tile, layer.paint['line-translate'], layer.paint['line-translate-anchor']); + gl.uniformMatrix4fv(program.u_matrix, false, posMatrix); + + var ratio = 1 / pixelsToTileUnits(tile, 1, painter.transform.zoom); + + if (dasharray) { + var widthA = posA.width * dasharray.fromScale; + var widthB = posB.width * dasharray.toScale; + var scaleA = [1 / pixelsToTileUnits(tile, widthA, painter.transform.tileZoom), -posA.height / 2]; + var scaleB = [1 / pixelsToTileUnits(tile, widthB, painter.transform.tileZoom), -posB.height / 2]; + var gamma = painter.lineAtlas.width / (Math.min(widthA, widthB) * 256 * browser.devicePixelRatio) / 2; + gl.uniform1f(program.u_ratio, ratio); + gl.uniform2fv(program.u_patternscale_a, scaleA); + gl.uniform2fv(program.u_patternscale_b, scaleB); + gl.uniform1f(program.u_sdfgamma, gamma); + + } else if (image) { + gl.uniform1f(program.u_ratio, ratio); + gl.uniform2fv(program.u_pattern_size_a, [ + pixelsToTileUnits(tile, imagePosA.size[0] * image.fromScale, painter.transform.tileZoom), + imagePosB.size[1] + ]); + gl.uniform2fv(program.u_pattern_size_b, [ + pixelsToTileUnits(tile, imagePosB.size[0] * image.toScale, painter.transform.tileZoom), + imagePosB.size[1] + ]); + + } else { + gl.uniform1f(program.u_ratio, ratio); } -}; + bucket.setUniforms(gl, 'line', program, layer, {zoom: painter.transform.zoom}); + + for (var i = 0; i < bufferGroups.length; i++) { + var group = bufferGroups[i]; + group.vaos[layer.id].bind(gl, program, group.layoutVertexBuffer, group.elementBuffer, group.paintVertexBuffers[layer.id]); + gl.drawElements(gl.TRIANGLES, group.elementBuffer.length * 3, gl.UNSIGNED_SHORT, 0); + } +} diff --git a/package.json b/package.json index e9573d77d8c..7598ff25396 100644 --- a/package.json +++ b/package.json @@ -20,7 +20,7 @@ "gl-matrix": "^2.3.1", "grid-index": "^1.0.0", "mapbox-gl-function": "^1.2.1", - "mapbox-gl-shaders": "mapbox/mapbox-gl-shaders#de2ab007455aa2587c552694c68583f94c9f2747", + "mapbox-gl-shaders": "mapbox/mapbox-gl-shaders#df162476980d9ee2ab6f8d0cf5a06e27aac60472", "mapbox-gl-style-spec": "mapbox/mapbox-gl-style-spec#83b1a3e5837d785af582efd5ed1a212f2df6a4ae", "mapbox-gl-supported": "^1.2.0", "pbf": "^1.3.2", @@ -62,7 +62,7 @@ "istanbul": "^0.4.2", "json-loader": "^0.5.4", "lodash": "^4.13.1", - "mapbox-gl-test-suite": "mapbox/mapbox-gl-test-suite#7babab52fb02788ebbc38384139bf350e8e38552", + "mapbox-gl-test-suite": "mapbox/mapbox-gl-test-suite#15e18375321393364907208715ab82c5a9c70f60", "memory-fs": "^0.3.0", "minifyify": "^7.0.1", "nyc": "6.4.0", diff --git a/test/js/data/line_bucket.test.js b/test/js/data/line_bucket.test.js index 6621a018243..656496d5972 100644 --- a/test/js/data/line_bucket.test.js +++ b/test/js/data/line_bucket.test.js @@ -28,27 +28,27 @@ test('LineBucket', function(t) { // should throw in the future? t.equal(bucket.addLine([ new Point(0, 0) - ]), undefined); + ], {}), undefined); // should also throw in the future? // this is a closed single-segment line t.equal(bucket.addLine([ new Point(0, 0), new Point(0, 0) - ]), undefined); + ], {}), undefined); t.equal(bucket.addLine([ new Point(0, 0), new Point(10, 10), new Point(10, 20) - ]), undefined); + ], {}), undefined); t.equal(bucket.addLine([ new Point(0, 0), new Point(10, 10), new Point(10, 20), new Point(0, 0) - ]), undefined); + ], {}), undefined); t.equal(bucket.addFeature(feature), undefined);