ol 7.0.0-dev.1658443472213 → 7.0.0-dev.1658733468997
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/Overlay.d.ts +3 -25
- package/Overlay.d.ts.map +1 -1
- package/Overlay.js +3 -25
- package/Overlay.js.map +1 -1
- package/package.json +2 -1
- package/render/webgl/BatchRenderer.d.ts +92 -0
- package/render/webgl/BatchRenderer.d.ts.map +1 -0
- package/render/webgl/BatchRenderer.js +165 -0
- package/render/webgl/BatchRenderer.js.map +1 -0
- package/render/webgl/LineStringBatchRenderer.d.ts +27 -0
- package/render/webgl/LineStringBatchRenderer.d.ts.map +1 -0
- package/render/webgl/LineStringBatchRenderer.js +114 -0
- package/render/webgl/LineStringBatchRenderer.js.map +1 -0
- package/render/webgl/MixedGeometryBatch.d.ts +306 -0
- package/render/webgl/MixedGeometryBatch.d.ts.map +1 -0
- package/render/webgl/MixedGeometryBatch.js +342 -0
- package/render/webgl/MixedGeometryBatch.js.map +1 -0
- package/render/webgl/PointBatchRenderer.d.ts +26 -0
- package/render/webgl/PointBatchRenderer.d.ts.map +1 -0
- package/render/webgl/PointBatchRenderer.js +102 -0
- package/render/webgl/PointBatchRenderer.js.map +1 -0
- package/render/webgl/PolygonBatchRenderer.d.ts +25 -0
- package/render/webgl/PolygonBatchRenderer.d.ts.map +1 -0
- package/render/webgl/PolygonBatchRenderer.js +110 -0
- package/render/webgl/PolygonBatchRenderer.js.map +1 -0
- package/render/webgl/constants.d.ts +43 -0
- package/render/webgl/constants.d.ts.map +1 -0
- package/render/webgl/constants.js +26 -0
- package/render/webgl/constants.js.map +1 -0
- package/render/webgl/utils.d.ts +76 -0
- package/render/webgl/utils.d.ts.map +1 -0
- package/render/webgl/utils.js +257 -0
- package/render/webgl/utils.js.map +1 -0
- package/renderer/webgl/Layer.d.ts +0 -98
- package/renderer/webgl/Layer.d.ts.map +1 -1
- package/renderer/webgl/Layer.js +0 -134
- package/renderer/webgl/Layer.js.map +1 -1
- package/renderer/webgl/PointsLayer.d.ts +4 -1
- package/renderer/webgl/PointsLayer.d.ts.map +1 -1
- package/renderer/webgl/PointsLayer.js +15 -8
- package/renderer/webgl/PointsLayer.js.map +1 -1
- package/renderer/webgl/TileLayer.js +1 -1
- package/renderer/webgl/TileLayer.js.map +1 -1
- package/renderer/webgl/VectorLayer.d.ts +142 -0
- package/renderer/webgl/VectorLayer.d.ts.map +1 -0
- package/renderer/webgl/VectorLayer.js +304 -0
- package/renderer/webgl/VectorLayer.js.map +1 -0
- package/renderer/webgl/shaders.d.ts +43 -0
- package/renderer/webgl/shaders.d.ts.map +1 -0
- package/renderer/webgl/shaders.js +53 -0
- package/renderer/webgl/shaders.js.map +1 -0
- package/src/Overlay.js +3 -25
- package/src/render/webgl/BatchRenderer.js +201 -0
- package/src/render/webgl/LineStringBatchRenderer.js +116 -0
- package/src/render/webgl/MixedGeometryBatch.js +364 -0
- package/src/render/webgl/PointBatchRenderer.js +97 -0
- package/src/render/webgl/PolygonBatchRenderer.js +117 -0
- package/src/render/webgl/constants.js +27 -0
- package/src/render/webgl/utils.js +351 -0
- package/src/renderer/webgl/Layer.js +0 -160
- package/src/renderer/webgl/PointsLayer.js +16 -12
- package/src/renderer/webgl/TileLayer.js +1 -1
- package/src/renderer/webgl/VectorLayer.js +409 -0
- package/src/renderer/webgl/shaders.js +198 -0
- package/src/webgl/Helper.js +30 -45
- package/src/worker/webgl.js +1 -1
- package/util.js +1 -1
- package/webgl/Helper.d.ts +17 -25
- package/webgl/Helper.d.ts.map +1 -1
- package/webgl/Helper.js +29 -43
- package/webgl/Helper.js.map +1 -1
- package/worker/webgl.js +1 -1
- package/worker/webgl.js.map +1 -1
|
@@ -0,0 +1,97 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* @module ol/render/webgl/PointBatchRenderer
|
|
3
|
+
*/
|
|
4
|
+
|
|
5
|
+
import AbstractBatchRenderer from './BatchRenderer.js';
|
|
6
|
+
import {AttributeType} from '../../webgl/Helper.js';
|
|
7
|
+
import {apply as applyTransform} from '../../transform.js';
|
|
8
|
+
|
|
9
|
+
/**
|
|
10
|
+
* Names of attributes made available to the vertex shader.
|
|
11
|
+
* Please note: changing these *will* break custom shaders!
|
|
12
|
+
* @enum {string}
|
|
13
|
+
*/
|
|
14
|
+
export const Attributes = {
|
|
15
|
+
POSITION: 'a_position',
|
|
16
|
+
INDEX: 'a_index',
|
|
17
|
+
};
|
|
18
|
+
|
|
19
|
+
class PointBatchRenderer extends AbstractBatchRenderer {
|
|
20
|
+
/**
|
|
21
|
+
* @param {import("../../webgl/Helper.js").default} helper WebGL helper instance
|
|
22
|
+
* @param {Worker} worker WebGL worker instance
|
|
23
|
+
* @param {string} vertexShader Vertex shader
|
|
24
|
+
* @param {string} fragmentShader Fragment shader
|
|
25
|
+
* @param {Array<import('./BatchRenderer.js').CustomAttribute>} customAttributes List of custom attributes
|
|
26
|
+
*/
|
|
27
|
+
constructor(helper, worker, vertexShader, fragmentShader, customAttributes) {
|
|
28
|
+
super(helper, worker, vertexShader, fragmentShader, customAttributes);
|
|
29
|
+
|
|
30
|
+
// vertices for point must hold both a position (x,y) and an index (their position in the quad)
|
|
31
|
+
this.attributes = [
|
|
32
|
+
{
|
|
33
|
+
name: Attributes.POSITION,
|
|
34
|
+
size: 2,
|
|
35
|
+
type: AttributeType.FLOAT,
|
|
36
|
+
},
|
|
37
|
+
{
|
|
38
|
+
name: Attributes.INDEX,
|
|
39
|
+
size: 1,
|
|
40
|
+
type: AttributeType.FLOAT,
|
|
41
|
+
},
|
|
42
|
+
].concat(
|
|
43
|
+
customAttributes.map(function (attribute) {
|
|
44
|
+
return {
|
|
45
|
+
name: 'a_' + attribute.name,
|
|
46
|
+
size: 1,
|
|
47
|
+
type: AttributeType.FLOAT,
|
|
48
|
+
};
|
|
49
|
+
})
|
|
50
|
+
);
|
|
51
|
+
}
|
|
52
|
+
|
|
53
|
+
/**
|
|
54
|
+
* Render instructions for lines are structured like so:
|
|
55
|
+
* [ x0, y0, customAttr0, ... , xN, yN, customAttrN ]
|
|
56
|
+
* @param {import("./MixedGeometryBatch.js").PointGeometryBatch} batch Point geometry batch
|
|
57
|
+
* @override
|
|
58
|
+
*/
|
|
59
|
+
generateRenderInstructions(batch) {
|
|
60
|
+
// here we anticipate the amount of render instructions for points:
|
|
61
|
+
// 2 instructions per vertex for position (x and y)
|
|
62
|
+
// + 1 instruction per vertex per custom attributes
|
|
63
|
+
const totalInstructionsCount =
|
|
64
|
+
(2 + this.customAttributes.length) * batch.geometriesCount;
|
|
65
|
+
if (
|
|
66
|
+
!batch.renderInstructions ||
|
|
67
|
+
batch.renderInstructions.length !== totalInstructionsCount
|
|
68
|
+
) {
|
|
69
|
+
batch.renderInstructions = new Float32Array(totalInstructionsCount);
|
|
70
|
+
}
|
|
71
|
+
|
|
72
|
+
// loop on features to fill the render instructions
|
|
73
|
+
let batchEntry;
|
|
74
|
+
const tmpCoords = [];
|
|
75
|
+
let renderIndex = 0;
|
|
76
|
+
let value;
|
|
77
|
+
for (const featureUid in batch.entries) {
|
|
78
|
+
batchEntry = batch.entries[featureUid];
|
|
79
|
+
for (let i = 0, ii = batchEntry.flatCoordss.length; i < ii; i++) {
|
|
80
|
+
tmpCoords[0] = batchEntry.flatCoordss[i][0];
|
|
81
|
+
tmpCoords[1] = batchEntry.flatCoordss[i][1];
|
|
82
|
+
applyTransform(batch.renderInstructionsTransform, tmpCoords);
|
|
83
|
+
|
|
84
|
+
batch.renderInstructions[renderIndex++] = tmpCoords[0];
|
|
85
|
+
batch.renderInstructions[renderIndex++] = tmpCoords[1];
|
|
86
|
+
|
|
87
|
+
// pushing custom attributes
|
|
88
|
+
for (let j = 0, jj = this.customAttributes.length; j < jj; j++) {
|
|
89
|
+
value = this.customAttributes[j].callback(batchEntry.feature);
|
|
90
|
+
batch.renderInstructions[renderIndex++] = value;
|
|
91
|
+
}
|
|
92
|
+
}
|
|
93
|
+
}
|
|
94
|
+
}
|
|
95
|
+
}
|
|
96
|
+
|
|
97
|
+
export default PointBatchRenderer;
|
|
@@ -0,0 +1,117 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* @module ol/render/webgl/PolygonBatchRenderer
|
|
3
|
+
*/
|
|
4
|
+
import AbstractBatchRenderer from './BatchRenderer.js';
|
|
5
|
+
import {AttributeType} from '../../webgl/Helper.js';
|
|
6
|
+
import {transform2D} from '../../geom/flat/transform.js';
|
|
7
|
+
|
|
8
|
+
/**
|
|
9
|
+
* Names of attributes made available to the vertex shader.
|
|
10
|
+
* Please note: changing these *will* break custom shaders!
|
|
11
|
+
* @enum {string}
|
|
12
|
+
*/
|
|
13
|
+
export const Attributes = {
|
|
14
|
+
POSITION: 'a_position',
|
|
15
|
+
};
|
|
16
|
+
|
|
17
|
+
class PolygonBatchRenderer extends AbstractBatchRenderer {
|
|
18
|
+
/**
|
|
19
|
+
* @param {import("../../webgl/Helper.js").default} helper WebGL helper instance
|
|
20
|
+
* @param {Worker} worker WebGL worker instance
|
|
21
|
+
* @param {string} vertexShader Vertex shader
|
|
22
|
+
* @param {string} fragmentShader Fragment shader
|
|
23
|
+
* @param {Array<import('./BatchRenderer.js').CustomAttribute>} customAttributes List of custom attributes
|
|
24
|
+
*/
|
|
25
|
+
constructor(helper, worker, vertexShader, fragmentShader, customAttributes) {
|
|
26
|
+
super(helper, worker, vertexShader, fragmentShader, customAttributes);
|
|
27
|
+
|
|
28
|
+
// By default only a position attribute is required to render polygons
|
|
29
|
+
this.attributes = [
|
|
30
|
+
{
|
|
31
|
+
name: Attributes.POSITION,
|
|
32
|
+
size: 2,
|
|
33
|
+
type: AttributeType.FLOAT,
|
|
34
|
+
},
|
|
35
|
+
].concat(
|
|
36
|
+
customAttributes.map(function (attribute) {
|
|
37
|
+
return {
|
|
38
|
+
name: 'a_' + attribute.name,
|
|
39
|
+
size: 1,
|
|
40
|
+
type: AttributeType.FLOAT,
|
|
41
|
+
};
|
|
42
|
+
})
|
|
43
|
+
);
|
|
44
|
+
}
|
|
45
|
+
|
|
46
|
+
/**
|
|
47
|
+
* Render instructions for polygons are structured like so:
|
|
48
|
+
* [ customAttr0, ..., customAttrN, numberOfRings, numberOfVerticesInRing0, ..., numberOfVerticesInRingN, x0, y0, ..., xN, yN, numberOfRings,... ]
|
|
49
|
+
* @param {import("./MixedGeometryBatch.js").PolygonGeometryBatch} batch Polygon geometry batch
|
|
50
|
+
* @override
|
|
51
|
+
*/
|
|
52
|
+
generateRenderInstructions(batch) {
|
|
53
|
+
// here we anticipate the amount of render instructions for polygons:
|
|
54
|
+
// 2 instructions per vertex for position (x and y)
|
|
55
|
+
// + 1 instruction per polygon per custom attributes
|
|
56
|
+
// + 1 instruction per polygon (for vertices count in polygon)
|
|
57
|
+
// + 1 instruction per ring (for vertices count in ring)
|
|
58
|
+
const totalInstructionsCount =
|
|
59
|
+
2 * batch.verticesCount +
|
|
60
|
+
(1 + this.customAttributes.length) * batch.geometriesCount +
|
|
61
|
+
batch.ringsCount;
|
|
62
|
+
if (
|
|
63
|
+
!batch.renderInstructions ||
|
|
64
|
+
batch.renderInstructions.length !== totalInstructionsCount
|
|
65
|
+
) {
|
|
66
|
+
batch.renderInstructions = new Float32Array(totalInstructionsCount);
|
|
67
|
+
}
|
|
68
|
+
|
|
69
|
+
// loop on features to fill the render instructions
|
|
70
|
+
let batchEntry;
|
|
71
|
+
const flatCoords = [];
|
|
72
|
+
let renderIndex = 0;
|
|
73
|
+
let value;
|
|
74
|
+
for (const featureUid in batch.entries) {
|
|
75
|
+
batchEntry = batch.entries[featureUid];
|
|
76
|
+
for (let i = 0, ii = batchEntry.flatCoordss.length; i < ii; i++) {
|
|
77
|
+
flatCoords.length = batchEntry.flatCoordss[i].length;
|
|
78
|
+
transform2D(
|
|
79
|
+
batchEntry.flatCoordss[i],
|
|
80
|
+
0,
|
|
81
|
+
flatCoords.length,
|
|
82
|
+
2,
|
|
83
|
+
batch.renderInstructionsTransform,
|
|
84
|
+
flatCoords
|
|
85
|
+
);
|
|
86
|
+
|
|
87
|
+
// custom attributes
|
|
88
|
+
for (let k = 0, kk = this.customAttributes.length; k < kk; k++) {
|
|
89
|
+
value = this.customAttributes[k].callback(batchEntry.feature);
|
|
90
|
+
batch.renderInstructions[renderIndex++] = value;
|
|
91
|
+
}
|
|
92
|
+
|
|
93
|
+
// ring count
|
|
94
|
+
batch.renderInstructions[renderIndex++] =
|
|
95
|
+
batchEntry.ringsVerticesCounts[i].length;
|
|
96
|
+
|
|
97
|
+
// vertices count in each ring
|
|
98
|
+
for (
|
|
99
|
+
let j = 0, jj = batchEntry.ringsVerticesCounts[i].length;
|
|
100
|
+
j < jj;
|
|
101
|
+
j++
|
|
102
|
+
) {
|
|
103
|
+
batch.renderInstructions[renderIndex++] =
|
|
104
|
+
batchEntry.ringsVerticesCounts[i][j];
|
|
105
|
+
}
|
|
106
|
+
|
|
107
|
+
// looping on points for positions
|
|
108
|
+
for (let j = 0, jj = flatCoords.length; j < jj; j += 2) {
|
|
109
|
+
batch.renderInstructions[renderIndex++] = flatCoords[j];
|
|
110
|
+
batch.renderInstructions[renderIndex++] = flatCoords[j + 1];
|
|
111
|
+
}
|
|
112
|
+
}
|
|
113
|
+
}
|
|
114
|
+
}
|
|
115
|
+
}
|
|
116
|
+
|
|
117
|
+
export default PolygonBatchRenderer;
|
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* @module ol/render/webgl/constants
|
|
3
|
+
*/
|
|
4
|
+
|
|
5
|
+
/**
|
|
6
|
+
* @enum {string}
|
|
7
|
+
*/
|
|
8
|
+
export const WebGLWorkerMessageType = {
|
|
9
|
+
GENERATE_POLYGON_BUFFERS: 'GENERATE_POLYGON_BUFFERS',
|
|
10
|
+
GENERATE_POINT_BUFFERS: 'GENERATE_POINT_BUFFERS',
|
|
11
|
+
GENERATE_LINE_STRING_BUFFERS: 'GENERATE_LINE_STRING_BUFFERS',
|
|
12
|
+
};
|
|
13
|
+
|
|
14
|
+
/**
|
|
15
|
+
* @typedef {Object} WebGLWorkerGenerateBuffersMessage
|
|
16
|
+
* This message will trigger the generation of a vertex and an index buffer based on the given render instructions.
|
|
17
|
+
* When the buffers are generated, the worked will send a message of the same type to the main thread, with
|
|
18
|
+
* the generated buffers in it.
|
|
19
|
+
* Note that any addition properties present in the message *will* be sent back to the main thread.
|
|
20
|
+
* @property {number} id Message id; will be used both in request and response as a means of identification
|
|
21
|
+
* @property {WebGLWorkerMessageType} type Message type
|
|
22
|
+
* @property {ArrayBuffer} renderInstructions Polygon render instructions raw binary buffer.
|
|
23
|
+
* @property {number} [customAttributesCount] Amount of custom attributes count in the polygon render instructions.
|
|
24
|
+
* @property {ArrayBuffer} [vertexBuffer] Vertices array raw binary buffer (sent by the worker).
|
|
25
|
+
* @property {ArrayBuffer} [indexBuffer] Indices array raw binary buffer (sent by the worker).
|
|
26
|
+
* @property {import("../../transform").Transform} [renderInstructionsTransform] Transformation matrix used to project the instructions coordinates
|
|
27
|
+
*/
|
|
@@ -0,0 +1,351 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* @module ol/render/webgl/utils
|
|
3
|
+
*/
|
|
4
|
+
import earcut from 'earcut';
|
|
5
|
+
import {apply as applyTransform} from '../../transform.js';
|
|
6
|
+
import {clamp} from '../../math.js';
|
|
7
|
+
|
|
8
|
+
const tmpArray_ = [];
|
|
9
|
+
|
|
10
|
+
/**
|
|
11
|
+
* An object holding positions both in an index and a vertex buffer.
|
|
12
|
+
* @typedef {Object} BufferPositions
|
|
13
|
+
* @property {number} vertexPosition Position in the vertex buffer
|
|
14
|
+
* @property {number} indexPosition Position in the index buffer
|
|
15
|
+
*/
|
|
16
|
+
const bufferPositions_ = {vertexPosition: 0, indexPosition: 0};
|
|
17
|
+
|
|
18
|
+
function writePointVertex(buffer, pos, x, y, index) {
|
|
19
|
+
buffer[pos + 0] = x;
|
|
20
|
+
buffer[pos + 1] = y;
|
|
21
|
+
buffer[pos + 2] = index;
|
|
22
|
+
}
|
|
23
|
+
|
|
24
|
+
/**
|
|
25
|
+
* Pushes a quad (two triangles) based on a point geometry
|
|
26
|
+
* @param {Float32Array} instructions Array of render instructions for points.
|
|
27
|
+
* @param {number} elementIndex Index from which render instructions will be read.
|
|
28
|
+
* @param {Float32Array} vertexBuffer Buffer in the form of a typed array.
|
|
29
|
+
* @param {Uint32Array} indexBuffer Buffer in the form of a typed array.
|
|
30
|
+
* @param {number} customAttributesCount Amount of custom attributes for each element.
|
|
31
|
+
* @param {BufferPositions} [bufferPositions] Buffer write positions; if not specified, positions will be set at 0.
|
|
32
|
+
* @return {BufferPositions} New buffer positions where to write next
|
|
33
|
+
* @property {number} vertexPosition New position in the vertex buffer where future writes should start.
|
|
34
|
+
* @property {number} indexPosition New position in the index buffer where future writes should start.
|
|
35
|
+
* @private
|
|
36
|
+
*/
|
|
37
|
+
export function writePointFeatureToBuffers(
|
|
38
|
+
instructions,
|
|
39
|
+
elementIndex,
|
|
40
|
+
vertexBuffer,
|
|
41
|
+
indexBuffer,
|
|
42
|
+
customAttributesCount,
|
|
43
|
+
bufferPositions
|
|
44
|
+
) {
|
|
45
|
+
// This is for x, y and index
|
|
46
|
+
const baseVertexAttrsCount = 3;
|
|
47
|
+
const baseInstructionsCount = 2;
|
|
48
|
+
const stride = baseVertexAttrsCount + customAttributesCount;
|
|
49
|
+
|
|
50
|
+
const x = instructions[elementIndex + 0];
|
|
51
|
+
const y = instructions[elementIndex + 1];
|
|
52
|
+
|
|
53
|
+
// read custom numerical attributes on the feature
|
|
54
|
+
const customAttrs = tmpArray_;
|
|
55
|
+
customAttrs.length = customAttributesCount;
|
|
56
|
+
for (let i = 0; i < customAttrs.length; i++) {
|
|
57
|
+
customAttrs[i] = instructions[elementIndex + baseInstructionsCount + i];
|
|
58
|
+
}
|
|
59
|
+
|
|
60
|
+
let vPos = bufferPositions ? bufferPositions.vertexPosition : 0;
|
|
61
|
+
let iPos = bufferPositions ? bufferPositions.indexPosition : 0;
|
|
62
|
+
const baseIndex = vPos / stride;
|
|
63
|
+
|
|
64
|
+
// push vertices for each of the four quad corners (first standard then custom attributes)
|
|
65
|
+
writePointVertex(vertexBuffer, vPos, x, y, 0);
|
|
66
|
+
customAttrs.length &&
|
|
67
|
+
vertexBuffer.set(customAttrs, vPos + baseVertexAttrsCount);
|
|
68
|
+
vPos += stride;
|
|
69
|
+
|
|
70
|
+
writePointVertex(vertexBuffer, vPos, x, y, 1);
|
|
71
|
+
customAttrs.length &&
|
|
72
|
+
vertexBuffer.set(customAttrs, vPos + baseVertexAttrsCount);
|
|
73
|
+
vPos += stride;
|
|
74
|
+
|
|
75
|
+
writePointVertex(vertexBuffer, vPos, x, y, 2);
|
|
76
|
+
customAttrs.length &&
|
|
77
|
+
vertexBuffer.set(customAttrs, vPos + baseVertexAttrsCount);
|
|
78
|
+
vPos += stride;
|
|
79
|
+
|
|
80
|
+
writePointVertex(vertexBuffer, vPos, x, y, 3);
|
|
81
|
+
customAttrs.length &&
|
|
82
|
+
vertexBuffer.set(customAttrs, vPos + baseVertexAttrsCount);
|
|
83
|
+
vPos += stride;
|
|
84
|
+
|
|
85
|
+
indexBuffer[iPos++] = baseIndex;
|
|
86
|
+
indexBuffer[iPos++] = baseIndex + 1;
|
|
87
|
+
indexBuffer[iPos++] = baseIndex + 3;
|
|
88
|
+
indexBuffer[iPos++] = baseIndex + 1;
|
|
89
|
+
indexBuffer[iPos++] = baseIndex + 2;
|
|
90
|
+
indexBuffer[iPos++] = baseIndex + 3;
|
|
91
|
+
|
|
92
|
+
bufferPositions_.vertexPosition = vPos;
|
|
93
|
+
bufferPositions_.indexPosition = iPos;
|
|
94
|
+
|
|
95
|
+
return bufferPositions_;
|
|
96
|
+
}
|
|
97
|
+
|
|
98
|
+
/**
|
|
99
|
+
* Pushes a single quad to form a line segment; also includes a computation for the join angles with previous and next
|
|
100
|
+
* segment, in order to be able to offset the vertices correctly in the shader
|
|
101
|
+
* @param {Float32Array} instructions Array of render instructions for lines.
|
|
102
|
+
* @param {number} segmentStartIndex Index of the segment start point from which render instructions will be read.
|
|
103
|
+
* @param {number} segmentEndIndex Index of the segment start point from which render instructions will be read.
|
|
104
|
+
* @param {number|null} beforeSegmentIndex Index of the point right before the segment (null if none, e.g this is a line start)
|
|
105
|
+
* @param {number|null} afterSegmentIndex Index of the point right after the segment (null if none, e.g this is a line end)
|
|
106
|
+
* @param {Array<number>} vertexArray Array containing vertices.
|
|
107
|
+
* @param {Array<number>} indexArray Array containing indices.
|
|
108
|
+
* @param {Array<number>} customAttributes Array of custom attributes value
|
|
109
|
+
* @param {import('../../transform.js').Transform} instructionsTransform Transform matrix used to project coordinates in instructions
|
|
110
|
+
* @param {import('../../transform.js').Transform} invertInstructionsTransform Transform matrix used to project coordinates in instructions
|
|
111
|
+
* @private
|
|
112
|
+
*/
|
|
113
|
+
export function writeLineSegmentToBuffers(
|
|
114
|
+
instructions,
|
|
115
|
+
segmentStartIndex,
|
|
116
|
+
segmentEndIndex,
|
|
117
|
+
beforeSegmentIndex,
|
|
118
|
+
afterSegmentIndex,
|
|
119
|
+
vertexArray,
|
|
120
|
+
indexArray,
|
|
121
|
+
customAttributes,
|
|
122
|
+
instructionsTransform,
|
|
123
|
+
invertInstructionsTransform
|
|
124
|
+
) {
|
|
125
|
+
// compute the stride to determine how many vertices were already pushed
|
|
126
|
+
const baseVertexAttrsCount = 5; // base attributes: x0, y0, x1, y1, params (vertex number [0-3], join angle 1, join angle 2)
|
|
127
|
+
const stride = baseVertexAttrsCount + customAttributes.length;
|
|
128
|
+
const baseIndex = vertexArray.length / stride;
|
|
129
|
+
|
|
130
|
+
// The segment is composed of two positions called P0[x0, y0] and P1[x1, y1]
|
|
131
|
+
// Depending on whether there are points before and after the segment, its final shape
|
|
132
|
+
// will be different
|
|
133
|
+
const p0 = [
|
|
134
|
+
instructions[segmentStartIndex + 0],
|
|
135
|
+
instructions[segmentStartIndex + 1],
|
|
136
|
+
];
|
|
137
|
+
const p1 = [instructions[segmentEndIndex], instructions[segmentEndIndex + 1]];
|
|
138
|
+
|
|
139
|
+
// to compute offsets from the line center we need to reproject
|
|
140
|
+
// coordinates back in world units and compute the length of the segment
|
|
141
|
+
const p0world = applyTransform(invertInstructionsTransform, [...p0]);
|
|
142
|
+
const p1world = applyTransform(invertInstructionsTransform, [...p1]);
|
|
143
|
+
|
|
144
|
+
function computeVertexParameters(vertexNumber, joinAngle1, joinAngle2) {
|
|
145
|
+
const shift = 10000;
|
|
146
|
+
const anglePrecision = 1500;
|
|
147
|
+
return (
|
|
148
|
+
Math.round(joinAngle1 * anglePrecision) +
|
|
149
|
+
Math.round(joinAngle2 * anglePrecision) * shift +
|
|
150
|
+
vertexNumber * shift * shift
|
|
151
|
+
);
|
|
152
|
+
}
|
|
153
|
+
|
|
154
|
+
// compute the angle between p0pA and p0pB
|
|
155
|
+
// returns a value in [0, 2PI]
|
|
156
|
+
function angleBetween(p0, pA, pB) {
|
|
157
|
+
const lenA = Math.sqrt(
|
|
158
|
+
(pA[0] - p0[0]) * (pA[0] - p0[0]) + (pA[1] - p0[1]) * (pA[1] - p0[1])
|
|
159
|
+
);
|
|
160
|
+
const tangentA = [(pA[0] - p0[0]) / lenA, (pA[1] - p0[1]) / lenA];
|
|
161
|
+
const orthoA = [-tangentA[1], tangentA[0]];
|
|
162
|
+
const lenB = Math.sqrt(
|
|
163
|
+
(pB[0] - p0[0]) * (pB[0] - p0[0]) + (pB[1] - p0[1]) * (pB[1] - p0[1])
|
|
164
|
+
);
|
|
165
|
+
const tangentB = [(pB[0] - p0[0]) / lenB, (pB[1] - p0[1]) / lenB];
|
|
166
|
+
|
|
167
|
+
// this angle can be clockwise or anticlockwise; hence the computation afterwards
|
|
168
|
+
const angle =
|
|
169
|
+
lenA === 0 || lenB === 0
|
|
170
|
+
? 0
|
|
171
|
+
: Math.acos(
|
|
172
|
+
clamp(tangentB[0] * tangentA[0] + tangentB[1] * tangentA[1], -1, 1)
|
|
173
|
+
);
|
|
174
|
+
const isClockwise = tangentB[0] * orthoA[0] + tangentB[1] * orthoA[1] > 0;
|
|
175
|
+
return !isClockwise ? Math.PI * 2 - angle : angle;
|
|
176
|
+
}
|
|
177
|
+
|
|
178
|
+
const joinBefore = beforeSegmentIndex !== null;
|
|
179
|
+
const joinAfter = afterSegmentIndex !== null;
|
|
180
|
+
|
|
181
|
+
let angle0 = 0;
|
|
182
|
+
let angle1 = 0;
|
|
183
|
+
|
|
184
|
+
// add vertices and adapt offsets for P0 in case of join
|
|
185
|
+
if (joinBefore) {
|
|
186
|
+
// B for before
|
|
187
|
+
const pB = [
|
|
188
|
+
instructions[beforeSegmentIndex],
|
|
189
|
+
instructions[beforeSegmentIndex + 1],
|
|
190
|
+
];
|
|
191
|
+
const pBworld = applyTransform(invertInstructionsTransform, [...pB]);
|
|
192
|
+
angle0 = angleBetween(p0world, p1world, pBworld);
|
|
193
|
+
}
|
|
194
|
+
// adapt offsets for P1 in case of join
|
|
195
|
+
if (joinAfter) {
|
|
196
|
+
// A for after
|
|
197
|
+
const pA = [
|
|
198
|
+
instructions[afterSegmentIndex],
|
|
199
|
+
instructions[afterSegmentIndex + 1],
|
|
200
|
+
];
|
|
201
|
+
const pAworld = applyTransform(invertInstructionsTransform, [...pA]);
|
|
202
|
+
angle1 = angleBetween(p1world, p0world, pAworld);
|
|
203
|
+
}
|
|
204
|
+
|
|
205
|
+
// add main segment triangles
|
|
206
|
+
vertexArray.push(
|
|
207
|
+
p0[0],
|
|
208
|
+
p0[1],
|
|
209
|
+
p1[0],
|
|
210
|
+
p1[1],
|
|
211
|
+
computeVertexParameters(0, angle0, angle1)
|
|
212
|
+
);
|
|
213
|
+
vertexArray.push(...customAttributes);
|
|
214
|
+
|
|
215
|
+
vertexArray.push(
|
|
216
|
+
p0[0],
|
|
217
|
+
p0[1],
|
|
218
|
+
p1[0],
|
|
219
|
+
p1[1],
|
|
220
|
+
computeVertexParameters(1, angle0, angle1)
|
|
221
|
+
);
|
|
222
|
+
vertexArray.push(...customAttributes);
|
|
223
|
+
|
|
224
|
+
vertexArray.push(
|
|
225
|
+
p0[0],
|
|
226
|
+
p0[1],
|
|
227
|
+
p1[0],
|
|
228
|
+
p1[1],
|
|
229
|
+
computeVertexParameters(2, angle0, angle1)
|
|
230
|
+
);
|
|
231
|
+
vertexArray.push(...customAttributes);
|
|
232
|
+
|
|
233
|
+
vertexArray.push(
|
|
234
|
+
p0[0],
|
|
235
|
+
p0[1],
|
|
236
|
+
p1[0],
|
|
237
|
+
p1[1],
|
|
238
|
+
computeVertexParameters(3, angle0, angle1)
|
|
239
|
+
);
|
|
240
|
+
vertexArray.push(...customAttributes);
|
|
241
|
+
|
|
242
|
+
indexArray.push(
|
|
243
|
+
baseIndex,
|
|
244
|
+
baseIndex + 1,
|
|
245
|
+
baseIndex + 2,
|
|
246
|
+
baseIndex + 1,
|
|
247
|
+
baseIndex + 3,
|
|
248
|
+
baseIndex + 2
|
|
249
|
+
);
|
|
250
|
+
}
|
|
251
|
+
|
|
252
|
+
/**
|
|
253
|
+
* Pushes several triangles to form a polygon, including holes
|
|
254
|
+
* @param {Float32Array} instructions Array of render instructions for lines.
|
|
255
|
+
* @param {number} polygonStartIndex Index of the polygon start point from which render instructions will be read.
|
|
256
|
+
* @param {Array<number>} vertexArray Array containing vertices.
|
|
257
|
+
* @param {Array<number>} indexArray Array containing indices.
|
|
258
|
+
* @param {number} customAttributesCount Amount of custom attributes for each element.
|
|
259
|
+
* @return {number} Next polygon instructions index
|
|
260
|
+
* @private
|
|
261
|
+
*/
|
|
262
|
+
export function writePolygonTrianglesToBuffers(
|
|
263
|
+
instructions,
|
|
264
|
+
polygonStartIndex,
|
|
265
|
+
vertexArray,
|
|
266
|
+
indexArray,
|
|
267
|
+
customAttributesCount
|
|
268
|
+
) {
|
|
269
|
+
const instructionsPerVertex = 2; // x, y
|
|
270
|
+
const attributesPerVertex = 2 + customAttributesCount;
|
|
271
|
+
let instructionsIndex = polygonStartIndex;
|
|
272
|
+
const customAttributes = instructions.slice(
|
|
273
|
+
instructionsIndex,
|
|
274
|
+
instructionsIndex + customAttributesCount
|
|
275
|
+
);
|
|
276
|
+
instructionsIndex += customAttributesCount;
|
|
277
|
+
const ringsCount = instructions[instructionsIndex++];
|
|
278
|
+
let verticesCount = 0;
|
|
279
|
+
const holes = new Array(ringsCount - 1);
|
|
280
|
+
for (let i = 0; i < ringsCount; i++) {
|
|
281
|
+
verticesCount += instructions[instructionsIndex++];
|
|
282
|
+
if (i < ringsCount - 1) {
|
|
283
|
+
holes[i] = verticesCount;
|
|
284
|
+
}
|
|
285
|
+
}
|
|
286
|
+
const flatCoords = instructions.slice(
|
|
287
|
+
instructionsIndex,
|
|
288
|
+
instructionsIndex + verticesCount * instructionsPerVertex
|
|
289
|
+
);
|
|
290
|
+
|
|
291
|
+
// pushing to vertices and indices!! this is where the magic happens
|
|
292
|
+
const result = earcut(flatCoords, holes, instructionsPerVertex);
|
|
293
|
+
for (let i = 0; i < result.length; i++) {
|
|
294
|
+
indexArray.push(result[i] + vertexArray.length / attributesPerVertex);
|
|
295
|
+
}
|
|
296
|
+
for (let i = 0; i < flatCoords.length; i += 2) {
|
|
297
|
+
vertexArray.push(flatCoords[i], flatCoords[i + 1], ...customAttributes);
|
|
298
|
+
}
|
|
299
|
+
|
|
300
|
+
return instructionsIndex + verticesCount * instructionsPerVertex;
|
|
301
|
+
}
|
|
302
|
+
|
|
303
|
+
/**
|
|
304
|
+
* Returns a texture of 1x1 pixel, white
|
|
305
|
+
* @private
|
|
306
|
+
* @return {ImageData} Image data.
|
|
307
|
+
*/
|
|
308
|
+
export function getBlankImageData() {
|
|
309
|
+
const canvas = document.createElement('canvas');
|
|
310
|
+
const image = canvas.getContext('2d').createImageData(1, 1);
|
|
311
|
+
image.data[0] = 255;
|
|
312
|
+
image.data[1] = 255;
|
|
313
|
+
image.data[2] = 255;
|
|
314
|
+
image.data[3] = 255;
|
|
315
|
+
return image;
|
|
316
|
+
}
|
|
317
|
+
|
|
318
|
+
/**
|
|
319
|
+
* Generates a color array based on a numerical id
|
|
320
|
+
* Note: the range for each component is 0 to 1 with 256 steps
|
|
321
|
+
* @param {number} id Id
|
|
322
|
+
* @param {Array<number>} [opt_array] Reusable array
|
|
323
|
+
* @return {Array<number>} Color array containing the encoded id
|
|
324
|
+
*/
|
|
325
|
+
export function colorEncodeId(id, opt_array) {
|
|
326
|
+
const array = opt_array || [];
|
|
327
|
+
const radix = 256;
|
|
328
|
+
const divide = radix - 1;
|
|
329
|
+
array[0] = Math.floor(id / radix / radix / radix) / divide;
|
|
330
|
+
array[1] = (Math.floor(id / radix / radix) % radix) / divide;
|
|
331
|
+
array[2] = (Math.floor(id / radix) % radix) / divide;
|
|
332
|
+
array[3] = (id % radix) / divide;
|
|
333
|
+
return array;
|
|
334
|
+
}
|
|
335
|
+
|
|
336
|
+
/**
|
|
337
|
+
* Reads an id from a color-encoded array
|
|
338
|
+
* Note: the expected range for each component is 0 to 1 with 256 steps.
|
|
339
|
+
* @param {Array<number>} color Color array containing the encoded id
|
|
340
|
+
* @return {number} Decoded id
|
|
341
|
+
*/
|
|
342
|
+
export function colorDecodeId(color) {
|
|
343
|
+
let id = 0;
|
|
344
|
+
const radix = 256;
|
|
345
|
+
const mult = radix - 1;
|
|
346
|
+
id += Math.round(color[0] * radix * radix * radix * mult);
|
|
347
|
+
id += Math.round(color[1] * radix * radix * mult);
|
|
348
|
+
id += Math.round(color[2] * radix * mult);
|
|
349
|
+
id += Math.round(color[3] * mult);
|
|
350
|
+
return id;
|
|
351
|
+
}
|