ShaderBuilder / adapt logic & tests to new expressions module
This commit is contained in:
@@ -1,112 +1,17 @@
|
||||
import {
|
||||
check,
|
||||
formatArray,
|
||||
formatColor,
|
||||
formatNumber,
|
||||
isValueTypeColor,
|
||||
isValueTypeNumber,
|
||||
isValueTypeString,
|
||||
parse,
|
||||
parseLiteralStyle,
|
||||
ShaderBuilder,
|
||||
ValueTypes
|
||||
} from '../../../../src/ol/webgl/ShaderBuilder.js';
|
||||
import {parseLiteralStyle, ShaderBuilder} from '../../../../src/ol/webgl/ShaderBuilder.js';
|
||||
import {arrayToGlsl, colorToGlsl, numberToGlsl} from '../../../../src/ol/style/expressions.js';
|
||||
|
||||
describe('ol.webgl.ShaderBuilder', function() {
|
||||
|
||||
describe('formatNumber', function() {
|
||||
it('does a simple transform when a fraction is present', function() {
|
||||
expect(formatNumber(1.3456)).to.eql('1.3456');
|
||||
});
|
||||
it('adds a fraction separator when missing', function() {
|
||||
expect(formatNumber(1)).to.eql('1.0');
|
||||
expect(formatNumber(2.0)).to.eql('2.0');
|
||||
});
|
||||
});
|
||||
|
||||
describe('formatArray', function() {
|
||||
it('outputs numbers with dot separators', function() {
|
||||
expect(formatArray([1, 0, 3.45, 0.8888])).to.eql('vec4(1.0, 0.0, 3.45, 0.8888)');
|
||||
expect(formatArray([3, 4])).to.eql('vec2(3.0, 4.0)');
|
||||
});
|
||||
it('throws on invalid lengths', function() {
|
||||
let thrown = false;
|
||||
try {
|
||||
formatArray([3]);
|
||||
} catch (e) {
|
||||
thrown = true;
|
||||
}
|
||||
try {
|
||||
formatArray([3, 2, 1, 0, -1]);
|
||||
} catch (e) {
|
||||
thrown = true;
|
||||
}
|
||||
expect(thrown).to.be(true);
|
||||
});
|
||||
});
|
||||
|
||||
describe('formatColor', function() {
|
||||
it('normalizes color and outputs numbers with dot separators', function() {
|
||||
expect(formatColor([100, 0, 255])).to.eql('vec4(0.39215686274509803, 0.0, 1.0, 1.0)');
|
||||
expect(formatColor([100, 0, 255, 1])).to.eql('vec4(0.39215686274509803, 0.0, 1.0, 1.0)');
|
||||
});
|
||||
it('handles colors in string format', function() {
|
||||
expect(formatColor('red')).to.eql('vec4(1.0, 0.0, 0.0, 1.0)');
|
||||
expect(formatColor('#00ff99')).to.eql('vec4(0.0, 1.0, 0.6, 1.0)');
|
||||
expect(formatColor('rgb(100, 0, 255)')).to.eql('vec4(0.39215686274509803, 0.0, 1.0, 1.0)');
|
||||
expect(formatColor('rgba(100, 0, 255, 0.3)')).to.eql('vec4(0.39215686274509803, 0.0, 1.0, 0.3)');
|
||||
});
|
||||
});
|
||||
|
||||
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() {
|
||||
it('generates a symbol vertex shader (with varying)', function() {
|
||||
const builder = new ShaderBuilder();
|
||||
builder.addVarying('v_opacity', 'float', formatNumber(0.4));
|
||||
builder.addVarying('v_test', 'vec3', formatArray([1, 2, 3]));
|
||||
builder.setSizeExpression(`vec2(${formatNumber(6)})`);
|
||||
builder.setSymbolOffsetExpression(formatArray([5, -7]));
|
||||
builder.setColorExpression(formatColor([80, 0, 255, 1]));
|
||||
builder.setTextureCoordinateExpression(formatArray([0, 0.5, 0.5, 1]));
|
||||
builder.addVarying('v_opacity', 'float', numberToGlsl(0.4));
|
||||
builder.addVarying('v_test', 'vec3', arrayToGlsl([1, 2, 3]));
|
||||
builder.setSizeExpression(`vec2(${numberToGlsl(6)})`);
|
||||
builder.setSymbolOffsetExpression(arrayToGlsl([5, -7]));
|
||||
builder.setColorExpression(colorToGlsl([80, 0, 255, 1]));
|
||||
builder.setTextureCoordinateExpression(arrayToGlsl([0, 0.5, 0.5, 1]));
|
||||
|
||||
expect(builder.getSymbolVertexShader()).to.eql(`precision mediump float;
|
||||
uniform mat4 u_projectionMatrix;
|
||||
@@ -144,10 +49,10 @@ void main(void) {
|
||||
const builder = new ShaderBuilder();
|
||||
builder.addUniform('float u_myUniform');
|
||||
builder.addAttribute('vec2 a_myAttr');
|
||||
builder.setSizeExpression(`vec2(${formatNumber(6)})`);
|
||||
builder.setSymbolOffsetExpression(formatArray([5, -7]));
|
||||
builder.setColorExpression(formatColor([80, 0, 255, 1]));
|
||||
builder.setTextureCoordinateExpression(formatArray([0, 0.5, 0.5, 1]));
|
||||
builder.setSizeExpression(`vec2(${numberToGlsl(6)})`);
|
||||
builder.setSymbolOffsetExpression(arrayToGlsl([5, -7]));
|
||||
builder.setColorExpression(colorToGlsl([80, 0, 255, 1]));
|
||||
builder.setTextureCoordinateExpression(arrayToGlsl([0, 0.5, 0.5, 1]));
|
||||
|
||||
expect(builder.getSymbolVertexShader()).to.eql(`precision mediump float;
|
||||
uniform mat4 u_projectionMatrix;
|
||||
@@ -181,10 +86,10 @@ void main(void) {
|
||||
});
|
||||
it('generates a symbol vertex shader (with rotateWithView)', function() {
|
||||
const builder = new ShaderBuilder();
|
||||
builder.setSizeExpression(`vec2(${formatNumber(6)})`);
|
||||
builder.setSymbolOffsetExpression(formatArray([5, -7]));
|
||||
builder.setColorExpression(formatColor([80, 0, 255, 1]));
|
||||
builder.setTextureCoordinateExpression(formatArray([0, 0.5, 0.5, 1]));
|
||||
builder.setSizeExpression(`vec2(${numberToGlsl(6)})`);
|
||||
builder.setSymbolOffsetExpression(arrayToGlsl([5, -7]));
|
||||
builder.setColorExpression(colorToGlsl([80, 0, 255, 1]));
|
||||
builder.setTextureCoordinateExpression(arrayToGlsl([0, 0.5, 0.5, 1]));
|
||||
builder.setSymbolRotateWithView(true);
|
||||
|
||||
expect(builder.getSymbolVertexShader()).to.eql(`precision mediump float;
|
||||
@@ -222,12 +127,12 @@ void main(void) {
|
||||
describe('getSymbolFragmentShader', function() {
|
||||
it('generates a symbol fragment shader (with varying)', function() {
|
||||
const builder = new ShaderBuilder();
|
||||
builder.addVarying('v_opacity', 'float', formatNumber(0.4));
|
||||
builder.addVarying('v_test', 'vec3', formatArray([1, 2, 3]));
|
||||
builder.setSizeExpression(`vec2(${formatNumber(6)})`);
|
||||
builder.setSymbolOffsetExpression(formatArray([5, -7]));
|
||||
builder.setColorExpression(formatColor([80, 0, 255]));
|
||||
builder.setTextureCoordinateExpression(formatArray([0, 0.5, 0.5, 1]));
|
||||
builder.addVarying('v_opacity', 'float', numberToGlsl(0.4));
|
||||
builder.addVarying('v_test', 'vec3', arrayToGlsl([1, 2, 3]));
|
||||
builder.setSizeExpression(`vec2(${numberToGlsl(6)})`);
|
||||
builder.setSymbolOffsetExpression(arrayToGlsl([5, -7]));
|
||||
builder.setColorExpression(colorToGlsl([80, 0, 255]));
|
||||
builder.setTextureCoordinateExpression(arrayToGlsl([0, 0.5, 0.5, 1]));
|
||||
|
||||
expect(builder.getSymbolFragmentShader()).to.eql(`precision mediump float;
|
||||
uniform float u_time;
|
||||
@@ -246,10 +151,10 @@ void main(void) {
|
||||
const builder = new ShaderBuilder();
|
||||
builder.addUniform('float u_myUniform');
|
||||
builder.addUniform('vec2 u_myUniform2');
|
||||
builder.setSizeExpression(`vec2(${formatNumber(6)})`);
|
||||
builder.setSymbolOffsetExpression(formatArray([5, -7]));
|
||||
builder.setColorExpression(formatColor([255, 255, 255, 1]));
|
||||
builder.setTextureCoordinateExpression(formatArray([0, 0.5, 0.5, 1]));
|
||||
builder.setSizeExpression(`vec2(${numberToGlsl(6)})`);
|
||||
builder.setSymbolOffsetExpression(arrayToGlsl([5, -7]));
|
||||
builder.setColorExpression(colorToGlsl([255, 255, 255, 1]));
|
||||
builder.setTextureCoordinateExpression(arrayToGlsl([0, 0.5, 0.5, 1]));
|
||||
builder.setFragmentDiscardExpression('u_myUniform > 0.5');
|
||||
|
||||
expect(builder.getSymbolFragmentShader()).to.eql(`precision mediump float;
|
||||
@@ -267,154 +172,6 @@ void main(void) {
|
||||
});
|
||||
});
|
||||
|
||||
describe('check', function() {
|
||||
|
||||
it('does not throw on valid expressions', function(done) {
|
||||
check(1);
|
||||
check('attr');
|
||||
check('rgba(12, 34, 56, 0.5)');
|
||||
check([255, 255, 255, 1]);
|
||||
check([255, 255, 255]);
|
||||
check(['get', 'myAttr']);
|
||||
check(['var', 'myValue']);
|
||||
check(['time']);
|
||||
check(['+', ['*', ['get', 'size'], 0.001], 12]);
|
||||
check(['/', ['-', ['get', 'size'], 0.001], 12]);
|
||||
check(['clamp', ['get', 'attr2'], ['get', 'attr3'], 20]);
|
||||
check(['stretch', ['get', 'size'], 10, 100, 4, 8]);
|
||||
check(['mod', ['pow', ['get', 'size'], 0.5], 12]);
|
||||
check(['>', 10, ['get', 'attr4']]);
|
||||
check(['>=', 10, ['get', 'attr4']]);
|
||||
check(['<', 10, ['get', 'attr4']]);
|
||||
check(['<=', 10, ['get', 'attr4']]);
|
||||
check(['==', 10, ['get', 'attr4']]);
|
||||
check(['between', ['get', 'attr4'], -4.0, 5.0]);
|
||||
check(['!', ['get', 'attr4']]);
|
||||
check(['interpolate', ['get', 'attr4'], 'green', '#3344FF']);
|
||||
check(['interpolate', 0.2, [10, 20, 30], [255, 255, 255, 1]]);
|
||||
done();
|
||||
});
|
||||
|
||||
it('throws on unsupported types for operators', function() {
|
||||
let thrown = false;
|
||||
try {
|
||||
check(['var', 1234]);
|
||||
} catch (e) {
|
||||
thrown = true;
|
||||
}
|
||||
try {
|
||||
check(['<', 0, 'aa']);
|
||||
} catch (e) {
|
||||
thrown = true;
|
||||
}
|
||||
try {
|
||||
check(['+', true, ['get', 'attr']]);
|
||||
} catch (e) {
|
||||
thrown = true;
|
||||
}
|
||||
try {
|
||||
check(['interpolate', ['get', 'attr4'], 1, '#3344FF']);
|
||||
} catch (e) {
|
||||
thrown = true;
|
||||
}
|
||||
expect(thrown).to.be(true);
|
||||
});
|
||||
|
||||
it('throws with the wrong number of arguments', function() {
|
||||
let thrown = false;
|
||||
try {
|
||||
check(['var', 1234, 456]);
|
||||
} catch (e) {
|
||||
thrown = true;
|
||||
}
|
||||
try {
|
||||
check(['<', 4]);
|
||||
} catch (e) {
|
||||
thrown = true;
|
||||
}
|
||||
try {
|
||||
check(['+']);
|
||||
} catch (e) {
|
||||
thrown = true;
|
||||
}
|
||||
expect(thrown).to.be(true);
|
||||
});
|
||||
|
||||
it('throws on invalid expressions', function() {
|
||||
let thrown = false;
|
||||
try {
|
||||
check(true);
|
||||
} catch (e) {
|
||||
thrown = true;
|
||||
}
|
||||
try {
|
||||
check([123, 456]);
|
||||
} catch (e) {
|
||||
thrown = true;
|
||||
}
|
||||
try {
|
||||
check(null);
|
||||
} catch (e) {
|
||||
thrown = true;
|
||||
}
|
||||
expect(thrown).to.be(true);
|
||||
});
|
||||
|
||||
});
|
||||
|
||||
describe('parse', function() {
|
||||
let attributes, prefix, variables, parseFn;
|
||||
|
||||
beforeEach(function() {
|
||||
attributes = [];
|
||||
variables = [];
|
||||
prefix = 'a_';
|
||||
parseFn = function(value, type) {
|
||||
return parse(value, attributes, prefix, variables, type);
|
||||
};
|
||||
});
|
||||
|
||||
it('parses expressions & literal values', function() {
|
||||
expect(parseFn(1)).to.eql('1.0');
|
||||
expect(parseFn('a_random_string')).to.eql('"a_random_string"');
|
||||
expect(parseFn([255, 127.5, 63.75, 0.1])).to.eql('vec4(1.0, 0.5, 0.25, 0.1)');
|
||||
expect(parseFn([255, 127.5, 63.75])).to.eql('vec4(1.0, 0.5, 0.25, 1.0)');
|
||||
expect(parseFn(['get', 'myAttr'])).to.eql('a_myAttr');
|
||||
expect(parseFn(['var', 'myValue'])).to.eql('u_myValue');
|
||||
expect(parseFn(['time'])).to.eql('u_time');
|
||||
expect(parseFn(['+', ['*', ['get', 'size'], 0.001], 12])).to.eql('((a_size * 0.001) + 12.0)');
|
||||
expect(parseFn(['/', ['-', ['get', 'size'], 20], 100])).to.eql('((a_size - 20.0) / 100.0)');
|
||||
expect(parseFn(['clamp', ['get', 'attr2'], ['get', 'attr3'], 20])).to.eql('clamp(a_attr2, a_attr3, 20.0)');
|
||||
expect(parseFn(['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(parseFn(['pow', ['mod', ['time'], 10], 2])).to.eql('pow(mod(u_time, 10.0), 2.0)');
|
||||
expect(parseFn(['>', 10, ['get', 'attr4']])).to.eql('(10.0 > a_attr4 ? 1.0 : 0.0)');
|
||||
expect(parseFn(['>=', 10, ['get', 'attr4']])).to.eql('(10.0 >= a_attr4 ? 1.0 : 0.0)');
|
||||
expect(parseFn(['<', 10, ['get', 'attr4']])).to.eql('(10.0 < a_attr4 ? 1.0 : 0.0)');
|
||||
expect(parseFn(['<=', 10, ['get', 'attr4']])).to.eql('(10.0 <= a_attr4 ? 1.0 : 0.0)');
|
||||
expect(parseFn(['==', 10, ['get', 'attr4']])).to.eql('(10.0 == a_attr4 ? 1.0 : 0.0)');
|
||||
expect(parseFn(['between', ['get', 'attr4'], -4.0, 5.0])).to.eql('(a_attr4 >= -4.0 && a_attr4 <= 5.0 ? 1.0 : 0.0)');
|
||||
expect(parseFn(['!', ['get', 'attr4']])).to.eql('(a_attr4 > 0.0 ? 0.0 : 1.0)');
|
||||
expect(parseFn(['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)');
|
||||
expect(attributes).to.eql(['myAttr', 'size', 'attr2', 'attr3', 'attr4']);
|
||||
expect(variables).to.eql(['myValue']);
|
||||
});
|
||||
|
||||
it('gives precedence to the string type unless asked otherwise', function() {
|
||||
expect(parseFn('lightgreen')).to.eql('"lightgreen"');
|
||||
expect(parseFn('lightgreen', ValueTypes.COLOR)).to.eql('vec4(0.5647058823529412, 0.9333333333333333, 0.5647058823529412, 1.0)');
|
||||
});
|
||||
|
||||
it('does not register an attribute several times', function() {
|
||||
parseFn(['get', 'myAttr']);
|
||||
parseFn(['var', 'myVar']);
|
||||
parseFn(['clamp', ['get', 'attr2'], ['get', 'attr2'], ['get', 'myAttr']]);
|
||||
parseFn(['*', ['get', 'attr2'], ['var', 'myVar']]);
|
||||
expect(attributes).to.eql(['myAttr', 'attr2']);
|
||||
expect(variables).to.eql(['myVar']);
|
||||
});
|
||||
});
|
||||
|
||||
describe('parseSymbolStyle', function() {
|
||||
it('parses a style without expressions', function() {
|
||||
const result = parseLiteralStyle({
|
||||
@@ -553,7 +310,7 @@ void main(void) {
|
||||
expect(result.builder.sizeExpression).to.eql('vec2(6.0, 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 ? 1.0 : 0.0) <= 0.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');
|
||||
|
||||
Reference in New Issue
Block a user