Skip to content

[pull] main from openlayers:main #311

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 3 commits into from
May 7, 2025
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
12 changes: 6 additions & 6 deletions src/ol/render/webgl/style.js
Original file line number Diff line number Diff line change
Expand Up @@ -648,9 +648,9 @@ function parseStrokeProperties(style, builder, uniforms, context) {
const uniqueDashKey = computeHash(style['stroke-line-dash']);
const dashFunctionName = `dashDistanceField_${uniqueDashKey}`;

const dashLengthsDef = dashPattern.map(
(v, i) => `float dashLength${i} = ${v};`,
);
const dashLengthsParamsDef = dashPattern
.map((v, i) => `float dashLength${i}`)
.join(', ');
const totalLengthDef = dashPattern
.map((v, i) => `dashLength${i}`)
.join(' + ');
Expand All @@ -664,13 +664,13 @@ function parseStrokeProperties(style, builder, uniforms, context) {
}

context.functions[dashFunctionName] =
`float ${dashFunctionName}(float distance, float radius, float capType, float lineWidth) {
${dashLengthsDef.join('\n ')}
`float ${dashFunctionName}(float distance, float radius, float capType, float lineWidth, ${dashLengthsParamsDef}) {
float totalDashLength = ${totalLengthDef};
return ${distanceExpression};
}`;
const dashLengthsCalls = dashPattern.map((v, i) => `${v}`).join(', ');
builder.setStrokeDistanceFieldExpression(
`${dashFunctionName}(currentLengthPx + ${offsetExpression}, currentRadiusPx, capType, v_width)`,
`${dashFunctionName}(currentLengthPx + ${offsetExpression}, currentRadiusPx, capType, v_width, ${dashLengthsCalls})`,
);
}
}
Expand Down
102 changes: 96 additions & 6 deletions test/browser/spec/ol/render/webgl/style.test.js
Original file line number Diff line number Diff line change
Expand Up @@ -746,7 +746,7 @@ describe('ol/render/webgl/style', () => {
'(u_var_miterLimit - 10.0)',
);
expect(result.builder.strokeDistanceFieldExpression_).to.eql(
'dashDistanceField_450289113(currentLengthPx + (u_time * 5.0), currentRadiusPx, capType, v_width)',
'dashDistanceField_450289113(currentLengthPx + (u_time * 5.0), currentRadiusPx, capType, v_width, (a_prop_size * 10.0), (a_prop_size * 20.0), 5.0, (a_prop_size * 20.0))',
);
expect(Object.keys(result.attributes).length).to.eql(3);
expect(result.attributes).to.have.property('prop_intensity');
Expand All @@ -761,11 +761,7 @@ describe('ol/render/webgl/style', () => {
'float getSingleDashDistance',
);
expect(result.builder.fragmentShaderFunctions_).to
.contain(`float dashDistanceField_450289113(float distance, float radius, float capType, float lineWidth) {
float dashLength0 = (a_prop_size * 10.0);
float dashLength1 = (a_prop_size * 20.0);
float dashLength2 = 5.0;
float dashLength3 = (a_prop_size * 20.0);
.contain(`float dashDistanceField_450289113(float distance, float radius, float capType, float lineWidth, float dashLength0, float dashLength1, float dashLength2, float dashLength3) {
float totalDashLength = dashLength0 + dashLength1 + dashLength2 + dashLength3;
return min(getSingleDashDistance(distance, radius, 0., dashLength0, totalDashLength, capType, lineWidth), getSingleDashDistance(distance, radius, 0. + dashLength0 + dashLength1, dashLength2, totalDashLength, capType, lineWidth));
}`);
Expand Down Expand Up @@ -832,6 +828,100 @@ describe('ol/render/webgl/style', () => {
);
});
});

describe('stroke style with all dynamic dash length expressions', () => {
let result;

beforeEach(() => {
// Create a style where ALL dash lengths come from expressions
const style = {
'stroke-color': 'red',
'stroke-width': 3,
'stroke-line-dash': [
['get', 'dashLength0'],
['get', 'dashLength1'],
['get', 'dashLength2'],
['get', 'dashLength3'],
],
'stroke-line-dash-offset': ['get', 'dashOffset'],
};
result = parseLiteralStyle(style);
});

it('includes dash distance functions in the shader', () => {
expect(
result.builder.fragmentShaderFunctions_.some((fn) =>
fn.includes('getSingleDashDistance'),
),
).to.be(true);

const dashFunctionName = result.builder.fragmentShaderFunctions_
.find((fn) => fn.startsWith('float dashDistanceField_'))
.split('(')[0]
.split(' ')[1];

expect(dashFunctionName).to.contain('dashDistanceField_');
});

it('defines dash lengths as function parameters instead of inside function body', () => {
// Get the dashDistanceField function definition
const dashFunctionDef = result.builder.fragmentShaderFunctions_.find(
(fn) => fn.startsWith('float dashDistanceField_'),
);

// The function signature should include parameters for all dash lengths
const functionSignature = dashFunctionDef.split('{')[0];
expect(functionSignature).to.contain('float distance');
expect(functionSignature).to.contain('float radius');
expect(functionSignature).to.contain('float capType');
expect(functionSignature).to.contain('float lineWidth');
expect(functionSignature).to.contain('float dashLength0');
expect(functionSignature).to.contain('float dashLength1');
expect(functionSignature).to.contain('float dashLength2');
expect(functionSignature).to.contain('float dashLength3');
});

it('passes all dynamic dash length expressions to the function as parameters', () => {
expect(result.builder.strokeDistanceFieldExpression_).to.contain(
'dashDistanceField_',
);
expect(result.builder.strokeDistanceFieldExpression_).to.contain(
'a_prop_dashLength0',
);
expect(result.builder.strokeDistanceFieldExpression_).to.contain(
'a_prop_dashLength1',
);
expect(result.builder.strokeDistanceFieldExpression_).to.contain(
'a_prop_dashLength2',
);
expect(result.builder.strokeDistanceFieldExpression_).to.contain(
'a_prop_dashLength3',
);
});

it('correctly extracts all dash length values from features', () => {
const feature = new Feature({
dashLength0: 10,
dashLength1: 5,
dashLength2: 15,
dashLength3: 12,
dashOffset: 2,
});

expect(
result.attributes['prop_dashLength0'].callback(feature),
).to.eql(10);
expect(
result.attributes['prop_dashLength1'].callback(feature),
).to.eql(5);
expect(
result.attributes['prop_dashLength2'].callback(feature),
).to.eql(15);
expect(
result.attributes['prop_dashLength3'].callback(feature),
).to.eql(12);
});
});
});

describe('fill style', () => {
Expand Down
4 changes: 3 additions & 1 deletion test/rendering/cases/webgl-line/main.js
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@ const openLine = new Feature({
[-60, -50],
]),
lineColor: 'rgba(80,0,0,0.75)',
firstDashDistance: 18,
});

const closedLine = new Feature({
Expand All @@ -32,6 +33,7 @@ const closedLine = new Feature({
[90, -80],
]),
lineColor: 'rgba(255,243,177,0.75)',
firstDashDistance: 18,
});

const dataDriven = {
Expand All @@ -55,7 +57,7 @@ const dashed = {
'stroke-color': 'rgb(0,104,218)',
'stroke-offset': -10,
'stroke-width': 4,
'stroke-line-dash': [18, 10, 10, 10],
'stroke-line-dash': [['get', 'firstDashDistance'], 10, 10, 10],
'stroke-line-dash-offset': 10,
};
const style = [bevelJoins, dataDriven, miterJoins, dashed];
Expand Down
Loading