Skip to content

Commit

Permalink
Enable property functions for line-width (#4773)
Browse files Browse the repository at this point in the history
line-dasharray is scaled by line-width and therefore requires the value of line-width at floor(current z). Therefore in order to enable property functions for line-width, we add an extra phantom paint attribute (which copies the line-width expression, but evaluates it at floor(z)) so that we can move the scaling calculations to the shader.
  • Loading branch information
Lauren Budorick authored Jun 19, 2017
1 parent 6a64798 commit 09bec65
Show file tree
Hide file tree
Showing 24 changed files with 528 additions and 41 deletions.
2 changes: 2 additions & 0 deletions src/data/bucket/line_bucket.js
Original file line number Diff line number Diff line change
Expand Up @@ -50,6 +50,8 @@ const lineInterface = {
{property: 'line-opacity', multiplier: 10, type: 'Uint8'},
{property: 'line-gap-width', multiplier: 10, type: 'Uint8', name: 'a_gapwidth'},
{property: 'line-offset', multiplier: 1, type: 'Int8'},
{property: 'line-width', multiplier: 10, type: 'Uint8', name: 'a_width'},
{property: 'line-width', multiplier: 10, type: 'Uint8', name: 'a_floorwidth', useIntegerZoom: true},
],
elementArrayType: createElementArrayType()
};
Expand Down
11 changes: 8 additions & 3 deletions src/data/program_configuration.js
Original file line number Diff line number Diff line change
Expand Up @@ -137,6 +137,7 @@ class ProgramConfiguration {
this.interpolationUniforms.push({
name: tName,
property: attribute.property,
useIntegerZoom: attribute.useIntegerZoom,
stopOffset
});

Expand Down Expand Up @@ -211,7 +212,8 @@ class ProgramConfiguration {
paintArray.resize(length);

for (const attribute of this.attributes) {
const value = getPaintAttributeValue(attribute, layer, globalProperties, featureProperties);
const zoomBase = attribute.useIntegerZoom ? { zoom: Math.floor(globalProperties.zoom) } : globalProperties;
const value = getPaintAttributeValue(attribute, layer, zoomBase, featureProperties);

for (let i = start; i < length; i++) {
const vertex = paintArray.get(i);
Expand All @@ -233,17 +235,20 @@ class ProgramConfiguration {

setUniforms(gl, program, layer, globalProperties) {
for (const uniform of this.uniforms) {
const value = layer.getPaintValue(uniform.property, globalProperties);
const zoomBase = uniform.useIntegerZoom ? { zoom: Math.floor(globalProperties.zoom) } : globalProperties;
const value = layer.getPaintValue(uniform.property, zoomBase);

if (uniform.components === 4) {
gl.uniform4fv(program[uniform.name], value);
} else {
gl.uniform1f(program[uniform.name], value);
}
}
for (const uniform of this.interpolationUniforms) {
const zoomBase = uniform.useIntegerZoom ? { zoom: Math.floor(globalProperties.zoom) } : globalProperties;
// stopInterp indicates which stops need to be interpolated.
// If stopInterp is 3.5 then interpolate half way between stops 3 and 4.
const stopInterp = layer.getPaintInterpolationT(uniform.property, globalProperties);
const stopInterp = layer.getPaintInterpolationT(uniform.property, zoomBase);
// We can only store four stop values in the buffers. stopOffset is the number of stops that come
// before the stops that were added to the buffers.
gl.uniform1f(program[uniform.name], Math.max(0, Math.min(3, stopInterp - uniform.stopOffset)));
Expand Down
1 change: 0 additions & 1 deletion src/render/draw_line.js
Original file line number Diff line number Diff line change
Expand Up @@ -107,7 +107,6 @@ function drawLineTile(program, painter, tile, buffers, layer, coord, layerData,
gl.uniform2fv(program.u_pattern_br_b, imagePosB.br);
gl.uniform1f(program.u_fade, image.t);
}
gl.uniform1f(program.u_width, layer.paint['line-width']);
}

painter.enableTileClippingMask(coord);
Expand Down
7 changes: 4 additions & 3 deletions src/shaders/line.vertex.glsl
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,6 @@ attribute vec4 a_data;

uniform mat4 u_matrix;
uniform mediump float u_ratio;
uniform mediump float u_width;
uniform vec2 u_gl_units_to_pixels;

varying vec2 v_normal;
Expand All @@ -29,13 +28,15 @@ varying float v_gamma_scale;
#pragma mapbox: define lowp float opacity
#pragma mapbox: define mediump float gapwidth
#pragma mapbox: define lowp float offset
#pragma mapbox: define mediump float width

void main() {
#pragma mapbox: initialize highp vec4 color
#pragma mapbox: initialize lowp float blur
#pragma mapbox: initialize lowp float opacity
#pragma mapbox: initialize mediump float gapwidth
#pragma mapbox: initialize lowp float offset
#pragma mapbox: initialize mediump float width

vec2 a_extrude = a_data.xy - 128.0;
float a_direction = mod(a_data.z, 4.0) - 1.0;
Expand All @@ -52,11 +53,11 @@ void main() {
// these transformations used to be applied in the JS and native code bases.
// moved them into the shader for clarity and simplicity.
gapwidth = gapwidth / 2.0;
float width = u_width / 2.0;
float halfwidth = width / 2.0;
offset = -1.0 * offset;

float inset = gapwidth + (gapwidth > 0.0 ? ANTIALIASING : 0.0);
float outset = gapwidth + width * (gapwidth > 0.0 ? 2.0 : 1.0) + ANTIALIASING;
float outset = gapwidth + halfwidth * (gapwidth > 0.0 ? 2.0 : 1.0) + ANTIALIASING;

// Scale the extrusion vector down to a normal and then up by the line width
// of this vertex.
Expand Down
7 changes: 4 additions & 3 deletions src/shaders/line_pattern.vertex.glsl
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,6 @@ attribute vec4 a_data;

uniform mat4 u_matrix;
uniform mediump float u_ratio;
uniform mediump float u_width;
uniform vec2 u_gl_units_to_pixels;

varying vec2 v_normal;
Expand All @@ -31,12 +30,14 @@ varying float v_gamma_scale;
#pragma mapbox: define lowp float opacity
#pragma mapbox: define lowp float offset
#pragma mapbox: define mediump float gapwidth
#pragma mapbox: define mediump float width

void main() {
#pragma mapbox: initialize lowp float blur
#pragma mapbox: initialize lowp float opacity
#pragma mapbox: initialize lowp float offset
#pragma mapbox: initialize mediump float gapwidth
#pragma mapbox: initialize mediump float width

vec2 a_extrude = a_data.xy - 128.0;
float a_direction = mod(a_data.z, 4.0) - 1.0;
Expand All @@ -53,11 +54,11 @@ void main() {
// these transformations used to be applied in the JS and native code bases.
// moved them into the shader for clarity and simplicity.
gapwidth = gapwidth / 2.0;
float width = u_width / 2.0;
float halfwidth = width / 2.0;
offset = -1.0 * offset;

float inset = gapwidth + (gapwidth > 0.0 ? ANTIALIASING : 0.0);
float outset = gapwidth + width * (gapwidth > 0.0 ? 2.0 : 1.0) + ANTIALIASING;
float outset = gapwidth + halfwidth * (gapwidth > 0.0 ? 2.0 : 1.0) + ANTIALIASING;

// Scale the extrusion vector down to a normal and then up by the line width
// of this vertex.
Expand Down
6 changes: 5 additions & 1 deletion src/shaders/line_sdf.fragment.glsl
Original file line number Diff line number Diff line change
Expand Up @@ -12,11 +12,15 @@ varying float v_gamma_scale;
#pragma mapbox: define highp vec4 color
#pragma mapbox: define lowp float blur
#pragma mapbox: define lowp float opacity
#pragma mapbox: define mediump float width
#pragma mapbox: define lowp float floorwidth

void main() {
#pragma mapbox: initialize highp vec4 color
#pragma mapbox: initialize lowp float blur
#pragma mapbox: initialize lowp float opacity
#pragma mapbox: initialize mediump float width
#pragma mapbox: initialize lowp float floorwidth

// Calculate the distance of the pixel from the line in pixels.
float dist = length(v_normal) * v_width2.s;
Expand All @@ -30,7 +34,7 @@ void main() {
float sdfdist_a = texture2D(u_image, v_tex_a).a;
float sdfdist_b = texture2D(u_image, v_tex_b).a;
float sdfdist = mix(sdfdist_a, sdfdist_b, u_mix);
alpha *= smoothstep(0.5 - u_sdfgamma, 0.5 + u_sdfgamma, sdfdist);
alpha *= smoothstep(0.5 - u_sdfgamma / floorwidth, 0.5 + u_sdfgamma / floorwidth, sdfdist);

gl_FragColor = color * (alpha * opacity);

Expand Down
13 changes: 8 additions & 5 deletions src/shaders/line_sdf.vertex.glsl
Original file line number Diff line number Diff line change
Expand Up @@ -24,7 +24,6 @@ uniform float u_tex_y_a;
uniform vec2 u_patternscale_b;
uniform float u_tex_y_b;
uniform vec2 u_gl_units_to_pixels;
uniform mediump float u_width;

varying vec2 v_normal;
varying vec2 v_width2;
Expand All @@ -37,13 +36,17 @@ varying float v_gamma_scale;
#pragma mapbox: define lowp float opacity
#pragma mapbox: define mediump float gapwidth
#pragma mapbox: define lowp float offset
#pragma mapbox: define mediump float width
#pragma mapbox: define lowp float floorwidth

void main() {
#pragma mapbox: initialize highp vec4 color
#pragma mapbox: initialize lowp float blur
#pragma mapbox: initialize lowp float opacity
#pragma mapbox: initialize mediump float gapwidth
#pragma mapbox: initialize lowp float offset
#pragma mapbox: initialize mediump float width
#pragma mapbox: initialize lowp float floorwidth

vec2 a_extrude = a_data.xy - 128.0;
float a_direction = mod(a_data.z, 4.0) - 1.0;
Expand All @@ -60,11 +63,11 @@ void main() {
// these transformations used to be applied in the JS and native code bases.
// moved them into the shader for clarity and simplicity.
gapwidth = gapwidth / 2.0;
float width = u_width / 2.0;
float halfwidth = width / 2.0;
offset = -1.0 * offset;

float inset = gapwidth + (gapwidth > 0.0 ? ANTIALIASING : 0.0);
float outset = gapwidth + width * (gapwidth > 0.0 ? 2.0 : 1.0) + ANTIALIASING;
float outset = gapwidth + halfwidth * (gapwidth > 0.0 ? 2.0 : 1.0) + ANTIALIASING;

// Scale the extrusion vector down to a normal and then up by the line width
// of this vertex.
Expand All @@ -89,8 +92,8 @@ void main() {
float extrude_length_with_perspective = length(projected_extrude.xy / gl_Position.w * u_gl_units_to_pixels);
v_gamma_scale = extrude_length_without_perspective / extrude_length_with_perspective;

v_tex_a = vec2(a_linesofar * u_patternscale_a.x, normal.y * u_patternscale_a.y + u_tex_y_a);
v_tex_b = vec2(a_linesofar * u_patternscale_b.x, normal.y * u_patternscale_b.y + u_tex_y_b);
v_tex_a = vec2(a_linesofar * u_patternscale_a.x / floorwidth, normal.y * u_patternscale_a.y + u_tex_y_a);
v_tex_b = vec2(a_linesofar * u_patternscale_b.x / floorwidth, normal.y * u_patternscale_b.y + u_tex_y_b);

v_width2 = vec2(outset, inset);
}
1 change: 1 addition & 0 deletions src/style-spec/reference/v8.json
Original file line number Diff line number Diff line change
Expand Up @@ -2191,6 +2191,7 @@
"minimum": 0,
"function": "interpolated",
"zoom-function": true,
"property-function": true,
"transition": true,
"units": "pixels",
"doc": "Stroke thickness.",
Expand Down
17 changes: 0 additions & 17 deletions src/style/style_layer/line_style_layer.js
Original file line number Diff line number Diff line change
Expand Up @@ -2,25 +2,8 @@

const StyleLayer = require('../style_layer');
const LineBucket = require('../../data/bucket/line_bucket');
const util = require('../../util/util');

class LineStyleLayer extends StyleLayer {

getPaintValue(name, globalProperties, featureProperties) {
const value = super.getPaintValue(name, globalProperties, featureProperties);

// If the line is dashed, scale the dash lengths by the line
// width at the previous round zoom level.
if (value && name === 'line-dasharray') {
const width = this.getPaintValue('line-width',
util.extend({}, globalProperties, {zoom: Math.floor(globalProperties.zoom)}), featureProperties);
value.fromScale *= width;
value.toScale *= width;
}

return value;
}

createBucket(options) {
return new LineBucket(options);
}
Expand Down
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Original file line number Diff line number Diff line change
@@ -0,0 +1,152 @@
{
"version": 8,
"metadata": {
"test": {
"width": 64,
"height": 64
}
},
"zoom": 0.5,
"sources": {
"geojson": {
"type": "geojson",
"data": {
"type": "FeatureCollection",
"features": [
{
"type": "Feature",
"properties": {
"property": 1
},
"geometry": {
"type": "LineString",
"coordinates": [
[
-10,
-5
],
[
10,
-5
]
]
}
},
{
"type": "Feature",
"properties": {
"property": 2
},
"geometry": {
"type": "LineString",
"coordinates": [
[
-10,
0
],
[
10,
0
]
]
}
},
{
"type": "Feature",
"properties": {
"property": 3
},
"geometry": {
"type": "LineString",
"coordinates": [
[
-10,
5
],
[
10,
5
]
]
}
}
]
}
}
},
"layers": [
{
"id": "road",
"type": "line",
"source": "geojson",
"paint": {
"line-width": {
"property": "property",
"type": "categorical",
"stops": [
[
{
"zoom": 0,
"value": 1
},
1
],
[
{
"zoom": 0,
"value": 2
},
2
],
[
{
"zoom": 0,
"value": 3
},
3
],
[
{
"zoom": 1,
"value": 1
},
4
],
[
{
"zoom": 1,
"value": 2
},
5
],
[
{
"zoom": 1,
"value": 3
},
6
]
]
},
"line-dasharray": {
"stops": [
[
0,
[
1,
1
]
],
[
1,
[
2,
1
]
]
]
}
}
}
]
}
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading

3 comments on commit 09bec65

@gagecarto
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@lbud - This is going to be a really useful feature - Is there anyway for me to use it asap before the next version is released? I have a project wrapping up where it would really add value

@mollymerp
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@gagecarto we just released v0.39.0 !

@gagecarto
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

That's great! You all rock - 🤘🤘🤘

Please sign in to comment.