Skip to content

Commit

Permalink
support line dash pattern with large meter values (>1000m)
Browse files Browse the repository at this point in the history
Signed-off-by: Tim Deubler <[email protected]>
  • Loading branch information
TerminalTim committed Nov 24, 2023
1 parent bd1d34e commit c381f20
Show file tree
Hide file tree
Showing 10 changed files with 82 additions and 49 deletions.
3 changes: 2 additions & 1 deletion packages/core/src/styles/GenericStyle.ts
Original file line number Diff line number Diff line change
Expand Up @@ -174,8 +174,9 @@ export interface Style {
* then the list of values is repeated to yield an even number of values. Thus, 5,3,2 is equivalent to 5,3,2,5,3,2.
* The size of dashes and gaps can be defined in pixel or meter.
* The default unit for dash and gap size is pixel.
* In a pattern utilizing both meter and pixel units, only the initial "dash" and "gap" combination is utilized, with the subsequent ones being skipped.
* To define the size in meters, a string containing the "dash"/"gap" size and ending with "m" must be used.
* This attribute is valid for Line styles only.
* This attribute is valid for Line and Polygon styles only.
*
* @example
* // dash and gap size is defined in pixel.
Expand Down
1 change: 1 addition & 0 deletions packages/core/src/styles/LineStyle.ts
Original file line number Diff line number Diff line change
Expand Up @@ -108,6 +108,7 @@ export interface LineStyle {
* then the list of values is repeated to yield an even number of values. Thus, 5,3,2 is equivalent to 5,3,2,5,3,2.
* The size of dashes and gaps can be defined in pixel or meter.
* The default unit for dash and gap size is pixel.
* In a pattern utilizing both meter and pixel units, only the initial "dash" and "gap" combination is utilized, with the subsequent ones being skipped.
* To define the size in meters, a string containing the "dash"/"gap" size and ending with "m" must be used.
*
* @example
Expand Down
13 changes: 12 additions & 1 deletion packages/core/src/styles/PolygonStyle.ts
Original file line number Diff line number Diff line change
Expand Up @@ -105,7 +105,18 @@ export interface PolygonStyle {
* The strokeDasharray attribute controls the pattern of dashes and gaps used to stroke paths.
* It's an array of <length> that specify the lengths of alternating dashes and gaps. If an odd number of values is provided,
* then the list of values is repeated to yield an even number of values. Thus, 5,3,2 is equivalent to 5,3,2,5,3,2.
* This attribute is valid for Line styles only.
* The size of dashes and gaps can be defined in pixel or meter.
* The default unit for dash and gap size is pixel.
* In a pattern utilizing both meter and pixel units, only the initial "dash" and "gap" combination is utilized, with the subsequent ones being skipped.
* To define the size in meters, a string containing the "dash"/"gap" size and ending with "m" must be used.
*
* @example
* // dash and gap size is defined in pixel.
* strokeDasharray: [20,10]
* // dash and gap size is defined in meter.
* strokeDasharray: ["20m","10m"]
* // dash -> 10 meter, gap -> 10 pixel.
* strokeDasharray: ["20m",10] || ["20m","10px"]
*/
strokeDasharray?: number[] | StyleValueFunction<number[]> | StyleZoomRange<number[]> | 'none';

Expand Down
28 changes: 17 additions & 11 deletions packages/display/src/displays/webgl/DashAtlas.ts
Original file line number Diff line number Diff line change
Expand Up @@ -18,11 +18,13 @@
*/
import {SharedTexture} from './Atlas';

type DashArray = [number, number, number?];
type DashArray = number[];

type DashTexture = { texture: SharedTexture, scale: number};

class DashAtlas {
private gl: WebGLRenderingContext;
private data: { [id: string]: SharedTexture } = {};
private data: { [id: string]: DashTexture } = {};

// scale by 10 to allow 0.1 meter precision
scale: number = 10;
Expand All @@ -33,7 +35,8 @@ class DashAtlas {

private create(dashArray: DashArray) {
let size = dashArray.reduce((a, b) => a + b);
let {scale} = this;
// Dynamically adjust the scale to roughly fit the size of a tile.
const scale = 512 / size;

size *= scale;

Expand All @@ -53,16 +56,19 @@ class DashAtlas {
}
}

return new SharedTexture(gl, {
width: pixels.length,
height: 1,
data: pixels
}, {
format: gl.LUMINANCE
});
return {
scale,
texture: new SharedTexture(gl, {
width: pixels.length,
height: 1,
data: pixels
}, {
format: gl.LUMINANCE
})
};
}

get(dashArray: DashArray, dashImage?): SharedTexture {
get(dashArray: DashArray): DashTexture {
const id = String(dashArray);
let dashData = this.data[id];

Expand Down
11 changes: 4 additions & 7 deletions packages/display/src/displays/webgl/GLRender.ts
Original file line number Diff line number Diff line change
Expand Up @@ -160,7 +160,7 @@ export class GLRender implements BasicRender {
};

private _lightDir: number[] = [0.5, 0.0, -1.0];
private programConfig: { [name: string]: { program: typeof Program, default?: boolean } };
private programConfig: { [name: string]: { program: typeof Program, default?: boolean, macros?: any } };
private resolution: number[] = [];

constructor(renderOptions: RenderOptions) {
Expand Down Expand Up @@ -225,10 +225,7 @@ export class GLRender implements BasicRender {
}

setBackgroundColor(color: RGBA) {
// this.clearColor = color;
if (this.gl) {
this.gl.clearColor(color[0], color[1], color[2], color[3] || 1.0);
}
this.gl?.clearColor(color[0], color[1], color[2], color[3] || 1.0);
}

setScale(scale: number, sx: number, sy: number) {
Expand Down Expand Up @@ -284,7 +281,7 @@ export class GLRender implements BasicRender {
const programConfig = this.programConfig = {
Rect: {program: RectProgram},
Line: {program: LineProgram},
DashedLine: {program: DashedLineProgram},
DashedLine: {program: DashedLineProgram, default: false},
Text: {program: TextProgram},
Image: {program: ImageProgram},
Circle: {program: CircleProgram},
Expand Down Expand Up @@ -935,7 +932,7 @@ export class GLRender implements BasicRender {
if (prog === undefined) {
const Program = this.programConfig[type].program;
if (Program) {
prog = this.createProgram(id, Program, Program.getMacros(buffer));
prog = this.createProgram(id, Program, Program.getMacros(buffer) );
}
}

Expand Down
2 changes: 0 additions & 2 deletions packages/display/src/displays/webgl/buffer/FeatureFactory.ts
Original file line number Diff line number Diff line change
Expand Up @@ -121,7 +121,6 @@ export class FeatureFactory {
private readonly gl: WebGLRenderingContext;
private atlasManager: TextureAtlasManager;
private dpr: number;
private dashes: DashAtlas;
private tile: Tile;
private groups: GroupMap;
private tileSize: number;
Expand All @@ -137,7 +136,6 @@ export class FeatureFactory {
this.gl = gl;
this.atlasManager = new TextureAtlasManager(gl);
this.dpr = devicePixelRatio;
this.dashes = new DashAtlas(gl);
this.collisions = collisionHandler;
this.lineFactory = new LineFactory(gl);
this.modelFactory = new ModelFactory(gl);
Expand Down
2 changes: 0 additions & 2 deletions packages/display/src/displays/webgl/buffer/createBuffer.ts
Original file line number Diff line number Diff line change
Expand Up @@ -197,8 +197,6 @@ const createBuffer = (
if (type == 'Line') {
if (shared.strokeDasharray) {
geoBuffer.type = 'DashedLine';
geoBuffer.addUniform('u_hasDashTexture', !!(geoBuffer.uniforms.u_dashTexture));

geoBuffer.addUniform('u_dashUnit', [
shared.strokeDasharray.units[0] == 'm' ? meterToPixel : 0,
shared.strokeDasharray.units[1] == 'm' ? meterToPixel : 0
Expand Down
46 changes: 29 additions & 17 deletions packages/display/src/displays/webgl/glsl/line_fragment.glsl
Original file line number Diff line number Diff line change
Expand Up @@ -7,11 +7,13 @@ uniform bool u_no_antialias;

#ifdef DASHARRAY
uniform highp float u_scale;
uniform sampler2D u_pattern;
#if (DASHARRAY & 2)
uniform sampler2D u_dashPattern;
#endif
varying float v_lengthSoFar;
uniform sampler2D u_dashTexture;
uniform bool u_hasDashTexture;
varying vec3 v_dashSize;
varying vec2 v_dashSize;
#endif
varying vec2 v_width;

Expand All @@ -24,23 +26,33 @@ void main(void){
}

#ifdef DASHARRAY
if (u_hasDashTexture){
// dash size + gap size
float dashSize = v_dashSize.y;
float gapSize = v_dashSize.z;
float dashSize = v_dashSize.x;
float gapSize = v_dashSize.y;
float totalDashSize = dashSize + gapSize;
// [dashsize: constant, gabsize: scaling, ->pattern: fix]
// float u = fract(v_lengthSoFar/totalDashSize) * (1. + gapSize / dashSize) * u_scale;
// [dashsize: constant, gabsize: constant, ->pattern: floating]
float u = fract(v_lengthSoFar/totalDashSize * u_scale) * (1. + gapSize / dashSize);
gl_FragColor = u_fill * texture2D(u_dashTexture, vec2(u, v_dir.y));
// gl_FragColor = vec4(u_fill.rgb, u_fill.a * texture2D(u_dashTexture, vec2(u, v_dir.y)).a);
} else {
float dash = texture2D(u_pattern, vec2(fract(v_lengthSoFar / v_dashSize.x * u_scale))).r;
gl_FragColor = u_fill * step(0.1,dash);
}

#if DASHARRAY & 2
float dash = texture2D(u_dashPattern, vec2(fract(v_lengthSoFar / totalDashSize * u_scale))).r;
gl_FragColor = u_fill * step(0.1, dash);
#else
float patternPosition = fract(v_lengthSoFar / totalDashSize * u_scale);
float dashPosition = dashSize / totalDashSize;

#if DASHARRAY & 4
// #ifdef DASH_ICON
// [dashsize: constant, gabsize: scaling, ->pattern: fix]
// float u = fract(v_lengthSoFar/totalDashSize) * (1. + gapSize / dashSize) * u_scale;
// [dashsize: constant, gabsize: constant, ->pattern: floating]
// float u = fract(v_lengthSoFar/totalDashSize * u_scale) * (1. + gapSize / dashSize);
// gl_FragColor = vec4(u_fill.rgb, u_fill.a * texture2D(u_dashTexture, vec2(u, v_dir.y)).a);
float u = patternPosition / dashPosition;
gl_FragColor = u_fill * texture2D(u_dashTexture, vec2(u, v_dir.y));
#else
gl_FragColor = vec4(u_fill.rgb, step(patternPosition, dashPosition));
#endif
#endif

#else
gl_FragColor = u_fill;
gl_FragColor = u_fill;
#endif

if (!u_no_antialias){
Expand Down
11 changes: 5 additions & 6 deletions packages/display/src/displays/webgl/glsl/line_vertex.glsl
Original file line number Diff line number Diff line change
Expand Up @@ -11,8 +11,8 @@ uniform vec2 u_topLeft;
varying vec2 v_normal;
#ifdef DASHARRAY
varying float v_lengthSoFar;
varying vec3 v_dashSize;
uniform vec4 u_dashSize;
varying vec2 v_dashSize;
uniform vec2 u_dashSize;
uniform vec2 u_dashUnit;
#endif
varying vec2 v_width;
Expand Down Expand Up @@ -47,10 +47,9 @@ void main(void){
#ifdef DASHARRAY
v_lengthSoFar = a_lengthSoFar;

v_dashSize = vec3(
toPixel(vec2(u_dashSize.x, u_dashUnit.x), u_scale) * u_dashSize.y,
toPixel(vec2(u_dashSize.z, u_dashUnit.x), u_scale),
toPixel(vec2(u_dashSize.w, u_dashUnit.y), u_scale)
v_dashSize = vec2(
toPixel(vec2(u_dashSize.x, u_dashUnit.x), u_scale), // dashSizePixel
toPixel(vec2(u_dashSize.y, u_dashUnit.y), u_scale) // gapSizePixel
);
#endif

Expand Down
14 changes: 12 additions & 2 deletions packages/display/src/displays/webgl/program/DashedLine.ts
Original file line number Diff line number Diff line change
Expand Up @@ -24,8 +24,18 @@ import fragmentShader from '../glsl/line_fragment.glsl';

import Program from './Program';
import {GLStates, PASS} from './GLStates';
import {GeometryBuffer} from '../buffer/GeometryBuffer';

class DashedLineProgram extends Program {
static getMacros(buffer: GeometryBuffer) {
const {uniforms} = buffer;
return {DASHARRAY: 1 | (uniforms.u_dashPattern?2:0) | (uniforms.u_dashTexture?4:0)};
}

static getProgramId(buffer: GeometryBuffer, macros?: { [name: string]: string | number | boolean }) {
return buffer.type + (<number>macros.DASHARRAY);
}

name = 'DashedLine';

glStates = new GLStates({
Expand All @@ -34,8 +44,8 @@ class DashedLineProgram extends Program {
depth: true
});

constructor(gl: WebGLRenderingContext, devicePixelRation: number) {
super(gl, devicePixelRation, {DASHARRAY: true});
constructor(gl: WebGLRenderingContext, devicePixelRation: number, macros = {}) {
super(gl, devicePixelRation, macros);

this.mode = gl.TRIANGLES;
this.vertexShaderSrc = vertexShader;
Expand Down

0 comments on commit c381f20

Please sign in to comment.