Expressions / adds color and array conversion operators

Also fixes existing error throwingtests which were essentially doing nothing.
This commit is contained in:
Olivier Guyot
2019-10-25 14:31:56 +02:00
parent ff3cc9b4d0
commit 4462608991
2 changed files with 96 additions and 11 deletions

View File

@@ -50,6 +50,13 @@ import {asArray, isStringColor} from '../color.js';
* * `['between', value1, value2, value3]` returns `1` if `value1` is contained between `value2` and `value3`
* (inclusively), or `0` otherwise.
*
* * Conversion operators:
* * `['array', value1, ...valueN]` creates a numerical array from `number` values; please note that the amount of
* values can currently only be 2, 3 or 4.
* * `['color', red, green, blue, alpha]` creates a `color` value from `number` values; the `alpha` parameter is
* optional; if not specified, it will be set to 1.
* Note: `red`, `green` and `blue` components must be values between 0 and 255; `alpha` between 0 and 1.
*
* Values can either be literals or another operator, as they will be evaluated recursively.
* Literal values can be of the following types:
* * `number`
@@ -265,6 +272,11 @@ function assertArgsMinCount(args, count) {
throw new Error(`At least ${count} arguments were expected, got ${args.length} instead`);
}
}
function assertArgsMaxCount(args, count) {
if (args.length > count) {
throw new Error(`At most ${count} arguments were expected, got ${args.length} instead`);
}
}
function assertArgsEven(args) {
if (args.length % 2 !== 0) {
throw new Error(`An even amount of arguments was expected, got ${args} instead`);
@@ -492,6 +504,42 @@ Operators['between'] = {
return `(${value} >= ${min} && ${value} <= ${max})`;
}
};
Operators['array'] = {
getReturnType: function(args) {
return ValueTypes.NUMBER_ARRAY;
},
toGlsl: function(context, args) {
assertArgsMinCount(args, 2);
assertArgsMaxCount(args, 4);
for (let i = 0; i < args.length; i++) {
assertNumber(args[i]);
}
const parsedArgs = args.map(function(val) {
return expressionToGlsl(context, val, ValueTypes.NUMBER);
});
return `vec${args.length}(${parsedArgs.join(', ')})`;
}
};
Operators['color'] = {
getReturnType: function(args) {
return ValueTypes.COLOR;
},
toGlsl: function(context, args) {
assertArgsMinCount(args, 3);
assertArgsMaxCount(args, 4);
for (let i = 0; i < args.length; i++) {
assertNumber(args[i]);
}
const array = /** @type {number[]} */(args);
if (args.length === 3) {
array.push(1);
}
const parsedArgs = args.map(function(val, i) {
return expressionToGlsl(context, val, ValueTypes.NUMBER) + (i < 3 ? ' / 255.0' : '');
});
return `vec${args.length}(${parsedArgs.join(', ')})`;
}
};
Operators['interpolate'] = {
getReturnType: function(args) {
let type = ValueTypes.COLOR | ValueTypes.NUMBER;

View File

@@ -138,7 +138,8 @@ describe('ol.style.expressions', function() {
expect(getValueType(['==', 10, ['get', 'attr4']])).to.eql(ValueTypes.BOOLEAN);
expect(getValueType(['between', ['get', 'attr4'], -4.0, 5.0])).to.eql(ValueTypes.BOOLEAN);
expect(getValueType(['!', ['get', 'attr4']])).to.eql(ValueTypes.BOOLEAN);
expect(getValueType(['interpolate', ['get', 'attr4'], [255, 255, 255, 1], 'transparent'])).to.eql(ValueTypes.COLOR);
expect(getValueType(['array', ['get', 'attr4'], 1, 2, 3])).to.eql(ValueTypes.NUMBER_ARRAY);
expect(getValueType(['color', ['get', 'attr4'], 1, 2])).to.eql(ValueTypes.COLOR);
});
});
@@ -171,6 +172,8 @@ describe('ol.style.expressions', function() {
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, ['array', ['get', 'attr4'], 1, 2, 3])).to.eql('vec4(a_attr4, 1.0, 2.0, 3.0)');
expect(expressionToGlsl(context, ['color', ['get', 'attr4'], 1, 2, 0.5])).to.eql('vec4(a_attr4 / 255.0, 1.0 / 255.0, 2.0 / 255.0, 0.5)');
});
it('correctly adapts output for fragment shaders', function() {
@@ -201,17 +204,39 @@ describe('ol.style.expressions', function() {
} catch (e) {
thrown = true;
}
expect(thrown).to.be(true);
thrown = false;
try {
expressionToGlsl(context, ['<', 0, 'aa']);
} catch (e) {
thrown = true;
}
expect(thrown).to.be(true);
thrown = false;
try {
expressionToGlsl(context, ['+', true, ['get', 'attr']]);
} catch (e) {
thrown = true;
}
expect(thrown).to.be(true);
thrown = false;
try {
expressionToGlsl(context, ['color', 1, 2, 'red']);
} catch (e) {
thrown = true;
}
expect(thrown).to.be(true);
thrown = false;
try {
expressionToGlsl(context, ['array', 1, '2', 3]);
} catch (e) {
thrown = true;
}
expect(thrown).to.be(true);
});
it('throws with the wrong number of arguments', function() {
@@ -221,31 +246,43 @@ describe('ol.style.expressions', function() {
} catch (e) {
thrown = true;
}
expect(thrown).to.be(true);
thrown = false;
try {
expressionToGlsl(context, ['<', 4]);
} catch (e) {
thrown = true;
}
expect(thrown).to.be(true);
thrown = false;
try {
expressionToGlsl(context, ['+']);
} catch (e) {
thrown = true;
}
expect(thrown).to.be(true);
thrown = false;
try {
expressionToGlsl(context, ['array', 1]);
} catch (e) {
thrown = true;
}
expect(thrown).to.be(true);
thrown = false;
try {
expressionToGlsl(context, ['color', 1, 2, 3, 4, 5]);
} catch (e) {
thrown = true;
}
expect(thrown).to.be(true);
});
it('throws on invalid expressions', function() {
let thrown = false;
try {
expressionToGlsl(context, true);
} catch (e) {
thrown = true;
}
try {
expressionToGlsl(context, [123, 456]);
} catch (e) {
thrown = true;
}
try {
expressionToGlsl(context, null);
} catch (e) {