Skip to content

Commit

Permalink
Create Painter#setUniforms
Browse files Browse the repository at this point in the history
  • Loading branch information
Lucas Wojciechowski committed Aug 3, 2016
1 parent 0ec8a9c commit ab615d6
Show file tree
Hide file tree
Showing 8 changed files with 251 additions and 150 deletions.
8 changes: 5 additions & 3 deletions js/data/bucket.js
Original file line number Diff line number Diff line change
Expand Up @@ -203,13 +203,15 @@ Bucket.prototype.getTransferables = function(transferables) {
}
};

Bucket.prototype.setUniforms = function(gl, programName, program, layer, globalProperties) {
Bucket.prototype.getUniforms = function(programName, program, layer, globalProperties) {
var uniforms = this.paintAttributes[programName][layer.id].uniforms;

var output = {};
for (var i = 0; i < uniforms.length; i++) {
var uniform = uniforms[i];
var uniformLocation = program[uniform.name];
gl['uniform' + uniform.components + 'fv'](uniformLocation, uniform.getValue(layer, globalProperties));
output[uniform.name] = uniform.getValue(layer, globalProperties);
}
return output;
};

Bucket.prototype.serialize = function() {
Expand Down
2 changes: 1 addition & 1 deletion js/render/draw_circle.js
Original file line number Diff line number Diff line change
Expand Up @@ -52,7 +52,7 @@ function drawCircles(painter, source, layer, coords) {
layer.paint['circle-translate-anchor']
));

bucket.setUniforms(gl, 'circle', program, layer, {zoom: painter.transform.zoom});
painter.setUniforms(bucket.getUniforms('circle', program, layer, {zoom: painter.transform.zoom}));

for (var k = 0; k < bufferGroups.length; k++) {
var group = bufferGroups[k];
Expand Down
4 changes: 2 additions & 2 deletions js/render/draw_fill.js
Original file line number Diff line number Diff line change
Expand Up @@ -77,7 +77,7 @@ function drawFill(painter, source, layer, coord) {
programOptions.vertexPragmas,
programOptions.fragmentPragmas
);
bucket.setUniforms(gl, 'fill', program, layer, {zoom: painter.transform.zoom});
painter.setUniforms(bucket.getUniforms('fill', program, layer, {zoom: painter.transform.zoom}));

} else {
// Draw texture fill
Expand Down Expand Up @@ -131,7 +131,7 @@ function drawStroke(painter, source, layer, coord) {
);
gl.uniform2f(program.u_world, gl.drawingBufferWidth, gl.drawingBufferHeight);
gl.uniform1f(program.u_opacity, opacity);
bucket.setUniforms(gl, 'fill', program, layer, {zoom: painter.transform.zoom});
painter.setUniforms(bucket.getUniforms('fill', program, layer, {zoom: painter.transform.zoom}));
}

gl.uniformMatrix4fv(program.u_matrix, false, painter.translatePosMatrix(
Expand Down
252 changes: 111 additions & 141 deletions js/render/draw_line.js
Original file line number Diff line number Diff line change
Expand Up @@ -22,166 +22,136 @@ module.exports = function drawLine(painter, source, layer, coords) {
var gl = painter.gl;
gl.enable(gl.STENCIL_TEST);

// 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;

var blur = layer.paint['line-blur'] + antialiasing;
var color = layer.paint['line-color'];

var tr = painter.transform;

var antialiasingMatrix = mat2.create();
mat2.scale(antialiasingMatrix, antialiasingMatrix, [1, Math.cos(tr._pitch)]);
mat2.scale(antialiasingMatrix, antialiasingMatrix, [1, Math.cos(painter.transform._pitch)]);
mat2.rotate(antialiasingMatrix, antialiasingMatrix, painter.transform.angle);

// calculate how much longer the real world distance is at the top of the screen
// than at the middle of the screen.
var topedgelength = Math.sqrt(tr.height * tr.height / 4 * (1 + tr.altitude * tr.altitude));
var x = tr.height / 2 * Math.tan(tr._pitch);
var extra = (topedgelength + x) / topedgelength - 1;

var dasharray = layer.paint['line-dasharray'];
var image = layer.paint['line-pattern'];
var program, posA, posB, imagePosA, imagePosB;

if (dasharray) {
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);
gl.uniform1f(program.u_antialiasing, antialiasing / 2);
gl.uniform1f(program.u_blur, blur);
gl.uniform4fv(program.u_color, color);
gl.uniform1f(program.u_opacity, layer.paint['line-opacity']);

posA = painter.lineAtlas.getDash(dasharray.from, layer.layout['line-cap'] === 'round');
posB = painter.lineAtlas.getDash(dasharray.to, layer.layout['line-cap'] === 'round');

gl.uniform1i(program.u_image, 0);
gl.activeTexture(gl.TEXTURE0);
painter.lineAtlas.bind(gl);

gl.uniform1f(program.u_tex_y_a, posA.y);
gl.uniform1f(program.u_tex_y_b, posB.y);
gl.uniform1f(program.u_mix, dasharray.t);
gl.uniform1f(program.u_extra, extra);
gl.uniform1f(program.u_offset, -layer.paint['line-offset']);
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;

var program;
var programOptions = bucket.paintAttributes.line[layer.id];
if (layer.paint['line-dasharray']) {
program = bindLineSDFPatternProgram(painter, source, layer, tile, programOptions);
} else if (layer.paint['line-pattern']) {
program = bindLinePatternProgram(painter, source, layer, tile, programOptions);
} else {
program = bindLineProgram(painter, source, layer, tile, programOptions);
}

var posMatrix = painter.translatePosMatrix(coord.posMatrix, tile, layer.paint['line-translate'], layer.paint['line-translate-anchor']);

painter.setUniforms({
'u_ratio': 1 / pixelsToTileUnits(tile, 1, painter.transform.zoom),
'u_blur': layer.paint['line-blur'] + 1 / browser.devicePixelRatio,
'u_extra': getExtra(painter.transform),
'u_linewidth': layer.paint['line-width'] / 2,
'u_opacity': layer.paint['line-opacity'],
'u_offset': -layer.paint['line-offset'],
'u_gapwidth': layer.paint['line-gap-width'] / 2,
'u_antialiasing': (1 / browser.devicePixelRatio) / 2
});
gl.uniformMatrix2fv(program.u_antialiasingmatrix, false, antialiasingMatrix);
gl.uniformMatrix4fv(program.u_matrix, false, posMatrix);
painter.setUniforms(bucket.getUniforms('line', program, layer, {zoom: painter.transform.zoom}));

} else if (image) {
imagePosA = painter.spriteAtlas.getPosition(image.from, true);
imagePosB = painter.spriteAtlas.getPosition(image.to, true);
if (!imagePosA || !imagePosB) return;

program = painter.useProgram(
'linepattern',
programOptions.defines,
programOptions.vertexPragmas,
programOptions.fragmentPragmas
);

gl.uniform1i(program.u_image, 0);
gl.activeTexture(gl.TEXTURE0);
painter.spriteAtlas.bind(gl, true);

gl.uniform1f(program.u_linewidth, layer.paint['line-width'] / 2);
gl.uniform1f(program.u_gapwidth, layer.paint['line-gap-width'] / 2);
gl.uniform1f(program.u_antialiasing, antialiasing / 2);
gl.uniform1f(program.u_blur, blur);
gl.uniform2fv(program.u_pattern_tl_a, imagePosA.tl);
gl.uniform2fv(program.u_pattern_br_a, imagePosA.br);
gl.uniform2fv(program.u_pattern_tl_b, imagePosB.tl);
gl.uniform2fv(program.u_pattern_br_b, imagePosB.br);
gl.uniform1f(program.u_fade, image.t);
gl.uniform1f(program.u_opacity, layer.paint['line-opacity']);
gl.uniform1f(program.u_extra, extra);
gl.uniform1f(program.u_offset, -layer.paint['line-offset']);
gl.uniformMatrix2fv(program.u_antialiasingmatrix, false, antialiasingMatrix);
painter.enableTileClippingMask(coord);

} else {
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);
gl.uniform1f(program.u_antialiasing, antialiasing / 2);
gl.uniform1f(program.u_blur, blur);
gl.uniform1f(program.u_extra, extra);
gl.uniform1f(program.u_offset, -layer.paint['line-offset']);
gl.uniformMatrix2fv(program.u_antialiasingmatrix, false, antialiasingMatrix);
gl.uniform4fv(program.u_color, color);
gl.uniform1f(program.u_opacity, layer.paint['line-opacity']);
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);
}
}
};

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);
function bindLineSDFPatternProgram(painter, source, layer, tile, programOptions) {
var gl = painter.gl;

var ratio = 1 / pixelsToTileUnits(tile, 1, painter.transform.zoom);
var program = painter.useProgram(
'linesdfpattern',
programOptions.defines,
programOptions.vertexPragmas,
programOptions.fragmentPragmas
);

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);
var dasharray = layer.paint['line-dasharray'];
var posA = painter.lineAtlas.getDash(dasharray.from, layer.layout['line-cap'] === 'round');
var posB = painter.lineAtlas.getDash(dasharray.to, layer.layout['line-cap'] === 'round');
var widthA = posA.width * dasharray.fromScale;
var widthB = posB.width * dasharray.toScale;
painter.setUniforms({
'u_tex_y_a': posA.y,
'u_tex_y_b': posB.y,
'u_mix': dasharray.t,
'u_patternscale_a': [1 / pixelsToTileUnits(tile, widthA, painter.transform.tileZoom), -posA.height / 2],
'u_patternscale_b': [1 / pixelsToTileUnits(tile, widthB, painter.transform.tileZoom), -posB.height / 2],
'u_sdfgamma': painter.lineAtlas.width / (Math.min(widthA, widthB) * 256 * browser.devicePixelRatio) / 2
});
gl.uniform1i(program.u_image, 0);
gl.activeTexture(gl.TEXTURE0);
painter.lineAtlas.bind(gl);

