diff --git a/src/data/array_types.js b/src/data/array_types.js index 0b72a45e9c2..92591d3d910 100644 --- a/src/data/array_types.js +++ b/src/data/array_types.js @@ -1169,7 +1169,7 @@ export { StructArrayLayout4i8 as FillExtrusionLayoutArray, StructArrayLayout2i4 as HeatmapLayoutArray, StructArrayLayout2i4ub1f12 as LineLayoutArray, - StructArrayLayout2f8 as LineExtLayoutArray, + StructArrayLayout3f12 as LineExtLayoutArray, StructArrayLayout10ui20 as PatternLayoutArray, StructArrayLayout8ui16 as DashLayoutArray, StructArrayLayout4i4ui4i24 as SymbolLayoutArray, diff --git a/src/data/bucket/line_attributes_ext.js b/src/data/bucket/line_attributes_ext.js index 22f6891f976..bdc230ef4cf 100644 --- a/src/data/bucket/line_attributes_ext.js +++ b/src/data/bucket/line_attributes_ext.js @@ -2,8 +2,7 @@ import {createLayout} from '../../util/struct_array.js'; const lineLayoutAttributesExt = createLayout([ - {name: 'a_uv_x', components: 1, type: 'Float32'}, - {name: 'a_split_index', components: 1, type: 'Float32'}, + {name: 'a_packed', components: 3, type: 'Float32'} ]); export default lineLayoutAttributesExt; diff --git a/src/data/bucket/line_bucket.js b/src/data/bucket/line_bucket.js index 13ce96de051..4dfd299598c 100644 --- a/src/data/bucket/line_bucket.js +++ b/src/data/bucket/line_bucket.js @@ -621,7 +621,7 @@ class LineBucket implements Bucket { // Constructs a second vertex buffer with higher precision line progress if (this.lineClips) { - this.layoutVertexArray2.emplaceBack(this.scaledDistance, this.lineClipsArray.length); + this.layoutVertexArray2.emplaceBack(this.scaledDistance, this.lineClipsArray.length, this.lineSoFar); } const e = segment.vertexLength++; diff --git a/src/render/draw_line.js b/src/render/draw_line.js index 381f36e6808..4a9da385509 100644 --- a/src/render/draw_line.js +++ b/src/render/draw_line.js @@ -6,8 +6,7 @@ import Texture from './texture.js'; import { lineUniformValues, linePatternUniformValues, - lineSDFUniformValues, - lineGradientUniformValues + lineDefinesValues } from './program/line_program.js'; import type Painter from './painter.js'; @@ -15,6 +14,7 @@ import type SourceCache from '../source/source_cache.js'; import type LineStyleLayer from '../style/style_layer/line_style_layer.js'; import type LineBucket from '../data/bucket/line_bucket.js'; import type {OverscaledTileID} from '../source/tile_id.js'; +import type {DynamicDefinesType} from './program/program_uniforms.js'; import {clamp, nextPowerOfTwo} from '../util/util.js'; import {renderColorRamp} from '../util/color_ramp.js'; import EXTENT from '../data/extent.js'; @@ -38,10 +38,7 @@ export default function drawLine(painter: Painter, sourceCache: SourceCache, lay const gradient = layer.paint.get('line-gradient'); const crossfade = layer.getCrossfadeParameters(); - const programId = - image ? 'linePattern' : - dasharray ? 'lineSDF' : - gradient ? 'lineGradient' : 'line'; + const programId = image ? 'linePattern' : 'line'; const context = painter.context; const gl = context.gl; @@ -55,7 +52,8 @@ export default function drawLine(painter: Painter, sourceCache: SourceCache, lay painter.prepareDrawTile(coord); const programConfiguration = bucket.programConfigurations.get(layer.id); - const program = painter.useProgram(programId, programConfiguration); + const definesValues = lineDefinesValues(layer); + const program = painter.useProgram(programId, programConfiguration, ((definesValues: any): DynamicDefinesType[])); const constantPattern = patternProperty.constantOr(null); if (constantPattern && tile.imageAtlas) { @@ -76,20 +74,11 @@ export default function drawLine(painter: Painter, sourceCache: SourceCache, lay } const matrix = painter.terrain ? coord.projMatrix : null; - const uniformValues = image ? linePatternUniformValues(painter, tile, layer, crossfade, matrix) : - dasharray ? lineSDFUniformValues(painter, tile, layer, crossfade, matrix) : - gradient ? lineGradientUniformValues(painter, tile, layer, matrix, bucket.lineClipsArray.length) : - lineUniformValues(painter, tile, layer, matrix); + const uniformValues = image ? + linePatternUniformValues(painter, tile, layer, crossfade, matrix) : + lineUniformValues(painter, tile, layer, crossfade, matrix, bucket.lineClipsArray.length); - if (image) { - context.activeTexture.set(gl.TEXTURE0); - tile.imageAtlasTexture.bind(gl.LINEAR, gl.CLAMP_TO_EDGE); - programConfiguration.updatePaintBuffers(crossfade); - } else if (dasharray) { - context.activeTexture.set(gl.TEXTURE0); - tile.lineAtlasTexture.bind(gl.LINEAR, gl.REPEAT); - programConfiguration.updatePaintBuffers(crossfade); - } else if (gradient) { + if (gradient) { const layerGradient = bucket.gradients[layer.id]; let gradientTexture = layerGradient.texture; if (layer.gradientVersion !== layerGradient.version) { @@ -120,9 +109,19 @@ export default function drawLine(painter: Painter, sourceCache: SourceCache, lay layerGradient.version = layer.gradientVersion; gradientTexture = layerGradient.texture; } - context.activeTexture.set(gl.TEXTURE0); + context.activeTexture.set(gl.TEXTURE1); gradientTexture.bind(layer.stepInterpolant ? gl.NEAREST : gl.LINEAR, gl.CLAMP_TO_EDGE); } + if (dasharray) { + context.activeTexture.set(gl.TEXTURE0); + tile.lineAtlasTexture.bind(gl.LINEAR, gl.REPEAT); + programConfiguration.updatePaintBuffers(crossfade); + } + if (image) { + context.activeTexture.set(gl.TEXTURE0); + tile.imageAtlasTexture.bind(gl.LINEAR, gl.CLAMP_TO_EDGE); + programConfiguration.updatePaintBuffers(crossfade); + } painter.prepareDrawProgram(context, program, coord.toUnwrapped()); diff --git a/src/render/program/line_program.js b/src/render/program/line_program.js index 49db11f119a..804e2b1b672 100644 --- a/src/render/program/line_program.js +++ b/src/render/program/line_program.js @@ -8,7 +8,6 @@ import { UniformMatrix4f } from '../uniform_binding.js'; import pixelsToTileUnits from '../../source/pixels_to_tile_units.js'; -import {extend} from '../../util/util.js'; import browser from '../../util/browser.js'; import type Context from '../../gl/context.js'; @@ -20,19 +19,16 @@ import type Painter from '../painter.js'; import type {CrossfadeParameters} from '../../style/evaluation_parameters.js'; export type LineUniformsType = {| - 'u_matrix': UniformMatrix4f, - 'u_ratio': Uniform1f, - 'u_device_pixel_ratio': Uniform1f, - 'u_units_to_pixels': Uniform2f -|}; - -export type LineGradientUniformsType = {| 'u_matrix': UniformMatrix4f, 'u_ratio': Uniform1f, 'u_device_pixel_ratio': Uniform1f, 'u_units_to_pixels': Uniform2f, - 'u_image': Uniform1i, + 'u_dash_image': Uniform1i, + 'u_gradient_image': Uniform1i, 'u_image_height': Uniform1f, + 'u_texsize': Uniform2f, + 'u_scale': Uniform3f, + 'u_mix': Uniform1f |}; export type LinePatternUniformsType = {| @@ -46,31 +42,19 @@ export type LinePatternUniformsType = {| 'u_fade': Uniform1f |}; -export type LineSDFUniformsType = {| - 'u_matrix': UniformMatrix4f, - 'u_texsize': Uniform2f, - 'u_ratio': Uniform1f, - 'u_device_pixel_ratio': Uniform1f, - 'u_units_to_pixels': Uniform2f, - 'u_scale': Uniform3f, - 'u_image': Uniform1i, - 'u_mix': Uniform1f -|}; +export type LineDefinesType = 'RENDER_LINE_GRADIENT' | 'RENDER_LINE_DASH'; const lineUniforms = (context: Context, locations: UniformLocations): LineUniformsType => ({ - 'u_matrix': new UniformMatrix4f(context, locations.u_matrix), - 'u_ratio': new Uniform1f(context, locations.u_ratio), - 'u_device_pixel_ratio': new Uniform1f(context, locations.u_device_pixel_ratio), - 'u_units_to_pixels': new Uniform2f(context, locations.u_units_to_pixels) -}); - -const lineGradientUniforms = (context: Context, locations: UniformLocations): LineGradientUniformsType => ({ 'u_matrix': new UniformMatrix4f(context, locations.u_matrix), 'u_ratio': new Uniform1f(context, locations.u_ratio), 'u_device_pixel_ratio': new Uniform1f(context, locations.u_device_pixel_ratio), 'u_units_to_pixels': new Uniform2f(context, locations.u_units_to_pixels), - 'u_image': new Uniform1i(context, locations.u_image), + 'u_dash_image': new Uniform1i(context, locations.u_dash_image), + 'u_gradient_image': new Uniform1i(context, locations.u_gradient_image), 'u_image_height': new Uniform1f(context, locations.u_image_height), + 'u_texsize': new Uniform2f(context, locations.u_texsize), + 'u_scale': new Uniform3f(context, locations.u_scale), + 'u_mix': new Uniform1f(context, locations.u_mix) }); const linePatternUniforms = (context: Context, locations: UniformLocations): LinePatternUniformsType => ({ @@ -84,47 +68,37 @@ const linePatternUniforms = (context: Context, locations: UniformLocations): Lin 'u_fade': new Uniform1f(context, locations.u_fade) }); -const lineSDFUniforms = (context: Context, locations: UniformLocations): LineSDFUniformsType => ({ - 'u_matrix': new UniformMatrix4f(context, locations.u_matrix), - 'u_texsize': new Uniform2f(context, locations.u_texsize), - 'u_ratio': new Uniform1f(context, locations.u_ratio), - 'u_device_pixel_ratio': new Uniform1f(context, locations.u_device_pixel_ratio), - 'u_units_to_pixels': new Uniform2f(context, locations.u_units_to_pixels), - 'u_image': new Uniform1i(context, locations.u_image), - 'u_scale': new Uniform3f(context, locations.u_scale), - 'u_mix': new Uniform1f(context, locations.u_mix) -}); - const lineUniformValues = ( painter: Painter, tile: Tile, layer: LineStyleLayer, - matrix: ?Float32Array + crossfade: CrossfadeParameters, + matrix: ?Float32Array, + imageHeight: number ): UniformValues => { const transform = painter.transform; - - return { + const values = { 'u_matrix': calculateMatrix(painter, tile, layer, matrix), 'u_ratio': 1 / pixelsToTileUnits(tile, 1, transform.zoom), 'u_device_pixel_ratio': browser.devicePixelRatio, 'u_units_to_pixels': [ 1 / transform.pixelsToGLUnits[0], 1 / transform.pixelsToGLUnits[1] - ] - }; -}; - -const lineGradientUniformValues = ( - painter: Painter, - tile: Tile, - layer: LineStyleLayer, - matrix: ?Float32Array, - imageHeight: number -): UniformValues => { - return extend(lineUniformValues(painter, tile, layer, matrix), { - 'u_image': 0, + ], + 'u_dash_image': 0, + 'u_gradient_image': 1, 'u_image_height': imageHeight, - }); + 'u_texsize': [0, 0], + 'u_scale': [0, 0, 0], + 'u_mix': 0 + }; + if (hasDash(layer)) { + const tileZoomRatio = calculateTileRatio(tile, painter.transform); + values['u_texsize'] = tile.lineAtlasTexture.size; + values['u_scale'] = [tileZoomRatio, crossfade.fromScale, crossfade.toScale]; + values['u_mix'] = crossfade.t; + } + return values; }; const linePatternUniformValues = ( @@ -152,22 +126,6 @@ const linePatternUniformValues = ( }; }; -const lineSDFUniformValues = ( - painter: Painter, - tile: Tile, - layer: LineStyleLayer, - crossfade: CrossfadeParameters, - matrix: ?Float32Array -): UniformValues => { - const tileZoomRatio = calculateTileRatio(tile, painter.transform); - return extend(lineUniformValues(painter, tile, layer, matrix), { - 'u_texsize': tile.lineAtlasTexture.size, - 'u_scale': [tileZoomRatio, crossfade.fromScale, crossfade.toScale], - 'u_image': 0, - 'u_mix': crossfade.t - }); -}; - function calculateTileRatio(tile: Tile, transform: Transform) { return 1 / pixelsToTileUnits(tile, 1, transform.tileZoom); } @@ -181,13 +139,22 @@ function calculateMatrix(painter, tile, layer, matrix) { ); } +const lineDefinesValues = (layer: LineStyleLayer): LineDefinesType[] => { + const values = []; + if (hasDash(layer)) values.push('RENDER_LINE_DASH'); + if (layer.paint.get('line-gradient')) values.push('RENDER_LINE_GRADIENT'); + return values; +}; + +function hasDash(layer) { + const dashPropertyValue = layer.paint.get('line-dasharray').value; + return dashPropertyValue.value || dashPropertyValue.kind !== "constant"; +} + export { lineUniforms, - lineGradientUniforms, linePatternUniforms, - lineSDFUniforms, lineUniformValues, - lineGradientUniformValues, linePatternUniformValues, - lineSDFUniformValues + lineDefinesValues }; diff --git a/src/render/program/program_uniforms.js b/src/render/program/program_uniforms.js index 03df1ddd7a7..c97a369aa4c 100644 --- a/src/render/program/program_uniforms.js +++ b/src/render/program/program_uniforms.js @@ -2,6 +2,7 @@ import type {CircleDefinesType} from './circle_program.js'; import type {SymbolDefinesType} from './symbol_program.js'; +import type {LineDefinesType} from './line_program.js'; import {fillExtrusionUniforms, fillExtrusionPatternUniforms} from './fill_extrusion_program.js'; import {fillUniforms, fillPatternUniforms, fillOutlineUniforms, fillOutlinePatternUniforms} from './fill_program.js'; import {circleUniforms} from './circle_program.js'; @@ -10,7 +11,7 @@ import {debugUniforms} from './debug_program.js'; import {clippingMaskUniforms} from './clipping_mask_program.js'; import {heatmapUniforms, heatmapTextureUniforms} from './heatmap_program.js'; import {hillshadeUniforms, hillshadePrepareUniforms} from './hillshade_program.js'; -import {lineUniforms, lineGradientUniforms, linePatternUniforms, lineSDFUniforms} from './line_program.js'; +import {lineUniforms, linePatternUniforms} from './line_program.js'; import {rasterUniforms} from './raster_program.js'; import {symbolIconUniforms, symbolSDFUniforms, symbolTextAndIconUniforms} from './symbol_program.js'; import {backgroundUniforms, backgroundPatternUniforms} from './background_program.js'; @@ -18,7 +19,7 @@ import {terrainRasterUniforms} from '../../terrain/terrain_raster_program.js'; import {skyboxUniforms, skyboxGradientUniforms} from './skybox_program.js'; import {skyboxCaptureUniforms} from './skybox_capture_program.js'; -export type DynamicDefinesType = CircleDefinesType | SymbolDefinesType; +export type DynamicDefinesType = CircleDefinesType | SymbolDefinesType | LineDefinesType; export const programUniforms = { fillExtrusion: fillExtrusionUniforms, @@ -37,9 +38,7 @@ export const programUniforms = { hillshade: hillshadeUniforms, hillshadePrepare: hillshadePrepareUniforms, line: lineUniforms, - lineGradient: lineGradientUniforms, linePattern: linePatternUniforms, - lineSDF: lineSDFUniforms, raster: rasterUniforms, symbolIcon: symbolIconUniforms, symbolSDF: symbolSDFUniforms, diff --git a/src/shaders/line.fragment.glsl b/src/shaders/line.fragment.glsl index 33a55c25b71..42b1b738d70 100644 --- a/src/shaders/line.fragment.glsl +++ b/src/shaders/line.fragment.glsl @@ -4,12 +4,31 @@ varying vec2 v_width2; varying vec2 v_normal; varying float v_gamma_scale; +#ifdef RENDER_LINE_DASH +uniform sampler2D u_dash_image; +uniform float u_mix; +uniform vec3 u_scale; +varying vec2 v_tex_a; +varying vec2 v_tex_b; +#endif + +#ifdef RENDER_LINE_GRADIENT +uniform sampler2D u_gradient_image; +varying highp vec2 v_uv; +#endif + #pragma mapbox: define highp vec4 color +#pragma mapbox: define lowp float floorwidth +#pragma mapbox: define lowp vec4 dash_from +#pragma mapbox: define lowp vec4 dash_to #pragma mapbox: define lowp float blur #pragma mapbox: define lowp float opacity void main() { #pragma mapbox: initialize highp vec4 color + #pragma mapbox: initialize lowp float floorwidth + #pragma mapbox: initialize lowp vec4 dash_from + #pragma mapbox: initialize lowp vec4 dash_to #pragma mapbox: initialize lowp float blur #pragma mapbox: initialize lowp float opacity @@ -22,7 +41,22 @@ void main() { float blur2 = (blur + 1.0 / u_device_pixel_ratio) * v_gamma_scale; float alpha = clamp(min(dist - (v_width2.t - blur2), v_width2.s - dist) / blur2, 0.0, 1.0); +#ifdef RENDER_LINE_DASH + float sdfdist_a = texture2D(u_dash_image, v_tex_a).a; + float sdfdist_b = texture2D(u_dash_image, v_tex_b).a; + float sdfdist = mix(sdfdist_a, sdfdist_b, u_mix); + float sdfwidth = min(dash_from.z * u_scale.y, dash_to.z * u_scale.z); + float sdfgamma = 1.0 / (2.0 * u_device_pixel_ratio) / sdfwidth; + alpha *= smoothstep(0.5 - sdfgamma / floorwidth, 0.5 + sdfgamma / floorwidth, sdfdist); +#endif + +#ifdef RENDER_LINE_GRADIENT + // For gradient lines, v_lineprogress is the ratio along the + // entire line, the gradient ramp is stored in a texture. + vec4 out_color = texture2D(u_gradient_image, v_uv); +#else vec4 out_color = color; +#endif #ifdef FOG out_color = fog_dither(fog_apply_premultiplied(out_color, v_fog_pos)); diff --git a/src/shaders/line.vertex.glsl b/src/shaders/line.vertex.glsl index a5efc9018ee..06287c1fd2a 100644 --- a/src/shaders/line.vertex.glsl +++ b/src/shaders/line.vertex.glsl @@ -4,11 +4,19 @@ // there are also "special" normals that have a bigger length (of up to 126 in // this case). // #define scale 63.0 -#define scale 0.015873016 +#define EXTRUDE_SCALE 0.015873016 attribute vec2 a_pos_normal; attribute vec4 a_data; +#ifdef RENDER_LINE_GRADIENT +// Includes in order: a_uv_x, a_split_index, a_linesofar +// to reduce attribute count on older devices +attribute vec3 a_packed; +#else +attribute float a_linesofar; +#endif + uniform mat4 u_matrix; uniform mediump float u_ratio; uniform vec2 u_units_to_pixels; @@ -18,7 +26,22 @@ varying vec2 v_normal; varying vec2 v_width2; varying float v_gamma_scale; +#ifdef RENDER_LINE_DASH +uniform vec2 u_texsize; +uniform mediump vec3 u_scale; +varying vec2 v_tex_a; +varying vec2 v_tex_b; +#endif + +#ifdef RENDER_LINE_GRADIENT +uniform float u_image_height; +varying highp vec2 v_uv; +#endif + #pragma mapbox: define highp vec4 color +#pragma mapbox: define lowp float floorwidth +#pragma mapbox: define lowp vec4 dash_from +#pragma mapbox: define lowp vec4 dash_to #pragma mapbox: define lowp float blur #pragma mapbox: define lowp float opacity #pragma mapbox: define mediump float gapwidth @@ -27,6 +50,9 @@ varying float v_gamma_scale; void main() { #pragma mapbox: initialize highp vec4 color + #pragma mapbox: initialize lowp float floorwidth + #pragma mapbox: initialize lowp vec4 dash_from + #pragma mapbox: initialize lowp vec4 dash_to #pragma mapbox: initialize lowp float blur #pragma mapbox: initialize lowp float opacity #pragma mapbox: initialize mediump float gapwidth @@ -59,7 +85,7 @@ void main() { // Scale the extrusion vector down to a normal and then up by the line width // of this vertex. - mediump vec2 dist = outset * a_extrude * scale; + mediump vec2 dist = outset * a_extrude * EXTRUDE_SCALE; // Calculate the offset when drawing a line that is to the side of the actual line. // We do this by creating a vector that points towards the extrude, but rotate @@ -67,7 +93,7 @@ void main() { // extrude vector points in another direction. mediump float u = 0.5 * a_direction; mediump float t = 1.0 - abs(u); - mediump vec2 offset2 = offset * a_extrude * scale * normal.y * mat2(t, -u, u, t); + mediump vec2 offset2 = offset * a_extrude * EXTRUDE_SCALE * normal.y * mat2(t, -u, u, t); vec4 projected_extrude = u_matrix * vec4(dist / u_ratio, 0.0, 0.0); gl_Position = u_matrix * vec4(pos + offset2 / u_ratio, 0.0, 1.0) + projected_extrude; @@ -80,6 +106,30 @@ void main() { #else v_gamma_scale = 1.0; #endif + +#ifdef RENDER_LINE_GRADIENT + float a_uv_x = a_packed[0]; + float a_split_index = a_packed[1]; + float a_linesofar = a_packed[2]; + highp float texel_height = 1.0 / u_image_height; + highp float half_texel_height = 0.5 * texel_height; + v_uv = vec2(a_uv_x, a_split_index * texel_height - half_texel_height); +#endif + +#ifdef RENDER_LINE_DASH + float tileZoomRatio = u_scale.x; + float fromScale = u_scale.y; + float toScale = u_scale.z; + + float scaleA = dash_from.z == 0.0 ? 0.0 : tileZoomRatio / (dash_from.z * fromScale); + float scaleB = dash_to.z == 0.0 ? 0.0 : tileZoomRatio / (dash_to.z * toScale); + float heightA = dash_from.y; + float heightB = dash_to.y; + + v_tex_a = vec2(a_linesofar * scaleA / floorwidth, (-normal.y * heightA + dash_from.x + 0.5) / u_texsize.y); + v_tex_b = vec2(a_linesofar * scaleB / floorwidth, (-normal.y * heightB + dash_to.x + 0.5) / u_texsize.y); +#endif + v_width2 = vec2(outset, inset); #ifdef FOG diff --git a/src/shaders/line_gradient.fragment.glsl b/src/shaders/line_gradient.fragment.glsl deleted file mode 100644 index 3bb04a5216c..00000000000 --- a/src/shaders/line_gradient.fragment.glsl +++ /dev/null @@ -1,38 +0,0 @@ -uniform lowp float u_device_pixel_ratio; -uniform sampler2D u_image; - -varying vec2 v_width2; -varying vec2 v_normal; -varying float v_gamma_scale; -varying highp vec2 v_uv; - -#pragma mapbox: define lowp float blur -#pragma mapbox: define lowp float opacity - -void main() { - #pragma mapbox: initialize lowp float blur - #pragma mapbox: initialize lowp float opacity - - // Calculate the distance of the pixel from the line in pixels. - float dist = length(v_normal) * v_width2.s; - - // Calculate the antialiasing fade factor. This is either when fading in - // the line in case of an offset line (v_width2.t) or when fading out - // (v_width2.s) - float blur2 = (blur + 1.0 / u_device_pixel_ratio) * v_gamma_scale; - float alpha = clamp(min(dist - (v_width2.t - blur2), v_width2.s - dist) / blur2, 0.0, 1.0); - - // For gradient lines, v_lineprogress is the ratio along the - // entire line, the gradient ramp is stored in a texture. - vec4 color = texture2D(u_image, v_uv); - -#ifdef FOG - color = fog_dither(fog_apply_premultiplied(color, v_fog_pos)); -#endif - - gl_FragColor = color * (alpha * opacity); - -#ifdef OVERDRAW_INSPECTOR - gl_FragColor = vec4(1.0); -#endif -} diff --git a/src/shaders/line_gradient.vertex.glsl b/src/shaders/line_gradient.vertex.glsl deleted file mode 100644 index a36b6aaae59..00000000000 --- a/src/shaders/line_gradient.vertex.glsl +++ /dev/null @@ -1,95 +0,0 @@ -// floor(127 / 2) == 63.0 -// the maximum allowed miter limit is 2.0 at the moment. the extrude normal is -// stored in a byte (-128..127). we scale regular normals up to length 63, but -// there are also "special" normals that have a bigger length (of up to 126 in -// this case). -// #define scale 63.0 -#define scale 0.015873016 - -attribute vec2 a_pos_normal; -attribute vec4 a_data; -attribute float a_uv_x; -attribute float a_split_index; - -uniform mat4 u_matrix; -uniform mediump float u_ratio; -uniform lowp float u_device_pixel_ratio; -uniform vec2 u_units_to_pixels; -uniform float u_image_height; - -varying vec2 v_normal; -varying vec2 v_width2; -varying float v_gamma_scale; -varying highp vec2 v_uv; - -#pragma mapbox: define lowp float blur -#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 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 - - // the distance over which the line edge fades out. - // Retina devices need a smaller distance to avoid aliasing. - float ANTIALIASING = 1.0 / u_device_pixel_ratio / 2.0; - - vec2 a_extrude = a_data.xy - 128.0; - float a_direction = mod(a_data.z, 4.0) - 1.0; - - highp float texel_height = 1.0 / u_image_height; - highp float half_texel_height = 0.5 * texel_height; - v_uv = vec2(a_uv_x, a_split_index * texel_height - half_texel_height); - - vec2 pos = floor(a_pos_normal * 0.5); - - // x is 1 if it's a round cap, 0 otherwise - // y is 1 if the normal points up, and -1 if it points down - // We store these in the least significant bit of a_pos_normal - mediump vec2 normal = a_pos_normal - 2.0 * pos; - normal.y = normal.y * 2.0 - 1.0; - v_normal = normal; - - // 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 halfwidth = width / 2.0; - offset = -1.0 * offset; - - float inset = gapwidth + (gapwidth > 0.0 ? ANTIALIASING : 0.0); - float outset = gapwidth + halfwidth * (gapwidth > 0.0 ? 2.0 : 1.0) + (halfwidth == 0.0 ? 0.0 : ANTIALIASING); - - // Scale the extrusion vector down to a normal and then up by the line width - // of this vertex. - mediump vec2 dist = outset * a_extrude * scale; - - // Calculate the offset when drawing a line that is to the side of the actual line. - // We do this by creating a vector that points towards the extrude, but rotate - // it when we're drawing round end points (a_direction = -1 or 1) since their - // extrude vector points in another direction. - mediump float u = 0.5 * a_direction; - mediump float t = 1.0 - abs(u); - mediump vec2 offset2 = offset * a_extrude * scale * normal.y * mat2(t, -u, u, t); - - vec4 projected_extrude = u_matrix * vec4(dist / u_ratio, 0.0, 0.0); - gl_Position = u_matrix * vec4(pos + offset2 / u_ratio, 0.0, 1.0) + projected_extrude; - -#ifndef RENDER_TO_TEXTURE - // calculate how much the perspective view squishes or stretches the extrude - float extrude_length_without_perspective = length(dist); - float extrude_length_with_perspective = length(projected_extrude.xy / gl_Position.w * u_units_to_pixels); - v_gamma_scale = extrude_length_without_perspective / extrude_length_with_perspective; -#else - v_gamma_scale = 1.0; -#endif - v_width2 = vec2(outset, inset); - -#ifdef FOG - v_fog_pos = fog_position(pos); -#endif -} diff --git a/src/shaders/line_sdf.fragment.glsl b/src/shaders/line_sdf.fragment.glsl deleted file mode 100644 index e32fda3e185..00000000000 --- a/src/shaders/line_sdf.fragment.glsl +++ /dev/null @@ -1,57 +0,0 @@ - -uniform lowp float u_device_pixel_ratio; -uniform sampler2D u_image; -uniform float u_mix; -uniform vec3 u_scale; - -varying vec2 v_normal; -varying vec2 v_width2; -varying vec2 v_tex_a; -varying vec2 v_tex_b; -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 -#pragma mapbox: define lowp vec4 dash_from -#pragma mapbox: define lowp vec4 dash_to - -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 - #pragma mapbox: initialize mediump vec4 dash_from - #pragma mapbox: initialize mediump vec4 dash_to - - // Calculate the distance of the pixel from the line in pixels. - float dist = length(v_normal) * v_width2.s; - - // Calculate the antialiasing fade factor. This is either when fading in - // the line in case of an offset line (v_width2.t) or when fading out - // (v_width2.s) - float blur2 = (blur + 1.0 / u_device_pixel_ratio) * v_gamma_scale; - float alpha = clamp(min(dist - (v_width2.t - blur2), v_width2.s - dist) / blur2, 0.0, 1.0); - - 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); - float sdfwidth = min(dash_from.z * u_scale.y, dash_to.z * u_scale.z); - float sdfgamma = 1.0 / (2.0 * u_device_pixel_ratio) / sdfwidth; - alpha *= smoothstep(0.5 - sdfgamma / floorwidth, 0.5 + sdfgamma / floorwidth, sdfdist); - - vec4 out_color = color; - -#ifdef FOG - out_color = fog_dither(fog_apply_premultiplied(out_color, v_fog_pos)); -#endif - - gl_FragColor = out_color * (alpha * opacity); - -#ifdef OVERDRAW_INSPECTOR - gl_FragColor = vec4(1.0); -#endif -} diff --git a/src/shaders/line_sdf.vertex.glsl b/src/shaders/line_sdf.vertex.glsl deleted file mode 100644 index 458e762d345..00000000000 --- a/src/shaders/line_sdf.vertex.glsl +++ /dev/null @@ -1,114 +0,0 @@ -// floor(127 / 2) == 63.0 -// the maximum allowed miter limit is 2.0 at the moment. the extrude normal is -// stored in a byte (-128..127). we scale regular normals up to length 63, but -// there are also "special" normals that have a bigger length (of up to 126 in -// this case). -// #define scale 63.0 -#define EXTRUDE_SCALE 0.015873016 - -attribute vec2 a_pos_normal; -attribute vec4 a_data; -attribute float a_linesofar; - -uniform mat4 u_matrix; -uniform mediump float u_ratio; -uniform lowp float u_device_pixel_ratio; -uniform vec2 u_units_to_pixels; - -uniform vec2 u_texsize; -uniform mediump vec3 u_scale; - -varying vec2 v_normal; -varying vec2 v_width2; -varying vec2 v_tex_a; -varying vec2 v_tex_b; -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 gapwidth -#pragma mapbox: define lowp float offset -#pragma mapbox: define mediump float width -#pragma mapbox: define lowp float floorwidth -#pragma mapbox: define lowp vec4 dash_from -#pragma mapbox: define lowp vec4 dash_to - -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 - #pragma mapbox: initialize mediump vec4 dash_from - #pragma mapbox: initialize mediump vec4 dash_to - - // the distance over which the line edge fades out. - // Retina devices need a smaller distance to avoid aliasing. - float ANTIALIASING = 1.0 / u_device_pixel_ratio / 2.0; - - vec2 a_extrude = a_data.xy - 128.0; - float a_direction = mod(a_data.z, 4.0) - 1.0; - - vec2 pos = floor(a_pos_normal * 0.5); - - // x is 1 if it's a round cap, 0 otherwise - // y is 1 if the normal points up, and -1 if it points down - // We store these in the least significant bit of a_pos_normal - mediump vec2 normal = a_pos_normal - 2.0 * pos; - normal.y = normal.y * 2.0 - 1.0; - v_normal = normal; - - // 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 halfwidth = width / 2.0; - offset = -1.0 * offset; - - float inset = gapwidth + (gapwidth > 0.0 ? ANTIALIASING : 0.0); - float outset = gapwidth + halfwidth * (gapwidth > 0.0 ? 2.0 : 1.0) + (halfwidth == 0.0 ? 0.0 : ANTIALIASING); - - // Scale the extrusion vector down to a normal and then up by the line width - // of this vertex. - mediump vec2 dist = outset * a_extrude * EXTRUDE_SCALE; - - // Calculate the offset when drawing a line that is to the side of the actual line. - // We do this by creating a vector that points towards the extrude, but rotate - // it when we're drawing round end points (a_direction = -1 or 1) since their - // extrude vector points in another direction. - mediump float u = 0.5 * a_direction; - mediump float t = 1.0 - abs(u); - mediump vec2 offset2 = offset * a_extrude * EXTRUDE_SCALE * normal.y * mat2(t, -u, u, t); - - vec4 projected_extrude = u_matrix * vec4(dist / u_ratio, 0.0, 0.0); - gl_Position = u_matrix * vec4(pos + offset2 / u_ratio, 0.0, 1.0) + projected_extrude; - -#ifndef RENDER_TO_TEXTURE - // calculate how much the perspective view squishes or stretches the extrude - float extrude_length_without_perspective = length(dist); - float extrude_length_with_perspective = length(projected_extrude.xy / gl_Position.w * u_units_to_pixels); - v_gamma_scale = extrude_length_without_perspective / extrude_length_with_perspective; -#else - v_gamma_scale = 1.0; -#endif - - float tileZoomRatio = u_scale.x; - float fromScale = u_scale.y; - float toScale = u_scale.z; - - float scaleA = dash_from.z == 0.0 ? 0.0 : tileZoomRatio / (dash_from.z * fromScale); - float scaleB = dash_to.z == 0.0 ? 0.0 : tileZoomRatio / (dash_to.z * toScale); - float heightA = dash_from.y; - float heightB = dash_to.y; - - v_tex_a = vec2(a_linesofar * scaleA / floorwidth, (-normal.y * heightA + dash_from.x + 0.5) / u_texsize.y); - v_tex_b = vec2(a_linesofar * scaleB / floorwidth, (-normal.y * heightB + dash_to.x + 0.5) / u_texsize.y); - - v_width2 = vec2(outset, inset); - -#ifdef FOG - v_fog_pos = fog_position(pos); -#endif -} diff --git a/src/shaders/shaders.js b/src/shaders/shaders.js index 1be05fa68d6..cc8143b9d53 100644 --- a/src/shaders/shaders.js +++ b/src/shaders/shaders.js @@ -41,12 +41,8 @@ import hillshadeFrag from './hillshade.fragment.glsl'; import hillshadeVert from './hillshade.vertex.glsl'; import lineFrag from './line.fragment.glsl'; import lineVert from './line.vertex.glsl'; -import lineGradientFrag from './line_gradient.fragment.glsl'; -import lineGradientVert from './line_gradient.vertex.glsl'; import linePatternFrag from './line_pattern.fragment.glsl'; import linePatternVert from './line_pattern.vertex.glsl'; -import lineSDFFrag from './line_sdf.fragment.glsl'; -import lineSDFVert from './line_sdf.vertex.glsl'; import rasterFrag from './raster.fragment.glsl'; import rasterVert from './raster.vertex.glsl'; import symbolIconFrag from './symbol_icon.fragment.glsl'; @@ -96,9 +92,7 @@ export default { hillshadePrepare: compile(hillshadePrepareFrag, hillshadePrepareVert), hillshade: compile(hillshadeFrag, hillshadeVert), line: compile(lineFrag, lineVert), - lineGradient: compile(lineGradientFrag, lineGradientVert), linePattern: compile(linePatternFrag, linePatternVert), - lineSDF: compile(lineSDFFrag, lineSDFVert), raster: compile(rasterFrag, rasterVert), symbolIcon: compile(symbolIconFrag, symbolIconVert), symbolSDF: compile(symbolSDFFrag, symbolSDFVert), diff --git a/src/style-spec/reference/v8.json b/src/style-spec/reference/v8.json index a00d6e9f508..7d3fe7e651f 100644 --- a/src/style-spec/reference/v8.json +++ b/src/style-spec/reference/v8.json @@ -4671,9 +4671,6 @@ "doc": "Defines a gradient with which to color a line feature. Can only be used with GeoJSON sources that specify `\"lineMetrics\": true`.", "transition": false, "requires": [ - { - "!": "line-dasharray" - }, { "!": "line-pattern" }, diff --git a/src/style/style_layer/line_style_layer.js b/src/style/style_layer/line_style_layer.js index 287941f9a8a..c55f74448da 100644 --- a/src/style/style_layer/line_style_layer.js +++ b/src/style/style_layer/line_style_layer.js @@ -82,14 +82,9 @@ class LineStyleLayer extends StyleLayer { } getProgramIds(): string[] { - const dasharray = this.paint.get('line-dasharray'); const patternProperty = this.paint.get('line-pattern'); const image = patternProperty.constantOr((1: any)); - const gradient = this.paint.get('line-gradient'); - const programId = - image ? 'linePattern' : - dasharray ? 'lineSDF' : - gradient ? 'lineGradient' : 'line'; + const programId = image ? 'linePattern' : 'line'; return [programId]; } diff --git a/test/integration/render-tests/line-gradient/gradient-with-dash/expected.png b/test/integration/render-tests/line-gradient/gradient-with-dash/expected.png new file mode 100644 index 00000000000..f8b78fc9191 Binary files /dev/null and b/test/integration/render-tests/line-gradient/gradient-with-dash/expected.png differ diff --git a/test/integration/render-tests/line-gradient/gradient-with-dash/style.json b/test/integration/render-tests/line-gradient/gradient-with-dash/style.json new file mode 100644 index 00000000000..33ace567841 --- /dev/null +++ b/test/integration/render-tests/line-gradient/gradient-with-dash/style.json @@ -0,0 +1,87 @@ +{ + "version": 8, + "metadata": { + "test": { + "width": 100, + "height": 100 + } + }, + "zoom": 2, + "sources": { + "gradient": { + "type": "geojson", + "data": { + "type": "Feature", + "properties": {}, + "geometry": { + "type": "LineString", + "coordinates": [ + [ + -1, + 8 + ], + [ + 8, + 1 + ], + [ + 1, + -8 + ], + [ + -8, + -1 + ], + [ + 1, + 4 + ], + [ + 4, + -1 + ], + [ + -1, + -4 + ], + [ + -2, + 0 + ] + ] + } + }, + "lineMetrics": true + } + }, + "layers": [ + { + "id": "line", + "type": "line", + "source": "gradient", + "layout": { + "line-cap": "round", + "line-join": "round" + }, + "paint": { + "line-width": 10, + "line-dasharray": [ + 1, + 1.5 + ], + "line-gradient": [ + "interpolate", + ["linear"], + ["line-progress"], + 0, "rgba(0, 0, 255, 0)", + 0.1, "royalblue", + 0.3, "cyan", + 0.5, "lime", + 0.7, "yellow", + 1, "red" + ] + } + } + ] + } + \ No newline at end of file