Expressions / restored the parsing logic with better type checking
Converting expressions to GLSL is now done in ol/style/expressions, with the same logic as before in ol/webgl/ShaderBuilder.
This commit is contained in:
@@ -3,7 +3,7 @@
|
|||||||
* @module ol/style/expressions
|
* @module ol/style/expressions
|
||||||
*/
|
*/
|
||||||
|
|
||||||
import {isStringColor} from '../color.js';
|
import {asArray, isStringColor} from '../color.js';
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Base type used for literal style parameters; can be a number literal or the output of an operator,
|
* Base type used for literal style parameters; can be a number literal or the output of an operator,
|
||||||
@@ -112,6 +112,88 @@ export function getValueType(value) {
|
|||||||
return operator.getReturnType(valueArr.slice(1));
|
return operator.getReturnType(valueArr.slice(1));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Context available during the parsing of an expression.
|
||||||
|
* @typedef {Object} ParsingContext
|
||||||
|
* @property {boolean} inFragmentShader If false, means the expression output should be made for a vertex shader
|
||||||
|
*/
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Will return the number as a float with a dot separator, which is required by GLSL.
|
||||||
|
* @param {number} v Numerical value.
|
||||||
|
* @returns {string} The value as string.
|
||||||
|
*/
|
||||||
|
export function numberToGlsl(v) {
|
||||||
|
const s = v.toString();
|
||||||
|
return s.indexOf('.') === -1 ? s + '.0' : s;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Will return the number array as a float with a dot separator, concatenated with ', '.
|
||||||
|
* @param {Array<number>} array Numerical values array.
|
||||||
|
* @returns {string} The array as a vector, e. g.: `vec3(1.0, 2.0, 3.0)`.
|
||||||
|
*/
|
||||||
|
export function arrayToGlsl(array) {
|
||||||
|
if (array.length < 2 || array.length > 4) {
|
||||||
|
throw new Error('`formatArray` can only output `vec2`, `vec3` or `vec4` arrays.');
|
||||||
|
}
|
||||||
|
return `vec${array.length}(${array.map(numberToGlsl).join(', ')})`;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Will normalize and converts to string a `vec4` color array compatible with GLSL.
|
||||||
|
* @param {string|import("../color.js").Color} color Color either in string format or [r, g, b, a] array format,
|
||||||
|
* with RGB components in the 0..255 range and the alpha component in the 0..1 range.
|
||||||
|
* Note that the final array will always have 4 components.
|
||||||
|
* @returns {string} The color expressed in the `vec4(1.0, 1.0, 1.0, 1.0)` form.
|
||||||
|
*/
|
||||||
|
export function colorToGlsl(color) {
|
||||||
|
const array = asArray(color).slice();
|
||||||
|
if (array.length < 4) {
|
||||||
|
array.push(1);
|
||||||
|
}
|
||||||
|
return arrayToGlsl(
|
||||||
|
array.map(function(c, i) {
|
||||||
|
return i < 3 ? c / 255 : c;
|
||||||
|
})
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Recursively parses a style expression and outputs a GLSL-compatible string. Takes in a parsing context that
|
||||||
|
* 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
|
||||||
|
* @returns {string} GLSL-compatible output
|
||||||
|
*/
|
||||||
|
export function expressionToGlsl(context, value, typeHint) {
|
||||||
|
// operator
|
||||||
|
if (Array.isArray(value) && typeof value[0] === 'string') {
|
||||||
|
const operator = Operators[value[0]];
|
||||||
|
if (operator === undefined) {
|
||||||
|
throw new Error(`Unrecognized expression operator: ${JSON.stringify(value)}`);
|
||||||
|
}
|
||||||
|
return operator.toGlsl(context, value.slice(1));
|
||||||
|
} else if ((getValueType(value) & ValueTypes.NUMBER) > 0) {
|
||||||
|
return numberToGlsl(/** @type {number} */(value));
|
||||||
|
} else if ((getValueType(value) & ValueTypes.BOOLEAN) > 0) {
|
||||||
|
return value.toString();
|
||||||
|
} else if (
|
||||||
|
((getValueType(value) & ValueTypes.STRING) > 0) &&
|
||||||
|
(typeHint === undefined || typeHint == ValueTypes.STRING)
|
||||||
|
) {
|
||||||
|
return value.toString();
|
||||||
|
} else if (
|
||||||
|
((getValueType(value) & ValueTypes.COLOR) > 0) &&
|
||||||
|
(typeHint === undefined || typeHint == ValueTypes.COLOR)
|
||||||
|
) {
|
||||||
|
return colorToGlsl(/** @type {number[]|string} */(value));
|
||||||
|
} else if ((getValueType(value) & ValueTypes.NUMBER_ARRAY) > 0) {
|
||||||
|
return arrayToGlsl(/** @type {number[]} */(value));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
function assertNumber(value) {
|
function assertNumber(value) {
|
||||||
if (!(getValueType(value) & ValueTypes.NUMBER)) {
|
if (!(getValueType(value) & ValueTypes.NUMBER)) {
|
||||||
throw new Error(`A numeric value was expected, got ${JSON.stringify(value)} instead`);
|
throw new Error(`A numeric value was expected, got ${JSON.stringify(value)} instead`);
|
||||||
@@ -138,19 +220,13 @@ function assertArgsCount(args, count) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* Context available during the parsing of an expression.
|
|
||||||
* @typedef {Object} ParsingContext
|
|
||||||
* @property {boolean} inFragmentShader If false, means the expression output should be made for a vertex shader
|
|
||||||
*/
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* An operator declaration must contain two methods: `getReturnType` which returns a type based on
|
* An operator declaration must contain two methods: `getReturnType` which returns a type based on
|
||||||
* the operator arguments, and `toGlsl` which returns a GLSL-compatible string.
|
* the operator arguments, and `toGlsl` which returns a GLSL-compatible string.
|
||||||
* Note: both methods can process arguments recursively.
|
* Note: both methods can process arguments recursively.
|
||||||
* @typedef {Object} Operator
|
* @typedef {Object} Operator
|
||||||
* @property {function(...ExpressionValue): ValueTypes|number} getReturnType Returns one or several types
|
* @property {function(Array<ExpressionValue>): ValueTypes|number} getReturnType Returns one or several types
|
||||||
* @property {function(ParsingContext, ...ExpressionValue): string} toGlsl Returns a GLSL-compatible string
|
* @property {function(ParsingContext, Array<ExpressionValue>): string} toGlsl Returns a GLSL-compatible string
|
||||||
*/
|
*/
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -159,218 +235,225 @@ function assertArgsCount(args, count) {
|
|||||||
*/
|
*/
|
||||||
export const Operators = {
|
export const Operators = {
|
||||||
'get': {
|
'get': {
|
||||||
getReturnType: function(...args) {
|
getReturnType: function(args) {
|
||||||
return ValueTypes.ANY;
|
return ValueTypes.ANY;
|
||||||
},
|
},
|
||||||
toGlsl: function(context, ...args) {
|
toGlsl: function(context, args) {
|
||||||
const prefix = context.inFragmentShader ? 'v_' : 'a_';
|
const prefix = context.inFragmentShader ? 'v_' : 'a_';
|
||||||
assertArgsCount(args, 1);
|
assertArgsCount(args, 1);
|
||||||
assertString(args[0]);
|
assertString(args[0]);
|
||||||
return prefix + args[0];
|
return prefix + expressionToGlsl(context, args[0]);
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
'var': {
|
'var': {
|
||||||
getReturnType: function(...args) {
|
getReturnType: function(args) {
|
||||||
return ValueTypes.ANY;
|
return ValueTypes.ANY;
|
||||||
},
|
},
|
||||||
toGlsl: function(context, ...args) {
|
toGlsl: function(context, args) {
|
||||||
assertArgsCount(args, 1);
|
assertArgsCount(args, 1);
|
||||||
assertString(args[0]);
|
assertString(args[0]);
|
||||||
return `u_${args[0]}`;
|
return `u_${expressionToGlsl(context, args[0])}`;
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
'time': {
|
'time': {
|
||||||
getReturnType: function(...args) {
|
getReturnType: function(args) {
|
||||||
return ValueTypes.NUMBER;
|
return ValueTypes.NUMBER;
|
||||||
},
|
},
|
||||||
toGlsl: function(context, ...args) {
|
toGlsl: function(context, args) {
|
||||||
assertArgsCount(args, 0);
|
assertArgsCount(args, 0);
|
||||||
return 'u_time';
|
return 'u_time';
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
'*': {
|
'*': {
|
||||||
getReturnType: function(...args) {
|
getReturnType: function(args) {
|
||||||
return ValueTypes.NUMBER;
|
return ValueTypes.NUMBER;
|
||||||
},
|
},
|
||||||
toGlsl: function(context, ...args) {
|
toGlsl: function(context, args) {
|
||||||
assertArgsCount(args, 2);
|
assertArgsCount(args, 2);
|
||||||
assertNumber(args[0]);
|
assertNumber(args[0]);
|
||||||
assertNumber(args[1]);
|
assertNumber(args[1]);
|
||||||
return `(${args[0]} * ${args[1]})`;
|
return `(${expressionToGlsl(context, args[0])} * ${expressionToGlsl(context, args[1])})`;
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
'/': {
|
'/': {
|
||||||
getReturnType: function(...args) {
|
getReturnType: function(args) {
|
||||||
return ValueTypes.NUMBER;
|
return ValueTypes.NUMBER;
|
||||||
},
|
},
|
||||||
toGlsl: function(context, ...args) {
|
toGlsl: function(context, args) {
|
||||||
assertArgsCount(args, 2);
|
assertArgsCount(args, 2);
|
||||||
assertNumber(args[0]);
|
assertNumber(args[0]);
|
||||||
assertNumber(args[1]);
|
assertNumber(args[1]);
|
||||||
return `(${args[0]} / ${args[1]})`;
|
return `(${expressionToGlsl(context, args[0])} / ${expressionToGlsl(context, args[1])})`;
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
'+': {
|
'+': {
|
||||||
getReturnType: function(...args) {
|
getReturnType: function(args) {
|
||||||
return ValueTypes.NUMBER;
|
return ValueTypes.NUMBER;
|
||||||
},
|
},
|
||||||
toGlsl: function(context, ...args) {
|
toGlsl: function(context, args) {
|
||||||
assertArgsCount(args, 2);
|
assertArgsCount(args, 2);
|
||||||
assertNumber(args[0]);
|
assertNumber(args[0]);
|
||||||
assertNumber(args[1]);
|
assertNumber(args[1]);
|
||||||
return `(${args[0]} + ${args[1]})`;
|
return `(${expressionToGlsl(context, args[0])} + ${expressionToGlsl(context, args[1])})`;
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
'-': {
|
'-': {
|
||||||
getReturnType: function(...args) {
|
getReturnType: function(args) {
|
||||||
return ValueTypes.NUMBER;
|
return ValueTypes.NUMBER;
|
||||||
},
|
},
|
||||||
toGlsl: function(context, ...args) {
|
toGlsl: function(context, args) {
|
||||||
assertArgsCount(args, 2);
|
assertArgsCount(args, 2);
|
||||||
assertNumber(args[0]);
|
assertNumber(args[0]);
|
||||||
assertNumber(args[1]);
|
assertNumber(args[1]);
|
||||||
return `(${args[0]} - ${args[1]})`;
|
return `(${expressionToGlsl(context, args[0])} - ${expressionToGlsl(context, args[1])})`;
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
'clamp': {
|
'clamp': {
|
||||||
getReturnType: function(...args) {
|
getReturnType: function(args) {
|
||||||
return ValueTypes.NUMBER;
|
return ValueTypes.NUMBER;
|
||||||
},
|
},
|
||||||
toGlsl: function(context, ...args) {
|
toGlsl: function(context, args) {
|
||||||
assertArgsCount(args, 3);
|
assertArgsCount(args, 3);
|
||||||
assertNumber(args[0]);
|
assertNumber(args[0]);
|
||||||
assertNumber(args[1]);
|
assertNumber(args[1]);
|
||||||
assertNumber(args[2]);
|
assertNumber(args[2]);
|
||||||
return `clamp(${args[0]}, ${args[1]}, ${args[2]})`;
|
const min = expressionToGlsl(context, args[1]);
|
||||||
|
const max = expressionToGlsl(context, args[2]);
|
||||||
|
return `clamp(${expressionToGlsl(context, args[0])}, ${min}, ${max})`;
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
'stretch': {
|
'stretch': {
|
||||||
getReturnType: function(...args) {
|
getReturnType: function(args) {
|
||||||
return ValueTypes.NUMBER;
|
return ValueTypes.NUMBER;
|
||||||
},
|
},
|
||||||
toGlsl: function(context, ...args) {
|
toGlsl: function(context, args) {
|
||||||
assertArgsCount(args, 5);
|
assertArgsCount(args, 5);
|
||||||
assertNumber(args[0]);
|
assertNumber(args[0]);
|
||||||
assertNumber(args[1]);
|
assertNumber(args[1]);
|
||||||
assertNumber(args[2]);
|
assertNumber(args[2]);
|
||||||
assertNumber(args[3]);
|
assertNumber(args[3]);
|
||||||
assertNumber(args[4]);
|
assertNumber(args[4]);
|
||||||
const low1 = args[1];
|
const low1 = expressionToGlsl(context, args[1]);
|
||||||
const high1 = args[2];
|
const high1 = expressionToGlsl(context, args[2]);
|
||||||
const low2 = args[3];
|
const low2 = expressionToGlsl(context, args[3]);
|
||||||
const high2 = args[4];
|
const high2 = expressionToGlsl(context, args[4]);
|
||||||
return `((clamp(${args[0]}, ${low1}, ${high1}) - ${low1}) * ((${high2} - ${low2}) / (${high1} - ${low1})) + ${low2})`;
|
return `((clamp(${expressionToGlsl(context, args[0])}, ${low1}, ${high1}) - ${low1}) * ((${high2} - ${low2}) / (${high1} - ${low1})) + ${low2})`;
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
'mod': {
|
'mod': {
|
||||||
getReturnType: function(...args) {
|
getReturnType: function(args) {
|
||||||
return ValueTypes.NUMBER;
|
return ValueTypes.NUMBER;
|
||||||
},
|
},
|
||||||
toGlsl: function(context, ...args) {
|
toGlsl: function(context, args) {
|
||||||
assertArgsCount(args, 2);
|
assertArgsCount(args, 2);
|
||||||
assertNumber(args[0]);
|
assertNumber(args[0]);
|
||||||
assertNumber(args[1]);
|
assertNumber(args[1]);
|
||||||
return `mod(${args[0]}, ${args[1]})`;
|
return `mod(${expressionToGlsl(context, args[0])}, ${expressionToGlsl(context, args[1])})`;
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
'pow': {
|
'pow': {
|
||||||
getReturnType: function(...args) {
|
getReturnType: function(args) {
|
||||||
return ValueTypes.NUMBER;
|
return ValueTypes.NUMBER;
|
||||||
},
|
},
|
||||||
toGlsl: function(context, ...args) {
|
toGlsl: function(context, args) {
|
||||||
assertArgsCount(args, 2);
|
assertArgsCount(args, 2);
|
||||||
assertNumber(args[0]);
|
assertNumber(args[0]);
|
||||||
assertNumber(args[1]);
|
assertNumber(args[1]);
|
||||||
return `pow(${args[0]}, ${args[1]})`;
|
return `pow(${expressionToGlsl(context, args[0])}, ${expressionToGlsl(context, args[1])})`;
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
'>': {
|
'>': {
|
||||||
getReturnType: function(...args) {
|
getReturnType: function(args) {
|
||||||
return ValueTypes.BOOLEAN;
|
return ValueTypes.BOOLEAN;
|
||||||
},
|
},
|
||||||
toGlsl: function(context, ...args) {
|
toGlsl: function(context, args) {
|
||||||
assertArgsCount(args, 2);
|
assertArgsCount(args, 2);
|
||||||
assertNumber(args[0]);
|
assertNumber(args[0]);
|
||||||
assertNumber(args[1]);
|
assertNumber(args[1]);
|
||||||
return `(${args[0]} > ${args[1]})`;
|
return `(${expressionToGlsl(context, args[0])} > ${expressionToGlsl(context, args[1])})`;
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
'>=': {
|
'>=': {
|
||||||
getReturnType: function(...args) {
|
getReturnType: function(args) {
|
||||||
return ValueTypes.BOOLEAN;
|
return ValueTypes.BOOLEAN;
|
||||||
},
|
},
|
||||||
toGlsl: function(context, ...args) {
|
toGlsl: function(context, args) {
|
||||||
assertArgsCount(args, 2);
|
assertArgsCount(args, 2);
|
||||||
assertNumber(args[0]);
|
assertNumber(args[0]);
|
||||||
assertNumber(args[1]);
|
assertNumber(args[1]);
|
||||||
return `(${args[0]} >= ${args[1]})`;
|
return `(${expressionToGlsl(context, args[0])} >= ${expressionToGlsl(context, args[1])})`;
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
'<': {
|
'<': {
|
||||||
getReturnType: function(...args) {
|
getReturnType: function(args) {
|
||||||
return ValueTypes.BOOLEAN;
|
return ValueTypes.BOOLEAN;
|
||||||
},
|
},
|
||||||
toGlsl: function(context, ...args) {
|
toGlsl: function(context, args) {
|
||||||
assertArgsCount(args, 2);
|
assertArgsCount(args, 2);
|
||||||
assertNumber(args[0]);
|
assertNumber(args[0]);
|
||||||
assertNumber(args[1]);
|
assertNumber(args[1]);
|
||||||
return `(${args[0]} < ${args[1]})`;
|
return `(${expressionToGlsl(context, args[0])} < ${expressionToGlsl(context, args[1])})`;
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
'<=': {
|
'<=': {
|
||||||
getReturnType: function(...args) {
|
getReturnType: function(args) {
|
||||||
return ValueTypes.BOOLEAN;
|
return ValueTypes.BOOLEAN;
|
||||||
},
|
},
|
||||||
toGlsl: function(context, ...args) {
|
toGlsl: function(context, args) {
|
||||||
assertArgsCount(args, 2);
|
assertArgsCount(args, 2);
|
||||||
assertNumber(args[0]);
|
assertNumber(args[0]);
|
||||||
assertNumber(args[1]);
|
assertNumber(args[1]);
|
||||||
return `(${args[0]} <= ${args[1]})`;
|
return `(${expressionToGlsl(context, args[0])} <= ${expressionToGlsl(context, args[1])})`;
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
'==': {
|
'==': {
|
||||||
getReturnType: function(...args) {
|
getReturnType: function(args) {
|
||||||
return ValueTypes.BOOLEAN;
|
return ValueTypes.BOOLEAN;
|
||||||
},
|
},
|
||||||
toGlsl: function(context, ...args) {
|
toGlsl: function(context, args) {
|
||||||
assertArgsCount(args, 2);
|
assertArgsCount(args, 2);
|
||||||
assertNumber(args[0]);
|
assertNumber(args[0]);
|
||||||
assertNumber(args[1]);
|
assertNumber(args[1]);
|
||||||
return `(${args[0]} == ${args[1]})`;
|
return `(${expressionToGlsl(context, args[0])} == ${expressionToGlsl(context, args[1])})`;
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
'!': {
|
'!': {
|
||||||
getReturnType: function(...args) {
|
getReturnType: function(args) {
|
||||||
return ValueTypes.BOOLEAN;
|
return ValueTypes.BOOLEAN;
|
||||||
},
|
},
|
||||||
toGlsl: function(context, ...args) {
|
toGlsl: function(context, args) {
|
||||||
assertArgsCount(args, 1);
|
assertArgsCount(args, 1);
|
||||||
assertBoolean(args[0]);
|
assertBoolean(args[0]);
|
||||||
return `(!${args[0]})`;
|
return `(!${expressionToGlsl(context, args[0])})`;
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
'between': {
|
'between': {
|
||||||
getReturnType: function(...args) {
|
getReturnType: function(args) {
|
||||||
return ValueTypes.BOOLEAN;
|
return ValueTypes.BOOLEAN;
|
||||||
},
|
},
|
||||||
toGlsl: function(context, ...args) {
|
toGlsl: function(context, args) {
|
||||||
assertArgsCount(args, 3);
|
assertArgsCount(args, 3);
|
||||||
assertNumber(args[0]);
|
assertNumber(args[0]);
|
||||||
assertNumber(args[1]);
|
assertNumber(args[1]);
|
||||||
assertNumber(args[2]);
|
assertNumber(args[2]);
|
||||||
return `(${args[0]} >= ${args[1]} && ${args[0]} <= ${args[2]})`;
|
const min = expressionToGlsl(context, args[1]);
|
||||||
|
const max = expressionToGlsl(context, args[2]);
|
||||||
|
const value = expressionToGlsl(context, args[0]);
|
||||||
|
return `(${value} >= ${min} && ${value} <= ${max})`;
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
'interpolate': {
|
'interpolate': {
|
||||||
getReturnType: function(...args) {
|
getReturnType: function(args) {
|
||||||
return ValueTypes.COLOR;
|
return ValueTypes.COLOR;
|
||||||
},
|
},
|
||||||
toGlsl: function(context, ...args) {
|
toGlsl: function(context, args) {
|
||||||
assertArgsCount(args, 3);
|
assertArgsCount(args, 3);
|
||||||
assertNumber(args[0]);
|
assertNumber(args[0]);
|
||||||
assertColor(args[1]);
|
assertColor(args[1]);
|
||||||
assertColor(args[2]);
|
assertColor(args[2]);
|
||||||
return `mix(${args[1]}, ${args[2]}, ${args[0]})`;
|
const start = expressionToGlsl(context, args[1], ValueTypes.COLOR);
|
||||||
|
const end = expressionToGlsl(context, args[2], ValueTypes.COLOR);
|
||||||
|
return `mix(${start}, ${end}, ${expressionToGlsl(context, args[0])})`;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|||||||
@@ -1,8 +1,58 @@
|
|||||||
import {getValueType, ValueTypes} from '../../../../src/ol/style/expressions.js';
|
import {
|
||||||
|
arrayToGlsl, colorToGlsl,
|
||||||
|
expressionToGlsl,
|
||||||
|
getValueType,
|
||||||
|
numberToGlsl,
|
||||||
|
ValueTypes
|
||||||
|
} from '../../../../src/ol/style/expressions.js';
|
||||||
|
|
||||||
|
|
||||||
describe('ol.style.expressions', function() {
|
describe('ol.style.expressions', function() {
|
||||||
|
|
||||||
|
describe('numberToGlsl', function() {
|
||||||
|
it('does a simple transform when a fraction is present', function() {
|
||||||
|
expect(numberToGlsl(1.3456)).to.eql('1.3456');
|
||||||
|
});
|
||||||
|
it('adds a fraction separator when missing', function() {
|
||||||
|
expect(numberToGlsl(1)).to.eql('1.0');
|
||||||
|
expect(numberToGlsl(2.0)).to.eql('2.0');
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
describe('arrayToGlsl', function() {
|
||||||
|
it('outputs numbers with dot separators', function() {
|
||||||
|
expect(arrayToGlsl([1, 0, 3.45, 0.8888])).to.eql('vec4(1.0, 0.0, 3.45, 0.8888)');
|
||||||
|
expect(arrayToGlsl([3, 4])).to.eql('vec2(3.0, 4.0)');
|
||||||
|
});
|
||||||
|
it('throws on invalid lengths', function() {
|
||||||
|
let thrown = false;
|
||||||
|
try {
|
||||||
|
arrayToGlsl([3]);
|
||||||
|
} catch (e) {
|
||||||
|
thrown = true;
|
||||||
|
}
|
||||||
|
try {
|
||||||
|
arrayToGlsl([3, 2, 1, 0, -1]);
|
||||||
|
} catch (e) {
|
||||||
|
thrown = true;
|
||||||
|
}
|
||||||
|
expect(thrown).to.be(true);
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
describe('colorToGlsl', function() {
|
||||||
|
it('normalizes color and outputs numbers with dot separators', function() {
|
||||||
|
expect(colorToGlsl([100, 0, 255])).to.eql('vec4(0.39215686274509803, 0.0, 1.0, 1.0)');
|
||||||
|
expect(colorToGlsl([100, 0, 255, 1])).to.eql('vec4(0.39215686274509803, 0.0, 1.0, 1.0)');
|
||||||
|
});
|
||||||
|
it('handles colors in string format', function() {
|
||||||
|
expect(colorToGlsl('red')).to.eql('vec4(1.0, 0.0, 0.0, 1.0)');
|
||||||
|
expect(colorToGlsl('#00ff99')).to.eql('vec4(0.0, 1.0, 0.6, 1.0)');
|
||||||
|
expect(colorToGlsl('rgb(100, 0, 255)')).to.eql('vec4(0.39215686274509803, 0.0, 1.0, 1.0)');
|
||||||
|
expect(colorToGlsl('rgba(100, 0, 255, 0.3)')).to.eql('vec4(0.39215686274509803, 0.0, 1.0, 0.3)');
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
describe('getValueType', function() {
|
describe('getValueType', function() {
|
||||||
|
|
||||||
it('correctly analyzes a literal value', function() {
|
it('correctly analyzes a literal value', function() {
|
||||||
@@ -60,4 +110,33 @@ describe('ol.style.expressions', function() {
|
|||||||
|
|
||||||
});
|
});
|
||||||
|
|
||||||
|
describe('expressionToGlsl', function() {
|
||||||
|
let context;
|
||||||
|
|
||||||
|
beforeEach(function() {
|
||||||
|
context = {};
|
||||||
|
});
|
||||||
|
|
||||||
|
it('correctly converts expressions to GLSL', function() {
|
||||||
|
expect(expressionToGlsl(context, ['get', 'myAttr'])).to.eql('a_myAttr');
|
||||||
|
expect(expressionToGlsl(context, ['var', 'myValue'])).to.eql('u_myValue');
|
||||||
|
expect(expressionToGlsl(context, ['time'])).to.eql('u_time');
|
||||||
|
expect(expressionToGlsl(context, ['+', ['*', ['get', 'size'], 0.001], 12])).to.eql('((a_size * 0.001) + 12.0)');
|
||||||
|
expect(expressionToGlsl(context, ['/', ['-', ['get', 'size'], 20], 100])).to.eql('((a_size - 20.0) / 100.0)');
|
||||||
|
expect(expressionToGlsl(context, ['clamp', ['get', 'attr2'], ['get', 'attr3'], 20])).to.eql('clamp(a_attr2, a_attr3, 20.0)');
|
||||||
|
expect(expressionToGlsl(context, ['stretch', ['get', 'size'], 10, 100, 4, 8])).to.eql('((clamp(a_size, 10.0, 100.0) - 10.0) * ((8.0 - 4.0) / (100.0 - 10.0)) + 4.0)');
|
||||||
|
expect(expressionToGlsl(context, ['pow', ['mod', ['time'], 10], 2])).to.eql('pow(mod(u_time, 10.0), 2.0)');
|
||||||
|
expect(expressionToGlsl(context, ['>', 10, ['get', 'attr4']])).to.eql('(10.0 > a_attr4)');
|
||||||
|
expect(expressionToGlsl(context, ['>=', 10, ['get', 'attr4']])).to.eql('(10.0 >= a_attr4)');
|
||||||
|
expect(expressionToGlsl(context, ['<', 10, ['get', 'attr4']])).to.eql('(10.0 < a_attr4)');
|
||||||
|
expect(expressionToGlsl(context, ['<=', 10, ['get', 'attr4']])).to.eql('(10.0 <= a_attr4)');
|
||||||
|
expect(expressionToGlsl(context, ['==', 10, ['get', 'attr4']])).to.eql('(10.0 == a_attr4)');
|
||||||
|
expect(expressionToGlsl(context, ['between', ['get', 'attr4'], -4.0, 5.0])).to.eql('(a_attr4 >= -4.0 && a_attr4 <= 5.0)');
|
||||||
|
expect(expressionToGlsl(context, ['!', ['get', 'attr4']])).to.eql('(!a_attr4)');
|
||||||
|
expect(expressionToGlsl(context, ['interpolate', ['get', 'attr4'], [255, 255, 255, 1], 'transparent'])).to.eql(
|
||||||
|
'mix(vec4(1.0, 1.0, 1.0, 1.0), vec4(0.0, 0.0, 0.0, 0.0), a_attr4)');
|
||||||
|
});
|
||||||
|
|
||||||
|
});
|
||||||
|
|
||||||
});
|
});
|
||||||
|
|||||||
Reference in New Issue
Block a user