diff --git a/src/ol/worker/webgl.js b/src/ol/worker/webgl.js index b4c5a9a6b5..3b50434792 100644 --- a/src/ol/worker/webgl.js +++ b/src/ol/worker/webgl.js @@ -2,60 +2,174 @@ * A worker that does cpu-heavy tasks related to webgl rendering. * @module ol/worker/webgl */ -import { - WebGLWorkerMessageType, - writePointFeatureToBuffers, -} from '../renderer/webgl/Layer.js'; import {assign} from '../obj.js'; +import {WebGLWorkerMessageType} from '../render/webgl/constants.js'; +import { + writeLineSegmentToBuffers, + writePointFeatureToBuffers, + writePolygonTrianglesToBuffers, +} from '../render/webgl/utils.js'; +import { + create as createTransform, + makeInverse as makeInverseTransform, +} from '../transform.js'; /** @type {any} */ const worker = self; worker.onmessage = (event) => { const received = event.data; - if (received.type === WebGLWorkerMessageType.GENERATE_BUFFERS) { - // This is specific to point features (x, y, index) - const baseVertexAttrsCount = 3; - const baseInstructionsCount = 2; + switch (received.type) { + case WebGLWorkerMessageType.GENERATE_POINT_BUFFERS: { + // This is specific to point features (x, y, index) + const baseVertexAttrsCount = 3; + const baseInstructionsCount = 2; - const customAttrsCount = received.customAttributesCount; - const instructionsCount = baseInstructionsCount + customAttrsCount; - const renderInstructions = new Float32Array(received.renderInstructions); + const customAttrsCount = received.customAttributesCount; + const instructionsCount = baseInstructionsCount + customAttrsCount; + const renderInstructions = new Float32Array(received.renderInstructions); - const elementsCount = renderInstructions.length / instructionsCount; - const indicesCount = elementsCount * 6; - const verticesCount = - elementsCount * 4 * (customAttrsCount + baseVertexAttrsCount); - const indexBuffer = new Uint32Array(indicesCount); - const vertexBuffer = new Float32Array(verticesCount); + const elementsCount = renderInstructions.length / instructionsCount; + const indicesCount = elementsCount * 6; + const verticesCount = + elementsCount * 4 * (customAttrsCount + baseVertexAttrsCount); + const indexBuffer = new Uint32Array(indicesCount); + const vertexBuffer = new Float32Array(verticesCount); - let bufferPositions; - for (let i = 0; i < renderInstructions.length; i += instructionsCount) { - bufferPositions = writePointFeatureToBuffers( - renderInstructions, - i, - vertexBuffer, - indexBuffer, - customAttrsCount, - bufferPositions + let bufferPositions; + for (let i = 0; i < renderInstructions.length; i += instructionsCount) { + bufferPositions = writePointFeatureToBuffers( + renderInstructions, + i, + vertexBuffer, + indexBuffer, + customAttrsCount, + bufferPositions + ); + } + + /** @type {import('../render/webgl/constants.js').WebGLWorkerGenerateBuffersMessage} */ + const message = assign( + { + vertexBuffer: vertexBuffer.buffer, + indexBuffer: indexBuffer.buffer, + renderInstructions: renderInstructions.buffer, + }, + received ); + + worker.postMessage(message, [ + vertexBuffer.buffer, + indexBuffer.buffer, + renderInstructions.buffer, + ]); + break; } + case WebGLWorkerMessageType.GENERATE_LINE_STRING_BUFFERS: { + const vertices = []; + const indices = []; - /** @type {import('../renderer/webgl/Layer').WebGLWorkerGenerateBuffersMessage} */ - const message = assign( - { - vertexBuffer: vertexBuffer.buffer, - indexBuffer: indexBuffer.buffer, - renderInstructions: renderInstructions.buffer, - }, - received - ); + const customAttrsCount = received.customAttributesCount; + const instructionsPerVertex = 2; - worker.postMessage(message, [ - vertexBuffer.buffer, - indexBuffer.buffer, - renderInstructions.buffer, - ]); + const renderInstructions = new Float32Array(received.renderInstructions); + let currentInstructionsIndex = 0; + + const transform = received.renderInstructionsTransform; + const invertTransform = createTransform(); + makeInverseTransform(invertTransform, transform); + + let verticesCount, customAttributes; + while (currentInstructionsIndex < renderInstructions.length) { + customAttributes = Array.from( + renderInstructions.slice( + currentInstructionsIndex, + currentInstructionsIndex + customAttrsCount + ) + ); + currentInstructionsIndex += customAttrsCount; + verticesCount = renderInstructions[currentInstructionsIndex++]; + + // last point is only a segment end, do not loop over it + for (let i = 0; i < verticesCount - 1; i++) { + writeLineSegmentToBuffers( + renderInstructions, + currentInstructionsIndex + i * instructionsPerVertex, + currentInstructionsIndex + (i + 1) * instructionsPerVertex, + i > 0 + ? currentInstructionsIndex + (i - 1) * instructionsPerVertex + : null, + i < verticesCount - 2 + ? currentInstructionsIndex + (i + 2) * instructionsPerVertex + : null, + vertices, + indices, + customAttributes, + transform, + invertTransform + ); + } + currentInstructionsIndex += verticesCount * instructionsPerVertex; + } + + const indexBuffer = Uint32Array.from(indices); + const vertexBuffer = Float32Array.from(vertices); + + /** @type {import('../render/webgl/constants.js').WebGLWorkerGenerateBuffersMessage} */ + const message = assign( + { + vertexBuffer: vertexBuffer.buffer, + indexBuffer: indexBuffer.buffer, + renderInstructions: renderInstructions.buffer, + }, + received + ); + + worker.postMessage(message, [ + vertexBuffer.buffer, + indexBuffer.buffer, + renderInstructions.buffer, + ]); + break; + } + case WebGLWorkerMessageType.GENERATE_POLYGON_BUFFERS: { + const vertices = []; + const indices = []; + + const customAttrsCount = received.customAttributesCount; + const renderInstructions = new Float32Array(received.renderInstructions); + + let currentInstructionsIndex = 0; + while (currentInstructionsIndex < renderInstructions.length) { + currentInstructionsIndex = writePolygonTrianglesToBuffers( + renderInstructions, + currentInstructionsIndex, + vertices, + indices, + customAttrsCount + ); + } + + const indexBuffer = Uint32Array.from(indices); + const vertexBuffer = Float32Array.from(vertices); + + /** @type {import('../render/webgl/constants.js').WebGLWorkerGenerateBuffersMessage} */ + const message = assign( + { + vertexBuffer: vertexBuffer.buffer, + indexBuffer: indexBuffer.buffer, + renderInstructions: renderInstructions.buffer, + }, + received + ); + + worker.postMessage(message, [ + vertexBuffer.buffer, + indexBuffer.buffer, + renderInstructions.buffer, + ]); + break; + } } }; diff --git a/test/browser/spec/ol/worker/webgl.test.js b/test/browser/spec/ol/worker/webgl.test.js index 9ddabb8643..cc0276f343 100644 --- a/test/browser/spec/ol/worker/webgl.test.js +++ b/test/browser/spec/ol/worker/webgl.test.js @@ -1,10 +1,14 @@ -import {WebGLWorkerMessageType} from '../../../../../src/ol/renderer/webgl/Layer.js'; +import {WebGLWorkerMessageType} from '../../../../../src/ol/render/webgl/constants.js'; import {create} from '../../../../../src/ol/worker/webgl.js'; +import {create as createTransform} from '../../../../../src/ol/transform.js'; describe('ol/worker/webgl', function () { let worker; beforeEach(function () { worker = create(); + worker.addEventListener('error', function (error) { + expect().fail(error.message); + }); }); afterEach(function () { @@ -15,35 +19,145 @@ describe('ol/worker/webgl', function () { }); describe('messaging', function () { - describe('GENERATE_BUFFERS', function () { - it('responds with buffer data', function (done) { - worker.addEventListener('error', function (error) { - expect().fail(error.message); - }); - - worker.addEventListener('message', function (event) { - expect(event.data.type).to.eql( - WebGLWorkerMessageType.GENERATE_BUFFERS - ); - expect(event.data.renderInstructions.byteLength).to.greaterThan(0); - expect(event.data.indexBuffer.byteLength).to.greaterThan(0); - expect(event.data.vertexBuffer.byteLength).to.greaterThan(0); - expect(event.data.testInt).to.be(101); - expect(event.data.testString).to.be('abcd'); - done(); - }); - - const instructions = new Float32Array(10); - + describe('GENERATE_POINT_BUFFERS', function () { + let responseData; + beforeEach(function (done) { + const renderInstructions = Float32Array.from([0, 10, 111, 20, 30, 222]); + const id = Math.floor(Math.random() * 10000); const message = { - type: WebGLWorkerMessageType.GENERATE_BUFFERS, - renderInstructions: instructions, - customAttributesCount: 0, + type: WebGLWorkerMessageType.GENERATE_POINT_BUFFERS, + renderInstructions, + customAttributesCount: 1, testInt: 101, testString: 'abcd', + id, }; - + responseData = null; worker.postMessage(message); + + worker.addEventListener('message', function (event) { + if (event.data.id === id) { + responseData = event.data; + done(); + } + }); + }); + it('responds with info passed in the message', function () { + expect(responseData.type).to.eql( + WebGLWorkerMessageType.GENERATE_POINT_BUFFERS + ); + expect(responseData.renderInstructions.byteLength).to.greaterThan(0); + expect(responseData.testInt).to.be(101); + expect(responseData.testString).to.be('abcd'); + }); + it('responds with buffer data', function () { + const indices = Array.from(new Uint32Array(responseData.indexBuffer)); + const vertices = Array.from( + new Float32Array(responseData.vertexBuffer) + ); + expect(indices).to.eql([0, 1, 3, 1, 2, 3, 4, 5, 7, 5, 6, 7]); + expect(vertices).to.eql([ + 0, 10, 0, 111, 0, 10, 1, 111, 0, 10, 2, 111, 0, 10, 3, 111, 20, 30, 0, + 222, 20, 30, 1, 222, 20, 30, 2, 222, 20, 30, 3, 222, + ]); + }); + }); + + describe('GENERATE_LINE_STRING_BUFFERS', function () { + let responseData; + beforeEach(function (done) { + const renderInstructions = Float32Array.from([ + 111, 4, 20, 30, 40, 50, 6, 7, 80, 90, + ]); + const id = Math.floor(Math.random() * 10000); + const renderInstructionsTransform = createTransform(); + const message = { + type: WebGLWorkerMessageType.GENERATE_LINE_STRING_BUFFERS, + renderInstructions, + customAttributesCount: 1, + testInt: 101, + testString: 'abcd', + id, + renderInstructionsTransform, + }; + responseData = null; + worker.postMessage(message); + + worker.addEventListener('message', function (event) { + if (event.data.id === id) { + responseData = event.data; + done(); + } + }); + }); + it('responds with info passed in the message', function () { + expect(responseData.type).to.eql( + WebGLWorkerMessageType.GENERATE_LINE_STRING_BUFFERS + ); + expect(responseData.renderInstructions.byteLength).to.greaterThan(0); + expect(responseData.testInt).to.be(101); + expect(responseData.testString).to.be('abcd'); + }); + it('responds with buffer data', function () { + const indices = Array.from(new Uint32Array(responseData.indexBuffer)); + const vertices = Array.from( + new Float32Array(responseData.vertexBuffer) + ); + expect(indices).to.eql([ + 0, 1, 2, 1, 3, 2, 4, 5, 6, 5, 7, 6, 8, 9, 10, 9, 11, 10, + ]); + expect(vertices).to.eql([ + 20, 30, 40, 50, 1750000, 111, 20, 30, 40, 50, 101750000, 111, 20, 30, + 40, 50, 201750000, 111, 20, 30, 40, 50, 301750016, 111, 40, 50, 6, 7, + 93369248, 111, 40, 50, 6, 7, 193369248, 111, 40, 50, 6, 7, 293369248, + 111, 40, 50, 6, 7, 393369248, 111, 6, 7, 80, 90, 89, 111, 6, 7, 80, + 90, 100000088, 111, 6, 7, 80, 90, 200000096, 111, 6, 7, 80, 90, + 300000096, 111, + ]); + }); + }); + + describe('GENERATE_POLYGON_BUFFERS', function () { + let responseData; + beforeEach(function (done) { + const renderInstructions = Float32Array.from([ + 1234, 2, 6, 5, 0, 0, 10, 0, 15, 6, 10, 12, 0, 12, 0, 0, 3, 3, 5, 1, 7, + 3, 5, 5, 3, 3, + ]); + const id = Math.floor(Math.random() * 10000); + const message = { + type: WebGLWorkerMessageType.GENERATE_POLYGON_BUFFERS, + renderInstructions, + customAttributesCount: 1, + testInt: 101, + testString: 'abcd', + id, + }; + responseData = null; + worker.postMessage(message); + + worker.addEventListener('message', function (event) { + if (event.data.id === id) { + responseData = event.data; + done(); + } + }); + }); + it('responds with info passed in the message', function () { + expect(responseData.type).to.eql( + WebGLWorkerMessageType.GENERATE_POLYGON_BUFFERS + ); + expect(responseData.renderInstructions.byteLength).to.greaterThan(0); + expect(responseData.testInt).to.be(101); + expect(responseData.testString).to.be('abcd'); + }); + it('responds with buffer data', function () { + const indices = Array.from(new Uint32Array(responseData.indexBuffer)); + const vertices = Array.from( + new Float32Array(responseData.vertexBuffer) + ); + expect(indices).to.have.length(24); + expect(vertices).to.have.length(33); }); }); });