return program;
}

function bindLinePatternProgram(painter, source, layer, tile, programOptions) {
var gl = painter.gl;

} else if (image) {
gl.uniform1f(program.u_ratio, ratio);
gl.uniform2fv(program.u_pattern_size_a, [
var program = painter.useProgram(
'linepattern',
programOptions.defines,
programOptions.vertexPragmas,
programOptions.fragmentPragmas
);

var image = layer.paint['line-pattern'];
var imagePosA = painter.spriteAtlas.getPosition(image.from, true);
var imagePosB = painter.spriteAtlas.getPosition(image.to, true);
if (!imagePosA || !imagePosB) return;
painter.setUniforms({
'u_pattern_tl_a': imagePosA.tl,
'u_pattern_br_a': imagePosA.br,
'u_pattern_tl_b': imagePosB.tl,
'u_pattern_br_b': imagePosB.br,
'u_fade': image.t,
'u_pattern_size_a': [
pixelsToTileUnits(tile, imagePosA.size[0] * image.fromScale, painter.transform.tileZoom),
imagePosB.size[1]
]);
gl.uniform2fv(program.u_pattern_size_b, [
],
'u_pattern_size_b': [
pixelsToTileUnits(tile, imagePosB.size[0] * image.toScale, painter.transform.tileZoom),
imagePosB.size[1]
]);
]
});
gl.uniform1i(program.u_image, 0);
gl.activeTexture(gl.TEXTURE0);
painter.spriteAtlas.bind(gl, true);

} else {
gl.uniform1f(program.u_ratio, ratio);
}
return program;
}

