Shader Builder / add utilities for checking an expression type
Type checking is done either against a literal value (number, string...) or against the operator in case of an expression. Sometimes it is not possible to infer only one type, for example the value 'transparent' could either be a color or a string. This is covered by the fact that all operators expect exactly one type for their arguments.
This commit is contained in:
@@ -3,7 +3,7 @@
|
|||||||
* @module ol/webgl/ShaderBuilder
|
* @module ol/webgl/ShaderBuilder
|
||||||
*/
|
*/
|
||||||
|
|
||||||
import {asArray} from '../color.js';
|
import {asArray, isStringColor} from '../color.js';
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Will return the number as a float with a dot separator, which is required by GLSL.
|
* Will return the number as a float with a dot separator, which is required by GLSL.
|
||||||
@@ -37,6 +37,89 @@ export function formatColor(color) {
|
|||||||
}).map(formatNumber).join(', ');
|
}).map(formatNumber).join(', ');
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Possible inferred types from a given value or expression
|
||||||
|
* @enum {number}
|
||||||
|
*/
|
||||||
|
const ValueTypes = {
|
||||||
|
UNKNOWN: -1,
|
||||||
|
NUMBER: 0,
|
||||||
|
STRING: 1,
|
||||||
|
COLOR: 2,
|
||||||
|
COLOR_OR_STRING: 3
|
||||||
|
};
|
||||||
|
|
||||||
|
function getValueType(value) {
|
||||||
|
if (typeof value === 'number') {
|
||||||
|
return ValueTypes.NUMBER;
|
||||||
|
}
|
||||||
|
if (typeof value === 'string') {
|
||||||
|
if (isStringColor(value)) {
|
||||||
|
return ValueTypes.COLOR_OR_STRING;
|
||||||
|
}
|
||||||
|
return ValueTypes.STRING;
|
||||||
|
}
|
||||||
|
if (!Array.isArray(value)) {
|
||||||
|
throw new Error(`Unrecognized value type: ${JSON.stringify(value)}`);
|
||||||
|
}
|
||||||
|
if (value.length === 3 || value.length === 4) {
|
||||||
|
const onlyNumbers = value.every(function(v) {
|
||||||
|
return typeof v === 'number';
|
||||||
|
});
|
||||||
|
if (onlyNumbers) {
|
||||||
|
return ValueTypes.COLOR;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (typeof value[0] !== 'string') {
|
||||||
|
return ValueTypes.UNKNOWN;
|
||||||
|
}
|
||||||
|
switch (value[0]) {
|
||||||
|
case 'get':
|
||||||
|
case 'var':
|
||||||
|
case 'time':
|
||||||
|
case '*':
|
||||||
|
case '+':
|
||||||
|
case 'clamp':
|
||||||
|
case 'stretch':
|
||||||
|
case '>':
|
||||||
|
case '>=':
|
||||||
|
case '<':
|
||||||
|
case '<=':
|
||||||
|
case '==':
|
||||||
|
case '!':
|
||||||
|
case 'between':
|
||||||
|
return ValueTypes.NUMBER;
|
||||||
|
case 'interpolate':
|
||||||
|
return ValueTypes.COLOR;
|
||||||
|
default:
|
||||||
|
return ValueTypes.UNKNOWN;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param {import("../style/LiteralStyle").ExpressionValue} value Either literal or an operator.
|
||||||
|
* @returns {boolean} True if a numeric value, false otherwise
|
||||||
|
*/
|
||||||
|
export function isValueTypeNumber(value) {
|
||||||
|
return getValueType(value) === ValueTypes.NUMBER;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param {import("../style/LiteralStyle").ExpressionValue} value Either literal or an operator.
|
||||||
|
* @returns {boolean} True if a string value, false otherwise
|
||||||
|
*/
|
||||||
|
export function isValueTypeString(value) {
|
||||||
|
return getValueType(value) === ValueTypes.STRING || getValueType(value) === ValueTypes.COLOR_OR_STRING;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param {import("../style/LiteralStyle").ExpressionValue} value Either literal or an operator.
|
||||||
|
* @returns {boolean} True if a color value, false otherwise
|
||||||
|
*/
|
||||||
|
export function isValueTypeColor(value) {
|
||||||
|
return getValueType(value) === ValueTypes.COLOR || getValueType(value) === ValueTypes.COLOR_OR_STRING;
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Parses the provided expressions and produces a GLSL-compatible assignment string, such as:
|
* Parses the provided expressions and produces a GLSL-compatible assignment string, such as:
|
||||||
* `['add', ['*', ['get', 'size'], 0.001], 12] => '(a_size * (0.001)) + (12.0)'
|
* `['add', ['*', ['get', 'size'], 0.001], 12] => '(a_size * (0.001)) + (12.0)'
|
||||||
|
|||||||
@@ -2,6 +2,9 @@ import {
|
|||||||
formatArray,
|
formatArray,
|
||||||
formatColor,
|
formatColor,
|
||||||
formatNumber,
|
formatNumber,
|
||||||
|
isValueTypeColor,
|
||||||
|
isValueTypeNumber,
|
||||||
|
isValueTypeString,
|
||||||
parse,
|
parse,
|
||||||
parseLiteralStyle,
|
parseLiteralStyle,
|
||||||
ShaderBuilder
|
ShaderBuilder
|
||||||
@@ -36,6 +39,46 @@ describe('ol.webgl.ShaderBuilder', function() {
|
|||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
|
describe('value type checking', function() {
|
||||||
|
it('correctly recognizes a number value', function() {
|
||||||
|
expect(isValueTypeNumber(1234)).to.eql(true);
|
||||||
|
expect(isValueTypeNumber(['time'])).to.eql(true);
|
||||||
|
expect(isValueTypeNumber(['clamp', ['get', 'attr'], -1, 1])).to.eql(true);
|
||||||
|
expect(isValueTypeNumber(['interpolate', ['get', 'attr'], 'red', 'green'])).to.eql(false);
|
||||||
|
expect(isValueTypeNumber('yellow')).to.eql(false);
|
||||||
|
expect(isValueTypeNumber('#113366')).to.eql(false);
|
||||||
|
expect(isValueTypeNumber('rgba(252,171,48,0.62)')).to.eql(false);
|
||||||
|
});
|
||||||
|
it('correctly recognizes a color value', function() {
|
||||||
|
expect(isValueTypeColor(1234)).to.eql(false);
|
||||||
|
expect(isValueTypeColor(['time'])).to.eql(false);
|
||||||
|
expect(isValueTypeColor(['clamp', ['get', 'attr'], -1, 1])).to.eql(false);
|
||||||
|
expect(isValueTypeColor(['interpolate', ['get', 'attr'], 'red', 'green'])).to.eql(true);
|
||||||
|
expect(isValueTypeColor('yellow')).to.eql(true);
|
||||||
|
expect(isValueTypeColor('#113366')).to.eql(true);
|
||||||
|
expect(isValueTypeColor('rgba(252,171,48,0.62)')).to.eql(true);
|
||||||
|
expect(isValueTypeColor('abcd')).to.eql(false);
|
||||||
|
});
|
||||||
|
it('correctly recognizes a string value', function() {
|
||||||
|
expect(isValueTypeString(1234)).to.eql(false);
|
||||||
|
expect(isValueTypeString(['time'])).to.eql(false);
|
||||||
|
expect(isValueTypeString(['clamp', ['get', 'attr'], -1, 1])).to.eql(false);
|
||||||
|
expect(isValueTypeString(['interpolate', ['get', 'attr'], 'red', 'green'])).to.eql(false);
|
||||||
|
expect(isValueTypeString('yellow')).to.eql(true);
|
||||||
|
expect(isValueTypeString('#113366')).to.eql(true);
|
||||||
|
expect(isValueTypeString('rgba(252,171,48,0.62)')).to.eql(true);
|
||||||
|
expect(isValueTypeString('abcd')).to.eql(true);
|
||||||
|
});
|
||||||
|
it('throws on an unsupported type', function(done) {
|
||||||
|
try {
|
||||||
|
isValueTypeColor(true);
|
||||||
|
} catch (e) {
|
||||||
|
done();
|
||||||
|
}
|
||||||
|
done(true);
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
describe('getSymbolVertexShader', function() {
|
describe('getSymbolVertexShader', function() {
|
||||||
it('generates a symbol vertex shader (with varying)', function() {
|
it('generates a symbol vertex shader (with varying)', function() {
|
||||||
const builder = new ShaderBuilder();
|
const builder = new ShaderBuilder();
|
||||||
|
|||||||
Reference in New Issue
Block a user