Organize tests
This commit is contained in:
@@ -0,0 +1,90 @@
|
||||
import WebGLArrayBuffer, {
|
||||
getArrayClassForType,
|
||||
} from '../../../../../src/ol/webgl/Buffer.js';
|
||||
import {
|
||||
ARRAY_BUFFER,
|
||||
ELEMENT_ARRAY_BUFFER,
|
||||
STATIC_DRAW,
|
||||
STREAM_DRAW,
|
||||
} from '../../../../../src/ol/webgl.js';
|
||||
|
||||
describe('ol.webgl.Buffer', function () {
|
||||
describe('constructor', function () {
|
||||
it('sets the default usage when not specified', function () {
|
||||
const b = new WebGLArrayBuffer(ARRAY_BUFFER);
|
||||
expect(b.getUsage()).to.be(STATIC_DRAW);
|
||||
});
|
||||
|
||||
it('sets the given usage when specified', function () {
|
||||
const b = new WebGLArrayBuffer(ARRAY_BUFFER, STREAM_DRAW);
|
||||
expect(b.getUsage()).to.be(STREAM_DRAW);
|
||||
});
|
||||
|
||||
it('raises an error if an incorrect type is used', function (done) {
|
||||
try {
|
||||
new WebGLArrayBuffer(1234);
|
||||
} catch (e) {
|
||||
done();
|
||||
}
|
||||
done(true);
|
||||
});
|
||||
});
|
||||
|
||||
describe('#getArrayClassForType', function () {
|
||||
it('returns the correct typed array constructor', function () {
|
||||
expect(getArrayClassForType(ARRAY_BUFFER)).to.be(Float32Array);
|
||||
expect(getArrayClassForType(ELEMENT_ARRAY_BUFFER)).to.be(Uint32Array);
|
||||
});
|
||||
});
|
||||
|
||||
describe('populate methods', function () {
|
||||
let b;
|
||||
beforeEach(function () {
|
||||
b = new WebGLArrayBuffer(ARRAY_BUFFER);
|
||||
});
|
||||
|
||||
it('initializes the array using a size', function () {
|
||||
b.ofSize(12);
|
||||
expect(b.getArray().length).to.be(12);
|
||||
expect(b.getArray()[0]).to.be(0);
|
||||
expect(b.getArray()[11]).to.be(0);
|
||||
});
|
||||
|
||||
it('initializes the array using an array', function () {
|
||||
b.fromArray([1, 2, 3, 4, 5]);
|
||||
expect(b.getArray().length).to.be(5);
|
||||
expect(b.getArray()[0]).to.be(1);
|
||||
expect(b.getArray()[1]).to.be(2);
|
||||
expect(b.getArray()[2]).to.be(3);
|
||||
expect(b.getArray()[3]).to.be(4);
|
||||
expect(b.getArray()[4]).to.be(5);
|
||||
});
|
||||
|
||||
it('initializes the array using a size', function () {
|
||||
const a = Float32Array.of(1, 2, 3, 4, 5);
|
||||
b.fromArrayBuffer(a.buffer);
|
||||
expect(b.getArray().length).to.be(5);
|
||||
expect(b.getArray()[0]).to.be(1);
|
||||
expect(b.getArray()[1]).to.be(2);
|
||||
expect(b.getArray()[2]).to.be(3);
|
||||
expect(b.getArray()[3]).to.be(4);
|
||||
expect(b.getArray()[4]).to.be(5);
|
||||
});
|
||||
});
|
||||
|
||||
describe('#getSize', function () {
|
||||
let b;
|
||||
beforeEach(function () {
|
||||
b = new WebGLArrayBuffer(ARRAY_BUFFER);
|
||||
});
|
||||
|
||||
it('returns 0 when the buffer array is not initialized', function () {
|
||||
expect(b.getSize()).to.be(0);
|
||||
});
|
||||
|
||||
it('returns the size of the array otherwise', function () {
|
||||
b.ofSize(12);
|
||||
expect(b.getSize()).to.be(12);
|
||||
});
|
||||
});
|
||||
});
|
||||
@@ -0,0 +1,408 @@
|
||||
import WebGLArrayBuffer from '../../../../../src/ol/webgl/Buffer.js';
|
||||
import WebGLHelper, {
|
||||
DefaultUniform,
|
||||
} from '../../../../../src/ol/webgl/Helper.js';
|
||||
import {ARRAY_BUFFER, FLOAT, STATIC_DRAW} from '../../../../../src/ol/webgl.js';
|
||||
import {
|
||||
create as createTransform,
|
||||
rotate as rotateTransform,
|
||||
scale as scaleTransform,
|
||||
translate as translateTransform,
|
||||
} from '../../../../../src/ol/transform.js';
|
||||
import {getUid} from '../../../../../src/ol/util.js';
|
||||
|
||||
const VERTEX_SHADER = `
|
||||
precision mediump float;
|
||||
|
||||
uniform mat4 u_offsetScaleMatrix;
|
||||
uniform mat4 u_offsetRotateMatrix;
|
||||
uniform float u_time;
|
||||
uniform float u_zoom;
|
||||
uniform float u_resolution;
|
||||
|
||||
attribute float a_test;
|
||||
uniform float u_test;
|
||||
|
||||
void main(void) {
|
||||
gl_Position = vec4(u_test, a_test, 0.0, 1.0);
|
||||
}`;
|
||||
|
||||
const INVALID_VERTEX_SHADER = `
|
||||
precision mediump float;
|
||||
|
||||
uniform mat4 u_offsetScaleMatrix;
|
||||
uniform mat4 u_offsetRotateMatrix;
|
||||
uniform float u_time;
|
||||
uniform float u_zoom;
|
||||
uniform float u_resolution;
|
||||
|
||||
bla
|
||||
uniform float u_test;
|
||||
|
||||
void main(void) {
|
||||
gl_Position = vec4(u_test, a_test, 0.0, 1.0);
|
||||
}`;
|
||||
|
||||
const FRAGMENT_SHADER = `
|
||||
precision mediump float;
|
||||
|
||||
void main(void) {
|
||||
gl_FragColor = vec4(1.0, 1.0, 1.0, 1.0);
|
||||
}`;
|
||||
|
||||
const INVALID_FRAGMENT_SHADER = `
|
||||
precision mediump float;
|
||||
|
||||
void main(void) {
|
||||
gl_FragColor = vec4(oops, 1.0, 1.0, 1.0);
|
||||
}`;
|
||||
|
||||
describe('ol/webgl/WebGLHelper', function () {
|
||||
describe('constructor', function () {
|
||||
describe('without an argument', function () {
|
||||
let h;
|
||||
beforeEach(function () {
|
||||
h = new WebGLHelper();
|
||||
});
|
||||
|
||||
it('initialized WebGL context & canvas', function () {
|
||||
expect(h.getGL() instanceof WebGLRenderingContext).to.eql(true);
|
||||
expect(h.getCanvas() instanceof HTMLCanvasElement).to.eql(true);
|
||||
});
|
||||
|
||||
it('has a default rendering pass', function () {
|
||||
expect(h.postProcessPasses_.length).to.eql(1);
|
||||
});
|
||||
});
|
||||
|
||||
describe('with post process passes', function () {
|
||||
let h;
|
||||
beforeEach(function () {
|
||||
h = new WebGLHelper({
|
||||
postProcesses: [
|
||||
{
|
||||
scaleRatio: 0.5,
|
||||
},
|
||||
{
|
||||
uniforms: {
|
||||
u_test: 4,
|
||||
},
|
||||
},
|
||||
],
|
||||
});
|
||||
});
|
||||
|
||||
it('has instantiated post-processing passes', function () {
|
||||
expect(h.postProcessPasses_.length).to.eql(2);
|
||||
expect(h.postProcessPasses_[0].scaleRatio_).to.eql(0.5);
|
||||
expect(h.postProcessPasses_[0].uniforms_.length).to.eql(0);
|
||||
expect(h.postProcessPasses_[1].scaleRatio_).to.eql(1);
|
||||
expect(h.postProcessPasses_[1].uniforms_.length).to.eql(1);
|
||||
expect(h.postProcessPasses_[1].uniforms_[0].value).to.eql(4);
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
describe('operations', function () {
|
||||
describe('prepare draw', function () {
|
||||
let h;
|
||||
beforeEach(function () {
|
||||
h = new WebGLHelper({
|
||||
uniforms: {
|
||||
u_test1: 42,
|
||||
u_test2: [1, 3],
|
||||
u_test3: document.createElement('canvas'),
|
||||
u_test4: createTransform(),
|
||||
},
|
||||
});
|
||||
h.useProgram(h.getProgram(FRAGMENT_SHADER, VERTEX_SHADER));
|
||||
h.prepareDraw({
|
||||
pixelRatio: 2,
|
||||
size: [50, 80],
|
||||
viewState: {
|
||||
rotation: 10,
|
||||
resolution: 10,
|
||||
center: [0, 0],
|
||||
},
|
||||
});
|
||||
});
|
||||
|
||||
it('has resized the canvas', function () {
|
||||
expect(h.getCanvas().width).to.eql(100);
|
||||
expect(h.getCanvas().height).to.eql(160);
|
||||
});
|
||||
|
||||
it('has processed default uniforms', function () {
|
||||
expect(
|
||||
h.uniformLocations_[DefaultUniform.OFFSET_ROTATION_MATRIX]
|
||||
).not.to.eql(undefined);
|
||||
expect(
|
||||
h.uniformLocations_[DefaultUniform.OFFSET_SCALE_MATRIX]
|
||||
).not.to.eql(undefined);
|
||||
expect(h.uniformLocations_[DefaultUniform.TIME]).not.to.eql(undefined);
|
||||
});
|
||||
|
||||
it('has processed uniforms', function () {
|
||||
expect(h.uniforms_.length).to.eql(4);
|
||||
expect(h.uniforms_[0].name).to.eql('u_test1');
|
||||
expect(h.uniforms_[1].name).to.eql('u_test2');
|
||||
expect(h.uniforms_[2].name).to.eql('u_test3');
|
||||
expect(h.uniforms_[3].name).to.eql('u_test4');
|
||||
expect(h.uniforms_[0].location).to.not.eql(-1);
|
||||
expect(h.uniforms_[1].location).to.not.eql(-1);
|
||||
expect(h.uniforms_[2].location).to.not.eql(-1);
|
||||
expect(h.uniforms_[3].location).to.not.eql(-1);
|
||||
expect(h.uniforms_[2].texture).to.not.eql(undefined);
|
||||
});
|
||||
});
|
||||
|
||||
describe('valid shader compiling', function () {
|
||||
let h;
|
||||
let p;
|
||||
beforeEach(function () {
|
||||
h = new WebGLHelper();
|
||||
|
||||
p = h.getProgram(FRAGMENT_SHADER, VERTEX_SHADER);
|
||||
h.useProgram(p);
|
||||
});
|
||||
|
||||
it('has saved the program', function () {
|
||||
expect(h.currentProgram_).to.eql(p);
|
||||
});
|
||||
|
||||
it('has no shader compilation error', function () {
|
||||
expect(h.shaderCompileErrors_).to.eql(null);
|
||||
});
|
||||
|
||||
it('can find the uniform location', function () {
|
||||
expect(h.getUniformLocation('u_test')).to.not.eql(null);
|
||||
});
|
||||
|
||||
it('can find the attribute location', function () {
|
||||
expect(h.getAttributeLocation('a_test')).to.not.eql(-1);
|
||||
});
|
||||
|
||||
it('cannot find an unknown attribute location', function () {
|
||||
expect(h.getAttributeLocation('a_test_missing')).to.eql(-1);
|
||||
});
|
||||
});
|
||||
|
||||
describe('invalid shader compiling', function () {
|
||||
it('throws for an invalid vertex shader', function () {
|
||||
const helper = new WebGLHelper();
|
||||
expect(() =>
|
||||
helper.getProgram(FRAGMENT_SHADER, INVALID_VERTEX_SHADER)
|
||||
).to.throwException(
|
||||
/Vertex shader compilation failed: ERROR: 0:10: 'bla' : syntax error/
|
||||
);
|
||||
});
|
||||
|
||||
it('throws for an invalid fragment shader', function () {
|
||||
const helper = new WebGLHelper();
|
||||
expect(() =>
|
||||
helper.getProgram(INVALID_FRAGMENT_SHADER, VERTEX_SHADER)
|
||||
).to.throwException(
|
||||
/Fragment shader compliation failed: ERROR: 0:5: 'oops' : undeclared identifier/
|
||||
);
|
||||
});
|
||||
});
|
||||
|
||||
describe('#makeProjectionTransform', function () {
|
||||
let h;
|
||||
let frameState;
|
||||
beforeEach(function () {
|
||||
h = new WebGLHelper();
|
||||
|
||||
frameState = {
|
||||
size: [100, 150],
|
||||
viewState: {
|
||||
rotation: 0.4,
|
||||
resolution: 2,
|
||||
center: [10, 20],
|
||||
},
|
||||
};
|
||||
});
|
||||
|
||||
it('gives out the correct transform', function () {
|
||||
const scaleX = 2 / frameState.size[0] / frameState.viewState.resolution;
|
||||
const scaleY = 2 / frameState.size[1] / frameState.viewState.resolution;
|
||||
const given = createTransform();
|
||||
const expected = createTransform();
|
||||
scaleTransform(expected, scaleX, scaleY);
|
||||
rotateTransform(expected, -frameState.viewState.rotation);
|
||||
translateTransform(
|
||||
expected,
|
||||
-frameState.viewState.center[0],
|
||||
-frameState.viewState.center[1]
|
||||
);
|
||||
|
||||
h.makeProjectionTransform(frameState, given);
|
||||
|
||||
expect(given.map((val) => val.toFixed(15))).to.eql(
|
||||
expected.map((val) => val.toFixed(15))
|
||||
);
|
||||
});
|
||||
});
|
||||
|
||||
describe('deleteBuffer()', function () {
|
||||
it('can be called to free up buffer resources', function () {
|
||||
const helper = new WebGLHelper();
|
||||
const buffer = new WebGLArrayBuffer(ARRAY_BUFFER, STATIC_DRAW);
|
||||
buffer.fromArray([0, 1, 2, 3]);
|
||||
helper.flushBufferData(buffer);
|
||||
const bufferKey = getUid(buffer);
|
||||
expect(helper.bufferCache_).to.have.property(bufferKey);
|
||||
|
||||
helper.deleteBuffer(buffer);
|
||||
expect(helper.bufferCache_).to.not.have.property(bufferKey);
|
||||
});
|
||||
});
|
||||
|
||||
describe('#createTexture', function () {
|
||||
let h;
|
||||
beforeEach(function () {
|
||||
h = new WebGLHelper();
|
||||
});
|
||||
|
||||
it('creates an empty texture from scratch', function () {
|
||||
const width = 4;
|
||||
const height = 4;
|
||||
const t = h.createTexture([width, height]);
|
||||
const gl = h.getGL();
|
||||
|
||||
const fb = gl.createFramebuffer();
|
||||
gl.bindFramebuffer(gl.FRAMEBUFFER, fb);
|
||||
gl.framebufferTexture2D(
|
||||
gl.FRAMEBUFFER,
|
||||
gl.COLOR_ATTACHMENT0,
|
||||
gl.TEXTURE_2D,
|
||||
t,
|
||||
0
|
||||
);
|
||||
const data = new Uint8Array(width * height * 4);
|
||||
gl.readPixels(0, 0, width, height, gl.RGBA, gl.UNSIGNED_BYTE, data);
|
||||
gl.deleteFramebuffer(fb);
|
||||
|
||||
expect(data[0]).to.eql(0);
|
||||
expect(data[1]).to.eql(0);
|
||||
expect(data[2]).to.eql(0);
|
||||
expect(data[3]).to.eql(0);
|
||||
expect(data[4]).to.eql(0);
|
||||
expect(data[5]).to.eql(0);
|
||||
expect(data[6]).to.eql(0);
|
||||
expect(data[7]).to.eql(0);
|
||||
});
|
||||
|
||||
it('creates a texture from image data', function () {
|
||||
const width = 4;
|
||||
const height = 4;
|
||||
const canvas = document.createElement('canvas');
|
||||
const image = canvas.getContext('2d').createImageData(width, height);
|
||||
for (let i = 0; i < image.data.length; i += 4) {
|
||||
image.data[i] = 100;
|
||||
image.data[i + 1] = 150;
|
||||
image.data[i + 2] = 200;
|
||||
image.data[i + 3] = 250;
|
||||
}
|
||||
const t = h.createTexture([width, height], image);
|
||||
const gl = h.getGL();
|
||||
|
||||
const fb = gl.createFramebuffer();
|
||||
gl.bindFramebuffer(gl.FRAMEBUFFER, fb);
|
||||
gl.framebufferTexture2D(
|
||||
gl.FRAMEBUFFER,
|
||||
gl.COLOR_ATTACHMENT0,
|
||||
gl.TEXTURE_2D,
|
||||
t,
|
||||
0
|
||||
);
|
||||
const data = new Uint8Array(width * height * 4);
|
||||
gl.readPixels(0, 0, width, height, gl.RGBA, gl.UNSIGNED_BYTE, data);
|
||||
gl.deleteFramebuffer(fb);
|
||||
|
||||
expect(data[0]).to.eql(100);
|
||||
expect(data[1]).to.eql(150);
|
||||
expect(data[2]).to.eql(200);
|
||||
expect(data[3]).to.eql(250);
|
||||
expect(data[4]).to.eql(100);
|
||||
expect(data[5]).to.eql(150);
|
||||
expect(data[6]).to.eql(200);
|
||||
expect(data[7]).to.eql(250);
|
||||
});
|
||||
|
||||
it('reuses a given texture', function () {
|
||||
const width = 4;
|
||||
const height = 4;
|
||||
const gl = h.getGL();
|
||||
const t1 = gl.createTexture();
|
||||
const t2 = h.createTexture([width, height], undefined, t1);
|
||||
expect(t1).to.be(t2);
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
describe('#enableAttributes', function () {
|
||||
let baseAttrs, h;
|
||||
|
||||
beforeEach(function () {
|
||||
h = new WebGLHelper();
|
||||
baseAttrs = [
|
||||
{
|
||||
name: 'attr1',
|
||||
size: 3,
|
||||
},
|
||||
{
|
||||
name: 'attr2',
|
||||
size: 2,
|
||||
},
|
||||
{
|
||||
name: 'attr3',
|
||||
size: 1,
|
||||
},
|
||||
];
|
||||
h.useProgram(
|
||||
h.getProgram(
|
||||
FRAGMENT_SHADER,
|
||||
`
|
||||
precision mediump float;
|
||||
|
||||
uniform mat4 u_projectionMatrix;
|
||||
uniform mat4 u_offsetScaleMatrix;
|
||||
uniform mat4 u_offsetRotateMatrix;
|
||||
|
||||
attribute vec3 attr1;
|
||||
attribute vec2 attr2;
|
||||
attribute float attr3;
|
||||
uniform float u_test;
|
||||
|
||||
void main(void) {
|
||||
gl_Position = vec4(u_test, attr3, 0.0, 1.0);
|
||||
}`
|
||||
)
|
||||
);
|
||||
});
|
||||
|
||||
it('enables attributes based on the given array (FLOAT)', function () {
|
||||
const spy = sinon.spy(h, 'enableAttributeArray_');
|
||||
h.enableAttributes(baseAttrs);
|
||||
const bytesPerFloat = Float32Array.BYTES_PER_ELEMENT;
|
||||
|
||||
expect(spy.callCount).to.eql(3);
|
||||
expect(spy.getCall(0).args[0]).to.eql('attr1');
|
||||
expect(spy.getCall(0).args[1]).to.eql(3);
|
||||
expect(spy.getCall(0).args[2]).to.eql(FLOAT);
|
||||
expect(spy.getCall(0).args[3]).to.eql(6 * bytesPerFloat);
|
||||
expect(spy.getCall(0).args[4]).to.eql(0);
|
||||
expect(spy.getCall(1).args[0]).to.eql('attr2');
|
||||
expect(spy.getCall(1).args[1]).to.eql(2);
|
||||
expect(spy.getCall(1).args[2]).to.eql(FLOAT);
|
||||
expect(spy.getCall(1).args[3]).to.eql(6 * bytesPerFloat);
|
||||
expect(spy.getCall(1).args[4]).to.eql(3 * bytesPerFloat);
|
||||
expect(spy.getCall(2).args[0]).to.eql('attr3');
|
||||
expect(spy.getCall(2).args[1]).to.eql(1);
|
||||
expect(spy.getCall(2).args[2]).to.eql(FLOAT);
|
||||
expect(spy.getCall(2).args[3]).to.eql(6 * bytesPerFloat);
|
||||
expect(spy.getCall(2).args[4]).to.eql(5 * bytesPerFloat);
|
||||
});
|
||||
});
|
||||
});
|
||||
@@ -0,0 +1,138 @@
|
||||
import WebGLHelper from '../../../../../src/ol/webgl/Helper.js';
|
||||
import WebGLRenderTarget from '../../../../../src/ol/webgl/RenderTarget.js';
|
||||
|
||||
describe('ol.webgl.RenderTarget', function () {
|
||||
let helper, testImage_4x4;
|
||||
|
||||
beforeEach(function () {
|
||||
helper = new WebGLHelper();
|
||||
|
||||
const canvas = document.createElement('canvas');
|
||||
testImage_4x4 = canvas.getContext('2d').createImageData(4, 4);
|
||||
for (let i = 0; i < testImage_4x4.data.length; i += 4) {
|
||||
testImage_4x4.data[i] = 100 + i / 4;
|
||||
testImage_4x4.data[i + 1] = 100 + i / 4;
|
||||
testImage_4x4.data[i + 2] = 200 + i / 4;
|
||||
testImage_4x4.data[i + 3] = 200 + i / 4;
|
||||
}
|
||||
});
|
||||
|
||||
describe('constructor', function () {
|
||||
it('creates a target of size 1x1', function () {
|
||||
const rt = new WebGLRenderTarget(helper);
|
||||
expect(rt.getSize()).to.eql([1, 1]);
|
||||
});
|
||||
|
||||
it('creates a target of specified size', function () {
|
||||
const rt = new WebGLRenderTarget(helper, [12, 34]);
|
||||
expect(rt.getSize()).to.eql([12, 34]);
|
||||
});
|
||||
});
|
||||
|
||||
describe('#setSize', function () {
|
||||
it('updates the target size', function () {
|
||||
const rt = new WebGLRenderTarget(helper, [12, 34]);
|
||||
expect(rt.getSize()).to.eql([12, 34]);
|
||||
rt.setSize([45, 67]);
|
||||
expect(rt.getSize()).to.eql([45, 67]);
|
||||
});
|
||||
|
||||
it('does nothing if the size has not changed', function () {
|
||||
const rt = new WebGLRenderTarget(helper, [12, 34]);
|
||||
const spy = sinon.spy(rt, 'updateSize_');
|
||||
rt.setSize([12, 34]);
|
||||
expect(spy.called).to.be(false);
|
||||
rt.setSize([12, 345]);
|
||||
expect(spy.called).to.be(true);
|
||||
});
|
||||
});
|
||||
|
||||
describe('#readAll', function () {
|
||||
it('returns 1-pixel data with the default options', function () {
|
||||
const rt = new WebGLRenderTarget(helper);
|
||||
expect(rt.readAll().length).to.eql(4);
|
||||
});
|
||||
|
||||
it('returns the content of the texture', function () {
|
||||
const rt = new WebGLRenderTarget(helper, [4, 4]);
|
||||
helper.createTexture([4, 4], testImage_4x4, rt.getTexture());
|
||||
const data = rt.readAll();
|
||||
|
||||
expect(data[0]).to.eql(100);
|
||||
expect(data[1]).to.eql(100);
|
||||
expect(data[2]).to.eql(200);
|
||||
expect(data[3]).to.eql(200);
|
||||
expect(data[4]).to.eql(101);
|
||||
expect(data[5]).to.eql(101);
|
||||
expect(data[6]).to.eql(201);
|
||||
expect(data[7]).to.eql(201);
|
||||
expect(data.length).to.eql(4 * 4 * 4);
|
||||
});
|
||||
|
||||
it('does not call gl.readPixels again when #clearCachedData is not called', function () {
|
||||
const rt = new WebGLRenderTarget(helper, [4, 4]);
|
||||
helper.createTexture([4, 4], testImage_4x4, rt.getTexture());
|
||||
const spy = sinon.spy(rt.helper_.getGL(), 'readPixels');
|
||||
rt.readAll();
|
||||
expect(spy.callCount).to.eql(1);
|
||||
rt.readAll();
|
||||
expect(spy.callCount).to.eql(1);
|
||||
rt.clearCachedData();
|
||||
rt.readAll();
|
||||
expect(spy.callCount).to.eql(2);
|
||||
});
|
||||
});
|
||||
|
||||
describe('#readPixel', function () {
|
||||
it('returns the content of one pixel', function () {
|
||||
const rt = new WebGLRenderTarget(helper, [4, 4]);
|
||||
helper.createTexture([4, 4], testImage_4x4, rt.getTexture());
|
||||
|
||||
let data = rt.readPixel(0, 0);
|
||||
expect(data[0]).to.eql(112);
|
||||
expect(data[1]).to.eql(112);
|
||||
expect(data[2]).to.eql(212);
|
||||
expect(data[3]).to.eql(212);
|
||||
|
||||
data = rt.readPixel(3, 3);
|
||||
expect(data[0]).to.eql(103);
|
||||
expect(data[1]).to.eql(103);
|
||||
expect(data[2]).to.eql(203);
|
||||
expect(data[3]).to.eql(203);
|
||||
expect(data.length).to.eql(4);
|
||||
});
|
||||
|
||||
it('does not call gl.readPixels again when #clearCachedData is not called', function () {
|
||||
const rt = new WebGLRenderTarget(helper, [4, 4]);
|
||||
helper.createTexture([4, 4], testImage_4x4, rt.getTexture());
|
||||
const spy = sinon.spy(rt.helper_.getGL(), 'readPixels');
|
||||
rt.readPixel(0, 0);
|
||||
expect(spy.callCount).to.eql(1);
|
||||
rt.readPixel(1, 1);
|
||||
expect(spy.callCount).to.eql(1);
|
||||
rt.clearCachedData();
|
||||
rt.readPixel(2, 2);
|
||||
expect(spy.callCount).to.eql(2);
|
||||
});
|
||||
|
||||
it('returns an array filled with 0 if outside of range', function () {
|
||||
const rt = new WebGLRenderTarget(helper, [4, 4]);
|
||||
helper.createTexture([4, 4], testImage_4x4, rt.getTexture());
|
||||
|
||||
let data = rt.readPixel(-1, 0);
|
||||
expect(data).to.eql([0, 0, 0, 0]);
|
||||
|
||||
data = rt.readPixel(3, -1);
|
||||
expect(data).to.eql([0, 0, 0, 0]);
|
||||
|
||||
data = rt.readPixel(6, 2);
|
||||
expect(data).to.eql([0, 0, 0, 0]);
|
||||
|
||||
data = rt.readPixel(2, 7);
|
||||
expect(data).to.eql([0, 0, 0, 0]);
|
||||
|
||||
data = rt.readPixel(2, 3);
|
||||
expect(data).not.to.eql([0, 0, 0, 0]);
|
||||
});
|
||||
});
|
||||
});
|
||||
@@ -0,0 +1,652 @@
|
||||
import {
|
||||
ShaderBuilder,
|
||||
parseLiteralStyle,
|
||||
} from '../../../../../src/ol/webgl/ShaderBuilder.js';
|
||||
import {
|
||||
arrayToGlsl,
|
||||
colorToGlsl,
|
||||
numberToGlsl,
|
||||
uniformNameForVariable,
|
||||
} from '../../../../../src/ol/style/expressions.js';
|
||||
|
||||
describe('ol.webgl.ShaderBuilder', function () {
|
||||
describe('getSymbolVertexShader', function () {
|
||||
it('generates a symbol vertex shader (with varying)', function () {
|
||||
const builder = new ShaderBuilder();
|
||||
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;
|
||||
uniform mat4 u_offsetScaleMatrix;
|
||||
uniform mat4 u_offsetRotateMatrix;
|
||||
uniform float u_time;
|
||||
uniform float u_zoom;
|
||||
uniform float u_resolution;
|
||||
|
||||
attribute vec2 a_position;
|
||||
attribute float a_index;
|
||||
|
||||
varying vec2 v_texCoord;
|
||||
varying vec2 v_quadCoord;
|
||||
varying float v_opacity;
|
||||
varying vec3 v_test;
|
||||
void main(void) {
|
||||
mat4 offsetMatrix = u_offsetScaleMatrix;
|
||||
vec2 halfSize = vec2(6.0) * 0.5;
|
||||
vec2 offset = vec2(5.0, -7.0);
|
||||
float angle = 0.0;
|
||||
float offsetX;
|
||||
float offsetY;
|
||||
if (a_index == 0.0) {
|
||||
offsetX = (offset.x - halfSize.x) * cos(angle) + (offset.y - halfSize.y) * sin(angle);
|
||||
offsetY = (offset.y - halfSize.y) * cos(angle) - (offset.x - halfSize.x) * sin(angle);
|
||||
} else if (a_index == 1.0) {
|
||||
offsetX = (offset.x + halfSize.x) * cos(angle) + (offset.y - halfSize.y) * sin(angle);
|
||||
offsetY = (offset.y - halfSize.y) * cos(angle) - (offset.x + halfSize.x) * sin(angle);
|
||||
} else if (a_index == 2.0) {
|
||||
offsetX = (offset.x + halfSize.x) * cos(angle) + (offset.y + halfSize.y) * sin(angle);
|
||||
offsetY = (offset.y + halfSize.y) * cos(angle) - (offset.x + halfSize.x) * sin(angle);
|
||||
} else {
|
||||
offsetX = (offset.x - halfSize.x) * cos(angle) + (offset.y + halfSize.y) * sin(angle);
|
||||
offsetY = (offset.y + halfSize.y) * cos(angle) - (offset.x - halfSize.x) * sin(angle);
|
||||
}
|
||||
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.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;
|
||||
v_quadCoord = vec2(u, v);
|
||||
v_opacity = 0.4;
|
||||
v_test = vec3(1.0, 2.0, 3.0);
|
||||
}`);
|
||||
});
|
||||
it('generates a symbol vertex shader (with uniforms and attributes)', function () {
|
||||
const builder = new ShaderBuilder();
|
||||
builder.addUniform('float u_myUniform');
|
||||
builder.addAttribute('vec2 a_myAttr');
|
||||
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;
|
||||
uniform mat4 u_offsetScaleMatrix;
|
||||
uniform mat4 u_offsetRotateMatrix;
|
||||
uniform float u_time;
|
||||
uniform float u_zoom;
|
||||
uniform float u_resolution;
|
||||
uniform float u_myUniform;
|
||||
attribute vec2 a_position;
|
||||
attribute float a_index;
|
||||
attribute vec2 a_myAttr;
|
||||
varying vec2 v_texCoord;
|
||||
varying vec2 v_quadCoord;
|
||||
|
||||
void main(void) {
|
||||
mat4 offsetMatrix = u_offsetScaleMatrix;
|
||||
vec2 halfSize = vec2(6.0) * 0.5;
|
||||
vec2 offset = vec2(5.0, -7.0);
|
||||
float angle = 0.0;
|
||||
float offsetX;
|
||||
float offsetY;
|
||||
if (a_index == 0.0) {
|
||||
offsetX = (offset.x - halfSize.x) * cos(angle) + (offset.y - halfSize.y) * sin(angle);
|
||||
offsetY = (offset.y - halfSize.y) * cos(angle) - (offset.x - halfSize.x) * sin(angle);
|
||||
} else if (a_index == 1.0) {
|
||||
offsetX = (offset.x + halfSize.x) * cos(angle) + (offset.y - halfSize.y) * sin(angle);
|
||||
offsetY = (offset.y - halfSize.y) * cos(angle) - (offset.x + halfSize.x) * sin(angle);
|
||||
} else if (a_index == 2.0) {
|
||||
offsetX = (offset.x + halfSize.x) * cos(angle) + (offset.y + halfSize.y) * sin(angle);
|
||||
offsetY = (offset.y + halfSize.y) * cos(angle) - (offset.x + halfSize.x) * sin(angle);
|
||||
} else {
|
||||
offsetX = (offset.x - halfSize.x) * cos(angle) + (offset.y + halfSize.y) * sin(angle);
|
||||
offsetY = (offset.y + halfSize.y) * cos(angle) - (offset.x - halfSize.x) * sin(angle);
|
||||
}
|
||||
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.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;
|
||||
v_quadCoord = vec2(u, v);
|
||||
|
||||
}`);
|
||||
});
|
||||
it('generates a symbol vertex shader (with rotateWithView)', function () {
|
||||
const builder = new ShaderBuilder();
|
||||
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;
|
||||
uniform mat4 u_projectionMatrix;
|
||||
uniform mat4 u_offsetScaleMatrix;
|
||||
uniform mat4 u_offsetRotateMatrix;
|
||||
uniform float u_time;
|
||||
uniform float u_zoom;
|
||||
uniform float u_resolution;
|
||||
|
||||
attribute vec2 a_position;
|
||||
attribute float a_index;
|
||||
|
||||
varying vec2 v_texCoord;
|
||||
varying vec2 v_quadCoord;
|
||||
|
||||
void main(void) {
|
||||
mat4 offsetMatrix = u_offsetScaleMatrix * u_offsetRotateMatrix;
|
||||
vec2 halfSize = vec2(6.0) * 0.5;
|
||||
vec2 offset = vec2(5.0, -7.0);
|
||||
float angle = 0.0;
|
||||
float offsetX;
|
||||
float offsetY;
|
||||
if (a_index == 0.0) {
|
||||
offsetX = (offset.x - halfSize.x) * cos(angle) + (offset.y - halfSize.y) * sin(angle);
|
||||
offsetY = (offset.y - halfSize.y) * cos(angle) - (offset.x - halfSize.x) * sin(angle);
|
||||
} else if (a_index == 1.0) {
|
||||
offsetX = (offset.x + halfSize.x) * cos(angle) + (offset.y - halfSize.y) * sin(angle);
|
||||
offsetY = (offset.y - halfSize.y) * cos(angle) - (offset.x + halfSize.x) * sin(angle);
|
||||
} else if (a_index == 2.0) {
|
||||
offsetX = (offset.x + halfSize.x) * cos(angle) + (offset.y + halfSize.y) * sin(angle);
|
||||
offsetY = (offset.y + halfSize.y) * cos(angle) - (offset.x + halfSize.x) * sin(angle);
|
||||
} else {
|
||||
offsetX = (offset.x - halfSize.x) * cos(angle) + (offset.y + halfSize.y) * sin(angle);
|
||||
offsetY = (offset.y + halfSize.y) * cos(angle) - (offset.x - halfSize.x) * sin(angle);
|
||||
}
|
||||
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.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;
|
||||
v_quadCoord = vec2(u, v);
|
||||
|
||||
}`);
|
||||
});
|
||||
it('generates a symbol vertex shader for hitDetection', function () {
|
||||
const builder = new ShaderBuilder();
|
||||
|
||||
expect(builder.getSymbolVertexShader(true)).to
|
||||
.eql(`precision mediump float;
|
||||
uniform mat4 u_projectionMatrix;
|
||||
uniform mat4 u_offsetScaleMatrix;
|
||||
uniform mat4 u_offsetRotateMatrix;
|
||||
uniform float u_time;
|
||||
uniform float u_zoom;
|
||||
uniform float u_resolution;
|
||||
|
||||
attribute vec2 a_position;
|
||||
attribute float a_index;
|
||||
attribute vec4 a_hitColor;
|
||||
varying vec2 v_texCoord;
|
||||
varying vec2 v_quadCoord;
|
||||
varying vec4 v_hitColor;
|
||||
void main(void) {
|
||||
mat4 offsetMatrix = u_offsetScaleMatrix;
|
||||
vec2 halfSize = vec2(1.0) * 0.5;
|
||||
vec2 offset = vec2(0.0);
|
||||
float angle = 0.0;
|
||||
float offsetX;
|
||||
float offsetY;
|
||||
if (a_index == 0.0) {
|
||||
offsetX = (offset.x - halfSize.x) * cos(angle) + (offset.y - halfSize.y) * sin(angle);
|
||||
offsetY = (offset.y - halfSize.y) * cos(angle) - (offset.x - halfSize.x) * sin(angle);
|
||||
} else if (a_index == 1.0) {
|
||||
offsetX = (offset.x + halfSize.x) * cos(angle) + (offset.y - halfSize.y) * sin(angle);
|
||||
offsetY = (offset.y - halfSize.y) * cos(angle) - (offset.x + halfSize.x) * sin(angle);
|
||||
} else if (a_index == 2.0) {
|
||||
offsetX = (offset.x + halfSize.x) * cos(angle) + (offset.y + halfSize.y) * sin(angle);
|
||||
offsetY = (offset.y + halfSize.y) * cos(angle) - (offset.x + halfSize.x) * sin(angle);
|
||||
} else {
|
||||
offsetX = (offset.x - halfSize.x) * cos(angle) + (offset.y + halfSize.y) * sin(angle);
|
||||
offsetY = (offset.y + halfSize.y) * cos(angle) - (offset.x - halfSize.x) * sin(angle);
|
||||
}
|
||||
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.0, 1.0, 1.0);
|
||||
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;
|
||||
v_quadCoord = vec2(u, v);
|
||||
v_hitColor = a_hitColor;
|
||||
}`);
|
||||
});
|
||||
it('generates a symbol vertex shader (with a rotation expression)', function () {
|
||||
const builder = new ShaderBuilder();
|
||||
builder.setSizeExpression(`vec2(${numberToGlsl(6)})`);
|
||||
builder.setSymbolOffsetExpression(arrayToGlsl([5, -7]));
|
||||
builder.setRotationExpression('u_time * 0.2');
|
||||
|
||||
expect(builder.getSymbolVertexShader()).to.eql(`precision mediump float;
|
||||
uniform mat4 u_projectionMatrix;
|
||||
uniform mat4 u_offsetScaleMatrix;
|
||||
uniform mat4 u_offsetRotateMatrix;
|
||||
uniform float u_time;
|
||||
uniform float u_zoom;
|
||||
uniform float u_resolution;
|
||||
|
||||
attribute vec2 a_position;
|
||||
attribute float a_index;
|
||||
|
||||
varying vec2 v_texCoord;
|
||||
varying vec2 v_quadCoord;
|
||||
|
||||
void main(void) {
|
||||
mat4 offsetMatrix = u_offsetScaleMatrix;
|
||||
vec2 halfSize = vec2(6.0) * 0.5;
|
||||
vec2 offset = vec2(5.0, -7.0);
|
||||
float angle = u_time * 0.2;
|
||||
float offsetX;
|
||||
float offsetY;
|
||||
if (a_index == 0.0) {
|
||||
offsetX = (offset.x - halfSize.x) * cos(angle) + (offset.y - halfSize.y) * sin(angle);
|
||||
offsetY = (offset.y - halfSize.y) * cos(angle) - (offset.x - halfSize.x) * sin(angle);
|
||||
} else if (a_index == 1.0) {
|
||||
offsetX = (offset.x + halfSize.x) * cos(angle) + (offset.y - halfSize.y) * sin(angle);
|
||||
offsetY = (offset.y - halfSize.y) * cos(angle) - (offset.x + halfSize.x) * sin(angle);
|
||||
} else if (a_index == 2.0) {
|
||||
offsetX = (offset.x + halfSize.x) * cos(angle) + (offset.y + halfSize.y) * sin(angle);
|
||||
offsetY = (offset.y + halfSize.y) * cos(angle) - (offset.x + halfSize.x) * sin(angle);
|
||||
} else {
|
||||
offsetX = (offset.x - halfSize.x) * cos(angle) + (offset.y + halfSize.y) * sin(angle);
|
||||
offsetY = (offset.y + halfSize.y) * cos(angle) - (offset.x - halfSize.x) * sin(angle);
|
||||
}
|
||||
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.0, 1.0, 1.0);
|
||||
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;
|
||||
v_quadCoord = vec2(u, v);
|
||||
|
||||
}`);
|
||||
});
|
||||
});
|
||||
|
||||
describe('getSymbolFragmentShader', function () {
|
||||
it('generates a symbol fragment shader (with varying)', function () {
|
||||
const builder = new ShaderBuilder();
|
||||
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;
|
||||
uniform float u_zoom;
|
||||
uniform float u_resolution;
|
||||
|
||||
varying vec2 v_texCoord;
|
||||
varying vec2 v_quadCoord;
|
||||
varying float v_opacity;
|
||||
varying vec3 v_test;
|
||||
void main(void) {
|
||||
if (false) { discard; }
|
||||
gl_FragColor = vec4(0.3137254901960784, 0.0, 1.0, 1.0);
|
||||
gl_FragColor.rgb *= gl_FragColor.a;
|
||||
|
||||
}`);
|
||||
});
|
||||
it('generates a symbol fragment shader (with uniforms)', function () {
|
||||
const builder = new ShaderBuilder();
|
||||
builder.addUniform('float u_myUniform');
|
||||
builder.addUniform('vec2 u_myUniform2');
|
||||
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;
|
||||
uniform float u_time;
|
||||
uniform float u_zoom;
|
||||
uniform float u_resolution;
|
||||
uniform float u_myUniform;
|
||||
uniform vec2 u_myUniform2;
|
||||
varying vec2 v_texCoord;
|
||||
varying vec2 v_quadCoord;
|
||||
|
||||
void main(void) {
|
||||
if (u_myUniform > 0.5) { discard; }
|
||||
gl_FragColor = vec4(1.0, 1.0, 1.0, 1.0);
|
||||
gl_FragColor.rgb *= gl_FragColor.a;
|
||||
|
||||
}`);
|
||||
});
|
||||
it('generates a symbol fragment shader for hit detection', function () {
|
||||
const builder = new ShaderBuilder();
|
||||
|
||||
expect(builder.getSymbolFragmentShader(true)).to
|
||||
.eql(`precision mediump float;
|
||||
uniform float u_time;
|
||||
uniform float u_zoom;
|
||||
uniform float u_resolution;
|
||||
|
||||
varying vec2 v_texCoord;
|
||||
varying vec2 v_quadCoord;
|
||||
varying vec4 v_hitColor;
|
||||
void main(void) {
|
||||
if (false) { discard; }
|
||||
gl_FragColor = vec4(1.0);
|
||||
gl_FragColor.rgb *= gl_FragColor.a;
|
||||
if (gl_FragColor.a < 0.1) { discard; } gl_FragColor = v_hitColor;
|
||||
}`);
|
||||
});
|
||||
});
|
||||
|
||||
describe('parseSymbolStyle', function () {
|
||||
it('parses a style without expressions', function () {
|
||||
const result = parseLiteralStyle({
|
||||
symbol: {
|
||||
symbolType: 'square',
|
||||
size: [4, 8],
|
||||
color: '#ff0000',
|
||||
rotateWithView: true,
|
||||
},
|
||||
});
|
||||
|
||||
expect(result.builder.uniforms).to.eql([]);
|
||||
expect(result.builder.attributes).to.eql([]);
|
||||
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(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);
|
||||
expect(result.attributes).to.eql([]);
|
||||
expect(result.uniforms).to.eql({});
|
||||
});
|
||||
|
||||
it('parses a style with expressions', function () {
|
||||
const result = parseLiteralStyle({
|
||||
symbol: {
|
||||
symbolType: 'square',
|
||||
size: ['get', 'attr1'],
|
||||
color: [255, 127.5, 63.75, 0.25],
|
||||
textureCoord: [0.5, 0.5, 0.5, 1],
|
||||
offset: [
|
||||
'match',
|
||||
['get', 'attr3'],
|
||||
'red',
|
||||
[6, 0],
|
||||
'green',
|
||||
[3, 0],
|
||||
[0, 0],
|
||||
],
|
||||
},
|
||||
});
|
||||
|
||||
expect(result.builder.uniforms).to.eql([]);
|
||||
expect(result.builder.attributes).to.eql([
|
||||
'float a_attr1',
|
||||
'float a_attr3',
|
||||
]);
|
||||
expect(result.builder.varyings).to.eql([
|
||||
{
|
||||
name: 'v_attr1',
|
||||
type: 'float',
|
||||
expression: 'a_attr1',
|
||||
},
|
||||
]);
|
||||
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)');
|
||||
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);
|
||||
expect(result.attributes[0].name).to.eql('attr1');
|
||||
expect(result.attributes[1].name).to.eql('attr3');
|
||||
expect(result.uniforms).to.eql({});
|
||||
});
|
||||
|
||||
it('parses a style with a uniform (texture)', function () {
|
||||
const result = parseLiteralStyle({
|
||||
symbol: {
|
||||
symbolType: 'image',
|
||||
src: '../data/image.png',
|
||||
size: 6,
|
||||
color: '#336699',
|
||||
opacity: 0.5,
|
||||
},
|
||||
});
|
||||
|
||||
expect(result.builder.uniforms).to.eql(['sampler2D u_texture']);
|
||||
expect(result.builder.attributes).to.eql([]);
|
||||
expect(result.builder.varyings).to.eql([]);
|
||||
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)');
|
||||
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);
|
||||
expect(result.attributes).to.eql([]);
|
||||
expect(result.uniforms).to.have.property('u_texture');
|
||||
});
|
||||
|
||||
it('parses a style with variables', function () {
|
||||
const result = parseLiteralStyle({
|
||||
variables: {
|
||||
lower: 100,
|
||||
higher: 400,
|
||||
},
|
||||
symbol: {
|
||||
symbolType: 'square',
|
||||
size: [
|
||||
'interpolate',
|
||||
['linear'],
|
||||
['get', 'population'],
|
||||
['var', 'lower'],
|
||||
4,
|
||||
['var', 'higher'],
|
||||
8,
|
||||
],
|
||||
color: '#336699',
|
||||
opacity: 0.5,
|
||||
},
|
||||
});
|
||||
|
||||
const lowerUniformName = uniformNameForVariable('lower');
|
||||
const higherUniformName = uniformNameForVariable('higher');
|
||||
expect(result.builder.uniforms).to.eql([
|
||||
`float ${lowerUniformName}`,
|
||||
`float ${higherUniformName}`,
|
||||
]);
|
||||
expect(result.builder.attributes).to.eql(['float a_population']);
|
||||
expect(result.builder.varyings).to.eql([
|
||||
{
|
||||
name: 'v_population',
|
||||
type: 'float',
|
||||
expression: 'a_population',
|
||||
},
|
||||
]);
|
||||
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)'
|
||||
);
|
||||
expect(result.builder.sizeExpression).to.eql(
|
||||
`vec2(mix(4.0, 8.0, pow(clamp((a_population - ${lowerUniformName}) / (${higherUniformName} - ${lowerUniformName}), 0.0, 1.0), 1.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);
|
||||
expect(result.attributes.length).to.eql(1);
|
||||
expect(result.attributes[0].name).to.eql('population');
|
||||
expect(result.uniforms).to.have.property(lowerUniformName);
|
||||
expect(result.uniforms).to.have.property(higherUniformName);
|
||||
});
|
||||
|
||||
it('parses a style with a filter', function () {
|
||||
const result = parseLiteralStyle({
|
||||
filter: ['between', ['get', 'attr0'], 0, 10],
|
||||
symbol: {
|
||||
symbolType: 'square',
|
||||
size: 6,
|
||||
color: '#336699',
|
||||
},
|
||||
});
|
||||
|
||||
expect(result.builder.attributes).to.eql(['float a_attr0']);
|
||||
expect(result.builder.varyings).to.eql([
|
||||
{
|
||||
name: 'v_attr0',
|
||||
type: 'float',
|
||||
expression: 'a_attr0',
|
||||
},
|
||||
]);
|
||||
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)');
|
||||
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.rotateWithView).to.eql(false);
|
||||
expect(result.attributes.length).to.eql(1);
|
||||
expect(result.attributes[0].name).to.eql('attr0');
|
||||
});
|
||||
|
||||
it('parses a style with a color interpolation', function () {
|
||||
const varName = 'ratio';
|
||||
const uniformName = uniformNameForVariable(varName);
|
||||
const result = parseLiteralStyle({
|
||||
symbol: {
|
||||
symbolType: 'square',
|
||||
size: 6,
|
||||
color: [
|
||||
'interpolate',
|
||||
['linear'],
|
||||
['var', varName],
|
||||
0,
|
||||
[255, 255, 0],
|
||||
1,
|
||||
'red',
|
||||
],
|
||||
},
|
||||
});
|
||||
|
||||
expect(result.builder.attributes).to.eql([]);
|
||||
expect(result.builder.varyings).to.eql([]);
|
||||
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), pow(clamp((${uniformName} - 0.0) / (1.0 - 0.0), 0.0, 1.0), 1.0)).rgb, mix(vec4(1.0, 1.0, 0.0, 1.0), vec4(1.0, 0.0, 0.0, 1.0), pow(clamp((${uniformName} - 0.0) / (1.0 - 0.0), 0.0, 1.0), 1.0)).a * 1.0 * 1.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);
|
||||
expect(result.attributes).to.eql([]);
|
||||
expect(result.uniforms).to.have.property(uniformName);
|
||||
});
|
||||
|
||||
it('parses a style with a rotation expression using an attribute', function () {
|
||||
const result = parseLiteralStyle({
|
||||
symbol: {
|
||||
symbolType: 'square',
|
||||
size: 6,
|
||||
rotation: ['get', 'heading'],
|
||||
},
|
||||
});
|
||||
|
||||
expect(result.builder.attributes).to.eql(['float a_heading']);
|
||||
expect(result.builder.varyings).to.eql([]);
|
||||
expect(result.builder.rotationExpression).to.eql('a_heading');
|
||||
});
|
||||
|
||||
it('correctly adds string variables to the string literals mapping', function () {
|
||||
const varName = 'mySize';
|
||||
const uniformName = uniformNameForVariable(varName);
|
||||
|
||||
const result = parseLiteralStyle({
|
||||
variables: {
|
||||
mySize: 'abcdef',
|
||||
},
|
||||
symbol: {
|
||||
symbolType: 'square',
|
||||
size: ['match', ['var', varName], 'abc', 10, 'def', 20, 30],
|
||||
color: 'red',
|
||||
},
|
||||
});
|
||||
|
||||
expect(result.uniforms[uniformName]()).to.be.greaterThan(0);
|
||||
});
|
||||
|
||||
it('throws when a variable is requested but not present in the style', function (done) {
|
||||
const varName = 'mySize';
|
||||
const uniformName = uniformNameForVariable(varName);
|
||||
|
||||
const result = parseLiteralStyle({
|
||||
variables: {},
|
||||
symbol: {
|
||||
symbolType: 'square',
|
||||
size: ['var', varName],
|
||||
color: 'red',
|
||||
},
|
||||
});
|
||||
|
||||
try {
|
||||
result.uniforms[uniformName]();
|
||||
} catch (e) {
|
||||
done();
|
||||
}
|
||||
done(true);
|
||||
});
|
||||
|
||||
it('throws when a variable is requested but the style does not have a variables dict', function (done) {
|
||||
const variableName = 'mySize';
|
||||
const uniformName = uniformNameForVariable(variableName);
|
||||
const result = parseLiteralStyle({
|
||||
symbol: {
|
||||
symbolType: 'square',
|
||||
size: ['var', variableName],
|
||||
color: 'red',
|
||||
},
|
||||
});
|
||||
|
||||
try {
|
||||
result.uniforms[uniformName]();
|
||||
} catch (e) {
|
||||
done();
|
||||
}
|
||||
done(true);
|
||||
});
|
||||
});
|
||||
});
|
||||
Reference in New Issue
Block a user