bucket.setUniforms(gl, 'line', program, layer, {zoom: painter.transform.zoom});
function bindLineProgram(painter, source, layer, tile, programOptions) {
return painter.useProgram(
'line',
programOptions.defines,
programOptions.vertexPragmas,
programOptions.fragmentPragmas
);
}

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);
}
function getExtra(transform) {
// calculate how much longer the real world distance is at the top of the screen
// than at the middle of the screen.
var topedgelength = Math.sqrt(transform.height * transform.height / 4 * (1 + transform.altitude * transform.altitude));
var x = transform.height / 2 * Math.tan(transform._pitch);
return (topedgelength + x) / topedgelength - 1;
}
25 changes: 25 additions & 0 deletions js/render/painter.js
Original file line number Diff line number Diff line change
Expand Up @@ -38,6 +38,7 @@ function Painter(gl, transform) {
this.depthEpsilon = 1 / Math.pow(2, 16);

this.lineWidthRange = gl.getParameter(gl.ALIASED_LINE_WIDTH_RANGE);
this.currentUniforms = {};
}

util.extend(Painter.prototype, require('./painter/use_program'));
Expand Down Expand Up @@ -340,3 +341,27 @@ Painter.prototype.showOverdrawInspector = function(enabled) {
gl.blendFunc(gl.ONE, gl.ONE_MINUS_SRC_ALPHA);
}
};

Painter.prototype.setUniforms = function(uniforms) {
var gl = this.gl;
for (var name in uniforms) {
var value = uniforms[name];
if (this.currentUniforms[name] !== value) {
var location = this.currentProgram[name];
if (Array.isArray(value)) {
if (value.length === 1) {
gl.uniform1fv(location, value);
} else if (value.length === 2) {
gl.uniform2fv(location, value);
} else if (value.length === 3) {
gl.uniform3fv(location, value);
} else if (value.length === 4) {
gl.uniform4fv(location, value);
}
} else {
gl.uniform1f(location, value);
}
this.currentUniforms[name] = value;
}
}
};
Loading

0 comments on commit ab615d6

Please sign in to comment.