diff --git a/src/ol/style/expressions.js b/src/ol/style/expressions.js index 759a127fc3..ed643fc58e 100644 --- a/src/ol/style/expressions.js +++ b/src/ol/style/expressions.js @@ -192,7 +192,7 @@ export function stringToGlsl(context, string) { * will be read and modified during the parsing operation. * @param {ParsingContext} context Parsing context * @param {ExpressionValue} value Value - * @param {ValueTypes} [typeHint] Hint for the expected final type + * @param {ValueTypes|number} [typeHint] Hint for the expected final type (can be several types combined) * @returns {string} GLSL-compatible output */ export function expressionToGlsl(context, value, typeHint) { diff --git a/src/ol/webgl/ShaderBuilder.js b/src/ol/webgl/ShaderBuilder.js index de3ccf8ce2..666c76d3cd 100644 --- a/src/ol/webgl/ShaderBuilder.js +++ b/src/ol/webgl/ShaderBuilder.js @@ -282,8 +282,8 @@ void main(void) { vec4 offsets = offsetMatrix * vec4(offsetX, offsetY, 0.0, 0.0); gl_Position = u_projectionMatrix * vec4(a_position, 0.0, 1.0) + offsets; vec4 texCoord = ${this.texCoordExpression}; - float u = a_index == 0.0 || a_index == 3.0 ? texCoord.s : texCoord.q; - float v = a_index == 2.0 || a_index == 3.0 ? texCoord.t : texCoord.p; + float u = a_index == 0.0 || a_index == 3.0 ? texCoord.s : texCoord.p; + float v = a_index == 2.0 || a_index == 3.0 ? texCoord.t : texCoord.q; v_texCoord = vec2(u, v); u = a_index == 0.0 || a_index == 3.0 ? 0.0 : 1.0; v = a_index == 2.0 || a_index == 3.0 ? 0.0 : 1.0; @@ -342,37 +342,39 @@ void main(void) { */ export function parseLiteralStyle(style) { const symbStyle = style.symbol; - const size = Array.isArray(symbStyle.size) && typeof symbStyle.size[0] == 'number' ? - symbStyle.size : [symbStyle.size, symbStyle.size]; + const size = symbStyle.size !== undefined ? symbStyle.size : 1; const color = symbStyle.color || 'white'; const texCoord = symbStyle.textureCoord || [0, 0, 1, 1]; const offset = symbStyle.offset || [0, 0]; const opacity = symbStyle.opacity !== undefined ? symbStyle.opacity : 1; + /** + * @type {import("../style/expressions.js").ParsingContext} + */ const vertContext = { inFragmentShader: false, variables: [], - attributes: [] + attributes: [], + stringLiteralsMap: {} }; - const parseSizeX = expressionToGlsl(vertContext, size[0], ValueTypes.NUMBER); - const parseSizeY = expressionToGlsl(vertContext, size[1], ValueTypes.NUMBER); - const parsedOffsetX = expressionToGlsl(vertContext, offset[0], ValueTypes.NUMBER); - const parsedOffsetY = expressionToGlsl(vertContext, offset[1], ValueTypes.NUMBER); - const parsedTexCoordU1 = expressionToGlsl(vertContext, texCoord[0], ValueTypes.NUMBER); - const parsedTexCoordV1 = expressionToGlsl(vertContext, texCoord[1], ValueTypes.NUMBER); - const parsedTexCoordU2 = expressionToGlsl(vertContext, texCoord[2], ValueTypes.NUMBER); - const parsedTexCoordV2 = expressionToGlsl(vertContext, texCoord[3], ValueTypes.NUMBER); + const parsedSize = expressionToGlsl(vertContext, size, ValueTypes.NUMBER_ARRAY | ValueTypes.NUMBER); + const parsedOffset = expressionToGlsl(vertContext, offset, ValueTypes.NUMBER_ARRAY); + const parsedTexCoord = expressionToGlsl(vertContext, texCoord, ValueTypes.NUMBER_ARRAY); + /** + * @type {import("../style/expressions.js").ParsingContext} + */ const fragContext = { inFragmentShader: true, variables: vertContext.variables, - attributes: [] + attributes: [], + stringLiteralsMap: vertContext.stringLiteralsMap }; const parsedColor = expressionToGlsl(fragContext, color, ValueTypes.COLOR); const parsedOpacity = expressionToGlsl(fragContext, opacity, ValueTypes.NUMBER); let opacityFilter = '1.0'; - const visibleSize = expressionToGlsl(fragContext, size[0], ValueTypes.NUMBER); + const visibleSize = `vec2(${expressionToGlsl(fragContext, size, ValueTypes.NUMBER_ARRAY | ValueTypes.NUMBER)}).x`; switch (symbStyle.symbolType) { case 'square': break; case 'image': break; @@ -390,10 +392,9 @@ export function parseLiteralStyle(style) { } const builder = new ShaderBuilder() - .setSizeExpression(`vec2(${parseSizeX}, ${parseSizeY})`) - .setSymbolOffsetExpression(`vec2(${parsedOffsetX}, ${parsedOffsetY})`) - .setTextureCoordinateExpression( - `vec4(${parsedTexCoordU1}, ${parsedTexCoordV1}, ${parsedTexCoordU2}, ${parsedTexCoordV2})`) + .setSizeExpression(`vec2(${parsedSize})`) + .setSymbolOffsetExpression(parsedOffset) + .setTextureCoordinateExpression(parsedTexCoord) .setSymbolRotateWithView(!!symbStyle.rotateWithView) .setColorExpression( `vec4(${parsedColor}.rgb, ${parsedColor}.a * ${parsedOpacity} * ${opacityFilter})`); @@ -444,7 +445,11 @@ export function parseLiteralStyle(style) { return { name: attributeName, callback: function(feature) { - return feature.get(attributeName) || 0; + let value = feature.get(attributeName); + if (typeof value === 'string') { + value = vertContext.stringLiteralsMap[value]; + } + return value !== undefined ? value : -9999999; // to avoid matching with the first string literal } }; }), diff --git a/test/spec/ol/webgl/shaderbuilder.test.js b/test/spec/ol/webgl/shaderbuilder.test.js index 0e136b251a..f6a7eafb25 100644 --- a/test/spec/ol/webgl/shaderbuilder.test.js +++ b/test/spec/ol/webgl/shaderbuilder.test.js @@ -35,8 +35,8 @@ void main(void) { vec4 offsets = offsetMatrix * vec4(offsetX, offsetY, 0.0, 0.0); gl_Position = u_projectionMatrix * vec4(a_position, 0.0, 1.0) + offsets; vec4 texCoord = vec4(0.0, 0.5, 0.5, 1.0); - float u = a_index == 0.0 || a_index == 3.0 ? texCoord.s : texCoord.q; - float v = a_index == 2.0 || a_index == 3.0 ? texCoord.t : texCoord.p; + float u = a_index == 0.0 || a_index == 3.0 ? texCoord.s : texCoord.p; + float v = a_index == 2.0 || a_index == 3.0 ? texCoord.t : texCoord.q; v_texCoord = vec2(u, v); u = a_index == 0.0 || a_index == 3.0 ? 0.0 : 1.0; v = a_index == 2.0 || a_index == 3.0 ? 0.0 : 1.0; @@ -75,8 +75,8 @@ void main(void) { vec4 offsets = offsetMatrix * vec4(offsetX, offsetY, 0.0, 0.0); gl_Position = u_projectionMatrix * vec4(a_position, 0.0, 1.0) + offsets; vec4 texCoord = vec4(0.0, 0.5, 0.5, 1.0); - float u = a_index == 0.0 || a_index == 3.0 ? texCoord.s : texCoord.q; - float v = a_index == 2.0 || a_index == 3.0 ? texCoord.t : texCoord.p; + float u = a_index == 0.0 || a_index == 3.0 ? texCoord.s : texCoord.p; + float v = a_index == 2.0 || a_index == 3.0 ? texCoord.t : texCoord.q; v_texCoord = vec2(u, v); u = a_index == 0.0 || a_index == 3.0 ? 0.0 : 1.0; v = a_index == 2.0 || a_index == 3.0 ? 0.0 : 1.0; @@ -113,8 +113,8 @@ void main(void) { vec4 offsets = offsetMatrix * vec4(offsetX, offsetY, 0.0, 0.0); gl_Position = u_projectionMatrix * vec4(a_position, 0.0, 1.0) + offsets; vec4 texCoord = vec4(0.0, 0.5, 0.5, 1.0); - float u = a_index == 0.0 || a_index == 3.0 ? texCoord.s : texCoord.q; - float v = a_index == 2.0 || a_index == 3.0 ? texCoord.t : texCoord.p; + float u = a_index == 0.0 || a_index == 3.0 ? texCoord.s : texCoord.p; + float v = a_index == 2.0 || a_index == 3.0 ? texCoord.t : texCoord.q; v_texCoord = vec2(u, v); u = a_index == 0.0 || a_index == 3.0 ? 0.0 : 1.0; v = a_index == 2.0 || a_index == 3.0 ? 0.0 : 1.0; @@ -188,7 +188,7 @@ void main(void) { expect(result.builder.varyings).to.eql([]); expect(result.builder.colorExpression).to.eql( 'vec4(vec4(1.0, 0.0, 0.0, 1.0).rgb, vec4(1.0, 0.0, 0.0, 1.0).a * 1.0 * 1.0)'); - expect(result.builder.sizeExpression).to.eql('vec2(4.0, 8.0)'); + expect(result.builder.sizeExpression).to.eql('vec2(vec2(4.0, 8.0))'); expect(result.builder.offsetExpression).to.eql('vec2(0.0, 0.0)'); expect(result.builder.texCoordExpression).to.eql('vec4(0.0, 0.0, 1.0, 1.0)'); expect(result.builder.rotateWithView).to.eql(true); @@ -203,7 +203,7 @@ void main(void) { size: ['get', 'attr1'], color: [255, 127.5, 63.75, 0.25], textureCoord: [0.5, 0.5, 0.5, 1], - offset: [3, ['get', 'attr3']] + offset: ['match', ['get', 'attr3'], 'red', [6, 0], 'green', [3, 0], [0, 0]] } }); @@ -217,8 +217,8 @@ void main(void) { expect(result.builder.colorExpression).to.eql( 'vec4(vec4(1.0, 0.5, 0.25, 0.25).rgb, vec4(1.0, 0.5, 0.25, 0.25).a * 1.0 * 1.0)' ); - expect(result.builder.sizeExpression).to.eql('vec2(a_attr1, a_attr1)'); - expect(result.builder.offsetExpression).to.eql('vec2(3.0, a_attr3)'); + expect(result.builder.sizeExpression).to.eql('vec2(a_attr1)'); + expect(result.builder.offsetExpression).to.eql('(a_attr3 == 1.0 ? vec2(6.0, 0.0) : (a_attr3 == 0.0 ? vec2(3.0, 0.0) : vec2(0.0, 0.0)))'); expect(result.builder.texCoordExpression).to.eql('vec4(0.5, 0.5, 0.5, 1.0)'); expect(result.builder.rotateWithView).to.eql(false); expect(result.attributes.length).to.eql(2); @@ -244,7 +244,7 @@ void main(void) { expect(result.builder.colorExpression).to.eql( 'vec4(vec4(0.2, 0.4, 0.6, 1.0).rgb, vec4(0.2, 0.4, 0.6, 1.0).a * 0.5 * 1.0) * texture2D(u_texture, v_texCoord)' ); - expect(result.builder.sizeExpression).to.eql('vec2(6.0, 6.0)'); + expect(result.builder.sizeExpression).to.eql('vec2(6.0)'); expect(result.builder.offsetExpression).to.eql('vec2(0.0, 0.0)'); expect(result.builder.texCoordExpression).to.eql('vec4(0.0, 0.0, 1.0, 1.0)'); expect(result.builder.rotateWithView).to.eql(false); @@ -277,7 +277,7 @@ void main(void) { 'vec4(vec4(0.2, 0.4, 0.6, 1.0).rgb, vec4(0.2, 0.4, 0.6, 1.0).a * 0.5 * 1.0)' ); expect(result.builder.sizeExpression).to.eql( - 'vec2(((clamp(a_population, u_lower, u_higher) - u_lower) * ((8.0 - 4.0) / (u_higher - u_lower)) + 4.0), ((clamp(a_population, u_lower, u_higher) - u_lower) * ((8.0 - 4.0) / (u_higher - u_lower)) + 4.0))' + 'vec2(((clamp(a_population, u_lower, u_higher) - u_lower) * ((8.0 - 4.0) / (u_higher - u_lower)) + 4.0))' ); expect(result.builder.offsetExpression).to.eql('vec2(0.0, 0.0)'); expect(result.builder.texCoordExpression).to.eql('vec4(0.0, 0.0, 1.0, 1.0)'); @@ -307,10 +307,10 @@ void main(void) { expect(result.builder.colorExpression).to.eql( 'vec4(vec4(0.2, 0.4, 0.6, 1.0).rgb, vec4(0.2, 0.4, 0.6, 1.0).a * 1.0 * 1.0)' ); - expect(result.builder.sizeExpression).to.eql('vec2(6.0, 6.0)'); + expect(result.builder.sizeExpression).to.eql('vec2(6.0)'); expect(result.builder.offsetExpression).to.eql('vec2(0.0, 0.0)'); expect(result.builder.texCoordExpression).to.eql('vec4(0.0, 0.0, 1.0, 1.0)'); - expect(result.builder.discardExpression).to.eql('(v_attr0 >= 0.0 && v_attr0 <= 10.0)'); + expect(result.builder.discardExpression).to.eql('!(v_attr0 >= 0.0 && v_attr0 <= 10.0)'); expect(result.builder.rotateWithView).to.eql(false); expect(result.attributes.length).to.eql(1); expect(result.attributes[0].name).to.eql('attr0'); @@ -330,7 +330,7 @@ void main(void) { expect(result.builder.colorExpression).to.eql( 'vec4(mix(vec4(1.0, 1.0, 0.0, 1.0), vec4(1.0, 0.0, 0.0, 1.0), u_ratio).rgb, mix(vec4(1.0, 1.0, 0.0, 1.0), vec4(1.0, 0.0, 0.0, 1.0), u_ratio).a * 1.0 * 1.0)' ); - expect(result.builder.sizeExpression).to.eql('vec2(6.0, 6.0)'); + expect(result.builder.sizeExpression).to.eql('vec2(6.0)'); expect(result.builder.offsetExpression).to.eql('vec2(0.0, 0.0)'); expect(result.builder.texCoordExpression).to.eql('vec4(0.0, 0.0, 1.0, 1.0)'); expect(result.builder.rotateWithView).to.eql(false);