diff --git a/.circleci/config.yml b/.circleci/config.yml
index 646d54b8cc1..6afe2cac7b6 100644
--- a/.circleci/config.yml
+++ b/.circleci/config.yml
@@ -71,6 +71,12 @@ workflows:
filters:
tags:
only: /.*/
+ - test-usvg:
+ requires:
+ - setup-playwright
+ filters:
+ tags:
+ only: /.*/
- test-csp:
requires:
- setup-playwright
@@ -365,6 +371,22 @@ jobs:
- store_test_results:
path: test/unit/test-results.xml
+ test-usvg:
+ <<: *linux-defaults
+ steps:
+ - attach_workspace:
+ at: ~/
+ - run:
+ name: Run usvg tests
+ command: |
+ tar xvzf test/usvg/test-suite.tar.gz -C test/usvg/
+ npm run test-usvg
+ no_output_timeout: 5m
+ - store_artifacts:
+ path: test/usvg/vitest
+ - store_test_results:
+ path: test/usvg/test-results.xml
+
test-query:
<<: *linux-defaults
steps:
diff --git a/.eslintrc b/.eslintrc
index 94c0726670d..684f236235f 100644
--- a/.eslintrc
+++ b/.eslintrc
@@ -9,7 +9,7 @@
"parserOptions": {
"projectService": {
"defaultProject": "./tsconfig.json",
- "allowDefaultProject": ["*.js"]
+ "allowDefaultProject": ["*.js", "debug/*", "build/*"]
}
},
"plugins": [
diff --git a/.gitignore b/.gitignore
index e56b0590682..000e2d6e5f5 100644
--- a/.gitignore
+++ b/.gitignore
@@ -37,3 +37,9 @@ vitest.config.js.*
tsconfig.tsbuildinfo
bundle-analysis.html
+
+# tmp usvg ignores
+test/usvg/vitest/
+test/usvg/test-suite/
+test/usvg/test-results.xml
+src/data/usvg/usvg_pb_renderer.js
diff --git a/3d-style/data/bucket/model_bucket.ts b/3d-style/data/bucket/model_bucket.ts
index 6f091f84936..fbe3dd8b481 100644
--- a/3d-style/data/bucket/model_bucket.ts
+++ b/3d-style/data/bucket/model_bucket.ts
@@ -39,12 +39,13 @@ import type {TileFootprint} from '../../../3d-style/util/conflation';
class ModelFeature {
feature: EvaluationFeature;
+ featureStates: FeatureState;
instancedDataOffset: number;
instancedDataCount: number;
- rotation: Array;
- scale: Array;
- translation: Array;
+ rotation: vec3;
+ scale: vec3;
+ translation: vec3;
constructor(feature: EvaluationFeature, offset: number) {
this.feature = feature;
@@ -83,9 +84,7 @@ class ModelBucket implements Bucket {
stateDependentLayerIds: Array;
hasPattern: boolean;
- instancesPerModel: {
- string: PerModelAttributes;
- };
+ instancesPerModel: Record;
uploaded: boolean;
@@ -128,7 +127,6 @@ class ModelBucket implements Bucket {
this.stateDependentLayerIds = this.layers.filter((l) => l.isStateDependent()).map((l) => l.id);
this.hasPattern = false;
- // @ts-expect-error - TS2741 - Property 'string' is missing in type '{}' but required in type '{ string: PerModelAttributes; }'.
this.instancesPerModel = {};
this.validForExaggeration = 0;
this.maxVerticalOffset = 0;
@@ -419,8 +417,7 @@ class ModelBucket implements Bucket {
const color = layer.paint.get('model-color').evaluate(evaluationFeature, featureState, canonical);
color.a = layer.paint.get('model-color-mix-intensity').evaluate(evaluationFeature, featureState, canonical);
- // @ts-expect-error - TS2322 - Type '[]' is not assignable to type 'mat4'.
- const rotationScaleYZFlip: mat4 = [];
+ const rotationScaleYZFlip = [] as unknown as mat4;
if (this.maxVerticalOffset < translation[2]) this.maxVerticalOffset = translation[2];
this.maxScale = Math.max(Math.max(this.maxScale, scale[0]), Math.max(scale[1], scale[2]));
diff --git a/3d-style/data/model.ts b/3d-style/data/model.ts
index cfd7cbe8457..bc6982e6dfb 100644
--- a/3d-style/data/model.ts
+++ b/3d-style/data/model.ts
@@ -174,7 +174,6 @@ export function calculateModelMatrix(matrix: mat4, model: Readonly, state
if (state.elevation) {
elevation = state.elevation.getAtPointOrZero(new MercatorCoordinate(projectedPoint.x / worldSize, projectedPoint.y / worldSize), 0.0);
}
- // @ts-expect-error - TS2345 - Argument of type 'number[] | Float32Array | Float64Array' is not assignable to parameter of type 'ReadonlyMat4'.
const mercProjPos = vec4.transformMat4([] as any, [projectedPoint.x, projectedPoint.y, elevation, 1.0], state.projMatrix);
const mercProjectionScale = mercProjPos[3] / state.cameraToCenterDistance;
const viewMetersPerPixel = getMetersPerPixelAtLatitude(state.center.lat, zoom);
@@ -182,7 +181,6 @@ export function calculateModelMatrix(matrix: mat4, model: Readonly, state
scaleZ = mercProjectionScale * viewMetersPerPixel;
} else if (state.projection.name === 'globe') {
const globeMatrix = convertModelMatrixForGlobe(matrix, state);
- // @ts-expect-error - TS2345 - Argument of type 'number[] | Float32Array | Float64Array' is not assignable to parameter of type 'ReadonlyMat4'.
const worldViewProjection = mat4.multiply([] as any, state.projMatrix, globeMatrix);
const globeProjPos = [0, 0, 0, 1];
vec4.transformMat4(globeProjPos as [number, number, number, number], globeProjPos as [number, number, number, number], worldViewProjection);
@@ -209,32 +207,30 @@ export function calculateModelMatrix(matrix: mat4, model: Readonly, state
// When applying physics (rotation) we need to insert rotation matrix
// between model rotation and transforms above. Keep the intermediate results.
- const modelMatrixBeforeRotationScaleYZFlip = [...matrix];
+ const modelMatrixBeforeRotationScaleYZFlip = [...matrix] as mat4;
const orientation = model.orientation;
- // @ts-expect-error - TS2322 - Type '[]' is not assignable to type 'mat4'.
- const rotationScaleYZFlip: mat4 = [];
- rotationScaleYZFlipMatrix(rotationScaleYZFlip,
- [orientation[0] + rotation[0],
- orientation[1] + rotation[1],
- orientation[2] + rotation[2]],
- scale);
- // @ts-expect-error - TS2345 - Argument of type '[number]' is not assignable to parameter of type 'ReadonlyMat4'. | TS2352 - Conversion of type 'mat4' to type '[]' may be a mistake because neither type sufficiently overlaps with the other. If this was intentional, convert the expression to 'unknown' first.
- mat4.multiply(matrix, modelMatrixBeforeRotationScaleYZFlip as [number], rotationScaleYZFlip as []);
+ const rotationScaleYZFlip = [] as unknown as mat4;
+ rotationScaleYZFlipMatrix(
+ rotationScaleYZFlip,
+ [
+ orientation[0] + rotation[0],
+ orientation[1] + rotation[1],
+ orientation[2] + rotation[2]
+ ],
+ scale
+ );
+ mat4.multiply(matrix, modelMatrixBeforeRotationScaleYZFlip, rotationScaleYZFlip);
if (applyElevation && state.elevation) {
let elevate = 0;
- const rotateOnTerrain = [];
+ const rotateOnTerrain = [] as unknown as quat;
if (followTerrainSlope && state.elevation) {
- // @ts-expect-error - TS2345 - Argument of type 'any[]' is not assignable to parameter of type 'quat'.
elevate = positionModelOnTerrain(rotateOnTerrain, state, model.aabb, matrix, position);
- // @ts-expect-error - TS2345 - Argument of type '[]' is not assignable to parameter of type 'ReadonlyQuat'.
- const rotationOnTerrain = mat4.fromQuat([] as any, rotateOnTerrain as []);
- // @ts-expect-error - TS2345 - Argument of type '[]' is not assignable to parameter of type 'ReadonlyMat4'. | TS2352 - Conversion of type 'mat4' to type '[]' may be a mistake because neither type sufficiently overlaps with the other. If this was intentional, convert the expression to 'unknown' first.
- const appendRotation = mat4.multiply([] as any, rotationOnTerrain, rotationScaleYZFlip as []);
- // @ts-expect-error - TS2345 - Argument of type '[number]' is not assignable to parameter of type 'ReadonlyMat4'.
- mat4.multiply(matrix, modelMatrixBeforeRotationScaleYZFlip as [number], appendRotation);
+ const rotationOnTerrain = mat4.fromQuat([] as unknown as mat4, rotateOnTerrain);
+ const appendRotation = mat4.multiply([] as any, rotationOnTerrain, rotationScaleYZFlip);
+ mat4.multiply(matrix, modelMatrixBeforeRotationScaleYZFlip, appendRotation);
} else {
elevate = state.elevation.getAtPointOrZero(new MercatorCoordinate(projectedPoint.x / worldSize, projectedPoint.y / worldSize), 0.0);
}
@@ -261,8 +257,7 @@ export default class Model {
this.nodes = nodes;
this.uploaded = false;
this.aabb = new Aabb([Infinity, Infinity, Infinity], [-Infinity, -Infinity, -Infinity]);
- // @ts-expect-error - TS2322 - Type '[]' is not assignable to type 'mat4'.
- this.matrix = [];
+ this.matrix = [] as unknown as mat4;
}
_applyTransformations(node: Node, parentMatrix: mat4) {
diff --git a/3d-style/render/draw_model.ts b/3d-style/render/draw_model.ts
index d26aed6b2f7..0a6534ccecd 100644
--- a/3d-style/render/draw_model.ts
+++ b/3d-style/render/draw_model.ts
@@ -71,15 +71,12 @@ type RenderData = {
function fogMatrixForModel(modelMatrix: mat4, transform: Transform): mat4 {
// convert model matrix from the default world size to the one used by the fog
- const fogMatrix = [...modelMatrix];
+ const fogMatrix = [...modelMatrix] as mat4;
const scale = transform.cameraWorldSizeForFog / transform.worldSize;
const scaleMatrix = mat4.identity([] as any);
mat4.scale(scaleMatrix, scaleMatrix, [scale, scale, 1]);
- // @ts-expect-error - TS2345 - Argument of type '[number]' is not assignable to parameter of type 'mat4'.
- mat4.multiply(fogMatrix as [number], scaleMatrix, fogMatrix as [number]);
- // @ts-expect-error - TS2345 - Argument of type '[number]' is not assignable to parameter of type 'mat4'.
- mat4.multiply(fogMatrix as [number], transform.worldToFogMatrix, fogMatrix as [number]);
- // @ts-expect-error - TS2322 - Type 'number[]' is not assignable to type 'mat4'.
+ mat4.multiply(fogMatrix, scaleMatrix, fogMatrix);
+ mat4.multiply(fogMatrix, transform.worldToFogMatrix, fogMatrix);
return fogMatrix;
}
@@ -168,7 +165,7 @@ function drawMesh(sortedMesh: SortedMesh, painter: Painter, layer: ModelStyleLay
if (painter.transform.projection.zAxisUnit === "pixels") {
lightingMatrix = [...sortedMesh.nodeModelMatrix];
} else {
- lightingMatrix = mat4.multiply([] as any, modelParameters.zScaleMatrix, sortedMesh.nodeModelMatrix);
+ lightingMatrix = mat4.multiply([] as unknown as mat4, modelParameters.zScaleMatrix, sortedMesh.nodeModelMatrix);
}
mat4.multiply(lightingMatrix, modelParameters.negCameraPosMatrix, lightingMatrix);
const normalMatrix = mat4.invert([] as any, lightingMatrix);
@@ -274,7 +271,7 @@ function prepareMeshes(transform: Transform, node: Node, modelMatrix: mat4, proj
nodeModelMatrix = [...modelMatrix];
}
mat4.multiply(nodeModelMatrix, nodeModelMatrix, node.matrix);
- const worldViewProjection = mat4.multiply([] as any, projectionMatrix, nodeModelMatrix);
+ const worldViewProjection = mat4.multiply([] as unknown as mat4, projectionMatrix, nodeModelMatrix);
if (node.meshes) {
for (const mesh of node.meshes) {
if (mesh.material.alphaMode !== 'BLEND') {
@@ -407,7 +404,6 @@ function drawModels(painter: Painter, sourceCache: SourceCache, layer: ModelStyl
const modelParameters = {zScaleMatrix, negCameraPosMatrix};
modelParametersVector.push(modelParameters);
for (const node of model.nodes) {
- // @ts-expect-error - TS2345 - Argument of type 'number[] | Float32Array | Float64Array' is not assignable to parameter of type 'mat4'.
prepareMeshes(painter.transform, node, model.matrix, painter.transform.expandedFarZProjMatrix, modelIndex, transparentMeshes, opaqueMeshes);
}
modelIndex++;
@@ -596,7 +592,6 @@ function drawVectorLayerModels(painter: Painter, source: SourceCache, layer: Mod
const tileMatrix = tr.calculatePosMatrix(coord.toUnwrapped(), tr.worldSize);
renderData.tileMatrix.set(tileMatrix);
- // @ts-expect-error - TS2345 - Argument of type 'Float64Array' is not assignable to parameter of type 'mat4'.
renderData.shadowTileMatrix = Float32Array.from(shadowRenderer.calculateShadowPassMatrixFromMatrix(tileMatrix));
renderData.aabb.min.fill(0);
renderData.aabb.max[0] = renderData.aabb.max[1] = EXTENT;
@@ -606,7 +601,7 @@ function drawVectorLayerModels(painter: Painter, source: SourceCache, layer: Mod
// camera position in the tile coordinates
const tiles = 1 << coord.canonical.z;
- const cameraPos = [
+ const cameraPos: [number, number, number] = [
((mercCameraPos.x - coord.wrap) * tiles - coord.canonical.x) * EXTENT,
(mercCameraPos.y * tiles - coord.canonical.y) * EXTENT,
mercCameraPos.z * tiles * EXTENT
@@ -632,7 +627,6 @@ function drawVectorLayerModels(painter: Painter, source: SourceCache, layer: Mod
if (!model || !model.uploaded) continue;
for (const node of model.nodes) {
- // @ts-expect-error - TS2345 - Argument of type 'number[]' is not assignable to parameter of type '[number, number, number]'.
drawInstancedNode(painter, layer, node, modelInstances, cameraPos, coord, renderData);
}
}
@@ -804,7 +798,7 @@ function drawBatchedModels(painter: Painter, source: SourceCache, layer: ModelSt
step = 1;
}
- const invTileMatrix = new Float64Array(16);
+ const invTileMatrix = new Float64Array(16) as unknown as mat4;
const cameraPosTileCoord = vec3.create();
const cameraPointTileCoord = new Point(0.0, 0.0);
@@ -822,9 +816,7 @@ function drawBatchedModels(painter: Painter, source: SourceCache, layer: ModelSt
const modelTraits = bucket.modelTraits;
if (!isShadowPass && frontCutoffEnabled) {
- // @ts-expect-error - TS2345 - Argument of type 'Float64Array' is not assignable to parameter of type 'ReadonlyMat4'.
mat4.invert(invTileMatrix, tileMatrix);
- // @ts-expect-error - TS2345 - Argument of type 'Float64Array' is not assignable to parameter of type 'ReadonlyMat4'.
vec3.transformMat4(cameraPosTileCoord, cameraPos, invTileMatrix);
cameraPointTileCoord.x = cameraPosTileCoord[0];
cameraPointTileCoord.y = cameraPosTileCoord[1];
@@ -843,15 +835,11 @@ function drawBatchedModels(painter: Painter, source: SourceCache, layer: ModelSt
const calculateNodeAabb = () => {
const localBounds = nodeInfo.aabb;
- // @ts-expect-error - TS2322 - Type 'number[]' is not assignable to type 'vec3'.
- aabb.min = [...localBounds.min];
- // @ts-expect-error - TS2322 - Type 'number[]' is not assignable to type 'vec3'.
- aabb.max = [...localBounds.max];
+ aabb.min = [...localBounds.min] as vec3;
+ aabb.max = [...localBounds.max] as vec3;
aabb.min[2] += elevation;
aabb.max[2] += elevation;
- // @ts-expect-error - TS2345 - Argument of type 'Float64Array' is not assignable to parameter of type 'ReadonlyMat4'.
vec3.transformMat4(aabb.min, aabb.min, tileMatrix);
- // @ts-expect-error - TS2345 - Argument of type 'Float64Array' is not assignable to parameter of type 'ReadonlyMat4'.
vec3.transformMat4(aabb.max, aabb.max, tileMatrix);
return aabb;
};
@@ -859,7 +847,7 @@ function drawBatchedModels(painter: Painter, source: SourceCache, layer: ModelSt
const scale = nodeInfo.evaluatedScale;
if (scale[0] <= 1 && scale[1] <= 1 && scale[2] <= 1 && nodeAabb.intersects(frustum) === 0) {
- // While it is possible to use arbitrary scale for landmarks, it is highly unlikely
+ // While it is possible to use arbitrary scale for landmarks, it is highly unlikely
// and frustum culling optimization could be skipped in that case.
continue;
}
@@ -876,28 +864,23 @@ function drawBatchedModels(painter: Painter, source: SourceCache, layer: ModelSt
}
}
- const tileModelMatrix = [...tileMatrix];
+ const tileModelMatrix = [...tileMatrix] as mat4;
const anchorX = node.anchor ? node.anchor[0] : 0;
const anchorY = node.anchor ? node.anchor[1] : 0;
- // @ts-expect-error - TS2345 - Argument of type '[number]' is not assignable to parameter of type 'mat4'.
- mat4.translate(tileModelMatrix as [number], tileModelMatrix as [number], [anchorX * (scale[0] - 1),
+ mat4.translate(tileModelMatrix, tileModelMatrix, [anchorX * (scale[0] - 1),
anchorY * (scale[1] - 1),
elevation]);
if (!vec3.exactEquals(scale, DefaultModelScale)) {
- // @ts-expect-error - TS2345 - Argument of type '[number]' is not assignable to parameter of type 'mat4'.
- mat4.scale(tileModelMatrix as [number], tileModelMatrix as [number], scale);
+ mat4.scale(tileModelMatrix, tileModelMatrix, scale);
}
// keep model and nodemodel matrices separate for rendering door lights
- // @ts-expect-error - TS2345 - Argument of type '[number]' is not assignable to parameter of type 'ReadonlyMat4'.
- const nodeModelMatrix = mat4.multiply([] as any, tileModelMatrix as [number], node.matrix);
- // @ts-expect-error - TS2345 - Argument of type 'number[] | Float32Array | Float64Array' is not assignable to parameter of type 'ReadonlyMat4'.
- const wvpForNode = mat4.multiply([] as any, tr.expandedFarZProjMatrix, nodeModelMatrix);
+ const nodeModelMatrix = mat4.multiply([] as unknown as mat4, tileModelMatrix, node.matrix);
+ const wvpForNode = mat4.multiply([] as unknown as mat4, tr.expandedFarZProjMatrix, nodeModelMatrix);
// Lights come in tilespace so wvp should not include node.matrix when rendering door ligths
- // @ts-expect-error - TS2345 - Argument of type 'number[] | Float32Array | Float64Array' is not assignable to parameter of type 'ReadonlyMat4'.
- const wvpForTile = mat4.multiply([] as any, tr.expandedFarZProjMatrix, tileModelMatrix as [number]);
+ const wvpForTile = mat4.multiply([] as unknown as mat4, tr.expandedFarZProjMatrix, tileModelMatrix);
const anchorPos = vec4.transformMat4([] as any, [anchorX, anchorY, elevation, 1.0], wvpForNode);
const depth = anchorPos[2];
@@ -924,7 +907,6 @@ function drawBatchedModels(painter: Painter, source: SourceCache, layer: ModelSt
wvpForNode,
wvpForTile,
nodeModelMatrix,
- // @ts-expect-error - TS2322 - Type 'number[]' is not assignable to type 'mat4'.
tileModelMatrix
};
@@ -954,7 +936,7 @@ function drawBatchedModels(painter: Painter, source: SourceCache, layer: ModelSt
const nodeInfo = sortedNode.nodeInfo;
const node = nodeInfo.node;
- let lightingMatrix = mat4.multiply([] as any, zScaleMatrix, sortedNode.tileModelMatrix);
+ let lightingMatrix = mat4.multiply([] as unknown as mat4, zScaleMatrix, sortedNode.tileModelMatrix);
mat4.multiply(lightingMatrix, negCameraPosMatrix, lightingMatrix);
const normalMatrix = mat4.invert([] as any, lightingMatrix);
mat4.transpose(normalMatrix, normalMatrix);
@@ -1122,10 +1104,8 @@ function calculateTileShadowPassCulling(bucket: ModelBucket, renderData: RenderD
aabb.min[2] += bucket.terrainElevationMin;
aabb.max[2] += bucket.terrainElevationMax;
- // @ts-expect-error - TS2345 - Argument of type 'Float64Array' is not assignable to parameter of type 'ReadonlyMat4'.
- vec3.transformMat4(aabb.min, aabb.min, renderData.tileMatrix);
- // @ts-expect-error - TS2345 - Argument of type 'Float64Array' is not assignable to parameter of type 'ReadonlyMat4'.
- vec3.transformMat4(aabb.max, aabb.max, renderData.tileMatrix);
+ vec3.transformMat4(aabb.min, aabb.min, renderData.tileMatrix as unknown as mat4);
+ vec3.transformMat4(aabb.max, aabb.max, renderData.tileMatrix as unknown as mat4);
const intersection = aabb.intersects(shadowRenderer.getCurrentCascadeFrustum());
if (painter.currentShadowCascade === 0) {
bucket.isInsideFirstShadowMapFrustum = intersection === 2;
diff --git a/3d-style/render/lights.ts b/3d-style/render/lights.ts
index e3790e37066..39b0cc366e6 100644
--- a/3d-style/render/lights.ts
+++ b/3d-style/render/lights.ts
@@ -52,21 +52,17 @@ function calculateAmbientDirectionalFactor(dir: vec3, normal: vec3, dirColor: ve
}
function calculateGroundRadiance(dir: vec3, dirColor: vec3, ambientColor: vec3): [number, number, number] {
- const groundNormal = [0.0, 0.0, 1.0];
- // @ts-expect-error - TS2345 - Argument of type 'number[]' is not assignable to parameter of type 'vec3'.
+ const groundNormal: vec3 = [0.0, 0.0, 1.0];
const ambientDirectionalFactor = calculateAmbientDirectionalFactor(dir, groundNormal, dirColor);
- const ambientContrib = [0, 0, 0];
- // @ts-expect-error - TS2345 - Argument of type 'number[] | Float32Array' is not assignable to parameter of type 'ReadonlyVec3'.
- vec3.scale(ambientContrib as [number, number, number], ambientColor.slice(0, 3), ambientDirectionalFactor);
- const dirConrib = [0, 0, 0];
- // @ts-expect-error - TS2345 - Argument of type 'number[] | Float32Array' is not assignable to parameter of type 'ReadonlyVec3'.
- vec3.scale(dirConrib as [number, number, number], dirColor.slice(0, 3), dir[2]);
+ const ambientContrib: vec3 = [0, 0, 0];
+ vec3.scale(ambientContrib, ambientColor.slice(0, 3) as vec3, ambientDirectionalFactor);
+ const dirConrib: vec3 = [0, 0, 0];
+ vec3.scale(dirConrib, dirColor.slice(0, 3) as vec3, dir[2]);
- const radiance = [0, 0, 0];
- vec3.add(radiance as [number, number, number], ambientContrib as [number, number, number], dirConrib as [number, number, number]);
+ const radiance: vec3 = [0, 0, 0];
+ vec3.add(radiance, ambientContrib, dirConrib);
- // @ts-expect-error - TS2345 - Argument of type 'number[]' is not assignable to parameter of type '[number, number, number]'.
return linearVec3TosRGB(radiance);
}
diff --git a/3d-style/render/program/ground_shadow_program.ts b/3d-style/render/program/ground_shadow_program.ts
index 4f6ebe6c9b5..69702479f05 100644
--- a/3d-style/render/program/ground_shadow_program.ts
+++ b/3d-style/render/program/ground_shadow_program.ts
@@ -1,5 +1,6 @@
import {UniformMatrix4f, Uniform3f} from '../../../src/render/uniform_binding';
+import type {mat4} from 'gl-matrix';
import type {UniformValues} from '../../../src/render/uniform_binding';
import type Context from '../../../src/gl/context';
@@ -13,8 +14,8 @@ const groundShadowUniforms = (context: Context): GroundShadowUniformsType => ({
'u_ground_shadow_factor': new Uniform3f(context)
});
-const groundShadowUniformValues = (matrix: Float32Array, shadowFactor: [number, number, number]): UniformValues => ({
- 'u_matrix': matrix,
+const groundShadowUniformValues = (matrix: mat4, shadowFactor: [number, number, number]): UniformValues => ({
+ 'u_matrix': matrix as Float32Array,
'u_ground_shadow_factor': shadowFactor
});
diff --git a/3d-style/render/program/model_program.ts b/3d-style/render/program/model_program.ts
index cf67f2fead2..d648f56b7ba 100644
--- a/3d-style/render/program/model_program.ts
+++ b/3d-style/render/program/model_program.ts
@@ -77,13 +77,13 @@ const modelUniforms = (context: Context): ModelUniformsType => ({
});
-const emptyMat4 = new Float32Array(mat4.identity([] as any));
+const emptyMat4 = new Float32Array(mat4.identity([] as unknown as mat4));
const modelUniformValues = (
- matrix: Float32Array,
- lightingMatrix: Float32Array,
- normalMatrix: Float32Array,
- nodeMatrix: Float32Array,
+ matrix: mat4,
+ lightingMatrix: mat4,
+ normalMatrix: mat4,
+ nodeMatrix: mat4,
painter: Painter,
opacity: number,
baseColorFactor: RenderColor,
@@ -118,10 +118,10 @@ const modelUniformValues = (
const colorMixIntensity = layer.paint.get('model-color-mix-intensity').constantOr(0.0);
const uniformValues = {
- 'u_matrix': matrix,
- 'u_lighting_matrix': lightingMatrix,
- 'u_normal_matrix': normalMatrix,
- 'u_node_matrix': nodeMatrix ? nodeMatrix : emptyMat4,
+ 'u_matrix': matrix as Float32Array,
+ 'u_lighting_matrix': lightingMatrix as Float32Array,
+ 'u_normal_matrix': normalMatrix as Float32Array,
+ 'u_node_matrix': (nodeMatrix ? nodeMatrix : emptyMat4) as Float32Array,
'u_lightpos': lightPos,
'u_lightintensity': light.properties.get('intensity'),
'u_lightcolor': [lightColor.r, lightColor.g, lightColor.b] as [number, number, number],
@@ -162,14 +162,14 @@ const modelDepthUniforms = (context: Context): ModelDepthUniformsType => ({
});
const modelDepthUniformValues = (
- matrix: Float32Array,
- instance: Float32Array = emptyMat4,
- nodeMatrix: Float32Array = emptyMat4,
+ matrix: mat4,
+ instance: mat4 = emptyMat4,
+ nodeMatrix: mat4 = emptyMat4,
): UniformValues => {
return {
- 'u_matrix': matrix,
- 'u_instance': instance,
- 'u_node_matrix': nodeMatrix
+ 'u_matrix': matrix as Float32Array,
+ 'u_instance': instance as Float32Array,
+ 'u_node_matrix': nodeMatrix as Float32Array
};
};
diff --git a/3d-style/render/shadow_renderer.ts b/3d-style/render/shadow_renderer.ts
index 0b0d312c504..2f1146bfb2d 100644
--- a/3d-style/render/shadow_renderer.ts
+++ b/3d-style/render/shadow_renderer.ts
@@ -16,6 +16,7 @@ import {groundShadowUniformValues} from './program/ground_shadow_program';
import EXTENT from '../../src/style-spec/data/extent';
import {getCutoffParams} from '../../src/render/cutoff';
+import type {vec4} from 'gl-matrix';
import type Lights from '../style/lights';
import type {OverscaledTileID, UnwrappedTileID} from '../../src/source/tile_id';
import type Transform from '../../src/geo/transform';
@@ -27,7 +28,7 @@ import type {UniformValues} from '../../src/render/uniform_binding';
import type {LightProps as Directional} from '../style/directional_light_properties';
import type {LightProps as Ambient} from '../style/ambient_light_properties';
import type {ShadowUniformsType} from '../render/shadow_uniforms';
-import type {vec4} from 'gl-matrix';
+import type {DynamicDefinesType} from '../../src/render/program/program_uniforms';
type ShadowCascade = {
framebuffer: Framebuffer;
@@ -231,8 +232,7 @@ export class ShadowRenderer {
this._cascades.push({
framebuffer: fbo,
texture: depthTexture,
- // @ts-expect-error - TS2322 - Type '[]' is not assignable to type 'mat4'.
- matrix: [],
+ matrix: [] as unknown as mat4,
far: 0,
boundingSphereRadius: 0,
frustum: new Frustum(),
@@ -258,7 +258,7 @@ export class ShadowRenderer {
const cascadeSplitDist = transform.cameraToCenterDistance * 1.5;
const shadowCutoutDist = cascadeSplitDist * 3.0;
- const cameraInvProj = new Float64Array(16);
+ const cameraInvProj = new Float64Array(16) as unknown as mat4;
for (let cascadeIndex = 0; cascadeIndex < this._cascades.length; ++cascadeIndex) {
const cascade = this._cascades[cascadeIndex];
@@ -278,11 +278,9 @@ export class ShadowRenderer {
const [matrix, radius] = createLightMatrix(transform, this.shadowDirection, near, far, shadowParameters.shadowMapResolution, verticalRange);
cascade.scale = transform.scale;
- // @ts-expect-error - TS2322 - Type 'Float64Array' is not assignable to type 'mat4'.
cascade.matrix = matrix;
cascade.boundingSphereRadius = radius;
- // @ts-expect-error - TS2345 - Argument of type 'Float64Array' is not assignable to parameter of type 'mat4'.
mat4.invert(cameraInvProj, cascade.matrix);
cascade.frustum = Frustum.fromInvProjectionMatrix(cameraInvProj, 1, 0, true);
cascade.far = far;
@@ -379,7 +377,7 @@ export class ShadowRenderer {
return;
}
- const baseDefines = ([] as any);
+ const baseDefines = [] as DynamicDefinesType[];
const cutoffParams = getCutoffParams(painter, painter.longestCutoffRange);
if (cutoffParams.shouldRenderCutoff) {
baseDefines.push('RENDER_CUTOFF');
@@ -419,16 +417,15 @@ export class ShadowRenderer {
return this._shadowLayerCount;
}
- calculateShadowPassMatrixFromTile(unwrappedId: UnwrappedTileID): Float32Array {
+ calculateShadowPassMatrixFromTile(unwrappedId: UnwrappedTileID): mat4 {
const tr = this.painter.transform;
const tileMatrix = tr.calculatePosMatrix(unwrappedId, tr.worldSize);
const lightMatrix = this._cascades[this.painter.currentShadowCascade].matrix;
- // @ts-expect-error - TS2345 - Argument of type 'Float64Array' is not assignable to parameter of type 'mat4'.
mat4.multiply(tileMatrix, lightMatrix, tileMatrix);
return Float32Array.from(tileMatrix);
}
- calculateShadowPassMatrixFromMatrix(matrix: mat4): Float32Array {
+ calculateShadowPassMatrixFromMatrix(matrix: mat4): mat4 {
const lightMatrix = this._cascades[this.painter.currentShadowCascade].matrix;
mat4.multiply(matrix, lightMatrix, matrix);
return Float32Array.from(matrix);
@@ -444,11 +441,10 @@ export class ShadowRenderer {
const gl = context.gl;
const uniforms = this._uniformValues;
- const lightMatrix = new Float64Array(16);
+ const lightMatrix = new Float64Array(16) as unknown as mat4;
const tileMatrix = transform.calculatePosMatrix(unwrappedTileID, transform.worldSize);
for (let i = 0; i < this._cascades.length; i++) {
- // @ts-expect-error - TS2345 - Argument of type 'Float64Array' is not assignable to parameter of type 'mat4'.
mat4.multiply(lightMatrix, this._cascades[i].matrix, tileMatrix);
uniforms[i === 0 ? 'u_light_matrix_0' : 'u_light_matrix_1'] = Float32Array.from(lightMatrix);
context.activeTexture.set(gl.TEXTURE0 + TextureSlots.ShadowMap0 + i);
@@ -486,9 +482,8 @@ export class ShadowRenderer {
const gl = context.gl;
const uniforms = this._uniformValues;
- const lightMatrix = new Float64Array(16);
+ const lightMatrix = new Float64Array(16) as unknown as mat4;
for (let i = 0; i < shadowParameters.cascadeCount; i++) {
- // @ts-expect-error - TS2345 - Argument of type 'Float64Array' is not assignable to parameter of type 'mat4'.
mat4.multiply(lightMatrix, this._cascades[i].matrix, worldMatrix);
uniforms[i === 0 ? 'u_light_matrix_0' : 'u_light_matrix_1'] = Float32Array.from(lightMatrix);
context.activeTexture.set(gl.TEXTURE0 + TextureSlots.ShadowMap0 + i);
@@ -611,31 +606,28 @@ export function calculateGroundShadowFactor(
const dirIntensity = directionalLight.properties.get('intensity');
const dirDirection = directionalLight.properties.get('direction');
- const directionVec = [dirDirection.x, dirDirection.y, dirDirection.z];
+ const directionVec: vec3 = [dirDirection.x, dirDirection.y, dirDirection.z];
const ambientColor = ambientLight.properties.get('color');
const ambientIntensity = ambientLight.properties.get('intensity');
- const groundNormal = [0.0, 0.0, 1.0];
- const dirDirectionalFactor = Math.max(vec3.dot(groundNormal as [number, number, number], directionVec as [number, number, number]), 0.0);
- const ambStrength = [0, 0, 0];
- // @ts-expect-error - TS2339 - Property 'toRenderColor' does not exist on type 'unknown'. | TS2345 - Argument of type 'unknown' is not assignable to parameter of type 'number'.
- vec3.scale(ambStrength as [number, number, number], ambientColor.toRenderColor(style.getLut(directionalLight.scope)).toArray01Linear().slice(0, 3), ambientIntensity);
- const dirStrength = [0, 0, 0];
- // @ts-expect-error - TS2339 - Property 'toRenderColor' does not exist on type 'unknown'. | TS2363 - The right-hand side of an arithmetic operation must be of type 'any', 'number', 'bigint' or an enum type.
- vec3.scale(dirStrength as [number, number, number], dirColor.toRenderColor(style.getLut(ambientLight.scope)).toArray01Linear().slice(0, 3), dirDirectionalFactor * dirIntensity);
+ const groundNormal: vec3 = [0.0, 0.0, 1.0];
+ const dirDirectionalFactor = Math.max(vec3.dot(groundNormal, directionVec), 0.0);
+ const ambStrength: vec3 = [0, 0, 0];
+ vec3.scale(ambStrength, ambientColor.toRenderColor(style.getLut(directionalLight.scope)).toArray01Linear().slice(0, 3) as vec3, ambientIntensity);
+ const dirStrength: vec3 = [0, 0, 0];
+ vec3.scale(dirStrength, dirColor.toRenderColor(style.getLut(ambientLight.scope)).toArray01Linear().slice(0, 3) as vec3, dirDirectionalFactor * dirIntensity);
// Multiplier X to get from lit surface color L to shadowed surface color S
// X = A / (A + D)
// A: Ambient light coming into the surface; taking into account color and intensity
// D: Directional light coming into the surface; taking into account color, intensity and direction
- const shadow = [
+ const shadow: vec3 = [
ambStrength[0] > 0.0 ? ambStrength[0] / (ambStrength[0] + dirStrength[0]) : 0.0,
ambStrength[1] > 0.0 ? ambStrength[1] / (ambStrength[1] + dirStrength[1]) : 0.0,
ambStrength[2] > 0.0 ? ambStrength[2] / (ambStrength[2] + dirStrength[2]) : 0.0
];
// Because blending will happen in sRGB space, convert the shadow factor to sRGB
- // @ts-expect-error - TS2345 - Argument of type 'number[]' is not assignable to parameter of type '[number, number, number]'.
return linearVec3TosRGB(shadow);
}
@@ -646,7 +638,7 @@ function createLightMatrix(
far: number,
resolution: number,
verticalRange: number,
-): [Float64Array, number] {
+): [mat4, number] {
const zoom = transform.zoom;
const scale = transform.scale;
const ws = transform.worldSize;
@@ -672,8 +664,8 @@ function createLightMatrix(
const pixelsPerMeter = transform.projection.pixelsPerMeter(transform.center.lat, ws);
const cameraToWorldMerc = transform._camera.getCameraToWorldMercator();
- const sphereCenter = [0.0, 0.0, -centerDepth * wsInverse];
- vec3.transformMat4(sphereCenter as [number, number, number], sphereCenter as [number, number, number], cameraToWorldMerc);
+ const sphereCenter: vec3 = [0.0, 0.0, -centerDepth * wsInverse];
+ vec3.transformMat4(sphereCenter, sphereCenter, cameraToWorldMerc);
let sphereRadius = radius * wsInverse;
// Transform frustum bounds to mercator space
@@ -699,12 +691,10 @@ function createLightMatrix(
cameraToClip[8] = -transform.centerOffset.x * 2 / transform.width;
cameraToClip[9] = transform.centerOffset.y * 2 / transform.height;
- const cameraProj = new Float64Array(16);
- // @ts-expect-error - TS2345 - Argument of type 'Float64Array' is not assignable to parameter of type 'mat4'.
+ const cameraProj = new Float64Array(16) as unknown as mat4;
mat4.mul(cameraProj, cameraToClip, worldToCamera);
- const cameraInvProj = new Float64Array(16);
- // @ts-expect-error - TS2345 - Argument of type 'Float64Array' is not assignable to parameter of type 'mat4'.
+ const cameraInvProj = new Float64Array(16) as unknown as mat4;
mat4.invert(cameraInvProj, cameraProj);
const frustum = Frustum.fromInvProjectionMatrix(cameraInvProj, ws, zoom, true);
@@ -712,7 +702,7 @@ function createLightMatrix(
// Iterate over the frustum points to get the furthest one from the center
for (const p of frustum.points) {
const fp = frustumPointToMercator(p);
- sphereRadius = Math.max(sphereRadius, vec3.len(vec3.subtract([] as any, sphereCenter as [number, number, number], fp)));
+ sphereRadius = Math.max(sphereRadius, vec3.len(vec3.subtract([] as unknown as vec3, sphereCenter, fp)));
}
}
}
@@ -724,7 +714,6 @@ function createLightMatrix(
const bearing = Math.atan2(-shadowDirection[0], -shadowDirection[1]);
const camera = new FreeCamera();
- // @ts-expect-error - TS2322 - Type 'number[]' is not assignable to type 'vec3'.
camera.position = sphereCenter;
camera.setPitchBearing(pitch, bearing);
@@ -740,8 +729,7 @@ function createLightMatrix(
const lightMatrixFarZ = (radiusPx + verticalRange * pixelsPerMeter) / shadowDirection[2];
const lightViewToClip = camera.getCameraToClipOrthographic(-radiusPx, radiusPx, -radiusPx, radiusPx, lightMatrixNearZ, lightMatrixFarZ);
- const lightWorldToClip = new Float64Array(16);
- // @ts-expect-error - TS2345 - Argument of type 'Float64Array' is not assignable to parameter of type 'mat4'.
+ const lightWorldToClip = new Float64Array(16) as unknown as mat4;
mat4.multiply(lightWorldToClip, lightViewToClip, lightWorldToView);
// Move light camera in discrete steps in order to reduce shimmering when translating
@@ -749,7 +737,6 @@ function createLightMatrix(
const halfResolution = 0.5 * resolution;
const projectedPoint = [0.0, 0.0, 0.0];
- // @ts-expect-error - TS2345 - Argument of type 'Float64Array' is not assignable to parameter of type 'ReadonlyMat4'.
vec3.transformMat4(projectedPoint as [number, number, number], alignedCenter, lightWorldToClip);
vec3.scale(projectedPoint as [number, number, number], projectedPoint as [number, number, number], halfResolution);
@@ -758,12 +745,9 @@ function createLightMatrix(
vec3.sub(offsetVec as [number, number, number], projectedPoint as [number, number, number], roundedPoint as [number, number, number]);
vec3.scale(offsetVec as [number, number, number], offsetVec as [number, number, number], -1.0 / halfResolution);
- const truncMatrix = new Float64Array(16);
- // @ts-expect-error - TS2345 - Argument of type 'Float64Array' is not assignable to parameter of type 'mat4'.
+ const truncMatrix = new Float64Array(16) as unknown as mat4;
mat4.identity(truncMatrix);
- // @ts-expect-error - TS2345 - Argument of type 'Float64Array' is not assignable to parameter of type 'mat4'.
mat4.translate(truncMatrix, truncMatrix, offsetVec as [number, number, number]);
- // @ts-expect-error - TS2345 - Argument of type 'Float64Array' is not assignable to parameter of type 'mat4'.
mat4.multiply(lightWorldToClip, truncMatrix, lightWorldToClip);
return [lightWorldToClip, radiusPx];
diff --git a/3d-style/shaders/_prelude_shadow.fragment.glsl b/3d-style/shaders/_prelude_shadow.fragment.glsl
index 3c62c99c060..08b94c82dff 100644
--- a/3d-style/shaders/_prelude_shadow.fragment.glsl
+++ b/3d-style/shaders/_prelude_shadow.fragment.glsl
@@ -46,7 +46,7 @@ float shadow_occlusion_0(highp vec4 pos, highp float bias) {
// Perform percentage-closer filtering with a 2x2 sample grid.
// Edge tap smoothing is used to weight each sample based on their contribution in the overall PCF kernel
-#ifdef NATIVE
+#ifdef TEXTURE_GATHER
highp vec2 uv = pos.xy;
highp vec4 samples = textureGather(u_shadowmap_0, uv, 0);
lowp vec4 stepSamples = step(samples, vec4(compare0));
diff --git a/3d-style/shaders/fill_extrusion_depth.vertex.glsl b/3d-style/shaders/fill_extrusion_depth.vertex.glsl
index 6aa155c33d2..cea10af55a1 100644
--- a/3d-style/shaders/fill_extrusion_depth.vertex.glsl
+++ b/3d-style/shaders/fill_extrusion_depth.vertex.glsl
@@ -5,6 +5,11 @@ uniform float u_edge_radius;
uniform float u_width_scale;
uniform float u_vertical_scale;
+#ifdef TERRAIN
+uniform int u_height_type;
+uniform int u_base_type;
+#endif
+
in vec4 a_pos_normal_ed;
in vec2 a_centroid_pos;
@@ -47,11 +52,13 @@ void main() {
vec3 pos;
#ifdef TERRAIN
- bool flat_roof = centroid_pos.x != 0.0 && t > 0.0;
+ bool is_flat_height = centroid_pos.x != 0.0 && u_height_type == 1;
+ bool is_flat_base = centroid_pos.x != 0.0 && u_base_type == 1;
float ele = elevation(pos_nx.xy);
- float c_ele = flat_roof ? centroid_pos.y == 0.0 ? elevationFromUint16(centroid_pos.x) : flatElevation(centroid_pos) : ele;
- // If centroid elevation lower than vertex elevation, roof at least 2 meters height above base.
- float h = flat_roof ? max(c_ele + height, ele + base + 2.0) : ele + (t > 0.0 ? height : base);
+ float c_ele = is_flat_height || is_flat_base ? (centroid_pos.y == 0.0 ? elevationFromUint16(centroid_pos.x) : flatElevation(centroid_pos)) : ele;
+ float h_height = is_flat_height ? max(c_ele + height, ele + base + 2.0) : ele + height;
+ float h_base = is_flat_base ? max(c_ele + base, ele + base) : ele + (base == 0.0 ? -5.0 : base);
+ float h = t > 0.0 ? max(h_base, h_height) : h_base;
pos = vec3(pos_nx.xy, h);
#else
pos = vec3(pos_nx.xy, t > 0.0 ? height : base);
diff --git a/3d-style/source/model_loader.ts b/3d-style/source/model_loader.ts
index 13a1841a1f8..dd4c861a345 100644
--- a/3d-style/source/model_loader.ts
+++ b/3d-style/source/model_loader.ts
@@ -16,11 +16,11 @@ import {base64DecToArr} from '../../src/util/util';
import TriangleGridIndex from '../../src/util/triangle_grid_index';
import {HEIGHTMAP_DIM} from '../data/model';
-import type {vec2} from 'gl-matrix';
+import type {vec2, vec4} from 'gl-matrix';
import type {Class} from '../../src/types/class';
import type {Footprint} from '../util/conflation';
import type {TextureImage} from '../../src/render/texture';
-import type {Mesh, Node, Material, ModelTexture, Sampler, AreaLight} from '../data/model';
+import type {Mesh, Node, Material, ModelTexture, Sampler, AreaLight, PbrMetallicRoughness} from '../data/model';
function convertTextures(gltf: any, images: Array): Array {
const textures: ModelTexture[] = [];
@@ -92,7 +92,7 @@ function convertMaterial(materialDesc: any, textures: Array): Mate
}
function computeCentroid(indexArray: ArrayBufferView, vertexArray: ArrayBufferView): vec3 {
- const out = [0.0, 0.0, 0.0];
+ const out: vec3 = [0.0, 0.0, 0.0];
// @ts-expect-error - TS2339 - Property 'length' does not exist on type 'ArrayBufferView'.
const indexSize = indexArray.length;
if (indexSize > 0) {
@@ -106,7 +106,6 @@ function computeCentroid(indexArray: ArrayBufferView, vertexArray: ArrayBufferVi
out[1] /= indexSize;
out[2] /= indexSize;
}
- // @ts-expect-error - TS2322 - Type 'number[]' is not assignable to type 'vec3'.
return out;
}
@@ -252,9 +251,8 @@ function convertMeshes(gltf: any, textures: Array): Array>): Node {
const {matrix, rotation, translation, scale, mesh, extras, children} = nodeDesc;
- // @ts-expect-error - TS2740 - Type '{}' is missing the following properties from type 'Node': id, matrix, meshes, children, and 6 more.
- const node: Node = {};
- node.matrix = matrix || mat4.fromRotationTranslationScale([] as any, rotation || [0, 0, 0, 1], translation || [0, 0, 0], scale || [1, 1, 1]);
+ const node = {} as Node;
+ node.matrix = matrix || mat4.fromRotationTranslationScale([] as unknown as mat4, rotation || [0, 0, 0, 1], translation || [0, 0, 0], scale || [1, 1, 1]);
if (mesh !== undefined) {
node.meshes = meshes[mesh];
const anchor: vec2 = node.anchor = [0, 0];
@@ -383,7 +381,7 @@ function parseNodeFootprintMesh(meshes: Array, matrix: mat4): FootprintMes
let baseVertex = 0;
- const tempVertex = [];
+ const tempVertex = [] as unknown as vec3;
for (const mesh of meshes) {
baseVertex = vertices.length;
@@ -394,8 +392,7 @@ function parseNodeFootprintMesh(meshes: Array, matrix: mat4): FootprintMes
tempVertex[0] = vArray[i * 3 + 0];
tempVertex[1] = vArray[i * 3 + 1];
tempVertex[2] = vArray[i * 3 + 2];
- // @ts-expect-error - TS2345 - Argument of type '[]' is not assignable to parameter of type 'vec3'.
- vec3.transformMat4(tempVertex as [], tempVertex as [], matrix);
+ vec3.transformMat4(tempVertex, tempVertex, matrix);
vertices.push(new Point(tempVertex[0], tempVertex[1]));
}
@@ -433,8 +430,8 @@ function convertFootprints(convertedNodes: Array, sceneNodes: any, modelNo
// connected to correct models via matching ids.
// Find footprint-only nodes from the list.
- const nodeFootprintLookup: Record = {};
- const footprintNodeIndices = new Set();
+ const nodeFootprintLookup: Record = {};
+ const footprintNodeIndices = new Set();
for (let i = 0; i < convertedNodes.length; i++) {
const gltfNode = modelNodes[sceneNodes[i]];
@@ -488,11 +485,9 @@ function convertFootprints(convertedNodes: Array, sceneNodes: any, modelNo
// Remove footprint nodes as they serve no other purpose
if (footprintNodeIndices.size > 0) {
- // @ts-expect-error - TS2362 - The left-hand side of an arithmetic operation must be of type 'any', 'number', 'bigint' or an enum type. | TS2363 - The right-hand side of an arithmetic operation must be of type 'any', 'number', 'bigint' or an enum type.
- const nodesToRemove = Array.from(footprintNodeIndices.values()).sort((a, b) => a - b);
+ const nodesToRemove: number[] = Array.from(footprintNodeIndices.values()).sort((a, b) => a - b);
for (let i = nodesToRemove.length - 1; i >= 0; i--) {
- // @ts-expect-error - TS2769 - No overload matches this call.
convertedNodes.splice(nodesToRemove[i], 1);
}
}
@@ -561,9 +556,7 @@ function parseHeightmap(mesh: Mesh) {
}
function createLightsMesh(lights: Array, zScale: number): Mesh {
-
- // @ts-expect-error - TS2740 - Type '{}' is missing the following properties from type 'Mesh': indexArray, indexBuffer, vertexArray, vertexBuffer, and 14 more.
- const mesh: Mesh = {};
+ const mesh = {} as Mesh;
mesh.indexArray = new TriangleIndexArray();
mesh.indexArray.reserve(4 * lights.length);
mesh.vertexArray = new ModelLayoutArray();
@@ -649,18 +642,11 @@ function createLightsMesh(lights: Array, zScale: number): Mesh {
mesh.indexArray.emplaceBack(1 + currentVertex, 3 + currentVertex, 2 + currentVertex);
currentVertex += 10;
}
- //mesh.featureArray = new FeatureVertexArray();
- //mesh.featureArray.reserve(10 * lights.length);
- //for (let i = 0; i < 10 * lights.length; i++) {
- // mesh.featureArray.emplaceBack(0xffff, 0xffff, 0xffff, 0xffff, 0, 0, 0);
- //}
- // @ts-expect-error - TS2740 - Type '{}' is missing the following properties from type 'Material': normalTexture, occlusionTexture, emissionTexture, pbrMetallicRoughness, and 5 more.
- const material: Material = {};
+ const material = {} as Material;
material.defined = true;
material.emissiveFactor = [0, 0, 0];
- const pbrMetallicRoughness: Record = {};
+ const pbrMetallicRoughness = {} as PbrMetallicRoughness;
pbrMetallicRoughness.baseColorFactor = Color.white;
- // @ts-expect-error - TS2739 - Type 'Record' is missing the following properties from type 'PbrMetallicRoughness': baseColorFactor, metallicFactor, roughnessFactor, baseColorTexture, metallicRoughnessTexture
material.pbrMetallicRoughness = pbrMetallicRoughness;
mesh.material = material;
mesh.aabb = new Aabb([Infinity, Infinity, Infinity], [-Infinity, -Infinity, -Infinity]);
@@ -689,10 +675,9 @@ function decodeLights(base64: string): Array {
const dx = x1 - x0;
const dy = y1 - y0;
const width = Math.hypot(dx, dy);
- const normal = [dy / width, -dx / width, 0];
- const pos = [x0 + dx * 0.5, y0 + dy * 0.5, elevation];
- const points = [x0, y0, x1, y1];
- // @ts-expect-error - TS2322 - Type 'number[]' is not assignable to type 'vec3'. | TS2322 - Type 'number[]' is not assignable to type 'vec3'. | TS2322 - Type 'number[]' is not assignable to type 'vec4'.
+ const normal: vec3 = [dy / width, -dx / width, 0];
+ const pos: vec3 = [x0 + dx * 0.5, y0 + dy * 0.5, elevation];
+ const points: vec4 = [x0, y0, x1, y1];
lights.push({pos, normal, width, height, depth, points});
}
return lights;
diff --git a/3d-style/source/tiled_3d_model_worker_source.ts b/3d-style/source/tiled_3d_model_worker_source.ts
index 19434c7d42b..5faf3017c1a 100644
--- a/3d-style/source/tiled_3d_model_worker_source.ts
+++ b/3d-style/source/tiled_3d_model_worker_source.ts
@@ -6,6 +6,7 @@ import Tiled3dModelBucket from '../data/bucket/tiled_3d_model_bucket';
import {OverscaledTileID} from '../../src/source/tile_id';
import {load3DTile} from '../util/loaders';
import EvaluationParameters from '../../src/style/evaluation_parameters';
+import {makeFQID} from "../../src/util/fqid";
import type {CanonicalTileID} from '../../src/source/tile_id';
import type Actor from '../../src/util/actor';
@@ -78,7 +79,7 @@ class Tiled3dWorkerTile {
for (const sourceLayerId in layerFamilies) {
for (const family of layerFamilies[sourceLayerId]) {
const layer = family[0];
- featureIndex.bucketLayerIDs.push(family.map((l) => l.id));
+ featureIndex.bucketLayerIDs.push(family.map((l) => makeFQID(l.id, l.scope)));
layer.recalculate(parameters, []);
const bucket = new Tiled3dModelBucket(nodes, tileID, hasMapboxMeshFeatures, hasMeshoptCompression, this.brightness, featureIndex);
// Upload to GPU without waiting for evaluation if we are in diffuse path
diff --git a/3d-style/style/style_layer/model_style_layer.ts b/3d-style/style/style_layer/model_style_layer.ts
index 408f3e03c31..b373198f512 100644
--- a/3d-style/style/style_layer/model_style_layer.ts
+++ b/3d-style/style/style_layer/model_style_layer.ts
@@ -11,6 +11,7 @@ import {convertModelMatrixForGlobe, queryGeometryIntersectsProjectedAabb} from '
import Tiled3dModelBucket from '../../data/bucket/tiled_3d_model_bucket';
import EvaluationParameters from '../../../src/style/evaluation_parameters';
+import type {vec3} from 'gl-matrix';
import type {Transitionable, Transitioning, PossiblyEvaluated, PropertyValue, ConfigOptions} from '../../../src/style/properties';
import type Point from '@mapbox/point-geometry';
import type {LayerSpecification} from '../../../src/style-spec/types';
@@ -23,15 +24,15 @@ import type ModelManager from '../../render/model_manager';
import type {Node} from '../../data/model';
import type {VectorTileFeature} from '@mapbox/vector-tile';
import type {FeatureFilter} from '../../../src/style-spec/feature_filter/index';
-import type {GeoJSONFeature} from '../../../src/util/vectortile_to_geojson';
+import type Feature from '../../../src/util/vectortile_to_geojson';
import type {CanonicalTileID} from '../../../src/source/tile_id';
import type {LUT} from "../../../src/util/lut";
class ModelStyleLayer extends StyleLayer {
- _transitionablePaint: Transitionable;
- _transitioningPaint: Transitioning;
- paint: PossiblyEvaluated;
- layout: PossiblyEvaluated;
+ override _transitionablePaint: Transitionable;
+ override _transitioningPaint: Transitioning;
+ override paint: PossiblyEvaluated;
+ override layout: PossiblyEvaluated;
modelManager: ModelManager;
constructor(layer: LayerSpecification, scope: string, lut: LUT | null, options?: ConfigOptions | null) {
@@ -47,36 +48,35 @@ class ModelStyleLayer extends StyleLayer {
return new ModelBucket(parameters);
}
- getProgramIds(): Array {
+ override getProgramIds(): Array {
return ['model'];
}
- is3D(): boolean {
+ override is3D(): boolean {
return true;
}
- hasShadowPass(): boolean {
+ override hasShadowPass(): boolean {
return true;
}
- canCastShadows(): boolean {
+ override canCastShadows(): boolean {
return true;
}
- hasLightBeamPass(): boolean {
+ override hasLightBeamPass(): boolean {
return true;
}
- cutoffRange(): number {
-
+ override cutoffRange(): number {
return this.paint.get('model-cutoff-fade-range');
}
- queryRadius(bucket: Bucket): number {
+ override queryRadius(bucket: Bucket): number {
return (bucket instanceof Tiled3dModelBucket) ? EXTENT - 1 : 0;
}
- queryIntersectsFeature(
+ override queryIntersectsFeature(
queryGeometry: TilespaceQueryGeometry,
feature: VectorTileFeature,
featureState: FeatureState,
@@ -93,7 +93,7 @@ class ModelStyleLayer extends StyleLayer {
for (const modelId in bucket.instancesPerModel) {
const instances = bucket.instancesPerModel[modelId];
const featureId = feature.id !== undefined ? feature.id :
- (feature.properties && feature.properties.hasOwnProperty("id")) ? feature.properties["id"] : undefined;
+ (feature.properties && feature.properties.hasOwnProperty("id")) ? (feature.properties["id"] as string | number) : undefined;
if (instances.idToFeaturesIndex.hasOwnProperty(featureId)) {
const modelFeature = instances.features[instances.idToFeaturesIndex[featureId]];
const model = modelManager.getModel(modelId, this.scope);
@@ -108,7 +108,7 @@ class ModelStyleLayer extends StyleLayer {
const offset = instanceOffset * 16;
const va = instances.instancedDataArray.float32;
- const translation = [va[offset + 4], va[offset + 5], va[offset + 6]];
+ const translation: vec3 = [va[offset + 4], va[offset + 5], va[offset + 6]];
const pointX = va[offset];
const pointY = va[offset + 1] | 0; // point.y stored in integer part
@@ -120,7 +120,6 @@ class ModelStyleLayer extends StyleLayer {
position,
modelFeature.rotation,
modelFeature.scale,
- // @ts-expect-error - TS2345 - Argument of type 'any[]' is not assignable to parameter of type 'vec3'.
translation,
false,
false,
@@ -128,7 +127,6 @@ class ModelStyleLayer extends StyleLayer {
if (transform.projection.name === 'globe') {
matrix = convertModelMatrixForGlobe(matrix, transform);
}
- // @ts-expect-error - TS2345 - Argument of type 'number[] | Float32Array | Float64Array' is not assignable to parameter of type 'ReadonlyMat4'.
const worldViewProjection = mat4.multiply([] as any, transform.projMatrix, matrix);
// Collision checks are performed in screen space. Corners are in ndc space.
const screenQuery = queryGeometry.queryGeometry;
@@ -147,7 +145,7 @@ class ModelStyleLayer extends StyleLayer {
return false;
}
- _handleOverridablePaintPropertyUpdate(name: string, oldValue: PropertyValue, newValue: PropertyValue): boolean {
+ override _handleOverridablePaintPropertyUpdate(name: string, oldValue: PropertyValue, newValue: PropertyValue): boolean {
if (!this.layout || oldValue.isDataDriven() || newValue.isDataDriven()) {
return false;
}
@@ -169,13 +167,13 @@ class ModelStyleLayer extends StyleLayer {
this._isPropertyZoomDependent('model-translation');
}
- queryIntersectsMatchingFeature(
+ override queryIntersectsMatchingFeature(
queryGeometry: TilespaceQueryGeometry,
featureIndex: number,
filter: FeatureFilter,
transform: Transform,
): {
- queryFeature: GeoJSONFeature | null | undefined;
+ queryFeature: Feature | null | undefined;
intersectionZ: number;
} {
@@ -206,14 +204,11 @@ class ModelStyleLayer extends StyleLayer {
const anchorX = node.anchor ? node.anchor[0] : 0;
const anchorY = node.anchor ? node.anchor[1] : 0;
- // @ts-expect-error - TS2345 - Argument of type 'Float64Array' is not assignable to parameter of type 'mat4'.
mat4.translate(modelMatrix, modelMatrix, [anchorX * (scale[0] - 1),
anchorY * (scale[1] - 1),
elevation]);
- // @ts-expect-error - TS2345 - Argument of type 'Float64Array' is not assignable to parameter of type 'mat4'.
mat4.scale(modelMatrix, modelMatrix, scale);
- // @ts-expect-error - TS2345 - Argument of type 'Float64Array' is not assignable to parameter of type 'mat4'.
mat4.multiply(modelMatrix, modelMatrix, node.matrix);
// Collision checks are performed in screen space. Corners are in ndc space.
@@ -221,9 +216,7 @@ class ModelStyleLayer extends StyleLayer {
const projectedQueryGeometry = screenQuery.isPointQuery() ? screenQuery.screenBounds : screenQuery.screenGeometry;
const checkNode = function(n: Node) {
- // @ts-expect-error - TS2345 - Argument of type 'Float64Array' is not assignable to parameter of type 'ReadonlyMat4'.
const nodeModelMatrix = mat4.multiply([] as any, modelMatrix, n.matrix);
- // @ts-expect-error - TS2345 - Argument of type 'number[] | Float32Array | Float64Array' is not assignable to parameter of type 'ReadonlyMat4'.
const worldViewProjection = mat4.multiply(nodeModelMatrix, transform.expandedFarZProjMatrix, nodeModelMatrix);
for (let i = 0; i < n.meshes.length; ++i) {
const mesh = n.meshes[i];
diff --git a/3d-style/util/model_util.ts b/3d-style/util/model_util.ts
index 8f00f0bb396..a4bc137a1d8 100644
--- a/3d-style/util/model_util.ts
+++ b/3d-style/util/model_util.ts
@@ -83,39 +83,37 @@ export function rotationFor3Points(
h2: number,
meterToMercator: number,
): quat {
- const p0p1 = [p1[0] - p0[0], p1[1] - p0[1], 0.0];
- const p0p2 = [p2[0] - p0[0], p2[1] - p0[1], 0.0];
+ const p0p1: vec3 = [p1[0] - p0[0], p1[1] - p0[1], 0.0];
+ const p0p2: vec3 = [p2[0] - p0[0], p2[1] - p0[1], 0.0];
// If model scale is zero, all bounding box points are identical and no rotation can be calculated
- if (vec3.length(p0p1 as [number, number, number]) < 1e-12 || vec3.length(p0p2 as [number, number, number]) < 1e-12) {
+ if (vec3.length(p0p1) < 1e-12 || vec3.length(p0p2) < 1e-12) {
return quat.identity(out);
}
- const from = vec3.cross([] as any, p0p1 as [number, number, number], p0p2 as [number, number, number]);
+ const from = vec3.cross([] as any, p0p1, p0p2);
vec3.normalize(from, from);
- vec3.subtract(p0p2 as [number, number, number], p2, p0);
+ vec3.subtract(p0p2, p2, p0);
p0p1[2] = (h1 - h0) * meterToMercator;
p0p2[2] = (h2 - h0) * meterToMercator;
const to = p0p1;
- // @ts-expect-error - TS2345 - Argument of type 'number[]' is not assignable to parameter of type 'vec3'.
- vec3.cross(to, p0p1 as [number, number, number], p0p2 as [number, number, number]);
- // @ts-expect-error - TS2345 - Argument of type 'number[]' is not assignable to parameter of type 'vec3'.
+ vec3.cross(to, p0p1, p0p2);
vec3.normalize(to, to);
return quat.rotationTo(out, from, to);
}
export function coordinateFrameAtEcef(ecef: vec3): mat4 {
- const zAxis = [ecef[0], ecef[1], ecef[2]];
- let yAxis = [0.0, 1.0, 0.0];
- const xAxis = vec3.cross([] as any, yAxis as [number, number, number], zAxis as [number, number, number]);
- vec3.cross(yAxis as [number, number, number], zAxis as [number, number, number], xAxis);
- if (vec3.squaredLength(yAxis as [number, number, number]) === 0.0) {
+ const zAxis: vec3 = [ecef[0], ecef[1], ecef[2]];
+ let yAxis: vec3 = [0.0, 1.0, 0.0];
+ const xAxis: vec3 = vec3.cross([] as unknown as vec3, yAxis, zAxis);
+ vec3.cross(yAxis, zAxis, xAxis);
+ if (vec3.squaredLength(yAxis) === 0.0) {
// Coordinate space is ambiguous if the model is placed directly at north or south pole
yAxis = [0.0, 1.0, 0.0];
- vec3.cross(xAxis, zAxis as [number, number, number], yAxis as [number, number, number]);
+ vec3.cross(xAxis, zAxis, yAxis);
assert(vec3.squaredLength(xAxis) > 0.0);
}
vec3.normalize(xAxis, xAxis);
- vec3.normalize(yAxis as [number, number, number], yAxis as [number, number, number]);
- vec3.normalize(zAxis as [number, number, number], zAxis as [number, number, number]);
+ vec3.normalize(yAxis, yAxis);
+ vec3.normalize(zAxis, zAxis);
return [xAxis[0], xAxis[1], xAxis[2], 0.0,
yAxis[0], yAxis[1], yAxis[2], 0.0,
zAxis[0], zAxis[1], zAxis[2], 0.0,
@@ -157,7 +155,6 @@ export function convertModelMatrix(matrix: mat4, transform: Transform, scaleWith
const ecefFrame = coordinateFrameAtEcef(ecefCoord);
mat4.scale(mercToEcef, mercToEcef, [scale, scale, scale * sourcePixelsPerMeter]);
mat4.translate(mercToEcef, mercToEcef, [-position[0], -position[1], -position[2]]);
- // @ts-expect-error - TS2345 - Argument of type 'Float64Array' is not assignable to parameter of type 'ReadonlyMat4'.
const result = mat4.multiply([] as any, transform.globeMatrix, ecefFrame);
mat4.multiply(result, result, mercToEcef);
mat4.multiply(result, result, matrix);
@@ -181,7 +178,6 @@ export function mercatorToGlobeMatrix(matrix: mat4, transform: Transform): mat4
mat4.translate(m, m, [transform.point.x - 0.5 * worldSize, transform.point.y - 0.5 * worldSize, 0.0]);
mat4.multiply(m, m, matrix);
- // @ts-expect-error - TS2345 - Argument of type 'Float64Array' is not assignable to parameter of type 'ReadonlyMat4'.
return mat4.multiply(m, transform.globeMatrix, m);
}
diff --git a/CHANGELOG.md b/CHANGELOG.md
index 42608072e87..c6a8d100bb0 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -1,3 +1,19 @@
+## 3.8.0-beta.1
+
+### Features and improvements β¨
+
+- Minor optimizations to reduce load time.
+
+### Bug fixes π
+- Fix raster array rendering on some Android devices.
+- Fix an issue where fill-extrusion buildings would disappear when zooming out.
+- Fix line joins for thick semi-transparent or blurred lines.
+- Improve appearance of line corners with densely placed vertices.
+- Fix anti-alising aftifacts on blurred lines.
+- Fix call stack overflow caused by repeated `addImport` calls.
+- Fix failures when handling non-renderable characters.
+- Fix the Osage script rendering.
+
## v3.7.0
### Features and improvements β¨
diff --git a/build/generate-struct-arrays.ts b/build/generate-struct-arrays.ts
index 0ff665916f4..25209f51fa0 100644
--- a/build/generate-struct-arrays.ts
+++ b/build/generate-struct-arrays.ts
@@ -209,6 +209,12 @@ createStructArrayType('atmosphere_vertex', atmosphereLayout);
import {starsLayout} from '../src/render/stars_attributes';
createStructArrayType('stars_vertex', starsLayout);
+import {snowLayout} from '../src/precipitation/snow_attributes.js';
+createStructArrayType('snow_vertex', snowLayout);
+
+import {rainLayout} from '../src/precipitation/rain_attributes.js';
+createStructArrayType('rain_vertex', rainLayout);
+
// feature index array
createStructArrayType('feature_index', createLayout([
// the index of the feature in the original vectortile
diff --git a/debug/access_token.js b/debug/access_token.js
index 13812ac2f76..14ad443abf9 100644
--- a/debug/access_token.js
+++ b/debug/access_token.js
@@ -4,13 +4,14 @@ mapboxgl.accessToken = getAccessToken();
function getAccessToken() {
const accessToken = [
- typeof process !== 'undefined' && process.env.MapboxAccessToken,
- typeof process !== 'undefined' && process.env.MAPBOX_ACCESS_TOKEN,
+ process.env.MapboxAccessToken,
+ process.env.MAPBOX_ACCESS_TOKEN,
getURLParameter('access_token'),
localStorage.getItem('accessToken'),
// this token is a fallback for CI and testing. it is domain restricted to localhost
'pk.eyJ1IjoibWFwYm94LWdsLWpzIiwiYSI6ImNram9ybGI1ajExYjQyeGxlemppb2pwYjIifQ.LGy5UGNIsXUZdYMvfYRiAQ'
].find(Boolean);
+
try {
localStorage.setItem('accessToken', accessToken);
} catch (_) {
@@ -20,7 +21,6 @@ function getAccessToken() {
}
function getURLParameter(name) {
- var regexp = new RegExp('[?&]' + name + '=([^]*)', 'i');
- var output = regexp.exec(window.location.href);
- return output && output[1];
+ const url = new URL(window.location.href);
+ return url.searchParams.get(name);
}
diff --git a/debug/extrusion-debug.html b/debug/extrusion-debug.html
new file mode 100644
index 00000000000..58dc0c93b2d
--- /dev/null
+++ b/debug/extrusion-debug.html
@@ -0,0 +1,104 @@
+
+
+
+ Mapbox GL JS debug page
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/debug/featuresets.html b/debug/featuresets.html
new file mode 100644
index 00000000000..c470c49a61f
--- /dev/null
+++ b/debug/featuresets.html
@@ -0,0 +1,117 @@
+
+
+
+ Mapbox GL JS debug page
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/debug/precipitation.html b/debug/precipitation.html
new file mode 100644
index 00000000000..2c84f61a14a
--- /dev/null
+++ b/debug/precipitation.html
@@ -0,0 +1,99 @@
+
+
+
+ Mapbox GL JS debug page
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/debug/render-test.html b/debug/render-test.html
index f2dfbe81d99..af27d6f9d6b 100644
--- a/debug/render-test.html
+++ b/debug/render-test.html
@@ -39,6 +39,7 @@
fadeDuration = 0,
localIdeographFontFamily = false,
operations,
+ scaleFactor = 1,
...options
} = style.metadata.test;
@@ -56,7 +57,8 @@
localIdeographFontFamily,
interactive: false,
attributionControl: false,
- performanceMetricsCollection: false
+ performanceMetricsCollection: false,
+ scaleFactor
});
map.removeControl(map._logoControl);
diff --git a/debug/usvg.html b/debug/usvg.html
new file mode 100644
index 00000000000..8ca06d4e491
--- /dev/null
+++ b/debug/usvg.html
@@ -0,0 +1,198 @@
+
+
+
+
+ Mapbox GL JS debug page
+
+
+
+
+
+
+
+
+
+
+
Expected
+
+
+
+
+
+
+ Source
+
+
+
+ uSVG
+
+
+
+
+
+
+
+
diff --git a/package-lock.json b/package-lock.json
index 4a73a55e506..a5d92bc3065 100644
--- a/package-lock.json
+++ b/package-lock.json
@@ -1,12 +1,12 @@
{
"name": "mapbox-gl",
- "version": "3.7.0",
+ "version": "3.8.0-beta.1",
"lockfileVersion": 3,
"requires": true,
"packages": {
"": {
"name": "mapbox-gl",
- "version": "3.7.0",
+ "version": "3.8.0-beta.1",
"license": "SEE LICENSE IN LICENSE.txt",
"workspaces": [
"src/style-spec",
@@ -45,22 +45,23 @@
"devDependencies": {
"@mapbox/mvt-fixtures": "^3.10.0",
"@octokit/rest": "^21.0.2",
- "@rollup/plugin-commonjs": "^28.0.0",
+ "@rollup/plugin-commonjs": "^28.0.1",
"@rollup/plugin-json": "^6.1.0",
"@rollup/plugin-node-resolve": "^15.3.0",
"@rollup/plugin-replace": "^6.0.1",
"@rollup/plugin-strip": "^3.0.4",
"@rollup/plugin-terser": "^0.4.4",
+ "@rollup/plugin-virtual": "^3.0.2",
"@tweakpane/core": "^2.0.4",
"@types/jest": "^29.5.13",
- "@types/node": "^22.6.1",
+ "@types/node": "^22.7.7",
"@types/offscreencanvas": "^2019.7.3",
- "@typescript-eslint/eslint-plugin": "^8.7.0",
- "@typescript-eslint/parser": "^8.7.0",
- "@vitest/browser": "^2.1.1",
+ "@typescript-eslint/eslint-plugin": "^8.11.0",
+ "@typescript-eslint/parser": "^8.11.0",
+ "@vitest/browser": "^2.1.3",
"@vitest/ui": "^2.0.3",
"address": "^2.0.3",
- "browserify": "^17.0.0",
+ "browserify": "^17.0.1",
"chalk": "^5.0.1",
"chokidar": "^4.0.1",
"cross-env": "^7.0.3",
@@ -75,13 +76,13 @@
"eslint-config-mourner": "^3.0.0",
"eslint-import-resolver-typescript": "^3.6.3",
"eslint-plugin-html": "^8.1.2",
- "eslint-plugin-import": "^2.30.0",
- "eslint-plugin-jsdoc": "^50.2.4",
+ "eslint-plugin-import": "^2.31.0",
+ "eslint-plugin-jsdoc": "^50.4.3",
"glob": "^11.0.0",
"is-builtin-module": "^4.0.0",
"jest-extended": "^4.0.2",
"json-stringify-pretty-compact": "^4.0.0",
- "lodash.template": "^4.5.0",
+ "lodash": "^4.17.21",
"mapbox-gl-styles": "^2.0.2",
"minimist": "^1.2.6",
"mock-geolocation": "^1.0.11",
@@ -90,7 +91,7 @@
"npm-font-open-sans": "^1.1.0",
"npm-run-all": "^4.1.5",
"pixelmatch": "^6.0.0",
- "playwright": "^1.47.2",
+ "playwright": "^1.48.1",
"postcss": "^8.4.47",
"postcss-cli": "^11.0.0",
"postcss-inline-svg": "^6.0.0",
@@ -102,15 +103,15 @@
"serve-static": "^1.16.2",
"shuffle-seed": "^1.1.6",
"st": "^3.0.0",
- "stylelint": "^16.9.0",
+ "stylelint": "^16.10.0",
"stylelint-config-standard": "^36.0.1",
"tape": "^5.9.0",
"tape-filter": "^1.0.4",
"testem": "^3.15.2",
"tsx": "^4.19.1",
"tweakpane": "^4.0.4",
- "typescript": "^5.6.2",
- "typescript-eslint": "^8.7.0",
+ "typescript": "^5.6.3",
+ "typescript-eslint": "^8.11.0",
"utility-types": "^3.11.0",
"vite-plugin-arraybuffer": "^0.0.8",
"vitest": "^2.0.3"
@@ -354,9 +355,9 @@
}
},
"node_modules/@es-joy/jsdoccomment": {
- "version": "0.48.0",
- "resolved": "https://registry.npmjs.org/@es-joy/jsdoccomment/-/jsdoccomment-0.48.0.tgz",
- "integrity": "sha512-G6QUWIcC+KvSwXNsJyDTHvqUdNoAVJPPgkc3+Uk4WBKqZvoXhlvazOgm9aL0HwihJLQf0l+tOE2UFzXBqCqgDw==",
+ "version": "0.49.0",
+ "resolved": "https://registry.npmjs.org/@es-joy/jsdoccomment/-/jsdoccomment-0.49.0.tgz",
+ "integrity": "sha512-xjZTSFgECpb9Ohuk5yMX5RhUEbfeQcuOp8IF60e+wyzWEF0M5xeSgqsfLtvPEX8BIyOX9saZqzuGPmZ8oWc+5Q==",
"dev": true,
"dependencies": {
"comment-parser": "1.4.1",
@@ -1930,18 +1931,18 @@
"dev": true
},
"node_modules/@rollup/plugin-commonjs": {
- "version": "28.0.0",
- "resolved": "https://registry.npmjs.org/@rollup/plugin-commonjs/-/plugin-commonjs-28.0.0.tgz",
- "integrity": "sha512-BJcu+a+Mpq476DMXG+hevgPSl56bkUoi88dKT8t3RyUp8kGuOh+2bU8Gs7zXDlu+fyZggnJ+iOBGrb/O1SorYg==",
+ "version": "28.0.1",
+ "resolved": "https://registry.npmjs.org/@rollup/plugin-commonjs/-/plugin-commonjs-28.0.1.tgz",
+ "integrity": "sha512-+tNWdlWKbpB3WgBN7ijjYkq9X5uhjmcvyjEght4NmH5fAU++zfQzAJ6wumLS+dNcvwEZhKx2Z+skY8m7v0wGSA==",
"dev": true,
"dependencies": {
"@rollup/pluginutils": "^5.0.1",
"commondir": "^1.0.1",
"estree-walker": "^2.0.2",
- "fdir": "^6.1.1",
+ "fdir": "^6.2.0",
"is-reference": "1.2.1",
"magic-string": "^0.30.3",
- "picomatch": "^2.3.1"
+ "picomatch": "^4.0.2"
},
"engines": {
"node": ">=16.0.0 || 14 >= 14.17"
@@ -1955,18 +1956,6 @@
}
}
},
- "node_modules/@rollup/plugin-commonjs/node_modules/picomatch": {
- "version": "2.3.1",
- "resolved": "https://registry.npmjs.org/picomatch/-/picomatch-2.3.1.tgz",
- "integrity": "sha512-JU3teHTNjmE2VCGFzuY8EXzCDVwEqB2a8fsIvwaStHhAWJEeVd1o1QD80CU6+ZdEXXSLbSsuLwJjkCBWqRQUVA==",
- "dev": true,
- "engines": {
- "node": ">=8.6"
- },
- "funding": {
- "url": "https://github.com/sponsors/jonschlinkert"
- }
- },
"node_modules/@rollup/plugin-json": {
"version": "6.1.0",
"resolved": "https://registry.npmjs.org/@rollup/plugin-json/-/plugin-json-6.1.0.tgz",
@@ -2079,6 +2068,24 @@
}
}
},
+ "node_modules/@rollup/plugin-virtual": {
+ "version": "3.0.2",
+ "resolved": "https://registry.npmjs.org/@rollup/plugin-virtual/-/plugin-virtual-3.0.2.tgz",
+ "integrity": "sha512-10monEYsBp3scM4/ND4LNH5Rxvh3e/cVeL3jWTgZ2SrQ+BmUoQcopVQvnaMcOnykb1VkxUFuDAN+0FnpTFRy2A==",
+ "dev": true,
+ "license": "MIT",
+ "engines": {
+ "node": ">=14.0.0"
+ },
+ "peerDependencies": {
+ "rollup": "^1.20.0||^2.0.0||^3.0.0||^4.0.0"
+ },
+ "peerDependenciesMeta": {
+ "rollup": {
+ "optional": true
+ }
+ }
+ },
"node_modules/@rollup/pluginutils": {
"version": "5.1.0",
"resolved": "https://registry.npmjs.org/@rollup/pluginutils/-/pluginutils-5.1.0.tgz",
@@ -2601,9 +2608,9 @@
}
},
"node_modules/@types/node": {
- "version": "22.6.1",
- "resolved": "https://registry.npmjs.org/@types/node/-/node-22.6.1.tgz",
- "integrity": "sha512-V48tCfcKb/e6cVUigLAaJDAILdMP0fUW6BidkPK4GpGjXcfbnoHasCZDwz3N3yVt5we2RHm4XTQCpv0KJz9zqw==",
+ "version": "22.7.7",
+ "resolved": "https://registry.npmjs.org/@types/node/-/node-22.7.7.tgz",
+ "integrity": "sha512-SRxCrrg9CL/y54aiMCG3edPKdprgMVGDXjA3gB8UmmBW5TcXzRUYAh8EWzTnSJFAd1rgImPELza+A3bJ+qxz8Q==",
"dev": true,
"dependencies": {
"undici-types": "~6.19.2"
@@ -2683,16 +2690,16 @@
"license": "MIT"
},
"node_modules/@typescript-eslint/eslint-plugin": {
- "version": "8.7.0",
- "resolved": "https://registry.npmjs.org/@typescript-eslint/eslint-plugin/-/eslint-plugin-8.7.0.tgz",
- "integrity": "sha512-RIHOoznhA3CCfSTFiB6kBGLQtB/sox+pJ6jeFu6FxJvqL8qRxq/FfGO/UhsGgQM9oGdXkV4xUgli+dt26biB6A==",
+ "version": "8.11.0",
+ "resolved": "https://registry.npmjs.org/@typescript-eslint/eslint-plugin/-/eslint-plugin-8.11.0.tgz",
+ "integrity": "sha512-KhGn2LjW1PJT2A/GfDpiyOfS4a8xHQv2myUagTM5+zsormOmBlYsnQ6pobJ8XxJmh6hnHwa2Mbe3fPrDJoDhbA==",
"dev": true,
"dependencies": {
"@eslint-community/regexpp": "^4.10.0",
- "@typescript-eslint/scope-manager": "8.7.0",
- "@typescript-eslint/type-utils": "8.7.0",
- "@typescript-eslint/utils": "8.7.0",
- "@typescript-eslint/visitor-keys": "8.7.0",
+ "@typescript-eslint/scope-manager": "8.11.0",
+ "@typescript-eslint/type-utils": "8.11.0",
+ "@typescript-eslint/utils": "8.11.0",
+ "@typescript-eslint/visitor-keys": "8.11.0",
"graphemer": "^1.4.0",
"ignore": "^5.3.1",
"natural-compare": "^1.4.0",
@@ -2716,15 +2723,15 @@
}
},
"node_modules/@typescript-eslint/parser": {
- "version": "8.7.0",
- "resolved": "https://registry.npmjs.org/@typescript-eslint/parser/-/parser-8.7.0.tgz",
- "integrity": "sha512-lN0btVpj2unxHlNYLI//BQ7nzbMJYBVQX5+pbNXvGYazdlgYonMn4AhhHifQ+J4fGRYA/m1DjaQjx+fDetqBOQ==",
+ "version": "8.11.0",
+ "resolved": "https://registry.npmjs.org/@typescript-eslint/parser/-/parser-8.11.0.tgz",
+ "integrity": "sha512-lmt73NeHdy1Q/2ul295Qy3uninSqi6wQI18XwSpm8w0ZbQXUpjCAWP1Vlv/obudoBiIjJVjlztjQ+d/Md98Yxg==",
"dev": true,
"dependencies": {
- "@typescript-eslint/scope-manager": "8.7.0",
- "@typescript-eslint/types": "8.7.0",
- "@typescript-eslint/typescript-estree": "8.7.0",
- "@typescript-eslint/visitor-keys": "8.7.0",
+ "@typescript-eslint/scope-manager": "8.11.0",
+ "@typescript-eslint/types": "8.11.0",
+ "@typescript-eslint/typescript-estree": "8.11.0",
+ "@typescript-eslint/visitor-keys": "8.11.0",
"debug": "^4.3.4"
},
"engines": {
@@ -2744,13 +2751,13 @@
}
},
"node_modules/@typescript-eslint/scope-manager": {
- "version": "8.7.0",
- "resolved": "https://registry.npmjs.org/@typescript-eslint/scope-manager/-/scope-manager-8.7.0.tgz",
- "integrity": "sha512-87rC0k3ZlDOuz82zzXRtQ7Akv3GKhHs0ti4YcbAJtaomllXoSO8hi7Ix3ccEvCd824dy9aIX+j3d2UMAfCtVpg==",
+ "version": "8.11.0",
+ "resolved": "https://registry.npmjs.org/@typescript-eslint/scope-manager/-/scope-manager-8.11.0.tgz",
+ "integrity": "sha512-Uholz7tWhXmA4r6epo+vaeV7yjdKy5QFCERMjs1kMVsLRKIrSdM6o21W2He9ftp5PP6aWOVpD5zvrvuHZC0bMQ==",
"dev": true,
"dependencies": {
- "@typescript-eslint/types": "8.7.0",
- "@typescript-eslint/visitor-keys": "8.7.0"
+ "@typescript-eslint/types": "8.11.0",
+ "@typescript-eslint/visitor-keys": "8.11.0"
},
"engines": {
"node": "^18.18.0 || ^20.9.0 || >=21.1.0"
@@ -2761,13 +2768,13 @@
}
},
"node_modules/@typescript-eslint/type-utils": {
- "version": "8.7.0",
- "resolved": "https://registry.npmjs.org/@typescript-eslint/type-utils/-/type-utils-8.7.0.tgz",
- "integrity": "sha512-tl0N0Mj3hMSkEYhLkjREp54OSb/FI6qyCzfiiclvJvOqre6hsZTGSnHtmFLDU8TIM62G7ygEa1bI08lcuRwEnQ==",
+ "version": "8.11.0",
+ "resolved": "https://registry.npmjs.org/@typescript-eslint/type-utils/-/type-utils-8.11.0.tgz",
+ "integrity": "sha512-ItiMfJS6pQU0NIKAaybBKkuVzo6IdnAhPFZA/2Mba/uBjuPQPet/8+zh5GtLHwmuFRShZx+8lhIs7/QeDHflOg==",
"dev": true,
"dependencies": {
- "@typescript-eslint/typescript-estree": "8.7.0",
- "@typescript-eslint/utils": "8.7.0",
+ "@typescript-eslint/typescript-estree": "8.11.0",
+ "@typescript-eslint/utils": "8.11.0",
"debug": "^4.3.4",
"ts-api-utils": "^1.3.0"
},
@@ -2785,9 +2792,9 @@
}
},
"node_modules/@typescript-eslint/types": {
- "version": "8.7.0",
- "resolved": "https://registry.npmjs.org/@typescript-eslint/types/-/types-8.7.0.tgz",
- "integrity": "sha512-LLt4BLHFwSfASHSF2K29SZ+ZCsbQOM+LuarPjRUuHm+Qd09hSe3GCeaQbcCr+Mik+0QFRmep/FyZBO6fJ64U3w==",
+ "version": "8.11.0",
+ "resolved": "https://registry.npmjs.org/@typescript-eslint/types/-/types-8.11.0.tgz",
+ "integrity": "sha512-tn6sNMHf6EBAYMvmPUaKaVeYvhUsrE6x+bXQTxjQRp360h1giATU0WvgeEys1spbvb5R+VpNOZ+XJmjD8wOUHw==",
"dev": true,
"engines": {
"node": "^18.18.0 || ^20.9.0 || >=21.1.0"
@@ -2798,13 +2805,13 @@
}
},
"node_modules/@typescript-eslint/typescript-estree": {
- "version": "8.7.0",
- "resolved": "https://registry.npmjs.org/@typescript-eslint/typescript-estree/-/typescript-estree-8.7.0.tgz",
- "integrity": "sha512-MC8nmcGHsmfAKxwnluTQpNqceniT8SteVwd2voYlmiSWGOtjvGXdPl17dYu2797GVscK30Z04WRM28CrKS9WOg==",
+ "version": "8.11.0",
+ "resolved": "https://registry.npmjs.org/@typescript-eslint/typescript-estree/-/typescript-estree-8.11.0.tgz",
+ "integrity": "sha512-yHC3s1z1RCHoCz5t06gf7jH24rr3vns08XXhfEqzYpd6Hll3z/3g23JRi0jM8A47UFKNc3u/y5KIMx8Ynbjohg==",
"dev": true,
"dependencies": {
- "@typescript-eslint/types": "8.7.0",
- "@typescript-eslint/visitor-keys": "8.7.0",
+ "@typescript-eslint/types": "8.11.0",
+ "@typescript-eslint/visitor-keys": "8.11.0",
"debug": "^4.3.4",
"fast-glob": "^3.3.2",
"is-glob": "^4.0.3",
@@ -2826,15 +2833,15 @@
}
},
"node_modules/@typescript-eslint/utils": {
- "version": "8.7.0",
- "resolved": "https://registry.npmjs.org/@typescript-eslint/utils/-/utils-8.7.0.tgz",
- "integrity": "sha512-ZbdUdwsl2X/s3CiyAu3gOlfQzpbuG3nTWKPoIvAu1pu5r8viiJvv2NPN2AqArL35NCYtw/lrPPfM4gxrMLNLPw==",
+ "version": "8.11.0",
+ "resolved": "https://registry.npmjs.org/@typescript-eslint/utils/-/utils-8.11.0.tgz",
+ "integrity": "sha512-CYiX6WZcbXNJV7UNB4PLDIBtSdRmRI/nb0FMyqHPTQD1rMjA0foPLaPUV39C/MxkTd/QKSeX+Gb34PPsDVC35g==",
"dev": true,
"dependencies": {
"@eslint-community/eslint-utils": "^4.4.0",
- "@typescript-eslint/scope-manager": "8.7.0",
- "@typescript-eslint/types": "8.7.0",
- "@typescript-eslint/typescript-estree": "8.7.0"
+ "@typescript-eslint/scope-manager": "8.11.0",
+ "@typescript-eslint/types": "8.11.0",
+ "@typescript-eslint/typescript-estree": "8.11.0"
},
"engines": {
"node": "^18.18.0 || ^20.9.0 || >=21.1.0"
@@ -2848,12 +2855,12 @@
}
},
"node_modules/@typescript-eslint/visitor-keys": {
- "version": "8.7.0",
- "resolved": "https://registry.npmjs.org/@typescript-eslint/visitor-keys/-/visitor-keys-8.7.0.tgz",
- "integrity": "sha512-b1tx0orFCCh/THWPQa2ZwWzvOeyzzp36vkJYOpVg0u8UVOIsfVrnuC9FqAw9gRKn+rG2VmWQ/zDJZzkxUnj/XQ==",
+ "version": "8.11.0",
+ "resolved": "https://registry.npmjs.org/@typescript-eslint/visitor-keys/-/visitor-keys-8.11.0.tgz",
+ "integrity": "sha512-EaewX6lxSjRJnc+99+dqzTeoDZUfyrA52d2/HRrkI830kgovWsmIiTfmr0NZorzqic7ga+1bS60lRBUgR3n/Bw==",
"dev": true,
"dependencies": {
- "@typescript-eslint/types": "8.7.0",
+ "@typescript-eslint/types": "8.11.0",
"eslint-visitor-keys": "^3.4.3"
},
"engines": {
@@ -2872,15 +2879,15 @@
"license": "ISC"
},
"node_modules/@vitest/browser": {
- "version": "2.1.1",
- "resolved": "https://registry.npmjs.org/@vitest/browser/-/browser-2.1.1.tgz",
- "integrity": "sha512-wLKqohwlZI24xMIEZAPwv9SVliv1avaIBeE0ou471D++BRPhiw2mubKBczFFIDHXuSL7UXb8/JQK9Ui6ttW9bQ==",
+ "version": "2.1.3",
+ "resolved": "https://registry.npmjs.org/@vitest/browser/-/browser-2.1.3.tgz",
+ "integrity": "sha512-PQ2kLLc9q8ukJutuuYsynHSr31E78/dtYEvPy4jCHLht1LmITqXTVTqu7THWdZ1kXNGrWwtdMqtt3z2mvSKdIg==",
"dev": true,
"dependencies": {
"@testing-library/dom": "^10.4.0",
"@testing-library/user-event": "^14.5.2",
- "@vitest/mocker": "2.1.1",
- "@vitest/utils": "2.1.1",
+ "@vitest/mocker": "2.1.3",
+ "@vitest/utils": "2.1.3",
"magic-string": "^0.30.11",
"msw": "^2.3.5",
"sirv": "^2.0.4",
@@ -2892,7 +2899,7 @@
},
"peerDependencies": {
"playwright": "*",
- "vitest": "2.1.1",
+ "vitest": "2.1.3",
"webdriverio": "*"
},
"peerDependenciesMeta": {
@@ -2929,13 +2936,13 @@
}
},
"node_modules/@vitest/expect": {
- "version": "2.1.1",
- "resolved": "https://registry.npmjs.org/@vitest/expect/-/expect-2.1.1.tgz",
- "integrity": "sha512-YeueunS0HiHiQxk+KEOnq/QMzlUuOzbU1Go+PgAsHvvv3tUkJPm9xWt+6ITNTlzsMXUjmgm5T+U7KBPK2qQV6w==",
+ "version": "2.1.3",
+ "resolved": "https://registry.npmjs.org/@vitest/expect/-/expect-2.1.3.tgz",
+ "integrity": "sha512-SNBoPubeCJhZ48agjXruCI57DvxcsivVDdWz+SSsmjTT4QN/DfHk3zB/xKsJqMs26bLZ/pNRLnCf0j679i0uWQ==",
"dev": true,
"dependencies": {
- "@vitest/spy": "2.1.1",
- "@vitest/utils": "2.1.1",
+ "@vitest/spy": "2.1.3",
+ "@vitest/utils": "2.1.3",
"chai": "^5.1.1",
"tinyrainbow": "^1.2.0"
},
@@ -2944,12 +2951,12 @@
}
},
"node_modules/@vitest/mocker": {
- "version": "2.1.1",
- "resolved": "https://registry.npmjs.org/@vitest/mocker/-/mocker-2.1.1.tgz",
- "integrity": "sha512-LNN5VwOEdJqCmJ/2XJBywB11DLlkbY0ooDJW3uRX5cZyYCrc4PI/ePX0iQhE3BiEGiQmK4GE7Q/PqCkkaiPnrA==",
+ "version": "2.1.3",
+ "resolved": "https://registry.npmjs.org/@vitest/mocker/-/mocker-2.1.3.tgz",
+ "integrity": "sha512-eSpdY/eJDuOvuTA3ASzCjdithHa+GIF1L4PqtEELl6Qa3XafdMLBpBlZCIUCX2J+Q6sNmjmxtosAG62fK4BlqQ==",
"dev": true,
"dependencies": {
- "@vitest/spy": "^2.1.0-beta.1",
+ "@vitest/spy": "2.1.3",
"estree-walker": "^3.0.3",
"magic-string": "^0.30.11"
},
@@ -2957,7 +2964,7 @@
"url": "https://opencollective.com/vitest"
},
"peerDependencies": {
- "@vitest/spy": "2.1.1",
+ "@vitest/spy": "2.1.3",
"msw": "^2.3.5",
"vite": "^5.0.0"
},
@@ -2980,9 +2987,9 @@
}
},
"node_modules/@vitest/pretty-format": {
- "version": "2.1.1",
- "resolved": "https://registry.npmjs.org/@vitest/pretty-format/-/pretty-format-2.1.1.tgz",
- "integrity": "sha512-SjxPFOtuINDUW8/UkElJYQSFtnWX7tMksSGW0vfjxMneFqxVr8YJ979QpMbDW7g+BIiq88RAGDjf7en6rvLPPQ==",
+ "version": "2.1.3",
+ "resolved": "https://registry.npmjs.org/@vitest/pretty-format/-/pretty-format-2.1.3.tgz",
+ "integrity": "sha512-XH1XdtoLZCpqV59KRbPrIhFCOO0hErxrQCMcvnQete3Vibb9UeIOX02uFPfVn3Z9ZXsq78etlfyhnkmIZSzIwQ==",
"dev": true,
"dependencies": {
"tinyrainbow": "^1.2.0"
@@ -2992,12 +2999,12 @@
}
},
"node_modules/@vitest/runner": {
- "version": "2.1.1",
- "resolved": "https://registry.npmjs.org/@vitest/runner/-/runner-2.1.1.tgz",
- "integrity": "sha512-uTPuY6PWOYitIkLPidaY5L3t0JJITdGTSwBtwMjKzo5O6RCOEncz9PUN+0pDidX8kTHYjO0EwUIvhlGpnGpxmA==",
+ "version": "2.1.3",
+ "resolved": "https://registry.npmjs.org/@vitest/runner/-/runner-2.1.3.tgz",
+ "integrity": "sha512-JGzpWqmFJ4fq5ZKHtVO3Xuy1iF2rHGV4d/pdzgkYHm1+gOzNZtqjvyiaDGJytRyMU54qkxpNzCx+PErzJ1/JqQ==",
"dev": true,
"dependencies": {
- "@vitest/utils": "2.1.1",
+ "@vitest/utils": "2.1.3",
"pathe": "^1.1.2"
},
"funding": {
@@ -3005,12 +3012,12 @@
}
},
"node_modules/@vitest/snapshot": {
- "version": "2.1.1",
- "resolved": "https://registry.npmjs.org/@vitest/snapshot/-/snapshot-2.1.1.tgz",
- "integrity": "sha512-BnSku1WFy7r4mm96ha2FzN99AZJgpZOWrAhtQfoxjUU5YMRpq1zmHRq7a5K9/NjqonebO7iVDla+VvZS8BOWMw==",
+ "version": "2.1.3",
+ "resolved": "https://registry.npmjs.org/@vitest/snapshot/-/snapshot-2.1.3.tgz",
+ "integrity": "sha512-qWC2mWc7VAXmjAkEKxrScWHWFyCQx/cmiZtuGqMi+WwqQJ2iURsVY4ZfAK6dVo6K2smKRU6l3BPwqEBvhnpQGg==",
"dev": true,
"dependencies": {
- "@vitest/pretty-format": "2.1.1",
+ "@vitest/pretty-format": "2.1.3",
"magic-string": "^0.30.11",
"pathe": "^1.1.2"
},
@@ -3019,9 +3026,9 @@
}
},
"node_modules/@vitest/spy": {
- "version": "2.1.1",
- "resolved": "https://registry.npmjs.org/@vitest/spy/-/spy-2.1.1.tgz",
- "integrity": "sha512-ZM39BnZ9t/xZ/nF4UwRH5il0Sw93QnZXd9NAZGRpIgj0yvVwPpLd702s/Cx955rGaMlyBQkZJ2Ir7qyY48VZ+g==",
+ "version": "2.1.3",
+ "resolved": "https://registry.npmjs.org/@vitest/spy/-/spy-2.1.3.tgz",
+ "integrity": "sha512-Nb2UzbcUswzeSP7JksMDaqsI43Sj5+Kry6ry6jQJT4b5gAK+NS9NED6mDb8FlMRCX8m5guaHCDZmqYMMWRy5nQ==",
"dev": true,
"dependencies": {
"tinyspy": "^3.0.0"
@@ -3031,12 +3038,12 @@
}
},
"node_modules/@vitest/ui": {
- "version": "2.1.1",
- "resolved": "https://registry.npmjs.org/@vitest/ui/-/ui-2.1.1.tgz",
- "integrity": "sha512-IIxo2LkQDA+1TZdPLYPclzsXukBWd5dX2CKpGqH8CCt8Wh0ZuDn4+vuQ9qlppEju6/igDGzjWF/zyorfsf+nHg==",
+ "version": "2.1.3",
+ "resolved": "https://registry.npmjs.org/@vitest/ui/-/ui-2.1.3.tgz",
+ "integrity": "sha512-2XwTrHVJw3t9NYES26LQUYy51ZB8W4bRPgqUH2Eyda3kIuOlYw1ZdPNU22qcVlUVx4WKgECFQOSXuopsczuVjQ==",
"dev": true,
"dependencies": {
- "@vitest/utils": "2.1.1",
+ "@vitest/utils": "2.1.3",
"fflate": "^0.8.2",
"flatted": "^3.3.1",
"pathe": "^1.1.2",
@@ -3048,16 +3055,16 @@
"url": "https://opencollective.com/vitest"
},
"peerDependencies": {
- "vitest": "2.1.1"
+ "vitest": "2.1.3"
}
},
"node_modules/@vitest/utils": {
- "version": "2.1.1",
- "resolved": "https://registry.npmjs.org/@vitest/utils/-/utils-2.1.1.tgz",
- "integrity": "sha512-Y6Q9TsI+qJ2CC0ZKj6VBb+T8UPz593N113nnUykqwANqhgf3QkZeHFlusgKLTqrnVHbj/XDKZcDHol+dxVT+rQ==",
+ "version": "2.1.3",
+ "resolved": "https://registry.npmjs.org/@vitest/utils/-/utils-2.1.3.tgz",
+ "integrity": "sha512-xpiVfDSg1RrYT0tX6czgerkpcKFmFOF/gCr30+Mve5V2kewCy4Prn1/NDMSRwaSmT7PRaOF83wu+bEtsY1wrvA==",
"dev": true,
"dependencies": {
- "@vitest/pretty-format": "2.1.1",
+ "@vitest/pretty-format": "2.1.3",
"loupe": "^3.1.1",
"tinyrainbow": "^1.2.0"
},
@@ -3843,11 +3850,10 @@
}
},
"node_modules/browserify": {
- "version": "17.0.0",
- "resolved": "https://registry.npmjs.org/browserify/-/browserify-17.0.0.tgz",
- "integrity": "sha512-SaHqzhku9v/j6XsQMRxPyBrSP3gnwmE27gLJYZgMT2GeK3J0+0toN+MnuNYDfHwVGQfLiMZ7KSNSIXHemy905w==",
+ "version": "17.0.1",
+ "resolved": "https://registry.npmjs.org/browserify/-/browserify-17.0.1.tgz",
+ "integrity": "sha512-pxhT00W3ylMhCHwG5yfqtZjNnFuX5h2IJdaBfSo4ChaaBsIp9VLrEMQ1bHV+Xr1uLPXuNDDM1GlJkjli0qkRsw==",
"dev": true,
- "license": "MIT",
"dependencies": {
"assert": "^1.4.0",
"browser-pack": "^6.0.1",
@@ -3865,7 +3871,7 @@
"duplexer2": "~0.1.2",
"events": "^3.0.0",
"glob": "^7.1.0",
- "has": "^1.0.0",
+ "hasown": "^2.0.0",
"htmlescape": "^1.1.0",
"https-browserify": "^1.0.0",
"inherits": "~2.0.1",
@@ -4831,11 +4837,10 @@
}
},
"node_modules/css-functions-list": {
- "version": "3.2.2",
- "resolved": "https://registry.npmjs.org/css-functions-list/-/css-functions-list-3.2.2.tgz",
- "integrity": "sha512-c+N0v6wbKVxTu5gOBBFkr9BEdBWaqqjQeiJ8QvSRIJOf+UxlJh930m8e6/WNeODIK0mYLFkoONrnj16i2EcvfQ==",
+ "version": "3.2.3",
+ "resolved": "https://registry.npmjs.org/css-functions-list/-/css-functions-list-3.2.3.tgz",
+ "integrity": "sha512-IQOkD3hbR5KrN93MtcYuad6YPuTSUhntLHDuLEbFWE+ff2/XSZNdZG+LcbbIW5AXKg/WFIfYItIzVoHngHXZzA==",
"dev": true,
- "license": "MIT",
"engines": {
"node": ">=12 || >=16"
}
@@ -5081,12 +5086,12 @@
}
},
"node_modules/debug": {
- "version": "4.3.6",
- "resolved": "https://registry.npmjs.org/debug/-/debug-4.3.6.tgz",
- "integrity": "sha512-O/09Bd4Z1fBrU4VzkhFqVgpPzaGbw6Sm9FEkBT1A/YBXQFGuuSxa1dN2nxgxS34JmKXqYx8CZAwEVoJFImUXIg==",
+ "version": "4.3.7",
+ "resolved": "https://registry.npmjs.org/debug/-/debug-4.3.7.tgz",
+ "integrity": "sha512-Er2nc/H7RrMXZBFCEim6TCmMk02Z8vLC2Rbi1KEBggpo0fS6l0S1nnapwmIi3yW/+GOJap1Krg4w0Hg80oCqgQ==",
"dev": true,
"dependencies": {
- "ms": "2.1.2"
+ "ms": "^2.1.3"
},
"engines": {
"node": ">=6.0"
@@ -6077,9 +6082,9 @@
}
},
"node_modules/eslint-module-utils": {
- "version": "2.11.0",
- "resolved": "https://registry.npmjs.org/eslint-module-utils/-/eslint-module-utils-2.11.0.tgz",
- "integrity": "sha512-gbBE5Hitek/oG6MUVj6sFuzEjA/ClzNflVrLovHi/JgLdC7fiN5gLAY1WIPW1a0V5I999MnsrvVrCOGmmVqDBQ==",
+ "version": "2.12.0",
+ "resolved": "https://registry.npmjs.org/eslint-module-utils/-/eslint-module-utils-2.12.0.tgz",
+ "integrity": "sha512-wALZ0HFoytlyh/1+4wuZ9FJCD/leWHQzzrxJ8+rebyReSLk7LApMyd3WJaLVoN+D5+WIdJyDK1c6JnE65V4Zyg==",
"dev": true,
"dependencies": {
"debug": "^3.2.7"
@@ -6116,9 +6121,9 @@
}
},
"node_modules/eslint-plugin-import": {
- "version": "2.30.0",
- "resolved": "https://registry.npmjs.org/eslint-plugin-import/-/eslint-plugin-import-2.30.0.tgz",
- "integrity": "sha512-/mHNE9jINJfiD2EKkg1BKyPyUk4zdnT54YgbOgfjSakWT5oyX/qQLVNTkehyfpcMxZXMy1zyonZ2v7hZTX43Yw==",
+ "version": "2.31.0",
+ "resolved": "https://registry.npmjs.org/eslint-plugin-import/-/eslint-plugin-import-2.31.0.tgz",
+ "integrity": "sha512-ixmkI62Rbc2/w8Vfxyh1jQRTdRTF52VxwRVHl/ykPAmqG+Nb7/kNn+byLP0LxPgI7zWA16Jt82SybJInmMia3A==",
"dev": true,
"dependencies": {
"@rtsao/scc": "^1.1.0",
@@ -6129,7 +6134,7 @@
"debug": "^3.2.7",
"doctrine": "^2.1.0",
"eslint-import-resolver-node": "^0.3.9",
- "eslint-module-utils": "^2.9.0",
+ "eslint-module-utils": "^2.12.0",
"hasown": "^2.0.2",
"is-core-module": "^2.15.1",
"is-glob": "^4.0.3",
@@ -6138,13 +6143,14 @@
"object.groupby": "^1.0.3",
"object.values": "^1.2.0",
"semver": "^6.3.1",
+ "string.prototype.trimend": "^1.0.8",
"tsconfig-paths": "^3.15.0"
},
"engines": {
"node": ">=4"
},
"peerDependencies": {
- "eslint": "^2 || ^3 || ^4 || ^5 || ^6 || ^7.2.0 || ^8"
+ "eslint": "^2 || ^3 || ^4 || ^5 || ^6 || ^7.2.0 || ^8 || ^9"
}
},
"node_modules/eslint-plugin-import/node_modules/brace-expansion": {
@@ -6205,12 +6211,12 @@
}
},
"node_modules/eslint-plugin-jsdoc": {
- "version": "50.2.4",
- "resolved": "https://registry.npmjs.org/eslint-plugin-jsdoc/-/eslint-plugin-jsdoc-50.2.4.tgz",
- "integrity": "sha512-020jA+dXaXdb+TML3ZJBvpPmzwbNROjnYuTYi/g6A5QEmEjhptz4oPJDKkOGMIByNxsPpdTLzSU1HYVqebOX1w==",
+ "version": "50.4.3",
+ "resolved": "https://registry.npmjs.org/eslint-plugin-jsdoc/-/eslint-plugin-jsdoc-50.4.3.tgz",
+ "integrity": "sha512-uWtwFxGRv6B8sU63HZM5dAGDhgsatb+LONwmILZJhdRALLOkCX2HFZhdL/Kw2ls8SQMAVEfK+LmnEfxInRN8HA==",
"dev": true,
"dependencies": {
- "@es-joy/jsdoccomment": "~0.48.0",
+ "@es-joy/jsdoccomment": "~0.49.0",
"are-docs-informative": "^0.0.2",
"comment-parser": "1.4.1",
"debug": "^4.3.6",
@@ -7219,15 +7225,6 @@
"node": "6.* || 8.* || >= 10.*"
}
},
- "node_modules/get-func-name": {
- "version": "2.0.2",
- "resolved": "https://registry.npmjs.org/get-func-name/-/get-func-name-2.0.2.tgz",
- "integrity": "sha512-8vXOvuE167CtIc3OyItco7N/dpRtBbYOsPsXCz7X/PMnlGjYjSGuZJgM1Y7mmew7BKf9BqvLX2tnOVy1BBUsxQ==",
- "dev": true,
- "engines": {
- "node": "*"
- }
- },
"node_modules/get-intrinsic": {
"version": "1.2.4",
"resolved": "https://registry.npmjs.org/get-intrinsic/-/get-intrinsic-1.2.4.tgz",
@@ -7523,16 +7520,6 @@
"dev": true,
"license": "MIT"
},
- "node_modules/has": {
- "version": "1.0.4",
- "resolved": "https://registry.npmjs.org/has/-/has-1.0.4.tgz",
- "integrity": "sha512-qdSAmqLF6209RFj4VVItywPMbm3vWylknmB3nvNiUIs72xAimcM8nVYxYr7ncvZq5qzk9MKIZR8ijqD/1QuYjQ==",
- "dev": true,
- "license": "MIT",
- "engines": {
- "node": ">= 0.4.0"
- }
- },
"node_modules/has-bigints": {
"version": "1.0.2",
"resolved": "https://registry.npmjs.org/has-bigints/-/has-bigints-1.0.2.tgz",
@@ -9137,7 +9124,8 @@
"version": "4.17.21",
"resolved": "https://registry.npmjs.org/lodash/-/lodash-4.17.21.tgz",
"integrity": "sha512-v2kDEe57lecTulaDIuNTPy3Ry4gLGJ6Z1O3vE1krgXZNrsQ+LFTGHVxVjcXPs17LhbZVGedAJv8XZ1tvj5FvSg==",
- "dev": true
+ "dev": true,
+ "license": "MIT"
},
"node_modules/lodash._baseflatten": {
"version": "3.1.4",
@@ -9164,13 +9152,6 @@
"dev": true,
"license": "MIT"
},
- "node_modules/lodash._reinterpolate": {
- "version": "3.0.0",
- "resolved": "https://registry.npmjs.org/lodash._reinterpolate/-/lodash._reinterpolate-3.0.0.tgz",
- "integrity": "sha512-xYHt68QRoYGjeeM/XOE1uJtvXQAgvszfBhjV4yvsQH0u2i9I6cI6c6/eG4Hh3UAOVn0y/xAXwmTzEay49Q//HA==",
- "dev": true,
- "license": "MIT"
- },
"node_modules/lodash.debounce": {
"version": "3.1.1",
"resolved": "https://registry.npmjs.org/lodash.debounce/-/lodash.debounce-3.1.1.tgz",
@@ -9220,27 +9201,6 @@
"dev": true,
"license": "MIT"
},
- "node_modules/lodash.template": {
- "version": "4.5.0",
- "resolved": "https://registry.npmjs.org/lodash.template/-/lodash.template-4.5.0.tgz",
- "integrity": "sha512-84vYFxIkmidUiFxidA/KjjH9pAycqW+h980j7Fuz5qxRtO9pgB7MDFTdys1N7A5mcucRiDyEq4fusljItR1T/A==",
- "dev": true,
- "license": "MIT",
- "dependencies": {
- "lodash._reinterpolate": "^3.0.0",
- "lodash.templatesettings": "^4.0.0"
- }
- },
- "node_modules/lodash.templatesettings": {
- "version": "4.2.0",
- "resolved": "https://registry.npmjs.org/lodash.templatesettings/-/lodash.templatesettings-4.2.0.tgz",
- "integrity": "sha512-stgLz+i3Aa9mZgnjr/O+v9ruKZsPsndy7qPZOchbqk2cnTU1ZaldKK+v7m54WoKIyxiuMZTKT2H81F8BeAc3ZQ==",
- "dev": true,
- "license": "MIT",
- "dependencies": {
- "lodash._reinterpolate": "^3.0.0"
- }
- },
"node_modules/lodash.truncate": {
"version": "4.4.2",
"resolved": "https://registry.npmjs.org/lodash.truncate/-/lodash.truncate-4.4.2.tgz",
@@ -9255,13 +9215,10 @@
"dev": true
},
"node_modules/loupe": {
- "version": "3.1.1",
- "resolved": "https://registry.npmjs.org/loupe/-/loupe-3.1.1.tgz",
- "integrity": "sha512-edNu/8D5MKVfGVFRhFf8aAxiTM6Wumfz5XsaatSxlD3w4R1d/WEKUTydCdPGbl9K7QG/Ca3GnDV2sIKIpXRQcw==",
- "dev": true,
- "dependencies": {
- "get-func-name": "^2.0.1"
- }
+ "version": "3.1.2",
+ "resolved": "https://registry.npmjs.org/loupe/-/loupe-3.1.2.tgz",
+ "integrity": "sha512-23I4pFZHmAemUnz8WZXbYRSKYj801VDaNv9ETuMh7IrMc7VuVVSo+Z9iLE3ni30+U48iDWfi30d3twAXBYmnCg==",
+ "dev": true
},
"node_modules/lru-cache": {
"version": "11.0.0",
@@ -9667,11 +9624,10 @@
}
},
"node_modules/ms": {
- "version": "2.1.2",
- "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.2.tgz",
- "integrity": "sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w==",
- "dev": true,
- "license": "MIT"
+ "version": "2.1.3",
+ "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.3.tgz",
+ "integrity": "sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA==",
+ "dev": true
},
"node_modules/msw": {
"version": "2.3.5",
@@ -10674,12 +10630,12 @@
}
},
"node_modules/playwright": {
- "version": "1.47.2",
- "resolved": "https://registry.npmjs.org/playwright/-/playwright-1.47.2.tgz",
- "integrity": "sha512-nx1cLMmQWqmA3UsnjaaokyoUpdVaaDhJhMoxX2qj3McpjnsqFHs516QAKYhqHAgOP+oCFTEOCOAaD1RgD/RQfA==",
+ "version": "1.48.1",
+ "resolved": "https://registry.npmjs.org/playwright/-/playwright-1.48.1.tgz",
+ "integrity": "sha512-j8CiHW/V6HxmbntOfyB4+T/uk08tBy6ph0MpBXwuoofkSnLmlfdYNNkFTYD6ofzzlSqLA1fwH4vwvVFvJgLN0w==",
"dev": true,
"dependencies": {
- "playwright-core": "1.47.2"
+ "playwright-core": "1.48.1"
},
"bin": {
"playwright": "cli.js"
@@ -10692,9 +10648,9 @@
}
},
"node_modules/playwright-core": {
- "version": "1.47.2",
- "resolved": "https://registry.npmjs.org/playwright-core/-/playwright-core-1.47.2.tgz",
- "integrity": "sha512-3JvMfF+9LJfe16l7AbSmU555PaTl2tPyQsVInqm3id16pdDfvZ8TTZ/pyzmkbDrZTQefyzU7AIHlZqQnxpqHVQ==",
+ "version": "1.48.1",
+ "resolved": "https://registry.npmjs.org/playwright-core/-/playwright-core-1.48.1.tgz",
+ "integrity": "sha512-Yw/t4VAFX/bBr1OzwCuOMZkY1Cnb4z/doAFSwf4huqAGWmf9eMNjmK7NiOljCdLmxeRYcGPPmcDgU0zOlzP0YA==",
"dev": true,
"bin": {
"playwright-core": "cli.js"
@@ -11377,9 +11333,9 @@
"dev": true
},
"node_modules/postcss-safe-parser": {
- "version": "7.0.0",
- "resolved": "https://registry.npmjs.org/postcss-safe-parser/-/postcss-safe-parser-7.0.0.tgz",
- "integrity": "sha512-ovehqRNVCpuFzbXoTb4qLtyzK3xn3t/CUBxOs8LsnQjQrShaB4lKiHoVqY8ANaC0hBMHq5QVWk77rwGklFUDrg==",
+ "version": "7.0.1",
+ "resolved": "https://registry.npmjs.org/postcss-safe-parser/-/postcss-safe-parser-7.0.1.tgz",
+ "integrity": "sha512-0AioNCJZ2DPYz5ABT6bddIqlhgwhpHZ/l65YAYo0BCIn0xiDpsnTHz0gnoTGk0OXZW0JRs+cDwL8u/teRdz+8A==",
"dev": true,
"funding": [
{
@@ -11395,7 +11351,6 @@
"url": "https://github.com/sponsors/ai"
}
],
- "license": "MIT",
"engines": {
"node": ">=18.0"
},
@@ -12316,13 +12271,6 @@
"dev": true,
"license": "MIT"
},
- "node_modules/send/node_modules/ms": {
- "version": "2.1.3",
- "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.3.tgz",
- "integrity": "sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA==",
- "dev": true,
- "license": "MIT"
- },
"node_modules/serialize-javascript": {
"version": "6.0.2",
"resolved": "https://registry.npmjs.org/serialize-javascript/-/serialize-javascript-6.0.2.tgz",
@@ -12381,12 +12329,6 @@
"node": ">= 0.8"
}
},
- "node_modules/serve-static/node_modules/ms": {
- "version": "2.1.3",
- "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.3.tgz",
- "integrity": "sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA==",
- "dev": true
- },
"node_modules/serve-static/node_modules/send": {
"version": "0.19.0",
"resolved": "https://registry.npmjs.org/send/-/send-0.19.0.tgz",
@@ -13240,9 +13182,9 @@
}
},
"node_modules/stylelint": {
- "version": "16.9.0",
- "resolved": "https://registry.npmjs.org/stylelint/-/stylelint-16.9.0.tgz",
- "integrity": "sha512-31Nm3WjxGOBGpQqF43o3wO9L5AC36TPIe6030Lnm13H3vDMTcS21DrLh69bMX+DBilKqMMVLian4iG6ybBoNRQ==",
+ "version": "16.10.0",
+ "resolved": "https://registry.npmjs.org/stylelint/-/stylelint-16.10.0.tgz",
+ "integrity": "sha512-z/8X2rZ52dt2c0stVwI9QL2AFJhLhbPkyfpDFcizs200V/g7v+UYY6SNcB9hKOLcDDX/yGLDsY/pX08sLkz9xQ==",
"dev": true,
"funding": [
{
@@ -13263,17 +13205,17 @@
"balanced-match": "^2.0.0",
"colord": "^2.9.3",
"cosmiconfig": "^9.0.0",
- "css-functions-list": "^3.2.2",
- "css-tree": "^2.3.1",
- "debug": "^4.3.6",
+ "css-functions-list": "^3.2.3",
+ "css-tree": "^3.0.0",
+ "debug": "^4.3.7",
"fast-glob": "^3.3.2",
"fastest-levenshtein": "^1.0.16",
- "file-entry-cache": "^9.0.0",
+ "file-entry-cache": "^9.1.0",
"global-modules": "^2.0.0",
"globby": "^11.1.0",
"globjoin": "^0.1.4",
"html-tags": "^3.3.1",
- "ignore": "^5.3.2",
+ "ignore": "^6.0.2",
"imurmurhash": "^0.1.4",
"is-plain-object": "^5.0.0",
"known-css-properties": "^0.34.0",
@@ -13282,14 +13224,13 @@
"micromatch": "^4.0.8",
"normalize-path": "^3.0.0",
"picocolors": "^1.0.1",
- "postcss": "^8.4.41",
+ "postcss": "^8.4.47",
"postcss-resolve-nested-selector": "^0.1.6",
- "postcss-safe-parser": "^7.0.0",
+ "postcss-safe-parser": "^7.0.1",
"postcss-selector-parser": "^6.1.2",
"postcss-value-parser": "^4.2.0",
"resolve-from": "^5.0.0",
"string-width": "^4.2.3",
- "strip-ansi": "^7.1.0",
"supports-hyperlinks": "^3.1.0",
"svg-tags": "^1.0.0",
"table": "^6.8.2",
@@ -13358,6 +13299,19 @@
"dev": true,
"license": "MIT"
},
+ "node_modules/stylelint/node_modules/css-tree": {
+ "version": "3.0.0",
+ "resolved": "https://registry.npmjs.org/css-tree/-/css-tree-3.0.0.tgz",
+ "integrity": "sha512-o88DVQ6GzsABn1+6+zo2ct801dBO5OASVyxbbvA2W20ue2puSh/VOuqUj90eUeMSX/xqGqBmOKiRQN7tJOuBXw==",
+ "dev": true,
+ "dependencies": {
+ "mdn-data": "2.10.0",
+ "source-map-js": "^1.0.1"
+ },
+ "engines": {
+ "node": "^10 || ^12.20.0 || ^14.13.0 || >=15.0.0"
+ }
+ },
"node_modules/stylelint/node_modules/emoji-regex": {
"version": "8.0.0",
"resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-8.0.0.tgz",
@@ -13366,11 +13320,10 @@
"license": "MIT"
},
"node_modules/stylelint/node_modules/file-entry-cache": {
- "version": "9.0.0",
- "resolved": "https://registry.npmjs.org/file-entry-cache/-/file-entry-cache-9.0.0.tgz",
- "integrity": "sha512-6MgEugi8p2tiUhqO7GnPsmbCCzj0YRCwwaTbpGRyKZesjRSzkqkAE9fPp7V2yMs5hwfgbQLgdvSSkGNg1s5Uvw==",
+ "version": "9.1.0",
+ "resolved": "https://registry.npmjs.org/file-entry-cache/-/file-entry-cache-9.1.0.tgz",
+ "integrity": "sha512-/pqPFG+FdxWQj+/WSuzXSDaNzxgTLr/OrR1QuqfEZzDakpdYE70PwUxL7BPUa8hpjbvY1+qvCl8k+8Tq34xJgg==",
"dev": true,
- "license": "MIT",
"dependencies": {
"flat-cache": "^5.0.0"
},
@@ -13383,7 +13336,6 @@
"resolved": "https://registry.npmjs.org/flat-cache/-/flat-cache-5.0.0.tgz",
"integrity": "sha512-JrqFmyUl2PnPi1OvLyTVHnQvwQ0S+e6lGSwu8OkAZlSaNIZciTY2H/cOOROxsBA1m/LZNHDsqAgDZt6akWcjsQ==",
"dev": true,
- "license": "MIT",
"dependencies": {
"flatted": "^3.3.1",
"keyv": "^4.5.4"
@@ -13392,6 +13344,21 @@
"node": ">=18"
}
},
+ "node_modules/stylelint/node_modules/ignore": {
+ "version": "6.0.2",
+ "resolved": "https://registry.npmjs.org/ignore/-/ignore-6.0.2.tgz",
+ "integrity": "sha512-InwqeHHN2XpumIkMvpl/DCJVrAHgCsG5+cn1XlnLWGwtZBm8QJfSusItfrwx81CTp5agNZqpKU2J/ccC5nGT4A==",
+ "dev": true,
+ "engines": {
+ "node": ">= 4"
+ }
+ },
+ "node_modules/stylelint/node_modules/mdn-data": {
+ "version": "2.10.0",
+ "resolved": "https://registry.npmjs.org/mdn-data/-/mdn-data-2.10.0.tgz",
+ "integrity": "sha512-qq7C3EtK3yJXMwz1zAab65pjl+UhohqMOctTgcqjLOWABqmwj+me02LSsCuEUxnst9X1lCBpoE0WArGKgdGDzw==",
+ "dev": true
+ },
"node_modules/stylelint/node_modules/resolve-from": {
"version": "5.0.0",
"resolved": "https://registry.npmjs.org/resolve-from/-/resolve-from-5.0.0.tgz",
@@ -13430,35 +13397,6 @@
"node": ">=8"
}
},
- "node_modules/stylelint/node_modules/strip-ansi": {
- "version": "7.1.0",
- "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-7.1.0.tgz",
- "integrity": "sha512-iq6eVVI64nQQTRYq2KtEg2d2uU7LElhTJwsH4YzIHZshxlgZms/wIc4VoDQTlG/IvVIrBKG06CrZnp0qv7hkcQ==",
- "dev": true,
- "license": "MIT",
- "dependencies": {
- "ansi-regex": "^6.0.1"
- },
- "engines": {
- "node": ">=12"
- },
- "funding": {
- "url": "https://github.com/chalk/strip-ansi?sponsor=1"
- }
- },
- "node_modules/stylelint/node_modules/strip-ansi/node_modules/ansi-regex": {
- "version": "6.0.1",
- "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-6.0.1.tgz",
- "integrity": "sha512-n5M855fKb2SsfMIiFFoVrABHJC8QtHwVx+mHWP3QcEqBHYienj5dHSgjbxtC0WEZXYt4wcD6zrQElDPhFuZgfA==",
- "dev": true,
- "license": "MIT",
- "engines": {
- "node": ">=12"
- },
- "funding": {
- "url": "https://github.com/chalk/ansi-regex?sponsor=1"
- }
- },
"node_modules/subarg": {
"version": "1.0.0",
"resolved": "https://registry.npmjs.org/subarg/-/subarg-1.0.0.tgz",
@@ -14755,9 +14693,9 @@
"license": "MIT"
},
"node_modules/typescript": {
- "version": "5.6.2",
- "resolved": "https://registry.npmjs.org/typescript/-/typescript-5.6.2.tgz",
- "integrity": "sha512-NW8ByodCSNCwZeghjN3o+JX5OFH0Ojg6sadjEKY4huZ52TqbJTJnDo5+Tw98lSy63NZvi4n+ez5m2u5d4PkZyw==",
+ "version": "5.6.3",
+ "resolved": "https://registry.npmjs.org/typescript/-/typescript-5.6.3.tgz",
+ "integrity": "sha512-hjcS1mhfuyi4WW8IWtjP7brDrG2cuDZukyrYrSauoXGNgx0S7zceP07adYkJycEr56BOUTNPzbInooiN3fn1qw==",
"dev": true,
"bin": {
"tsc": "bin/tsc",
@@ -14768,14 +14706,14 @@
}
},
"node_modules/typescript-eslint": {
- "version": "8.7.0",
- "resolved": "https://registry.npmjs.org/typescript-eslint/-/typescript-eslint-8.7.0.tgz",
- "integrity": "sha512-nEHbEYJyHwsuf7c3V3RS7Saq+1+la3i0ieR3qP0yjqWSzVmh8Drp47uOl9LjbPANac4S7EFSqvcYIKXUUwIfIQ==",
+ "version": "8.11.0",
+ "resolved": "https://registry.npmjs.org/typescript-eslint/-/typescript-eslint-8.11.0.tgz",
+ "integrity": "sha512-cBRGnW3FSlxaYwU8KfAewxFK5uzeOAp0l2KebIlPDOT5olVi65KDG/yjBooPBG0kGW/HLkoz1c/iuBFehcS3IA==",
"dev": true,
"dependencies": {
- "@typescript-eslint/eslint-plugin": "8.7.0",
- "@typescript-eslint/parser": "8.7.0",
- "@typescript-eslint/utils": "8.7.0"
+ "@typescript-eslint/eslint-plugin": "8.11.0",
+ "@typescript-eslint/parser": "8.11.0",
+ "@typescript-eslint/utils": "8.11.0"
},
"engines": {
"node": "^18.18.0 || ^20.9.0 || >=21.1.0"
@@ -15068,9 +15006,9 @@
}
},
"node_modules/vite": {
- "version": "5.4.6",
- "resolved": "https://registry.npmjs.org/vite/-/vite-5.4.6.tgz",
- "integrity": "sha512-IeL5f8OO5nylsgzd9tq4qD2QqI0k2CQLGrWD0rCN0EQJZpBK5vJAx0I+GDkMOXxQX/OfFHMuLIx6ddAxGX/k+Q==",
+ "version": "5.4.9",
+ "resolved": "https://registry.npmjs.org/vite/-/vite-5.4.9.tgz",
+ "integrity": "sha512-20OVpJHh0PAM0oSOELa5GaZNWeDjcAvQjGXy2Uyr+Tp+/D2/Hdz6NLgpJLsarPTA2QJ6v8mX2P1ZfbsSKvdMkg==",
"dev": true,
"dependencies": {
"esbuild": "^0.21.3",
@@ -15127,9 +15065,9 @@
}
},
"node_modules/vite-node": {
- "version": "2.1.1",
- "resolved": "https://registry.npmjs.org/vite-node/-/vite-node-2.1.1.tgz",
- "integrity": "sha512-N/mGckI1suG/5wQI35XeR9rsMsPqKXzq1CdUndzVstBj/HvyxxGctwnK6WX43NGt5L3Z5tcRf83g4TITKJhPrA==",
+ "version": "2.1.3",
+ "resolved": "https://registry.npmjs.org/vite-node/-/vite-node-2.1.3.tgz",
+ "integrity": "sha512-I1JadzO+xYX887S39Do+paRePCKoiDrWRRjp9kkG5he0t7RXNvPAJPCQSJqbGN4uCrFFeS3Kj3sLqY8NMYBEdA==",
"dev": true,
"dependencies": {
"cac": "^6.7.14",
@@ -15561,18 +15499,18 @@
}
},
"node_modules/vitest": {
- "version": "2.1.1",
- "resolved": "https://registry.npmjs.org/vitest/-/vitest-2.1.1.tgz",
- "integrity": "sha512-97We7/VC0e9X5zBVkvt7SGQMGrRtn3KtySFQG5fpaMlS+l62eeXRQO633AYhSTC3z7IMebnPPNjGXVGNRFlxBA==",
+ "version": "2.1.3",
+ "resolved": "https://registry.npmjs.org/vitest/-/vitest-2.1.3.tgz",
+ "integrity": "sha512-Zrxbg/WiIvUP2uEzelDNTXmEMJXuzJ1kCpbDvaKByFA9MNeO95V+7r/3ti0qzJzrxdyuUw5VduN7k+D3VmVOSA==",
"dev": true,
"dependencies": {
- "@vitest/expect": "2.1.1",
- "@vitest/mocker": "2.1.1",
- "@vitest/pretty-format": "^2.1.1",
- "@vitest/runner": "2.1.1",
- "@vitest/snapshot": "2.1.1",
- "@vitest/spy": "2.1.1",
- "@vitest/utils": "2.1.1",
+ "@vitest/expect": "2.1.3",
+ "@vitest/mocker": "2.1.3",
+ "@vitest/pretty-format": "^2.1.3",
+ "@vitest/runner": "2.1.3",
+ "@vitest/snapshot": "2.1.3",
+ "@vitest/spy": "2.1.3",
+ "@vitest/utils": "2.1.3",
"chai": "^5.1.1",
"debug": "^4.3.6",
"magic-string": "^0.30.11",
@@ -15583,7 +15521,7 @@
"tinypool": "^1.0.0",
"tinyrainbow": "^1.2.0",
"vite": "^5.0.0",
- "vite-node": "2.1.1",
+ "vite-node": "2.1.3",
"why-is-node-running": "^2.3.0"
},
"bin": {
@@ -15598,8 +15536,8 @@
"peerDependencies": {
"@edge-runtime/vm": "*",
"@types/node": "^18.0.0 || >=20.0.0",
- "@vitest/browser": "2.1.1",
- "@vitest/ui": "2.1.1",
+ "@vitest/browser": "2.1.3",
+ "@vitest/ui": "2.1.3",
"happy-dom": "*",
"jsdom": "*"
},
@@ -16048,7 +15986,7 @@
},
"src/style-spec": {
"name": "@mapbox/mapbox-gl-style-spec",
- "version": "14.7.1",
+ "version": "14.8.0-beta.1",
"license": "SEE LICENSE IN LICENSE.txt",
"dependencies": {
"@mapbox/jsonlint-lines-primitives": "~2.0.2",
@@ -16076,7 +16014,7 @@
},
"devDependencies": {
"@types/geojson": "*",
- "typescript": "^5.6.2"
+ "typescript": "^5.6.3"
}
}
}
diff --git a/package.json b/package.json
index 01ac5bd0ecc..82167236873 100644
--- a/package.json
+++ b/package.json
@@ -1,7 +1,7 @@
{
"name": "mapbox-gl",
"description": "A WebGL interactive maps library",
- "version": "3.7.0",
+ "version": "3.8.0-beta.1",
"main": "dist/mapbox-gl.js",
"style": "dist/mapbox-gl.css",
"types": "dist/mapbox-gl.d.ts",
@@ -48,22 +48,23 @@
"devDependencies": {
"@mapbox/mvt-fixtures": "^3.10.0",
"@octokit/rest": "^21.0.2",
- "@rollup/plugin-commonjs": "^28.0.0",
+ "@rollup/plugin-commonjs": "^28.0.1",
"@rollup/plugin-json": "^6.1.0",
"@rollup/plugin-node-resolve": "^15.3.0",
"@rollup/plugin-replace": "^6.0.1",
"@rollup/plugin-strip": "^3.0.4",
"@rollup/plugin-terser": "^0.4.4",
+ "@rollup/plugin-virtual": "^3.0.2",
"@tweakpane/core": "^2.0.4",
"@types/jest": "^29.5.13",
- "@types/node": "^22.6.1",
+ "@types/node": "^22.7.7",
"@types/offscreencanvas": "^2019.7.3",
- "@typescript-eslint/eslint-plugin": "^8.7.0",
- "@typescript-eslint/parser": "^8.7.0",
- "@vitest/browser": "^2.1.1",
+ "@typescript-eslint/eslint-plugin": "^8.11.0",
+ "@typescript-eslint/parser": "^8.11.0",
+ "@vitest/browser": "^2.1.3",
"@vitest/ui": "^2.0.3",
"address": "^2.0.3",
- "browserify": "^17.0.0",
+ "browserify": "^17.0.1",
"chalk": "^5.0.1",
"chokidar": "^4.0.1",
"cross-env": "^7.0.3",
@@ -78,13 +79,13 @@
"eslint-config-mourner": "^3.0.0",
"eslint-import-resolver-typescript": "^3.6.3",
"eslint-plugin-html": "^8.1.2",
- "eslint-plugin-import": "^2.30.0",
- "eslint-plugin-jsdoc": "^50.2.4",
+ "eslint-plugin-import": "^2.31.0",
+ "eslint-plugin-jsdoc": "^50.4.3",
"glob": "^11.0.0",
"is-builtin-module": "^4.0.0",
"jest-extended": "^4.0.2",
"json-stringify-pretty-compact": "^4.0.0",
- "lodash.template": "^4.5.0",
+ "lodash": "^4.17.21",
"mapbox-gl-styles": "^2.0.2",
"minimist": "^1.2.6",
"mock-geolocation": "^1.0.11",
@@ -93,7 +94,7 @@
"npm-font-open-sans": "^1.1.0",
"npm-run-all": "^4.1.5",
"pixelmatch": "^6.0.0",
- "playwright": "^1.47.2",
+ "playwright": "^1.48.1",
"postcss": "^8.4.47",
"postcss-cli": "^11.0.0",
"postcss-inline-svg": "^6.0.0",
@@ -105,15 +106,15 @@
"serve-static": "^1.16.2",
"shuffle-seed": "^1.1.6",
"st": "^3.0.0",
- "stylelint": "^16.9.0",
+ "stylelint": "^16.10.0",
"stylelint-config-standard": "^36.0.1",
"tape": "^5.9.0",
"tape-filter": "^1.0.4",
"testem": "^3.15.2",
"tsx": "^4.19.1",
"tweakpane": "^4.0.4",
- "typescript": "^5.6.2",
- "typescript-eslint": "^8.7.0",
+ "typescript": "^5.6.3",
+ "typescript-eslint": "^8.11.0",
"utility-types": "^3.11.0",
"vite-plugin-arraybuffer": "^0.0.8",
"vitest": "^2.0.3"
@@ -144,10 +145,12 @@
"test-suite-clean": "find test/integration/{render,query, expressions}-tests -mindepth 2 -type d -exec test -e \"{}/actual.png\" \\; -not \\( -exec test -e \"{}/style.json\" \\; \\) -print | xargs -t rm -r",
"watch-unit": "vitest --config vitest.config.unit.ts",
"test-unit": "vitest --config vitest.config.unit.ts --run",
+ "test-usvg": "vitest --config ./vitest.config.usvg.ts --run",
+ "start-usvg": "esbuild src/data/usvg/usvg_pb_renderer.ts --outfile=src/data/usvg/usvg_pb_renderer.js --bundle --format=esm --watch --serve=9966 --servedir=.",
"test-build": "tsx ./node_modules/.bin/tape test/build/**/*.test.js",
"watch-render": "cross-env SUITE_NAME=render testem -f test/integration/testem/testem.js",
"watch-query": "SUITE_NAME=query testem -f test/integration/testem/testem.js",
- "test-csp": "vitest --config vitest.config.csp.js --run",
+ "test-csp": "npm run build-token && vitest --config vitest.config.csp.ts --run",
"test-render": "cross-env SUITE_NAME=render testem ci -f test/integration/testem/testem.js",
"test-render-firefox": "cross-env BROWSER=Firefox SUITE_NAME=render testem ci -f test/integration/testem/testem.js",
"test-render-safari": "cross-env BROWSER=Safari SUITE_NAME=render testem ci -f test/integration/testem/testem.js",
diff --git a/rollup.config.js b/rollup.config.js
index e05b761b36f..fc2858823c5 100644
--- a/rollup.config.js
+++ b/rollup.config.js
@@ -48,7 +48,7 @@ export default ({watch}) => {
onwarn: production ? onwarn : false,
treeshake: production ? {
moduleSideEffects: (id, external) => {
- return !id.endsWith("tracked_parameters.ts");
+ return !id.endsWith("tracked_parameters.ts") && !id.endsWith("draw_snow.ts") && !id.endsWith("draw_rain.ts");
},
preset: "recommended"
} : false,
diff --git a/src/data/array_types.ts b/src/data/array_types.ts
index 426e5729b2d..7e2409af1db 100644
--- a/src/data/array_types.ts
+++ b/src/data/array_types.ts
@@ -14,21 +14,21 @@ import type {IStructArrayLayout} from '../util/struct_array';
* @private
*/
class StructArrayLayout2i4 extends StructArray implements IStructArrayLayout {
- uint8: Uint8Array;
- int16: Int16Array;
+ override uint8: Uint8Array;
+ override int16: Int16Array;
- _refreshViews() {
+ override _refreshViews() {
this.uint8 = new Uint8Array(this.arrayBuffer);
this.int16 = new Int16Array(this.arrayBuffer);
}
- emplaceBack(v0: number, v1: number): number {
+ override emplaceBack(v0: number, v1: number): number {
const i = this.length;
this.resize(i + 1);
return this.emplace(i, v0, v1);
}
- emplace(i: number, v0: number, v1: number): number {
+ override emplace(i: number, v0: number, v1: number): number {
const o2 = i * 2;
this.int16[o2 + 0] = v0;
this.int16[o2 + 1] = v1;
@@ -46,21 +46,21 @@ register(StructArrayLayout2i4, 'StructArrayLayout2i4');
* @private
*/
class StructArrayLayout3i6 extends StructArray implements IStructArrayLayout {
- uint8: Uint8Array;
- int16: Int16Array;
+ override uint8: Uint8Array;
+ override int16: Int16Array;
- _refreshViews() {
+ override _refreshViews() {
this.uint8 = new Uint8Array(this.arrayBuffer);
this.int16 = new Int16Array(this.arrayBuffer);
}
- emplaceBack(v0: number, v1: number, v2: number): number {
+ override emplaceBack(v0: number, v1: number, v2: number): number {
const i = this.length;
this.resize(i + 1);
return this.emplace(i, v0, v1, v2);
}
- emplace(i: number, v0: number, v1: number, v2: number): number {
+ override emplace(i: number, v0: number, v1: number, v2: number): number {
const o2 = i * 3;
this.int16[o2 + 0] = v0;
this.int16[o2 + 1] = v1;
@@ -79,21 +79,21 @@ register(StructArrayLayout3i6, 'StructArrayLayout3i6');
* @private
*/
class StructArrayLayout4i8 extends StructArray implements IStructArrayLayout {
- uint8: Uint8Array;
- int16: Int16Array;
+ override uint8: Uint8Array;
+ override int16: Int16Array;
- _refreshViews() {
+ override _refreshViews() {
this.uint8 = new Uint8Array(this.arrayBuffer);
this.int16 = new Int16Array(this.arrayBuffer);
}
- emplaceBack(v0: number, v1: number, v2: number, v3: number): number {
+ override emplaceBack(v0: number, v1: number, v2: number, v3: number): number {
const i = this.length;
this.resize(i + 1);
return this.emplace(i, v0, v1, v2, v3);
}
- emplace(i: number, v0: number, v1: number, v2: number, v3: number): number {
+ override emplace(i: number, v0: number, v1: number, v2: number, v3: number): number {
const o2 = i * 4;
this.int16[o2 + 0] = v0;
this.int16[o2 + 1] = v1;
@@ -113,21 +113,21 @@ register(StructArrayLayout4i8, 'StructArrayLayout4i8');
* @private
*/
class StructArrayLayout5i10 extends StructArray implements IStructArrayLayout {
- uint8: Uint8Array;
- int16: Int16Array;
+ override uint8: Uint8Array;
+ override int16: Int16Array;
- _refreshViews() {
+ override _refreshViews() {
this.uint8 = new Uint8Array(this.arrayBuffer);
this.int16 = new Int16Array(this.arrayBuffer);
}
- emplaceBack(v0: number, v1: number, v2: number, v3: number, v4: number): number {
+ override emplaceBack(v0: number, v1: number, v2: number, v3: number, v4: number): number {
const i = this.length;
this.resize(i + 1);
return this.emplace(i, v0, v1, v2, v3, v4);
}
- emplace(i: number, v0: number, v1: number, v2: number, v3: number, v4: number): number {
+ override emplace(i: number, v0: number, v1: number, v2: number, v3: number, v4: number): number {
const o2 = i * 5;
this.int16[o2 + 0] = v0;
this.int16[o2 + 1] = v1;
@@ -150,23 +150,23 @@ register(StructArrayLayout5i10, 'StructArrayLayout5i10');
* @private
*/
class StructArrayLayout2i4ub1f12 extends StructArray implements IStructArrayLayout {
- uint8: Uint8Array;
- int16: Int16Array;
- float32: Float32Array;
+ override uint8: Uint8Array;
+ override int16: Int16Array;
+ override float32: Float32Array;
- _refreshViews() {
+ override _refreshViews() {
this.uint8 = new Uint8Array(this.arrayBuffer);
this.int16 = new Int16Array(this.arrayBuffer);
this.float32 = new Float32Array(this.arrayBuffer);
}
- emplaceBack(v0: number, v1: number, v2: number, v3: number, v4: number, v5: number, v6: number): number {
+ override emplaceBack(v0: number, v1: number, v2: number, v3: number, v4: number, v5: number, v6: number): number {
const i = this.length;
this.resize(i + 1);
return this.emplace(i, v0, v1, v2, v3, v4, v5, v6);
}
- emplace(i: number, v0: number, v1: number, v2: number, v3: number, v4: number, v5: number, v6: number): number {
+ override emplace(i: number, v0: number, v1: number, v2: number, v3: number, v4: number, v5: number, v6: number): number {
const o2 = i * 6;
const o1 = i * 12;
const o4 = i * 3;
@@ -191,21 +191,21 @@ register(StructArrayLayout2i4ub1f12, 'StructArrayLayout2i4ub1f12');
* @private
*/
class StructArrayLayout4f16 extends StructArray implements IStructArrayLayout {
- uint8: Uint8Array;
- float32: Float32Array;
+ override uint8: Uint8Array;
+ override float32: Float32Array;
- _refreshViews() {
+ override _refreshViews() {
this.uint8 = new Uint8Array(this.arrayBuffer);
this.float32 = new Float32Array(this.arrayBuffer);
}
- emplaceBack(v0: number, v1: number, v2: number, v3: number): number {
+ override emplaceBack(v0: number, v1: number, v2: number, v3: number): number {
const i = this.length;
this.resize(i + 1);
return this.emplace(i, v0, v1, v2, v3);
}
- emplace(i: number, v0: number, v1: number, v2: number, v3: number): number {
+ override emplace(i: number, v0: number, v1: number, v2: number, v3: number): number {
const o4 = i * 4;
this.float32[o4 + 0] = v0;
this.float32[o4 + 1] = v1;
@@ -225,21 +225,21 @@ register(StructArrayLayout4f16, 'StructArrayLayout4f16');
* @private
*/
class StructArrayLayout3f12 extends StructArray implements IStructArrayLayout {
- uint8: Uint8Array;
- float32: Float32Array;
+ override uint8: Uint8Array;
+ override float32: Float32Array;
- _refreshViews() {
+ override _refreshViews() {
this.uint8 = new Uint8Array(this.arrayBuffer);
this.float32 = new Float32Array(this.arrayBuffer);
}
- emplaceBack(v0: number, v1: number, v2: number): number {
+ override emplaceBack(v0: number, v1: number, v2: number): number {
const i = this.length;
this.resize(i + 1);
return this.emplace(i, v0, v1, v2);
}
- emplace(i: number, v0: number, v1: number, v2: number): number {
+ override emplace(i: number, v0: number, v1: number, v2: number): number {
const o4 = i * 3;
this.float32[o4 + 0] = v0;
this.float32[o4 + 1] = v1;
@@ -259,23 +259,23 @@ register(StructArrayLayout3f12, 'StructArrayLayout3f12');
* @private
*/
class StructArrayLayout4ui1f12 extends StructArray implements IStructArrayLayout {
- uint8: Uint8Array;
- uint16: Uint16Array;
- float32: Float32Array;
+ override uint8: Uint8Array;
+ override uint16: Uint16Array;
+ override float32: Float32Array;
- _refreshViews() {
+ override _refreshViews() {
this.uint8 = new Uint8Array(this.arrayBuffer);
this.uint16 = new Uint16Array(this.arrayBuffer);
this.float32 = new Float32Array(this.arrayBuffer);
}
- emplaceBack(v0: number, v1: number, v2: number, v3: number, v4: number): number {
+ override emplaceBack(v0: number, v1: number, v2: number, v3: number, v4: number): number {
const i = this.length;
this.resize(i + 1);
return this.emplace(i, v0, v1, v2, v3, v4);
}
- emplace(i: number, v0: number, v1: number, v2: number, v3: number, v4: number): number {
+ override emplace(i: number, v0: number, v1: number, v2: number, v3: number, v4: number): number {
const o2 = i * 6;
const o4 = i * 3;
this.uint16[o2 + 0] = v0;
@@ -297,21 +297,21 @@ register(StructArrayLayout4ui1f12, 'StructArrayLayout4ui1f12');
* @private
*/
class StructArrayLayout4ui8 extends StructArray implements IStructArrayLayout {
- uint8: Uint8Array;
- uint16: Uint16Array;
+ override uint8: Uint8Array;
+ override uint16: Uint16Array;
- _refreshViews() {
+ override _refreshViews() {
this.uint8 = new Uint8Array(this.arrayBuffer);
this.uint16 = new Uint16Array(this.arrayBuffer);
}
- emplaceBack(v0: number, v1: number, v2: number, v3: number): number {
+ override emplaceBack(v0: number, v1: number, v2: number, v3: number): number {
const i = this.length;
this.resize(i + 1);
return this.emplace(i, v0, v1, v2, v3);
}
- emplace(i: number, v0: number, v1: number, v2: number, v3: number): number {
+ override emplace(i: number, v0: number, v1: number, v2: number, v3: number): number {
const o2 = i * 4;
this.uint16[o2 + 0] = v0;
this.uint16[o2 + 1] = v1;
@@ -331,21 +331,21 @@ register(StructArrayLayout4ui8, 'StructArrayLayout4ui8');
* @private
*/
class StructArrayLayout6i12 extends StructArray implements IStructArrayLayout {
- uint8: Uint8Array;
- int16: Int16Array;
+ override uint8: Uint8Array;
+ override int16: Int16Array;
- _refreshViews() {
+ override _refreshViews() {
this.uint8 = new Uint8Array(this.arrayBuffer);
this.int16 = new Int16Array(this.arrayBuffer);
}
- emplaceBack(v0: number, v1: number, v2: number, v3: number, v4: number, v5: number): number {
+ override emplaceBack(v0: number, v1: number, v2: number, v3: number, v4: number, v5: number): number {
const i = this.length;
this.resize(i + 1);
return this.emplace(i, v0, v1, v2, v3, v4, v5);
}
- emplace(i: number, v0: number, v1: number, v2: number, v3: number, v4: number, v5: number): number {
+ override emplace(i: number, v0: number, v1: number, v2: number, v3: number, v4: number, v5: number): number {
const o2 = i * 6;
this.int16[o2 + 0] = v0;
this.int16[o2 + 1] = v1;
@@ -369,23 +369,23 @@ register(StructArrayLayout6i12, 'StructArrayLayout6i12');
* @private
*/
class StructArrayLayout4i4ui4i24 extends StructArray implements IStructArrayLayout {
- uint8: Uint8Array;
- int16: Int16Array;
- uint16: Uint16Array;
+ override uint8: Uint8Array;
+ override int16: Int16Array;
+ override uint16: Uint16Array;
- _refreshViews() {
+ override _refreshViews() {
this.uint8 = new Uint8Array(this.arrayBuffer);
this.int16 = new Int16Array(this.arrayBuffer);
this.uint16 = new Uint16Array(this.arrayBuffer);
}
- emplaceBack(v0: number, v1: number, v2: number, v3: number, v4: number, v5: number, v6: number, v7: number, v8: number, v9: number, v10: number, v11: number): number {
+ override emplaceBack(v0: number, v1: number, v2: number, v3: number, v4: number, v5: number, v6: number, v7: number, v8: number, v9: number, v10: number, v11: number): number {
const i = this.length;
this.resize(i + 1);
return this.emplace(i, v0, v1, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11);
}
- emplace(i: number, v0: number, v1: number, v2: number, v3: number, v4: number, v5: number, v6: number, v7: number, v8: number, v9: number, v10: number, v11: number): number {
+ override emplace(i: number, v0: number, v1: number, v2: number, v3: number, v4: number, v5: number, v6: number, v7: number, v8: number, v9: number, v10: number, v11: number): number {
const o2 = i * 12;
this.int16[o2 + 0] = v0;
this.int16[o2 + 1] = v1;
@@ -414,23 +414,23 @@ register(StructArrayLayout4i4ui4i24, 'StructArrayLayout4i4ui4i24');
* @private
*/
class StructArrayLayout3i3f20 extends StructArray implements IStructArrayLayout {
- uint8: Uint8Array;
- int16: Int16Array;
- float32: Float32Array;
+ override uint8: Uint8Array;
+ override int16: Int16Array;
+ override float32: Float32Array;
- _refreshViews() {
+ override _refreshViews() {
this.uint8 = new Uint8Array(this.arrayBuffer);
this.int16 = new Int16Array(this.arrayBuffer);
this.float32 = new Float32Array(this.arrayBuffer);
}
- emplaceBack(v0: number, v1: number, v2: number, v3: number, v4: number, v5: number): number {
+ override emplaceBack(v0: number, v1: number, v2: number, v3: number, v4: number, v5: number): number {
const i = this.length;
this.resize(i + 1);
return this.emplace(i, v0, v1, v2, v3, v4, v5);
}
- emplace(i: number, v0: number, v1: number, v2: number, v3: number, v4: number, v5: number): number {
+ override emplace(i: number, v0: number, v1: number, v2: number, v3: number, v4: number, v5: number): number {
const o2 = i * 10;
const o4 = i * 5;
this.int16[o2 + 0] = v0;
@@ -453,21 +453,21 @@ register(StructArrayLayout3i3f20, 'StructArrayLayout3i3f20');
* @private
*/
class StructArrayLayout1ul4 extends StructArray implements IStructArrayLayout {
- uint8: Uint8Array;
- uint32: Uint32Array;
+ override uint8: Uint8Array;
+ override uint32: Uint32Array;
- _refreshViews() {
+ override _refreshViews() {
this.uint8 = new Uint8Array(this.arrayBuffer);
this.uint32 = new Uint32Array(this.arrayBuffer);
}
- emplaceBack(v0: number): number {
+ override emplaceBack(v0: number): number {
const i = this.length;
this.resize(i + 1);
return this.emplace(i, v0);
}
- emplace(i: number, v0: number): number {
+ override emplace(i: number, v0: number): number {
const o4 = i * 1;
this.uint32[o4 + 0] = v0;
return i;
@@ -484,21 +484,21 @@ register(StructArrayLayout1ul4, 'StructArrayLayout1ul4');
* @private
*/
class StructArrayLayout2ui4 extends StructArray implements IStructArrayLayout {
- uint8: Uint8Array;
- uint16: Uint16Array;
+ override uint8: Uint8Array;
+ override uint16: Uint16Array;
- _refreshViews() {
+ override _refreshViews() {
this.uint8 = new Uint8Array(this.arrayBuffer);
this.uint16 = new Uint16Array(this.arrayBuffer);
}
- emplaceBack(v0: number, v1: number): number {
+ override emplaceBack(v0: number, v1: number): number {
const i = this.length;
this.resize(i + 1);
return this.emplace(i, v0, v1);
}
- emplace(i: number, v0: number, v1: number): number {
+ override emplace(i: number, v0: number, v1: number): number {
const o2 = i * 2;
this.uint16[o2 + 0] = v0;
this.uint16[o2 + 1] = v1;
@@ -520,13 +520,13 @@ register(StructArrayLayout2ui4, 'StructArrayLayout2ui4');
* @private
*/
class StructArrayLayout5i4f1i1ul2ui40 extends StructArray implements IStructArrayLayout {
- uint8: Uint8Array;
- int16: Int16Array;
- float32: Float32Array;
- uint32: Uint32Array;
- uint16: Uint16Array;
+ override uint8: Uint8Array;
+ override int16: Int16Array;
+ override float32: Float32Array;
+ override uint32: Uint32Array;
+ override uint16: Uint16Array;
- _refreshViews() {
+ override _refreshViews() {
this.uint8 = new Uint8Array(this.arrayBuffer);
this.int16 = new Int16Array(this.arrayBuffer);
this.float32 = new Float32Array(this.arrayBuffer);
@@ -534,13 +534,13 @@ class StructArrayLayout5i4f1i1ul2ui40 extends StructArray implements IStructArra
this.uint16 = new Uint16Array(this.arrayBuffer);
}
- emplaceBack(v0: number, v1: number, v2: number, v3: number, v4: number, v5: number, v6: number, v7: number, v8: number, v9: number, v10: number, v11: number, v12: number): number {
+ override emplaceBack(v0: number, v1: number, v2: number, v3: number, v4: number, v5: number, v6: number, v7: number, v8: number, v9: number, v10: number, v11: number, v12: number): number {
const i = this.length;
this.resize(i + 1);
return this.emplace(i, v0, v1, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12);
}
- emplace(i: number, v0: number, v1: number, v2: number, v3: number, v4: number, v5: number, v6: number, v7: number, v8: number, v9: number, v10: number, v11: number, v12: number): number {
+ override emplace(i: number, v0: number, v1: number, v2: number, v3: number, v4: number, v5: number, v6: number, v7: number, v8: number, v9: number, v10: number, v11: number, v12: number): number {
const o2 = i * 20;
const o4 = i * 10;
this.int16[o2 + 0] = v0;
@@ -572,21 +572,21 @@ register(StructArrayLayout5i4f1i1ul2ui40, 'StructArrayLayout5i4f1i1ul2ui40');
* @private
*/
class StructArrayLayout3i2i2i16 extends StructArray implements IStructArrayLayout {
- uint8: Uint8Array;
- int16: Int16Array;
+ override uint8: Uint8Array;
+ override int16: Int16Array;
- _refreshViews() {
+ override _refreshViews() {
this.uint8 = new Uint8Array(this.arrayBuffer);
this.int16 = new Int16Array(this.arrayBuffer);
}
- emplaceBack(v0: number, v1: number, v2: number, v3: number, v4: number, v5: number, v6: number): number {
+ override emplaceBack(v0: number, v1: number, v2: number, v3: number, v4: number, v5: number, v6: number): number {
const i = this.length;
this.resize(i + 1);
return this.emplace(i, v0, v1, v2, v3, v4, v5, v6);
}
- emplace(i: number, v0: number, v1: number, v2: number, v3: number, v4: number, v5: number, v6: number): number {
+ override emplace(i: number, v0: number, v1: number, v2: number, v3: number, v4: number, v5: number, v6: number): number {
const o2 = i * 8;
this.int16[o2 + 0] = v0;
this.int16[o2 + 1] = v1;
@@ -611,23 +611,23 @@ register(StructArrayLayout3i2i2i16, 'StructArrayLayout3i2i2i16');
* @private
*/
class StructArrayLayout2f1f2i16 extends StructArray implements IStructArrayLayout {
- uint8: Uint8Array;
- float32: Float32Array;
- int16: Int16Array;
+ override uint8: Uint8Array;
+ override float32: Float32Array;
+ override int16: Int16Array;
- _refreshViews() {
+ override _refreshViews() {
this.uint8 = new Uint8Array(this.arrayBuffer);
this.float32 = new Float32Array(this.arrayBuffer);
this.int16 = new Int16Array(this.arrayBuffer);
}
- emplaceBack(v0: number, v1: number, v2: number, v3: number, v4: number): number {
+ override emplaceBack(v0: number, v1: number, v2: number, v3: number, v4: number): number {
const i = this.length;
this.resize(i + 1);
return this.emplace(i, v0, v1, v2, v3, v4);
}
- emplace(i: number, v0: number, v1: number, v2: number, v3: number, v4: number): number {
+ override emplace(i: number, v0: number, v1: number, v2: number, v3: number, v4: number): number {
const o4 = i * 4;
const o2 = i * 8;
this.float32[o4 + 0] = v0;
@@ -650,21 +650,21 @@ register(StructArrayLayout2f1f2i16, 'StructArrayLayout2f1f2i16');
* @private
*/
class StructArrayLayout2ub4f20 extends StructArray implements IStructArrayLayout {
- uint8: Uint8Array;
- float32: Float32Array;
+ override uint8: Uint8Array;
+ override float32: Float32Array;
- _refreshViews() {
+ override _refreshViews() {
this.uint8 = new Uint8Array(this.arrayBuffer);
this.float32 = new Float32Array(this.arrayBuffer);
}
- emplaceBack(v0: number, v1: number, v2: number, v3: number, v4: number, v5: number): number {
+ override emplaceBack(v0: number, v1: number, v2: number, v3: number, v4: number, v5: number): number {
const i = this.length;
this.resize(i + 1);
return this.emplace(i, v0, v1, v2, v3, v4, v5);
}
- emplace(i: number, v0: number, v1: number, v2: number, v3: number, v4: number, v5: number): number {
+ override emplace(i: number, v0: number, v1: number, v2: number, v3: number, v4: number, v5: number): number {
const o1 = i * 20;
const o4 = i * 5;
this.uint8[o1 + 0] = v0;
@@ -687,21 +687,21 @@ register(StructArrayLayout2ub4f20, 'StructArrayLayout2ub4f20');
* @private
*/
class StructArrayLayout3ui6 extends StructArray implements IStructArrayLayout {
- uint8: Uint8Array;
- uint16: Uint16Array;
+ override uint8: Uint8Array;
+ override uint16: Uint16Array;
- _refreshViews() {
+ override _refreshViews() {
this.uint8 = new Uint8Array(this.arrayBuffer);
this.uint16 = new Uint16Array(this.arrayBuffer);
}
- emplaceBack(v0: number, v1: number, v2: number): number {
+ override emplaceBack(v0: number, v1: number, v2: number): number {
const i = this.length;
this.resize(i + 1);
return this.emplace(i, v0, v1, v2);
}
- emplace(i: number, v0: number, v1: number, v2: number): number {
+ override emplace(i: number, v0: number, v1: number, v2: number): number {
const o2 = i * 3;
this.uint16[o2 + 0] = v0;
this.uint16[o2 + 1] = v1;
@@ -729,13 +729,13 @@ register(StructArrayLayout3ui6, 'StructArrayLayout3ui6');
* @private
*/
class StructArrayLayout3i2f2ui3ul3ui2f3ub1ul1i1ub60 extends StructArray implements IStructArrayLayout {
- uint8: Uint8Array;
- int16: Int16Array;
- float32: Float32Array;
- uint16: Uint16Array;
- uint32: Uint32Array;
+ override uint8: Uint8Array;
+ override int16: Int16Array;
+ override float32: Float32Array;
+ override uint16: Uint16Array;
+ override uint32: Uint32Array;
- _refreshViews() {
+ override _refreshViews() {
this.uint8 = new Uint8Array(this.arrayBuffer);
this.int16 = new Int16Array(this.arrayBuffer);
this.float32 = new Float32Array(this.arrayBuffer);
@@ -743,13 +743,13 @@ class StructArrayLayout3i2f2ui3ul3ui2f3ub1ul1i1ub60 extends StructArray implemen
this.uint32 = new Uint32Array(this.arrayBuffer);
}
- emplaceBack(v0: number, v1: number, v2: number, v3: number, v4: number, v5: number, v6: number, v7: number, v8: number, v9: number, v10: number, v11: number, v12: number, v13: number, v14: number, v15: number, v16: number, v17: number, v18: number, v19: number, v20: number): number {
+ override emplaceBack(v0: number, v1: number, v2: number, v3: number, v4: number, v5: number, v6: number, v7: number, v8: number, v9: number, v10: number, v11: number, v12: number, v13: number, v14: number, v15: number, v16: number, v17: number, v18: number, v19: number, v20: number): number {
const i = this.length;
this.resize(i + 1);
return this.emplace(i, v0, v1, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20);
}
- emplace(i: number, v0: number, v1: number, v2: number, v3: number, v4: number, v5: number, v6: number, v7: number, v8: number, v9: number, v10: number, v11: number, v12: number, v13: number, v14: number, v15: number, v16: number, v17: number, v18: number, v19: number, v20: number): number {
+ override emplace(i: number, v0: number, v1: number, v2: number, v3: number, v4: number, v5: number, v6: number, v7: number, v8: number, v9: number, v10: number, v11: number, v12: number, v13: number, v14: number, v15: number, v16: number, v17: number, v18: number, v19: number, v20: number): number {
const o2 = i * 30;
const o4 = i * 15;
const o1 = i * 60;
@@ -793,13 +793,13 @@ register(StructArrayLayout3i2f2ui3ul3ui2f3ub1ul1i1ub60, 'StructArrayLayout3i2f2u
* @private
*/
class StructArrayLayout2f9i15ui1ul4f1ub80 extends StructArray implements IStructArrayLayout {
- uint8: Uint8Array;
- float32: Float32Array;
- int16: Int16Array;
- uint16: Uint16Array;
- uint32: Uint32Array;
+ override uint8: Uint8Array;
+ override float32: Float32Array;
+ override int16: Int16Array;
+ override uint16: Uint16Array;
+ override uint32: Uint32Array;
- _refreshViews() {
+ override _refreshViews() {
this.uint8 = new Uint8Array(this.arrayBuffer);
this.float32 = new Float32Array(this.arrayBuffer);
this.int16 = new Int16Array(this.arrayBuffer);
@@ -807,13 +807,13 @@ class StructArrayLayout2f9i15ui1ul4f1ub80 extends StructArray implements IStruct
this.uint32 = new Uint32Array(this.arrayBuffer);
}
- emplaceBack(v0: number, v1: number, v2: number, v3: number, v4: number, v5: number, v6: number, v7: number, v8: number, v9: number, v10: number, v11: number, v12: number, v13: number, v14: number, v15: number, v16: number, v17: number, v18: number, v19: number, v20: number, v21: number, v22: number, v23: number, v24: number, v25: number, v26: number, v27: number, v28: number, v29: number, v30: number, v31: number): number {
+ override emplaceBack(v0: number, v1: number, v2: number, v3: number, v4: number, v5: number, v6: number, v7: number, v8: number, v9: number, v10: number, v11: number, v12: number, v13: number, v14: number, v15: number, v16: number, v17: number, v18: number, v19: number, v20: number, v21: number, v22: number, v23: number, v24: number, v25: number, v26: number, v27: number, v28: number, v29: number, v30: number, v31: number): number {
const i = this.length;
this.resize(i + 1);
return this.emplace(i, v0, v1, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20, v21, v22, v23, v24, v25, v26, v27, v28, v29, v30, v31);
}
- emplace(i: number, v0: number, v1: number, v2: number, v3: number, v4: number, v5: number, v6: number, v7: number, v8: number, v9: number, v10: number, v11: number, v12: number, v13: number, v14: number, v15: number, v16: number, v17: number, v18: number, v19: number, v20: number, v21: number, v22: number, v23: number, v24: number, v25: number, v26: number, v27: number, v28: number, v29: number, v30: number, v31: number): number {
+ override emplace(i: number, v0: number, v1: number, v2: number, v3: number, v4: number, v5: number, v6: number, v7: number, v8: number, v9: number, v10: number, v11: number, v12: number, v13: number, v14: number, v15: number, v16: number, v17: number, v18: number, v19: number, v20: number, v21: number, v22: number, v23: number, v24: number, v25: number, v26: number, v27: number, v28: number, v29: number, v30: number, v31: number): number {
const o4 = i * 20;
const o2 = i * 40;
const o1 = i * 80;
@@ -863,21 +863,21 @@ register(StructArrayLayout2f9i15ui1ul4f1ub80, 'StructArrayLayout2f9i15ui1ul4f1ub
* @private
*/
class StructArrayLayout1f4 extends StructArray implements IStructArrayLayout {
- uint8: Uint8Array;
- float32: Float32Array;
+ override uint8: Uint8Array;
+ override float32: Float32Array;
- _refreshViews() {
+ override _refreshViews() {
this.uint8 = new Uint8Array(this.arrayBuffer);
this.float32 = new Float32Array(this.arrayBuffer);
}
- emplaceBack(v0: number): number {
+ override emplaceBack(v0: number): number {
const i = this.length;
this.resize(i + 1);
return this.emplace(i, v0);
}
- emplace(i: number, v0: number): number {
+ override emplace(i: number, v0: number): number {
const o4 = i * 1;
this.float32[o4 + 0] = v0;
return i;
@@ -894,21 +894,21 @@ register(StructArrayLayout1f4, 'StructArrayLayout1f4');
* @private
*/
class StructArrayLayout5f20 extends StructArray implements IStructArrayLayout {
- uint8: Uint8Array;
- float32: Float32Array;
+ override uint8: Uint8Array;
+ override float32: Float32Array;
- _refreshViews() {
+ override _refreshViews() {
this.uint8 = new Uint8Array(this.arrayBuffer);
this.float32 = new Float32Array(this.arrayBuffer);
}
- emplaceBack(v0: number, v1: number, v2: number, v3: number, v4: number): number {
+ override emplaceBack(v0: number, v1: number, v2: number, v3: number, v4: number): number {
const i = this.length;
this.resize(i + 1);
return this.emplace(i, v0, v1, v2, v3, v4);
}
- emplace(i: number, v0: number, v1: number, v2: number, v3: number, v4: number): number {
+ override emplace(i: number, v0: number, v1: number, v2: number, v3: number, v4: number): number {
const o4 = i * 5;
this.float32[o4 + 0] = v0;
this.float32[o4 + 1] = v1;
@@ -929,21 +929,21 @@ register(StructArrayLayout5f20, 'StructArrayLayout5f20');
* @private
*/
class StructArrayLayout7f28 extends StructArray implements IStructArrayLayout {
- uint8: Uint8Array;
- float32: Float32Array;
+ override uint8: Uint8Array;
+ override float32: Float32Array;
- _refreshViews() {
+ override _refreshViews() {
this.uint8 = new Uint8Array(this.arrayBuffer);
this.float32 = new Float32Array(this.arrayBuffer);
}
- emplaceBack(v0: number, v1: number, v2: number, v3: number, v4: number, v5: number, v6: number): number {
+ override emplaceBack(v0: number, v1: number, v2: number, v3: number, v4: number, v5: number, v6: number): number {
const i = this.length;
this.resize(i + 1);
return this.emplace(i, v0, v1, v2, v3, v4, v5, v6);
}
- emplace(i: number, v0: number, v1: number, v2: number, v3: number, v4: number, v5: number, v6: number): number {
+ override emplace(i: number, v0: number, v1: number, v2: number, v3: number, v4: number, v5: number, v6: number): number {
const o4 = i * 7;
this.float32[o4 + 0] = v0;
this.float32[o4 + 1] = v1;
@@ -959,6 +959,86 @@ class StructArrayLayout7f28 extends StructArray implements IStructArrayLayout {
StructArrayLayout7f28.prototype.bytesPerElement = 28;
register(StructArrayLayout7f28, 'StructArrayLayout7f28');
+/**
+ * Implementation of the StructArray layout:
+ * [0]: Float32[11]
+ *
+ * @private
+ */
+class StructArrayLayout11f44 extends StructArray implements IStructArrayLayout {
+ override uint8: Uint8Array;
+ override float32: Float32Array;
+
+ override _refreshViews() {
+ this.uint8 = new Uint8Array(this.arrayBuffer);
+ this.float32 = new Float32Array(this.arrayBuffer);
+ }
+
+ override emplaceBack(v0: number, v1: number, v2: number, v3: number, v4: number, v5: number, v6: number, v7: number, v8: number, v9: number, v10: number): number {
+ const i = this.length;
+ this.resize(i + 1);
+ return this.emplace(i, v0, v1, v2, v3, v4, v5, v6, v7, v8, v9, v10);
+ }
+
+ override emplace(i: number, v0: number, v1: number, v2: number, v3: number, v4: number, v5: number, v6: number, v7: number, v8: number, v9: number, v10: number): number {
+ const o4 = i * 11;
+ this.float32[o4 + 0] = v0;
+ this.float32[o4 + 1] = v1;
+ this.float32[o4 + 2] = v2;
+ this.float32[o4 + 3] = v3;
+ this.float32[o4 + 4] = v4;
+ this.float32[o4 + 5] = v5;
+ this.float32[o4 + 6] = v6;
+ this.float32[o4 + 7] = v7;
+ this.float32[o4 + 8] = v8;
+ this.float32[o4 + 9] = v9;
+ this.float32[o4 + 10] = v10;
+ return i;
+ }
+}
+
+StructArrayLayout11f44.prototype.bytesPerElement = 44;
+register(StructArrayLayout11f44, 'StructArrayLayout11f44');
+
+/**
+ * Implementation of the StructArray layout:
+ * [0]: Float32[9]
+ *
+ * @private
+ */
+class StructArrayLayout9f36 extends StructArray implements IStructArrayLayout {
+ override uint8: Uint8Array;
+ override float32: Float32Array;
+
+ override _refreshViews() {
+ this.uint8 = new Uint8Array(this.arrayBuffer);
+ this.float32 = new Float32Array(this.arrayBuffer);
+ }
+
+ override emplaceBack(v0: number, v1: number, v2: number, v3: number, v4: number, v5: number, v6: number, v7: number, v8: number): number {
+ const i = this.length;
+ this.resize(i + 1);
+ return this.emplace(i, v0, v1, v2, v3, v4, v5, v6, v7, v8);
+ }
+
+ override emplace(i: number, v0: number, v1: number, v2: number, v3: number, v4: number, v5: number, v6: number, v7: number, v8: number): number {
+ const o4 = i * 9;
+ this.float32[o4 + 0] = v0;
+ this.float32[o4 + 1] = v1;
+ this.float32[o4 + 2] = v2;
+ this.float32[o4 + 3] = v3;
+ this.float32[o4 + 4] = v4;
+ this.float32[o4 + 5] = v5;
+ this.float32[o4 + 6] = v6;
+ this.float32[o4 + 7] = v7;
+ this.float32[o4 + 8] = v8;
+ return i;
+ }
+}
+
+StructArrayLayout9f36.prototype.bytesPerElement = 36;
+register(StructArrayLayout9f36, 'StructArrayLayout9f36');
+
/**
* Implementation of the StructArray layout:
* [0]: Uint32[1]
@@ -967,23 +1047,23 @@ register(StructArrayLayout7f28, 'StructArrayLayout7f28');
* @private
*/
class StructArrayLayout1ul3ui12 extends StructArray implements IStructArrayLayout {
- uint8: Uint8Array;
- uint32: Uint32Array;
- uint16: Uint16Array;
+ override uint8: Uint8Array;
+ override uint32: Uint32Array;
+ override uint16: Uint16Array;
- _refreshViews() {
+ override _refreshViews() {
this.uint8 = new Uint8Array(this.arrayBuffer);
this.uint32 = new Uint32Array(this.arrayBuffer);
this.uint16 = new Uint16Array(this.arrayBuffer);
}
- emplaceBack(v0: number, v1: number, v2: number, v3: number): number {
+ override emplaceBack(v0: number, v1: number, v2: number, v3: number): number {
const i = this.length;
this.resize(i + 1);
return this.emplace(i, v0, v1, v2, v3);
}
- emplace(i: number, v0: number, v1: number, v2: number, v3: number): number {
+ override emplace(i: number, v0: number, v1: number, v2: number, v3: number): number {
const o4 = i * 3;
const o2 = i * 6;
this.uint32[o4 + 0] = v0;
@@ -1004,21 +1084,21 @@ register(StructArrayLayout1ul3ui12, 'StructArrayLayout1ul3ui12');
* @private
*/
class StructArrayLayout1ui2 extends StructArray implements IStructArrayLayout {
- uint8: Uint8Array;
- uint16: Uint16Array;
+ override uint8: Uint8Array;
+ override uint16: Uint16Array;
- _refreshViews() {
+ override _refreshViews() {
this.uint8 = new Uint8Array(this.arrayBuffer);
this.uint16 = new Uint16Array(this.arrayBuffer);
}
- emplaceBack(v0: number): number {
+ override emplaceBack(v0: number): number {
const i = this.length;
this.resize(i + 1);
return this.emplace(i, v0);
}
- emplace(i: number, v0: number): number {
+ override emplace(i: number, v0: number): number {
const o2 = i * 1;
this.uint16[o2 + 0] = v0;
return i;
@@ -1035,21 +1115,21 @@ register(StructArrayLayout1ui2, 'StructArrayLayout1ui2');
* @private
*/
class StructArrayLayout2f8 extends StructArray implements IStructArrayLayout {
- uint8: Uint8Array;
- float32: Float32Array;
+ override uint8: Uint8Array;
+ override float32: Float32Array;
- _refreshViews() {
+ override _refreshViews() {
this.uint8 = new Uint8Array(this.arrayBuffer);
this.float32 = new Float32Array(this.arrayBuffer);
}
- emplaceBack(v0: number, v1: number): number {
+ override emplaceBack(v0: number, v1: number): number {
const i = this.length;
this.resize(i + 1);
return this.emplace(i, v0, v1);
}
- emplace(i: number, v0: number, v1: number): number {
+ override emplace(i: number, v0: number, v1: number): number {
const o4 = i * 2;
this.float32[o4 + 0] = v0;
this.float32[o4 + 1] = v1;
@@ -1067,21 +1147,21 @@ register(StructArrayLayout2f8, 'StructArrayLayout2f8');
* @private
*/
class StructArrayLayout16f64 extends StructArray implements IStructArrayLayout {
- uint8: Uint8Array;
- float32: Float32Array;
+ override uint8: Uint8Array;
+ override float32: Float32Array;
- _refreshViews() {
+ override _refreshViews() {
this.uint8 = new Uint8Array(this.arrayBuffer);
this.float32 = new Float32Array(this.arrayBuffer);
}
- emplaceBack(v0: number, v1: number, v2: number, v3: number, v4: number, v5: number, v6: number, v7: number, v8: number, v9: number, v10: number, v11: number, v12: number, v13: number, v14: number, v15: number): number {
+ override emplaceBack(v0: number, v1: number, v2: number, v3: number, v4: number, v5: number, v6: number, v7: number, v8: number, v9: number, v10: number, v11: number, v12: number, v13: number, v14: number, v15: number): number {
const i = this.length;
this.resize(i + 1);
return this.emplace(i, v0, v1, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15);
}
- emplace(i: number, v0: number, v1: number, v2: number, v3: number, v4: number, v5: number, v6: number, v7: number, v8: number, v9: number, v10: number, v11: number, v12: number, v13: number, v14: number, v15: number): number {
+ override emplace(i: number, v0: number, v1: number, v2: number, v3: number, v4: number, v5: number, v6: number, v7: number, v8: number, v9: number, v10: number, v11: number, v12: number, v13: number, v14: number, v15: number): number {
const o4 = i * 16;
this.float32[o4 + 0] = v0;
this.float32[o4 + 1] = v1;
@@ -1114,23 +1194,23 @@ register(StructArrayLayout16f64, 'StructArrayLayout16f64');
* @private
*/
class StructArrayLayout4ui3f20 extends StructArray implements IStructArrayLayout {
- uint8: Uint8Array;
- uint16: Uint16Array;
- float32: Float32Array;
+ override uint8: Uint8Array;
+ override uint16: Uint16Array;
+ override float32: Float32Array;
- _refreshViews() {
+ override _refreshViews() {
this.uint8 = new Uint8Array(this.arrayBuffer);
this.uint16 = new Uint16Array(this.arrayBuffer);
this.float32 = new Float32Array(this.arrayBuffer);
}
- emplaceBack(v0: number, v1: number, v2: number, v3: number, v4: number, v5: number, v6: number): number {
+ override emplaceBack(v0: number, v1: number, v2: number, v3: number, v4: number, v5: number, v6: number): number {
const i = this.length;
this.resize(i + 1);
return this.emplace(i, v0, v1, v2, v3, v4, v5, v6);
}
- emplace(i: number, v0: number, v1: number, v2: number, v3: number, v4: number, v5: number, v6: number): number {
+ override emplace(i: number, v0: number, v1: number, v2: number, v3: number, v4: number, v5: number, v6: number): number {
const o2 = i * 10;
const o4 = i * 5;
this.uint16[o2 + 0] = v0;
@@ -1154,21 +1234,21 @@ register(StructArrayLayout4ui3f20, 'StructArrayLayout4ui3f20');
* @private
*/
class StructArrayLayout1i2 extends StructArray implements IStructArrayLayout {
- uint8: Uint8Array;
- int16: Int16Array;
+ override uint8: Uint8Array;
+ override int16: Int16Array;
- _refreshViews() {
+ override _refreshViews() {
this.uint8 = new Uint8Array(this.arrayBuffer);
this.int16 = new Int16Array(this.arrayBuffer);
}
- emplaceBack(v0: number): number {
+ override emplaceBack(v0: number): number {
const i = this.length;
this.resize(i + 1);
return this.emplace(i, v0);
}
- emplace(i: number, v0: number): number {
+ override emplace(i: number, v0: number): number {
const o2 = i * 1;
this.int16[o2 + 0] = v0;
return i;
@@ -1185,19 +1265,19 @@ register(StructArrayLayout1i2, 'StructArrayLayout1i2');
* @private
*/
class StructArrayLayout1ub1 extends StructArray implements IStructArrayLayout {
- uint8: Uint8Array;
+ override uint8: Uint8Array;
- _refreshViews() {
+ override _refreshViews() {
this.uint8 = new Uint8Array(this.arrayBuffer);
}
- emplaceBack(v0: number): number {
+ override emplaceBack(v0: number): number {
const i = this.length;
this.resize(i + 1);
return this.emplace(i, v0);
}
- emplace(i: number, v0: number): number {
+ override emplace(i: number, v0: number): number {
const o1 = i * 1;
this.uint8[o1 + 0] = v0;
return i;
@@ -1208,7 +1288,7 @@ StructArrayLayout1ub1.prototype.bytesPerElement = 1;
register(StructArrayLayout1ub1, 'StructArrayLayout1ub1');
class CollisionBoxStruct extends Struct {
- _structArray: CollisionBoxArray;
+ override _structArray: CollisionBoxArray;
get projectedAnchorX(): number { return this._structArray.int16[this._pos2 + 0]; }
get projectedAnchorY(): number { return this._structArray.int16[this._pos2 + 1]; }
get projectedAnchorZ(): number { return this._structArray.int16[this._pos2 + 2]; }
@@ -1248,7 +1328,7 @@ export class CollisionBoxArray extends StructArrayLayout5i4f1i1ul2ui40 {
register(CollisionBoxArray, 'CollisionBoxArray');
class PlacedSymbolStruct extends Struct {
- _structArray: PlacedSymbolArray;
+ override _structArray: PlacedSymbolArray;
get projectedAnchorX(): number { return this._structArray.int16[this._pos2 + 0]; }
get projectedAnchorY(): number { return this._structArray.int16[this._pos2 + 1]; }
get projectedAnchorZ(): number { return this._structArray.int16[this._pos2 + 2]; }
@@ -1300,7 +1380,7 @@ export class PlacedSymbolArray extends StructArrayLayout3i2f2ui3ul3ui2f3ub1ul1i1
register(PlacedSymbolArray, 'PlacedSymbolArray');
class SymbolInstanceStruct extends Struct {
- _structArray: SymbolInstanceArray;
+ override _structArray: SymbolInstanceArray;
get tileAnchorX(): number { return this._structArray.float32[this._pos4 + 0]; }
get tileAnchorY(): number { return this._structArray.float32[this._pos4 + 1]; }
get projectedAnchorX(): number { return this._structArray.int16[this._pos2 + 4]; }
@@ -1380,7 +1460,7 @@ export class SymbolLineVertexArray extends StructArrayLayout2i4 {
register(SymbolLineVertexArray, 'SymbolLineVertexArray');
class FeatureIndexStruct extends Struct {
- _structArray: FeatureIndexArray;
+ override _structArray: FeatureIndexArray;
get featureIndex(): number { return this._structArray.uint32[this._pos4 + 0]; }
get sourceLayerIndex(): number { return this._structArray.uint16[this._pos2 + 2]; }
get bucketIndex(): number { return this._structArray.uint16[this._pos2 + 3]; }
@@ -1421,7 +1501,7 @@ export class FillExtrusionCentroidArray extends StructArrayLayout2ui4 {
register(FillExtrusionCentroidArray, 'FillExtrusionCentroidArray');
class FillExtrusionWallStruct extends Struct {
- _structArray: FillExtrusionWallArray;
+ override _structArray: FillExtrusionWallArray;
get a_join_normal_inside0(): number { return this._structArray.int16[this._pos2 + 0]; }
get a_join_normal_inside1(): number { return this._structArray.int16[this._pos2 + 1]; }
get a_join_normal_inside2(): number { return this._structArray.int16[this._pos2 + 2]; }
@@ -1475,6 +1555,8 @@ export {
StructArrayLayout1f4,
StructArrayLayout5f20,
StructArrayLayout7f28,
+ StructArrayLayout11f44,
+ StructArrayLayout9f36,
StructArrayLayout1ul3ui12,
StructArrayLayout1ui2,
StructArrayLayout2f8,
@@ -1510,6 +1592,8 @@ export {
StructArrayLayout5f20 as GlobeVertexArray,
StructArrayLayout5f20 as AtmosphereVertexArray,
StructArrayLayout7f28 as StarsVertexArray,
+ StructArrayLayout11f44 as SnowVertexArray,
+ StructArrayLayout9f36 as RainVertexArray,
StructArrayLayout3ui6 as TriangleIndexArray,
StructArrayLayout2ui4 as LineIndexArray,
StructArrayLayout1ui2 as LineStripIndexArray,
diff --git a/src/data/bucket/fill_extrusion_bucket.ts b/src/data/bucket/fill_extrusion_bucket.ts
index e4f1c280fd2..f8f5e570582 100644
--- a/src/data/bucket/fill_extrusion_bucket.ts
+++ b/src/data/bucket/fill_extrusion_bucket.ts
@@ -35,7 +35,7 @@ import {dropBufferConnectionLines, createLineWallGeometry} from '../../geo/line_
import type {Elevation} from '../../terrain/elevation';
import type {Frustum} from '../../util/primitives';
-import type {ReplacementSource} from '../../../3d-style/source/replacement_source';
+import type {Region, ReplacementSource} from '../../../3d-style/source/replacement_source';
import type {Feature} from "../../style-spec/expression";
import type {ClippedPolygon} from '../../util/polygon_clipping';
import type {vec3} from 'gl-matrix';
@@ -672,7 +672,7 @@ class FillExtrusionBucket implements Bucket {
needsCentroidUpdate: boolean;
tileToMeter: number; // cache conversion.
projection: ProjectionSpecification;
- activeReplacements: Array;
+ activeReplacements: Array;
replacementUpdateTime: number;
groundEffect: GroundEffect;
@@ -1575,12 +1575,11 @@ class FillExtrusionBucket implements Bucket {
// Hide all centroids that are overlapping with footprints from the replacement source
for (const region of this.activeReplacements) {
- // if ((region.order < layerIndex) || (region.order !== ReplacementOrderLandmark && region.order > layerIndex && !(region.clipMask & LayerTypeMask.FillExtrusion))) continue;
if ((region.order < layerIndex)) continue; // fill-extrusions always get removed. This will be separated (similar to symbol and model) in future.
- // Apply slight padding (one unit) to fill extrusion footprints. This reduces false positives where
- // two adjacent lines would be reported overlapping due to limited precision (16 bit) of tile units.
- const padding = Math.pow(2.0, region.footprintTileId.canonical.z - coord.canonical.z);
+ // Apply slight padding to fill extrusion footprints. This reduces false positives where two adjacent lines
+ // would be reported overlapping due to limited precision (16 bit) of tile units.
+ const padding = Math.max(1.0, Math.pow(2.0, region.footprintTileId.canonical.z - coord.canonical.z));
for (const centroid of this.centroidData) {
if (centroid.flags & HIDDEN_BY_REPLACEMENT) {
diff --git a/src/data/bucket/heatmap_bucket.ts b/src/data/bucket/heatmap_bucket.ts
index 3d4a0e6c7e9..43e97656025 100644
--- a/src/data/bucket/heatmap_bucket.ts
+++ b/src/data/bucket/heatmap_bucket.ts
@@ -4,7 +4,7 @@ import {register} from '../../util/web_worker_transfer';
import type HeatmapStyleLayer from '../../style/style_layer/heatmap_style_layer';
class HeatmapBucket extends CircleBucket {
- layers: Array;
+ override layers: Array;
}
register(HeatmapBucket, 'HeatmapBucket', {omit: ['layers']});
diff --git a/src/data/bucket/line_bucket.ts b/src/data/bucket/line_bucket.ts
index 129b19e1dba..cd2c41f1f25 100644
--- a/src/data/bucket/line_bucket.ts
+++ b/src/data/bucket/line_bucket.ts
@@ -27,7 +27,6 @@ import '../../render/line_atlas';
import type {ProjectionSpecification} from '../../style-spec/types';
import type {CanonicalTileID, UnwrappedTileID} from '../../source/tile_id';
-import type Point from "@mapbox/point-geometry";
import type {
Bucket,
BucketParameters,
@@ -47,6 +46,8 @@ import type LineAtlas from '../../render/line_atlas';
import type {TileTransform} from '../../geo/projection/tile_transform';
import type {VectorTileLayer} from '@mapbox/vector-tile';
import type {TileFootprint} from '../../../3d-style/util/conflation';
+import type {PossiblyEvaluatedValue} from '../../style/properties';
+import type Point from "@mapbox/point-geometry";
// NOTE ON EXTRUDE SCALE:
// scale the extrusion vector so that the normal length is this value.
@@ -64,11 +65,8 @@ const EXTRUDE_SCALE = 63;
*
* COS_HALF_SHARP_CORNER controls how sharp a corner has to be for us to add an
* extra vertex. The default is 75 degrees.
- *
- * The newly created vertices are placed SHARP_CORNER_OFFSET pixels from the corner.
*/
const COS_HALF_SHARP_CORNER = Math.cos(75 / 2 * (Math.PI / 180));
-const SHARP_CORNER_OFFSET = 15;
/*
* Straight corners are used to reduce vertex count for line-join: none lines.
@@ -96,11 +94,15 @@ type GradientTexture = {
*/
class LineBucket implements Bucket {
distance: number;
+ prevDistance: number;
totalDistance: number;
+ totalFeatureLength: number;
maxLineLength: number;
scaledDistance: number;
lineSoFar: number;
lineClips: LineClips | null | undefined;
+ zOffsetValue: PossiblyEvaluatedValue;
+ lineFeature: BucketFeature;
e1: number;
e2: number;
@@ -138,6 +140,7 @@ class LineBucket implements Bucket {
hasPattern: boolean;
hasZOffset: boolean;
+ hasCrossSlope: boolean;
programConfigurations: ProgramConfigurationSet;
segments: SegmentVector;
uploaded: boolean;
@@ -146,8 +149,11 @@ class LineBucket implements Bucket {
currentVertexIsOutside: boolean;
tessellationStep: number;
+ evaluationGlobals = {'zoom': 0, 'lineProgress': undefined};
+
constructor(options: BucketParameters) {
this.zoom = options.zoom;
+ this.evaluationGlobals.zoom = this.zoom;
this.overscaling = options.overscaling;
this.layers = options.layers;
this.layerIds = this.layers.map(layer => layer.fqid);
@@ -155,6 +161,7 @@ class LineBucket implements Bucket {
this.projection = options.projection;
this.hasPattern = false;
this.hasZOffset = false;
+ this.hasCrossSlope = false;
this.patternFeatures = [];
this.lineClipsArray = [];
this.gradients = {};
@@ -184,9 +191,16 @@ class LineBucket implements Bucket {
populate(features: Array, options: PopulateParameters, canonical: CanonicalTileID, tileTransform: TileTransform) {
this.hasPattern = hasPattern('line', this.layers, options);
const lineSortKey = this.layers[0].layout.get('line-sort-key');
- const zOffset = this.layers[0].layout.get('line-z-offset');
- this.hasZOffset = !zOffset.isConstant() || !!zOffset.constantOr(0);
+ this.hasZOffset = !this.layers[0].isDraped();
+ const elevationReference = this.layers[0].layout.get('line-elevation-reference');
+ if (this.hasZOffset && elevationReference === 'none') {
+ warnOnce(`line-elevation-reference: ground is used for the layer ${this.layerIds[0]} because non-zero line-z-offset value was found.`);
+ }
+
+ const crossSlope = this.layers[0].layout.get('line-cross-slope');
+ this.hasCrossSlope = this.hasZOffset && crossSlope !== undefined;
+
const bucketFeatures = [];
for (const {feature, id, index, sourceLayerIndex} of features) {
@@ -197,7 +211,6 @@ class LineBucket implements Bucket {
continue;
const sortKey = lineSortKey ?
-
lineSortKey.evaluate(evaluationFeature, {}, canonical) :
undefined;
@@ -376,9 +389,10 @@ class LineBucket implements Bucket {
const miterLimit = layout.get('line-miter-limit');
const roundLimit = layout.get('line-round-limit');
this.lineClips = this.lineFeatureClips(feature);
+ this.lineFeature = feature;
+ this.zOffsetValue = layout.get('line-z-offset').value;
for (const line of geometry) {
-
this.addLine(line, feature, canonical, join, cap, miterLimit, roundLimit);
}
@@ -387,12 +401,12 @@ class LineBucket implements Bucket {
addLine(vertices: Array, feature: BucketFeature, canonical: CanonicalTileID, join: string, cap: string, miterLimit: number, roundLimit: number) {
this.distance = 0;
+ this.prevDistance = 0;
this.scaledDistance = 0;
this.totalDistance = 0;
+ this.totalFeatureLength = 0;
this.lineSoFar = 0;
this.currentVertex = undefined;
- const evaluationGlobals = {'zoom': this.zoom, 'lineProgress': undefined};
- const layout = this.layers[0].layout;
const joinNone = join === 'none';
this.patternJoinNone = this.hasPattern && joinNone;
@@ -406,6 +420,8 @@ class LineBucket implements Bucket {
for (let i = 0; i < vertices.length - 1; i++) {
this.totalDistance += vertices[i].dist(vertices[i + 1]);
}
+ const featureShare = this.lineClips.end - this.lineClips.start;
+ this.totalFeatureLength = this.totalDistance / featureShare;
this.updateScaledDistance();
this.maxLineLength = Math.max(this.maxLineLength, this.totalDistance);
}
@@ -427,10 +443,6 @@ class LineBucket implements Bucket {
if (join === 'bevel') miterLimit = 1.05;
- const sharpCornerOffset = this.overscaling <= 16 ?
- SHARP_CORNER_OFFSET * EXTENT / (512 * this.overscaling) :
- 0;
-
// we could be more precise, but it would only save a negligible amount of space
const segment = this.segments.prepareSegment(len * 10, this.layoutVertexArray, this.indexArray);
@@ -450,7 +462,6 @@ class LineBucket implements Bucket {
let fixedElevation: number | null | undefined;
for (let i = first; i < len; i++) {
-
nextVertex = i === len - 1 ?
(isPolygon ? vertices[first + 1] : (undefined as any)) : // if it's a polygon, treat the last vertex like the first
vertices[i + 1]; // just the next vertex
@@ -462,24 +473,7 @@ class LineBucket implements Bucket {
if (currentVertex) prevVertex = currentVertex;
currentVertex = vertices[i];
- if (this.hasZOffset) {
-
- const value = layout.get('line-z-offset').value;
- if (value.kind === 'constant') {
- fixedElevation = value.value;
- } else {
- if (this.lineClips) {
- const featureShare = this.lineClips.end - this.lineClips.start;
- const totalFeatureLength = this.totalDistance / featureShare;
- evaluationGlobals['lineProgress'] = (totalFeatureLength * this.lineClips.start + this.distance + (prevVertex ? prevVertex.dist(currentVertex) : 0)) / totalFeatureLength;
- } else {
- warnOnce(`line-z-offset evaluation for ${this.layerIds[0]} requires enabling 'lineMetrics' for the source.`);
- evaluationGlobals['lineProgress'] = 0;
- }
- fixedElevation = value.evaluate(evaluationGlobals, feature);
- }
- fixedElevation = fixedElevation || 0;
- }
+ fixedElevation = this.hasZOffset ? this.evaluateElevationValue(prevVertex ? prevVertex.dist(currentVertex) : 0) : null;
// Calculate the normal towards the next vertex in this line. In case
// there is no next vertex, pretend that the line is continuing straight,
@@ -573,22 +567,20 @@ class LineBucket implements Bucket {
const isSharpCorner = cosHalfAngle < COS_HALF_SHARP_CORNER && prevVertex && nextVertex;
const lineTurnsLeft = prevNormal.x * nextNormal.y - prevNormal.y * nextNormal.x > 0;
-
- if (isSharpCorner && i > first) {
- const prevSegmentLength = currentVertex.dist(prevVertex);
- if (prevSegmentLength > 2 * sharpCornerOffset) {
- const newPrevVertex = currentVertex.sub(currentVertex.sub(prevVertex)._mult(sharpCornerOffset / prevSegmentLength)._round());
- this.updateDistance(prevVertex, newPrevVertex);
- this.addCurrentVertex(newPrevVertex, prevNormal, 0, 0, segment, fixedElevation);
- prevVertex = newPrevVertex;
- }
- }
+ // Fixed offset from the corners to straighted up edges (require for pattern, gradient and trim-offset)
+ const SHARP_CORNER_OFFSET = 15;
+ const sharpCornerOffset = this.overscaling <= 16 ? SHARP_CORNER_OFFSET * EXTENT / (512 * this.overscaling) : 0;
if (middleVertex && currentJoin === 'round') {
if (miterLength < roundLimit) {
currentJoin = 'miter';
} else if (miterLength <= 2) {
- currentJoin = 'fakeround';
+ const boundsMin = -10;
+ const boundsMax = EXTENT + 10;
+ const outside = pointOutsideBounds(currentVertex, boundsMin, boundsMax);
+ // Disable 'fakeround' for line-z-offset when either outside tile bounds or when using line-cross-slope.
+ // In these cases, using 'fakeround' either causes some rendering artifacts or doesn't look good.
+ currentJoin = (this.hasZOffset && (outside || this.hasCrossSlope)) ? 'miter' : 'fakeround';
}
}
@@ -606,17 +598,36 @@ class LineBucket implements Bucket {
if (miterLength < miterLimit) currentJoin = 'miter';
}
+ const sharpMiter = currentJoin === 'miter' && isSharpCorner;
+
// Calculate how far along the line the currentVertex is
- if (prevVertex) this.updateDistance(prevVertex, currentVertex);
+ if (prevVertex && !sharpMiter) this.updateDistance(prevVertex, currentVertex);
if (currentJoin === 'miter') {
-
- joinNormal._mult(miterLength);
- this.addCurrentVertex(currentVertex, joinNormal, 0, 0, segment, fixedElevation);
-
+ if (isSharpCorner) {
+ const prevSegmentLength = currentVertex.dist(prevVertex);
+ if (prevSegmentLength > 2 * sharpCornerOffset) {
+ const newPrevVertex = currentVertex.sub(currentVertex.sub(prevVertex)._mult(sharpCornerOffset / prevSegmentLength)._round());
+ this.updateDistance(prevVertex, newPrevVertex);
+ this.addCurrentVertex(newPrevVertex, prevNormal, 0, 0, segment, fixedElevation);
+ prevVertex = newPrevVertex;
+ }
+ this.updateDistance(prevVertex, currentVertex);
+ joinNormal._mult(miterLength);
+ this.addCurrentVertex(currentVertex, joinNormal, 0, 0, segment, fixedElevation);
+ const nextSegmentLength = currentVertex.dist(nextVertex);
+ if (nextSegmentLength > 2 * sharpCornerOffset) {
+ const newCurrentVertex = currentVertex.add(nextVertex.sub(currentVertex)._mult(sharpCornerOffset / nextSegmentLength)._round());
+ this.updateDistance(currentVertex, newCurrentVertex);
+ this.addCurrentVertex(newCurrentVertex, nextNormal, 0, 0, segment, fixedElevation);
+ currentVertex = newCurrentVertex;
+ }
+ } else {
+ joinNormal._mult(miterLength);
+ this.addCurrentVertex(currentVertex, joinNormal, 0, 0, segment, fixedElevation);
+ }
} else if (currentJoin === 'flipbevel') {
// miter is too big, flip the direction to make a beveled join
-
if (miterLength > 100) {
// Almost parallel lines
joinNormal = nextNormal.mult(-1);
@@ -629,13 +640,26 @@ class LineBucket implements Bucket {
this.addCurrentVertex(currentVertex, joinNormal.mult(-1), 0, 0, segment, fixedElevation);
} else if (currentJoin === 'bevel' || currentJoin === 'fakeround') {
- const offset = -Math.sqrt(miterLength * miterLength - 1);
- const offsetA = lineTurnsLeft ? offset : 0;
- const offsetB = lineTurnsLeft ? 0 : offset;
+ if (fixedElevation != null && prevVertex) {
+ // Close previous segment with butt
+ this.addCurrentVertex(currentVertex, prevNormal, -1, -1, segment, fixedElevation);
+ }
- // Close previous segment with a bevel
- if (prevVertex) {
- this.addCurrentVertex(currentVertex, prevNormal, offsetA, offsetB, segment, fixedElevation);
+ const dist = currentVertex.dist(prevVertex);
+ const skipStraightEdges = dist <= 2 * sharpCornerOffset && currentJoin !== 'bevel';
+ const join = joinNormal.mult(lineTurnsLeft ? 1.0 : -1.0);
+ join._mult(miterLength);
+ const next = nextNormal.mult(lineTurnsLeft ? -1.0 : 1.0);
+ const prev = prevNormal.mult(lineTurnsLeft ? -1.0 : 1.0);
+ const z = this.evaluateElevationValue(this.distance);
+
+ if (fixedElevation == null) {
+ // This vertex is placed at the inner side of the corner
+ this.addHalfVertex(currentVertex, join.x, join.y, false, !lineTurnsLeft, 0, segment, z);
+ if (!skipStraightEdges) {
+ // This vertex is responsible to straighten up the line before the corner
+ this.addHalfVertex(currentVertex, join.x + prev.x * 2.0, join.y + prev.y * 2.0, false, lineTurnsLeft, 0, segment, z);
+ }
}
if (currentJoin === 'fakeround') {
@@ -647,7 +671,8 @@ class LineBucket implements Bucket {
// pick the number of triangles for approximating round join by based on the angle between normals
const n = Math.round((approxAngle * 180 / Math.PI) / DEG_PER_TRIANGLE);
- for (let m = 1; m < n; m++) {
+ this.addHalfVertex(currentVertex, prev.x, prev.y, false, lineTurnsLeft, 0, segment, z);
+ for (let m = 0; m < n; m++) {
let t = m / n;
if (t !== 0.5) {
// approximate spherical interpolation https://observablehq.com/@mourner/approximating-geometric-slerp
@@ -656,16 +681,22 @@ class LineBucket implements Bucket {
const B = 0.848013 + cosAngle * (-1.06021 + cosAngle * 0.215638);
t = t + t * t2 * (t - 1) * (A * t2 * t2 + B);
}
- const extrude = nextNormal.sub(prevNormal)._mult(t)._add(prevNormal)._unit()._mult(lineTurnsLeft ? -1 : 1);
- this.addHalfVertex(currentVertex, extrude.x, extrude.y, false, lineTurnsLeft, 0, segment, fixedElevation);
+ const extrude = next.sub(prev)._mult(t)._add(prev)._unit();
+ this.addHalfVertex(currentVertex, extrude.x, extrude.y, false, lineTurnsLeft, 0, segment, z);
}
+ // These vertices are placed on the outer side of the line
+ this.addHalfVertex(currentVertex, next.x, next.y, false, lineTurnsLeft, 0, segment, z);
}
- if (nextVertex) {
- // Start next segment
- this.addCurrentVertex(currentVertex, nextNormal, -offsetA, -offsetB, segment, fixedElevation);
+ if (!skipStraightEdges && fixedElevation == null) {
+ // This vertex is responsible to straighten up the line after the corner
+ this.addHalfVertex(currentVertex, join.x + next.x * 2.0, join.y + next.y * 2.0, false, lineTurnsLeft, 0, segment, z);
}
+ if (fixedElevation != null && nextVertex) {
+ // Start next segment with a butt
+ this.addCurrentVertex(currentVertex, nextNormal, 1, 1, segment, fixedElevation);
+ }
} else if (currentJoin === 'butt') {
this.addCurrentVertex(currentVertex, joinNormal, 0, 0, segment, fixedElevation); // butt cap
@@ -698,16 +729,6 @@ class LineBucket implements Bucket {
this.addCurrentVertex(currentVertex, nextNormal, 0, 0, segment, fixedElevation);
}
}
-
- if (isSharpCorner && i < len - 1) {
- const nextSegmentLength = currentVertex.dist(nextVertex);
- if (nextSegmentLength > 2 * sharpCornerOffset) {
- const newCurrentVertex = currentVertex.add(nextVertex.sub(currentVertex)._mult(sharpCornerOffset / nextSegmentLength)._round());
- this.updateDistance(currentVertex, newCurrentVertex);
- this.addCurrentVertex(newCurrentVertex, nextNormal, 0, 0, segment, fixedElevation);
- currentVertex = newCurrentVertex;
- }
- }
}
}
@@ -715,6 +736,9 @@ class LineBucket implements Bucket {
// one vector tile is usually rendered over 64x64 terrain grid. This should be enough for higher res grid, too.
const STEP = this.tessellationStep;
const steps = ((to.w - from.w) / STEP) | 0;
+ let stepsDistance = 0;
+ const scaledDistance = this.scaledDistance;
+
if (steps > 1) {
this.lineSoFar = from.w;
const stepX = (to.x - from.x) / steps;
@@ -726,13 +750,35 @@ class LineBucket implements Bucket {
from.y += stepY;
from.z += stepZ;
this.lineSoFar += stepW;
- this.addHalfVertex(from, leftX, leftY, round, false, endLeft, segment, from.z);
- this.addHalfVertex(from, rightX, rightY, round, true, -endRight, segment, from.z);
+ stepsDistance += stepW;
+ const z = this.evaluateElevationValue(this.prevDistance + stepsDistance);
+ this.scaledDistance = (this.prevDistance + stepsDistance) / this.totalDistance;
+ this.addHalfVertex(from, leftX, leftY, round, false, endLeft, segment, z);
+ this.addHalfVertex(from, rightX, rightY, round, true, -endRight, segment, z);
}
}
this.lineSoFar = to.w;
- this.addHalfVertex(to, leftX, leftY, round, false, endLeft, segment, to.z);
- this.addHalfVertex(to, rightX, rightY, round, true, -endRight, segment, to.z);
+ this.scaledDistance = scaledDistance;
+ const z = this.evaluateElevationValue(this.distance);
+ this.addHalfVertex(to, leftX, leftY, round, false, endLeft, segment, z);
+ this.addHalfVertex(to, rightX, rightY, round, true, -endRight, segment, z);
+ }
+
+ evaluateElevationValue(distance: number): number | undefined {
+ assert(distance >= 0);
+ if (!this.hasZOffset) {
+ return undefined;
+ } else if (this.zOffsetValue.kind === 'constant') {
+ return this.zOffsetValue.value;
+ } else {
+ this.evaluationGlobals.lineProgress = 0;
+ if (this.lineClips) {
+ this.evaluationGlobals.lineProgress = Math.min(1.0, (this.totalFeatureLength * this.lineClips.start + distance) / this.totalFeatureLength);
+ } else {
+ warnOnce(`line-z-offset evaluation for ${this.layerIds[0]} requires enabling 'lineMetrics' for the source.`);
+ }
+ return this.zOffsetValue.evaluate(this.evaluationGlobals, this.lineFeature) || 0.0;
+ }
}
/**
@@ -761,6 +807,8 @@ class LineBucket implements Bucket {
// tesellated chunks outside tile borders are not added.
const outside = pointOutsideBounds(p, boundsMin, boundsMax);
const lineSoFar = this.lineSoFar;
+ const distance = this.distance;
+ const scaledDist = this.scaledDistance;
if (!this.currentVertex) {
if (!outside) { // add the first point
@@ -777,11 +825,20 @@ class LineBucket implements Bucket {
if (prevOutside) {
// add half vertex to start the segment
this.e1 = this.e2 = -1;
+ // Previously calculated distance is not correct after clipLine()
+ const updatedDist = this.prevDistance + prev.dist(vertex);
+ this.prevDistance -= updatedDist - this.distance;
+ this.distance = updatedDist;
this.lineSoFar = prev.w;
- this.addHalfVertex(prev, leftX, leftY, round, false, endLeft, segment, prev.z);
- this.addHalfVertex(prev, rightX, rightY, round, true, -endRight, segment, prev.z);
+ const z = this.evaluateElevationValue(prev.w - this.totalFeatureLength * (this.lineClips ? this.lineClips.start : 0));
+ this.addHalfVertex(prev, leftX, leftY, round, false, endLeft, segment, z);
+ this.addHalfVertex(prev, rightX, rightY, round, true, -endRight, segment, z);
}
+ this.distance = this.prevDistance + prev.dist(next);
+ this.scaledDistance = this.distance / this.totalDistance;
this.addVerticesTo(prev, next, leftX, leftY, rightX, rightY, endLeft, endRight, segment, round);
+ this.distance = distance;
+ this.scaledDistance = scaledDist;
}
} else {
// inside
@@ -792,9 +849,17 @@ class LineBucket implements Bucket {
assert(vertex.x === p.x && vertex.y === p.y);
// add half vertex to start the segment
this.e1 = this.e2 = -1;
+ // Previously calculated distance is not correct after clipLine()
+ const updatedDist = this.prevDistance + prev.dist(vertex);
+ this.prevDistance -= updatedDist - this.distance;
+ this.distance = updatedDist;
+ this.scaledDistance = this.prevDistance / this.totalDistance;
this.lineSoFar = prev.w;
- this.addHalfVertex(prev, leftX, leftY, round, false, endLeft, segment, prev.z);
- this.addHalfVertex(prev, rightX, rightY, round, true, -endRight, segment, prev.z);
+ const z = this.evaluateElevationValue(prev.w - this.totalFeatureLength * (this.lineClips ? this.lineClips.start : 0));
+ this.addHalfVertex(prev, leftX, leftY, round, false, endLeft, segment, z);
+ this.addHalfVertex(prev, rightX, rightY, round, true, -endRight, segment, z);
+ this.distance = distance;
+ this.scaledDistance = scaledDist;
}
this.addVerticesTo(prev, vertex, leftX, leftY, rightX, rightY, endLeft, endRight, segment, round);
}
@@ -864,16 +929,15 @@ class LineBucket implements Bucket {
// (in tile units) of the current vertex, we can determine the relative distance
// of this vertex along the full linestring feature.
if (this.lineClips) {
- const featureShare = this.lineClips.end - this.lineClips.start;
- const totalFeatureLength = this.totalDistance / featureShare;
this.scaledDistance = this.distance / this.totalDistance;
- this.lineSoFar = totalFeatureLength * this.lineClips.start + this.distance;
+ this.lineSoFar = this.totalFeatureLength * this.lineClips.start + this.distance;
} else {
this.lineSoFar = this.distance;
}
}
updateDistance(prev: Point, next: Point) {
+ this.prevDistance = this.distance;
this.distance += prev.dist(next);
this.updateScaledDistance();
}
diff --git a/src/data/bucket/symbol_bucket.ts b/src/data/bucket/symbol_bucket.ts
index eb73e3c8279..4bad22cd210 100644
--- a/src/data/bucket/symbol_bucket.ts
+++ b/src/data/bucket/symbol_bucket.ts
@@ -521,12 +521,12 @@ class SymbolBucket implements Bucket {
calculateGlyphDependencies(text: string, stack: {
[_: number]: boolean;
}, textAlongLine: boolean, allowVerticalPlacement: boolean, doesAllowVerticalWritingMode: boolean) {
- for (let i = 0; i < text.length; i++) {
- const codePoint = text.codePointAt(i);
+ for (const char of text) {
+ const codePoint = char.codePointAt(0);
if (codePoint === undefined) break;
stack[codePoint] = true;
if (allowVerticalPlacement && doesAllowVerticalWritingMode && codePoint <= 65535) {
- const verticalChar = verticalizedCharacterMap[text.charAt(i)];
+ const verticalChar = verticalizedCharacterMap[char];
if (verticalChar) {
stack[verticalChar.charCodeAt(0)] = true;
}
@@ -994,7 +994,7 @@ class SymbolBucket implements Bucket {
}
}
- generateCollisionDebugBuffers(zoom: number, collisionBoxArray: CollisionBoxArray) {
+ generateCollisionDebugBuffers(zoom: number, collisionBoxArray: CollisionBoxArray, textScaleFactor: number) {
if (this.hasDebugData()) {
this.destroyDebugData();
}
@@ -1003,7 +1003,7 @@ class SymbolBucket implements Bucket {
this.iconCollisionBox = new CollisionBuffers(CollisionBoxLayoutArray, collisionBoxLayout.members, LineIndexArray);
const iconSize = symbolSize.evaluateSizeForZoom(this.iconSizeData, zoom);
- const textSize = symbolSize.evaluateSizeForZoom(this.textSizeData, zoom);
+ const textSize = symbolSize.evaluateSizeForZoom(this.textSizeData, zoom, textScaleFactor);
for (let i = 0; i < this.symbolInstances.length; i++) {
const symbolInstance = this.symbolInstances.get(i);
@@ -1041,7 +1041,7 @@ class SymbolBucket implements Bucket {
array.emplaceBack(scale, -padding, padding, zOffset);
}
- _updateTextDebugCollisionBoxes(size: any, zoom: number, collisionBoxArray: CollisionBoxArray, startIndex: number, endIndex: number, instance: SymbolInstance) {
+ _updateTextDebugCollisionBoxes(size: any, zoom: number, collisionBoxArray: CollisionBoxArray, startIndex: number, endIndex: number, instance: SymbolInstance, scaleFactor: number) {
for (let b = startIndex; b < endIndex; b++) {
const box: CollisionBox = (collisionBoxArray.get(b) as any);
const scale = this.getSymbolInstanceTextSize(size, instance, zoom, b);
@@ -1050,7 +1050,7 @@ class SymbolBucket implements Bucket {
}
}
- _updateIconDebugCollisionBoxes(size: any, zoom: number, collisionBoxArray: CollisionBoxArray, startIndex: number, endIndex: number, instance: SymbolInstance) {
+ _updateIconDebugCollisionBoxes(size: any, zoom: number, collisionBoxArray: CollisionBoxArray, startIndex: number, endIndex: number, instance: SymbolInstance, iconScaleFactor: number) {
for (let b = startIndex; b < endIndex; b++) {
const box = (collisionBoxArray.get(b));
const scale = this.getSymbolInstanceIconSize(size, zoom, instance.placedIconSymbolIndex);
@@ -1059,7 +1059,7 @@ class SymbolBucket implements Bucket {
}
}
- updateCollisionDebugBuffers(zoom: number, collisionBoxArray: CollisionBoxArray) {
+ updateCollisionDebugBuffers(zoom: number, collisionBoxArray: CollisionBoxArray, textScaleFactor: number, iconScaleFactor: number) {
if (!this.hasDebugData()) {
return;
}
@@ -1067,15 +1067,15 @@ class SymbolBucket implements Bucket {
if (this.hasTextCollisionBoxData()) this.textCollisionBox.collisionVertexArrayExt.clear();
if (this.hasIconCollisionBoxData()) this.iconCollisionBox.collisionVertexArrayExt.clear();
- const iconSize = symbolSize.evaluateSizeForZoom(this.iconSizeData, zoom);
- const textSize = symbolSize.evaluateSizeForZoom(this.textSizeData, zoom);
+ const iconSize = symbolSize.evaluateSizeForZoom(this.iconSizeData, zoom, iconScaleFactor);
+ const textSize = symbolSize.evaluateSizeForZoom(this.textSizeData, zoom, textScaleFactor);
for (let i = 0; i < this.symbolInstances.length; i++) {
const symbolInstance = this.symbolInstances.get(i);
- this._updateTextDebugCollisionBoxes(textSize, zoom, collisionBoxArray, symbolInstance.textBoxStartIndex, symbolInstance.textBoxEndIndex, symbolInstance);
- this._updateTextDebugCollisionBoxes(textSize, zoom, collisionBoxArray, symbolInstance.verticalTextBoxStartIndex, symbolInstance.verticalTextBoxEndIndex, symbolInstance);
- this._updateIconDebugCollisionBoxes(iconSize, zoom, collisionBoxArray, symbolInstance.iconBoxStartIndex, symbolInstance.iconBoxEndIndex, symbolInstance);
- this._updateIconDebugCollisionBoxes(iconSize, zoom, collisionBoxArray, symbolInstance.verticalIconBoxStartIndex, symbolInstance.verticalIconBoxEndIndex, symbolInstance);
+ this._updateTextDebugCollisionBoxes(textSize, zoom, collisionBoxArray, symbolInstance.textBoxStartIndex, symbolInstance.textBoxEndIndex, symbolInstance, textScaleFactor);
+ this._updateTextDebugCollisionBoxes(textSize, zoom, collisionBoxArray, symbolInstance.verticalTextBoxStartIndex, symbolInstance.verticalTextBoxEndIndex, symbolInstance, textScaleFactor);
+ this._updateIconDebugCollisionBoxes(iconSize, zoom, collisionBoxArray, symbolInstance.iconBoxStartIndex, symbolInstance.iconBoxEndIndex, symbolInstance, iconScaleFactor);
+ this._updateIconDebugCollisionBoxes(iconSize, zoom, collisionBoxArray, symbolInstance.verticalIconBoxStartIndex, symbolInstance.verticalIconBoxEndIndex, symbolInstance, iconScaleFactor);
}
if (this.hasTextCollisionBoxData() && this.textCollisionBox.collisionVertexBufferExt) {
diff --git a/src/data/dem_tree.ts b/src/data/dem_tree.ts
index bb886dc654c..0ccaa3e75e9 100644
--- a/src/data/dem_tree.ts
+++ b/src/data/dem_tree.ts
@@ -199,9 +199,8 @@ export default class DemMinMaxQuadTree {
d: vec3,
exaggeration: number = 1,
): number | null | undefined {
- const min = [minx, miny, -aabbSkirtPadding];
- const max = [maxx, maxy, this.maximums[0] * exaggeration];
- // @ts-expect-error - TS2345 - Argument of type 'number[]' is not assignable to parameter of type 'vec3'.
+ const min: vec3 = [minx, miny, -aabbSkirtPadding];
+ const max: vec3 = [maxx, maxy, this.maximums[0] * exaggeration];
return aabbRayIntersect(min, max, p, d);
}
@@ -223,8 +222,8 @@ export default class DemMinMaxQuadTree {
const tHits = [];
const sortedHits = [];
- const boundsMin = [];
- const boundsMax = [];
+ const boundsMin = [] as unknown as vec3;
+ const boundsMax = [] as unknown as vec3;
const stack = [{
idx: 0,
@@ -240,7 +239,7 @@ export default class DemMinMaxQuadTree {
if (this.leaves[idx]) {
// Create 2 triangles to approximate the surface plane for more precise tests
- decodeBounds(nodex, nodey, depth, rootMinx, rootMiny, rootMaxx, rootMaxy, boundsMin, boundsMax);
+ decodeBounds(nodex, nodey, depth, rootMinx, rootMiny, rootMaxx, rootMaxy, boundsMin as number[], boundsMax as number[]);
const scale = 1 << depth;
const minxUv = (nodex + 0) / scale;
@@ -295,12 +294,11 @@ export default class DemMinMaxQuadTree {
const childNodeY = (nodey << 1) + this._siblingOffset[i][1];
// Decode node aabb from the morton code
- decodeBounds(childNodeX, childNodeY, depth + 1, rootMinx, rootMiny, rootMaxx, rootMaxy, boundsMin, boundsMax);
+ decodeBounds(childNodeX, childNodeY, depth + 1, rootMinx, rootMiny, rootMaxx, rootMaxy, boundsMin as number[], boundsMax as number[]);
boundsMin[2] = -aabbSkirtPadding;
boundsMax[2] = this.maximums[this.childOffsets[idx] + i] * exaggeration;
- // @ts-expect-error - TS2345 - Argument of type 'any[]' is not assignable to parameter of type 'vec3'.
const result = aabbRayIntersect(boundsMin, boundsMax, p, d);
if (result != null) {
// Build the result list from furthest to closest hit.
diff --git a/src/data/feature_index.ts b/src/data/feature_index.ts
index 2e411c78c8e..5308cd06fa9 100644
--- a/src/data/feature_index.ts
+++ b/src/data/feature_index.ts
@@ -24,8 +24,7 @@ import type {QueryResult} from '../source/query_features';
import type {FeatureStates} from '../source/source_state';
import type {FeatureFilter} from '../style-spec/feature_filter/index';
import type Transform from '../geo/transform';
-import type {GeoJSONFeature} from '../util/vectortile_to_geojson';
-import type {FilterSpecification, PromoteIdSpecification} from '../style-spec/types';
+import type {FilterSpecification, PromoteIdSpecification, LayerSpecification} from '../style-spec/types';
import type {TilespaceQueryGeometry} from '../style/query_geometry';
import type {FeatureIndex as FeatureIndexStruct} from './array_types';
import type {TileTransform} from '../geo/projection/tile_transform';
@@ -37,11 +36,9 @@ type QueryParameters = {
transform: Transform;
tileResult: TilespaceQueryGeometry;
tileTransform: TileTransform;
- params: {
- filter: FilterSpecification;
- layers: Array;
- availableImages: Array;
- };
+ availableImages: Array;
+ layers?: string[];
+ filter?: FilterSpecification;
};
type FeatureIndices = {
@@ -71,6 +68,7 @@ class FeatureIndex {
};
sourceLayerCoder: DictionaryCoder;
is3DTile: boolean; // no vector source layers
+ serializedLayersCache: Map;
constructor(tileID: OverscaledTileID, promoteId?: PromoteIdSpecification | null) {
this.tileID = tileID;
@@ -81,6 +79,7 @@ class FeatureIndex {
this.featureIndexArray = new FeatureIndexArray();
this.promoteId = promoteId;
this.is3DTile = false;
+ this.serializedLayersCache = new Map();
}
insert(feature: VectorTileFeature, geometry: Array>, featureIndex: number, sourceLayerIndex: number, bucketIndex: number, layoutVertexArrayOffset: number = 0, envelopePadding: number = 0) {
@@ -135,12 +134,11 @@ class FeatureIndex {
query(
args: QueryParameters,
styleLayers: {[_: string]: StyleLayer},
- serializedLayers: {[_: string]: any},
sourceFeatureState: SourceFeatureState,
): QueryResult {
this.loadVTLayers();
- const params = args.params || ({} as Partial);
- const filter = featureFilter(params.filter);
+ this.serializedLayersCache.clear();
+ const filter = featureFilter(args.filter);
const tilespaceGeometry = args.tileResult;
const transform = args.transform;
@@ -184,10 +182,9 @@ class FeatureIndex {
result,
match,
filter,
- params.layers,
- params.availableImages,
+ args.layers,
+ args.availableImages,
styleLayers,
- serializedLayers,
sourceFeatureState,
(feature: VectorTileFeature, styleLayer: StyleLayer, featureState: any, layoutVertexArrayOffset: number = 0) => {
if (!featureGeometry) {
@@ -211,9 +208,6 @@ class FeatureIndex {
styleLayers: {
[_: string]: StyleLayer;
},
- serializedLayers: {
- [_: string]: any;
- },
sourceFeatureState?: SourceFeatureState,
intersectionTest?: (
feature: VectorTileFeature,
@@ -224,7 +218,7 @@ class FeatureIndex {
const {featureIndex, bucketIndex, sourceLayerIndex, layoutVertexArrayOffset} = featureIndexData;
const layerIDs = this.bucketLayerIDs[bucketIndex];
- if (filterLayerIDs && !arraysIntersect(filterLayerIDs, layerIDs))
+ if (filterLayerIDs.length && !arraysIntersect(filterLayerIDs, layerIDs))
return;
const sourceLayerName = this.sourceLayerCoder.decode(sourceLayerIndex);
@@ -245,7 +239,7 @@ class FeatureIndex {
for (let l = 0; l < layerIDs.length; l++) {
const layerID = layerIDs[l];
- if (filterLayerIDs && filterLayerIDs.indexOf(layerID) < 0) {
+ if (filterLayerIDs.length && filterLayerIDs.indexOf(layerID) < 0) {
continue;
}
@@ -267,17 +261,21 @@ class FeatureIndex {
const geojsonFeature = new Feature(feature, this.z, this.x, this.y, id);
- const serializedLayer = extend({}, serializedLayers[layerID]);
-
- serializedLayer.paint = evaluateProperties(serializedLayer.paint, styleLayer.paint, feature, featureState, availableImages);
- serializedLayer.layout = evaluateProperties(serializedLayer.layout, styleLayer.layout, feature, featureState, availableImages);
-
- geojsonFeature.layer = serializedLayer;
+ let serializedLayer = this.serializedLayersCache.get(layerID);
+ if (!serializedLayer) {
+ serializedLayer = styleLayer.serialize();
+ serializedLayer.id = layerID;
+ this.serializedLayersCache.set(layerID, serializedLayer);
+ }
+ geojsonFeature.layer = extend({}, serializedLayer);
+ geojsonFeature.tile = this.tileID.canonical;
+ geojsonFeature.layer.paint = evaluateProperties(serializedLayer.paint, styleLayer.paint, feature, featureState, availableImages);
+ geojsonFeature.layer.layout = evaluateProperties(serializedLayer.layout, styleLayer.layout, feature, featureState, availableImages);
this.appendToResult(result, layerID, featureIndex, geojsonFeature, intersectionZ);
}
}
- appendToResult(result: QueryResult, layerID: string, featureIndex: number, geojsonFeature: GeoJSONFeature, intersectionZ: boolean | number) {
+ appendToResult(result: QueryResult, layerID: string, featureIndex: number, geojsonFeature: Feature, intersectionZ: boolean | number) {
let layerResult = result[layerID];
if (layerResult === undefined) {
layerResult = result[layerID] = [];
@@ -290,9 +288,6 @@ class FeatureIndex {
// return a matching set of GeoJSONFeatures
lookupSymbolFeatures(
symbolFeatureIndexes: Array,
- serializedLayers: {
- [key: string]: StyleLayer;
- },
bucketIndex: number,
sourceLayerIndex: number,
filterSpec: FilterSpecification,
@@ -318,8 +313,7 @@ class FeatureIndex {
filter,
filterLayerIDs,
availableImages,
- styleLayers,
- serializedLayers
+ styleLayers
);
}
diff --git a/src/data/mrt/mrt.esm.js b/src/data/mrt/mrt.esm.js
index 838a719366b..4c556de918f 100644
--- a/src/data/mrt/mrt.esm.js
+++ b/src/data/mrt/mrt.esm.js
@@ -3,7 +3,7 @@
function readTileHeader(pbf, end) {
return pbf.readFields(readTileHeaderTag, {
- header_length: 0,
+ headerLength: 0,
x: 0,
y: 0,
z: 0,
@@ -11,7 +11,7 @@ function readTileHeader(pbf, end) {
}, end);
}
function readTileHeaderTag(tag, obj, pbf) {
- if (tag === 1) obj.header_length = pbf.readFixed32();else if (tag === 2) obj.x = pbf.readVarint();else if (tag === 3) obj.y = pbf.readVarint();else if (tag === 4) obj.z = pbf.readVarint();else if (tag === 5) obj.layers.push(readLayer(pbf, pbf.readVarint() + pbf.pos));
+ if (tag === 1) obj.headerLength = pbf.readFixed32();else if (tag === 2) obj.x = pbf.readVarint();else if (tag === 3) obj.y = pbf.readVarint();else if (tag === 4) obj.z = pbf.readVarint();else if (tag === 5) obj.layers.push(readLayer(pbf, pbf.readVarint() + pbf.pos));
}
function readFilter(pbf, end) {
return pbf.readFields(readFilterTag, {}, end);
@@ -33,11 +33,11 @@ function readFilterTag(tag, obj, pbf) {
}
function readFilterDelta(pbf, end) {
return pbf.readFields(readFilterDeltaTag, {
- block_size: 0
+ blockSize: 0
}, end);
}
function readFilterDeltaTag(tag, obj, pbf) {
- if (tag === 1) obj.block_size = pbf.readVarint();
+ if (tag === 1) obj.blockSize = pbf.readVarint();
}
function readCodec(pbf, end) {
return pbf.readFields(readCodecTag, {}, end);
@@ -59,33 +59,44 @@ function readCodecTag(tag, obj, pbf) {
}
function readDataIndexEntry(pbf, end) {
return pbf.readFields(readDataIndexEntryTag, {
- first_byte: 0,
- last_byte: 0,
+ firstByte: 0,
+ lastByte: 0,
filters: [],
codec: null,
offset: 0,
scale: 0,
- deprecated_offset: 0,
- deprecated_scale: 0,
bands: []
}, end);
}
function readDataIndexEntryTag(tag, obj, pbf) {
- if (tag === 1) obj.first_byte = pbf.readFixed64();else if (tag === 2) obj.last_byte = pbf.readFixed64();else if (tag === 3) obj.filters.push(readFilter(pbf, pbf.readVarint() + pbf.pos));else if (tag === 4) obj.codec = readCodec(pbf, pbf.readVarint() + pbf.pos);else if (tag === 5) obj.deprecated_offset = pbf.readFloat();else if (tag === 6) obj.deprecated_scale = pbf.readFloat();else if (tag === 7) obj.bands.push(pbf.readString());else if (tag === 8) obj.offset = pbf.readDouble();else if (tag === 9) obj.scale = pbf.readDouble();
+ let deprecated_scale = 0;
+ let deprecated_offset = 0;
+ if (tag === 1) obj.firstByte = pbf.readFixed64();else if (tag === 2) obj.lastByte = pbf.readFixed64();else if (tag === 3) obj.filters.push(readFilter(pbf, pbf.readVarint() + pbf.pos));else if (tag === 4) obj.codec = readCodec(pbf, pbf.readVarint() + pbf.pos);else if (tag === 5) deprecated_offset = pbf.readFloat();else if (tag === 6) deprecated_scale = pbf.readFloat();else if (tag === 7) obj.bands.push(pbf.readString());else if (tag === 8) obj.offset = pbf.readDouble();else if (tag === 9) obj.scale = pbf.readDouble();
+
+ // Overwrite these values if they're zero. Scale can never be zero, so this could only
+ // mean it's being overwritten with something that is potentially valid (or at least
+ // not any more invalid). For offset, the same situation applies except that it could
+ // technically have been affirmatively set to zero to begin with. However, it would then
+ // be overwritten with the deprecated float32 value, which is identically zero whether
+ // or not it was actually set. At the end of the day, it only achieves some increased
+ // robustness for historical tilesets written during early beta, before the field type
+ // was upgraded to double precision.
+ if (obj.offset === 0) obj.offset = deprecated_offset;
+ if (obj.scale === 0) obj.scale = deprecated_scale;
}
function readLayer(pbf, end) {
return pbf.readFields(readLayerTag, {
version: 0,
name: '',
units: '',
- tilesize: 0,
+ tileSize: 0,
buffer: 0,
- pixel_format: 0,
- data_index: []
+ pixelFormat: 0,
+ dataIndex: []
}, end);
}
function readLayerTag(tag, obj, pbf) {
- if (tag === 1) obj.version = pbf.readVarint();else if (tag === 2) obj.name = pbf.readString();else if (tag === 3) obj.units = pbf.readString();else if (tag === 4) obj.tilesize = pbf.readVarint();else if (tag === 5) obj.buffer = pbf.readVarint();else if (tag === 6) obj.pixel_format = pbf.readVarint();else if (tag === 7) obj.data_index.push(readDataIndexEntry(pbf, pbf.readVarint() + pbf.pos));
+ if (tag === 1) obj.version = pbf.readVarint();else if (tag === 2) obj.name = pbf.readString();else if (tag === 3) obj.units = pbf.readString();else if (tag === 4) obj.tileSize = pbf.readVarint();else if (tag === 5) obj.buffer = pbf.readVarint();else if (tag === 6) obj.pixelFormat = pbf.readVarint();else if (tag === 7) obj.dataIndex.push(readDataIndexEntry(pbf, pbf.readVarint() + pbf.pos));
}
function readNumericData(pbf, values) {
pbf.readFields(readNumericDataTag, values);
@@ -617,6 +628,8 @@ try {
tds = 1;
} catch (e) {}
+/* global Response */
+
/** @typedef { import("./types/types").TCodec } TCodec */
/** @type { { [key: string]: string } } */
@@ -649,6 +662,14 @@ function decompress(bytes, codec) {
return new Response(new Blob([bytes]).stream().pipeThrough(ds)).arrayBuffer().then(buf => new Uint8Array(buf));
}
+/**
+ * An error class for MRT modules.
+ *
+ * MRTError should be thrown only for user input errors and not for
+ * internal inconsistencies or assertions. The class is designed to
+ * facilitate catching and responding to the end user with meaningful
+ * error messages.
+ */
class MRTError extends Error {
/**
* @param {string} message - error message
@@ -659,7 +680,7 @@ class MRTError extends Error {
}
}
-const VERSION = '1.0.0-alpha.24.2';
+const VERSION = '2.0.1';
/** @typedef { import("pbf") } Pbf; */
/** @typedef { import("./types/types").TArrayLike } TArrayLike; */
@@ -777,8 +798,8 @@ class MapboxRasterTile {
const layer = this.getLayer(range.layerName);
for (let blockIndex of range.blockIndices) {
const block = layer.dataIndex[blockIndex];
- const firstByte = block.first_byte - range.firstByte;
- const lastByte = block.last_byte - range.firstByte;
+ const firstByte = block.firstByte - range.firstByte;
+ const lastByte = block.lastByte - range.firstByte;
if (layer._blocksInProgress.has(blockIndex)) continue;
const task = {
layerName: layer.name,
@@ -815,20 +836,20 @@ class RasterLayer {
* @param {number} pbf.version - major version of MRT specification with which tile was encoded
* @param {string} pbf.name - layer name
* @param {string} pbf.units - layer units
- * @param {number} pbf.tilesize - number of rows and columns in raster data
+ * @param {number} pbf.tileSize - number of rows and columns in raster data
* @param {number} pbf.buffer - number of pixels around the edge of each tile
- * @param {number} pbf.pixel_format - encoded pixel format enum indicating uint32, uint16, or uint8
- * @param {TPbfDataIndexEntry[]} pbf.data_index - index of data chunk byte offsets
+ * @param {number} pbf.pixelFormat - encoded pixel format enum indicating uint32, uint16, or uint8
+ * @param {TPbfDataIndexEntry[]} pbf.dataIndex - index of data chunk byte offsets
* @param {TRasterLayerConfig} [config] - Additional configuration parameters
*/
constructor({
version,
name,
units,
- tilesize,
- pixel_format,
+ tileSize,
+ pixelFormat,
buffer,
- data_index
+ dataIndex
}, config) {
// Take these directly from decoded Pbf
this.version = version;
@@ -837,11 +858,11 @@ class RasterLayer {
}
this.name = name;
this.units = units;
- this.tileSize = tilesize;
+ this.tileSize = tileSize;
this.buffer = buffer;
- this.pixelFormat = PIXEL_FORMAT[pixel_format];
- this.dataIndex = data_index;
- this.bandShape = [tilesize + 2 * buffer, tilesize + 2 * buffer, PIXEL_FORMAT_TO_DIM_LEN[this.pixelFormat]];
+ this.pixelFormat = PIXEL_FORMAT[pixelFormat];
+ this.dataIndex = dataIndex;
+ this.bandShape = [tileSize + 2 * buffer, tileSize + 2 * buffer, PIXEL_FORMAT_TO_DIM_LEN[this.pixelFormat]];
// Type script is creating more problems than it solves here:
const cacheSize = config ? config.cacheSize : 5;
@@ -947,8 +968,8 @@ class RasterLayer {
blockIndices.push(blockIndex);
}
allBlocks.add(blockIndex);
- firstByte = Math.min(firstByte, block.first_byte);
- lastByte = Math.max(lastByte, block.last_byte);
+ firstByte = Math.min(firstByte, block.firstByte);
+ lastByte = Math.max(lastByte, block.lastByte);
}
if (allBlocks.size > this.cacheSize) {
throw new MRTError(`Number of blocks to decode (${allBlocks.size}) exceeds cache size (${this.cacheSize}).`);
@@ -1013,13 +1034,8 @@ class RasterLayer {
buffer: this.buffer,
pixelFormat: this.pixelFormat,
dimension: this.dimension,
- // Offset and scale were upgraded from single precision to double. Since they
- // are both initialized to zero, we prefer non-deprecated properties. If the
- // non-deprecated property is zero, then we use the deprecated property, which
- // has also been initialized to zero. This will ignore the deprecated field if
- // both are non-zero.
- offset: block.offset !== 0 ? block.offset : block.deprecated_offset,
- scale: block.scale !== 0 ? block.scale : block.deprecated_scale
+ offset: block.offset,
+ scale: block.scale
};
}
}
diff --git a/src/data/usvg/usvg_pb_decoder.js b/src/data/usvg/usvg_pb_decoder.js
new file mode 100644
index 00000000000..e7b94f50be2
--- /dev/null
+++ b/src/data/usvg/usvg_pb_decoder.js
@@ -0,0 +1,607 @@
+/* eslint-disable camelcase */
+/* eslint-disable brace-style */
+/* eslint-disable no-sparse-arrays */
+
+// code generated by pbf v4.0.1
+// npx pbf usvg_tree.proto --no-write --jsdoc
+
+/**
+ * @typedef {import("pbf")} Pbf
+ */
+
+/** @enum {number} */
+export const FillRule = {
+ "FILL_RULE_UNSPECIFIED": 0,
+ "FILL_RULE_NON_ZERO": 1,
+ "FILL_RULE_EVEN_ODD": 2
+};
+
+/** @enum {number} */
+export const LineCap = {
+ "LINE_CAP_UNSPECIFIED": 0,
+ "LINE_CAP_BUTT": 1,
+ "LINE_CAP_ROUND": 2,
+ "LINE_CAP_SQUARE": 3
+};
+
+/** @enum {number} */
+export const LineJoin = {
+ "LINE_JOIN_UNSPECIFIED": 0,
+ "LINE_JOIN_MITER": 1,
+ "LINE_JOIN_MITER_CLIP": 2,
+ "LINE_JOIN_ROUND": 3,
+ "LINE_JOIN_BEVEL": 4
+};
+
+/** @enum {number} */
+export const PaintOrder = {
+ "PAINT_ORDER_UNSPECIFIED": 0,
+ "PAINT_ORDER_FILL_AND_STROKE": 1,
+ "PAINT_ORDER_STROKE_AND_FILL": 2
+};
+
+/** @enum {number} */
+export const PathCommand = {
+ "PATH_COMMAND_UNSPECIFIED": 0,
+ "PATH_COMMAND_MOVE": 1,
+ "PATH_COMMAND_LINE": 2,
+ "PATH_COMMAND_QUAD": 3,
+ "PATH_COMMAND_CUBIC": 4,
+ "PATH_COMMAND_CLOSE": 5
+};
+
+/** @enum {number} */
+export const SpreadMethod = {
+ "SPREAD_METHOD_UNSPECIFIED": 0,
+ "SPREAD_METHOD_PAD": 1,
+ "SPREAD_METHOD_REFLECT": 2,
+ "SPREAD_METHOD_REPEAT": 3
+};
+
+/** @enum {number} */
+export const ClipRule = {
+ "CLIP_RULE_UNSPECIFIED": 0,
+ "CLIP_RULE_NON_ZERO": 1,
+ "CLIP_RULE_EVEN_ODD": 2
+};
+
+/** @enum {number} */
+export const MaskType = {
+ "MASK_TYPE_UNSPECIFIED": 0,
+ "MASK_TYPE_LUMINANCE": 1,
+ "MASK_TYPE_ALPHA": 2
+};
+
+/**
+ * @typedef {object} IconSet
+ * @property {Icon[]} icons
+ */
+
+/**
+ * @param {Pbf} pbf
+ * @param {number} [end]
+ * @returns {IconSet}
+ */
+export function readIconSet(pbf, end) {
+ return pbf.readFields(readIconSetField, {icons: []}, end);
+}
+
+/**
+ * @param {number} tag
+ * @param {IconSet} obj
+ * @param {Pbf} pbf
+ */
+function readIconSetField(tag, obj, pbf) {
+ if (tag === 1) obj.icons.push(readIcon(pbf, pbf.readVarint() + pbf.pos));
+}
+
+/**
+ * @typedef {object} Icon
+ * @property {string} name
+ * @property {IconMetadata} [metadata]
+ * @property {UsvgTree} [usvg_tree]
+ * @property {"usvg_tree"} [data]
+ */
+
+/**
+ * @param {Pbf} pbf
+ * @param {number} [end]
+ * @returns {Icon}
+ */
+export function readIcon(pbf, end) {
+ return pbf.readFields(readIconField, {name: undefined}, end);
+}
+
+/**
+ * @param {number} tag
+ * @param {Icon} obj
+ * @param {Pbf} pbf
+ */
+function readIconField(tag, obj, pbf) {
+ if (tag === 1) obj.name = pbf.readString();
+ else if (tag === 2) obj.metadata = readIconMetadata(pbf, pbf.readVarint() + pbf.pos);
+ else if (tag === 3) { obj.usvg_tree = readUsvgTree(pbf, pbf.readVarint() + pbf.pos); obj.data = "usvg_tree"; }
+}
+
+/**
+ * @typedef {object} IconMetadata
+ * @property {number[]} stretch_x
+ * @property {number[]} stretch_y
+ * @property {ContentArea} [content_area]
+ * @property {Variable[]} variables
+ */
+
+/**
+ * @param {Pbf} pbf
+ * @param {number} [end]
+ * @returns {IconMetadata}
+ */
+export function readIconMetadata(pbf, end) {
+ return pbf.readFields(readIconMetadataField, {stretch_x: [], stretch_y: [], variables: []}, end);
+}
+
+/**
+ * @param {number} tag
+ * @param {IconMetadata} obj
+ * @param {Pbf} pbf
+ */
+function readIconMetadataField(tag, obj, pbf) {
+ if (tag === 1) pbf.readPackedVarint(obj.stretch_x);
+ else if (tag === 2) pbf.readPackedVarint(obj.stretch_y);
+ else if (tag === 3) obj.content_area = readContentArea(pbf, pbf.readVarint() + pbf.pos);
+ else if (tag === 4) obj.variables.push(readVariable(pbf, pbf.readVarint() + pbf.pos));
+}
+
+/**
+ * @typedef {object} ContentArea
+ * @property {number} [left]
+ * @property {number} [width]
+ * @property {number} [top]
+ * @property {number} [height]
+ */
+
+/**
+ * @param {Pbf} pbf
+ * @param {number} [end]
+ * @returns {ContentArea}
+ */
+export function readContentArea(pbf, end) {
+ return pbf.readFields(readContentAreaField, {left: 0}, end);
+}
+
+/**
+ * @param {number} tag
+ * @param {ContentArea} obj
+ * @param {Pbf} pbf
+ */
+function readContentAreaField(tag, obj, pbf) {
+ if (tag === 1) obj.left = pbf.readVarint();
+ else if (tag === 2) obj.width = pbf.readVarint();
+ else if (tag === 3) obj.top = pbf.readVarint();
+ else if (tag === 4) obj.height = pbf.readVarint();
+}
+
+/**
+ * @typedef {object} Variable
+ * @property {string} name
+ * @property {number} [rgb_color]
+ * @property {"rgb_color"} [value]
+ */
+
+/**
+ * @param {Pbf} pbf
+ * @param {number} [end]
+ * @returns {Variable}
+ */
+export function readVariable(pbf, end) {
+ return pbf.readFields(readVariableField, {name: undefined}, end);
+}
+
+/**
+ * @param {number} tag
+ * @param {Variable} obj
+ * @param {Pbf} pbf
+ */
+function readVariableField(tag, obj, pbf) {
+ if (tag === 1) obj.name = pbf.readString();
+ else if (tag === 2) { obj.rgb_color = pbf.readVarint(); obj.value = "rgb_color"; }
+}
+
+/**
+ * @typedef {object} UsvgTree
+ * @property {number} [width]
+ * @property {number} [height]
+ * @property {Node[]} children
+ * @property {LinearGradient[]} linear_gradients
+ * @property {RadialGradient[]} radial_gradients
+ * @property {ClipPath[]} clip_paths
+ * @property {Mask[]} masks
+ */
+
+/**
+ * @param {Pbf} pbf
+ * @param {number} [end]
+ * @returns {UsvgTree}
+ */
+export function readUsvgTree(pbf, end) {
+ return pbf.readFields(readUsvgTreeField, {width: 20, children: [], linear_gradients: [], radial_gradients: [], clip_paths: [], masks: []}, end);
+}
+
+/**
+ * @param {number} tag
+ * @param {UsvgTree} obj
+ * @param {Pbf} pbf
+ */
+function readUsvgTreeField(tag, obj, pbf) {
+ if (tag === 1) obj.width = obj.height = pbf.readVarint();
+ else if (tag === 2) obj.height = pbf.readVarint();
+ else if (tag === 3) obj.children.push(readNode(pbf, pbf.readVarint() + pbf.pos));
+ else if (tag === 4) obj.linear_gradients.push(readLinearGradient(pbf, pbf.readVarint() + pbf.pos));
+ else if (tag === 5) obj.radial_gradients.push(readRadialGradient(pbf, pbf.readVarint() + pbf.pos));
+ else if (tag === 7) obj.clip_paths.push(readClipPath(pbf, pbf.readVarint() + pbf.pos));
+ else if (tag === 8) obj.masks.push(readMask(pbf, pbf.readVarint() + pbf.pos));
+}
+
+/**
+ * @typedef {object} Node
+ * @property {Group} [group]
+ * @property {Path} [path]
+ * @property {"group" | "path"} [node]
+ */
+
+/**
+ * @param {Pbf} pbf
+ * @param {number} [end]
+ * @returns {Node}
+ */
+export function readNode(pbf, end) {
+ return pbf.readFields(readNodeField, {}, end);
+}
+
+/**
+ * @param {number} tag
+ * @param {Node} obj
+ * @param {Pbf} pbf
+ */
+function readNodeField(tag, obj, pbf) {
+ if (tag === 1) { obj.group = readGroup(pbf, pbf.readVarint() + pbf.pos); obj.node = "group"; }
+ else if (tag === 2) { obj.path = readPath(pbf, pbf.readVarint() + pbf.pos); obj.node = "path"; }
+}
+
+/**
+ * @typedef {object} Group
+ * @property {Transform} [transform]
+ * @property {number} [opacity]
+ * @property {number} [clip_path_idx]
+ * @property {number} [mask_idx]
+ * @property {Node[]} children
+ */
+
+/**
+ * @param {Pbf} pbf
+ * @param {number} [end]
+ * @returns {Group}
+ */
+export function readGroup(pbf, end) {
+ return pbf.readFields(readGroupField, {opacity: 255, children: []}, end);
+}
+
+/**
+ * @param {number} tag
+ * @param {Group} obj
+ * @param {Pbf} pbf
+ */
+function readGroupField(tag, obj, pbf) {
+ if (tag === 1) obj.transform = readTransform(pbf, pbf.readVarint() + pbf.pos);
+ else if (tag === 2) obj.opacity = pbf.readVarint();
+ else if (tag === 5) obj.clip_path_idx = pbf.readVarint();
+ else if (tag === 6) obj.mask_idx = pbf.readVarint();
+ else if (tag === 7) obj.children.push(readNode(pbf, pbf.readVarint() + pbf.pos));
+}
+
+/**
+ * @typedef {object} Transform
+ * @property {number} [sx]
+ * @property {number} [ky]
+ * @property {number} [kx]
+ * @property {number} [sy]
+ * @property {number} [tx]
+ * @property {number} [ty]
+ */
+
+/**
+ * @param {Pbf} pbf
+ * @param {number} [end]
+ * @returns {Transform}
+ */
+export function readTransform(pbf, end) {
+ return pbf.readFields(readTransformField, {sx: 1, ky: 0, kx: 0, sy: 1, tx: 0, ty: 0}, end);
+}
+
+/**
+ * @param {number} tag
+ * @param {Transform} obj
+ * @param {Pbf} pbf
+ */
+function readTransformField(tag, obj, pbf) {
+ if (tag === 1) obj.sx = pbf.readFloat();
+ else if (tag === 2) obj.ky = pbf.readFloat();
+ else if (tag === 3) obj.kx = pbf.readFloat();
+ else if (tag === 4) obj.sy = pbf.readFloat();
+ else if (tag === 5) obj.tx = pbf.readFloat();
+ else if (tag === 6) obj.ty = pbf.readFloat();
+}
+
+/**
+ * @typedef {object} Path
+ * @property {Fill} [fill]
+ * @property {Stroke} [stroke]
+ * @property {PaintOrder} [paint_order]
+ * @property {PathCommand[]} commands
+ * @property {number} [step]
+ * @property {number[]} diffs
+ * @property {ClipRule} [clip_rule]
+ */
+
+/**
+ * @param {Pbf} pbf
+ * @param {number} [end]
+ * @returns {Path}
+ */
+export function readPath(pbf, end) {
+ return pbf.readFields(readPathField, {paint_order: 1, commands: [], step: 1, diffs: [], clip_rule: 1}, end);
+}
+
+/**
+ * @param {number} tag
+ * @param {Path} obj
+ * @param {Pbf} pbf
+ */
+function readPathField(tag, obj, pbf) {
+ if (tag === 1) obj.fill = readFill(pbf, pbf.readVarint() + pbf.pos);
+ else if (tag === 2) obj.stroke = readStroke(pbf, pbf.readVarint() + pbf.pos);
+ else if (tag === 3) obj.paint_order = pbf.readVarint();
+ else if (tag === 5) pbf.readPackedVarint(obj.commands);
+ else if (tag === 6) obj.step = pbf.readFloat();
+ else if (tag === 7) pbf.readPackedSVarint(obj.diffs);
+ else if (tag === 8) obj.clip_rule = pbf.readVarint();
+}
+
+/**
+ * @typedef {object} Fill
+ * @property {number} [rgb_color]
+ * @property {number} [linear_gradient_idx]
+ * @property {number} [radial_gradient_idx]
+ * @property {number} [opacity]
+ * @property {FillRule} [rule]
+ * @property {"rgb_color" | "linear_gradient_idx" | "radial_gradient_idx"} [paint]
+ */
+
+/**
+ * @param {Pbf} pbf
+ * @param {number} [end]
+ * @returns {Fill}
+ */
+export function readFill(pbf, end) {
+ return pbf.readFields(readFillField, {rgb_color: 0, paint: "rgb_color", opacity: 255, rule: 1}, end);
+}
+
+/**
+ * @param {number} tag
+ * @param {Fill} obj
+ * @param {Pbf} pbf
+ */
+function readFillField(tag, obj, pbf) {
+ if (tag === 1) { obj.rgb_color = pbf.readVarint(); obj.paint = "rgb_color"; }
+ else if (tag === 2) { obj.linear_gradient_idx = pbf.readVarint(); obj.paint = "linear_gradient_idx"; }
+ else if (tag === 3) { obj.radial_gradient_idx = pbf.readVarint(); obj.paint = "radial_gradient_idx"; }
+ else if (tag === 5) obj.opacity = pbf.readVarint();
+ else if (tag === 6) obj.rule = pbf.readVarint();
+}
+
+/**
+ * @typedef {object} Stroke
+ * @property {number} [rgb_color]
+ * @property {number} [linear_gradient_idx]
+ * @property {number} [radial_gradient_idx]
+ * @property {number[]} dasharray
+ * @property {number} [dashoffset]
+ * @property {number} [miterlimit]
+ * @property {number} [opacity]
+ * @property {number} [width]
+ * @property {LineCap} [linecap]
+ * @property {LineJoin} [linejoin]
+ * @property {"rgb_color" | "linear_gradient_idx" | "radial_gradient_idx"} [paint]
+ */
+
+/**
+ * @param {Pbf} pbf
+ * @param {number} [end]
+ * @returns {Stroke}
+ */
+export function readStroke(pbf, end) {
+ return pbf.readFields(readStrokeField, {rgb_color: 0, paint: "rgb_color", dasharray: [], dashoffset: 0, miterlimit: 4, opacity: 255, width: 1, linecap: 1, linejoin: 1}, end);
+}
+
+/**
+ * @param {number} tag
+ * @param {Stroke} obj
+ * @param {Pbf} pbf
+ */
+function readStrokeField(tag, obj, pbf) {
+ if (tag === 1) { obj.rgb_color = pbf.readVarint(); obj.paint = "rgb_color"; }
+ else if (tag === 2) { obj.linear_gradient_idx = pbf.readVarint(); obj.paint = "linear_gradient_idx"; }
+ else if (tag === 3) { obj.radial_gradient_idx = pbf.readVarint(); obj.paint = "radial_gradient_idx"; }
+ else if (tag === 5) pbf.readPackedFloat(obj.dasharray);
+ else if (tag === 6) obj.dashoffset = pbf.readFloat();
+ else if (tag === 7) obj.miterlimit = pbf.readFloat();
+ else if (tag === 8) obj.opacity = pbf.readVarint();
+ else if (tag === 9) obj.width = pbf.readFloat();
+ else if (tag === 10) obj.linecap = pbf.readVarint();
+ else if (tag === 11) obj.linejoin = pbf.readVarint();
+}
+
+/**
+ * @typedef {object} LinearGradient
+ * @property {Transform} [transform]
+ * @property {SpreadMethod} [spread_method]
+ * @property {Stop[]} stops
+ * @property {number} [x1]
+ * @property {number} [y1]
+ * @property {number} [x2]
+ * @property {number} [y2]
+ */
+
+/**
+ * @param {Pbf} pbf
+ * @param {number} [end]
+ * @returns {LinearGradient}
+ */
+export function readLinearGradient(pbf, end) {
+ return pbf.readFields(readLinearGradientField, {spread_method: 1, stops: [], x1: 0, y1: 0, x2: 1, y2: 0}, end);
+}
+
+/**
+ * @param {number} tag
+ * @param {LinearGradient} obj
+ * @param {Pbf} pbf
+ */
+function readLinearGradientField(tag, obj, pbf) {
+ if (tag === 1) obj.transform = readTransform(pbf, pbf.readVarint() + pbf.pos);
+ else if (tag === 2) obj.spread_method = pbf.readVarint();
+ else if (tag === 3) obj.stops.push(readStop(pbf, pbf.readVarint() + pbf.pos));
+ else if (tag === 4) obj.x1 = pbf.readFloat();
+ else if (tag === 5) obj.y1 = pbf.readFloat();
+ else if (tag === 6) obj.x2 = pbf.readFloat();
+ else if (tag === 7) obj.y2 = pbf.readFloat();
+}
+
+/**
+ * @typedef {object} Stop
+ * @property {number} [offset]
+ * @property {number} [opacity]
+ * @property {number} [rgb_color]
+ */
+
+/**
+ * @param {Pbf} pbf
+ * @param {number} [end]
+ * @returns {Stop}
+ */
+export function readStop(pbf, end) {
+ return pbf.readFields(readStopField, {offset: 0, opacity: 255, rgb_color: 0}, end);
+}
+
+/**
+ * @param {number} tag
+ * @param {Stop} obj
+ * @param {Pbf} pbf
+ */
+function readStopField(tag, obj, pbf) {
+ if (tag === 1) obj.offset = pbf.readFloat();
+ else if (tag === 2) obj.opacity = pbf.readVarint();
+ else if (tag === 3) obj.rgb_color = pbf.readVarint();
+}
+
+/**
+ * @typedef {object} RadialGradient
+ * @property {Transform} [transform]
+ * @property {SpreadMethod} [spread_method]
+ * @property {Stop[]} stops
+ * @property {number} [cx]
+ * @property {number} [cy]
+ * @property {number} [r]
+ * @property {number} [fx]
+ * @property {number} [fy]
+ * @property {number} [fr]
+ */
+
+/**
+ * @param {Pbf} pbf
+ * @param {number} [end]
+ * @returns {RadialGradient}
+ */
+export function readRadialGradient(pbf, end) {
+ return pbf.readFields(readRadialGradientField, {spread_method: 1, stops: [], cx: 0.5, cy: 0.5, r: 0.5, fx: 0.5, fy: 0.5, fr: 0}, end);
+}
+
+/**
+ * @param {number} tag
+ * @param {RadialGradient} obj
+ * @param {Pbf} pbf
+ */
+function readRadialGradientField(tag, obj, pbf) {
+ if (tag === 1) obj.transform = readTransform(pbf, pbf.readVarint() + pbf.pos);
+ else if (tag === 2) obj.spread_method = pbf.readVarint();
+ else if (tag === 3) obj.stops.push(readStop(pbf, pbf.readVarint() + pbf.pos));
+ else if (tag === 4) obj.cx = pbf.readFloat();
+ else if (tag === 5) obj.cy = pbf.readFloat();
+ else if (tag === 6) obj.r = pbf.readFloat();
+ else if (tag === 7) obj.fx = pbf.readFloat();
+ else if (tag === 8) obj.fy = pbf.readFloat();
+ else if (tag === 9) obj.fr = pbf.readFloat();
+}
+
+/**
+ * @typedef {object} ClipPath
+ * @property {Transform} [transform]
+ * @property {number} [clip_path_idx]
+ * @property {Path[]} paths
+ */
+
+/**
+ * @param {Pbf} pbf
+ * @param {number} [end]
+ * @returns {ClipPath}
+ */
+export function readClipPath(pbf, end) {
+ return pbf.readFields(readClipPathField, {paths: []}, end);
+}
+
+/**
+ * @param {number} tag
+ * @param {ClipPath} obj
+ * @param {Pbf} pbf
+ */
+function readClipPathField(tag, obj, pbf) {
+ if (tag === 1) obj.transform = readTransform(pbf, pbf.readVarint() + pbf.pos);
+ else if (tag === 2) obj.clip_path_idx = pbf.readVarint();
+ else if (tag === 3) obj.paths.push(readPath(pbf, pbf.readVarint() + pbf.pos));
+}
+
+/**
+ * @typedef {object} Mask
+ * @property {number} [left]
+ * @property {number} [width]
+ * @property {number} [top]
+ * @property {number} [height]
+ * @property {MaskType} [mask_type]
+ * @property {number} [mask_idx]
+ * @property {Transform} [transform]
+ * @property {Node[]} children
+ */
+
+/**
+ * @param {Pbf} pbf
+ * @param {number} [end]
+ * @returns {Mask}
+ */
+export function readMask(pbf, end) {
+ return pbf.readFields(readMaskField, {left: 0, width: 20, mask_type: 1, children: []}, end);
+}
+
+/**
+ * @param {number} tag
+ * @param {Mask} obj
+ * @param {Pbf} pbf
+ */
+function readMaskField(tag, obj, pbf) {
+ if (tag === 1) obj.left = obj.top = pbf.readFloat();
+ else if (tag === 2) obj.width = obj.height = pbf.readFloat();
+ else if (tag === 3) obj.top = pbf.readFloat();
+ else if (tag === 4) obj.height = pbf.readFloat();
+ else if (tag === 5) obj.mask_type = pbf.readVarint();
+ else if (tag === 6) obj.mask_idx = pbf.readVarint();
+ else if (tag === 7) obj.transform = readTransform(pbf, pbf.readVarint() + pbf.pos);
+ else if (tag === 8) obj.children.push(readNode(pbf, pbf.readVarint() + pbf.pos));
+}
diff --git a/src/data/usvg/usvg_pb_renderer.ts b/src/data/usvg/usvg_pb_renderer.ts
new file mode 100644
index 00000000000..df201a0d259
--- /dev/null
+++ b/src/data/usvg/usvg_pb_renderer.ts
@@ -0,0 +1,357 @@
+import {PaintOrder, PathCommand, LineCap, LineJoin, FillRule, ClipRule, MaskType} from './usvg_pb_decoder.js';
+
+import type {UsvgTree, Icon, Group, Node, Path, Transform, ClipPath, Mask, LinearGradient, RadialGradient} from './usvg_pb_decoder';
+
+/**
+ * Renders a uSVG icon to an ImageData object.
+ *
+ * @param icon uSVG icon.
+ * @param transform Transformation matrix.
+ * @returns ImageData object.
+ */
+export function renderIcon(icon: Icon, transform?: DOMMatrix): ImageData {
+ const tree = icon.usvg_tree;
+
+ let naturalWidth = tree.width;
+ let naturalHeight = tree.height;
+ if (naturalWidth == null || naturalHeight == null) {
+ naturalWidth = naturalWidth || 0;
+ naturalHeight = naturalHeight || naturalWidth;
+ }
+
+ const tr = transform ? transform : new DOMMatrix();
+ const renderedWidth = Math.round(naturalWidth * tr.a); // transform.sx
+ const renderedHeight = Math.round(naturalHeight * tr.d); // transform.sy
+
+ const offscreenCanvas = new OffscreenCanvas(renderedWidth, renderedHeight);
+ const context = offscreenCanvas.getContext('2d');
+
+ renderNodes(context, tr, tree, tree as unknown as Group);
+ return context.getImageData(0, 0, renderedWidth, renderedHeight);
+}
+
+function renderNodes(context: OffscreenCanvasRenderingContext2D, transform: DOMMatrix, tree: UsvgTree, parent: Group) {
+ for (const node of parent.children) {
+ renderNode(context, transform, tree, node);
+ }
+}
+
+function renderNode(context: OffscreenCanvasRenderingContext2D, transform: DOMMatrix, tree: UsvgTree, node: Node) {
+ if (node.group) {
+ context.save();
+ renderGroup(context, transform, tree, node.group);
+ context.restore();
+ } else if (node.path) {
+ context.save();
+ renderPath(context, transform, tree, node.path);
+ context.restore();
+ } else {
+ assert(false, 'Not implemented');
+ }
+}
+
+function shouldIsolate(group: Group, hasClipPath: boolean, hasMask: boolean): boolean {
+ return group.opacity !== 255 || hasClipPath || hasMask;
+}
+
+function renderGroup(context: OffscreenCanvasRenderingContext2D, transform: DOMMatrix, tree: UsvgTree, group: Group) {
+ const mask = group.mask_idx != null ? tree.masks[group.mask_idx] : null;
+ const clipPath = group.clip_path_idx != null ? tree.clip_paths[group.clip_path_idx] : null;
+
+ if (group.transform) {
+ transform = makeTransform(group.transform).preMultiplySelf(transform);
+ }
+
+ if (!shouldIsolate(group, clipPath != null, mask != null)) {
+ renderNodes(context, transform, tree, group);
+ return;
+ }
+
+ const groupCanvas = new OffscreenCanvas(context.canvas.width, context.canvas.height);
+ const groupContext = groupCanvas.getContext('2d');
+
+ if (clipPath) {
+ applyClipPath(groupContext, transform, tree, clipPath);
+ }
+
+ renderNodes(groupContext, transform, tree, group);
+
+ if (mask) {
+ applyMask(groupContext, transform, tree, mask);
+ }
+
+ context.globalAlpha = toAlpha(group.opacity);
+ context.drawImage(groupCanvas, 0, 0);
+}
+
+function renderPath(context: OffscreenCanvasRenderingContext2D, transform: DOMMatrix, tree: UsvgTree, path: Path) {
+ const path2d = makePath2d(path);
+ context.setTransform(transform);
+
+ if (path.paint_order === PaintOrder.PAINT_ORDER_FILL_AND_STROKE) {
+ fillPath(context, tree, path, path2d);
+ strokePath(context, tree, path, path2d);
+ } else {
+ strokePath(context, tree, path, path2d);
+ fillPath(context, tree, path, path2d);
+ }
+}
+
+function fillPath(context: OffscreenCanvasRenderingContext2D, tree: UsvgTree, path: Path, path2d: Path2D) {
+ const fill = path.fill;
+ if (!fill) return;
+
+ switch (fill.paint) {
+ case 'rgb_color':
+ context.fillStyle = toRGBA(fill.rgb_color, fill.opacity);
+ break;
+ case 'linear_gradient_idx':
+ context.fillStyle = convertLinearGradient(context, tree.linear_gradients[fill.linear_gradient_idx]);
+ break;
+ case 'radial_gradient_idx':
+ context.fillStyle = convertRadialGradient(context, tree.radial_gradients[fill.radial_gradient_idx]);
+ }
+
+ let fillRule: CanvasFillRule;
+ switch (fill.rule) {
+ case FillRule.FILL_RULE_NON_ZERO:
+ fillRule = 'nonzero';
+ break;
+ case FillRule.FILL_RULE_EVEN_ODD:
+ fillRule = 'evenodd';
+ }
+
+ context.fill(path2d, fillRule);
+}
+
+function strokePath(context: OffscreenCanvasRenderingContext2D, tree: UsvgTree, path: Path, path2d: Path2D) {
+ const stroke = path.stroke;
+ if (!stroke) return;
+
+ context.lineWidth = stroke.width;
+ context.miterLimit = stroke.miterlimit;
+ context.setLineDash(stroke.dasharray);
+ context.lineDashOffset = stroke.dashoffset;
+
+ switch (stroke.paint) {
+ case 'rgb_color':
+ context.strokeStyle = toRGBA(stroke.rgb_color, stroke.opacity);
+ break;
+ case 'linear_gradient_idx':
+ context.strokeStyle = convertLinearGradient(context, tree.linear_gradients[stroke.linear_gradient_idx]);
+ break;
+ case 'radial_gradient_idx':
+ context.strokeStyle = convertRadialGradient(context, tree.radial_gradients[stroke.radial_gradient_idx]);
+ }
+
+ switch (stroke.linejoin) {
+ case LineJoin.LINE_JOIN_MITER:
+ context.lineJoin = 'miter';
+ break;
+ case LineJoin.LINE_JOIN_ROUND:
+ context.lineJoin = 'round';
+ break;
+ case LineJoin.LINE_JOIN_BEVEL:
+ context.lineJoin = 'bevel';
+ }
+
+ switch (stroke.linecap) {
+ case LineCap.LINE_CAP_BUTT:
+ context.lineCap = 'butt';
+ break;
+ case LineCap.LINE_CAP_ROUND:
+ context.lineCap = 'round';
+ break;
+ case LineCap.LINE_CAP_SQUARE:
+ context.lineCap = 'square';
+ }
+
+ context.stroke(path2d);
+}
+
+function convertLinearGradient(context: OffscreenCanvasRenderingContext2D, gradient: LinearGradient): CanvasGradient | string {
+ if (gradient.stops.length === 1) {
+ const stop = gradient.stops[0];
+ return toRGBA(stop.rgb_color, stop.opacity);
+ }
+
+ const tr = makeTransform(gradient.transform);
+ const {x1, y1, x2, y2} = gradient;
+ const start = tr.transformPoint(new DOMPoint(x1, y1));
+ const end = tr.transformPoint(new DOMPoint(x2, y2));
+
+ const linearGradient = context.createLinearGradient(start.x, start.y, end.x, end.y);
+ for (const stop of gradient.stops) {
+ linearGradient.addColorStop(stop.offset, toRGBA(stop.rgb_color, stop.opacity));
+ }
+
+ return linearGradient;
+}
+
+function convertRadialGradient(context: OffscreenCanvasRenderingContext2D, gradient: RadialGradient): CanvasGradient | string {
+ if (gradient.stops.length === 1) {
+ const stop = gradient.stops[0];
+ return toRGBA(stop.rgb_color, stop.opacity);
+ }
+
+ const tr = makeTransform(gradient.transform);
+ const {fx, fy, cx, cy} = gradient;
+ const start = tr.transformPoint(new DOMPoint(fx, fy));
+ const end = tr.transformPoint(new DOMPoint(cx, cy));
+
+ // Extract the scale component from the transform
+ const uniformScale = (tr.a + tr.d) / 2;
+ const r1 = gradient.r * uniformScale;
+
+ const radialGradient = context.createRadialGradient(start.x, start.y, 0, end.x, end.y, r1);
+ for (const stop of gradient.stops) {
+ radialGradient.addColorStop(stop.offset, toRGBA(stop.rgb_color, stop.opacity));
+ }
+
+ return radialGradient;
+}
+
+function applyClipPath(context: OffscreenCanvasRenderingContext2D, transform: DOMMatrix, tree: UsvgTree, clipPath: ClipPath) {
+ const tr = makeTransform(clipPath.transform).preMultiplySelf(transform);
+
+ if (clipPath.clip_path_idx != null) {
+ const selfClipPath = clipPath.clip_path_idx != null ? tree.clip_paths[clipPath.clip_path_idx] : null;
+ applyClipPath(context, tr, tree, selfClipPath);
+ }
+
+ for (const path of clipPath.paths) {
+ const path2d = new Path2D();
+ path2d.addPath(makePath2d(path), tr);
+
+ let clipRule;
+ switch (path.clip_rule) {
+ case ClipRule.CLIP_RULE_NON_ZERO:
+ clipRule = 'nonzero';
+ break;
+ case ClipRule.CLIP_RULE_EVEN_ODD:
+ clipRule = 'evenodd';
+ }
+
+ context.clip(path2d, clipRule);
+ }
+}
+
+function applyMask(context: OffscreenCanvasRenderingContext2D, transform: DOMMatrix, tree: UsvgTree, mask: Mask) {
+ if (mask.children.length === 0) {
+ return;
+ }
+
+ let maskWidth = mask.width;
+ let maskHeight = mask.height;
+ if (maskWidth == null || maskHeight == null) {
+ maskWidth = maskWidth || 0;
+ maskHeight = maskHeight || maskWidth;
+ }
+
+ let maskLeft = mask.left;
+ let maskTop = mask.top;
+ if (maskLeft == null || maskTop == null) {
+ maskLeft = maskLeft || 0;
+ maskTop = maskTop || maskLeft;
+ }
+
+ const maskCanvas = new OffscreenCanvas(maskWidth, maskHeight);
+ const maskContext = maskCanvas.getContext('2d');
+
+ for (const node of mask.children) {
+ renderNode(maskContext, transform, tree, node);
+ }
+
+ const maskImageData = maskContext.getImageData(0, 0, maskWidth, maskHeight);
+ const maskData = maskImageData.data;
+
+ if (mask.mask_type === MaskType.MASK_TYPE_LUMINANCE) {
+ // Set alpha to luminance
+ for (let i = 0; i < maskData.length; i += 4) {
+ const r = maskData[i];
+ const g = maskData[i + 1];
+ const b = maskData[i + 2];
+ const luminance = 0.2126 * r + 0.7152 * g + 0.0722 * b;
+ maskData[i + 3] = luminance;
+ }
+ }
+
+ maskContext.putImageData(maskImageData, 0, 0);
+
+ context.globalCompositeOperation = 'destination-in';
+ context.drawImage(maskCanvas, maskLeft, maskTop);
+}
+
+function toAlpha(opacity: number) {
+ return opacity / 255;
+}
+
+function toRGBA(color: number, opacity: number = 1) {
+ return `rgba(${(color >> 16) & 255}, ${(color >> 8) & 255}, ${color & 255}, ${toAlpha(opacity)})`;
+}
+
+// Transform
+// sx kx tx
+// ky sy ty
+// 0 0 1
+function makeTransform(transform?: Transform) {
+ return transform ?
+ new DOMMatrix([transform.sx, transform.ky, transform.kx, transform.sy, transform.tx, transform.ty]) :
+ new DOMMatrix();
+}
+
+function makePath2d(path: Path): Path2D {
+ const path2d = new Path2D();
+ const step = path.step || 1;
+
+ let x = path.diffs[0] * step;
+ let y = path.diffs[1] * step;
+ path2d.moveTo(x, y);
+
+ for (let i = 0, j = 2; i < path.commands.length; i++) {
+ switch (path.commands[i]) {
+ case PathCommand.PATH_COMMAND_MOVE: {
+ x += path.diffs[j++] * step;
+ y += path.diffs[j++] * step;
+ path2d.moveTo(x, y);
+ break;
+ }
+ case PathCommand.PATH_COMMAND_LINE: {
+ x += path.diffs[j++] * step;
+ y += path.diffs[j++] * step;
+ path2d.lineTo(x, y);
+ break;
+ }
+ case PathCommand.PATH_COMMAND_QUAD: {
+ const cpx = x + path.diffs[j++] * step;
+ const cpy = y + path.diffs[j++] * step;
+ x = cpx + path.diffs[j++] * step;
+ y = cpy + path.diffs[j++] * step;
+ path2d.quadraticCurveTo(cpx, cpy, x, y);
+ break;
+ }
+ case PathCommand.PATH_COMMAND_CUBIC: {
+ const cp1x = x + path.diffs[j++] * step;
+ const cp1y = y + path.diffs[j++] * step;
+ const cp2x = cp1x + path.diffs[j++] * step;
+ const cp2y = cp1y + path.diffs[j++] * step;
+ x = cp2x + path.diffs[j++] * step;
+ y = cp2y + path.diffs[j++] * step;
+ path2d.bezierCurveTo(cp1x, cp1y, cp2x, cp2y, x, y);
+ break;
+ }
+ case PathCommand.PATH_COMMAND_CLOSE: {
+ path2d.closePath();
+ break;
+ }
+ default:
+ assert(false, `Unknown path command "${path.commands[i]}"`);
+ }
+ }
+
+ return path2d;
+}
+
+function assert(condition: boolean, message: string) {
+ console.assert(condition, message);
+}
diff --git a/src/geo/projection/adjustments.ts b/src/geo/projection/adjustments.ts
index f5bc3bad85c..73a6db3d036 100644
--- a/src/geo/projection/adjustments.ts
+++ b/src/geo/projection/adjustments.ts
@@ -25,12 +25,12 @@ export function getScaleAdjustment(transform: Transform): number {
return scaleAdjustment;
}
-export function getProjectionAdjustmentInverted(transform: Transform): number[] {
+export function getProjectionAdjustmentInverted(transform: Transform): mat2 {
const m = getProjectionAdjustments(transform, true);
return mat2.invert([] as unknown as mat2, [
m[0], m[1],
m[4], m[5]]
- ) as number[];
+ );
}
export function getProjectionInterpolationT(
diff --git a/src/geo/projection/albers.ts b/src/geo/projection/albers.ts
index f9cbbaf08de..6934f58ea29 100644
--- a/src/geo/projection/albers.ts
+++ b/src/geo/projection/albers.ts
@@ -24,7 +24,7 @@ export default class Albers extends Projection {
this.r0 = Math.sqrt(this.c) / this.n;
}
- project(lng: number, lat: number): ProjectedPoint {
+ override project(lng: number, lat: number): ProjectedPoint {
const {n, c, r0} = this;
const lambda = degToRad(lng - this.center[0]);
const phi = degToRad(lat);
@@ -35,7 +35,7 @@ export default class Albers extends Projection {
return {x, y, z: 0};
}
- unproject(x: number, y: number): LngLat {
+ override unproject(x: number, y: number): LngLat {
const {n, c, r0} = this;
const r0y = r0 + y;
let l = Math.atan2(x, Math.abs(r0y)) * Math.sign(r0y);
diff --git a/src/geo/projection/cylindrical_equal_area.ts b/src/geo/projection/cylindrical_equal_area.ts
index 88b6a29df6d..d52f2516690 100644
--- a/src/geo/projection/cylindrical_equal_area.ts
+++ b/src/geo/projection/cylindrical_equal_area.ts
@@ -21,7 +21,7 @@ export default class CylindricalEqualArea extends Projection {
this.supportsWorldCopies = true;
}
- project(lng: number, lat: number): ProjectedPoint {
+ override project(lng: number, lat: number): ProjectedPoint {
const {scale, cosPhi} = this;
const x = degToRad(lng) * cosPhi;
const y = Math.sin(degToRad(lat)) / cosPhi;
@@ -33,7 +33,7 @@ export default class CylindricalEqualArea extends Projection {
};
}
- unproject(x: number, y: number): LngLat {
+ override unproject(x: number, y: number): LngLat {
const {scale, cosPhi} = this;
const x_ = (x - 0.5) / scale;
const y_ = -(y - 0.5) / scale;
diff --git a/src/geo/projection/equal_earth.ts b/src/geo/projection/equal_earth.ts
index c78d2eecd1e..e7c33556a7a 100644
--- a/src/geo/projection/equal_earth.ts
+++ b/src/geo/projection/equal_earth.ts
@@ -13,7 +13,7 @@ const M = Math.sqrt(3) / 2;
export default class EqualEarth extends Projection {
- project(lng: number, lat: number): ProjectedPoint {
+ override project(lng: number, lat: number): ProjectedPoint {
// based on https://github.com/d3/d3-geo, MIT-licensed
lat = lat / 180 * Math.PI;
lng = lng / 180 * Math.PI;
@@ -30,7 +30,7 @@ export default class EqualEarth extends Projection {
};
}
- unproject(x: number, y: number): LngLat {
+ override unproject(x: number, y: number): LngLat {
// based on https://github.com/d3/d3-geo, MIT-licensed
x = (2 * x - 0.5) * Math.PI;
y = (2 * (1 - y) - 1) * Math.PI;
diff --git a/src/geo/projection/equirectangular.ts b/src/geo/projection/equirectangular.ts
index d489bdc3e12..769326210b7 100644
--- a/src/geo/projection/equirectangular.ts
+++ b/src/geo/projection/equirectangular.ts
@@ -14,13 +14,13 @@ export default class Equirectangular extends Projection {
this.supportsWorldCopies = true;
}
- project(lng: number, lat: number): ProjectedPoint {
+ override project(lng: number, lat: number): ProjectedPoint {
const x = 0.5 + lng / 360;
const y = 0.5 - lat / 360;
return {x, y, z: 0};
}
- unproject(x: number, y: number): LngLat {
+ override unproject(x: number, y: number): LngLat {
const lng = (x - 0.5) * 360;
const lat = clamp((0.5 - y) * 360, -MAX_MERCATOR_LATITUDE, MAX_MERCATOR_LATITUDE);
return new LngLat(lng, lat);
diff --git a/src/geo/projection/far_z.ts b/src/geo/projection/far_z.ts
index 88f63a2a903..a96c54e9459 100644
--- a/src/geo/projection/far_z.ts
+++ b/src/geo/projection/far_z.ts
@@ -46,7 +46,7 @@ export function farthestPixelDistanceOnSphere(tr: Transform, pixelsPerMeter: num
const cameraPosition = vec3.add([] as any, vec3.scale([] as any, forward, -cameraDistance), [0, 0, centerPixelAltitude]);
const globeRadius = tr.worldSize / (2.0 * Math.PI);
- const globeCenter = [0, 0, -globeRadius];
+ const globeCenter: vec3 = [0, 0, -globeRadius];
const aspectRatio = tr.width / tr.height;
const tanFovAboveCenter = Math.tan(tr.fovAboveCenter);
@@ -55,23 +55,21 @@ export function farthestPixelDistanceOnSphere(tr: Transform, pixelsPerMeter: num
const right = vec3.scale([] as any, camera.right(), tanFovAboveCenter * aspectRatio);
const dir = vec3.normalize([] as any, vec3.add([] as any, vec3.add([] as any, forward, up), right));
- const pointOnGlobe = [];
+ const pointOnGlobe = [] as unknown as vec3;
const ray = new Ray(cameraPosition, dir);
let pixelDistance;
- // @ts-expect-error - TS2345 - Argument of type 'number[]' is not assignable to parameter of type 'vec3'.
if (ray.closestPointOnSphere(globeCenter, globeRadius, pointOnGlobe)) {
- // @ts-expect-error - TS2345 - Argument of type '[]' is not assignable to parameter of type 'ReadonlyVec3'.
- const p0 = vec3.add([] as any, pointOnGlobe as [], globeCenter as [number, number, number]);
- const p1 = vec3.sub([] as any, p0, cameraPosition);
+ const p0 = vec3.add([] as unknown as vec3, pointOnGlobe, globeCenter);
+ const p1 = vec3.sub([] as unknown as vec3, p0, cameraPosition);
// Globe is fully covering the view frustum. Project the intersection
// point to the camera view vector in order to find the pixel distance
pixelDistance = Math.cos(tr.fovAboveCenter) * vec3.length(p1);
} else {
// Background space is visible. Find distance to the point of the
// globe where surface normal is parallel to the view vector
- const globeCenterToCamera = vec3.sub([] as any, cameraPosition, globeCenter as [number, number, number]);
- const cameraToGlobe = vec3.sub([] as any, globeCenter as [number, number, number], cameraPosition);
+ const globeCenterToCamera = vec3.sub([] as unknown as vec3, cameraPosition, globeCenter);
+ const cameraToGlobe = vec3.sub([] as unknown as vec3, globeCenter, cameraPosition);
vec3.normalize(cameraToGlobe, cameraToGlobe);
const cameraHeight = vec3.length(globeCenterToCamera) - globeRadius;
diff --git a/src/geo/projection/globe.ts b/src/geo/projection/globe.ts
index 05b2da2cf1d..e4b916b1e90 100644
--- a/src/geo/projection/globe.ts
+++ b/src/geo/projection/globe.ts
@@ -39,7 +39,7 @@ export default class Globe extends Mercator {
this.range = [3, 5];
}
- projectTilePoint(x: number, y: number, id: CanonicalTileID): {
+ override projectTilePoint(x: number, y: number, id: CanonicalTileID): {
x: number;
y: number;
z: number;
@@ -47,13 +47,12 @@ export default class Globe extends Mercator {
const pos = tileCoordToECEF(x, y, id);
const bounds = globeTileBounds(id);
const normalizationMatrix = globeNormalizeECEF(bounds);
- // @ts-expect-error - TS2345 - Argument of type 'Float64Array' is not assignable to parameter of type 'ReadonlyMat4'.
vec3.transformMat4(pos, pos, normalizationMatrix);
return {x: pos[0], y: pos[1], z: pos[2]};
}
- locationPoint(tr: Transform, lngLat: LngLat): Point {
+ override locationPoint(tr: Transform, lngLat: LngLat): Point {
const pos = latLngToECEF(lngLat.lat, lngLat.lng);
const up = vec3.normalize([] as any, pos);
@@ -63,20 +62,18 @@ export default class Globe extends Mercator {
const upScale = mercatorZfromAltitude(1, 0) * EXTENT * elevation;
vec3.scaleAndAdd(pos, pos, up, upScale);
- // @ts-expect-error - TS2345 - Argument of type 'Float64Array' is not assignable to parameter of type 'mat4'.
- const matrix = mat4.identity(new Float64Array(16));
- // @ts-expect-error - TS2345 - Argument of type 'Float64Array' is not assignable to parameter of type 'ReadonlyMat4'.
+ const matrix = mat4.identity(new Float64Array(16) as unknown as mat4);
mat4.multiply(matrix, tr.pixelMatrix, tr.globeMatrix);
vec3.transformMat4(pos, pos, matrix);
return new Point(pos[0], pos[1]);
}
- pixelsPerMeter(lat: number, worldSize: number): number {
+ override pixelsPerMeter(lat: number, worldSize: number): number {
return mercatorZfromAltitude(1, 0) * worldSize;
}
- pixelSpaceConversion(lat: number, worldSize: number, interpolationT: number): number {
+ override pixelSpaceConversion(lat: number, worldSize: number, interpolationT: number): number {
// Using only the center latitude to determine scale causes the globe to rapidly change
// size as you pan up and down. As you approach the pole, the globe's size approaches infinity.
// This is because zoom levels are based on mercator.
@@ -90,41 +87,37 @@ export default class Globe extends Mercator {
return this.pixelsPerMeter(lat, worldSize) / combinedScale;
}
- createTileMatrix(tr: Transform, worldSize: number, id: UnwrappedTileID): Float64Array {
+ override createTileMatrix(tr: Transform, worldSize: number, id: UnwrappedTileID): mat4 {
const decode = globeDenormalizeECEF(globeTileBounds(id.canonical));
- // @ts-expect-error - TS2322 - Type 'mat4' is not assignable to type 'Float64Array'. | TS2345 - Argument of type 'Float64Array' is not assignable to parameter of type 'mat4'.
- return mat4.multiply(new Float64Array(16), tr.globeMatrix, decode);
+ return mat4.multiply(new Float64Array(16) as unknown as mat4, tr.globeMatrix, decode);
}
- createInversionMatrix(tr: Transform, id: CanonicalTileID): Float32Array {
+ override createInversionMatrix(tr: Transform, id: CanonicalTileID): Float32Array {
const {center} = tr;
const matrix = globeNormalizeECEF(globeTileBounds(id));
- // @ts-expect-error - TS2345 - Argument of type 'Float64Array' is not assignable to parameter of type 'mat4'.
mat4.rotateY(matrix, matrix, degToRad(center.lng));
- // @ts-expect-error - TS2345 - Argument of type 'Float64Array' is not assignable to parameter of type 'mat4'.
mat4.rotateX(matrix, matrix, degToRad(center.lat));
- // @ts-expect-error - TS2345 - Argument of type 'Float64Array' is not assignable to parameter of type 'mat4'.
mat4.scale(matrix, matrix, [tr._pixelsPerMercatorPixel, tr._pixelsPerMercatorPixel, 1.0]);
return Float32Array.from(matrix);
}
- pointCoordinate(tr: Transform, x: number, y: number, _: number): MercatorCoordinate {
+ override pointCoordinate(tr: Transform, x: number, y: number, _: number): MercatorCoordinate {
const coord = globePointCoordinate(tr, x, y, true);
if (!coord) { return new MercatorCoordinate(0, 0); } // This won't happen, is here for Flow
return coord;
}
- pointCoordinate3D(tr: Transform, x: number, y: number): vec3 | null | undefined {
+ override pointCoordinate3D(tr: Transform, x: number, y: number): vec3 | null | undefined {
const coord = this.pointCoordinate(tr, x, y, 0);
return [coord.x, coord.y, coord.z];
}
- isPointAboveHorizon(tr: Transform, p: Point): boolean {
+ override isPointAboveHorizon(tr: Transform, p: Point): boolean {
const raycastOnGlobe = globePointCoordinate(tr, p.x, p.y, false);
return !raycastOnGlobe;
}
- farthestPixelDistance(tr: Transform): number {
+ override farthestPixelDistance(tr: Transform): number {
const pixelsPerMeter = this.pixelsPerMeter(tr.center.lat, tr.worldSize);
const globePixelDistance = farthestPixelDistanceOnSphere(tr, pixelsPerMeter);
const t = globeToMercatorTransition(tr.zoom);
@@ -144,11 +137,11 @@ export default class Globe extends Mercator {
return globePixelDistance;
}
- upVector(id: CanonicalTileID, x: number, y: number): [number, number, number] {
+ override upVector(id: CanonicalTileID, x: number, y: number): [number, number, number] {
return tileCoordToECEF(x, y, id, 1);
}
- upVectorScale(id: CanonicalTileID): ElevationScale {
+ override upVectorScale(id: CanonicalTileID): ElevationScale {
return {metersToTile: globeMetersToEcef(globeECEFNormalizationScale(globeTileBounds(id)))};
}
}
diff --git a/src/geo/projection/globe_util.ts b/src/geo/projection/globe_util.ts
index 2445b6aab9a..63d84394279 100644
--- a/src/geo/projection/globe_util.ts
+++ b/src/geo/projection/globe_util.ts
@@ -51,23 +51,21 @@ const GLOBE_LOW_ZOOM_TILE_AABBS = [
];
export function globePointCoordinate(tr: Transform, x: number, y: number, clampToHorizon: boolean = true): MercatorCoordinate | null | undefined {
- const point0 = vec3.scale([] as any, tr._camera.position, tr.worldSize);
- const point1 = [x, y, 1, 1];
+ const point0 = vec3.scale([] as unknown as vec3, tr._camera.position, tr.worldSize);
+ const point1: vec4 = [x, y, 1, 1];
- // @ts-expect-error - TS2345 - Argument of type 'Float64Array' is not assignable to parameter of type 'ReadonlyMat4'.
- vec4.transformMat4(point1 as [number, number, number, number], point1 as [number, number, number, number], tr.pixelMatrixInverse);
- vec4.scale(point1 as [number, number, number, number], point1 as [number, number, number, number], 1 / point1[3]);
+ vec4.transformMat4(point1, point1, tr.pixelMatrixInverse);
+ vec4.scale(point1, point1, 1 / point1[3]);
- // @ts-expect-error - TS2345 - Argument of type '[number, number, number, number]' is not assignable to parameter of type 'ReadonlyVec3'.
- const p0p1 = vec3.sub([] as any, point1 as [number, number, number, number], point0);
- const dir = vec3.normalize([] as any, p0p1);
+ const p0p1 = vec3.sub([] as unknown as vec3, point1 as unknown as vec3, point0);
+ const dir = vec3.normalize([] as unknown as vec3, p0p1);
// Find closest point on the sphere to the ray. This is a bit more involving operation
// if the ray is not intersecting with the sphere, in which case we "clamp" the ray
// to the surface of the sphere, i.e. find a tangent vector that originates from the camera position
const m = tr.globeMatrix;
- const globeCenter = [m[12], m[13], m[14]];
- const p0toCenter = vec3.sub([] as any, globeCenter as [number, number, number], point0);
+ const globeCenter: vec3 = [m[12], m[13], m[14]];
+ const p0toCenter = vec3.sub([] as any, globeCenter, point0);
const p0toCenterDist = vec3.length(p0toCenter);
const centerDir = vec3.normalize([] as any, p0toCenter);
const radius = tr.worldSize / (2.0 * Math.PI);
@@ -82,36 +80,27 @@ export function globePointCoordinate(tr: Transform, x: number, y: number, clampT
// Find the tangent vector by interpolating between camera-to-globe and camera-to-click vectors.
// First we'll find a point P1 on the clicked ray that forms a right-angled triangle with the camera position
// and the center of the globe. Angle of the tanget vector is then used as the interpolation factor
- const clampedP1 = [], origoToP1 = [];
-
- // @ts-expect-error - TS2345 - Argument of type '[]' is not assignable to parameter of type 'vec3'.
- vec3.scale(clampedP1 as [], dir, p0toCenterDist / cosAngle);
- // @ts-expect-error - TS2345 - Argument of type '[]' is not assignable to parameter of type 'vec3'. | TS2345 - Argument of type '[]' is not assignable to parameter of type 'vec3'.
- vec3.normalize(origoToP1 as [], vec3.sub(origoToP1 as [], clampedP1 as [], p0toCenter));
- // @ts-expect-error - TS2345 - Argument of type '[]' is not assignable to parameter of type 'ReadonlyVec3'.
- vec3.normalize(dir, vec3.add(dir, p0toCenter, vec3.scale(dir, origoToP1 as [], Math.tan(origoTangentAngle) * p0toCenterDist)));
+ const clampedP1 = [] as unknown as vec3;
+ const origoToP1 = [] as unknown as vec3;
+
+ vec3.scale(clampedP1, dir, p0toCenterDist / cosAngle);
+ vec3.normalize(origoToP1, vec3.sub(origoToP1, clampedP1, p0toCenter));
+ vec3.normalize(dir, vec3.add(dir, p0toCenter, vec3.scale(dir, origoToP1, Math.tan(origoTangentAngle) * p0toCenterDist)));
}
- const pointOnGlobe = [];
+ const pointOnGlobe = [] as unknown as vec3;
const ray = new Ray(point0, dir);
- // @ts-expect-error - TS2345 - Argument of type 'number[]' is not assignable to parameter of type 'vec3'.
ray.closestPointOnSphere(globeCenter, radius, pointOnGlobe);
// Transform coordinate axes to find lat & lng of the position
- // @ts-expect-error - TS2345 - Argument of type 'vec4' is not assignable to parameter of type 'ReadonlyVec3'. | TS2345 - Argument of type 'Float64Array' is not assignable to parameter of type 'mat4'.
- const xa = vec3.normalize([] as any, getColumn(m, 0));
- // @ts-expect-error - TS2345 - Argument of type 'vec4' is not assignable to parameter of type 'ReadonlyVec3'. | TS2345 - Argument of type 'Float64Array' is not assignable to parameter of type 'mat4'.
- const ya = vec3.normalize([] as any, getColumn(m, 1));
- // @ts-expect-error - TS2345 - Argument of type 'vec4' is not assignable to parameter of type 'ReadonlyVec3'. | TS2345 - Argument of type 'Float64Array' is not assignable to parameter of type 'mat4'.
- const za = vec3.normalize([] as any, getColumn(m, 2));
-
- // @ts-expect-error - TS2345 - Argument of type '[]' is not assignable to parameter of type 'ReadonlyVec3'.
- const xp = vec3.dot(xa, pointOnGlobe as []);
- // @ts-expect-error - TS2345 - Argument of type '[]' is not assignable to parameter of type 'ReadonlyVec3'.
- const yp = vec3.dot(ya, pointOnGlobe as []);
- // @ts-expect-error - TS2345 - Argument of type '[]' is not assignable to parameter of type 'ReadonlyVec3'.
- const zp = vec3.dot(za, pointOnGlobe as []);
+ const xa = vec3.normalize([] as unknown as vec3, getColumn(m, 0) as unknown as vec3);
+ const ya = vec3.normalize([] as unknown as vec3, getColumn(m, 1) as unknown as vec3);
+ const za = vec3.normalize([] as unknown as vec3, getColumn(m, 2) as unknown as vec3);
+
+ const xp = vec3.dot(xa, pointOnGlobe);
+ const yp = vec3.dot(ya, pointOnGlobe);
+ const zp = vec3.dot(za, pointOnGlobe);
const lat = radToDeg(Math.asin(-yp / radius));
let lng = radToDeg(Math.atan2(xp, zp));
@@ -127,11 +116,11 @@ export function globePointCoordinate(tr: Transform, x: number, y: number, clampT
export class Arc {
constructor(p0: vec3, p1: vec3, center: vec3) {
- this.a = vec3.sub([] as any, p0, center);
- this.b = vec3.sub([] as any, p1, center);
+ this.a = vec3.sub([] as unknown as vec3, p0, center);
+ this.b = vec3.sub([] as unknown as vec3, p1, center);
this.center = center;
- const an = vec3.normalize([] as any, this.a);
- const bn = vec3.normalize([] as any, this.b);
+ const an = vec3.normalize([] as unknown as vec3, this.a);
+ const bn = vec3.normalize([] as unknown as vec3, this.b);
this.angle = Math.acos(vec3.dot(an, bn));
}
@@ -203,25 +192,20 @@ export function transitionTileAABBinECEF(id: CanonicalTileID, tr: Transform): Aa
const n = mercatorYfromLat(bounds.getNorth()) * tr.worldSize;
const s = mercatorYfromLat(bounds.getSouth()) * tr.worldSize;
// Mercator bounds globeCorners in world/pixel space
- const nw = [w, n, 0];
- const ne = [e, n, 0];
- const sw = [w, s, 0];
- const se = [e, s, 0];
+ const nw: vec3 = [w, n, 0];
+ const ne: vec3 = [e, n, 0];
+ const sw: vec3 = [w, s, 0];
+ const se: vec3 = [e, s, 0];
// Transform Mercator globeCorners to ECEF
- // @ts-expect-error - TS2345 - Argument of type 'Float64Array' is not assignable to parameter of type 'ReadonlyMat4'.
- const worldToECEFMatrix = mat4.invert([] as any, tr.globeMatrix);
- vec3.transformMat4(nw as [number, number, number], nw as [number, number, number], worldToECEFMatrix);
- vec3.transformMat4(ne as [number, number, number], ne as [number, number, number], worldToECEFMatrix);
- vec3.transformMat4(sw as [number, number, number], sw as [number, number, number], worldToECEFMatrix);
- vec3.transformMat4(se as [number, number, number], se as [number, number, number], worldToECEFMatrix);
+ const worldToECEFMatrix = mat4.invert([] as unknown as mat4, tr.globeMatrix);
+ vec3.transformMat4(nw, nw, worldToECEFMatrix);
+ vec3.transformMat4(ne, ne, worldToECEFMatrix);
+ vec3.transformMat4(sw, sw, worldToECEFMatrix);
+ vec3.transformMat4(se, se, worldToECEFMatrix);
// Interpolate Mercator corners and globe corners
- // @ts-expect-error - TS2345 - Argument of type 'number[]' is not assignable to parameter of type 'vec3'.
corners[0] = interpolateVec3(corners[0], sw, phase);
- // @ts-expect-error - TS2345 - Argument of type 'number[]' is not assignable to parameter of type 'vec3'.
corners[1] = interpolateVec3(corners[1], se, phase);
- // @ts-expect-error - TS2345 - Argument of type 'number[]' is not assignable to parameter of type 'vec3'.
corners[2] = interpolateVec3(corners[2], ne, phase);
- // @ts-expect-error - TS2345 - Argument of type 'number[]' is not assignable to parameter of type 'vec3'.
corners[3] = interpolateVec3(corners[3], nw, phase);
return Aabb.fromPoints(corners);
@@ -249,7 +233,6 @@ export function aabbForTileOnGlobe(
// Compute world/pixel space AABB that fully encapsulates
// transformed corners of the ECEF AABB
const corners = globeTileBounds(tileId).getCorners();
- // @ts-expect-error - TS2345 - Argument of type 'Float64Array' is not assignable to parameter of type 'mat4'.
transformPoints(corners, m, scale);
return Aabb.fromPoints(corners);
}
@@ -271,44 +254,41 @@ export function aabbForTileOnGlobe(
const corners = boundsToECEF(bounds, GLOBE_RADIUS + globeMetersToEcef(tr._tileCoverLift));
// Transform the corners to world space
- // @ts-expect-error - TS2345 - Argument of type 'Float64Array' is not assignable to parameter of type 'mat4'.
transformPoints(corners, m, scale);
const mx = Number.MAX_VALUE;
- const cornerMax = [-mx, -mx, -mx];
- const cornerMin = [mx, mx, mx];
+ const cornerMax: vec3 = [-mx, -mx, -mx];
+ const cornerMin: vec3 = [mx, mx, mx];
// Extend the aabb by including the center point. There are some corner cases where center point is inside the
// tile but due to curvature aabb computed from corner points does not cover the curved area.
if (bounds.contains(tr.center)) {
for (const corner of corners) {
- vec3.min(cornerMin as [number, number, number], cornerMin as [number, number, number], corner);
- vec3.max(cornerMax as [number, number, number], cornerMax as [number, number, number], corner);
+ vec3.min(cornerMin, cornerMin, corner);
+ vec3.max(cornerMax, cornerMax, corner);
}
cornerMax[2] = 0.0;
const point = tr.point;
- const center = [point.x * scale, point.y * scale, 0];
- vec3.min(cornerMin as [number, number, number], cornerMin as [number, number, number], center as [number, number, number]);
- vec3.max(cornerMax as [number, number, number], cornerMax as [number, number, number], center as [number, number, number]);
+ const center: vec3 = [point.x * scale, point.y * scale, 0];
+ vec3.min(cornerMin, cornerMin, center);
+ vec3.max(cornerMax, cornerMax, center);
- // @ts-expect-error - TS2345 - Argument of type 'number[]' is not assignable to parameter of type 'vec3'.
return new Aabb(cornerMin, cornerMax);
}
if (tr._tileCoverLift > 0.0) {
// Early return for elevated globe tiles, where the tile cover optimization is ignored
for (const corner of corners) {
- vec3.min(cornerMin as [number, number, number], cornerMin as [number, number, number], corner);
- vec3.max(cornerMax as [number, number, number], cornerMax as [number, number, number], corner);
+ vec3.min(cornerMin, cornerMin, corner);
+ vec3.max(cornerMax, cornerMax, corner);
}
- // @ts-expect-error - TS2345 - Argument of type 'number[]' is not assignable to parameter of type 'vec3'.
return new Aabb(cornerMin, cornerMax);
}
// Compute arcs describing edges of the tile on the globe surface.
// Vertical edges revolves around the globe origin whereas horizontal edges revolves around the y-axis.
- const arcCenter = [m[12] * scale, m[13] * scale, m[14] * scale];
+ const arcCenter: vec3 = [m[12] * scale, m[13] * scale, m[14] * scale];
const tileCenter = bounds.getCenter();
const centerLat = clamp(tr.center.lat, -MAX_MERCATOR_LATITUDE, MAX_MERCATOR_LATITUDE);
@@ -335,17 +315,16 @@ export function aabbForTileOnGlobe(
closestArcIdx = dx >= 0 ? 1 : 3;
} else {
closestArcIdx = dy >= 0 ? 0 : 2;
- const yAxis = [m[4] * scale, m[5] * scale, m[6] * scale];
+ const yAxis: vec3 = [m[4] * scale, m[5] * scale, m[6] * scale];
const shift = -Math.sin(degToRad(dy >= 0 ? bounds.getSouth() : bounds.getNorth())) * GLOBE_RADIUS;
- vec3.scaleAndAdd(arcCenter as [number, number, number], arcCenter as [number, number, number], yAxis as [number, number, number], shift);
+ vec3.scaleAndAdd(arcCenter, arcCenter, yAxis, shift);
}
const arcStart = corners[closestArcIdx];
const arcEnd = corners[(closestArcIdx + 1) % 4];
- // @ts-expect-error - TS2345 - Argument of type 'number[]' is not assignable to parameter of type 'vec3'.
const closestArc = new Arc(arcStart, arcEnd, arcCenter);
- const arcExtremum = [
+ const arcExtremum: vec3 = [
(localExtremum(closestArc, 0) || arcStart[0]),
(localExtremum(closestArc, 1) || arcStart[1]),
(localExtremum(closestArc, 2) || arcStart[2])];
@@ -361,13 +340,12 @@ export function aabbForTileOnGlobe(
const mercatorMidpoint = vec3.add([] as any, mercatorCorners[closestArcIdx], mercatorCorners[(closestArcIdx + 1) % 4]);
vec3.scale(mercatorMidpoint, mercatorMidpoint, .5);
// Interpolate globe extremum toward Mercator midpoint
- // @ts-expect-error - TS2345 - Argument of type 'number[]' is not assignable to parameter of type 'vec3'.
interpolateVec3(arcExtremum, mercatorMidpoint, phase);
}
for (const corner of corners) {
- vec3.min(cornerMin as [number, number, number], cornerMin as [number, number, number], corner);
- vec3.max(cornerMax as [number, number, number], cornerMax as [number, number, number], corner);
+ vec3.min(cornerMin, cornerMin, corner);
+ vec3.max(cornerMax, cornerMax, corner);
}
// Reduce height of the aabb to match height of the closest arc. This reduces false positives
@@ -375,10 +353,9 @@ export function aabbForTileOnGlobe(
// of the view frustum
cornerMin[2] = Math.min(arcStart[2], arcEnd[2]);
- vec3.min(cornerMin as [number, number, number], cornerMin as [number, number, number], arcExtremum as [number, number, number]);
- vec3.max(cornerMax as [number, number, number], cornerMax as [number, number, number], arcExtremum as [number, number, number]);
+ vec3.min(cornerMin, cornerMin, arcExtremum);
+ vec3.max(cornerMax, cornerMax, arcExtremum);
- // @ts-expect-error - TS2345 - Argument of type 'number[]' is not assignable to parameter of type 'vec3'.
return new Aabb(cornerMin, cornerMax);
}
@@ -467,13 +444,11 @@ export function tileCoordToECEF(x: number, y: number, id: CanonicalTileID, radiu
}
export function globeECEFOrigin(tileMatrix: mat4, id: UnwrappedTileID): [number, number, number] {
- const origin = [0, 0, 0];
+ const origin: vec3 = [0, 0, 0];
const bounds = globeTileBounds(id.canonical);
const normalizationMatrix = globeNormalizeECEF(bounds);
- // @ts-expect-error - TS2345 - Argument of type 'Float64Array' is not assignable to parameter of type 'ReadonlyMat4'.
- vec3.transformMat4(origin as [number, number, number], origin as [number, number, number], normalizationMatrix);
- vec3.transformMat4(origin as [number, number, number], origin as [number, number, number], tileMatrix);
- // @ts-expect-error - TS2322 - Type 'number[]' is not assignable to type '[number, number, number]'.
+ vec3.transformMat4(origin, origin, normalizationMatrix);
+ vec3.transformMat4(origin, origin, tileMatrix);
return origin;
}
@@ -488,21 +463,17 @@ export function globeECEFNormalizationScale(
// avoid redundant allocations by sharing the same typed array for normalization/denormalization matrices;
// we never use multiple instances of these at the same time, but this might change, so let's be careful here!
-const tempMatrix = new Float64Array(16);
+const tempMatrix = new Float64Array(16) as unknown as mat4;
-export function globeNormalizeECEF(bounds: Aabb): Float64Array {
+export function globeNormalizeECEF(bounds: Aabb): mat4 {
const scale = globeECEFNormalizationScale(bounds);
- // @ts-expect-error - TS2345 - Argument of type 'Float64Array' is not assignable to parameter of type 'mat4'.
const m = mat4.fromScaling(tempMatrix, [scale, scale, scale]);
- // @ts-expect-error - TS2322 - Type 'mat4' is not assignable to type 'Float64Array'.
return mat4.translate(m, m, vec3.negate([] as any, bounds.min));
}
-export function globeDenormalizeECEF(bounds: Aabb): Float64Array {
-// @ts-expect-error - TS2345 - Argument of type 'Float64Array' is not assignable to parameter of type 'mat4'.
+export function globeDenormalizeECEF(bounds: Aabb): mat4 {
const m = mat4.fromTranslation(tempMatrix, bounds.min);
const scale = 1.0 / globeECEFNormalizationScale(bounds);
- // @ts-expect-error - TS2322 - Type 'mat4' is not assignable to type 'Float64Array'.
return mat4.scale(m, m, [scale, scale, scale]);
}
@@ -519,27 +490,25 @@ export function globePixelsToTileUnits(zoom: number, id: CanonicalTileID): numbe
return ecefPerPixel * normCoeff;
}
-function calculateGlobePosMatrix(x: number, y: number, worldSize: number, lng: number, lat: number): Float64Array {
+function calculateGlobePosMatrix(x: number, y: number, worldSize: number, lng: number, lat: number): mat4 {
// transform the globe from reference coordinate space to world space
const scale = globeECEFUnitsToPixelScale(worldSize);
- const offset = [x, y, -worldSize / (2.0 * Math.PI)];
- // @ts-expect-error - TS2345 - Argument of type 'Float64Array' is not assignable to parameter of type 'mat4'.
- const m = mat4.identity(new Float64Array(16));
- mat4.translate(m, m, offset as [number, number, number]);
+ const offset: vec3 = [x, y, -worldSize / (2.0 * Math.PI)];
+ const m = mat4.identity(new Float64Array(16) as unknown as mat4);
+ mat4.translate(m, m, offset);
mat4.scale(m, m, [scale, scale, scale]);
mat4.rotateX(m, m, degToRad(-lat));
mat4.rotateY(m, m, degToRad(-lng));
- // @ts-expect-error - TS2322 - Type 'mat4' is not assignable to type 'Float64Array'.
return m;
}
-export function calculateGlobeMatrix(tr: Transform): Float64Array {
+export function calculateGlobeMatrix(tr: Transform): mat4 {
const {x, y} = tr.point;
const {lng, lat} = tr._center;
return calculateGlobePosMatrix(x, y, tr.worldSize, lng, lat);
}
-export function calculateGlobeLabelMatrix(tr: Transform, id: CanonicalTileID): Float64Array {
+export function calculateGlobeLabelMatrix(tr: Transform, id: CanonicalTileID): mat4 {
const {x, y} = tr.point;
// Map aligned label space for globe view is the non-rotated globe itself in pixel coordinates.
@@ -549,16 +518,14 @@ export function calculateGlobeLabelMatrix(tr: Transform, id: CanonicalTileID): F
// map aligned label space. Whithout this logic map aligned symbols
// would appear larger than intended.
const m = calculateGlobePosMatrix(x, y, tr.worldSize / tr._pixelsPerMercatorPixel, 0, 0);
- // @ts-expect-error - TS2322 - Type 'mat4' is not assignable to type 'Float64Array'. | TS2345 - Argument of type 'Float64Array' is not assignable to parameter of type 'mat4'.
return mat4.multiply(m, m, globeDenormalizeECEF(globeTileBounds(id)));
}
-export function calculateGlobeMercatorMatrix(tr: Transform): Float32Array {
+export function calculateGlobeMercatorMatrix(tr: Transform): mat4 {
const zScale = tr.pixelsPerMeter;
const ws = zScale / mercatorZfromAltitude(1, tr.center.lat);
- // @ts-expect-error - TS2345 - Argument of type 'Float64Array' is not assignable to parameter of type 'mat4'.
- const posMatrix = mat4.identity(new Float64Array(16));
+ const posMatrix = mat4.identity(new Float64Array(16) as unknown as mat4);
mat4.translate(posMatrix, posMatrix, [tr.point.x, tr.point.y, 0.0]);
mat4.scale(posMatrix, posMatrix, [ws, ws, zScale]);
@@ -569,20 +536,17 @@ export function globeToMercatorTransition(zoom: number): number {
return smoothstep(GLOBE_ZOOM_THRESHOLD_MIN, GLOBE_ZOOM_THRESHOLD_MAX, zoom);
}
-export function globeMatrixForTile(id: CanonicalTileID, globeMatrix: Float64Array): Float32Array {
+export function globeMatrixForTile(id: CanonicalTileID, globeMatrix: mat4): mat4 {
const decode = globeDenormalizeECEF(globeTileBounds(id));
- // @ts-expect-error - TS2322 - Type 'mat4' is not assignable to type 'Float32Array'. | TS2345 - Argument of type 'Float64Array' is not assignable to parameter of type 'ReadonlyMat4'.
return mat4.mul(mat4.create(), globeMatrix, decode);
}
-export function globePoleMatrixForTile(z: number, x: number, tr: Transform): Float32Array {
-// @ts-expect-error - TS2345 - Argument of type 'Float64Array' is not assignable to parameter of type 'mat4'.
- const poleMatrix = mat4.identity(new Float64Array(16));
+export function globePoleMatrixForTile(z: number, x: number, tr: Transform): mat4 {
+ const poleMatrix = mat4.identity(new Float64Array(16) as unknown as mat4);
// Rotate the pole triangle fan to the correct location
const numTiles = 1 << z;
const xOffsetAngle = (x / numTiles - 0.5) * Math.PI * 2.0;
- // @ts-expect-error - TS2345 - Argument of type 'Float64Array' is not assignable to parameter of type 'ReadonlyMat4'.
mat4.rotateY(poleMatrix, tr.globeMatrix, xOffsetAngle);
return Float32Array.from(poleMatrix);
@@ -613,7 +577,7 @@ export function getGridMatrix(
const tileToLng = tileWidth / GLOBE_VERTEX_GRID_SIZE;
const tileToLat = -tileHeight / GLOBE_LATITUDINAL_GRID_LOD_TABLE[latitudinalLod];
- const matrix = [0, tileToLng, 0, tileToLat, 0, 0, n, w, 0];
+ const matrix: mat3 = [0, tileToLng, 0, tileToLat, 0, 0, n, w, 0];
if (id.z > 0) {
// Add slight padding to patch seams between tiles.
@@ -625,9 +589,9 @@ export function getGridMatrix(
const xScale = padding / tileWidth + 1;
const yScale = padding / tileHeight + 1;
- const padMatrix = [xScale, 0, 0, 0, yScale, 0, -0.5 * padding / tileToLng, 0.5 * padding / tileToLat, 1];
+ const padMatrix: mat3 = [xScale, 0, 0, 0, yScale, 0, -0.5 * padding / tileToLng, 0.5 * padding / tileToLat, 1];
- mat3.multiply(matrix as [number, number, number, number, number, number, number, number, number], matrix as [number, number, number, number, number, number, number, number, number], padMatrix as [number, number, number, number, number, number, number, number, number]);
+ mat3.multiply(matrix, matrix, padMatrix);
}
// Embed additional variables to the last row of the matrix
@@ -635,8 +599,7 @@ export function getGridMatrix(
matrix[5] = id.x;
matrix[8] = id.y;
- // @ts-expect-error - TS2322 - Type 'number[]' is not assignable to type 'mat4'.
- return matrix;
+ return matrix as unknown as mat4;
}
export function getLatitudinalLod(lat: number): number {
@@ -649,16 +612,14 @@ export function getLatitudinalLod(lat: number): number {
}
export function globeCenterToScreenPoint(tr: Transform): Point {
- const pos = [0, 0, 0];
- // @ts-expect-error - TS2345 - Argument of type 'Float64Array' is not assignable to parameter of type 'mat4'.
- const matrix = mat4.identity(new Float64Array(16));
- // @ts-expect-error - TS2345 - Argument of type 'Float64Array' is not assignable to parameter of type 'ReadonlyMat4'.
+ const pos: vec3 = [0, 0, 0];
+ const matrix = mat4.identity(new Float64Array(16) as unknown as mat4);
mat4.multiply(matrix, tr.pixelMatrix, tr.globeMatrix);
- vec3.transformMat4(pos as [number, number, number], pos as [number, number, number], matrix);
+ vec3.transformMat4(pos, pos, matrix);
return new Point(pos[0], pos[1]);
}
-function cameraPositionInECEF(tr: Transform): Array {
+function cameraPositionInECEF(tr: Transform): vec3 {
// Here "center" is the center of the globe. We refer to transform._center
// (the surface of the map on the center of the screen) as "pivot" to avoid confusion.
const centerToPivot = latLngToECEF(tr._center.lat, tr._center.lng);
@@ -678,8 +639,7 @@ function cameraPositionInECEF(tr: Transform): Array {
vec3.scale(pivotToCamera, pivotToCamera, globeMetersToEcef(tr.cameraToCenterDistance / tr.pixelsPerMeter));
vec3.transformMat4(pivotToCamera, pivotToCamera, rotation);
- // @ts-expect-error - TS2322 - Type 'vec3' is not assignable to type 'number[]'.
- return vec3.add([] as any, centerToPivot, pivotToCamera);
+ return vec3.add([] as unknown as vec3, centerToPivot, pivotToCamera);
}
// Return the angle of the normal vector at a point on the globe relative to the camera.
@@ -687,8 +647,7 @@ function cameraPositionInECEF(tr: Transform): Array {
export function globeTiltAtLngLat(tr: Transform, lngLat: LngLat): number {
const centerToPoint = latLngToECEF(lngLat.lat, lngLat.lng);
const centerToCamera = cameraPositionInECEF(tr);
- // @ts-expect-error - TS2345 - Argument of type 'number[]' is not assignable to parameter of type 'ReadonlyVec3'.
- const pointToCamera = vec3.subtract([] as any, centerToCamera, centerToPoint);
+ const pointToCamera = vec3.subtract([] as unknown as vec3, centerToCamera, centerToPoint);
return vec3.angle(pointToCamera, centerToPoint);
}
@@ -705,17 +664,15 @@ export function isLngLatBehindGlobe(tr: Transform, lngLat: LngLat): boolean {
*/
export function polesInViewport(tr: Transform): [boolean, boolean] {
// Create matrix from ECEF to screen coordinates
-// @ts-expect-error - TS2345 - Argument of type 'Float64Array' is not assignable to parameter of type 'mat4'.
- const ecefToScreenMatrix = mat4.identity(new Float64Array(16));
- // @ts-expect-error - TS2345 - Argument of type 'Float64Array' is not assignable to parameter of type 'ReadonlyMat4'.
+ const ecefToScreenMatrix = mat4.identity(new Float64Array(16) as unknown as mat4);
mat4.multiply(ecefToScreenMatrix, tr.pixelMatrix, tr.globeMatrix);
- const north = [0, GLOBE_MIN, 0];
- const south = [0, GLOBE_MAX, 0];
+ const north: vec3 = [0, GLOBE_MIN, 0];
+ const south: vec3 = [0, GLOBE_MAX, 0];
// Translate the poles from ECEF to screen coordinates
- vec3.transformMat4(north as [number, number, number], north as [number, number, number], ecefToScreenMatrix);
- vec3.transformMat4(south as [number, number, number], south as [number, number, number], ecefToScreenMatrix);
+ vec3.transformMat4(north, north, ecefToScreenMatrix);
+ vec3.transformMat4(south, south, ecefToScreenMatrix);
// Check if the poles are inside the viewport and not behind the globe surface
const northInViewport =
@@ -905,8 +862,7 @@ export class GlobeSharedBuffers {
}
_createGrid(context: Context) {
- // @ts-expect-error - TS2345 - Argument of type 'readonly [64, number, number]' is not assignable to parameter of type 'number[]'.
- const gridWithLods = this._fillGridMeshWithLods(GLOBE_VERTEX_GRID_SIZE, GLOBE_LATITUDINAL_GRID_LOD_TABLE);
+ const gridWithLods = this._fillGridMeshWithLods(GLOBE_VERTEX_GRID_SIZE, GLOBE_LATITUDINAL_GRID_LOD_TABLE as unknown as number[]);
this._gridSegments = gridWithLods.segments;
this._gridBuffer = context.createVertexBuffer(gridWithLods.vertices, posAttributes.members);
diff --git a/src/geo/projection/lambert.ts b/src/geo/projection/lambert.ts
index 038451180b8..4029d80c763 100644
--- a/src/geo/projection/lambert.ts
+++ b/src/geo/projection/lambert.ts
@@ -39,7 +39,7 @@ export default class LambertConformalConic extends Projection {
this.f = cy0 * Math.pow(tany(y0), this.n) / this.n;
}
- project(lng: number, lat: number): ProjectedPoint {
+ override project(lng: number, lat: number): ProjectedPoint {
lat = degToRad(lat);
if (this.southernCenter) lat = -lat;
lng = degToRad(lng - this.center[0]);
@@ -66,7 +66,7 @@ export default class LambertConformalConic extends Projection {
};
}
- unproject(x: number, y: number): LngLat {
+ override unproject(x: number, y: number): LngLat {
x = (2 * x - 0.5) * Math.PI;
if (this.southernCenter) y = 1 - y;
y = (2 * (1 - y) - 0.5) * Math.PI;
diff --git a/src/geo/projection/mercator.ts b/src/geo/projection/mercator.ts
index 068774fd5b9..2388ca3f1c3 100644
--- a/src/geo/projection/mercator.ts
+++ b/src/geo/projection/mercator.ts
@@ -19,13 +19,13 @@ export default class Mercator extends Projection {
this.range = null;
}
- project(lng: number, lat: number): ProjectedPoint {
+ override project(lng: number, lat: number): ProjectedPoint {
const x = mercatorXfromLng(lng);
const y = mercatorYfromLat(lat);
return {x, y, z: 0};
}
- unproject(x: number, y: number): LngLat {
+ override unproject(x: number, y: number): LngLat {
const lng = lngFromMercatorX(x);
const lat = latFromMercatorY(y);
return new LngLat(lng, lat);
diff --git a/src/geo/projection/natural_earth.ts b/src/geo/projection/natural_earth.ts
index 394b29d7f36..046ef51dc29 100644
--- a/src/geo/projection/natural_earth.ts
+++ b/src/geo/projection/natural_earth.ts
@@ -9,7 +9,7 @@ const maxPhi = degToRad(MAX_MERCATOR_LATITUDE);
export default class NaturalEarth extends Projection {
- project(lng: number, lat: number): ProjectedPoint {
+ override project(lng: number, lat: number): ProjectedPoint {
// based on https://github.com/d3/d3-geo, MIT-licensed
lat = degToRad(lat);
lng = degToRad(lng);
@@ -26,7 +26,7 @@ export default class NaturalEarth extends Projection {
};
}
- unproject(x: number, y: number): LngLat {
+ override unproject(x: number, y: number): LngLat {
// based on https://github.com/d3/d3-geo, MIT-licensed
x = (2 * x - 0.5) * Math.PI;
y = (2 * (1 - y) - 1) * Math.PI;
diff --git a/src/geo/projection/projection.ts b/src/geo/projection/projection.ts
index 0e9ed12ca92..c9d2ea2efc9 100644
--- a/src/geo/projection/projection.ts
+++ b/src/geo/projection/projection.ts
@@ -6,8 +6,8 @@ import {mat4} from 'gl-matrix';
import EXTENT from '../../style-spec/data/extent';
import tileTransform from './tile_transform';
-import type Transform from '../../geo/transform';
import type {vec3} from 'gl-matrix';
+import type Transform from '../../geo/transform';
import type MercatorCoordinate from '../mercator_coordinate';
import type {ProjectionSpecification} from '../../style-spec/types';
import type {CanonicalTileID, UnwrappedTileID} from '../../source/tile_id';
@@ -103,8 +103,7 @@ export default class Projection {
pointCoordinate3D(tr: Transform, x: number, y: number): vec3 | null | undefined {
const p = new Point(x, y);
if (tr.elevation) {
- // @ts-expect-error - TS2322 - Type 'vec4' is not assignable to type 'vec3'.
- return tr.elevation.pointCoordinate(p);
+ return tr.elevation.pointCoordinate(p) as vec3;
} else {
const mc = this.pointCoordinate(tr, p.x, p.y, 0);
return [mc.x, mc.y, mc.z];
@@ -120,16 +119,14 @@ export default class Projection {
return p.y < horizon;
}
- createInversionMatrix(tr: Transform, id: CanonicalTileID): Float32Array { // eslint-disable-line
- // @ts-expect-error - TS2322 - Type 'mat4' is not assignable to type 'Float32Array'.
+ createInversionMatrix(tr: Transform, id: CanonicalTileID): mat4 {
return identity;
}
- createTileMatrix(tr: Transform, worldSize: number, id: UnwrappedTileID): Float64Array {
+ createTileMatrix(tr: Transform, worldSize: number, id: UnwrappedTileID): mat4 {
let scale, scaledX, scaledY;
const canonical = id.canonical;
- // @ts-expect-error - TS2345 - Argument of type 'Float64Array' is not assignable to parameter of type 'mat4'.
- const posMatrix = mat4.identity(new Float64Array(16));
+ const posMatrix = mat4.identity(new Float64Array(16) as unknown as mat4);
if (this.isReprojectedInTileSpace) {
const cs = tileTransform(canonical, this);
@@ -147,7 +144,6 @@ export default class Projection {
mat4.translate(posMatrix, posMatrix, [scaledX, scaledY, 0]);
mat4.scale(posMatrix, posMatrix, [scale / EXTENT, scale / EXTENT, 1]);
- // @ts-expect-error - TS2322 - Type 'mat4' is not assignable to type 'Float64Array'.
return posMatrix;
}
diff --git a/src/geo/projection/projection_util.ts b/src/geo/projection/projection_util.ts
index ffaec6bc92e..4705502b6a5 100644
--- a/src/geo/projection/projection_util.ts
+++ b/src/geo/projection/projection_util.ts
@@ -6,23 +6,21 @@ import type SymbolBucket from '../../data/bucket/symbol_bucket';
import type Transform from '../../geo/transform';
import type Projection from './projection';
-function reconstructTileMatrix(transform: Transform, projection: Projection, coord: OverscaledTileID) {
+function reconstructTileMatrix(transform: Transform, projection: Projection, coord: OverscaledTileID): mat4 {
// Bucket being rendered is built for different map projection
// than is currently being used. Reconstruct correct matrices.
// This code path may happen during a Globe - Mercator transition
const tileMatrix = projection.createTileMatrix(transform, transform.worldSize, coord.toUnwrapped());
- // @ts-expect-error - TS2345 - Argument of type 'number[] | Float32Array | Float64Array' is not assignable to parameter of type 'ReadonlyMat4'.
return mat4.multiply(new Float32Array(16), transform.projMatrix, tileMatrix);
}
-export function getCollisionDebugTileProjectionMatrix(coord: OverscaledTileID, bucket: SymbolBucket, transform: Transform): Float32Array {
+export function getCollisionDebugTileProjectionMatrix(coord: OverscaledTileID, bucket: SymbolBucket, transform: Transform): mat4 {
if (bucket.projection.name === transform.projection.name) {
assert(coord.projMatrix);
return coord.projMatrix;
}
const tr = transform.clone();
tr.setProjection(bucket.projection);
- // @ts-expect-error - TS2322 - Type 'mat4' is not assignable to type 'Float32Array'.
return reconstructTileMatrix(tr, bucket.getProjection(), coord);
}
@@ -30,12 +28,11 @@ export function getSymbolTileProjectionMatrix(
coord: OverscaledTileID,
bucketProjection: Projection,
transform: Transform,
-): Float32Array {
+): mat4 {
if (bucketProjection.name === transform.projection.name) {
assert(coord.projMatrix);
return coord.projMatrix;
}
- // @ts-expect-error - TS2322 - Type 'mat4' is not assignable to type 'Float32Array'.
return reconstructTileMatrix(transform, bucketProjection, coord);
}
@@ -44,11 +41,10 @@ export function getSymbolPlacementTileProjectionMatrix(
bucketProjection: Projection,
transform: Transform,
runtimeProjection: string,
-): Float32Array {
+): mat4 {
if (bucketProjection.name === runtimeProjection) {
return transform.calculateProjMatrix(coord.toUnwrapped());
}
assert(transform.projection.name === bucketProjection.name);
- // @ts-expect-error - TS2322 - Type 'mat4' is not assignable to type 'Float32Array'.
return reconstructTileMatrix(transform, bucketProjection, coord);
}
diff --git a/src/geo/projection/winkel_tripel.ts b/src/geo/projection/winkel_tripel.ts
index 904051404f6..e7d56d178db 100644
--- a/src/geo/projection/winkel_tripel.ts
+++ b/src/geo/projection/winkel_tripel.ts
@@ -9,7 +9,7 @@ const maxPhi = degToRad(MAX_MERCATOR_LATITUDE);
export default class WinkelTripel extends Projection {
- project(lng: number, lat: number): ProjectedPoint {
+ override project(lng: number, lat: number): ProjectedPoint {
lat = degToRad(lat);
lng = degToRad(lng);
const cosLat = Math.cos(lat);
@@ -25,7 +25,7 @@ export default class WinkelTripel extends Projection {
};
}
- unproject(x: number, y: number): LngLat {
+ override unproject(x: number, y: number): LngLat {
// based on https://github.com/d3/d3-geo-projection, MIT-licensed
x = (2 * x - 0.5) * Math.PI;
y = (2 * (1 - y) - 1) * Math.PI;
diff --git a/src/geo/transform.ts b/src/geo/transform.ts
index db8f462446c..4c990a769ed 100644
--- a/src/geo/transform.ts
+++ b/src/geo/transform.ts
@@ -63,7 +63,7 @@ const lerp = (x: number, y: number, t: number) => { return (1 - t) * x + t * y;
const easeIn = (x: number) => {
return x * x * x * x * x;
};
-const lerpMatrix = (out: Float64Array, a: Float64Array, b: Float64Array, value: number) => {
+const lerpMatrix = (out: mat4, a: mat4, b: mat4, value: number) => {
for (let i = 0; i < 16; i++) {
out[i] = lerp(a[i], b[i], value);
}
@@ -114,45 +114,45 @@ class Transform {
cameraToCenterDistance: number;
// Projection from mercator coordinates ([0, 0] nw, [1, 1] se) to GL clip coordinates
- mercatorMatrix: Array;
+ mercatorMatrix: mat4;
// Translate points in mercator coordinates to be centered about the camera, with units chosen
// for screen-height-independent scaling of fog. Not affected by orientation of camera.
- mercatorFogMatrix: Float32Array;
+ mercatorFogMatrix: mat4;
// Projection from world coordinates (mercator scaled by worldSize) to clip coordinates
- projMatrix: Array | Float32Array | Float64Array;
- invProjMatrix: Float64Array;
+ projMatrix: mat4;
+ invProjMatrix: mat4;
// Projection matrix with expanded farZ on globe projection
- expandedFarZProjMatrix: Array | Float32Array | Float64Array;
+ expandedFarZProjMatrix: mat4;
// Same as projMatrix, pixel-aligned to avoid fractional pixels for raster tiles
- alignedProjMatrix: Float64Array;
+ alignedProjMatrix: mat4;
// From world coordinates to screen pixel coordinates (projMatrix premultiplied by labelPlaneMatrix)
- pixelMatrix: Float64Array;
- pixelMatrixInverse: Float64Array;
+ pixelMatrix: mat4;
+ pixelMatrixInverse: mat4;
- worldToFogMatrix: Float64Array;
- skyboxMatrix: Float32Array;
+ worldToFogMatrix: mat4;
+ skyboxMatrix: mat4;
- starsProjMatrix: Float32Array;
+ starsProjMatrix: mat4;
// Transform from screen coordinates to GL NDC, [0, w] x [h, 0] --> [-1, 1] x [-1, 1]
// Roughly speaking, applies pixelsToGLUnits scaling with a translation
- glCoordMatrix: Float32Array;
+ glCoordMatrix: mat4;
// Inverse of glCoordMatrix, from NDC to screen coordinates, [-1, 1] x [-1, 1] --> [0, w] x [h, 0]
- labelPlaneMatrix: Float32Array;
+ labelPlaneMatrix: mat4;
// globe coordinate transformation matrix
- globeMatrix: Float64Array;
+ globeMatrix: mat4;
globeCenterInViewSpace: [number, number, number];
globeRadius: number;
- inverseAdjustmentMatrix: Array;
+ inverseAdjustmentMatrix: mat2;
mercatorFromTransition: boolean;
@@ -190,19 +190,19 @@ class Transform {
_edgeInsets: EdgeInsets;
_constraining: boolean;
_projMatrixCache: {
- [_: number]: Float32Array;
+ [_: number]: mat4;
};
_alignedProjMatrixCache: {
- [_: number]: Float32Array;
+ [_: number]: mat4;
};
_pixelsToTileUnitsCache: {
- [_: number]: Float32Array;
+ [_: number]: mat2;
};
_expandedProjMatrixCache: {
- [_: number]: Float32Array;
+ [_: number]: mat4;
};
_fogTileMatrixCache: {
- [_: number]: Float32Array;
+ [_: number]: mat4;
};
_distanceTileDataCache: {
[_: number]: FeatureDistanceData;
@@ -549,7 +549,7 @@ class Transform {
if (usePreviousCenter || (this._centerAltitude && this._centerAltitudeValidForExaggeration &&
elevation.exaggeration() && this._centerAltitudeValidForExaggeration !== elevation.exaggeration())) {
assert(this._centerAltitudeValidForExaggeration);
- const previousExaggeration = (this._centerAltitudeValidForExaggeration as any);
+ const previousExaggeration = this._centerAltitudeValidForExaggeration;
// scale down the centerAltitude
this._centerAltitude = this._centerAltitude / previousExaggeration * elevation.exaggeration();
this._centerAltitudeValidForExaggeration = elevation.exaggeration();
@@ -668,7 +668,7 @@ class Transform {
targetPosition = [position.x, position.y, position.z];
}
- const distToTarget = vec3.length(vec3.sub([] as any, this._camera.position, targetPosition));
+ const distToTarget = vec3.length(vec3.sub([] as unknown as vec3, this._camera.position, targetPosition));
return clamp(this._zoomFromMercatorZ(distToTarget), this._minZoom, this._maxZoom);
}
@@ -722,8 +722,8 @@ class Transform {
// The new orientation must be sanitized by making sure it can be represented
// with a pitch and bearing. Roll-component must be removed and the camera can't be upside down
- const forward = vec3.transformQuat([] as any, [0, 0, -1], orientation);
- const up = vec3.transformQuat([] as any, [0, -1, 0], orientation);
+ const forward = vec3.transformQuat([] as unknown as vec3, [0, 0, -1], orientation);
+ const up = vec3.transformQuat([] as unknown as vec3, [0, -1, 0], orientation);
if (up[2] < 0.0)
return false;
@@ -1242,9 +1242,9 @@ class Transform {
let closestDistance = Number.MAX_VALUE;
let closestElevation = 0.0;
const corners = it.aabb.getCorners();
- const distanceXyz = [] as any;
+ const distanceXyz = [];
for (const corner of corners) {
- vec3.sub(distanceXyz, corner, cameraPoint as any);
+ vec3.sub(distanceXyz as unknown as vec3, corner, cameraPoint as unknown as vec3);
if (!isGlobe) {
if (useElevationData) {
distanceXyz[2] *= meterToTile;
@@ -1252,7 +1252,7 @@ class Transform {
distanceXyz[2] = cameraHeight;
}
}
- const dist = vec3.dot(distanceXyz, this._camera.forward());
+ const dist = vec3.dot(distanceXyz as unknown as vec3, this._camera.forward());
if (dist < closestDistance) {
closestDistance = dist;
closestElevation = Math.abs(distanceXyz[2]);
@@ -1267,7 +1267,7 @@ class Transform {
}
// Border case: with tilt of 85 degrees, center could be outside max zoom distance, due to scale.
// Ensure max zoom tiles over center.
- const closestPointToCenter = it.aabb.closestPoint(centerPoint as any);
+ const closestPointToCenter = it.aabb.closestPoint(centerPoint as unknown as vec3);
return (closestPointToCenter[0] === centerPoint[0] && closestPointToCenter[1] === centerPoint[1]);
};
@@ -1386,8 +1386,8 @@ class Transform {
vec4.transformMat4(br, br, fogTileMatrix);
// the fog matrix can flip the min/max values, so we calculate them explicitly
- const min = vec4.min([] as any, tl, br) as [number, number, number, number];
- const max = vec4.max([] as any, tl, br) as [number, number, number, number];
+ const min = vec4.min([] as unknown as vec4, tl, br) as number[];
+ const max = vec4.max([] as unknown as vec4, tl, br) as number[];
const sqDist = getAABBPointSquareDist(min, max);
@@ -1602,9 +1602,7 @@ class Transform {
const p0: [number, number, number, number] = [p.x, p.y, 0, 1];
const p1: [number, number, number, number] = [p.x, p.y, 1, 1];
- // @ts-expect-error - TS2345 - Argument of type 'Float64Array' is not assignable to parameter of type 'ReadonlyMat4'.
vec4.transformMat4(p0, p0, this.pixelMatrixInverse);
- // @ts-expect-error - TS2345 - Argument of type 'Float64Array' is not assignable to parameter of type 'ReadonlyMat4'.
vec4.transformMat4(p1, p1, this.pixelMatrixInverse);
const w0 = p0[3];
@@ -1624,9 +1622,7 @@ class Transform {
const p0: [number, number, number, number] = [p.x, p.y, 0, 1];
const p1: [number, number, number, number] = [p.x, p.y, 1, 1];
- // @ts-expect-error - TS2345 - Argument of type 'Float64Array' is not assignable to parameter of type 'ReadonlyMat4'.
vec4.transformMat4(p0, p0, this.pixelMatrixInverse);
- // @ts-expect-error - TS2345 - Argument of type 'Float64Array' is not assignable to parameter of type 'ReadonlyMat4'.
vec4.transformMat4(p1, p1, this.pixelMatrixInverse);
vec4.scale(p0, p0, 1 / p0[3]);
@@ -1639,8 +1635,7 @@ class Transform {
vec4.scale(p0, p0, 1 / this.worldSize);
vec4.scale(p1, p1, 1 / this.worldSize);
- // @ts-expect-error - TS2345 - Argument of type '[number, number, number, number]' is not assignable to parameter of type 'ReadonlyVec3'.
- return new Ray([p0[0], p0[1], p0[2]], vec3.normalize([] as any, vec3.sub([] as any, p1, p0)));
+ return new Ray([p0[0], p0[1], p0[2]], vec3.normalize([] as unknown as vec3, vec3.sub([] as unknown as vec3, p1 as unknown as vec3, p0 as unknown as vec3)));
}
/**
@@ -1740,7 +1735,6 @@ class Transform {
_coordinatePoint(coord: MercatorCoordinate, sampleTerrainIn3D: boolean): Point {
const elevation = sampleTerrainIn3D && this.elevation ? this.elevation.getAtPointOrZero(coord, this._centerAltitude) : this._centerAltitude;
const p = [coord.x * this.worldSize, coord.y * this.worldSize, elevation + coord.toAltitude(), 1];
- // @ts-expect-error - TS2345 - Argument of type 'Float64Array' is not assignable to parameter of type 'ReadonlyMat4'.
vec4.transformMat4(p as [number, number, number, number], p as [number, number, number, number], this.pixelMatrix);
return p[3] > 0 ?
new Point(p[0] / p[3], p[1] / p[3]) :
@@ -1934,7 +1928,7 @@ class Transform {
this._constrain();
}
- calculatePosMatrix(unwrappedTileID: UnwrappedTileID, worldSize: number): Float64Array {
+ calculatePosMatrix(unwrappedTileID: UnwrappedTileID, worldSize: number): mat4 {
return this.projection.createTileMatrix(this, worldSize, unwrappedTileID);
}
@@ -1984,7 +1978,7 @@ class Transform {
* @param {UnwrappedTileID} unwrappedTileID;
* @private
*/
- calculateFogTileMatrix(unwrappedTileID: UnwrappedTileID): Float32Array {
+ calculateFogTileMatrix(unwrappedTileID: UnwrappedTileID): mat4 {
const fogTileMatrixKey = unwrappedTileID.key;
const cache = this._fogTileMatrixCache;
if (cache[fogTileMatrixKey]) {
@@ -1992,7 +1986,6 @@ class Transform {
}
const posMatrix = this.projection.createTileMatrix(this, this.cameraWorldSizeForFog, unwrappedTileID);
- // @ts-expect-error - TS2345 - Argument of type 'Float64Array' is not assignable to parameter of type 'mat4'.
mat4.multiply(posMatrix, this.worldToFogMatrix, posMatrix);
cache[fogTileMatrixKey] = new Float32Array(posMatrix);
@@ -2008,7 +2001,7 @@ class Transform {
unwrappedTileID: UnwrappedTileID,
aligned: boolean = false,
expanded: boolean = false,
- ): Float32Array {
+ ): mat4 {
const projMatrixKey = unwrappedTileID.key;
let cache;
if (expanded) {
@@ -2032,14 +2025,13 @@ class Transform {
} else {
projMatrix = aligned ? this.alignedProjMatrix : this.projMatrix;
}
- // @ts-expect-error - TS2345 - Argument of type 'Float64Array' is not assignable to parameter of type 'mat4'.
mat4.multiply(posMatrix, projMatrix, posMatrix);
cache[projMatrixKey] = new Float32Array(posMatrix);
return cache[projMatrixKey];
}
- calculatePixelsToTileUnitsMatrix(tile: Tile): Float32Array {
+ calculatePixelsToTileUnitsMatrix(tile: Tile): mat2 {
const key = tile.tileID.key;
const cache = this._pixelsToTileUnitsCache;
if (cache[key]) {
@@ -2051,16 +2043,15 @@ class Transform {
return cache[key];
}
- customLayerMatrix(): Array {
- return this.mercatorMatrix.slice();
+ customLayerMatrix(): mat4 {
+ return this.mercatorMatrix.slice() as mat4;
}
globeToMercatorMatrix(): Array | null | undefined {
if (this.projection.name === 'globe') {
const pixelsToMerc = 1 / this.worldSize;
- const m = mat4.fromScaling([] as any, [pixelsToMerc, pixelsToMerc, pixelsToMerc]);
- // @ts-expect-error - TS2345 - Argument of type 'Float64Array' is not assignable to parameter of type 'ReadonlyMat4'.
- mat4.multiply(m, m, this.globeMatrix);
+ const m = mat4.fromScaling([] as unknown as mat4, [pixelsToMerc, pixelsToMerc, pixelsToMerc]);
+ mat4.multiply(m, m, this.globeMatrix as unknown as mat4);
return m as number[];
}
return undefined;
@@ -2089,7 +2080,7 @@ class Transform {
const t = elevation.raycast(start, dir, elevation.exaggeration());
if (t) {
- const point = vec3.scaleAndAdd([] as any, start, dir, t);
+ const point = vec3.scaleAndAdd([] as unknown as vec3, start, dir, t);
const newCenter = new MercatorCoordinate(point[0], point[1], mercatorZfromAltitude(point[2], latFromMercatorY(point[1])));
const camToNew = [newCenter.x - start[0], newCenter.y - start[1], newCenter.z - start[2] * metersToMerc];
@@ -2298,21 +2289,18 @@ class Transform {
cameraToClip = cameraToClipPerspective;
}
- // @ts-expect-error - TS2345 - Argument of type 'Float64Array' is not assignable to parameter of type 'ReadonlyMat4'.
- const worldToClipPerspective: Array | Float32Array | Float64Array = mat4.mul([] as any, cameraToClipPerspective, worldToCamera);
- // @ts-expect-error - TS2345 - Argument of type 'Float64Array' is not assignable to parameter of type 'ReadonlyMat4'.
- let m: mat4 | Float64Array = mat4.mul([] as any, cameraToClip, worldToCamera);
+ const worldToClipPerspective = mat4.mul([] as unknown as mat4, cameraToClipPerspective, worldToCamera);
+ let m = mat4.mul([] as unknown as mat4, cameraToClip, worldToCamera);
if (this.projection.isReprojectedInTileSpace) {
// Projections undistort as you zoom in (shear, scale, rotate).
// Apply the undistortion around the center of the map.
const mc = this.locationCoordinate(this.center);
- const adjustments = mat4.identity([] as any);
+ const adjustments = mat4.identity([] as unknown as mat4);
mat4.translate(adjustments, adjustments, [mc.x * this.worldSize, mc.y * this.worldSize, 0]);
mat4.multiply(adjustments, adjustments, getProjectionAdjustments(this) as mat4);
mat4.translate(adjustments, adjustments, [-mc.x * this.worldSize, -mc.y * this.worldSize, 0]);
mat4.multiply(m, m, adjustments);
- // @ts-expect-error - TS2345 - Argument of type 'number[] | Float32Array' is not assignable to parameter of type 'mat4'.
mat4.multiply(worldToClipPerspective, worldToClipPerspective, adjustments);
this.inverseAdjustmentMatrix = getProjectionAdjustmentInverted(this);
} else {
@@ -2321,28 +2309,24 @@ class Transform {
// The mercatorMatrix can be used to transform points from mercator coordinates
// ([0, 0] nw, [1, 1] se) to GL coordinates. / zUnit compensates for scaling done in worldToCamera.
- // @ts-expect-error - TS2322 - Type 'mat4' is not assignable to type 'number[]'. | TS2345 - Argument of type 'number[] | Float32Array' is not assignable to parameter of type 'ReadonlyMat4'.
- this.mercatorMatrix = mat4.scale([] as any, m, [this.worldSize, this.worldSize, this.worldSize / zUnit, 1.0]);
+ this.mercatorMatrix = mat4.scale([] as unknown as mat4, m, [this.worldSize, this.worldSize, this.worldSize / zUnit, 1.0] as unknown as vec3);
this.projMatrix = m;
// For tile cover calculation, use inverted of base (non elevated) matrix
// as tile elevations are in tile coordinates and relative to center elevation.
- // @ts-expect-error - TS2322 - Type 'mat4' is not assignable to type 'Float64Array'. | TS2345 - Argument of type 'Float64Array' is not assignable to parameter of type 'mat4'.
- this.invProjMatrix = mat4.invert(new Float64Array(16), this.projMatrix);
+ this.invProjMatrix = mat4.invert(new Float64Array(16) as unknown as mat4, this.projMatrix);
if (isGlobe) {
const expandedCameraToClipPerspective = this._camera.getCameraToClipPerspective(this._fov, this.width / this.height, this._nearZ, Infinity);
expandedCameraToClipPerspective[8] = -offset.x * 2 / this.width;
expandedCameraToClipPerspective[9] = offset.y * 2 / this.height;
- // @ts-expect-error - TS2345 - Argument of type 'Float64Array' is not assignable to parameter of type 'ReadonlyMat4'.
- this.expandedFarZProjMatrix = mat4.mul([] as any, expandedCameraToClipPerspective, worldToCamera);
+ this.expandedFarZProjMatrix = mat4.mul([] as unknown as mat4, expandedCameraToClipPerspective, worldToCamera);
} else {
this.expandedFarZProjMatrix = this.projMatrix;
}
- const clipToCamera = mat4.invert([] as any, cameraToClip);
- // @ts-expect-error - TS2345 - Argument of type 'mat4' is not assignable to parameter of type 'number[]'.
+ const clipToCamera = mat4.invert([] as unknown as mat4, cameraToClip);
this.frustumCorners = FrustumCorners.fromInvProjectionMatrix(clipToCamera, this.horizonLineFromTop(), this.height);
// Create a camera frustum in mercator units
@@ -2356,7 +2340,6 @@ class Transform {
const projection = mat4.perspective(new Float32Array(16), this._fov, this.width / this.height, this._nearZ, this._farZ);
- // @ts-expect-error - TS2322 - Type 'mat4' is not assignable to type 'Float32Array'.
this.starsProjMatrix = mat4.clone(projection);
// The distance in pixels the skybox needs to be shifted down by to meet the shifted horizon.
@@ -2364,7 +2347,6 @@ class Transform {
// Apply center of perspective offset to skybox projection
projection[8] = -offset.x * 2 / this.width;
projection[9] = (offset.y + skyboxHorizonShift) * 2 / this.height;
- // @ts-expect-error - TS2322 - Type 'mat4' is not assignable to type 'Float32Array'.
this.skyboxMatrix = mat4.multiply(view, projection, view);
// Make a second projection matrix that is aligned to a pixel grid for rendering raster tiles.
@@ -2379,44 +2361,39 @@ class Transform {
angleCos = Math.cos(this.angle), angleSin = Math.sin(this.angle),
dx = x - Math.round(x) + angleCos * xShift + angleSin * yShift,
dy = y - Math.round(y) + angleCos * yShift + angleSin * xShift;
- const alignedM = new Float64Array(m);
- // @ts-expect-error - TS2345 - Argument of type 'Float64Array' is not assignable to parameter of type 'mat4'.
+ const alignedM = new Float64Array(m) as unknown as mat4;
mat4.translate(alignedM, alignedM, [ dx > 0.5 ? dx - 1 : dx, dy > 0.5 ? dy - 1 : dy, 0 ]);
this.alignedProjMatrix = alignedM;
m = mat4.create();
mat4.scale(m, m, [this.width / 2, -this.height / 2, 1]);
mat4.translate(m, m, [1, -1, 0]);
- this.labelPlaneMatrix = m as Float32Array;
+ this.labelPlaneMatrix = m;
m = mat4.create();
mat4.scale(m, m, [1, -1, 1]);
mat4.translate(m, m, [-1, -1, 0]);
mat4.scale(m, m, [2 / this.width, 2 / this.height, 1]);
- this.glCoordMatrix = m as Float32Array;
+ this.glCoordMatrix = m;
// matrix for conversion from location to screen coordinates
- // @ts-expect-error - TS2322 - Type 'mat4' is not assignable to type 'Float64Array'. | TS2345 - Argument of type 'Float64Array' is not assignable to parameter of type 'mat4'.
- this.pixelMatrix = mat4.multiply(new Float64Array(16), this.labelPlaneMatrix, worldToClipPerspective);
+ this.pixelMatrix = mat4.multiply(new Float64Array(16) as unknown as mat4, this.labelPlaneMatrix, worldToClipPerspective);
this._calcFogMatrices();
this._distanceTileDataCache = {};
// inverse matrix for conversion from screen coordinates to location
- // @ts-expect-error - TS2345 - Argument of type 'Float64Array' is not assignable to parameter of type 'mat4'.
- m = mat4.invert(new Float64Array(16), this.pixelMatrix);
+ m = mat4.invert(new Float64Array(16) as unknown as mat4, this.pixelMatrix);
if (!m) throw new Error("failed to invert matrix");
- // @ts-expect-error - TS2322 - Type 'number[] | Float32Array' is not assignable to type 'Float64Array'.
this.pixelMatrixInverse = m;
if (this.projection.name === 'globe' || this.mercatorFromTransition) {
- this.globeMatrix = calculateGlobeMatrix(this);
+ this.globeMatrix = calculateGlobeMatrix(this) as unknown as mat4;
const globeCenter: [number, number, number] = [this.globeMatrix[12], this.globeMatrix[13], this.globeMatrix[14]];
this.globeCenterInViewSpace = vec3.transformMat4(globeCenter, globeCenter, worldToCamera as unknown as mat4) as [number, number, number];
this.globeRadius = this.worldSize / 2.0 / Math.PI - 1.0;
} else {
- // @ts-expect-error - TS2322 - Type 'number[] | Float32Array' is not assignable to type 'Float64Array'.
this.globeMatrix = m;
}
@@ -2448,7 +2425,6 @@ class Transform {
const m = mat4.create();
mat4.translate(m, m, cameraPos);
mat4.scale(m, m, metersToPixel as [number, number, number]);
- // @ts-expect-error - TS2322 - Type 'mat4' is not assignable to type 'Float32Array'.
this.mercatorFogMatrix = m;
// The worldToFogMatrix can be used for conversion from world coordinates to relative camera position in
@@ -2506,7 +2482,7 @@ class Transform {
t = Math.min((maxZ - z) / deltaZ, 1);
}
- this._camera.position = vec3.scaleAndAdd([] as any, this._camera.position, translation, t);
+ this._camera.position = vec3.scaleAndAdd([] as unknown as vec3, this._camera.position, translation, t);
this._updateStateFromCamera();
}
@@ -2674,7 +2650,7 @@ class Transform {
* @returns {number} The distance in mercator coordinates.
*/
zoomDeltaToMovement(center: vec3, zoomDelta: number): number {
- const distance = vec3.length(vec3.sub([] as any, this._camera.position, center));
+ const distance = vec3.length(vec3.sub([] as unknown as vec3, this._camera.position, center));
const relativeZoom = this._zoomFromMercatorZ(distance) + zoomDelta;
return distance - this._mercatorZfromZoom(relativeZoom);
}
@@ -2693,8 +2669,7 @@ class Transform {
getCameraPoint(): Point {
if (this.projection.name === 'globe') {
// Find precise location of the projected camera position on the curved surface
- const center = [this.globeMatrix[12], this.globeMatrix[13], this.globeMatrix[14]];
- // @ts-expect-error - TS2345 - Argument of type 'number[]' is not assignable to parameter of type '[any, any, any]'.
+ const center: vec3 = [this.globeMatrix[12], this.globeMatrix[13], this.globeMatrix[14]];
const pos = projectClamped(center, this.pixelMatrix);
return new Point(pos[0], pos[1]);
} else {
@@ -2727,11 +2702,9 @@ class Transform {
const worldToCamera = this._camera.getWorldToCamera(this.worldSize, zUnit);
if (this.projection.name === 'globe') {
- // @ts-expect-error - TS2345 - Argument of type 'Float64Array' is not assignable to parameter of type 'mat4'.
mat4.multiply(worldToCamera, worldToCamera, this.globeMatrix);
}
- // @ts-expect-error - TS2322 - Type 'Float64Array' is not assignable to type 'mat4'.
return worldToCamera;
}
diff --git a/src/gl/value.ts b/src/gl/value.ts
index ccc996d089b..33df0c398b2 100644
--- a/src/gl/value.ts
+++ b/src/gl/value.ts
@@ -42,6 +42,7 @@ class BaseValue implements Value {
get(): T {
return this.current;
}
+
set(value: T) { // eslint-disable-line
// overridden in child classes;
}
@@ -49,16 +50,18 @@ class BaseValue implements Value {
getDefault(): T {
return this.default; // overriden in child classes
}
+
setDefault() {
this.set(this.default);
}
}
export class ClearColor extends BaseValue {
- getDefault(): Color {
+ override getDefault(): Color {
return Color.transparent;
}
- set(v: Color) {
+
+ override set(v: Color) {
const c = this.current;
if (v.r === c.r && v.g === c.g && v.b === c.b && v.a === c.a && !this.dirty) return;
this.gl.clearColor(v.r, v.g, v.b, v.a);
@@ -68,10 +71,11 @@ export class ClearColor extends BaseValue {
}
export class ClearDepth extends BaseValue {
- getDefault(): number {
+ override getDefault(): number {
return 1;
}
- set(v: number) {
+
+ override set(v: number) {
if (v === this.current && !this.dirty) return;
this.gl.clearDepth(v);
this.current = v;
@@ -80,10 +84,11 @@ export class ClearDepth extends BaseValue {
}
export class ClearStencil extends BaseValue {
- getDefault(): number {
+ override getDefault(): number {
return 0;
}
- set(v: number) {
+
+ override set(v: number) {
if (v === this.current && !this.dirty) return;
this.gl.clearStencil(v);
this.current = v;
@@ -92,10 +97,11 @@ export class ClearStencil extends BaseValue {
}
export class ColorMask extends BaseValue {
- getDefault(): ColorMaskType {
+ override getDefault(): ColorMaskType {
return [true, true, true, true];
}
- set(v: ColorMaskType) {
+
+ override set(v: ColorMaskType) {
const c = this.current;
if (v[0] === c[0] && v[1] === c[1] && v[2] === c[2] && v[3] === c[3] && !this.dirty) return;
this.gl.colorMask(v[0], v[1], v[2], v[3]);
@@ -105,10 +111,11 @@ export class ColorMask extends BaseValue {
}
export class DepthMask extends BaseValue {
- getDefault(): DepthMaskType {
+ override getDefault(): DepthMaskType {
return true;
}
- set(v: DepthMaskType): void {
+
+ override set(v: DepthMaskType): void {
if (v === this.current && !this.dirty) return;
this.gl.depthMask(v);
this.current = v;
@@ -117,10 +124,11 @@ export class DepthMask extends BaseValue {
}
export class StencilMask extends BaseValue {
- getDefault(): number {
+ override getDefault(): number {
return 0xFF;
}
- set(v: number): void {
+
+ override set(v: number): void {
if (v === this.current && !this.dirty) return;
this.gl.stencilMask(v);
this.current = v;
@@ -129,14 +137,15 @@ export class StencilMask extends BaseValue {
}
export class StencilFunc extends BaseValue {
- getDefault(): StencilFuncType {
+ override getDefault(): StencilFuncType {
return {
func: this.gl.ALWAYS,
ref: 0,
mask: 0xFF
};
}
- set(v: StencilFuncType): void {
+
+ override set(v: StencilFuncType): void {
const c = this.current;
if (v.func === c.func && v.ref === c.ref && v.mask === c.mask && !this.dirty) return;
// Assume UNSIGNED_INT_24_8 storage, with 8 bits dedicated to stencil.
@@ -149,11 +158,12 @@ export class StencilFunc extends BaseValue {
}
export class StencilOp extends BaseValue {
- getDefault(): StencilOpType {
+ override getDefault(): StencilOpType {
const gl = this.gl;
return [gl.KEEP, gl.KEEP, gl.KEEP];
}
- set(v: StencilOpType) {
+
+ override set(v: StencilOpType) {
const c = this.current;
if (v[0] === c[0] && v[1] === c[1] && v[2] === c[2] && !this.dirty) return;
this.gl.stencilOp(v[0], v[1], v[2]);
@@ -163,10 +173,11 @@ export class StencilOp extends BaseValue {
}
export class StencilTest extends BaseValue {
- getDefault(): boolean {
+ override getDefault(): boolean {
return false;
}
- set(v: boolean) {
+
+ override set(v: boolean) {
if (v === this.current && !this.dirty) return;
const gl = this.gl;
if (v) {
@@ -180,10 +191,11 @@ export class StencilTest extends BaseValue {
}
export class DepthRange extends BaseValue {
- getDefault(): DepthRangeType {
+ override getDefault(): DepthRangeType {
return [0, 1];
}
- set(v: DepthRangeType) {
+
+ override set(v: DepthRangeType) {
const c = this.current;
if (v[0] === c[0] && v[1] === c[1] && !this.dirty) return;
this.gl.depthRange(v[0], v[1]);
@@ -193,10 +205,11 @@ export class DepthRange extends BaseValue {
}
export class DepthTest extends BaseValue {
- getDefault(): boolean {
+ override getDefault(): boolean {
return false;
}
- set(v: boolean) {
+
+ override set(v: boolean) {
if (v === this.current && !this.dirty) return;
const gl = this.gl;
if (v) {
@@ -210,10 +223,11 @@ export class DepthTest extends BaseValue {
}
export class DepthFunc extends BaseValue {
- getDefault(): DepthFuncType {
+ override getDefault(): DepthFuncType {
return this.gl.LESS;
}
- set(v: DepthFuncType) {
+
+ override set(v: DepthFuncType) {
if (v === this.current && !this.dirty) return;
this.gl.depthFunc(v);
this.current = v;
@@ -222,10 +236,11 @@ export class DepthFunc extends BaseValue {
}
export class Blend extends BaseValue {
- getDefault(): boolean {
+ override getDefault(): boolean {
return false;
}
- set(v: boolean) {
+
+ override set(v: boolean) {
if (v === this.current && !this.dirty) return;
const gl = this.gl;
if (v) {
@@ -239,11 +254,12 @@ export class Blend extends BaseValue {
}
export class BlendFunc extends BaseValue {
- getDefault(): BlendFuncType {
+ override getDefault(): BlendFuncType {
const gl = this.gl;
return [gl.ONE, gl.ZERO, gl.ONE, gl.ZERO];
}
- set(v: BlendFuncType) {
+
+ override set(v: BlendFuncType) {
const c = this.current;
if (v[0] === c[0] && v[1] === c[1] && v[2] === c[2] && v[3] === c[3] && !this.dirty) return;
this.gl.blendFuncSeparate(v[0], v[1], v[2], v[3]);
@@ -253,10 +269,11 @@ export class BlendFunc extends BaseValue {
}
export class BlendColor extends BaseValue {
- getDefault(): Color {
+ override getDefault(): Color {
return Color.transparent;
}
- set(v: Color) {
+
+ override set(v: Color) {
const c = this.current;
if (v.r === c.r && v.g === c.g && v.b === c.b && v.a === c.a && !this.dirty) return;
this.gl.blendColor(v.r, v.g, v.b, v.a);
@@ -266,10 +283,11 @@ export class BlendColor extends BaseValue {
}
export class BlendEquation extends BaseValue {
- getDefault(): BlendEquationType {
+ override getDefault(): BlendEquationType {
return this.gl.FUNC_ADD;
}
- set(v: BlendEquationType) {
+
+ override set(v: BlendEquationType) {
if (v === this.current && !this.dirty) return;
this.gl.blendEquationSeparate(v, v);
this.current = v;
@@ -278,10 +296,11 @@ export class BlendEquation extends BaseValue {
}
export class CullFace extends BaseValue {
- getDefault(): boolean {
+ override getDefault(): boolean {
return false;
}
- set(v: boolean) {
+
+ override set(v: boolean) {
if (v === this.current && !this.dirty) return;
const gl = this.gl;
if (v) {
@@ -295,10 +314,11 @@ export class CullFace extends BaseValue {
}
export class CullFaceSide extends BaseValue {
- getDefault(): CullFaceModeType {
+ override getDefault(): CullFaceModeType {
return this.gl.BACK;
}
- set(v: CullFaceModeType) {
+
+ override set(v: CullFaceModeType) {
if (v === this.current && !this.dirty) return;
this.gl.cullFace(v);
this.current = v;
@@ -307,10 +327,11 @@ export class CullFaceSide extends BaseValue {
}
export class FrontFace extends BaseValue {
- getDefault(): FrontFaceType {
+ override getDefault(): FrontFaceType {
return this.gl.CCW;
}
- set(v: FrontFaceType) {
+
+ override set(v: FrontFaceType) {
if (v === this.current && !this.dirty) return;
this.gl.frontFace(v);
this.current = v;
@@ -319,10 +340,11 @@ export class FrontFace extends BaseValue {
}
export class Program extends BaseValue {
- getDefault(): WebGLProgram | null {
+ override getDefault(): WebGLProgram | null {
return null;
}
- set(v?: WebGLProgram | null) {
+
+ override set(v?: WebGLProgram | null) {
if (v === this.current && !this.dirty) return;
this.gl.useProgram(v);
this.current = v;
@@ -331,10 +353,11 @@ export class Program extends BaseValue {
}
export class ActiveTextureUnit extends BaseValue {
- getDefault(): TextureUnitType {
+ override getDefault(): TextureUnitType {
return this.gl.TEXTURE0;
}
- set(v: TextureUnitType) {
+
+ override set(v: TextureUnitType) {
if (v === this.current && !this.dirty) return;
this.gl.activeTexture(v);
this.current = v;
@@ -343,11 +366,12 @@ export class ActiveTextureUnit extends BaseValue {
}
export class Viewport extends BaseValue {
- getDefault(): ViewportType {
+ override getDefault(): ViewportType {
const gl = this.gl;
return [0, 0, gl.drawingBufferWidth, gl.drawingBufferHeight];
}
- set(v: ViewportType) {
+
+ override set(v: ViewportType) {
const c = this.current;
if (v[0] === c[0] && v[1] === c[1] && v[2] === c[2] && v[3] === c[3] && !this.dirty) return;
this.gl.viewport(v[0], v[1], v[2], v[3]);
@@ -357,10 +381,11 @@ export class Viewport extends BaseValue {
}
export class BindFramebuffer extends BaseValue {
- getDefault(): WebGLFramebuffer | null {
+ override getDefault(): WebGLFramebuffer | null {
return null;
}
- set(v?: WebGLFramebuffer | null) {
+
+ override set(v?: WebGLFramebuffer | null) {
if (v === this.current && !this.dirty) return;
const gl = this.gl;
gl.bindFramebuffer(gl.FRAMEBUFFER, v);
@@ -370,10 +395,11 @@ export class BindFramebuffer extends BaseValue {
- getDefault(): WebGLRenderbuffer | null {
+ override getDefault(): WebGLRenderbuffer | null {
return null;
}
- set(v?: WebGLRenderbuffer | null) {
+
+ override set(v?: WebGLRenderbuffer | null) {
if (v === this.current && !this.dirty) return;
const gl = this.gl;
gl.bindRenderbuffer(gl.RENDERBUFFER, v);
@@ -383,10 +409,11 @@ export class BindRenderbuffer extends BaseValue {
- getDefault(): WebGLTexture | null {
+ override getDefault(): WebGLTexture | null {
return null;
}
- set(v?: WebGLTexture | null) {
+
+ override set(v?: WebGLTexture | null) {
if (v === this.current && !this.dirty) return;
const gl = this.gl;
gl.bindTexture(gl.TEXTURE_2D, v);
@@ -396,10 +423,11 @@ export class BindTexture extends BaseValue {
}
export class BindVertexBuffer extends BaseValue {
- getDefault(): WebGLBuffer | null {
+ override getDefault(): WebGLBuffer | null {
return null;
}
- set(v?: WebGLBuffer | null) {
+
+ override set(v?: WebGLBuffer | null) {
if (v === this.current && !this.dirty) return;
const gl = this.gl;
gl.bindBuffer(gl.ARRAY_BUFFER, v);
@@ -409,10 +437,11 @@ export class BindVertexBuffer extends BaseValue
}
export class BindElementBuffer extends BaseValue {
- getDefault(): WebGLBuffer | null {
+ override getDefault(): WebGLBuffer | null {
return null;
}
- set(v?: WebGLBuffer | null) {
+
+ override set(v?: WebGLBuffer | null) {
// Always rebind
const gl = this.gl;
gl.bindBuffer(gl.ELEMENT_ARRAY_BUFFER, v);
@@ -422,10 +451,11 @@ export class BindElementBuffer extends BaseValue
}
export class BindVertexArrayOES extends BaseValue {
- getDefault(): any {
+ override getDefault(): any {
return null;
}
- set(v: any) {
+
+ override set(v: any) {
if (!this.gl || (v === this.current && !this.dirty)) return;
this.gl.bindVertexArray(v);
this.current = v;
@@ -434,10 +464,11 @@ export class BindVertexArrayOES extends BaseValue {
}
export class PixelStoreUnpack extends BaseValue {
- getDefault(): number {
+ override getDefault(): number {
return 4;
}
- set(v: number) {
+
+ override set(v: number) {
if (v === this.current && !this.dirty) return;
const gl = this.gl;
gl.pixelStorei(gl.UNPACK_ALIGNMENT, v);
@@ -447,10 +478,11 @@ export class PixelStoreUnpack extends BaseValue {
}
export class PixelStoreUnpackPremultiplyAlpha extends BaseValue {
- getDefault(): boolean {
+ override getDefault(): boolean {
return false;
}
- set(v: boolean): void {
+
+ override set(v: boolean): void {
if (v === this.current && !this.dirty) return;
const gl = this.gl;
gl.pixelStorei(gl.UNPACK_PREMULTIPLY_ALPHA_WEBGL, (v as any));
@@ -460,10 +492,11 @@ export class PixelStoreUnpackPremultiplyAlpha extends BaseValue {
}
export class PixelStoreUnpackFlipY extends BaseValue {
- getDefault(): boolean {
+ override getDefault(): boolean {
return false;
}
- set(v: boolean): void {
+
+ override set(v: boolean): void {
if (v === this.current && !this.dirty) return;
const gl = this.gl;
gl.pixelStorei(gl.UNPACK_FLIP_Y_WEBGL, (v as any));
@@ -481,7 +514,7 @@ class FramebufferAttachment extends BaseValue {
this.context = context;
this.parent = parent;
}
- getDefault(): null {
+ override getDefault(): null {
return null;
}
}
@@ -490,7 +523,8 @@ export class ColorAttachment extends FramebufferAttachment {
setDirty() {
this.dirty = true;
}
- set(v?: WebGLTexture | null): void {
+
+ override set(v?: WebGLTexture | null): void {
if (v === this.current && !this.dirty) return;
this.context.bindFramebuffer.set(this.parent);
// note: it's possible to attach a renderbuffer to the color
@@ -504,7 +538,7 @@ export class ColorAttachment extends FramebufferAttachment {
export class DepthRenderbufferAttachment extends FramebufferAttachment {
attachment(): number { return this.gl.DEPTH_ATTACHMENT; }
- set(v: WebGLRenderbuffer | null | undefined | WebGLTexture): void {
+ override set(v: WebGLRenderbuffer | null | undefined | WebGLTexture): void {
if (v === this.current && !this.dirty) return;
this.context.bindFramebuffer.set(this.parent);
const gl = this.gl;
@@ -516,7 +550,7 @@ export class DepthRenderbufferAttachment extends FramebufferAttachment {
attachment(): number { return this.gl.DEPTH_ATTACHMENT; }
- set(v?: WebGLTexture | null): void {
+ override set(v?: WebGLTexture | null): void {
if (v === this.current && !this.dirty) return;
this.context.bindFramebuffer.set(this.parent);
const gl = this.gl;
@@ -527,5 +561,5 @@ export class DepthTextureAttachment extends FramebufferAttachment
}
export class DepthStencilAttachment extends DepthRenderbufferAttachment {
- attachment(): number { return this.gl.DEPTH_STENCIL_ATTACHMENT; }
+ override attachment(): number { return this.gl.DEPTH_STENCIL_ATTACHMENT; }
}
diff --git a/src/precipitation/draw_rain.ts b/src/precipitation/draw_rain.ts
new file mode 100644
index 00000000000..30502a749be
--- /dev/null
+++ b/src/precipitation/draw_rain.ts
@@ -0,0 +1,361 @@
+// // @flow
+
+import StencilMode from '../gl/stencil_mode.js';
+import DepthMode from '../gl/depth_mode.js';
+import {default as ColorMode} from '../gl/color_mode.js';
+import CullFaceMode from '../gl/cull_face_mode.js';
+import {degToRad, clamp} from '../util/util.js';
+import {vec3, mat4, quat} from 'gl-matrix';
+import SegmentVector from '../data/segment.js';
+import {TriangleIndexArray, RainVertexArray} from '../data/array_types.js';
+import {rainUniformValues} from './rain_program.js';
+import {mulberry32} from '../style-spec/util/random.js';
+import {rainLayout} from "./rain_attributes.js";
+import {earthRadius} from '../geo/lng_lat.js';
+import Texture from '../render/texture.js';
+import {PrecipitationRevealParams} from './precipitation_reveal_params.js';
+
+import type VertexBuffer from '../gl/vertex_buffer.js';
+import type {vec4} from 'gl-matrix';
+import type IndexBuffer from '../gl/index_buffer.js';
+import type Painter from '../render/painter.js';
+
+function generateUniformDistributedPointsInsideCube(pointsCount: number): Array {
+ const sRand = mulberry32(1323123451230);
+
+ const points: Array = [];
+ for (let i = 0; i < pointsCount; ++i) {
+ const vx = -1 + 2 * sRand();
+ const vy = -1 + 2 * sRand();
+ const vz = -1 + 2 * sRand();
+
+ points.push(vec3.fromValues(vx, vy, vz));
+ }
+
+ return points;
+}
+
+export class Rain {
+ particlesVx: VertexBuffer | null | undefined;
+ particlesIdx: IndexBuffer | null | undefined;
+ particlesCount: number;
+ particlesSegments: SegmentVector;
+ startTime: number;
+ prevTime: number;
+ accumulatedTimeFromStart: number;
+
+ screenTexture: Texture | null | undefined;
+
+ _revealParams: PrecipitationRevealParams;
+
+ _offsetXPrev: number | undefined;
+ _offsetYPrev: number | undefined;
+ _elevationPrev: number | undefined;
+
+ _accumulatedOffsetX: number;
+ _accumulatedOffsetY: number;
+ _accumulatedElevation: number;
+
+ _params: {
+ intensity: number,
+ timeFactor: number,
+ velocityConeAperture: number,
+ velocity: number,
+ boxSize: number,
+ dropletSizeX: number,
+ dropletSizeYScale: number,
+ distortionStrength: number,
+ screenThinning:{
+ intensity: number,
+ start: number,
+ range: number,
+ fadePower: number,
+ affectedRatio: number,
+ particleOffset: number
+ },
+ color: { r: number, g: number, b: number, a: number },
+ direction: {x: number, y: number},
+ shapeDirPower: number;
+ };
+
+ constructor(painter: Painter) {
+
+ this.accumulatedTimeFromStart = 0;
+ this.startTime = Date.now() / 1000;
+ this.prevTime = Date.now() / 1000;
+
+ this._accumulatedOffsetX = 0;
+ this._accumulatedOffsetY = 0;
+ this._accumulatedElevation = 0;
+
+ this._params = {
+ intensity: 1.0,
+ timeFactor: 1.0,
+ velocityConeAperture: 5.0,
+ velocity: 100.0,
+ boxSize: 1200,
+ dropletSizeX: 1.0,
+ dropletSizeYScale: 10.0,
+ distortionStrength: 50.0,
+ screenThinning: {
+ intensity: 0.0,
+ start: 0.56,
+ range: 0.37,
+ fadePower: 0,
+ affectedRatio: 1.0,
+ particleOffset: -0.2
+ },
+ color: {r: 0.57, g: 0.57, b: 0.57, a: 0.19},
+ direction: {x: -50, y: -35},
+ shapeDirPower: 2.0
+ };
+
+ const tp = painter.tp;
+
+ const scope = ["Precipitation", "Rain"];
+ this._revealParams = new PrecipitationRevealParams(painter.tp, scope);
+ tp.registerParameter(this._params, scope, 'intensity', {min: 0.0, max: 1.0});
+ tp.registerParameter(this._params, scope, 'timeFactor', {min: 0.0, max: 3.0, step: 0.01});
+ tp.registerParameter(this._params, scope, 'velocityConeAperture', {min: 0.0, max: 160.0, step: 1.0});
+ tp.registerParameter(this._params, scope, 'velocity', {min: 0.0, max: 1500.0, step: 5});
+ tp.registerParameter(this._params, scope, 'boxSize', {min: 100.0, max: 4400.0, step: 10.0});
+ tp.registerParameter(this._params, scope, 'dropletSizeX', {min: 0.1, max: 10.0, step: 0.1});
+ tp.registerParameter(this._params, scope, 'dropletSizeYScale', {min: 0.1, max: 10.0, step: 0.1});
+ tp.registerParameter(this._params, scope, 'distortionStrength', {min: 0.0, max: 100.0, step: 0.5});
+
+ tp.registerParameter(this._params, scope, 'direction', {
+ picker: 'inline',
+ expanded: true,
+ x: {min: -200, max: 200},
+ y: {min: -200, max: 200},
+ });
+
+ const shapeScope = [...scope, "Shape"];
+ tp.registerParameter(this._params, shapeScope, 'shapeDirPower', {min: 1.0, max: 10.0, step: 0.01});
+
+ tp.registerParameter(this._params, scope, 'color', {
+ color: {type: 'float'},
+ });
+
+ const thinningScope = [...scope, "ScreenThinning"];
+
+ tp.registerParameter(this._params.screenThinning, thinningScope, 'intensity', {min: 0.0, max: 1.0});
+ tp.registerParameter(this._params.screenThinning, thinningScope, 'start', {min: 0.0, max: 2.0});
+ tp.registerParameter(this._params.screenThinning, thinningScope, 'range', {min: 0.0, max: 2.0});
+ tp.registerParameter(this._params.screenThinning, thinningScope, 'fadePower', {min: -1.0, max: 1.0, step: 0.01});
+ tp.registerParameter(this._params.screenThinning, thinningScope, 'affectedRatio', {min: 0.0, max: 1.0, step: 0.01});
+ tp.registerParameter(this._params.screenThinning, thinningScope, 'particleOffset', {min: -1.0, max: 1.0, step: 0.01});
+
+ this.particlesCount = 16000;
+ }
+
+ update(painter: Painter) {
+ const context = painter.context;
+
+ if (!this.particlesVx) {
+
+ const positions = generateUniformDistributedPointsInsideCube(this.particlesCount);
+
+ const vertices = new RainVertexArray();
+ const triangles = new TriangleIndexArray();
+
+ let base = 0;
+ const sRand = mulberry32(1323123451230);
+ for (let i = 0; i < positions.length; ++i) {
+
+ const p = positions[i];
+
+ const angularVelocityScale = -1 + 2 * sRand();
+ const velocityScale = sRand();
+ const directionConeHeading = sRand();
+ const directionConePitch = sRand();
+ const data: vec4 = [angularVelocityScale, velocityScale, directionConeHeading, directionConePitch];
+
+ vertices.emplaceBack(p[0], p[1], p[2], -1, -1, ...data);
+ vertices.emplaceBack(p[0], p[1], p[2], 1, -1, ...data);
+ vertices.emplaceBack(p[0], p[1], p[2], 1, 1, ...data);
+ vertices.emplaceBack(p[0], p[1], p[2], -1, 1, ...data);
+
+ triangles.emplaceBack(base + 0, base + 1, base + 2);
+ triangles.emplaceBack(base + 0, base + 2, base + 3);
+
+ base += 4;
+ }
+
+ this.particlesVx = context.createVertexBuffer(vertices, rainLayout.members);
+ this.particlesIdx = context.createIndexBuffer(triangles);
+ this.particlesSegments = SegmentVector.simpleSegment(0, 0, vertices.length, triangles.length);
+ }
+ }
+
+ destroy() {
+ }
+
+ draw(painter: Painter) {
+ // Global parameters
+ const gp = this._revealParams;
+ const zoom = painter.transform.zoom;
+ const lerpClamp = (a: number, b: number, t1: number, t2: number, tMid: number,) => {
+ const t = clamp((tMid - t1) / (t2 - t1), 0, 1);
+ return (1 - t) * a + t * b;
+ };
+ if (gp.revealStart > zoom) { return; }
+ const revealFactor = lerpClamp(0, 1, gp.revealStart, gp.revealStart + gp.revealRange, zoom);
+
+ if (!this.particlesVx || !this.particlesIdx) {
+ return;
+ }
+
+ const context = painter.context;
+ const gl = context.gl;
+
+ //
+ // Fill screen texture
+ //
+
+ const tr = painter.transform;
+
+ if (!this.screenTexture || this.screenTexture.size[0] !== painter.width || this.screenTexture.size[1] !== painter.height) {
+ this.screenTexture = new Texture(context, {width: painter.width, height: painter.height, data: null}, gl.RGBA8);
+ }
+
+ if (this._params.distortionStrength > 0) {
+ context.activeTexture.set(gl.TEXTURE0);
+ this.screenTexture.bind(gl.LINEAR, gl.CLAMP_TO_EDGE);
+ gl.copyTexSubImage2D(gl.TEXTURE_2D, 0, 0, 0, 0, 0, painter.width, painter.height);
+ }
+
+ const curTime = Date.now() / 1000;
+ this.accumulatedTimeFromStart += (curTime - this.prevTime) * this._params.timeFactor;
+
+ this.prevTime = curTime;
+
+ const ppmScale = tr.pixelsPerMeter / 4.25;
+
+ const program = painter.getOrCreateProgram('rainParticle');
+
+ const projectionMatrix = tr.starsProjMatrix;
+
+ const orientation = quat.identity([] as any);
+
+ quat.rotateX(orientation, orientation, degToRad(90) - tr._pitch);
+ quat.rotateZ(orientation, orientation, -tr.angle);
+
+ const rotationMatrix = mat4.fromQuat(new Float32Array(16), orientation);
+ const swapAxesT = mat4.fromValues(1, 0, 0, 0,
+ 0, 0, 1, 0,
+ 0, -1, 0, 0,
+ 0, 0, 0, 1);
+ const swapAxes = mat4.transpose([] as any, swapAxesT);
+ const modelviewMatrix = mat4.multiply([] as any, swapAxes, rotationMatrix);
+
+ const options = tr.getFreeCameraOptions();
+
+ const cameraMercatorPos = options.position;
+
+ const elevation = cameraMercatorPos.toAltitude();
+
+ const latLng = cameraMercatorPos.toLngLat();
+ const lng = degToRad(latLng.lng);
+ const lat = degToRad(latLng.lat);
+
+ // Mercator meters
+ const offsetXCur = lng * earthRadius;
+ const offsetYCur = earthRadius * Math.log(Math.tan(Math.PI / 4 + lat / 2));
+
+ if (this._offsetXPrev === undefined) {
+ this._offsetXPrev = 0;
+ this._offsetYPrev = 0;
+ this._elevationPrev = 0;
+
+ this._accumulatedOffsetX = 0;
+ this._accumulatedOffsetY = 0;
+ this._accumulatedElevation = 0;
+ } else {
+ const deltaX = -this._offsetXPrev + offsetXCur;
+ const deltaY = -this._offsetYPrev + offsetYCur;
+ const deltaE = -this._elevationPrev + elevation;
+
+ this._accumulatedOffsetX += deltaX * ppmScale;
+ this._accumulatedOffsetY += deltaY * ppmScale;
+ this._accumulatedElevation += deltaE * ppmScale;
+
+ this._offsetXPrev = offsetXCur;
+ this._offsetYPrev = offsetYCur;
+ this._elevationPrev = elevation;
+ }
+
+ painter.uploadCommonUniforms(context, program);
+
+ context.activeTexture.set(gl.TEXTURE0);
+ this.screenTexture.bind(gl.LINEAR, gl.CLAMP_TO_EDGE);
+
+ const depthMode = new DepthMode(painter.context.gl.ALWAYS, DepthMode.ReadOnly, painter.depthRangeFor3D);
+
+ const rainDirection: vec3 = [-this._params.direction.x, this._params.direction.y, -100];
+ vec3.normalize(rainDirection, rainDirection);
+
+ const colorVec: vec4 = [this._params.color.r, this._params.color.g, this._params.color.b, this._params.color.a];
+
+ const drawParticlesBox = (boxSize: number, distortionOnly: boolean) => {
+ const offsetX = this._accumulatedOffsetX;
+ const offsetY = this._accumulatedOffsetY;
+ const offsetZ = this._accumulatedElevation;
+
+ const wrappedOffsetX = offsetX - Math.floor(offsetX / boxSize) * boxSize;
+ const wrappedOffsetY = offsetY - Math.floor(offsetY / boxSize) * boxSize;
+ const wrappedOffsetZ = offsetZ - Math.floor(offsetZ / boxSize) * boxSize;
+
+ const camPos: vec3 = [-wrappedOffsetX, -wrappedOffsetY, -wrappedOffsetZ];
+
+ const sizeX = this._params.dropletSizeX;
+ const sizeY = this._params.dropletSizeX * this._params.dropletSizeYScale;
+
+ const thinningX = painter.width / 2;
+ const thinningY = painter.height / 2;
+
+ const dp = this._params;
+
+ const thinningStart = lerpClamp(0, dp.screenThinning.start, 0, 1, dp.screenThinning.intensity);
+ const thinningRange = lerpClamp(0.001, dp.screenThinning.range, 0, 1, dp.screenThinning.intensity);
+ const thinningParticleOffset = lerpClamp(0.0, dp.screenThinning.particleOffset, 0, 1, dp.screenThinning.intensity);
+
+ const uniforms = rainUniformValues({
+ modelview: modelviewMatrix,
+ projection: projectionMatrix,
+ time: this.accumulatedTimeFromStart,
+ camPos,
+ velocityConeAperture: this._params.velocityConeAperture,
+ velocity: this._params.velocity,
+ boxSize,
+ rainDropletSize: [sizeX, sizeY],
+ distortionStrength: this._params.distortionStrength,
+ rainDirection,
+ color: colorVec,
+ screenSize: [tr.width, tr.height],
+ thinningCenterPos: [thinningX, thinningY],
+ thinningShape: [thinningStart, thinningRange, Math.pow(10.0, dp.screenThinning.fadePower)],
+ thinningAffectedRatio: dp.screenThinning.affectedRatio,
+ thinningParticleOffset,
+ shapeDirectionalPower: dp.shapeDirPower,
+ mode: distortionOnly ? 0 : 1
+ });
+
+ const count = Math.round(revealFactor * this._params.intensity * this.particlesCount);
+ const particlesSegments = SegmentVector.simpleSegment(0, 0, count * 4, count * 2);
+
+ program.draw(painter, gl.TRIANGLES, depthMode, StencilMode.disabled,
+ ColorMode.alphaBlended, CullFaceMode.disabled, uniforms, "rain_particles",
+ this.particlesVx, this.particlesIdx, particlesSegments, {});
+ };
+
+ // Distortion only
+ if (this._params.distortionStrength > 0) {
+ drawParticlesBox(this._params.boxSize, true);
+ }
+
+ // Same data alpha blended only
+ drawParticlesBox(this._params.boxSize, false);
+ }
+
+}
diff --git a/src/precipitation/draw_snow.ts b/src/precipitation/draw_snow.ts
new file mode 100644
index 00000000000..2880169efde
--- /dev/null
+++ b/src/precipitation/draw_snow.ts
@@ -0,0 +1,385 @@
+// @flow
+import StencilMode from '../gl/stencil_mode';
+import DepthMode from '../gl/depth_mode';
+import {default as ColorMode} from '../gl/color_mode';
+import CullFaceMode from '../gl/cull_face_mode';
+import {degToRad, clamp} from '../util/util';
+import {vec3, mat4, quat} from 'gl-matrix';
+import SegmentVector from '../data/segment';
+import {TriangleIndexArray, SnowVertexArray} from '../data/array_types';
+import {snowUniformValues} from './snow_program';
+import {mulberry32} from '../style-spec/util/random';
+import {snowLayout} from "./snow_attributes";
+import {earthRadius} from '../geo/lng_lat';
+import {PrecipitationRevealParams} from './precipitation_reveal_params';
+
+import type Painter from '../render/painter';
+import type IndexBuffer from '../gl/index_buffer';
+import type VertexBuffer from '../gl/vertex_buffer';
+import type {vec2, vec4} from 'gl-matrix';
+
+function generateUniformDistributedPointsInsideCube(pointsCount: number): Array {
+ const sRand = mulberry32(1323123451230);
+ // const sRand = Math.random;
+
+ const points: Array = [];
+ for (let i = 0; i < pointsCount; ++i) {
+ const vx = -1 + 2 * sRand();
+ const vy = -1 + 2 * sRand();
+ const vz = -1 + 2 * sRand();
+
+ points.push(vec3.fromValues(vx, vy, vz));
+ }
+
+ return points;
+}
+
+export class Snow {
+ particlesVx: VertexBuffer | null | undefined;
+ particlesIdx: IndexBuffer | null | undefined;
+ particlesCount: number;
+ particlesSegments: SegmentVector;
+ startTime: number;
+ prevTime: number;
+ accumulatedTimeFromStart: number;
+
+ _revealParams: PrecipitationRevealParams;
+
+ _offsetX: number | undefined;
+ _offsetY: number | undefined;
+ _elevation: number | undefined;
+
+ _offsetYPrev: number | undefined;
+ _offsetXPrev: number | undefined;
+ _elevationPrev: number | undefined;
+
+ _offsetXAccum: number | undefined;
+ _offsetYAccum: number | undefined;
+ _elevationAccum: number | undefined;
+
+ _params: {
+ overrideStyleParameters: boolean,
+ intensity: number,
+ timeFactor: number,
+ velocityConeAperture: number,
+ velocity: number,
+ horizontalOscillationRadius: number,
+ horizontalOscillationRate: number,
+ boxSize: number,
+ billboardSize: number,
+ shapeFadeStart: number,
+ shapeFadePower: number,
+ firstBatch: boolean,
+ secondBatch: boolean,
+ secondaryBoxSize: number,
+ secondaryBillboardSizeScale: number,
+ secondaryIntensity: number,
+ screenThinning:{
+ intensity: number,
+ start: number,
+ range: number,
+ fadePower: number,
+ affectedRatio: number,
+ particleOffset: number
+ },
+ color: { r: number, g: number, b: number, a: number },
+ direction: {x: number, y: number}
+ };
+
+ constructor(painter: Painter) {
+ this.accumulatedTimeFromStart = 0;
+ this.startTime = Date.now() / 1000;
+ this.prevTime = Date.now() / 1000;
+
+ this._offsetX = undefined;
+ this._offsetY = undefined;
+ this._elevation = undefined;
+
+ this._offsetXAccum = undefined;
+ this._offsetYAccum = undefined;
+ this._elevationAccum = undefined;
+
+ this._offsetXPrev = undefined;
+ this._offsetYPrev = undefined;
+ this._elevationPrev = undefined;
+
+ this._params = {
+ overrideStyleParameters: true,
+ intensity: 1.0,
+ timeFactor: 0.75,
+ velocityConeAperture: 60.0,
+ velocity: 60.0,
+ horizontalOscillationRadius: 4.2,
+ horizontalOscillationRate: 1.5,
+ boxSize: 2400,
+ billboardSize: 2.79,
+ shapeFadeStart: 0.54,
+ shapeFadePower: 0.21,
+ firstBatch: true,
+ secondBatch: false,
+ secondaryBoxSize: 2440,
+ secondaryBillboardSizeScale: 1.3,
+ secondaryIntensity: 1.0,
+ screenThinning: {
+ intensity: 0.0,
+ start: 0.56,
+ range: 0.37,
+ fadePower: 0,
+ affectedRatio: 1.0,
+ particleOffset: -0.2
+ },
+ color: {r: 1.0, g: 1, b: 1, a: 0.82},
+ direction: {x: -50, y: -35},
+ };
+
+ const tp = painter.tp;
+ const scope = ["Precipitation", "Snow"];
+ this._revealParams = new PrecipitationRevealParams(painter.tp, scope);
+ tp.registerParameter(this._params, scope, 'overrideStyleParameters');
+ tp.registerParameter(this._params, scope, 'intensity', {min: 0.0, max: 1.0});
+ tp.registerParameter(this._params, scope, 'timeFactor', {min: 0.0, max: 1.0, step: 0.01});
+ tp.registerParameter(this._params, scope, 'velocityConeAperture', {min: 0.0, max: 160.0, step: 1.0});
+ tp.registerParameter(this._params, scope, 'velocity', {min: 0.0, max: 500.0, step: 0.5});
+ tp.registerParameter(this._params, scope, 'horizontalOscillationRadius', {min: 0.0, max: 10.0, step: 0.1});
+ tp.registerParameter(this._params, scope, 'horizontalOscillationRate', {min: 0.3, max: 3.0, step: 0.05});
+ tp.registerParameter(this._params, scope, 'boxSize', {min: 100.0, max: 10000.0, step: 50.0});
+ tp.registerParameter(this._params, scope, 'billboardSize', {min: 0.1, max: 10.0, step: 0.01});
+ tp.registerParameter(this._params, scope, 'firstBatch');
+ tp.registerParameter(this._params, scope, 'secondBatch');
+ tp.registerParameter(this._params, scope, 'secondaryBoxSize', {min: 100.0, max: 24000.0, step: 100.0});
+ tp.registerParameter(this._params, scope, 'secondaryBillboardSizeScale', {min: 0.1, max: 10.0, step: 0.05});
+ tp.registerParameter(this._params, scope, 'secondaryIntensity', {min: 0.0, max: 1.0});
+
+ const thinningScope = [...scope, "ScreenThinning"];
+
+ tp.registerParameter(this._params.screenThinning, thinningScope, 'intensity', {min: 0.0, max: 1.0});
+ tp.registerParameter(this._params.screenThinning, thinningScope, 'start', {min: 0.0, max: 2.0});
+ tp.registerParameter(this._params.screenThinning, thinningScope, 'range', {min: 0.0, max: 2.0});
+ tp.registerParameter(this._params.screenThinning, thinningScope, 'fadePower', {min: -1.0, max: 1.0, step: 0.01});
+ tp.registerParameter(this._params.screenThinning, thinningScope, 'affectedRatio', {min: 0.0, max: 1.0, step: 0.01});
+ tp.registerParameter(this._params.screenThinning, thinningScope, 'particleOffset', {min: -1.0, max: 1.0, step: 0.01});
+
+ const shapeScope = [...scope, "Shape"];
+ tp.registerParameter(this._params, shapeScope, 'shapeFadeStart', {min: 0.0, max: 1.0, step: 0.01});
+ tp.registerParameter(this._params, shapeScope, 'shapeFadePower', {min: -1.0, max: 0.99, step: 0.01});
+
+ // const colorScope = ["Precipitation", "Snow", "Color"];
+ tp.registerParameter(this._params, scope, 'color', {
+ color: {type: 'float'},
+ });
+
+ tp.registerParameter(this._params, scope, 'direction', {
+ picker: 'inline',
+ expanded: true,
+ x: {min: -200, max: 200},
+ y: {min: -200, max: 200},
+ });
+
+ this.particlesCount = 16000;
+ }
+
+ update(painter: Painter) {
+ const context = painter.context;
+
+ if (!this.particlesVx) {
+ const positions = generateUniformDistributedPointsInsideCube(this.particlesCount);
+
+ const vertices = new SnowVertexArray();
+ const triangles = new TriangleIndexArray();
+
+ let base = 0;
+ const sRand = mulberry32(1323123451230);
+ // const sRand = Math.random;
+ for (let i = 0; i < positions.length; ++i) {
+ const p = positions[i];
+
+ const velocityScale = sRand();
+ const directionConeHeading = sRand();
+ const directionConePitch = sRand();
+ const data: vec4 = [i / positions.length, velocityScale, directionConeHeading, directionConePitch];
+ const dataHorizontalOscillation: vec2 = [sRand(), sRand()];
+
+ vertices.emplaceBack(p[0], p[1], p[2], -1, -1, ...data, ...dataHorizontalOscillation);
+ vertices.emplaceBack(p[0], p[1], p[2], 1, -1, ...data, ...dataHorizontalOscillation);
+ vertices.emplaceBack(p[0], p[1], p[2], 1, 1, ...data, ...dataHorizontalOscillation);
+ vertices.emplaceBack(p[0], p[1], p[2], -1, 1, ...data, ...dataHorizontalOscillation);
+
+ triangles.emplaceBack(base + 0, base + 1, base + 2);
+ triangles.emplaceBack(base + 0, base + 2, base + 3);
+
+ base += 4;
+ }
+
+ this.particlesVx = context.createVertexBuffer(vertices, snowLayout.members);
+ this.particlesIdx = context.createIndexBuffer(triangles);
+ this.particlesSegments = SegmentVector.simpleSegment(0, 0, vertices.length, triangles.length);
+ }
+ }
+
+ destroy() {
+ if (this.particlesVx) {
+ this.particlesVx.destroy();
+ }
+
+ if (this.particlesIdx) {
+ this.particlesIdx.destroy();
+ }
+ }
+
+ draw(painter: Painter) {
+ // Global parameters
+ const gp = this._revealParams;
+ const zoom = painter.transform.zoom;
+ const lerpClamp = (a: number, b: number, t1: number, t2: number, tMid: number,) => {
+ const t = clamp((tMid - t1) / (t2 - t1), 0, 1);
+ return (1 - t) * a + t * b;
+ };
+ if (gp.revealStart > zoom) { return; }
+ const revealFactor = lerpClamp(0, 1, gp.revealStart, gp.revealStart + gp.revealRange, zoom);
+
+ if (!this.particlesVx || !this.particlesIdx) {
+ return;
+ }
+
+ const curTime = Date.now() / 1000;
+ this.accumulatedTimeFromStart += (curTime - this.prevTime) * this._params.timeFactor;
+
+ this.prevTime = curTime;
+
+ const context = painter.context;
+ const gl = context.gl;
+ const tr = painter.transform;
+
+ const program = painter.getOrCreateProgram('snowParticle');
+
+ const projectionMatrix = tr.starsProjMatrix;
+
+ const orientation = quat.identity([] as any);
+
+ quat.rotateX(orientation, orientation, degToRad(90) - tr._pitch);
+ quat.rotateZ(orientation, orientation, -tr.angle);
+
+ const rotationMatrix = mat4.fromQuat(new Float32Array(16), orientation);
+
+ const swapAxesT = mat4.fromValues(1, 0, 0, 0,
+ 0, 0, 1, 0,
+ 0, -1, 0, 0,
+ 0, 0, 0, 1);
+ const swapAxes = mat4.transpose([] as any, swapAxesT);
+
+ const modelviewMatrix = mat4.multiply([] as any, swapAxes, rotationMatrix);
+
+ const options = tr.getFreeCameraOptions();
+
+ const cameraMercatorPos = options.position;
+
+ if (!cameraMercatorPos) {
+ return;
+ }
+
+ const ppmScale = tr.pixelsPerMeter / 2.25;
+ const altitudeMeters = cameraMercatorPos.toAltitude();
+ const elevation = altitudeMeters;
+
+ // Calculate mercator meters
+ const latLngF = cameraMercatorPos.toLngLat();
+ const lng = degToRad(latLngF.lng);
+ const lat = degToRad(latLngF.lat);
+
+ // Mercator meters
+ const offsetXCur = lng * earthRadius;
+ const offsetYCur = earthRadius * Math.log(Math.tan(Math.PI / 4 + lat / 2));
+
+ if (this._offsetXPrev === undefined) {
+ this._offsetXPrev = 0;
+ this._offsetYPrev = 0;
+ this._elevationPrev = 0;
+
+ this._offsetXAccum = 0;
+ this._offsetYAccum = 0;
+ this._elevationAccum = 0;
+ } else {
+ const deltaX = -this._offsetXPrev + offsetXCur;
+ const deltaY = -this._offsetYPrev + offsetYCur;
+ const deltaE = -this._elevationPrev + elevation;
+
+ this._offsetXAccum += deltaX * ppmScale;
+ this._offsetYAccum += deltaY * ppmScale;
+ this._elevationAccum += deltaE * ppmScale;
+
+ this._offsetXPrev = offsetXCur;
+ this._offsetYPrev = offsetYCur;
+ this._elevationPrev = elevation;
+ }
+
+ painter.uploadCommonUniforms(context, program);
+
+ const depthMode = new DepthMode(painter.context.gl.ALWAYS, DepthMode.ReadOnly, painter.depthRangeFor3D);
+
+ const drawParticlesBox = (boxSize: number, sizeScale: number, dp: any) => {
+
+ const offsetX = this._offsetXAccum;
+ const offsetY = this._offsetYAccum;
+ const offsetZ = this._elevationAccum;
+
+ const wrappedOffsetX = offsetX - Math.floor(offsetX / boxSize) * boxSize;
+ const wrappedOffsetY = offsetY - Math.floor(offsetY / boxSize) * boxSize;
+ const wrappedOffsetZ = offsetZ - Math.floor(offsetZ / boxSize) * boxSize;
+
+ const camPos: [number, number, number] = [-wrappedOffsetX, -wrappedOffsetY, -wrappedOffsetZ];
+
+ const snowDirection: [number, number, number] = [-dp.direction.x, dp.direction.y, -100];
+ vec3.normalize(snowDirection, snowDirection);
+
+ const thinningX = tr.width / 2;
+ const thinningY = tr.height / 2;
+
+ const thinningStart = lerpClamp(0, dp.screenThinning.start, 0, 1, dp.screenThinning.intensity);
+ const thinningRange = lerpClamp(0.001, dp.screenThinning.range, 0, 1, dp.screenThinning.intensity);
+ const thinningParticleOffset = lerpClamp(0.0, dp.screenThinning.particleOffset, 0, 1, dp.screenThinning.intensity);
+
+ const uniforms = snowUniformValues({
+ modelview: modelviewMatrix,
+ projection: projectionMatrix,
+ time: this.accumulatedTimeFromStart,
+ camPos,
+ velocityConeAperture: dp.velocityConeAperture,
+ velocity: dp.velocity,
+ horizontalOscillationRadius: dp.horizontalOscillationRadius,
+ horizontalOscillationRate: dp.horizontalOscillationRate,
+ boxSize,
+ billboardSize: dp.billboardSize * sizeScale,
+ simpleShapeParameters: [dp.shapeFadeStart, dp.shapeFadePower],
+ screenSize: [tr.width, tr.height],
+ thinningCenterPos: [thinningX, thinningY],
+ thinningShape: [thinningStart, thinningRange, Math.pow(10.0, dp.screenThinning.fadePower)],
+ thinningAffectedRatio: dp.screenThinning.affectedRatio,
+ thinningParticleOffset,
+ color: [dp.color.r, dp.color.g, dp.color.b, dp.color.a],
+ direction: snowDirection
+ }
+ );
+
+ const count = Math.round(revealFactor * dp.intensity * this.particlesCount);
+ const particlesSegments = SegmentVector.simpleSegment(0, 0, count * 4, count * 2);
+
+ if (this.particlesVx && this.particlesIdx) {
+ program.draw(painter, gl.TRIANGLES, depthMode, StencilMode.disabled,
+ ColorMode.alphaBlended, CullFaceMode.disabled, uniforms, "snow_particles",
+ this.particlesVx, this.particlesIdx, particlesSegments, {});
+ }
+ };
+
+ const batchBoxSize = this._params.boxSize;
+ if (this._params.firstBatch) {
+ drawParticlesBox(batchBoxSize, 1.0, this._params);
+ }
+
+ const dp2 = structuredClone(this._params);
+ dp2.intensity = dp2.secondaryIntensity;
+ const boxSize2 = this._params.secondaryBoxSize;
+ if (this._params.secondBatch) {
+ drawParticlesBox(boxSize2, this._params.secondaryBillboardSizeScale, dp2);
+ }
+ }
+}
diff --git a/src/precipitation/precipitation_reveal_params.ts b/src/precipitation/precipitation_reveal_params.ts
new file mode 100644
index 00000000000..9b8d8f31f2a
--- /dev/null
+++ b/src/precipitation/precipitation_reveal_params.ts
@@ -0,0 +1,15 @@
+// @flow
+import {type ITrackedParameters} from '../tracked-parameters/tracked_parameters_base';
+
+export class PrecipitationRevealParams {
+ revealStart: number;
+ revealRange: number;
+
+ constructor(tp: ITrackedParameters, namespace: Array) {
+ this.revealStart = 11.0;
+ this.revealRange = 1.0;
+
+ tp.registerParameter(this, [...namespace, "Reveal"], 'revealStart', {min: 8, max: 17, step: 0.05});
+ tp.registerParameter(this, [...namespace, "Reveal"], 'revealRange', {min: 0.1, max: 5.1, step: 0.05});
+ }
+}
diff --git a/src/precipitation/rain_attributes.ts b/src/precipitation/rain_attributes.ts
new file mode 100644
index 00000000000..76126af4542
--- /dev/null
+++ b/src/precipitation/rain_attributes.ts
@@ -0,0 +1,10 @@
+// @flow
+import {createLayout} from '../util/struct_array.js';
+
+import type {StructArrayLayout} from '../util/struct_array.js';
+
+export const rainLayout: StructArrayLayout = createLayout([
+ {type: 'Float32', name: 'a_pos_3f', components: 3},
+ {type: 'Float32', name: 'a_uv', components: 2},
+ {type: 'Float32', name: 'a_rainParticleData', components: 4},
+]);
diff --git a/src/precipitation/rain_program.ts b/src/precipitation/rain_program.ts
new file mode 100644
index 00000000000..f5f2bca37cb
--- /dev/null
+++ b/src/precipitation/rain_program.ts
@@ -0,0 +1,102 @@
+// @flow
+
+import {
+ Uniform4f,
+ Uniform3f,
+ Uniform2f,
+ UniformMatrix4f,
+ Uniform1f,
+ Uniform1i,
+} from '../render/uniform_binding.js';
+
+import type Context from '../gl/context.js';
+import type {UniformValues} from '../render/uniform_binding.js';
+import type {mat4} from 'gl-matrix';
+
+export type RainUniformsType = {
+ 'u_modelview': UniformMatrix4f,
+ 'u_projection': UniformMatrix4f,
+ 'u_time': Uniform1f,
+ 'u_cam_pos': Uniform3f,
+ 'u_texScreen': Uniform1i,
+ 'u_velocityConeAperture': Uniform1f,
+ 'u_velocity': Uniform1f,
+ 'u_boxSize': Uniform1f,
+ 'u_rainDropletSize': Uniform2f,
+ 'u_distortionStrength': Uniform1f,
+ 'u_rainDirection': Uniform3f,
+ 'u_color': Uniform4f,
+ 'u_screenSize': Uniform2f,
+ 'u_thinningCenterPos': Uniform2f,
+ 'u_thinningShape': Uniform3f,
+ 'u_thinningAffectedRatio': Uniform1f,
+ 'u_thinningParticleOffset': Uniform1f,
+ 'u_shapeDirectionalPower': Uniform1f,
+ 'u_mode': Uniform1f,
+};
+
+const rainUniforms = (context: Context): RainUniformsType => ({
+ 'u_modelview': new UniformMatrix4f(context),
+ 'u_projection': new UniformMatrix4f(context),
+ 'u_time': new Uniform1f(context),
+ 'u_cam_pos': new Uniform3f(context),
+ 'u_texScreen': new Uniform1i(context),
+ 'u_velocityConeAperture': new Uniform1f(context),
+ 'u_velocity': new Uniform1f(context),
+ 'u_boxSize': new Uniform1f(context),
+ 'u_rainDropletSize': new Uniform2f(context),
+ 'u_distortionStrength': new Uniform1f(context),
+ 'u_rainDirection': new Uniform3f(context),
+ 'u_color': new Uniform4f(context),
+ 'u_screenSize': new Uniform2f(context),
+ 'u_thinningCenterPos': new Uniform2f(context),
+ 'u_thinningShape': new Uniform3f(context),
+ 'u_thinningAffectedRatio': new Uniform1f(context),
+ 'u_thinningParticleOffset': new Uniform1f(context),
+ 'u_shapeDirectionalPower': new Uniform1f(context),
+ 'u_mode': new Uniform1f(context),
+});
+
+const rainUniformValues = (values: {
+ modelview: mat4,
+ projection: mat4,
+ time: number,
+ camPos: [number, number, number],
+ velocityConeAperture: number,
+ velocity: number,
+ boxSize: number,
+ rainDropletSize: [number, number],
+ distortionStrength: number,
+ rainDirection: [number, number, number],
+ color: [number, number, number, number],
+ screenSize: [number, number],
+ thinningCenterPos: [number, number],
+ thinningShape: [number, number, number],
+ thinningAffectedRatio: number,
+ thinningParticleOffset: number,
+ shapeDirectionalPower: number,
+ mode: number,
+}
+): UniformValues => ({
+ 'u_modelview': Float32Array.from(values.modelview),
+ 'u_projection': Float32Array.from(values.projection),
+ 'u_time': values.time,
+ 'u_cam_pos': values.camPos,
+ 'u_texScreen': 0,
+ 'u_velocityConeAperture': values.velocityConeAperture,
+ 'u_velocity': values.velocity,
+ 'u_boxSize': values.boxSize,
+ 'u_rainDropletSize': values.rainDropletSize,
+ 'u_distortionStrength': values.distortionStrength,
+ 'u_rainDirection': values.rainDirection,
+ 'u_color': values.color,
+ 'u_screenSize': values.screenSize,
+ 'u_thinningCenterPos': values.thinningCenterPos,
+ 'u_thinningShape': values.thinningShape,
+ 'u_thinningAffectedRatio': values.thinningAffectedRatio,
+ 'u_thinningParticleOffset': values.thinningParticleOffset,
+ 'u_shapeDirectionalPower': values.shapeDirectionalPower,
+ 'u_mode': values.mode,
+});
+
+export {rainUniforms, rainUniformValues};
diff --git a/src/precipitation/snow_attributes.ts b/src/precipitation/snow_attributes.ts
new file mode 100644
index 00000000000..0d6c2359ddc
--- /dev/null
+++ b/src/precipitation/snow_attributes.ts
@@ -0,0 +1,11 @@
+// @flow
+import {createLayout} from '../util/struct_array.js';
+
+import type {StructArrayLayout} from '../util/struct_array.js';
+
+export const snowLayout: StructArrayLayout = createLayout([
+ {type: 'Float32', name: 'a_pos_3f', components: 3},
+ {type: 'Float32', name: 'a_uv', components: 2},
+ {type: 'Float32', name: 'a_snowParticleData', components: 4},
+ {type: 'Float32', name: 'a_snowParticleDataHorizontalOscillation', components: 2}
+]);
diff --git a/src/precipitation/snow_program.ts b/src/precipitation/snow_program.ts
new file mode 100644
index 00000000000..e6f689e5ca1
--- /dev/null
+++ b/src/precipitation/snow_program.ts
@@ -0,0 +1,100 @@
+// @flow
+
+import {
+ Uniform4f,
+ Uniform3f,
+ Uniform2f,
+ UniformMatrix4f,
+ Uniform1f
+} from '../render/uniform_binding.js';
+
+import type Context from '../gl/context.js';
+import type {UniformValues} from '../render/uniform_binding.js';
+import type {mat4} from 'gl-matrix';
+
+export type SnowDefinesType = 'TERRAIN';
+
+export type SnowUniformsType = {
+ 'u_modelview': UniformMatrix4f,
+ 'u_projection': UniformMatrix4f,
+ 'u_time': Uniform1f,
+ 'u_cam_pos': Uniform3f,
+ 'u_velocityConeAperture': Uniform1f,
+ 'u_velocity': Uniform1f,
+ 'u_horizontalOscillationRadius': Uniform1f,
+ 'u_horizontalOscillationRate': Uniform1f,
+ 'u_boxSize': Uniform1f,
+ 'u_billboardSize': Uniform1f,
+ 'u_simpleShapeParameters': Uniform2f,
+ 'u_screenSize': Uniform2f,
+ 'u_thinningCenterPos': Uniform2f,
+ 'u_thinningShape': Uniform3f,
+ 'u_thinningAffectedRatio': Uniform1f,
+ 'u_thinningParticleOffset': Uniform1f,
+ 'u_particleColor': Uniform4f,
+ 'u_direction': Uniform3f,
+};
+
+const snowUniforms = (context: Context): SnowUniformsType => ({
+ 'u_modelview': new UniformMatrix4f(context),
+ 'u_projection': new UniformMatrix4f(context),
+ 'u_time': new Uniform1f(context),
+ 'u_cam_pos': new Uniform3f(context),
+ 'u_velocityConeAperture': new Uniform1f(context),
+ 'u_velocity': new Uniform1f(context),
+ 'u_horizontalOscillationRadius': new Uniform1f(context),
+ 'u_horizontalOscillationRate': new Uniform1f(context),
+ 'u_boxSize': new Uniform1f(context),
+ 'u_billboardSize': new Uniform1f(context),
+ 'u_simpleShapeParameters': new Uniform2f(context),
+ 'u_screenSize': new Uniform2f(context),
+ 'u_thinningCenterPos': new Uniform2f(context),
+ 'u_thinningShape': new Uniform3f(context),
+ 'u_thinningAffectedRatio': new Uniform1f(context),
+ 'u_thinningParticleOffset': new Uniform1f(context),
+ 'u_particleColor': new Uniform4f(context),
+ 'u_direction': new Uniform3f(context),
+});
+
+const snowUniformValues = (values: {
+ modelview: mat4,
+ projection: mat4,
+ time: number,
+ camPos: [number, number, number],
+ velocityConeAperture: number,
+ velocity: number,
+ horizontalOscillationRadius: number,
+ horizontalOscillationRate: number,
+ boxSize: number,
+ billboardSize: number,
+ simpleShapeParameters: [number, number],
+ screenSize: [number, number],
+ thinningCenterPos: [number, number],
+ thinningShape: [number, number, number],
+ thinningAffectedRatio: number,
+ thinningParticleOffset: number,
+ color: [number, number, number, number],
+ direction: [number, number, number],
+}
+): UniformValues => ({
+ 'u_modelview': Float32Array.from(values.modelview),
+ 'u_projection': Float32Array.from(values.projection),
+ 'u_time': values.time,
+ 'u_cam_pos': values.camPos,
+ 'u_velocityConeAperture': values.velocityConeAperture,
+ 'u_velocity': values.velocity,
+ 'u_horizontalOscillationRadius': values.horizontalOscillationRadius,
+ 'u_horizontalOscillationRate': values.horizontalOscillationRate,
+ 'u_boxSize': values.boxSize,
+ 'u_billboardSize': values.billboardSize,
+ 'u_simpleShapeParameters': values.simpleShapeParameters,
+ 'u_screenSize': values.screenSize,
+ 'u_thinningCenterPos': values.thinningCenterPos,
+ 'u_thinningShape': values.thinningShape,
+ 'u_thinningAffectedRatio': values.thinningAffectedRatio,
+ 'u_thinningParticleOffset': values.thinningParticleOffset,
+ 'u_particleColor': values.color,
+ 'u_direction': values.direction
+});
+
+export {snowUniforms, snowUniformValues};
diff --git a/src/render/draw_atmosphere.ts b/src/render/draw_atmosphere.ts
index 3b12220b782..395c5af879c 100644
--- a/src/render/draw_atmosphere.ts
+++ b/src/render/draw_atmosphere.ts
@@ -158,8 +158,7 @@ class Atmosphere {
tr.worldSize / (2.0 * Math.PI * 1.025) - 1.0 : tr.globeRadius;
const temporalOffset = (painter.frameCounter / 1000.0) % 1;
- const globeCenterInViewSpace = ((tr.globeCenterInViewSpace) as Array);
- // @ts-expect-error - TS2345 - Argument of type 'number[]' is not assignable to parameter of type 'ReadonlyVec3'.
+ const globeCenterInViewSpace = tr.globeCenterInViewSpace;
const globeCenterDistance = vec3.length(globeCenterInViewSpace);
const distanceToHorizon = Math.sqrt(Math.pow(globeCenterDistance, 2.0) - Math.pow(globeRadius, 2.0));
const horizonAngle = Math.acos(distanceToHorizon / globeCenterDistance);
@@ -206,7 +205,6 @@ class Atmosphere {
}
drawStars(painter: Painter, fog: Fog) {
-
const starIntensity = clamp(fog.properties.get('star-intensity'), 0.0, 1.0);
if (starIntensity === 0) {
@@ -219,31 +217,26 @@ class Atmosphere {
const program = painter.getOrCreateProgram('stars');
- const orientation = quat.identity([] as any);
-
+ const orientation = quat.identity([] as unknown as quat);
quat.rotateX(orientation, orientation, -tr._pitch);
quat.rotateZ(orientation, orientation, -tr.angle);
quat.rotateX(orientation, orientation, degToRad(tr._center.lat));
quat.rotateY(orientation, orientation, -degToRad(tr._center.lng));
const rotationMatrix = mat4.fromQuat(new Float32Array(16), orientation);
+ const mvp = mat4.multiply([] as unknown as mat4, tr.starsProjMatrix, rotationMatrix);
+ const modelView3 = mat3.fromMat4([] as unknown as mat3, rotationMatrix);
+ const modelviewInv = mat3.invert([] as unknown as mat3, modelView3);
- const mvp = mat4.multiply([] as any, tr.starsProjMatrix, rotationMatrix);
-
- const modelView3 = mat3.fromMat4([] as any, rotationMatrix);
-
- const modelviewInv = mat3.invert([] as any, modelView3);
-
- const camUp = [0, 1, 0];
- vec3.transformMat3(camUp as [number, number, number], camUp as [number, number, number], modelviewInv);
- vec3.scale(camUp as [number, number, number], camUp as [number, number, number], this.params.sizeMultiplier);
- const camRight = [1, 0, 0];
- vec3.transformMat3(camRight as [number, number, number], camRight as [number, number, number], modelviewInv);
- vec3.scale(camRight as [number, number, number], camRight as [number, number, number], this.params.sizeMultiplier);
+ const camUp: vec3 = [0, 1, 0];
+ vec3.transformMat3(camUp, camUp, modelviewInv);
+ vec3.scale(camUp, camUp, this.params.sizeMultiplier);
+ const camRight: vec3 = [1, 0, 0];
+ vec3.transformMat3(camRight, camRight, modelviewInv);
+ vec3.scale(camRight, camRight, this.params.sizeMultiplier);
const uniforms = starsUniformValues(
mvp,
- // @ts-expect-error - TS2345 - Argument of type 'number[]' is not assignable to parameter of type '[number, number, number]'.
camUp,
camRight,
starIntensity);
diff --git a/src/render/draw_background.ts b/src/render/draw_background.ts
index 1024e733ed1..016f13ab432 100644
--- a/src/render/draw_background.ts
+++ b/src/render/draw_background.ts
@@ -90,9 +90,7 @@ function drawBackground(painter: Painter, sourceCache: SourceCache, layer: Backg
backgroundTiles ? backgroundTiles[tileID.key] : new Tile(tileID, tileSize, transform.zoom, painter);
const uniformValues = image ?
-
backgroundPatternUniformValues(matrix, emissiveStrength, opacity, painter, image, layer.scope, patternPosition, isViewportPitch, {tileID, tileSize}) :
-
backgroundUniformValues(matrix, emissiveStrength, opacity, color.toRenderColor(layer.lut));
painter.uploadCommonUniforms(context, program, unwrappedTileID);
diff --git a/src/render/draw_circle.ts b/src/render/draw_circle.ts
index 65561245094..16fd9fcb44a 100644
--- a/src/render/draw_circle.ts
+++ b/src/render/draw_circle.ts
@@ -62,7 +62,7 @@ function drawCircles(painter: Painter, sourceCache: SourceCache, layer: CircleSt
const colorMode = painter.colorModeForDrapableLayerRenderPass(emissiveStrength);
const isGlobeProjection = tr.projection.name === 'globe';
- const mercatorCenter = [mercatorXfromLng(tr.center.lng), mercatorYfromLat(tr.center.lat)];
+ const mercatorCenter: [number, number] = [mercatorXfromLng(tr.center.lng), mercatorYfromLat(tr.center.lat)];
const segmentsRenderStates: Array = [];
@@ -90,7 +90,6 @@ function drawCircles(painter: Painter, sourceCache: SourceCache, layer: CircleSt
const globeExtVertexBuffer = bucket.globeExtVertexBuffer;
const indexBuffer = bucket.indexBuffer;
const invMatrix = tr.projection.createInversionMatrix(tr, coord.canonical);
- // @ts-expect-error - TS2345 - Argument of type 'number[]' is not assignable to parameter of type '[number, number]'.
const uniformValues = circleUniformValues(painter, coord, tile, invMatrix, mercatorCenter, layer);
const state: TileRenderState = {
diff --git a/src/render/draw_collision_debug.ts b/src/render/draw_collision_debug.ts
index f57f9d91442..e132cf6763a 100644
--- a/src/render/draw_collision_debug.ts
+++ b/src/render/draw_collision_debug.ts
@@ -22,8 +22,8 @@ export default drawCollisionDebug;
type TileBatch = {
circleArray: Array;
circleOffset: number;
- transform: Float32Array;
- invTransform: Float32Array;
+ transform: mat4;
+ invTransform: mat4;
projection: Projection;
};
@@ -67,8 +67,7 @@ function drawCollisionDebug(painter: Painter, sourceCache: SourceCache, layer: S
circleArray,
circleOffset,
transform,
- // @ts-expect-error - TS2322 - Type 'mat4' is not assignable to type 'Float32Array'.
- invTransform,
+ invTransform: invTransform as Float32Array,
projection: bucket.getProjection()
});
diff --git a/src/render/draw_custom.ts b/src/render/draw_custom.ts
index f88876cbe5e..ef49e5f2dd8 100644
--- a/src/render/draw_custom.ts
+++ b/src/render/draw_custom.ts
@@ -76,9 +76,9 @@ function drawCustom(painter: Painter, sourceCache: SourceCache, layer: CustomSty
if (painter.transform.projection.name === "globe") {
const center = painter.transform.pointMerc;
- implementation.render(context.gl, painter.transform.customLayerMatrix(), painter.transform.getProjection(), painter.transform.globeToMercatorMatrix(), globeToMercatorTransition(painter.transform.zoom), [center.x, center.y], painter.transform.pixelsPerMeterRatio);
+ implementation.render(context.gl, painter.transform.customLayerMatrix() as number[], painter.transform.getProjection(), painter.transform.globeToMercatorMatrix(), globeToMercatorTransition(painter.transform.zoom), [center.x, center.y], painter.transform.pixelsPerMeterRatio);
} else {
- implementation.render(context.gl, painter.transform.customLayerMatrix());
+ implementation.render(context.gl, painter.transform.customLayerMatrix() as number[]);
}
context.setDirty();
diff --git a/src/render/draw_debug.ts b/src/render/draw_debug.ts
index 4eade631d11..909ff1fb1c0 100644
--- a/src/render/draw_debug.ts
+++ b/src/render/draw_debug.ts
@@ -74,10 +74,8 @@ function drawDebugTile(painter: Painter, sourceCache: SourceCache, coord: Oversc
// except we use transitionTileAABBinECEF instead of globeTileBounds to account for the transition.
const bounds = transitionTileAABBinECEF(coord.canonical, tr);
const decode = globeDenormalizeECEF(bounds);
- // @ts-expect-error - TS2345 - Argument of type 'Float64Array' is not assignable to parameter of type 'ReadonlyMat4'.
posMatrix = mat4.multiply(new Float32Array(16), tr.globeMatrix, decode);
- // @ts-expect-error - TS2345 - Argument of type 'number[] | Float32Array | Float64Array' is not assignable to parameter of type 'ReadonlyMat4'.
mat4.multiply(posMatrix, tr.projMatrix, posMatrix);
}
@@ -111,7 +109,6 @@ function drawDebugTile(painter: Painter, sourceCache: SourceCache, coord: Oversc
const debugSegments = tile._tileDebugSegments || painter.debugSegments;
program.draw(painter, gl.LINE_STRIP, depthMode, stencilMode, colorMode, CullFaceMode.disabled,
- // @ts-expect-error - TS2345 - Argument of type 'mat4' is not assignable to parameter of type 'Float32Array'.
debugUniformValues(posMatrix, color), id,
debugBuffer, debugIndexBuffer, debugSegments,
null, null, null, [tile._globeTileDebugBorderBuffer]);
@@ -136,7 +133,6 @@ function drawDebugTile(painter: Painter, sourceCache: SourceCache, coord: Oversc
const debugTextSegments = tile._tileDebugTextSegments || painter.debugSegments;
program.draw(painter, gl.TRIANGLES, depthMode, stencilMode, ColorMode.alphaBlended, CullFaceMode.disabled,
- // @ts-expect-error - TS2345 - Argument of type 'mat4' is not assignable to parameter of type 'Float32Array'.
debugUniformValues(posMatrix, Color.transparent, scaleRatio), id,
debugTextBuffer, debugTextIndexBuffer, debugTextSegments,
null, null, null, [tile._globeTileDebugTextBuffer]);
diff --git a/src/render/draw_fill.ts b/src/render/draw_fill.ts
index 1965197abb8..91032a6e0ca 100644
--- a/src/render/draw_fill.ts
+++ b/src/render/draw_fill.ts
@@ -111,7 +111,6 @@ function drawFillTiles(painter: Painter, sourceCache: SourceCache, layer: FillSt
}
const tileMatrix = painter.translatePosMatrix(coord.projMatrix, tile,
-
layer.paint.get('fill-translate'), layer.paint.get('fill-translate-anchor'));
const emissiveStrength = layer.paint.get('fill-emissive-strength');
@@ -120,18 +119,14 @@ function drawFillTiles(painter: Painter, sourceCache: SourceCache, layer: FillSt
indexBuffer = bucket.indexBuffer;
segments = bucket.segments;
uniformValues = image ?
-
fillPatternUniformValues(tileMatrix, emissiveStrength, painter, tile) :
-
fillUniformValues(tileMatrix, emissiveStrength);
} else {
indexBuffer = bucket.indexBuffer2;
segments = bucket.segments2;
- const drawingBufferSize = (painter.terrain && painter.terrain.renderingToTexture) ? painter.terrain.drapeBufferSize : [gl.drawingBufferWidth, gl.drawingBufferHeight];
+ const drawingBufferSize: [number, number] = (painter.terrain && painter.terrain.renderingToTexture) ? painter.terrain.drapeBufferSize : [gl.drawingBufferWidth, gl.drawingBufferHeight];
uniformValues = (programName === 'fillOutlinePattern' && image) ?
- // @ts-expect-error - TS2345 - Argument of type 'unknown' is not assignable to parameter of type 'number'.
fillOutlinePatternUniformValues(tileMatrix, emissiveStrength, painter, tile, drawingBufferSize) :
- // @ts-expect-error - TS2345 - Argument of type 'unknown' is not assignable to parameter of type 'number'.
fillOutlineUniformValues(tileMatrix, emissiveStrength, drawingBufferSize);
}
diff --git a/src/render/draw_fill_extrusion.ts b/src/render/draw_fill_extrusion.ts
index 519a3ea2948..9e830089bbd 100644
--- a/src/render/draw_fill_extrusion.ts
+++ b/src/render/draw_fill_extrusion.ts
@@ -29,6 +29,7 @@ import {mat4} from "gl-matrix";
import {getCutoffParams} from './cutoff';
import {ZoomDependentExpression} from '../style-spec/expression/index';
+import type {vec3} from 'gl-matrix';
import type FillExtrusionStyleLayer from '../style/style_layer/fill_extrusion_style_layer';
import type SourceCache from '../source/source_cache';
import type Painter from './painter';
@@ -269,7 +270,7 @@ function drawExtrusionTiles(painter: Painter, source: SourceCache, layer: FillEx
const opacity = layer.paint.get('fill-extrusion-opacity');
const lighting3DMode = painter.style.enable3dLights();
const aoRadius = (lighting3DMode && !image) ? layer.paint.get('fill-extrusion-ambient-occlusion-wall-radius') : layer.paint.get('fill-extrusion-ambient-occlusion-radius');
- const ao = [layer.paint.get('fill-extrusion-ambient-occlusion-intensity'), aoRadius];
+ const ao: [number, number] = [layer.paint.get('fill-extrusion-ambient-occlusion-intensity'), aoRadius];
const edgeRadius = layer.layout.get('fill-extrusion-edge-radius');
const zeroRoofRadius = edgeRadius > 0 && !layer.paint.get('fill-extrusion-rounded-roof');
@@ -277,12 +278,14 @@ function drawExtrusionTiles(painter: Painter, source: SourceCache, layer: FillEx
const heightLift = tr.projection.name === 'globe' ? fillExtrusionHeightLift() : 0;
const isGlobeProjection = tr.projection.name === 'globe';
const globeToMercator = isGlobeProjection ? globeToMercatorTransition(tr.zoom) : 0.0;
- const mercatorCenter = [mercatorXfromLng(tr.center.lng), mercatorYfromLat(tr.center.lat)];
+ const mercatorCenter: [number, number] = [mercatorXfromLng(tr.center.lng), mercatorYfromLat(tr.center.lat)];
const floodLightColor = (layer.paint.get('fill-extrusion-flood-light-color').toRenderColor(layer.lut).toArray01().slice(0, 3) as any);
const floodLightIntensity = layer.paint.get('fill-extrusion-flood-light-intensity');
const verticalScale = layer.paint.get('fill-extrusion-vertical-scale');
const wallMode = layer.paint.get('fill-extrusion-line-width').constantOr(1.0) !== 0.0;
+ const heightAlignment = layer.paint.get('fill-extrusion-height-alignment');
+ const baseAlignment = layer.paint.get('fill-extrusion-base-alignment');
const cutoffParams = getCutoffParams(painter, layer.paint.get('fill-extrusion-cutoff-fade-range'));
const baseDefines = ([] as any);
@@ -383,7 +386,7 @@ function drawExtrusionTiles(painter: Painter, source: SourceCache, layer: FillEx
}
const tileMatrix = shadowRenderer.calculateShadowPassMatrixFromTile(tile.tileID.toUnwrapped());
- uniformValues = fillExtrusionDepthUniformValues(tileMatrix, roofEdgeRadius, lineWidthScale, verticalScale);
+ uniformValues = fillExtrusionDepthUniformValues(tileMatrix, roofEdgeRadius, lineWidthScale, verticalScale, heightAlignment, baseAlignment);
} else {
const matrix = painter.translatePosMatrix(
coord.expandedProjMatrix,
@@ -394,13 +397,11 @@ function drawExtrusionTiles(painter: Painter, source: SourceCache, layer: FillEx
const invMatrix = tr.projection.createInversionMatrix(tr, coord.canonical);
if (image) {
- // @ts-expect-error - TS2345 - Argument of type 'unknown' is not assignable to parameter of type 'boolean'.
uniformValues = fillExtrusionPatternUniformValues(matrix, painter, shouldUseVerticalGradient, opacity, ao, roofEdgeRadius, lineWidthScale, coord,
- tile, heightLift, globeToMercator, mercatorCenter, invMatrix, floodLightColor, verticalScale);
+ tile, heightLift, heightAlignment, baseAlignment, globeToMercator, mercatorCenter, invMatrix, floodLightColor, verticalScale);
} else {
- // @ts-expect-error - TS2345 - Argument of type 'unknown' is not assignable to parameter of type 'boolean'.
uniformValues = fillExtrusionUniformValues(matrix, painter, shouldUseVerticalGradient, opacity, ao, roofEdgeRadius, lineWidthScale, coord,
- heightLift, globeToMercator, mercatorCenter, invMatrix, floodLightColor, verticalScale, floodLightIntensity, groundShadowFactor);
+ heightLift, heightAlignment, baseAlignment, globeToMercator, mercatorCenter, invMatrix, floodLightColor, verticalScale, floodLightIntensity, groundShadowFactor);
}
}
@@ -478,16 +479,15 @@ function drawGroundEffect(painter: Painter, source: SourceCache, layer: FillExtr
}
const edgeRadius = layer.layout.get('fill-extrusion-edge-radius');
- const renderGroundEffectTile = (coord: OverscaledTileID, groundEffect: GroundEffect, segments: any, matrix: Float32Array, meterToTile: number) => {
+ const renderGroundEffectTile = (coord: OverscaledTileID, groundEffect: GroundEffect, segments: any, matrix: mat4, meterToTile: number) => {
const programConfiguration = groundEffect.programConfigurations.get(layer.id);
const affectedByFog = painter.isTileAffectedByFog(coord);
const program = painter.getOrCreateProgram('fillExtrusionGroundEffect', {config: programConfiguration, defines, overrideFog: affectedByFog});
- const ao = [aoIntensity, aoRadius * meterToTile];
+ const ao: [number, number] = [aoIntensity, aoRadius * meterToTile];
const edgeRadiusTile = zoom >= 17 ? 0 : edgeRadius * meterToTile;
const fbSize = framebufferCopyTexture ? framebufferCopyTexture.size[0] : 0;
- // @ts-expect-error - TS2345 - Argument of type 'number[]' is not assignable to parameter of type '[number, number]'.
const uniformValues = fillExtrusionGroundEffectUniformValues(painter, matrix, opacity, aoPass, meterToTile, ao, floodLightIntensity, floodLightColor, attenuation, edgeRadiusTile, fbSize);
const dynamicBuffers = [];
@@ -641,18 +641,16 @@ function updateBorders(context: Context, source: SourceCache, coord: OverscaledT
if (!terrain) {
return 0;
}
- const points = [[verticalEdge ? edge : min, verticalEdge ? min : edge, 0], [verticalEdge ? edge : max, verticalEdge ? max : edge, 0]];
+ const points: vec3[] = [[verticalEdge ? edge : min, verticalEdge ? min : edge, 0], [verticalEdge ? edge : max, verticalEdge ? max : edge, 0]];
const coord3 = maxOffsetFromBorder < 0 ? EXTENT + maxOffsetFromBorder : maxOffsetFromBorder;
- const thirdPoint = [verticalEdge ? coord3 : (min + max) / 2, verticalEdge ? (min + max) / 2 : coord3, 0];
+ const thirdPoint: vec3 = [verticalEdge ? coord3 : (min + max) / 2, verticalEdge ? (min + max) / 2 : coord3, 0];
if ((edge === 0 && maxOffsetFromBorder < 0) || (edge !== 0 && maxOffsetFromBorder > 0)) {
// Third point is inside neighbor tile, not in the |coord| tile.
- // @ts-expect-error - TS2322 - Type 'number[]' is not assignable to type 'vec3'.
terrain.getForTilePoints(neighborTileID, [thirdPoint], true, neighborDEMTile);
} else {
points.push(thirdPoint);
}
- // @ts-expect-error - TS2345 - Argument of type 'number[][]' is not assignable to parameter of type 'vec3[]'.
terrain.getForTilePoints(coord, points, true, demTile);
return Math.max(points[0][2], points[1][2], thirdPoint[2]) / terrain.exaggeration();
};
@@ -805,9 +803,9 @@ function updateBorders(context: Context, source: SourceCache, coord: OverscaledT
}
}
-const XAxis = [1, 0, 0];
-const YAxis = [0, 1, 0];
-const ZAxis = [0, 0, 1];
+const XAxis: vec3 = [1, 0, 0];
+const YAxis: vec3 = [0, 1, 0];
+const ZAxis: vec3 = [0, 0, 1];
function frustumCullShadowCaster(id: OverscaledTileID, bucket: FillExtrusionBucket, painter: Painter): boolean {
const transform = painter.transform;
@@ -827,10 +825,9 @@ function frustumCullShadowCaster(id: OverscaledTileID, bucket: FillExtrusionBuck
height += minmax.max;
}
}
- const shadowDir = [...shadowRenderer.shadowDirection];
+ const shadowDir = [...shadowRenderer.shadowDirection] as vec3;
shadowDir[2] = -shadowDir[2];
- // @ts-expect-error - TS2345 - Argument of type 'number[]' is not assignable to parameter of type 'vec3'.
const tileShadowVolume = shadowRenderer.computeSimplifiedTileShadowVolume(unwrappedId, height, ws, shadowDir);
if (!tileShadowVolume) {
return false;
@@ -838,16 +835,14 @@ function frustumCullShadowCaster(id: OverscaledTileID, bucket: FillExtrusionBuck
// Projected shadow volume has 3-6 unique edge direction vectors.
// These are used for computing remaining separating axes for the intersection test
- const edges = [XAxis, YAxis, ZAxis, shadowDir, [shadowDir[0], 0, shadowDir[2]], [0, shadowDir[1], shadowDir[2]]];
+ const edges: vec3[] = [XAxis, YAxis, ZAxis, shadowDir, [shadowDir[0], 0, shadowDir[2]], [0, shadowDir[1], shadowDir[2]]];
const isGlobe = transform.projection.name === 'globe';
const zoom = transform.scaleZoom(ws);
const cameraFrustum = Frustum.fromInvProjectionMatrix(transform.invProjMatrix, transform.worldSize, zoom, !isGlobe);
const cascadeFrustum = shadowRenderer.getCurrentCascadeFrustum();
- // @ts-expect-error - TS2345 - Argument of type 'number[][]' is not assignable to parameter of type 'vec3[]'.
if (cameraFrustum.intersectsPrecise(tileShadowVolume.vertices, tileShadowVolume.planes, edges) === 0) {
return true;
}
- // @ts-expect-error - TS2345 - Argument of type 'number[][]' is not assignable to parameter of type 'vec3[]'.
if (cascadeFrustum.intersectsPrecise(tileShadowVolume.vertices, tileShadowVolume.planes, edges) === 0) {
return true;
}
diff --git a/src/render/draw_heatmap.ts b/src/render/draw_heatmap.ts
index c0ec0d69521..cf540266794 100644
--- a/src/render/draw_heatmap.ts
+++ b/src/render/draw_heatmap.ts
@@ -74,7 +74,7 @@ function drawHeatmap(painter: Painter, sourceCache: SourceCache, layer: HeatmapS
program.draw(painter, gl.TRIANGLES, DepthMode.disabled, stencilMode, colorMode, cullMode,
heatmapUniformValues(painter, coord,
- tile, invMatrix, mercatorCenter, zoom, layer.paint.get('heatmap-intensity')),
+ tile, invMatrix as Float32Array, mercatorCenter, zoom, layer.paint.get('heatmap-intensity')),
layer.id, bucket.layoutVertexBuffer, bucket.indexBuffer,
bucket.segments, layer.paint, painter.transform.zoom,
programConfiguration, isGlobeProjection ? [bucket.globeExtVertexBuffer] : null);
diff --git a/src/render/draw_line.ts b/src/render/draw_line.ts
index a977c7619b7..8ecd206c1c4 100644
--- a/src/render/draw_line.ts
+++ b/src/render/draw_line.ts
@@ -30,13 +30,19 @@ export default function drawLine(painter: Painter, sourceCache: SourceCache, lay
const emissiveStrength = layer.paint.get('line-emissive-strength');
const occlusionOpacity = layer.paint.get('line-occlusion-opacity');
+ const elevationReference = layer.layout.get('line-elevation-reference');
+ const elevationFromSea = elevationReference === 'sea';
const context = painter.context;
const gl = context.gl;
- const zOffset = layer.layout.get('line-z-offset');
+ const hasZOffset = !layer.isDraped();
+ // line-z-offset is not supported for globe projection
+ if (hasZOffset && painter.transform.projection.name === 'globe') return;
- const hasZOffset = !zOffset.isConstant() || !!zOffset.constantOr(0);
+ const crossSlope = layer.layout.get('line-cross-slope');
+ const hasCrossSlope = crossSlope !== undefined;
+ const crossSlopeHorizontal = crossSlope < 1.0;
const depthMode = hasZOffset ?
(new DepthMode(painter.depthOcclusion ? gl.GREATER : gl.LEQUAL, DepthMode.ReadOnly, painter.depthRangeFor3D)) :
@@ -89,12 +95,22 @@ export default function drawLine(painter: Painter, sourceCache: SourceCache, lay
}
if (hasZOffset) painter.forceTerrainMode = true;
if (!hasZOffset && occlusionOpacity !== 0 && painter.terrain && !isDraping) {
- warnOnce(`Occlusion opacity for layer ${layer.id} is supported on terrain only if the layer has non-zero line-z-offset.`);
+ warnOnce(`Occlusion opacity for layer ${layer.id} is supported on terrain only if the layer has line-z-offset enabled.`);
return;
}
// No need for tile clipping, a single pass only even for transparent lines.
const stencilMode3D = (useStencilMaskRenderPass && hasZOffset) ? painter.stencilModeFor3D() : StencilMode.disabled;
+ if (hasZOffset) {
+ definesValues.push("ELEVATED");
+ if (hasCrossSlope) {
+ definesValues.push(crossSlopeHorizontal ? "CROSS_SLOPE_HORIZONTAL" : "CROSS_SLOPE_VERTICAL");
+ }
+ if (elevationFromSea) {
+ definesValues.push('ELEVATION_REFERENCE_SEA');
+ }
+ }
+
for (const coord of coords) {
const tile = sourceCache.getTile(coord);
if (image && !tile.patternsLoaded()) continue;
@@ -105,7 +121,7 @@ export default function drawLine(painter: Painter, sourceCache: SourceCache, lay
const programConfiguration = bucket.programConfigurations.get(layer.id);
const affectedByFog = painter.isTileAffectedByFog(coord);
- const program = painter.getOrCreateProgram(programId, {config: programConfiguration, defines: hasZOffset ? [...definesValues, "ELEVATED"] : definesValues, overrideFog: affectedByFog});
+ const program = painter.getOrCreateProgram(programId, {config: programConfiguration, defines: definesValues, overrideFog: affectedByFog, overrideRtt: hasZOffset ? true : undefined});
if (constantPattern && tile.imageAtlas) {
const posTo = tile.imageAtlas.patternPositions[constantPattern.toString()];
@@ -190,7 +206,7 @@ export default function drawLine(painter: Painter, sourceCache: SourceCache, lay
programConfiguration.updatePaintBuffers();
}
- if (hasZOffset) {
+ if (hasZOffset && !elevationFromSea) {
assert(painter.terrain);
painter.terrain.setupElevationDraw(tile, program);
}
diff --git a/src/render/draw_raster.ts b/src/render/draw_raster.ts
index 085d6add950..ccad956d1f0 100644
--- a/src/render/draw_raster.ts
+++ b/src/render/draw_raster.ts
@@ -184,7 +184,7 @@ function drawRaster(painter: Painter, sourceCache: SourceCache, layer: RasterSty
const tr = painter.transform;
let perspectiveTransform: [number, number];
- const cutoffParams = renderingWithElevation ? cutoffParamsForElevation(tr) : [0, 0, 0, 0];
+ const cutoffParams: [number, number, number, number] = renderingWithElevation ? cutoffParamsForElevation(tr) : [0, 0, 0, 0];
let normalizeMatrix: Float32Array;
let globeMatrix: Float32Array;
@@ -227,7 +227,6 @@ function drawRaster(painter: Painter, sourceCache: SourceCache, layer: RasterSty
parentTL || [0, 0],
globeToMercatorTransition(painter.transform.zoom),
mercatorCenter,
- // @ts-expect-error - TS2345 - Argument of type 'number[]' is not assignable to parameter of type '[number, number, number, number]'.
cutoffParams,
parentScaleBy || 1,
fade,
@@ -473,7 +472,7 @@ function configureRaster(
let range = layer.paint.get('raster-color-range');
// Unpack the offset for use in a separate uniform
- const mix = [inputMix[0], inputMix[1], inputMix[2], 0];
+ const mix: [number, number, number, number] = [inputMix[0], inputMix[1], inputMix[2], 0];
const offset = inputMix[3];
let resampling = inputResampling === 'nearest' ? gl.NEAREST : gl.LINEAR;
@@ -519,9 +518,7 @@ function configureRaster(
}
return {
- // @ts-expect-error - TS2322 - Type 'any[]' is not assignable to type '[number, number, number, number]'.
mix,
-
range,
offset,
defines,
diff --git a/src/render/draw_raster_particle.ts b/src/render/draw_raster_particle.ts
index 13a62f2f274..dea2b770b7f 100644
--- a/src/render/draw_raster_particle.ts
+++ b/src/render/draw_raster_particle.ts
@@ -133,7 +133,7 @@ function renderParticlesToTexture(painter: Painter, sourceCache: SourceCache, la
if (!data) continue;
assert(data.texture);
- const textureSize = [tile.tileSize, tile.tileSize];
+ const textureSize: [number, number] = [tile.tileSize, tile.tileSize];
let tileFramebuffer = layer.tileFramebuffer;
if (!tileFramebuffer) {
const fbWidth = textureSize[0];
@@ -144,7 +144,6 @@ function renderParticlesToTexture(painter: Painter, sourceCache: SourceCache, la
let state = tile.rasterParticleState;
if (!state) {
- // @ts-expect-error - TS2345 - Argument of type 'number[]' is not assignable to parameter of type '[number, number]'.
state = tile.rasterParticleState = new RasterParticleState(context, id, textureSize, particlePositionRGBAImage);
}
@@ -230,7 +229,7 @@ function getTileData(
uint8: 'DATA_FORMAT_UINT8',
uint16: 'DATA_FORMAT_UINT16',
uint32: 'DATA_FORMAT_UINT32',
- }[format];
+ }[format] as DynamicDefinesType;
return {
texture,
@@ -239,7 +238,6 @@ function getTileData(
scalarData,
scale: mix,
offset,
- // @ts-expect-error - TS2322 - Type 'string' is not assignable to type 'DynamicDefinesType'.
defines: ['RASTER_ARRAY', dataFormatDefine]
};
}
@@ -339,11 +337,10 @@ function renderParticles(painter: Painter, sourceCache: SourceCache, layer: Rast
const rasterParticleTextureRes = state.particleTexture0.size;
assert(rasterParticleTextureRes[0] === rasterParticleTextureRes[1]);
const rasterParticleTextureSideLen = rasterParticleTextureRes[0];
- const tileOffset = [nx - x, ny - y];
+ const tileOffset: [number, number] = [nx - x, ny - y];
const uniforms = rasterParticleDrawUniformValues(
RASTER_PARTICLE_TEXTURE_UNIT,
rasterParticleTextureSideLen,
- // @ts-expect-error - TS2345 - Argument of type 'number[]' is not assignable to parameter of type '[number, number]'.
tileOffset,
VELOCITY_TEXTURE_UNIT,
targetTileData.texture.size,
@@ -503,7 +500,7 @@ function renderTextureToMap(painter: Painter, sourceCache: SourceCache, layer: R
}
const uniformValues = rasterParticleUniformValues(
- projMatrix,
+ projMatrix as Float32Array,
normalizeMatrix,
globeMatrix,
globeMercatorMatrix,
diff --git a/src/render/draw_sky.ts b/src/render/draw_sky.ts
index 9474e1262a9..c55c64ecda0 100644
--- a/src/render/draw_sky.ts
+++ b/src/render/draw_sky.ts
@@ -67,7 +67,7 @@ function drawSkyboxGradient(painter: Painter, layer: SkyLayer, depthMode: DepthM
}
colorRampTexture.bind(gl.LINEAR, gl.CLAMP_TO_EDGE);
const uniformValues = skyboxGradientUniformValues(
- transform.skyboxMatrix,
+ transform.skyboxMatrix as Float32Array,
layer.getCenter(painter, false),
layer.paint.get('sky-gradient-radius'),
@@ -94,7 +94,7 @@ function drawSkyboxFromCapture(painter: Painter, layer: SkyLayer, depthMode: Dep
gl.bindTexture(gl.TEXTURE_CUBE_MAP, layer.skyboxTexture);
- const uniformValues = skyboxUniformValues(transform.skyboxMatrix, layer.getCenter(painter, false), 0, opacity, temporalOffset);
+ const uniformValues = skyboxUniformValues(transform.skyboxMatrix as Float32Array, layer.getCenter(painter, false), 0, opacity, temporalOffset);
painter.uploadCommonUniforms(context, program);
@@ -114,8 +114,7 @@ function drawSkyboxFace(painter: Painter, layer: SkyLayer, program: Program
const sunIntensity = layer.paint.get('sky-atmosphere-sun-intensity');
const uniformValues = skyboxCaptureUniformValues(
- // @ts-expect-error - TS2345 - Argument of type 'mat3' is not assignable to parameter of type 'Float32Array'.
- mat3.fromMat4(mat3.create(), faceRotate),
+ mat3.fromMat4(mat3.create(), faceRotate) as Float32Array,
sunDirection,
sunIntensity,
atmosphereColor,
@@ -160,47 +159,30 @@ function captureSkybox(painter: Painter, layer: SkyLayer, width: number, height:
const sunDirection = layer.getCenter(painter, true);
const program = painter.getOrCreateProgram('skyboxCapture');
- const faceRotate = new Float64Array(16);
+ const faceRotate = new Float64Array(16) as unknown as mat4;
// +x;
- // @ts-expect-error - TS2345 - Argument of type 'Float64Array' is not assignable to parameter of type 'mat4'.
mat4.identity(faceRotate);
- // @ts-expect-error - TS2345 - Argument of type 'Float64Array' is not assignable to parameter of type 'mat4'.
mat4.rotateY(faceRotate, faceRotate, -Math.PI * 0.5);
- // @ts-expect-error - TS2345 - Argument of type 'Float64Array' is not assignable to parameter of type 'mat4'.
drawSkyboxFace(painter, layer, program, faceRotate, sunDirection, 0);
// -x
- // @ts-expect-error - TS2345 - Argument of type 'Float64Array' is not assignable to parameter of type 'mat4'.
mat4.identity(faceRotate);
- // @ts-expect-error - TS2345 - Argument of type 'Float64Array' is not assignable to parameter of type 'mat4'.
mat4.rotateY(faceRotate, faceRotate, Math.PI * 0.5);
- // @ts-expect-error - TS2345 - Argument of type 'Float64Array' is not assignable to parameter of type 'mat4'.
drawSkyboxFace(painter, layer, program, faceRotate, sunDirection, 1);
// +y
- // @ts-expect-error - TS2345 - Argument of type 'Float64Array' is not assignable to parameter of type 'mat4'.
mat4.identity(faceRotate);
- // @ts-expect-error - TS2345 - Argument of type 'Float64Array' is not assignable to parameter of type 'mat4'.
mat4.rotateX(faceRotate, faceRotate, -Math.PI * 0.5);
- // @ts-expect-error - TS2345 - Argument of type 'Float64Array' is not assignable to parameter of type 'mat4'.
drawSkyboxFace(painter, layer, program, faceRotate, sunDirection, 2);
// -y
- // @ts-expect-error - TS2345 - Argument of type 'Float64Array' is not assignable to parameter of type 'mat4'.
mat4.identity(faceRotate);
- // @ts-expect-error - TS2345 - Argument of type 'Float64Array' is not assignable to parameter of type 'mat4'.
mat4.rotateX(faceRotate, faceRotate, Math.PI * 0.5);
- // @ts-expect-error - TS2345 - Argument of type 'Float64Array' is not assignable to parameter of type 'mat4'.
drawSkyboxFace(painter, layer, program, faceRotate, sunDirection, 3);
// +z
- // @ts-expect-error - TS2345 - Argument of type 'Float64Array' is not assignable to parameter of type 'mat4'.
mat4.identity(faceRotate);
- // @ts-expect-error - TS2345 - Argument of type 'Float64Array' is not assignable to parameter of type 'mat4'.
drawSkyboxFace(painter, layer, program, faceRotate, sunDirection, 4);
// -z
- // @ts-expect-error - TS2345 - Argument of type 'Float64Array' is not assignable to parameter of type 'mat4'.
mat4.identity(faceRotate);
- // @ts-expect-error - TS2345 - Argument of type 'Float64Array' is not assignable to parameter of type 'mat4'.
mat4.rotateY(faceRotate, faceRotate, Math.PI);
- // @ts-expect-error - TS2345 - Argument of type 'Float64Array' is not assignable to parameter of type 'mat4'.
drawSkyboxFace(painter, layer, program, faceRotate, sunDirection, 5);
context.viewport.set([0, 0, painter.width, painter.height]);
diff --git a/src/render/draw_symbol.ts b/src/render/draw_symbol.ts
index 81fbed58522..65a3f13952e 100644
--- a/src/render/draw_symbol.ts
+++ b/src/render/draw_symbol.ts
@@ -4,6 +4,7 @@ import SegmentVector from '../data/segment';
import * as symbolProjection from '../symbol/projection';
import * as symbolSize from '../symbol/symbol_size';
import {mat4, vec3, vec4} from 'gl-matrix';
+import {clamp} from '../util/util';
const identityMat4 = mat4.create();
import StencilMode from '../gl/stencil_mode';
import DepthMode from '../gl/depth_mode';
@@ -53,7 +54,7 @@ type SymbolTileRenderState = {
isSDF: boolean;
hasHalo: boolean;
tile: Tile;
- labelPlaneMatrixInv: Float32Array | null | undefined;
+ labelPlaneMatrixInv: mat4 | null | undefined;
} | null;
};
@@ -66,6 +67,8 @@ function drawSymbols(painter: Painter, sourceCache: SourceCache, layer: SymbolSt
const stencilMode = StencilMode.disabled;
const colorMode = painter.colorModeForRenderPass();
const variablePlacement = layer.layout.get('text-variable-anchor');
+ const textSizeScaleRange = layer.layout.get('text-size-scale-range');
+ const textScaleFactor = clamp(painter.scaleFactor, textSizeScaleRange[0], textSizeScaleRange[1]);
//Compute variable-offsets before painting since icons and text data positioning
//depend on each other in this case.
@@ -74,7 +77,8 @@ function drawSymbols(painter: Painter, sourceCache: SourceCache, layer: SymbolSt
layer.layout.get('text-rotation-alignment'),
layer.layout.get('text-pitch-alignment'),
- variableOffsets
+ variableOffsets,
+ textScaleFactor
);
}
@@ -109,19 +113,17 @@ function drawSymbols(painter: Painter, sourceCache: SourceCache, layer: SymbolSt
function computeGlobeCameraUp(transform: Transform): [number, number, number] {
const viewMatrix = transform._camera.getWorldToCamera(transform.worldSize, 1);
- // @ts-expect-error - TS2345 - Argument of type 'Float64Array' is not assignable to parameter of type 'ReadonlyMat4'.
const viewToEcef = mat4.multiply([] as any, viewMatrix, transform.globeMatrix);
mat4.invert(viewToEcef, viewToEcef);
- const cameraUpVector = [0, 0, 0];
- const up = [0, 1, 0, 0];
- vec4.transformMat4(up as [number, number, number, number], up as [number, number, number, number], viewToEcef);
+ const cameraUpVector: vec3 = [0, 0, 0];
+ const up: vec4 = [0, 1, 0, 0];
+ vec4.transformMat4(up, up, viewToEcef);
cameraUpVector[0] = up[0];
cameraUpVector[1] = up[1];
cameraUpVector[2] = up[2];
- vec3.normalize(cameraUpVector as [number, number, number], cameraUpVector as [number, number, number]);
+ vec3.normalize(cameraUpVector, cameraUpVector);
- // @ts-expect-error - TS2322 - Type 'number[]' is not assignable to type '[number, number, number]'.
return cameraUpVector;
}
@@ -145,7 +147,7 @@ function calculateVariableRenderShift(
);
}
-function updateVariableAnchors(coords: Array, painter: Painter, layer: SymbolStyleLayer, sourceCache: SourceCache, rotationAlignment: Alignment, pitchAlignment: Alignment, variableOffsets: Partial>) {
+function updateVariableAnchors(coords: Array, painter: Painter, layer: SymbolStyleLayer, sourceCache: SourceCache, rotationAlignment: Alignment, pitchAlignment: Alignment, variableOffsets: Partial>, textScaleFactor: number) {
const tr = painter.transform;
const rotateWithMap = rotationAlignment === 'map';
const pitchWithMap = pitchAlignment === 'map';
@@ -158,7 +160,7 @@ function updateVariableAnchors(coords: Array, painter: Painter
}
const sizeData = bucket.textSizeData;
- const size = symbolSize.evaluateSizeForZoom(sizeData, tr.zoom);
+ const size = symbolSize.evaluateSizeForZoom(sizeData, tr.zoom, textScaleFactor);
const tileMatrix = getSymbolTileProjectionMatrix(coord, bucket.getProjection(), tr);
const pixelsToTileUnits = tr.calculatePixelsToTileUnitsMatrix(tile);
@@ -168,7 +170,7 @@ function updateVariableAnchors(coords: Array, painter: Painter
if (size) {
const tileScale = Math.pow(2, tr.zoom - tile.tileID.overscaledZ);
updateVariableAnchorsForBucket(bucket, rotateWithMap, pitchWithMap, variableOffsets, symbolSize,
- tr, labelPlaneMatrix, coord, tileScale, size, updateTextFitIcon);
+ tr, labelPlaneMatrix as Float32Array, coord, tileScale, size, updateTextFitIcon);
}
}
}
@@ -297,8 +299,6 @@ function drawLayerSymbols(
const iconBrightnessMax = layer.paint.get('icon-color-brightness-max');
const elevationFromSea = layer.paint.get('symbol-elevation-reference') === 'sea';
- const textOccludedOpacityMultiplier = layer.paint.get('text-occlusion-opacity').constantOr(0);
-
const context = painter.context;
const gl = context.gl;
const tr = painter.transform;
@@ -312,7 +312,7 @@ function drawLayerSymbols(
let sortFeaturesByKey = false;
const depthMode = painter.depthModeForSublayer(0, DepthMode.ReadOnly);
- const mercatorCenter = [
+ const mercatorCenter: [number, number] = [
mercatorXfromLng(tr.center.lng),
mercatorYfromLat(tr.center.lat)
];
@@ -320,7 +320,7 @@ function drawLayerSymbols(
const isGlobeProjection = tr.projection.name === 'globe';
const tileRenderState: Array = [];
- const mercatorCameraUp = [0, -1, 0];
+ const mercatorCameraUp: [number, number, number] = [0, -1, 0];
for (const coord of coords) {
const tile = sourceCache.getTile(coord);
@@ -405,7 +405,7 @@ function drawLayerSymbols(
const programConfiguration = bucket.icon.programConfigurations.get(layer.id);
const program = painter.getOrCreateProgram('symbol', {config: programConfiguration, defines: baseDefines});
- const texSize = tile.imageAtlasTexture ? tile.imageAtlasTexture.size : [0, 0];
+ const texSize: [number, number] = tile.imageAtlasTexture ? tile.imageAtlasTexture.size : [0, 0];
const sizeData = bucket.iconSizeData;
const size = symbolSize.evaluateSizeForZoom(sizeData, tr.zoom);
const transformed = iconPitchWithMap || tr.pitch !== 0;
@@ -420,8 +420,7 @@ function drawLayerSymbols(
const uLabelPlaneMatrix = projectedPosOnLabelSpace ? identityMat4 : labelPlaneMatrixRendering;
const rotateInShader = iconRotateWithMap && !iconPitchWithMap && !alongLine;
- // @ts-expect-error - TS2322 - Type 'number[]' is not assignable to type '[number, number, number]'.
- let globeCameraUp: [number, number, number] = mercatorCameraUp;
+ let globeCameraUp = mercatorCameraUp;
if ((isGlobeProjection || tr.mercatorFromTransition) && !iconRotateWithMap) {
// Each symbol rotating with the viewport requires per-instance information about
// how to align with the viewport. In 2D case rotation is shared between all of the symbols and
@@ -434,7 +433,6 @@ function drawLayerSymbols(
const colorAdjustmentMatrix = layer.getColorAdjustmentMatrix(iconSaturation, iconContrast, iconBrightnessMin, iconBrightnessMax);
const uniformValues = symbolUniformValues(sizeData.kind, size, rotateInShader, iconPitchWithMap, painter,
- // @ts-expect-error - TS2345 - Argument of type 'mat4' is not assignable to parameter of type 'Float32Array'.
matrix, uLabelPlaneMatrix, uglCoordMatrix, elevationFromSea, false, texSize, [0, 0], true, coord, globeToMercator, mercatorCenter, invMatrix, cameraUpVector, bucket.getProjection(), colorAdjustmentMatrix, transitionProgress);
const atlasTexture = tile.imageAtlasTexture ? tile.imageAtlasTexture : null;
@@ -515,8 +513,10 @@ function drawLayerSymbols(
atlasInterpolationIcon = transformed || painter.options.rotating || painter.options.zooming || zoomDependentSize ? gl.LINEAR : gl.NEAREST;
}
- const texSize = tile.glyphAtlasTexture ? tile.glyphAtlasTexture.size : [0, 0];
- const size = symbolSize.evaluateSizeForZoom(sizeData, tr.zoom);
+ const texSize: [number, number] = tile.glyphAtlasTexture ? tile.glyphAtlasTexture.size : [0, 0];
+ const textSizeScaleRange = layer.layout.get('text-size-scale-range');
+ const textScaleFactor = clamp(painter.scaleFactor, textSizeScaleRange[0], textSizeScaleRange[1]);
+ const size = symbolSize.evaluateSizeForZoom(sizeData, tr.zoom, textScaleFactor);
const labelPlaneMatrixRendering = symbolProjection.getLabelPlaneMatrixForRendering(tileMatrix, tile.tileID.canonical, textPitchWithMap, textRotateWithMap, tr, bucket.getProjection(), s);
// labelPlaneMatrixInv is used for converting vertex pos to tile coordinates needed for sampling elevation.
const glCoordMatrix = symbolProjection.getGlCoordMatrix(tileMatrix, tile.tileID.canonical, textPitchWithMap, textRotateWithMap, tr, bucket.getProjection(), s);
@@ -531,8 +531,7 @@ function drawLayerSymbols(
// Unpitched point labels need to have their rotation applied after projection
const rotateInShader = textRotateWithMap && !textPitchWithMap && !alongLine;
- // @ts-expect-error - TS2322 - Type 'number[]' is not assignable to type '[number, number, number]'.
- let globeCameraUp: [number, number, number] = mercatorCameraUp;
+ let globeCameraUp = mercatorCameraUp;
if ((isGlobeProjection || tr.mercatorFromTransition) && !textRotateWithMap) {
// Each symbol rotating with the viewport requires per-instance information about
// how to align with the viewport. In 2D case rotation is shared between all of the symbols and
@@ -544,8 +543,7 @@ function drawLayerSymbols(
const cameraUpVector = bucketIsGlobeProjection ? globeCameraUp : mercatorCameraUp;
const uniformValues = symbolUniformValues(sizeData.kind, size, rotateInShader, textPitchWithMap, painter,
- // @ts-expect-error - TS2345 - Argument of type 'mat4' is not assignable to parameter of type 'Float32Array'.
- matrix, uLabelPlaneMatrix, uglCoordMatrix, elevationFromSea, true, texSize, texSizeIcon, true, coord, globeToMercator, mercatorCenter, invMatrix, cameraUpVector, bucket.getProjection(), textOccludedOpacityMultiplier);
+ matrix, uLabelPlaneMatrix, uglCoordMatrix, elevationFromSea, true, texSize, texSizeIcon, true, coord, globeToMercator, mercatorCenter, invMatrix, cameraUpVector, bucket.getProjection(), null, null, textScaleFactor);
const atlasTexture = tile.glyphAtlasTexture ? tile.glyphAtlasTexture : null;
const atlasInterpolation = gl.LINEAR;
@@ -594,7 +592,6 @@ function drawLayerSymbols(
tileRenderState.push({
segments: new SegmentVector([segment]),
sortKey: (segment.sortKey),
- // @ts-expect-error - TS2322 - Type '{ program: Program; buffers: SymbolBuffers; uniformValues: any; atlasTexture: Texture; atlasTextureIcon: any; atlasInterpolation: 9728 | 9729; ... 4 more ...; labelPlaneMatrixInv: mat4; }' is not assignable to type '{ program: any; buffers: SymbolBuffers; uniformValues: any; atlasTexture: Texture; atlasTextureIcon: Texture; atlasInterpolation: any; atlasInterpolationIcon: any; isSDF: boolean; hasHalo: boolean; tile: Tile; labelPlaneMatrixInv: Float32Array; }'.
state: iconState
});
}
@@ -603,7 +600,6 @@ function drawLayerSymbols(
tileRenderState.push({
segments: new SegmentVector([segment]),
sortKey: (segment.sortKey),
- // @ts-expect-error - TS2322 - Type '{ program: Program; buffers: SymbolBuffers; uniformValues: any; atlasTexture: Texture; atlasTextureIcon: Texture; atlasInterpolation: 9729; ... 4 more ...; labelPlaneMatrixInv: mat4; }' is not assignable to type '{ program: any; buffers: SymbolBuffers; uniformValues: any; atlasTexture: Texture; atlasTextureIcon: Texture; atlasInterpolation: any; atlasInterpolationIcon: any; isSDF: boolean; hasHalo: boolean; tile: Tile; labelPlaneMatrixInv: Float32Array; }'.
state: textState
});
}
@@ -612,7 +608,6 @@ function drawLayerSymbols(
tileRenderState.push({
segments: iconOpacity ? bucket.icon.segments : new SegmentVector([]),
sortKey: 0,
- // @ts-expect-error - TS2322 - Type '{ program: Program; buffers: SymbolBuffers; uniformValues: any; atlasTexture: Texture; atlasTextureIcon: any; atlasInterpolation: 9728 | 9729; ... 4 more ...; labelPlaneMatrixInv: mat4; }' is not assignable to type '{ program: any; buffers: SymbolBuffers; uniformValues: any; atlasTexture: Texture; atlasTextureIcon: Texture; atlasInterpolation: any; atlasInterpolationIcon: any; isSDF: boolean; hasHalo: boolean; tile: Tile; labelPlaneMatrixInv: Float32Array; }'.
state: iconState
});
}
@@ -621,7 +616,6 @@ function drawLayerSymbols(
tileRenderState.push({
segments: textOpacity ? bucket.text.segments : new SegmentVector([]),
sortKey: 0,
- // @ts-expect-error - TS2322 - Type '{ program: Program; buffers: SymbolBuffers; uniformValues: any; atlasTexture: Texture; atlasTextureIcon: Texture; atlasInterpolation: 9729; ... 4 more ...; labelPlaneMatrixInv: mat4; }' is not assignable to type '{ program: any; buffers: SymbolBuffers; uniformValues: any; atlasTexture: Texture; atlasTextureIcon: Texture; atlasInterpolation: any; atlasInterpolationIcon: any; isSDF: boolean; hasHalo: boolean; tile: Tile; labelPlaneMatrixInv: Float32Array; }'.
state: textState
});
}
diff --git a/src/render/fog.ts b/src/render/fog.ts
index 6951269f413..5a9e63d153a 100644
--- a/src/render/fog.ts
+++ b/src/render/fog.ts
@@ -65,7 +65,7 @@ export const fogUniformValues = (
const [verticalRangeMin, verticalRangeMax] = fog.properties.get('vertical-range');
return {
- 'u_fog_matrix': tileID ? tr.calculateFogTileMatrix(tileID) : fogMatrix ? fogMatrix : painter.identityMat,
+ 'u_fog_matrix': (tileID ? tr.calculateFogTileMatrix(tileID) : fogMatrix ? fogMatrix : painter.identityMat) as Float32Array,
'u_fog_range': fog.getFovAdjustedRange(tr._fov),
'u_fog_color': fogColor,
'u_fog_horizon_blend': fog.properties.get('horizon-blend'),
diff --git a/src/render/glyph_manager.ts b/src/render/glyph_manager.ts
index 7ea098c244d..2db730e5de8 100644
--- a/src/render/glyph_manager.ts
+++ b/src/render/glyph_manager.ts
@@ -2,7 +2,7 @@ import loadGlyphRange from '../style/load_glyph_range';
import TinySDF from '@mapbox/tiny-sdf';
import isChar from '../util/is_char_in_unicode_block';
import config from '../util/config';
-import {asyncAll} from '../util/util';
+import {asyncAll, warnOnce} from '../util/util';
import {AlphaImage} from '../util/image';
import type {Class} from '../types/class';
@@ -163,7 +163,8 @@ class GlyphManager {
const range = Math.floor(id / 256);
if (range * 256 > 65535) {
- fnCallback(new Error('glyphs > 65535 not supported'));
+ warnOnce('glyphs > 65535 not supported');
+ fnCallback(null, {stack, id, glyph});
return;
}
@@ -255,7 +256,8 @@ class GlyphManager {
isChar['Katakana'](id) ||
// gl-native parity: Extend Ideographs rasterization range to include CJK symbols and punctuations
isChar['CJK Symbols and Punctuation'](id) ||
- isChar['CJK Unified Ideographs Extension A'](id) || isChar['CJK Unified Ideographs Extension B'](id)) // very rare surrogate characters
+ isChar['CJK Unified Ideographs Extension A'](id) || isChar['CJK Unified Ideographs Extension B'](id)) || // very rare surrogate characters
+ isChar['Osage'](id)
);
/* eslint-enable new-cap */
}
diff --git a/src/render/painter.ts b/src/render/painter.ts
index 82b5bdef4a9..ff903cc6205 100644
--- a/src/render/painter.ts
+++ b/src/render/painter.ts
@@ -49,6 +49,8 @@ import {WireframeDebugCache} from './wireframe_cache';
import {FOG_OPACITY_THRESHOLD} from '../style/fog_helpers';
import Framebuffer from '../gl/framebuffer';
import {OcclusionParams} from './occlusion_params';
+import {Rain} from '../precipitation/draw_rain';
+import {Snow} from '../precipitation/draw_snow';
// 3D-style related
import type {Source} from '../source/source';
@@ -195,7 +197,7 @@ class Painter {
gpuTimers: GPUTimers;
deferredRenderGpuTimeQueries: Array;
emptyTexture: Texture;
- identityMat: Float32Array;
+ identityMat: mat4;
debugOverlayTexture: Texture;
debugOverlayCanvas: HTMLCanvasElement;
_terrain: Terrain | null | undefined;
@@ -208,6 +210,8 @@ class Painter {
[key: number]: Tile;
};
_atmosphere: Atmosphere | null | undefined;
+ _rain: any;
+ _snow: any;
replacementSource: ReplacementSource;
conflationActive: boolean;
firstLightBeamLayer: number;
@@ -230,6 +234,7 @@ class Painter {
tp: ITrackedParameters;
_debugParams: {
+ forceEnablePrecipitation: boolean;
showTerrainProxyTiles: boolean;
fpsWindow: number;
continousRedraw: boolean;
@@ -253,7 +258,9 @@ class Painter {
_clippingActiveLastFrame: boolean;
- constructor(gl: WebGL2RenderingContext, contextCreateOptions: ContextOptions, transform: Transform, tp: ITrackedParameters) {
+ scaleFactor: number;
+
+ constructor(gl: WebGL2RenderingContext, contextCreateOptions: ContextOptions, transform: Transform, scaleFactor: number, tp: ITrackedParameters) {
this.context = new Context(gl, contextCreateOptions);
this.transform = transform;
@@ -268,6 +275,7 @@ class Painter {
this._dt = 0;
this._debugParams = {
+ forceEnablePrecipitation: false,
showTerrainProxyTiles: false,
fpsWindow: 30,
continousRedraw:false,
@@ -285,6 +293,8 @@ class Painter {
this.style.map.triggerRepaint();
});
+ tp.registerParameter(this._debugParams, ["Precipitation"], "forceEnablePrecipitation");
+
tp.registerParameter(this._debugParams, ["FPS"], "fpsWindow", {min: 1, max: 100, step: 1});
tp.registerBinding(this._debugParams, ["FPS"], 'continousRedraw', {
readonly:true,
@@ -337,6 +347,8 @@ class Painter {
this.emptyDepthTexture = new Texture(this.context, emptyDepth, gl.RGBA8);
this._clippingActiveLastFrame = false;
+
+ this.scaleFactor = scaleFactor;
}
updateTerrain(style: Style, adaptCameraAltitude: boolean) {
@@ -470,7 +482,6 @@ class Painter {
this.emptyTexture = new Texture(context,
new RGBAImage({width: 1, height: 1}, Uint8Array.of(0, 0, 0, 0)), context.gl.RGBA8);
- // @ts-expect-error - TS2322 - Type 'mat4' is not assignable to type 'Float32Array'.
this.identityMat = mat4.create();
const gl = this.context.gl;
@@ -1004,6 +1015,25 @@ class Painter {
}
}
+ Debug.run(() => {
+ if (this._debugParams.forceEnablePrecipitation) {
+ if (!this._snow) {
+ this._snow = new Snow(this);
+ }
+
+ if (!this._rain) {
+ this._rain = new Rain(this);
+ }
+ }
+
+ if (this._debugParams.forceEnablePrecipitation && this._snow) {
+ this._snow.update(this);
+ }
+ if (this._debugParams.forceEnablePrecipitation && this._rain) {
+ this._rain.update(this);
+ }
+ });
+
// Following line is billing related code. Do not change. See LICENSE.txt
if (!isMapAuthenticated(this.context.gl)) return;
@@ -1263,6 +1293,15 @@ class Painter {
this.terrain.postRender();
}
+ Debug.run(() => {
+ if (this._debugParams.forceEnablePrecipitation && this._snow) {
+ this._snow.draw(this);
+ }
+
+ if (this._debugParams.forceEnablePrecipitation && this._rain) {
+ this._rain.draw(this);
+ }
+ });
if (this.options.showTileBoundaries || this.options.showQueryGeometry || this.options.showTileAABBs) {
// Use source with highest maxzoom
let selectedSource = null;
@@ -1416,13 +1455,12 @@ class Painter {
queryGpuTimeDeferredRender(gpuQueries: Array): number {
if (!this.options.gpuTimingDeferredRender) return 0;
- const ext = this.context.extTimerQuery;
const gl = this.context.gl;
let gpuTime = 0;
for (const query of gpuQueries) {
- gpuTime += ext.getQueryParameter(query, gl.QUERY_RESULT) / (1000 * 1000);
- ext.deleteQueryEXT(query);
+ gpuTime += gl.getQueryParameter(query, gl.QUERY_RESULT) / (1000 * 1000);
+ gl.deleteQuery(query);
}
return gpuTime;
@@ -1435,12 +1473,12 @@ class Painter {
* @private
*/
translatePosMatrix(
- matrix: Float32Array,
+ matrix: mat4,
tile: Tile,
translate: [number, number],
translateAnchor: 'map' | 'viewport',
inViewportPixelUnitsUnits?: boolean,
- ): Float32Array {
+ ): mat4 {
if (!translate[0] && !translate[1]) return matrix;
const angle = inViewportPixelUnitsUnits ?
@@ -1505,9 +1543,9 @@ class Painter {
* @returns {string[]}
* @private
*/
- currentGlobalDefines(name: string, overrideFog?: boolean | null, overrideRtt?: boolean | null): string[] {
+ currentGlobalDefines(name: string, overrideFog?: boolean | null, overrideRtt?: boolean | null): DynamicDefinesType[] {
const rtt = (overrideRtt === undefined) ? this.terrain && this.terrain.renderingToTexture : overrideRtt;
- const defines = [];
+ const defines: DynamicDefinesType[] = [];
if (this.style && this.style.enable3dLights()) {
// In case of terrain and map optimized for terrain mode flag
@@ -1547,7 +1585,7 @@ class Painter {
getOrCreateProgram(name: string, options?: CreateProgramParams): Program {
this.cache = this.cache || {};
- const defines = (((options && options.defines) || []) as string[]);
+ const defines = ((options && options.defines) || []);
const config = options && options.config;
const overrideFog = options && options.overrideFog;
const overrideRtt = options && options.overrideRtt;
diff --git a/src/render/program.ts b/src/render/program.ts
index 264b7e8316b..f3ce5fc78ec 100644
--- a/src/render/program.ts
+++ b/src/render/program.ts
@@ -32,6 +32,7 @@ import type {UniformBindings, UniformValues} from './uniform_binding';
import type {BinderUniform} from '../data/program_configuration';
import type Painter from './painter';
import type {Segment} from "../data/segment";
+import type {DynamicDefinesType} from '../render/program/program_uniforms';
export type DrawMode = WebGL2RenderingContext['POINTS'] | WebGL2RenderingContext['LINES'] | WebGL2RenderingContext['TRIANGLES'] | WebGL2RenderingContext['LINE_STRIP'];
@@ -39,7 +40,7 @@ type ShaderSource = {
fragmentSource: string;
vertexSource: string;
staticAttributes: Array;
- usedDefines: Array;
+ usedDefines: Array;
vertexIncludes: Array;
fragmentIncludes: Array;
};
@@ -53,6 +54,8 @@ const debugWireframe2DLayerProgramNames = [
const debugWireframe3DLayerProgramNames = [
"stars",
+ "rain_particle",
+ "snow_particle",
"fillExtrusion", "fillExtrusionGroundEffect",
"model",
"symbol"];
@@ -75,12 +78,12 @@ class Program {
name: string;
configuration: ProgramConfiguration | null | undefined;
- fixedDefines: string[];
+ fixedDefines: DynamicDefinesType[];
static cacheKey(
source: ShaderSource,
name: string,
- defines: string[],
+ defines: DynamicDefinesType[],
programConfiguration?: ProgramConfiguration | null,
): string {
let key = `${name}${programConfiguration ? programConfiguration.cacheKey : ''}`;
@@ -97,7 +100,7 @@ class Program {
source: ShaderSource,
configuration: ProgramConfiguration | null | undefined,
fixedUniforms: (arg1: Context) => Us,
- fixedDefines: string[]) {
+ fixedDefines: DynamicDefinesType[]) {
const gl = context.gl;
this.program = (gl.createProgram());
@@ -319,9 +322,8 @@ class Program {
return;
}
- const debugDefines = [...this.fixedDefines];
- debugDefines.push("DEBUG_WIREFRAME");
- // @ts-expect-error - TS2322 - Type 'string[]' is not assignable to type 'DynamicDefinesType[]'.
+ const debugDefines = [...this.fixedDefines] as DynamicDefinesType[];
+ debugDefines.push('DEBUG_WIREFRAME');
const debugProgram = painter.getOrCreateProgram(this.name, {config: this.configuration, defines: debugDefines});
context.program.set(debugProgram.program);
diff --git a/src/render/program/background_program.ts b/src/render/program/background_program.ts
index dfd18af628b..1559add8ea9 100644
--- a/src/render/program/background_program.ts
+++ b/src/render/program/background_program.ts
@@ -8,6 +8,7 @@ import {
} from '../uniform_binding';
import {extend} from '../../util/util';
+import type {mat4} from 'gl-matrix';
import type Painter from '../painter';
import type {UniformValues} from '../uniform_binding';
import type Context from '../../gl/context';
@@ -60,19 +61,19 @@ const backgroundPatternUniforms = (context: Context): BackgroundPatternUniformsT
});
const backgroundUniformValues = (
- matrix: Float32Array,
+ matrix: mat4,
emissiveStrength: number,
opacity: number,
color: RenderColor,
): UniformValues => ({
- 'u_matrix': matrix,
+ 'u_matrix': matrix as Float32Array,
'u_emissive_strength': emissiveStrength,
'u_opacity': opacity,
'u_color': color
});
const backgroundPatternUniformValues = (
- matrix: Float32Array,
+ matrix: mat4,
emissiveStrength: number,
opacity: number,
painter: Painter,
@@ -87,7 +88,7 @@ const backgroundPatternUniformValues = (
): UniformValues => extend(
bgPatternUniformValues(image, scope, patternPosition, painter, isViewport, tile),
{
- 'u_matrix': matrix,
+ 'u_matrix': matrix as Float32Array,
'u_emissive_strength': emissiveStrength,
'u_opacity': opacity
}
diff --git a/src/render/program/circle_program.ts b/src/render/program/circle_program.ts
index be490a85acb..535d0898059 100644
--- a/src/render/program/circle_program.ts
+++ b/src/render/program/circle_program.ts
@@ -40,13 +40,13 @@ const circleUniforms = (context: Context): CircleUniformsType => ({
'u_emissive_strength': new Uniform1f(context),
});
-const identityMatrix = mat4.create() as Float32Array;
+const identityMatrix = mat4.create();
const circleUniformValues = (
painter: Painter,
coord: OverscaledTileID,
tile: Tile,
- invMatrix: Float32Array,
+ invMatrix: mat4,
mercatorCenter: [number, number],
layer: CircleStyleLayer,
): UniformValues => {
@@ -75,10 +75,10 @@ const circleUniformValues = (
coord.projMatrix,
tile,
layer.paint.get('circle-translate'),
- layer.paint.get('circle-translate-anchor')),
+ layer.paint.get('circle-translate-anchor')) as Float32Array,
'u_device_pixel_ratio': browser.devicePixelRatio,
'u_extrude_scale': extrudeScale,
- 'u_inv_rot_matrix': identityMatrix,
+ 'u_inv_rot_matrix': identityMatrix as Float32Array,
'u_merc_center': [0, 0] as [number, number],
'u_tile_id': [0, 0, 0] as [number, number, number],
'u_zoom_transition': 0,
@@ -87,7 +87,7 @@ const circleUniformValues = (
};
if (isGlobe) {
- values['u_inv_rot_matrix'] = invMatrix;
+ values['u_inv_rot_matrix'] = invMatrix as Float32Array;
values['u_merc_center'] = mercatorCenter;
values['u_tile_id'] = [coord.canonical.x, coord.canonical.y, 1 << coord.canonical.z];
values['u_zoom_transition'] = globeToMercatorTransition(transform.zoom);
diff --git a/src/render/program/clipping_mask_program.ts b/src/render/program/clipping_mask_program.ts
index 2e47ec04ef0..4e4e21d05c7 100644
--- a/src/render/program/clipping_mask_program.ts
+++ b/src/render/program/clipping_mask_program.ts
@@ -1,5 +1,6 @@
import {UniformMatrix4f} from '../uniform_binding';
+import type {mat4} from 'gl-matrix';
import type Context from '../../gl/context';
import type {UniformValues} from '../uniform_binding';
@@ -11,8 +12,8 @@ const clippingMaskUniforms = (context: Context): ClippingMaskUniformsType => ({
'u_matrix': new UniformMatrix4f(context)
});
-const clippingMaskUniformValues = (matrix: Float32Array): UniformValues => ({
- 'u_matrix': matrix
+const clippingMaskUniformValues = (matrix: mat4): UniformValues => ({
+ 'u_matrix': matrix as Float32Array
});
export {clippingMaskUniforms, clippingMaskUniformValues};
diff --git a/src/render/program/collision_program.ts b/src/render/program/collision_program.ts
index 1e5aaf691e2..eb9780d37e9 100644
--- a/src/render/program/collision_program.ts
+++ b/src/render/program/collision_program.ts
@@ -1,6 +1,7 @@
import {Uniform1f, Uniform2f, UniformMatrix4f} from '../uniform_binding';
import EXTENT from '../../style-spec/data/extent';
+import type {mat4} from 'gl-matrix';
import type Context from '../../gl/context';
import type {UniformValues} from '../uniform_binding';
import type Transform from '../../geo/transform';
@@ -34,7 +35,7 @@ const collisionCircleUniforms = (context: Context): CollisionCircleUniformsType
});
const collisionUniformValues = (
- matrix: Float32Array,
+ matrix: mat4,
transform: Transform,
tile: Tile,
projection: Projection,
@@ -42,7 +43,7 @@ const collisionUniformValues = (
const pixelRatio = EXTENT / tile.tileSize;
return {
- 'u_matrix': matrix,
+ 'u_matrix': matrix as Float32Array,
'u_camera_to_center_distance': transform.getCameraToCenterDistance(projection),
'u_extrude_scale': [transform.pixelsToGLUnits[0] / pixelRatio,
transform.pixelsToGLUnits[1] / pixelRatio]
@@ -50,14 +51,14 @@ const collisionUniformValues = (
};
const collisionCircleUniformValues = (
- matrix: Float32Array,
- invMatrix: Float32Array,
+ matrix: mat4,
+ invMatrix: mat4,
transform: Transform,
projection: Projection,
): UniformValues => {
return {
- 'u_matrix': matrix,
- 'u_inv_matrix': invMatrix,
+ 'u_matrix': matrix as Float32Array,
+ 'u_inv_matrix': invMatrix as Float32Array,
'u_camera_to_center_distance': transform.getCameraToCenterDistance(projection),
'u_viewport_size': [transform.width, transform.height]
};
diff --git a/src/render/program/debug_program.ts b/src/render/program/debug_program.ts
index e3c3065e826..92df1b1af4c 100644
--- a/src/render/program/debug_program.ts
+++ b/src/render/program/debug_program.ts
@@ -1,5 +1,6 @@
import {UniformColor, UniformMatrix4f, Uniform1i, Uniform1f} from '../uniform_binding';
+import type {mat4} from 'gl-matrix';
import type Context from '../../gl/context';
import type {UniformValues} from '../uniform_binding';
import type Color from '../../style-spec/util/color';
@@ -18,8 +19,8 @@ const debugUniforms = (context: Context): DebugUniformsType => ({
'u_overlay_scale': new Uniform1f(context),
});
-const debugUniformValues = (matrix: Float32Array, color: Color, scaleRatio: number = 1): UniformValues => ({
- 'u_matrix': matrix,
+const debugUniformValues = (matrix: mat4, color: Color, scaleRatio: number = 1): UniformValues => ({
+ 'u_matrix': matrix as Float32Array,
'u_color': color.toRenderColor(null),
'u_overlay': 0,
'u_overlay_scale': scaleRatio
diff --git a/src/render/program/fill_extrusion_program.ts b/src/render/program/fill_extrusion_program.ts
index c908f5d8f59..a79890fb29c 100644
--- a/src/render/program/fill_extrusion_program.ts
+++ b/src/render/program/fill_extrusion_program.ts
@@ -17,6 +17,11 @@ import type {UniformValues} from '../uniform_binding';
import type Tile from '../../source/tile';
import type {OverscaledTileID} from '../../source/tile_id';
+const fillExtrusionAlignmentType = {
+ 'terrain': 0,
+ 'flat': 1,
+};
+
export type FillExtrusionUniformsType = {
['u_matrix']: UniformMatrix4f;
['u_lightpos']: Uniform3f;
@@ -24,6 +29,8 @@ export type FillExtrusionUniformsType = {
['u_lightcolor']: Uniform3f;
['u_vertical_gradient']: Uniform1f;
['u_opacity']: Uniform1f;
+ ['u_height_type']: Uniform1i;
+ ['u_base_type']: Uniform1i;
// globe uniforms:
['u_tile_id']: Uniform3f;
['u_zoom_transition']: Uniform1f;
@@ -45,6 +52,8 @@ export type FillExtrusionDepthUniformsType = {
['u_edge_radius']: Uniform1f;
['u_width_scale']: Uniform1f;
['u_vertical_scale']: Uniform1f;
+ ['u_height_type']: Uniform1i;
+ ['u_base_type']: Uniform1i;
};
export type FillExtrusionPatternUniformsType = {
@@ -57,6 +66,8 @@ export type FillExtrusionPatternUniformsType = {
['u_ao']: Uniform2f;
['u_edge_radius']: Uniform1f;
['u_width_scale']: Uniform1f;
+ ['u_height_type']: Uniform1i;
+ ['u_base_type']: Uniform1i;
// globe uniforms:
['u_tile_id']: Uniform3f;
['u_zoom_transition']: Uniform1f;
@@ -97,6 +108,8 @@ const fillExtrusionUniforms = (context: Context): FillExtrusionUniformsType => (
'u_edge_radius': new Uniform1f(context),
'u_width_scale': new Uniform1f(context),
'u_ao': new Uniform2f(context),
+ 'u_height_type': new Uniform1i(context),
+ 'u_base_type': new Uniform1i(context),
// globe uniforms:
'u_tile_id': new Uniform3f(context),
'u_zoom_transition': new Uniform1f(context),
@@ -107,14 +120,16 @@ const fillExtrusionUniforms = (context: Context): FillExtrusionUniformsType => (
'u_flood_light_color': new Uniform3f(context),
'u_vertical_scale': new Uniform1f(context),
'u_flood_light_intensity': new Uniform1f(context),
- 'u_ground_shadow_factor': new Uniform3f(context)
+ 'u_ground_shadow_factor': new Uniform3f(context),
});
const fillExtrusionDepthUniforms = (context: Context): FillExtrusionDepthUniformsType => ({
'u_matrix': new UniformMatrix4f(context),
'u_edge_radius': new Uniform1f(context),
'u_width_scale': new Uniform1f(context),
- 'u_vertical_scale': new Uniform1f(context)
+ 'u_vertical_scale': new Uniform1f(context),
+ 'u_height_type': new Uniform1i(context),
+ 'u_base_type': new Uniform1i(context),
});
const fillExtrusionPatternUniforms = (context: Context): FillExtrusionPatternUniformsType => ({
@@ -127,6 +142,8 @@ const fillExtrusionPatternUniforms = (context: Context): FillExtrusionPatternUni
'u_edge_radius': new Uniform1f(context),
'u_width_scale': new Uniform1f(context),
'u_ao': new Uniform2f(context),
+ 'u_height_type': new Uniform1i(context),
+ 'u_base_type': new Uniform1i(context),
// globe uniforms:
'u_tile_id': new Uniform3f(context),
'u_zoom_transition': new Uniform1f(context),
@@ -140,7 +157,7 @@ const fillExtrusionPatternUniforms = (context: Context): FillExtrusionPatternUni
'u_pixel_coord_upper': new Uniform2f(context),
'u_pixel_coord_lower': new Uniform2f(context),
'u_tile_units_to_pixels': new Uniform1f(context),
- 'u_opacity': new Uniform1f(context)
+ 'u_opacity': new Uniform1f(context),
});
const fillExtrusionGroundEffectUniforms = (context: Context): FillExtrusionGroundEffectUniformsType => ({
@@ -158,10 +175,10 @@ const fillExtrusionGroundEffectUniforms = (context: Context): FillExtrusionGroun
'u_dynamic_offset': new Uniform1f(context)
});
-const identityMatrix = mat4.create() as Float32Array;
+const identityMatrix = mat4.create();
const fillExtrusionUniformValues = (
- matrix: Float32Array,
+ matrix: mat4,
painter: Painter,
shouldUseVerticalGradient: boolean,
opacity: number,
@@ -170,9 +187,11 @@ const fillExtrusionUniformValues = (
lineWidthScale: number,
coord: OverscaledTileID,
heightLift: number,
+ heightAlignment: string,
+ baseAlignment: string,
zoomTransition: number,
mercatorCenter: [number, number],
- invMatrix: Float32Array,
+ invMatrix: mat4,
floodLightColor: [number, number, number],
verticalScale: number,
floodLightIntensity: number,
@@ -192,7 +211,7 @@ const fillExtrusionUniformValues = (
const tr = painter.transform;
const uniformValues = {
- 'u_matrix': matrix,
+ 'u_matrix': matrix as Float32Array,
'u_lightpos': lightPos,
'u_lightintensity': light.properties.get('intensity'),
@@ -201,23 +220,25 @@ const fillExtrusionUniformValues = (
'u_opacity': opacity,
'u_tile_id': [0, 0, 0] as [number, number, number],
'u_zoom_transition': 0,
- 'u_inv_rot_matrix': identityMatrix,
+ 'u_inv_rot_matrix': identityMatrix as Float32Array,
'u_merc_center': [0, 0] as [number, number],
'u_up_dir': [0, 0, 0] as [number, number, number],
'u_height_lift': 0,
+ 'u_height_type': fillExtrusionAlignmentType[heightAlignment],
+ 'u_base_type': fillExtrusionAlignmentType[baseAlignment],
'u_ao': aoIntensityRadius,
'u_edge_radius': edgeRadius,
'u_width_scale': lineWidthScale,
'u_flood_light_color': floodLightColor,
'u_vertical_scale': verticalScale,
'u_flood_light_intensity': floodLightIntensity,
- 'u_ground_shadow_factor': groundShadowFactor
+ 'u_ground_shadow_factor': groundShadowFactor,
};
if (tr.projection.name === 'globe') {
uniformValues['u_tile_id'] = [coord.canonical.x, coord.canonical.y, 1 << coord.canonical.z];
uniformValues['u_zoom_transition'] = zoomTransition;
- uniformValues['u_inv_rot_matrix'] = invMatrix;
+ uniformValues['u_inv_rot_matrix'] = invMatrix as Float32Array;
uniformValues['u_merc_center'] = mercatorCenter;
uniformValues['u_up_dir'] = (tr.projection.upVector(new CanonicalTileID(0, 0, 0), mercatorCenter[0] * EXTENT, mercatorCenter[1] * EXTENT) as any);
uniformValues['u_height_lift'] = heightLift;
@@ -226,17 +247,19 @@ const fillExtrusionUniformValues = (
return uniformValues;
};
-const fillExtrusionDepthUniformValues = (matrix: Float32Array, edgeRadius: number, lineWidthScale: number, verticalScale: number): UniformValues => {
+const fillExtrusionDepthUniformValues = (matrix: mat4, edgeRadius: number, lineWidthScale: number, verticalScale: number, heightAlignment: string, baseAlignment: string): UniformValues => {
return {
- 'u_matrix': matrix,
+ 'u_matrix': matrix as Float32Array,
'u_edge_radius': edgeRadius,
'u_width_scale': lineWidthScale,
- 'u_vertical_scale': verticalScale
+ 'u_vertical_scale': verticalScale,
+ 'u_height_type': fillExtrusionAlignmentType[heightAlignment],
+ 'u_base_type': fillExtrusionAlignmentType[baseAlignment],
};
};
const fillExtrusionPatternUniformValues = (
- matrix: Float32Array,
+ matrix: mat4,
painter: Painter,
shouldUseVerticalGradient: boolean,
opacity: number,
@@ -246,15 +269,17 @@ const fillExtrusionPatternUniformValues = (
coord: OverscaledTileID,
tile: Tile,
heightLift: number,
+ heightAlignment: string,
+ baseAlignment: string,
zoomTransition: number,
mercatorCenter: [number, number],
- invMatrix: Float32Array,
+ invMatrix: mat4,
floodLightColor: [number, number, number],
verticalScale: number,
): UniformValues => {
const uniformValues = fillExtrusionUniformValues(
matrix, painter, shouldUseVerticalGradient, opacity, aoIntensityRadius, edgeRadius, lineWidthScale, coord,
- heightLift, zoomTransition, mercatorCenter, invMatrix, floodLightColor, verticalScale, 1.0, [0, 0, 0]);
+ heightLift, heightAlignment, baseAlignment, zoomTransition, mercatorCenter, invMatrix, floodLightColor, verticalScale, 1.0, [0, 0, 0]);
const heightFactorUniform = {
'u_height_factor': -Math.pow(2, coord.overscaledZ) / tile.tileSize / 8
};
@@ -263,7 +288,7 @@ const fillExtrusionPatternUniformValues = (
const fillExtrusionGroundEffectUniformValues = (
painter: Painter,
- matrix: Float32Array,
+ matrix: mat4,
opacity: number,
aoPass: boolean,
meterToTile: number,
@@ -275,7 +300,7 @@ const fillExtrusionGroundEffectUniformValues = (
fbSize: number,
): UniformValues => {
const uniformValues = {
- 'u_matrix': matrix,
+ 'u_matrix': matrix as Float32Array,
'u_opacity': opacity,
'u_ao_pass': aoPass ? 1 : 0,
'u_meter_to_tile': meterToTile,
diff --git a/src/render/program/fill_program.ts b/src/render/program/fill_program.ts
index f3a38aac70e..928538da89d 100644
--- a/src/render/program/fill_program.ts
+++ b/src/render/program/fill_program.ts
@@ -7,6 +7,7 @@ import {
} from '../uniform_binding';
import {extend} from '../../util/util';
+import type {mat4} from 'gl-matrix';
import type Painter from '../painter';
import type {UniformValues} from '../uniform_binding';
import type Context from '../../gl/context';
@@ -78,13 +79,13 @@ const fillOutlinePatternUniforms = (context: Context): FillOutlinePatternUniform
'u_tile_units_to_pixels': new Uniform1f(context)
});
-const fillUniformValues = (matrix: Float32Array, emissiveStrength: number): UniformValues => ({
- 'u_matrix': matrix,
+const fillUniformValues = (matrix: mat4, emissiveStrength: number): UniformValues => ({
+ 'u_matrix': matrix as Float32Array,
'u_emissive_strength': emissiveStrength
});
const fillPatternUniformValues = (
- matrix: Float32Array,
+ matrix: mat4,
emissiveStrength: number,
painter: Painter,
tile: Tile,
@@ -94,17 +95,17 @@ const fillPatternUniformValues = (
);
const fillOutlineUniformValues = (
- matrix: Float32Array,
+ matrix: mat4,
emissiveStrength: number,
drawingBufferSize: [number, number],
): UniformValues => ({
- 'u_matrix': matrix,
+ 'u_matrix': matrix as Float32Array,
'u_world': drawingBufferSize,
'u_emissive_strength': emissiveStrength
});
const fillOutlinePatternUniformValues = (
- matrix: Float32Array,
+ matrix: mat4,
emissiveStrength: number,
painter: Painter,
tile: Tile,
diff --git a/src/render/program/heatmap_program.ts b/src/render/program/heatmap_program.ts
index e248d0c368b..a13b64066a0 100644
--- a/src/render/program/heatmap_program.ts
+++ b/src/render/program/heatmap_program.ts
@@ -46,7 +46,7 @@ const heatmapTextureUniforms = (context: Context): HeatmapTextureUniformsType =>
'u_opacity': new Uniform1f(context)
});
-const identityMatrix = mat4.create() as Float32Array;
+const identityMatrix = mat4.create();
const heatmapUniformValues = (
painter: Painter,
@@ -62,10 +62,10 @@ const heatmapUniformValues = (
const extrudeScale = isGlobe ? globePixelsToTileUnits(transform.zoom, coord.canonical) * transform._pixelsPerMercatorPixel : pixelsToTileUnits(tile, 1, zoom);
const values = {
- 'u_matrix': coord.projMatrix,
+ 'u_matrix': coord.projMatrix as Float32Array,
'u_extrude_scale': extrudeScale,
'u_intensity': intensity,
- 'u_inv_rot_matrix': identityMatrix,
+ 'u_inv_rot_matrix': identityMatrix as Float32Array,
'u_merc_center': [0, 0] as [number, number],
'u_tile_id': [0, 0, 0] as [number, number, number],
'u_zoom_transition': 0,
diff --git a/src/render/program/hillshade_program.ts b/src/render/program/hillshade_program.ts
index de5032b2b70..20c8efac46b 100644
--- a/src/render/program/hillshade_program.ts
+++ b/src/render/program/hillshade_program.ts
@@ -60,7 +60,7 @@ const hillshadeUniformValues = (
painter: Painter,
tile: Tile,
layer: HillshadeStyleLayer,
- matrix?: Float32Array | null,
+ matrix?: mat4 | null,
): UniformValues => {
const shadow = layer.paint.get("hillshade-shadow-color");
const highlight = layer.paint.get("hillshade-highlight-color");
@@ -82,7 +82,7 @@ const hillshadeUniformValues = (
}
const align = !painter.options.moving;
return {
- 'u_matrix': matrix ? matrix : painter.transform.calculateProjMatrix(tile.tileID.toUnwrapped(), align),
+ 'u_matrix': (matrix ? matrix : painter.transform.calculateProjMatrix(tile.tileID.toUnwrapped(), align)) as Float32Array,
'u_image': 0,
'u_latrange': getTileLatRange(painter, tile.tileID),
'u_light': [layer.paint.get('hillshade-exaggeration'), azimuthal],
@@ -97,7 +97,6 @@ const hillshadeUniformValues = (
};
const hillshadeUniformPrepareValues = (tileID: OverscaledTileID, dem: DEMData): UniformValues => {
-
const stride = dem.stride;
const matrix = mat4.create() as Float32Array;
// Flip rendering at y axis.
diff --git a/src/render/program/line_program.ts b/src/render/program/line_program.ts
index 7c8bf5c69a6..fb3b5cf7ce8 100644
--- a/src/render/program/line_program.ts
+++ b/src/render/program/line_program.ts
@@ -1,6 +1,9 @@
import {Uniform1i, Uniform1f, Uniform2f, Uniform4f, UniformMatrix2f, UniformMatrix4f} from '../uniform_binding';
import pixelsToTileUnits from '../../source/pixels_to_tile_units';
+import {clamp} from '../../../src/util/util';
+import {tileToMeter} from '../../../src/geo/mercator_coordinate';
+import type {mat4} from 'gl-matrix';
import type Context from '../../gl/context';
import type {UniformValues} from '../uniform_binding';
import type Transform from '../../geo/transform';
@@ -23,6 +26,8 @@ export type LineUniformsType = {
['u_trim_fade_range']: Uniform2f;
['u_trim_color']: Uniform4f;
['u_emissive_strength']: Uniform1f;
+ ['u_zbias_factor']: Uniform1f;
+ ['u_tile_to_meter']: Uniform1f;
};
export type LinePatternUniformsType = {
@@ -35,9 +40,11 @@ export type LinePatternUniformsType = {
['u_tile_units_to_pixels']: Uniform1f;
['u_alpha_discard_threshold']: Uniform1f;
['u_trim_offset']: Uniform2f;
+ ['u_zbias_factor']: Uniform1f;
+ ['u_tile_to_meter']: Uniform1f;
};
-export type LineDefinesType = 'RENDER_LINE_GRADIENT' | 'RENDER_LINE_DASH' | 'RENDER_LINE_TRIM_OFFSET' | 'RENDER_LINE_BORDER' | 'LINE_JOIN_NONE' | 'ELEVATED';
+export type LineDefinesType = 'RENDER_LINE_GRADIENT' | 'RENDER_LINE_DASH' | 'RENDER_LINE_TRIM_OFFSET' | 'RENDER_LINE_BORDER' | 'LINE_JOIN_NONE' | 'ELEVATED' | 'CROSS_SLOPE_VERTICAL' | 'CROSS_SLOPE_HORIZONTAL' | 'ELEVATION_REFERENCE_SEA';
const lineUniforms = (context: Context): LineUniformsType => ({
'u_matrix': new UniformMatrix4f(context),
@@ -53,7 +60,9 @@ const lineUniforms = (context: Context): LineUniformsType => ({
'u_trim_offset': new Uniform2f(context),
'u_trim_fade_range': new Uniform2f(context),
'u_trim_color': new Uniform4f(context),
- 'u_emissive_strength': new Uniform1f(context)
+ 'u_emissive_strength': new Uniform1f(context),
+ 'u_zbias_factor': new Uniform1f(context),
+ 'u_tile_to_meter': new Uniform1f(context)
});
const linePatternUniforms = (context: Context): LinePatternUniformsType => ({
@@ -66,22 +75,29 @@ const linePatternUniforms = (context: Context): LinePatternUniformsType => ({
'u_tile_units_to_pixels': new Uniform1f(context),
'u_alpha_discard_threshold': new Uniform1f(context),
'u_trim_offset': new Uniform2f(context),
+ 'u_zbias_factor': new Uniform1f(context),
+ 'u_tile_to_meter': new Uniform1f(context)
});
+const lerp = (a: number, b: number, t: number) => { return (1 - t) * a + t * b; };
+
const lineUniformValues = (
painter: Painter,
tile: Tile,
layer: LineStyleLayer,
- matrix: Float32Array | null | undefined,
+ matrix: mat4 | null | undefined,
imageHeight: number,
pixelRatio: number,
trimOffset: [number, number],
): UniformValues => {
const transform = painter.transform;
const pixelsToTileUnits = transform.calculatePixelsToTileUnitsMatrix(tile);
+ // Increase zbias factor for low pitch values based on the zoom level. Lower zoom level increases the zbias factor.
+ // The values were found experimentally, to make an elevated line look good over a terrain with high elevation differences.
+ const zbiasFactor = transform.pitch < 15.0 ? lerp(0.07, 0.7, clamp((14.0 - transform.zoom) / (14.0 - 9.0), 0.0, 1.0)) : 0.07;
return {
- 'u_matrix': calculateMatrix(painter, tile, layer, matrix),
- 'u_pixels_to_tile_units': pixelsToTileUnits,
+ 'u_matrix': calculateMatrix(painter, tile, layer, matrix) as Float32Array,
+ 'u_pixels_to_tile_units': pixelsToTileUnits as Float32Array,
'u_device_pixel_ratio': pixelRatio,
'u_units_to_pixels': [
1 / transform.pixelsToGLUnits[0],
@@ -96,7 +112,9 @@ const lineUniformValues = (
'u_trim_offset': trimOffset,
'u_trim_fade_range': layer.paint.get('line-trim-fade-range'),
'u_trim_color': layer.paint.get('line-trim-color').toRenderColor(layer.lut).toArray01(),
- 'u_emissive_strength': layer.paint.get('line-emissive-strength')
+ 'u_emissive_strength': layer.paint.get('line-emissive-strength'),
+ 'u_zbias_factor': zbiasFactor,
+ 'u_tile_to_meter': tileToMeter(tile.tileID.canonical, 0.0)
};
};
@@ -104,16 +122,19 @@ const linePatternUniformValues = (
painter: Painter,
tile: Tile,
layer: LineStyleLayer,
- matrix: Float32Array | null | undefined,
+ matrix: mat4 | null | undefined,
pixelRatio: number,
trimOffset: [number, number],
): UniformValues => {
const transform = painter.transform;
+ const zbiasFactor = transform.pitch < 15.0 ? lerp(0.07, 0.7, clamp((14.0 - transform.zoom) / (14.0 - 9.0), 0.0, 1.0)) : 0.07;
+ // Increase zbias factor for low pitch values based on the zoom level. Lower zoom level increases the zbias factor.
+ // The values were found experimentally, to make an elevated line look good over a terrain with high elevation differences.
return {
- 'u_matrix': calculateMatrix(painter, tile, layer, matrix),
+ 'u_matrix': calculateMatrix(painter, tile, layer, matrix) as Float32Array,
'u_texsize': tile.imageAtlasTexture ? tile.imageAtlasTexture.size : [0, 0],
// camera zoom ratio
- 'u_pixels_to_tile_units': transform.calculatePixelsToTileUnitsMatrix(tile),
+ 'u_pixels_to_tile_units': transform.calculatePixelsToTileUnitsMatrix(tile) as Float32Array,
'u_device_pixel_ratio': pixelRatio,
'u_image': 0,
'u_tile_units_to_pixels': calculateTileRatio(tile, transform),
@@ -122,7 +143,9 @@ const linePatternUniformValues = (
1 / transform.pixelsToGLUnits[1]
],
'u_alpha_discard_threshold': 0.0,
- 'u_trim_offset': trimOffset
+ 'u_trim_offset': trimOffset,
+ 'u_zbias_factor': zbiasFactor,
+ 'u_tile_to_meter': tileToMeter(tile.tileID.canonical, 0.0)
};
};
@@ -130,7 +153,7 @@ function calculateTileRatio(tile: Tile, transform: Transform) {
return 1 / pixelsToTileUnits(tile, 1, transform.tileZoom);
}
-function calculateMatrix(painter: Painter, tile: Tile, layer: LineStyleLayer, matrix?: Float32Array | null) {
+function calculateMatrix(painter: Painter, tile: Tile, layer: LineStyleLayer, matrix?: mat4) {
return painter.translatePosMatrix(
matrix ? matrix : tile.tileID.projMatrix,
tile,
@@ -141,7 +164,7 @@ function calculateMatrix(painter: Painter, tile: Tile, layer: LineStyleLayer, ma
}
const lineDefinesValues = (layer: LineStyleLayer): LineDefinesType[] => {
- const values = [];
+ const values: LineDefinesType[] = [];
if (hasDash(layer)) values.push('RENDER_LINE_DASH');
if (layer.paint.get('line-gradient')) values.push('RENDER_LINE_GRADIENT');
@@ -164,7 +187,6 @@ const lineDefinesValues = (layer: LineStyleLayer): LineDefinesType[] => {
};
function hasDash(layer: LineStyleLayer) {
-
const dashPropertyValue = layer.paint.get('line-dasharray').value;
// @ts-expect-error - TS2339 - Property 'value' does not exist on type 'PossiblyEvaluatedValue'.
return dashPropertyValue.value || dashPropertyValue.kind !== "constant";
diff --git a/src/render/program/program_uniforms.ts b/src/render/program/program_uniforms.ts
index 0148f0207da..ff036b80578 100644
--- a/src/render/program/program_uniforms.ts
+++ b/src/render/program/program_uniforms.ts
@@ -19,6 +19,8 @@ import {modelUniforms, modelDepthUniforms} from '../../../3d-style/render/progra
import {groundShadowUniforms} from '../../../3d-style/render/program/ground_shadow_program';
import {starsUniforms} from '../../terrain/stars_program';
import {occlusionUniforms} from './occlusion_program';
+import {snowUniforms} from '../../precipitation/snow_program';
+import {rainUniforms} from "../../precipitation/rain_program";
import type {GlobeDefinesType} from '../../terrain/globe_raster_program';
import type {HeatmapDefinesType} from './heatmap_program';
@@ -32,7 +34,25 @@ import type {ModelDefinesType} from '../../../3d-style/render/program/model_prog
export type FogDefinesType = ['FOG', 'FOG_DITHERING'];
export type TerrainDepthAccessDefinesType = 'DEPTH_D24' | 'DEPTH_OCCLUSION';
+
+type GlobalDefinesType =
+ | 'DEBUG_WIREFRAME'
+ | 'DEPTH_TEXTURE'
+ | 'FOG_DITHERING'
+ | 'FOG'
+ | 'GLOBE'
+ | 'LIGHTING_3D_ALPHA_EMISSIVENESS'
+ | 'LIGHTING_3D_MODE'
+ | 'NORMAL_OFFSET'
+ | 'OVERDRAW_INSPECTOR'
+ | 'RENDER_CUTOFF'
+ | 'RENDER_SHADOWS'
+ | 'RENDER_TO_TEXTURE'
+ | 'TERRAIN_DEM_FLOAT_FORMAT'
+ | 'TERRAIN';
+
export type DynamicDefinesType =
+ | GlobalDefinesType
| CircleDefinesType
| SymbolDefinesType
| LineDefinesType
@@ -83,5 +103,7 @@ export const programUniforms = {
modelDepth: modelDepthUniforms,
groundShadow: groundShadowUniforms,
stars: starsUniforms,
+ snowParticle: snowUniforms,
+ rainParticle: rainUniforms,
occlusion: occlusionUniforms
} as const;
diff --git a/src/render/program/symbol_program.ts b/src/render/program/symbol_program.ts
index d989d68b6bf..3d34110c445 100644
--- a/src/render/program/symbol_program.ts
+++ b/src/render/program/symbol_program.ts
@@ -42,6 +42,7 @@ export type SymbolUniformsType = {
['u_is_halo']: Uniform1i;
['u_icon_transition']: Uniform1f;
['u_color_adj_mat']: UniformMatrix4f;
+ ['u_scale_factor']: Uniform1f;
};
export type SymbolDefinesType = 'PITCH_WITH_MAP_TERRAIN';
@@ -78,9 +79,10 @@ const symbolUniforms = (context: Context): SymbolUniformsType => ({
'u_is_halo': new Uniform1i(context),
'u_icon_transition': new Uniform1f(context),
'u_color_adj_mat': new UniformMatrix4f(context),
+ 'u_scale_factor': new Uniform1f(context)
});
-const identityMatrix = mat4.create() as Float32Array;
+const identityMatrix = mat4.create();
const symbolUniformValues = (
functionType: string,
@@ -88,9 +90,9 @@ const symbolUniformValues = (
rotateInShader: boolean,
pitchWithMap: boolean,
painter: Painter,
- matrix: Float32Array,
- labelPlaneMatrix: Float32Array,
- glCoordMatrix: Float32Array,
+ matrix: mat4,
+ labelPlaneMatrix: mat4,
+ glCoordMatrix: mat4,
elevationFromSea: boolean,
isText: boolean,
texSize: [number, number],
@@ -99,11 +101,12 @@ const symbolUniformValues = (
coord: OverscaledTileID,
zoomTransition: number,
mercatorCenter: [number, number],
- invMatrix: Float32Array,
+ invMatrix: mat4,
upVector: [number, number, number],
projection: Projection,
- colorAdjustmentMatrix?: Float32Array | null,
+ colorAdjustmentMatrix?: mat4 | null,
transition?: number | null,
+ scaleFactor?: number | null
): UniformValues => {
const transform = painter.transform;
@@ -116,9 +119,9 @@ const symbolUniformValues = (
'u_rotate_symbol': +rotateInShader,
'u_aspect_ratio': transform.width / transform.height,
'u_fade_change': painter.options.fadeDuration ? painter.symbolFadeChange : 1,
- 'u_matrix': matrix,
- 'u_label_plane_matrix': labelPlaneMatrix,
- 'u_coord_matrix': glCoordMatrix,
+ 'u_matrix': matrix as Float32Array,
+ 'u_label_plane_matrix': labelPlaneMatrix as Float32Array,
+ 'u_coord_matrix': glCoordMatrix as Float32Array,
'u_is_text': +isText,
'u_elevation_from_sea': elevationFromSea ? 1.0 : 0.0,
'u_pitch_with_map': +pitchWithMap,
@@ -128,26 +131,26 @@ const symbolUniformValues = (
'u_texture_icon': 1,
'u_tile_id': [0, 0, 0] as [number, number, number],
'u_zoom_transition': 0,
- 'u_inv_rot_matrix': identityMatrix,
+ 'u_inv_rot_matrix': identityMatrix as Float32Array,
'u_merc_center': [0, 0] as [number, number],
'u_camera_forward': [0, 0, 0] as [number, number, number],
'u_ecef_origin': [0, 0, 0] as [number, number, number],
- 'u_tile_matrix': identityMatrix,
+ 'u_tile_matrix': identityMatrix as Float32Array,
'u_up_vector': [0, -1, 0] as [number, number, number],
- 'u_color_adj_mat': colorAdjustmentMatrix,
+ 'u_color_adj_mat': colorAdjustmentMatrix as Float32Array,
'u_icon_transition': transition ? transition : 0.0,
'u_gamma_scale': pitchWithMap ? painter.transform.getCameraToCenterDistance(projection) * Math.cos(painter.terrain ? 0 : painter.transform._pitch) : 1,
'u_device_pixel_ratio': browser.devicePixelRatio,
- 'u_is_halo': +isHalo
+ 'u_is_halo': +isHalo,
+ 'u_scale_factor': scaleFactor ? scaleFactor : 1.0
};
if (projection.name === 'globe') {
values['u_tile_id'] = [coord.canonical.x, coord.canonical.y, 1 << coord.canonical.z];
values['u_zoom_transition'] = zoomTransition;
- values['u_inv_rot_matrix'] = invMatrix;
+ values['u_inv_rot_matrix'] = invMatrix as Float32Array;
values['u_merc_center'] = mercatorCenter;
values['u_camera_forward'] = (transform._camera.forward() as [number, number, number]);
- // @ts-expect-error - TS2345 - Argument of type 'Float64Array' is not assignable to parameter of type 'mat4'.
values['u_ecef_origin'] = globeECEFOrigin(transform.globeMatrix, coord.toUnwrapped());
values['u_tile_matrix'] = Float32Array.from(transform.globeMatrix);
values['u_up_vector'] = upVector;
diff --git a/src/render/uniform_binding.ts b/src/render/uniform_binding.ts
index 21c0b502e59..3fcbed0daf6 100644
--- a/src/render/uniform_binding.ts
+++ b/src/render/uniform_binding.ts
@@ -46,7 +46,7 @@ class Uniform1i extends Uniform implements IUniform {
this.current = 0;
}
- set(program: WebGLProgram, name: string, v: number): void {
+ override set(program: WebGLProgram, name: string, v: number): void {
if (!this.fetchUniformLocation(program, name)) return;
if (this.current !== v) {
this.current = v;
@@ -61,7 +61,7 @@ class Uniform1f extends Uniform implements IUniform {
this.current = 0;
}
- set(program: WebGLProgram, name: string, v: number): void {
+ override set(program: WebGLProgram, name: string, v: number): void {
if (!this.fetchUniformLocation(program, name)) return;
if (this.current !== v) {
this.current = v;
@@ -76,7 +76,7 @@ class Uniform2f extends Uniform<[number, number]> implements IUniform<[number, n
this.current = [0, 0];
}
- set(program: WebGLProgram, name: string, v: [number, number]): void {
+ override set(program: WebGLProgram, name: string, v: [number, number]): void {
if (!this.fetchUniformLocation(program, name)) return;
if (v[0] !== this.current[0] || v[1] !== this.current[1]) {
this.current = v;
@@ -91,7 +91,7 @@ class Uniform3f extends Uniform<[number, number, number]> implements IUniform<[n
this.current = [0, 0, 0];
}
- set(program: WebGLProgram, name: string, v: [number, number, number]): void {
+ override set(program: WebGLProgram, name: string, v: [number, number, number]): void {
if (!this.fetchUniformLocation(program, name)) return;
if (v[0] !== this.current[0] || v[1] !== this.current[1] || v[2] !== this.current[2]) {
this.current = v;
@@ -106,7 +106,7 @@ class Uniform4f extends Uniform<[number, number, number, number]> implements IUn
this.current = [0, 0, 0, 0];
}
- set(program: WebGLProgram, name: string, v: [number, number, number, number]): void {
+ override set(program: WebGLProgram, name: string, v: [number, number, number, number]): void {
if (!this.fetchUniformLocation(program, name)) return;
if (v[0] !== this.current[0] || v[1] !== this.current[1] ||
v[2] !== this.current[2] || v[3] !== this.current[3]) {
@@ -122,7 +122,7 @@ class UniformColor extends Uniform implements IUniform
this.current = Color.transparent.toRenderColor(null);
}
- set(program: WebGLProgram, name: string, v: RenderColor): void {
+ override set(program: WebGLProgram, name: string, v: RenderColor): void {
if (!this.fetchUniformLocation(program, name)) return;
if (v.r !== this.current.r || v.g !== this.current.g ||
v.b !== this.current.b || v.a !== this.current.a) {
@@ -139,7 +139,7 @@ class UniformMatrix4f extends Uniform implements IUniform implements IUniform implements IUniform 0.0;
+ bool is_flat_height = centroid_pos.x != 0.0 && u_height_type == 1;
+ bool is_flat_base = centroid_pos.x != 0.0 && u_base_type == 1;
ele = elevation(pos_nx.xy);
- c_ele = flat_roof ? centroid_pos.y == 0.0 ? elevationFromUint16(centroid_pos.x) : flatElevation(centroid_pos) : ele;
- // If centroid elevation lower than vertex elevation, roof at least 2 meters height above base.
- h = flat_roof ? max(c_ele + height, ele + base + 2.0) : ele + (t > 0.0 ? height : base == 0.0 ? -5.0 : base);
+ c_ele = is_flat_height || is_flat_base ? (centroid_pos.y == 0.0 ? elevationFromUint16(centroid_pos.x) : flatElevation(centroid_pos)) : ele;
+ float h_height = is_flat_height ? max(c_ele + height, ele + base + 2.0) : ele + height;
+ float h_base = is_flat_base ? max(c_ele + base, ele + base) : ele + (base == 0.0 ? -5.0 : base);
+ h = t > 0.0 ? max(h_base, h_height) : h_base;
pos = vec3(pos_nx.xy, h);
#else
h = t > 0.0 ? height : base;
diff --git a/src/shaders/fill_extrusion_pattern.vertex.glsl b/src/shaders/fill_extrusion_pattern.vertex.glsl
index d1147f1b370..fa18e27595e 100644
--- a/src/shaders/fill_extrusion_pattern.vertex.glsl
+++ b/src/shaders/fill_extrusion_pattern.vertex.glsl
@@ -34,6 +34,11 @@ uniform vec3 u_up_dir;
uniform float u_height_lift;
#endif
+#ifdef TERRAIN
+uniform int u_height_type;
+uniform int u_base_type;
+#endif
+
out highp vec2 v_pos;
out vec4 v_lighting;
@@ -93,11 +98,13 @@ void main() {
vec3 p;
float c_ele;
#ifdef TERRAIN
- bool flat_roof = centroid_pos.x != 0.0 && t > 0.0;
+ bool is_flat_height = centroid_pos.x != 0.0 && u_height_type == 1;
+ bool is_flat_base = centroid_pos.x != 0.0 && u_base_type == 1;
ele = elevation(pos_nx.xy);
- c_ele = flat_roof ? centroid_pos.y == 0.0 ? elevationFromUint16(centroid_pos.x) : flatElevation(centroid_pos) : ele;
- // If centroid elevation lower than vertex elevation, roof at least 2 meters height above base.
- h = flat_roof ? max(c_ele + height, ele + base + 2.0) : ele + (t > 0.0 ? height : base == 0.0 ? -5.0 : base);
+ c_ele = is_flat_height || is_flat_base ? (centroid_pos.y == 0.0 ? elevationFromUint16(centroid_pos.x) : flatElevation(centroid_pos)) : ele;
+ float h_height = is_flat_height ? max(c_ele + height, ele + base + 2.0) : ele + height;
+ float h_base = is_flat_base ? max(c_ele + base, ele + base) : ele + (base == 0.0 ? -5.0 : base);
+ h = t > 0.0 ? max(h_base, h_height) : h_base;
p = vec3(pos_nx.xy, h);
#else
p = vec3(pos_nx.xy, z);
diff --git a/src/shaders/line.vertex.glsl b/src/shaders/line.vertex.glsl
index 30e5483d9f4..00fe0e1df16 100644
--- a/src/shaders/line.vertex.glsl
+++ b/src/shaders/line.vertex.glsl
@@ -31,6 +31,19 @@ uniform mat2 u_pixels_to_tile_units;
uniform vec2 u_units_to_pixels;
uniform lowp float u_device_pixel_ratio;
+#ifdef ELEVATED
+uniform lowp float u_zbias_factor;
+uniform lowp float u_tile_to_meter;
+
+float sample_elevation(vec2 apos) {
+#ifdef ELEVATION_REFERENCE_SEA
+ return 0.0;
+#else
+ return elevation(apos);
+#endif
+}
+#endif
+
out vec2 v_normal;
out vec2 v_width2;
out float v_gamma_scale;
@@ -106,25 +119,44 @@ void main() {
mediump vec2 offset2 = offset * a_extrude * EXTRUDE_SCALE * normal.y * mat2(t, -u, u, t);
float hidden = float(opacity == 0.0);
- vec4 projected_extrude = u_matrix * vec4(dist * u_pixels_to_tile_units, 0.0, 0.0);
+ vec2 extrude = dist * u_pixels_to_tile_units;
+ vec4 projected_extrude = u_matrix * vec4(extrude, 0.0, 0.0);
#ifdef ELEVATED_ROADS
// Apply slight vertical offset (1cm) for elevated vertices above the ground plane
gl_Position = u_matrix * vec4(pos + offset2 * u_pixels_to_tile_units, a_z_offset + 0.01 * step(0.01, a_z_offset), 1.0) + projected_extrude;
-#else // ELEVATED_ROADS
+#else
#ifdef ELEVATED
vec2 offsetTile = offset2 * u_pixels_to_tile_units;
- // forward or backward along the line, perpendicular to offset
- vec2 halfCellProgress = normal.yx * 32.0;
- float ele0 = elevation(pos);
- float ele_line = max(ele0, max(elevation(pos + halfCellProgress), elevation(pos - halfCellProgress)));
- float ele1 = elevation(pos + offsetTile);
- float ele2 = elevation(pos - offsetTile);
- float ele_max = max(ele_line, 0.5 * (ele1 + ele2));
- // keep cross slope by default
- float ele = ele_max - ele0 + ele1 + a_z_offset ;
- gl_Position = u_matrix * vec4(pos + offsetTile, ele, 1.0) + projected_extrude;
+ vec2 offset_pos = pos + offsetTile;
+ float ele = 0.0;
+#ifdef CROSS_SLOPE_VERTICAL
+ // Vertical line
+ // The least significant bit of a_pos_normal.y hold 1 if it's on top, 0 for bottom
+ float top = a_pos_normal.y - 2.0 * floor(a_pos_normal.y * 0.5);
+ float line_height = 2.0 * u_tile_to_meter * outset * top * u_pixels_to_tile_units[1][1] + a_z_offset;
+ ele = sample_elevation(offset_pos) + line_height;
+ // Ignore projected extrude for vertical lines
+ projected_extrude = vec4(0);
+#else // CROSS_SLOPE_VERTICAL
+#ifdef CROSS_SLOPE_HORIZONTAL
+ // Horizontal line
+ float ele0 = sample_elevation(offset_pos);
+ float ele1 = max(sample_elevation(offset_pos + extrude), sample_elevation(offset_pos + extrude / 2.0));
+ float ele2 = max(sample_elevation(offset_pos - extrude), sample_elevation(offset_pos - extrude / 2.0));
+ float ele_max = max(ele0, max(ele1, ele2));
+ ele = ele_max + a_z_offset;
+#else // CROSS_SLOPE_HORIZONTAL
+ // Line follows terrain slope
+ float ele0 = sample_elevation(offset_pos);
+ float ele1 = max(sample_elevation(offset_pos + extrude), sample_elevation(offset_pos + extrude / 2.0));
+ float ele2 = max(sample_elevation(offset_pos - extrude), sample_elevation(offset_pos - extrude / 2.0));
+ float ele_max = max(ele0, 0.5 * (ele1 + ele2));
+ ele = ele_max - ele0 + ele1 + a_z_offset;
+#endif // CROSS_SLOPE_HORIZONTAL
+#endif // CROSS_SLOPE_VERTICAL
+ gl_Position = u_matrix * vec4(offset_pos, ele, 1.0) + projected_extrude;
float z = clamp(gl_Position.z / gl_Position.w, 0.5, 1.0);
- float zbias = max(0.00005, (pow(z, 0.8) - z) * 0.1 * u_exaggeration);
+ float zbias = max(0.00005, (pow(z, 0.8) - z) * u_zbias_factor * u_exaggeration);
gl_Position.z -= (gl_Position.w * zbias);
gl_Position = mix(gl_Position, AWAY, hidden);
#else // ELEVATED
@@ -136,7 +168,7 @@ void main() {
// calculate how much the perspective view squishes or stretches the extrude
float extrude_length_without_perspective = length(dist);
float extrude_length_with_perspective = length(projected_extrude.xy / gl_Position.w * u_units_to_pixels);
- v_gamma_scale = extrude_length_without_perspective / extrude_length_with_perspective;
+ v_gamma_scale = mix(extrude_length_without_perspective / extrude_length_with_perspective, 1.0, step(0.01, blur));
#else
v_gamma_scale = 1.0;
#endif
diff --git a/src/shaders/line_pattern.vertex.glsl b/src/shaders/line_pattern.vertex.glsl
index 99848cb88bc..42746c9797c 100644
--- a/src/shaders/line_pattern.vertex.glsl
+++ b/src/shaders/line_pattern.vertex.glsl
@@ -33,6 +33,19 @@ uniform vec2 u_units_to_pixels;
uniform mat2 u_pixels_to_tile_units;
uniform float u_device_pixel_ratio;
+#ifdef ELEVATED
+uniform lowp float u_zbias_factor;
+uniform lowp float u_tile_to_meter;
+
+float sample_elevation(vec2 apos) {
+#ifdef ELEVATION_REFERENCE_SEA
+ return 0.0;
+#else
+ return elevation(apos);
+#endif
+}
+#endif
+
out vec2 v_normal;
out vec2 v_width2;
out highp float v_linesofar;
@@ -99,25 +112,44 @@ void main() {
vec2 offset2 = offset * a_extrude * scale * normal.y * mat2(t, -u, u, t);
float hidden = float(opacity == 0.0);
- vec4 projected_extrude = u_matrix * vec4(dist * u_pixels_to_tile_units, 0.0, 0.0);
+ vec2 extrude = dist * u_pixels_to_tile_units;
+ vec4 projected_extrude = u_matrix * vec4(extrude, 0.0, 0.0);
#ifdef ELEVATED_ROADS
// Apply slight vertical offset (1cm) for elevated vertices above the ground plane
gl_Position = u_matrix * vec4(pos + offset2 * u_pixels_to_tile_units, a_z_offset + 0.01 * step(0.01, a_z_offset), 1.0) + projected_extrude;
-#else // ELEVATED_ROADS
+#else
#ifdef ELEVATED
vec2 offsetTile = offset2 * u_pixels_to_tile_units;
- // forward or backward along the line, perpendicular to offset
- vec2 halfCellProgress = normal.yx * 32.0;
- float ele0 = elevation(pos);
- float ele_line = max(ele0, max(elevation(pos + halfCellProgress), elevation(pos - halfCellProgress)));
- float ele1 = elevation(pos + offsetTile);
- float ele2 = elevation(pos - offsetTile);
- float ele_max = max(ele_line, 0.5 * (ele1 + ele2));
- // keep cross slope by default
- float ele = ele_max - ele0 + ele1 + a_z_offset ;
- gl_Position = u_matrix * vec4(pos + offsetTile, ele, 1.0) + projected_extrude;
+ vec2 offset_pos = pos + offsetTile;
+ float ele = 0.0;
+#ifdef CROSS_SLOPE_VERTICAL
+ // Vertical line
+ // The least significant bit of a_pos_normal.y hold 1 if it's on top, 0 for bottom
+ float top = a_pos_normal.y - 2.0 * floor(a_pos_normal.y * 0.5);
+ float line_height = 2.0 * u_tile_to_meter * outset * top * u_pixels_to_tile_units[1][1] + a_z_offset;
+ ele = sample_elevation(offset_pos) + line_height;
+ // Ignore projected extrude for vertical lines
+ projected_extrude = vec4(0);
+#else // CROSS_SLOPE_VERTICAL
+#ifdef CROSS_SLOPE_HORIZONTAL
+ // Horizontal line
+ float ele0 = sample_elevation(offset_pos);
+ float ele1 = max(sample_elevation(offset_pos + extrude), sample_elevation(offset_pos + extrude / 2.0));
+ float ele2 = max(sample_elevation(offset_pos - extrude), sample_elevation(offset_pos - extrude / 2.0));
+ float ele_max = max(ele0, max(ele1, ele2));
+ ele = ele_max + a_z_offset;
+#else // CROSS_SLOPE_HORIZONTAL
+ // Line follows terrain slope
+ float ele0 = sample_elevation(offset_pos);
+ float ele1 = max(sample_elevation(offset_pos + extrude), sample_elevation(offset_pos + extrude / 2.0));
+ float ele2 = max(sample_elevation(offset_pos - extrude), sample_elevation(offset_pos - extrude / 2.0));
+ float ele_max = max(ele0, 0.5 * (ele1 + ele2));
+ ele = ele_max - ele0 + ele1 + a_z_offset;
+#endif // CROSS_SLOPE_HORIZONTAL
+#endif // CROSS_SLOPE_VERTICAL
+ gl_Position = u_matrix * vec4(offset_pos, ele, 1.0) + projected_extrude;
float z = clamp(gl_Position.z / gl_Position.w, 0.5, 1.0);
- float zbias = max(0.00005, (pow(z, 0.8) - z) * 0.1 * u_exaggeration);
+ float zbias = max(0.00005, (pow(z, 0.8) - z) * u_zbias_factor * u_exaggeration);
gl_Position.z -= (gl_Position.w * zbias);
gl_Position = mix(gl_Position, AWAY, hidden);
#else // ELEVATED
@@ -125,11 +157,12 @@ void main() {
#endif // ELEVATED
#endif // ELEVATED_ROADS
+
#ifndef RENDER_TO_TEXTURE
// calculate how much the perspective view squishes or stretches the extrude
float extrude_length_without_perspective = length(dist);
float extrude_length_with_perspective = length(projected_extrude.xy / gl_Position.w * u_units_to_pixels);
- v_gamma_scale = extrude_length_without_perspective / extrude_length_with_perspective;
+ v_gamma_scale = mix(extrude_length_without_perspective / extrude_length_with_perspective, 1.0, step(0.01, blur));
#else
v_gamma_scale = 1.0;
#endif
diff --git a/src/shaders/rain_particle.fragment.glsl b/src/shaders/rain_particle.fragment.glsl
new file mode 100644
index 00000000000..e91f22ffb0c
--- /dev/null
+++ b/src/shaders/rain_particle.fragment.glsl
@@ -0,0 +1,63 @@
+in highp vec2 uv;
+in highp float particleRandomValue;
+
+uniform sampler2D u_texScreen;
+
+uniform float u_distortionStrength;
+
+uniform vec4 u_color;
+
+// Thinning
+uniform vec2 u_thinningCenterPos;
+uniform vec3 u_thinningShape;
+// .x - start
+// .y - range
+// .z - fade power
+uniform float u_thinningAffectedRatio;
+uniform float u_thinningParticleOffset;
+
+
+uniform float u_shapeDirectionalPower;
+
+uniform float u_mode;
+// 0 - distortion only
+// 1 - alpha blend only
+
+void main() {
+ vec2 st = uv * 0.5 + vec2(0.5);
+
+
+ vec2 uvm = uv;
+ uvm.y = -1.0 + 2.0 * pow(st.y, u_shapeDirectionalPower);
+
+ float shape = clamp(1.0 - length(uvm), 0.0, 1.0);
+
+ float alpha = abs(shape) * u_color.a;
+
+
+ vec2 screenSize = vec2(textureSize(u_texScreen, 0));
+
+ vec2 thinningCenterPos = u_thinningCenterPos.xy;
+ thinningCenterPos.y = screenSize.y - thinningCenterPos.y;
+
+ float screenDist = length((thinningCenterPos - gl_FragCoord.xy) / (0.5 * screenSize));
+ screenDist += (0.5 + 0.5 * particleRandomValue) * u_thinningParticleOffset;
+
+ float thinningShapeDist = u_thinningShape.x + u_thinningShape.y;
+ float thinningAlpha = 1.0;
+ if (screenDist < thinningShapeDist) {
+ float thinningFadeRatio = clamp((screenDist - u_thinningShape.x) / u_thinningShape.y, 0.0, 1.0);
+ thinningFadeRatio = pow(thinningFadeRatio, u_thinningShape.z);
+ thinningAlpha *= thinningFadeRatio;
+ }
+
+ vec2 offsetXY = normalize(uvm) * abs(shape);
+ vec2 stScreen = (gl_FragCoord.xy + offsetXY * u_distortionStrength * thinningAlpha) / screenSize;
+ vec3 colorScreen = texture(u_texScreen, stScreen).rgb;
+
+ alpha *= thinningAlpha;
+
+ glFragColor = mix(vec4(colorScreen, 1.0), vec4(u_color.rgb * alpha, alpha), u_mode);
+
+ HANDLE_WIREFRAME_DEBUG;
+}
diff --git a/src/shaders/rain_particle.vertex.glsl b/src/shaders/rain_particle.vertex.glsl
new file mode 100644
index 00000000000..338ee70b4f0
--- /dev/null
+++ b/src/shaders/rain_particle.vertex.glsl
@@ -0,0 +1,108 @@
+// Position
+in highp vec3 a_pos_3f;
+// Offset from center ([-1, -1], ...)
+in highp vec2 a_uv;
+
+in highp vec4 a_rainParticleData;
+// .x - random value
+// .y - velocity scale multiplier
+// .z - velocity cone angle pitch scale
+// .w - velocity cone angle heading scale
+
+// mvp
+uniform mat4 u_modelview;
+uniform mat4 u_projection;
+
+// camera up & right vectors mulitplied by size
+uniform vec3 u_cam_pos;
+
+uniform float u_time;
+
+uniform float u_boxSize;
+
+uniform float u_velocityConeAperture;
+
+uniform float u_velocity;
+
+uniform vec2 u_rainDropletSize;
+
+uniform vec3 u_rainDirection;
+
+
+out highp vec2 uv;
+out highp float particleRandomValue;
+
+void main() {
+ vec3 pos = a_pos_3f;
+
+ float halfBoxSize = 0.5 * u_boxSize;
+
+ pos *= halfBoxSize;
+ pos += u_cam_pos;
+
+ //
+ // Movement animation
+ //
+
+ // Cone angle
+ float velocityConeApertureRad = radians(u_velocityConeAperture * 0.5);
+ float coneAnglePichRad = velocityConeApertureRad * a_rainParticleData.z;
+
+ float coneAngleHeadingRad = a_rainParticleData.w * radians(360.0);
+
+ // vec3 direction = u_rainDirection;
+
+ vec3 localZ = normalize(u_rainDirection);
+ vec3 localX = normalize(cross(localZ, vec3(1, 0, 0)));
+ vec3 localY = normalize(cross(localZ, localX));
+
+ // Direction in local coordinate system
+ vec3 directionLocal;
+ directionLocal.x = cos(coneAngleHeadingRad) * sin(coneAnglePichRad);
+ directionLocal.y = sin(coneAngleHeadingRad) * sin(coneAnglePichRad);
+ directionLocal.z = cos(coneAnglePichRad);
+
+ directionLocal = normalize(directionLocal);
+
+ vec3 directionWorld = localX * directionLocal.x + localY * directionLocal.y + localZ * directionLocal.z;
+
+ float velocityScale = (1.0 + 3.0 * a_rainParticleData.y) * u_velocity;
+
+ vec3 simPosLocal = vec3(0, 0, 0);
+ simPosLocal += directionLocal * velocityScale * u_time;
+
+ vec3 simPos = localX * simPosLocal.x +
+ localY * simPosLocal.y +
+ localZ * simPosLocal.z;
+
+ pos += simPos;
+
+ // Wrap against box around camera
+ pos = fract((pos + vec3(halfBoxSize)) / vec3(u_boxSize)) * u_boxSize - vec3(halfBoxSize);
+
+ vec4 posView = u_modelview * vec4(pos, 1.0);
+
+ //
+ // Billboarding
+ //
+
+ vec3 directionView = normalize((u_modelview * vec4(directionWorld, 0.0)).xyz);
+ vec3 side = cross(directionView, normalize(posView.xyz));
+
+ posView.xyz += side * a_uv.x * u_rainDropletSize.x;
+ posView.xyz += directionView * a_uv.y * u_rainDropletSize.y;
+
+
+ //
+ // Pass attributes
+ //
+
+ uv = a_uv;
+ particleRandomValue = a_rainParticleData.x;
+
+ //
+ // Projection
+ //
+
+ gl_Position = u_projection * posView;
+}
diff --git a/src/shaders/raster.fragment.glsl b/src/shaders/raster.fragment.glsl
index 1eb68636602..16a6e1cc1b0 100644
--- a/src/shaders/raster.fragment.glsl
+++ b/src/shaders/raster.fragment.glsl
@@ -26,7 +26,7 @@ uniform float u_emissive_strength;
#ifndef RASTER_ARRAY
// Since samplers cannot be used as function parameters, they must be hard-coded. These
// are therefore instead moved to the raster_array prelude when raster arrays are active.
-uniform sampler2D u_image0;
+uniform highp sampler2D u_image0;
uniform sampler2D u_image1;
#endif
diff --git a/src/shaders/shaders.ts b/src/shaders/shaders.ts
index 97d0d4f0717..25662620fa7 100644
--- a/src/shaders/shaders.ts
+++ b/src/shaders/shaders.ts
@@ -77,6 +77,10 @@ import atmosphereFrag from './atmosphere.fragment.glsl';
import atmosphereVert from './atmosphere.vertex.glsl';
import starsFrag from './stars.fragment.glsl';
import starsVert from './stars.vertex.glsl';
+import snowFrag from './snow_particle.fragment.glsl';
+import snowVert from './snow_particle.vertex.glsl';
+import rainFrag from './rain_particle.fragment.glsl';
+import rainVert from './rain_particle.vertex.glsl';
import occlusionFrag from './occlusion.fragment.glsl';
import occlusionVert from './occlusion.vertex.glsl';
// 3d-style related shaders
@@ -166,6 +170,8 @@ export default {
model: compile(modelFrag, modelVert),
modelDepth: compile(modelDepthFrag, modelDepthVert),
stars: compile(starsFrag, starsVert),
+ snowParticle: compile(snowFrag, snowVert),
+ rainParticle: compile(rainFrag, rainVert),
occlusion: compile(occlusionFrag, occlusionVert)
};
diff --git a/src/shaders/snow_particle.fragment.glsl b/src/shaders/snow_particle.fragment.glsl
new file mode 100644
index 00000000000..74321f08847
--- /dev/null
+++ b/src/shaders/snow_particle.fragment.glsl
@@ -0,0 +1,20 @@
+in highp vec2 uv;
+in highp float alphaMultiplier;
+
+uniform vec4 u_particleColor;
+uniform vec2 u_simpleShapeParameters;
+// .x - simple shape fade start
+// .y - simple shape fade power
+
+void main() {
+ float t = clamp((length(uv) - u_simpleShapeParameters.x) / (1.0 - u_simpleShapeParameters.x), 0.0, 1.0);
+ float alpha = 1.0 - pow(t, pow(10.0, u_simpleShapeParameters.y));
+
+ alpha *= alphaMultiplier;
+ alpha *= u_particleColor.a;
+
+ vec3 color = u_particleColor.rgb * alpha;
+ glFragColor = vec4(color, alpha) ;
+
+ HANDLE_WIREFRAME_DEBUG;
+}
diff --git a/src/shaders/snow_particle.vertex.glsl b/src/shaders/snow_particle.vertex.glsl
new file mode 100644
index 00000000000..a94ff3511d5
--- /dev/null
+++ b/src/shaders/snow_particle.vertex.glsl
@@ -0,0 +1,190 @@
+// Position
+in highp vec3 a_pos_3f;
+// Offset from center ([-1, -1], ...)
+in highp vec2 a_uv;
+
+in highp vec4 a_snowParticleData;
+// .x - relative index [0, 1]
+// .y - velocity scale multiplier
+// .z - velocity cone angle scale
+// .w - velocity cone pitch scale
+
+in highp vec4 a_snowParticleDataHorizontalOscillation;
+// .x - radius scale
+// .y - velocity scale
+
+// mvp
+uniform mat4 u_modelview;
+uniform mat4 u_projection;
+
+uniform vec3 u_cam_pos;
+
+uniform vec2 u_screenSize;
+
+uniform float u_time;
+
+uniform float u_boxSize;
+
+uniform float u_velocityConeAperture;
+
+uniform float u_velocity;
+
+// Main direction
+uniform vec3 u_direction;
+
+
+uniform float u_horizontalOscillationRadius;
+uniform float u_horizontalOscillationRate;
+
+uniform float u_billboardSize;
+
+// Thinning
+uniform vec2 u_thinningCenterPos;
+uniform vec3 u_thinningShape;
+// .x - start
+// .y - range
+// .z - fade power
+
+// Ratio of particles subject to thinning
+uniform float u_thinningAffectedRatio;
+
+// Particle-based thinning shape offset
+// Needed in order to make thinning shape less uniform
+uniform float u_thinningParticleOffset;
+
+out highp vec2 uv;
+out highp float alphaMultiplier;
+
+void main() {
+ vec3 pos = a_pos_3f;
+
+ float halfBoxSize = 0.5 * u_boxSize;
+
+ pos.xyz *= halfBoxSize;
+
+ pos += u_cam_pos;
+
+ //
+ // Movement animation
+ //
+
+ // Cone angle
+ float velocityConeApertureRad = radians(u_velocityConeAperture * 0.5);
+ float coneAnglePichRad = velocityConeApertureRad * a_snowParticleData.z;
+
+ float coneAngleHeadingRad = a_snowParticleData.w * radians(360.0);
+
+ vec3 localZ = normalize(u_direction);
+ vec3 localX = normalize(cross(localZ, vec3(1, 0, 0)));
+ vec3 localY = normalize(cross(localZ, localX));
+
+ // Direction in local coordinate system
+ vec3 direction;
+ direction.x = cos(coneAngleHeadingRad) * sin(coneAnglePichRad);
+ direction.y = sin(coneAngleHeadingRad) * sin(coneAnglePichRad);
+ direction.z = cos(coneAnglePichRad);
+
+ direction = normalize(direction);
+
+ vec3 simPosLocal = vec3(0, 0, 0);
+
+ float velocityScale = (1.0 + 3.0 * a_snowParticleData.y) * u_velocity;
+ simPosLocal += direction * velocityScale * u_time;
+
+ // Horizontal oscillation
+ float horizontalOscillationRadius = u_horizontalOscillationRadius * a_snowParticleDataHorizontalOscillation.x;
+ float horizontalOscillationAngle = u_horizontalOscillationRate * u_time * (-1.0 + 2.0 * a_snowParticleDataHorizontalOscillation.y);
+ simPosLocal.xy += horizontalOscillationRadius * vec2(cos(horizontalOscillationAngle), sin(horizontalOscillationAngle));
+
+ vec3 simPos = localX * simPosLocal.x +
+ localY * simPosLocal.y +
+ localZ * simPosLocal.z;
+
+ pos += simPos;
+
+
+ // Wrap against box around camera
+
+ pos = fract((pos + vec3(halfBoxSize)) / vec3(u_boxSize)) * u_boxSize - vec3(halfBoxSize);
+
+ float clipZ = -u_cam_pos.z + pos.z;
+
+ vec4 posView = u_modelview * vec4(pos, 1.0);
+
+ //
+ // Billboarding
+ //
+
+ float size = u_billboardSize;
+
+ alphaMultiplier = 1.0;
+
+ vec4 posScreen = u_projection * posView;
+ posScreen /= posScreen.w;
+ posScreen.xy = vec2(0.5) + posScreen.xy * 0.5;
+ posScreen.xy *= u_screenSize;
+
+ vec2 thinningCenterPos = u_thinningCenterPos.xy;
+ thinningCenterPos.y = u_screenSize.y - thinningCenterPos.y;
+
+ float screenDist = length((thinningCenterPos - posScreen.xy) / (0.5 * u_screenSize));
+ screenDist += a_snowParticleData.x * u_thinningParticleOffset;
+ float scaleFactorMode = 0.0;
+ float thinningShapeDist = u_thinningShape.x + u_thinningShape.y;
+ if (screenDist < thinningShapeDist) {
+ float thinningFadeRatio = clamp((screenDist - u_thinningShape.x) / u_thinningShape.y, 0.0, 1.0);
+ thinningFadeRatio = pow(thinningFadeRatio, u_thinningShape.z);
+ if (a_snowParticleData.x < u_thinningAffectedRatio) {
+ scaleFactorMode = 1.0 - thinningFadeRatio;
+ alphaMultiplier = thinningFadeRatio;
+ }
+ }
+
+ vec4 posScreen1 = u_projection * vec4(posView.x - size, posView.yzw);
+ posScreen1 /= posScreen1.w;
+
+ vec4 posScreen2 = u_projection * vec4(posView.x + size, posView.yzw);
+ posScreen2 /= posScreen2.w;
+
+
+ posScreen1.xy = vec2(0.5) + posScreen1.xy * 0.5;
+ posScreen1.xy *= u_screenSize;
+ posScreen2.xy = vec2(0.5) + posScreen2.xy * 0.5;
+ posScreen2.xy *= u_screenSize;
+
+ float screenLength = length(posScreen1.xy - posScreen2.xy);
+
+ // Min size restriction in pixels
+ float screenEpsilon = 3.0;
+ float scaleFactor = 1.0;
+ if (screenLength < screenEpsilon) {
+ scaleFactor = screenEpsilon / max(screenLength, 0.01);
+ scaleFactor = mix(scaleFactor, 1.0, scaleFactorMode);
+ }
+
+ // Max size restriction in pixels
+ float screenEpsilon2 = 15.0;
+ if (screenLength > screenEpsilon2) {
+ scaleFactor = screenEpsilon2 / max(screenLength, 0.01);
+ }
+
+ size *= scaleFactor;
+
+ vec2 right = size * vec2(1, 0);
+ vec2 up = size * vec2(0, 1);
+
+ posView.xy += right * a_uv.x;
+ posView.xy += up * a_uv.y;
+
+ //
+ // Pass attributes
+ //
+
+ uv = a_uv;
+
+ //
+ // Projection
+ //
+
+ gl_Position = u_projection * posView;
+}
diff --git a/src/shaders/symbol.fragment.glsl b/src/shaders/symbol.fragment.glsl
index 75a5229bf39..fa4253ea277 100644
--- a/src/shaders/symbol.fragment.glsl
+++ b/src/shaders/symbol.fragment.glsl
@@ -10,6 +10,7 @@ uniform highp float u_gamma_scale;
uniform lowp float u_device_pixel_ratio;
uniform bool u_is_text;
uniform bool u_is_halo;
+uniform lowp float u_scale_factor;
#ifdef ICON_TRANSITION
uniform float u_icon_transition;
#endif
@@ -76,8 +77,8 @@ void main() {
bool draw_halo = v_draw_halo > 0.0;
if (draw_halo) {
out_color = halo_color;
- gamma = (halo_blur * 1.19 / SDF_PX + EDGE_GAMMA) / (fontScale * u_gamma_scale);
- buff = (6.0 - halo_width / fontScale) / SDF_PX;
+ gamma = (halo_blur * u_scale_factor * 1.19 / SDF_PX + EDGE_GAMMA) / (fontScale * u_gamma_scale);
+ buff = (6.0 - halo_width * u_scale_factor / fontScale) / SDF_PX;
}
lowp float dist = texture(u_texture, v_tex_a).r;
diff --git a/src/source/canvas_source.ts b/src/source/canvas_source.ts
index c2c169fe40d..e5548018672 100644
--- a/src/source/canvas_source.ts
+++ b/src/source/canvas_source.ts
@@ -54,8 +54,8 @@ export type CanvasSourceSpecification = {
* @see [Example: Add a canvas source](https://docs.mapbox.com/mapbox-gl-js/example/canvas-source/)
*/
class CanvasSource extends ImageSource<'canvas'> {
- type: 'canvas';
- options: CanvasSourceSpecification;
+ override type: 'canvas';
+ override options: CanvasSourceSpecification;
animate: boolean;
canvas: HTMLCanvasElement;
play: () => void;
@@ -106,7 +106,7 @@ class CanvasSource extends ImageSource<'canvas'> {
* @memberof CanvasSource
*/
- load() {
+ override load() {
this._loaded = true;
if (!this.canvas) {
this.canvas = (this.options.canvas instanceof HTMLCanvasElement) ?
@@ -159,7 +159,7 @@ class CanvasSource extends ImageSource<'canvas'> {
return this.canvas;
}
- onAdd(map: Map) {
+ override onAdd(map: Map) {
this.map = map;
this.load();
if (this.canvas) {
@@ -167,7 +167,7 @@ class CanvasSource extends ImageSource<'canvas'> {
}
}
- onRemove(_: Map) {
+ override onRemove(_: Map) {
this.pause();
}
@@ -186,7 +186,7 @@ class CanvasSource extends ImageSource<'canvas'> {
// setCoordinates inherited from ImageSource
- prepare() {
+ override prepare() {
let resize = false;
if (this.canvas.width !== this.width) {
this.width = this.canvas.width;
@@ -212,14 +212,14 @@ class CanvasSource extends ImageSource<'canvas'> {
this._prepareData(context);
}
- serialize(): any {
+ override serialize(): any {
return {
type: 'canvas',
coordinates: this.coordinates
};
}
- hasTransition(): boolean {
+ override hasTransition(): boolean {
return this._playing;
}
diff --git a/src/source/geojson_source.ts b/src/source/geojson_source.ts
index a7aa4c1bd85..07d08fc71f4 100644
--- a/src/source/geojson_source.ts
+++ b/src/source/geojson_source.ts
@@ -446,6 +446,7 @@ class GeoJSONSource extends Evented implements ISource {
showCollisionBoxes: this.map.showCollisionBoxes,
promoteId: this.promoteId,
brightness: this.map.style ? (this.map.style.getBrightness() || 0.0) : 0.0,
+ scaleFactor: this.map.getScaleFactor(),
partial
};
diff --git a/src/source/geojson_worker_source.ts b/src/source/geojson_worker_source.ts
index 21ed92fabe1..bfe99a6d312 100644
--- a/src/source/geojson_worker_source.ts
+++ b/src/source/geojson_worker_source.ts
@@ -200,7 +200,7 @@ class GeoJSONWorkerSource extends VectorTileWorkerSource {
* @param params.uid The UID for this tile.
* @private
*/
- reloadTile(params: WorkerTileParameters, callback: WorkerTileCallback): void {
+ override reloadTile(params: WorkerTileParameters, callback: WorkerTileCallback): void {
const loaded = this.loaded,
uid = params.uid;
diff --git a/src/source/image_source.ts b/src/source/image_source.ts
index 52a1b06f505..5f91d509113 100644
--- a/src/source/image_source.ts
+++ b/src/source/image_source.ts
@@ -67,7 +67,7 @@ function getTextureToTileTransformMatrix(x1: number, y1: number, x2: number, y2:
return mat3.multiply(b, b, adjA);
}
-function getPerspectiveTransform(x1: number, y1: number, x2: number, y2: number, x3: number, y3: number, x4: number, y4: number) {
+function getPerspectiveTransform(x1: number, y1: number, x2: number, y2: number, x3: number, y3: number, x4: number, y4: number): [number, number] {
const m = getTextureToTileTransformMatrix(x1, y1, x2, y2, x3, y3, x4, y4);
return [
m[2] / m[8] / EXTENT,
@@ -94,11 +94,11 @@ function isConvex(coords: [ProjectedPoint, ProjectedPoint, ProjectedPoint, Proje
(crossProduct1 < 0 && crossProduct2 < 0 && crossProduct3 < 0 && crossProduct4 < 0);
}
-function constrainCoordinates(coords: [number, number]) {
+function constrainCoordinates(coords: [number, number]): [number, number] {
return [coords[0], Math.min(Math.max(coords[1], -MAX_MERCATOR_LATITUDE), MAX_MERCATOR_LATITUDE)];
}
-function constrain(coords: Coordinates) {
+function constrain(coords: Coordinates): Coordinates {
return [
constrainCoordinates(coords[0]),
constrainCoordinates(coords[1]),
@@ -522,14 +522,13 @@ class ImageSource extends Event
const globalTileTr = tileTransform(new CanonicalTileID(0, 0, 0), this.map.transform.projection);
- const globalTileCoords = [
+ const globalTileCoords: [ProjectedPoint, ProjectedPoint, ProjectedPoint, ProjectedPoint] = [
globalTileTr.projection.project(this.coordinates[0][0], this.coordinates[0][1]),
globalTileTr.projection.project(this.coordinates[1][0], this.coordinates[1][1]),
globalTileTr.projection.project(this.coordinates[2][0], this.coordinates[2][1]),
globalTileTr.projection.project(this.coordinates[3][0], this.coordinates[3][1])
];
- // @ts-expect-error - TS2345 - Argument of type 'ProjectedPoint[]' is not assignable to parameter of type '[ProjectedPoint, ProjectedPoint, ProjectedPoint, ProjectedPoint]'.
if (!isConvex(globalTileCoords)) {
console.warn('Image source coordinates are defining non-convex area in the Mercator projection');
this._unsupportedCoords = true;
@@ -544,7 +543,6 @@ class ImageSource extends Event
return getTilePoint(tileTr, projectedCoord)._round();
});
- // @ts-expect-error - TS2322 - Type 'number[]' is not assignable to type '[number, number]'.
this.perspectiveTransform = getPerspectiveTransform(tl.x, tl.y, tr.x, tr.y, br.x, br.y, bl.x, bl.y);
const boundsArray = this._boundsArray = new RasterBoundsArray();
@@ -592,7 +590,6 @@ class ImageSource extends Event
const triangleCount = cellCount * cellCount * 2;
const verticesLongitudes = [];
const constrainedCoordinates = constrain(this.coordinates);
- // @ts-expect-error - TS2345 - Argument of type 'number[][]' is not assignable to parameter of type 'Coordinates'.
const [minLng, minLat, lngDiff, latDiff] = calculateMinAndSize(constrainedCoordinates);
// Vertices
@@ -606,7 +603,6 @@ class ImageSource extends Event
};
const [p0, p1, p2, p3] = globalTileCoords.map(transformToImagePoint);
const toUV = getTileToTextureTransformMatrix(p0[0], p0[1], p1[0], p1[1], p2[0], p2[1], p3[0], p3[1]);
- // @ts-expect-error - TS2322 - Type 'number[]' is not assignable to type '[number, number]'.
this.elevatedGlobePerspectiveTransform = getPerspectiveTransform(p0[0], p0[1], p1[0], p1[1], p2[0], p2[1], p3[0], p3[1]);
const addVertex = (point: LngLat, tilePoint: ProjectedPoint) => {
diff --git a/src/source/load_tilejson.ts b/src/source/load_tilejson.ts
index b42e3114b8c..0b7d6b0098b 100644
--- a/src/source/load_tilejson.ts
+++ b/src/source/load_tilejson.ts
@@ -104,7 +104,7 @@ export default function(
const result = pick(
// explicit source options take precedence over TileJSON
- extend(tileJSON, options),
+ extend({}, tileJSON, options),
['tilejson', 'tiles', 'minzoom', 'maxzoom', 'attribution', 'mapbox_logo', 'bounds', 'scheme', 'tileSize', 'encoding']
) as ExtendedTileJSON;
diff --git a/src/source/pixels_to_tile_units.ts b/src/source/pixels_to_tile_units.ts
index a9e614a4fa0..51759b84cae 100644
--- a/src/source/pixels_to_tile_units.ts
+++ b/src/source/pixels_to_tile_units.ts
@@ -35,9 +35,8 @@ export function getPixelsToTileUnitsMatrix(
readonly tileTransform: TileTransform;
},
transform: Transform,
-): Float32Array {
+): mat2 {
const {scale} = tile.tileTransform;
const s = scale * EXTENT / (tile.tileSize * Math.pow(2, transform.zoom - tile.tileID.overscaledZ + tile.tileID.canonical.z));
- // @ts-expect-error - TS2322 - Type 'mat2' is not assignable to type 'Float32Array'. | TS2345 - Argument of type 'number[]' is not assignable to parameter of type 'ReadonlyMat2'.
return mat2.scale(new Float32Array(4), transform.inverseAdjustmentMatrix, [s, s]);
}
diff --git a/src/source/query_features.ts b/src/source/query_features.ts
index 78e1cc3630a..ee14bed0c12 100644
--- a/src/source/query_features.ts
+++ b/src/source/query_features.ts
@@ -1,12 +1,13 @@
import assert from 'assert';
import {mat4} from 'gl-matrix';
+import {isFQID} from '../util/fqid';
import type Point from '@mapbox/point-geometry';
import type SourceCache from './source_cache';
import type StyleLayer from '../style/style_layer';
import type CollisionIndex from '../symbol/collision_index';
import type Transform from '../geo/transform';
-import type {GeoJSONFeature} from '../util/vectortile_to_geojson';
+import type Feature from '../util/vectortile_to_geojson';
import type {OverscaledTileID} from './tile_id';
import type {RetainedQueryData} from '../symbol/placement';
import type {QueryGeometry, TilespaceQueryGeometry} from '../style/query_geometry';
@@ -15,7 +16,7 @@ import type {FilterSpecification} from '../style-spec/types';
export type QueryResult = {
[_: string]: Array<{
featureIndex: number;
- feature: GeoJSONFeature;
+ feature: Feature;
intersectionZ: boolean | number;
}>;
};
@@ -25,17 +26,6 @@ export type RenderedFeatureLayers = Array<{
queryResults: QueryResult;
}>;
-export type QueryRenderedFeaturesParams = {
- scope?: string;
- layers?: string[];
- filter?: FilterSpecification;
- validate?: boolean;
- availableImages?: string[];
- serializedLayers?: {
- [key: string]: StyleLayer;
- };
-};
-
/*
* Returns a matrix that can be used to convert from tile coordinates to viewport pixel coordinates.
*/
@@ -52,15 +42,10 @@ export function queryRenderedFeatures(
styleLayers: {
[_: string]: StyleLayer;
},
- serializedLayers: {
- [_: string]: any;
- },
queryGeometry: QueryGeometry,
- params: {
- filter: FilterSpecification;
- layers: Array;
- availableImages: Array;
- },
+ filter: FilterSpecification,
+ layers: string[],
+ availableImages: Array,
transform: Transform,
use3DQuery: boolean,
visualizeQueryGeometry: boolean = false,
@@ -73,10 +58,11 @@ export function queryRenderedFeatures(
wrappedTileID: tileResult.tile.tileID.wrapped().key,
queryResults: tileResult.tile.queryRenderedFeatures(
styleLayers,
- serializedLayers,
sourceCache._state,
tileResult,
- params,
+ filter,
+ layers,
+ availableImages,
transform,
getPixelPosMatrix(sourceCache.transform, tileResult.tile.tileID),
visualizeQueryGeometry)
@@ -93,9 +79,11 @@ export function queryRenderedFeatures(
if (!layer || layer.type === 'background' || layer.type === 'sky' || layer.type === 'slot') return;
- feature.source = layer.source;
- if (layer['source-layer']) {
- feature.sourceLayer = layer['source-layer'];
+ if (!isFQID(layerID)) {
+ feature.source = layer.source;
+ if (layer['source-layer']) {
+ feature.sourceLayer = layer['source-layer'];
+ }
}
feature.state = feature.id !== undefined ? sourceCache.getFeatureState(layer['source-layer'], feature.id) : {};
});
@@ -107,16 +95,11 @@ export function queryRenderedSymbols(
styleLayers: {
[_: string]: StyleLayer;
},
- serializedLayers: {
- [_: string]: StyleLayer;
- },
getLayerSourceCache: (layer: StyleLayer) => SourceCache | void,
queryGeometry: Array,
- params: {
- filter: FilterSpecification;
- layers: Array;
- availableImages: Array;
- },
+ filter: FilterSpecification,
+ layers: string[],
+ availableImages: Array,
collisionIndex: CollisionIndex,
retainedQueryData: {
[_: number]: RetainedQueryData;
@@ -133,12 +116,11 @@ export function queryRenderedSymbols(
for (const queryData of bucketQueryData) {
const bucketSymbols = queryData.featureIndex.lookupSymbolFeatures(
renderedSymbols[queryData.bucketInstanceId],
- serializedLayers,
queryData.bucketIndex,
queryData.sourceLayerIndex,
- params.filter,
- params.layers,
- params.availableImages,
+ filter,
+ layers,
+ availableImages,
styleLayers);
for (const layerID in bucketSymbols) {
@@ -179,11 +161,14 @@ export function queryRenderedSymbols(
if (!sourceCache) return;
const state = sourceCache.getFeatureState(feature.layer['source-layer'], feature.id);
- feature.source = feature.layer.source;
- if (feature.layer['source-layer']) {
- feature.sourceLayer = feature.layer['source-layer'];
- }
feature.state = state;
+
+ if (!isFQID(layer.id)) {
+ feature.source = feature.layer.source;
+ if (feature.layer['source-layer']) {
+ feature.sourceLayer = feature.layer['source-layer'];
+ }
+ }
});
}
return result;
@@ -193,7 +178,7 @@ export function querySourceFeatures(sourceCache: SourceCache, params?: {
sourceLayer?: string;
filter?: FilterSpecification;
validate?: boolean;
-}): Array {
+}): Array {
const tiles = sourceCache.getRenderableIds().map((id) => {
return sourceCache.getTileByID(id);
});
diff --git a/src/source/raster_array_tile.ts b/src/source/raster_array_tile.ts
index 7db52172149..5dcf16bde66 100644
--- a/src/source/raster_array_tile.ts
+++ b/src/source/raster_array_tile.ts
@@ -92,7 +92,7 @@ const FIRST_TRY_HEADER_LENGTH = 16384;
const MRT_DECODED_BAND_CACHE_SIZE = 30;
class RasterArrayTile extends Tile {
- texture: Texture | null | undefined;
+ override texture: Texture | null | undefined;
entireBuffer: ArrayBuffer | null | undefined;
requestParams: RequestParameters | null | undefined;
@@ -113,7 +113,7 @@ class RasterArrayTile extends Tile {
this._isHeaderLoaded = false;
}
- setTexture(img: TextureImage, painter: Painter) {
+ override setTexture(img: TextureImage, painter: Painter) {
const context = painter.context;
const gl = context.gl;
this.texture = this.texture || painter.getTileTexture(img.width);
diff --git a/src/source/raster_array_tile_source.ts b/src/source/raster_array_tile_source.ts
index f64546f783e..ed87ced656a 100644
--- a/src/source/raster_array_tile_source.ts
+++ b/src/source/raster_array_tile_source.ts
@@ -34,8 +34,8 @@ import type {RasterArraySourceSpecification} from '../style-spec/types';
* @see [Example: Create a wind particle animation](https://docs.mapbox.com/mapbox-gl-js/example/raster-particle-layer/)
*/
class RasterArrayTileSource extends RasterTileSource<'raster-array'> implements ISource {
- type: 'raster-array';
- map: Map;
+ override type: 'raster-array';
+ override map: Map;
rasterLayers: Array | undefined;
rasterLayerIds: Array | undefined;
@@ -58,7 +58,7 @@ class RasterArrayTileSource extends RasterTileSource<'raster-array'> implements
this.map.triggerRepaint();
}
- loadTile(tile: Tile, callback: Callback) {
+ override loadTile(tile: Tile, callback: Callback) {
tile = (tile as RasterArrayTile);
const url = this.map._requestManager.normalizeTileURL(tile.tileID.canonical.url(this.tiles, this.scheme), false, this.tileSize);
@@ -93,7 +93,7 @@ class RasterArrayTileSource extends RasterTileSource<'raster-array'> implements
});
}
- unloadTile(tile: Tile, _?: Callback | null) {
+ override unloadTile(tile: Tile, _?: Callback | null) {
tile = (tile as RasterArrayTile);
const texture = tile.texture;
diff --git a/src/source/raster_dem_tile_source.ts b/src/source/raster_dem_tile_source.ts
index b0c9205432a..0cce50b20db 100644
--- a/src/source/raster_dem_tile_source.ts
+++ b/src/source/raster_dem_tile_source.ts
@@ -18,7 +18,7 @@ import type {TextureImage} from '../render/texture';
import type {RasterDEMSourceSpecification} from '../style-spec/types';
class RasterDEMTileSource extends RasterTileSource<'raster-dem'> implements ISource {
- type: 'raster-dem';
+ override type: 'raster-dem';
encoding: 'mapbox' | 'terrarium';
constructor(id: string, options: RasterDEMSourceSpecification, dispatcher: Dispatcher, eventedParent: Evented) {
@@ -29,7 +29,7 @@ class RasterDEMTileSource extends RasterTileSource<'raster-dem'> implements ISou
this.encoding = options.encoding || "mapbox";
}
- loadTile(tile: Tile, callback: Callback) {
+ override loadTile(tile: Tile, callback: Callback) {
const url = this.map._requestManager.normalizeTileURL(tile.tileID.canonical.url(this.tiles, this.scheme), false, this.tileSize);
tile.request = getImage(this.map._requestManager.transformRequest(url, ResourceType.Tile), imageLoaded.bind(this));
diff --git a/src/source/source_state.ts b/src/source/source_state.ts
index 5a31be1631d..199869e1ea4 100644
--- a/src/source/source_state.ts
+++ b/src/source/source_state.ts
@@ -86,16 +86,15 @@ class SourceFeatureState {
}
}
- getState(sourceLayer: string, featureId: number | string | undefined): FeatureState {
+ getState(sourceLayer: string, featureId?: number | string): FeatureState | FeatureStates {
const base = this.state[sourceLayer] || {};
const changes = this.stateChanges[sourceLayer] || {};
const deletedStates = this.deletedStates[sourceLayer];
- //return empty object if the whole source layer is awaiting deletion
+ // return empty object if the whole source layer is awaiting deletion
if (deletedStates === null) return {};
if (featureId !== undefined) {
const feature = String(featureId);
-
const reconciledState = extend({}, base[feature], changes[feature]);
if (deletedStates) {
@@ -103,6 +102,7 @@ class SourceFeatureState {
if (featureDeletions === null) return {};
for (const prop in featureDeletions) delete reconciledState[prop];
}
+
return reconciledState;
}
@@ -110,11 +110,12 @@ class SourceFeatureState {
if (deletedStates) {
for (const feature in deletedStates) delete reconciledState[feature];
}
+
return reconciledState;
}
initializeTileState(tile: Tile, painter?: Painter | null) {
- tile.setFeatureState(this.state, painter);
+ tile.refreshFeatureState(painter);
}
coalesceChanges(tiles: Record, painter: Painter) {
@@ -165,7 +166,7 @@ class SourceFeatureState {
for (const id in tiles) {
const tile = tiles[id];
- tile.setFeatureState(featuresChanged, painter);
+ tile.refreshFeatureState(painter);
}
}
}
diff --git a/src/source/tile.ts b/src/source/tile.ts
index 9f9c7b381cf..fb914090d0d 100644
--- a/src/source/tile.ts
+++ b/src/source/tile.ts
@@ -43,8 +43,7 @@ import type Context from '../gl/context';
import type {CanonicalTileID, OverscaledTileID} from './tile_id';
import type Framebuffer from '../gl/framebuffer';
import type Transform from '../geo/transform';
-import type {GeoJSONFeature} from '../util/vectortile_to_geojson';
-import type {LayerFeatureStates} from './source_state';
+import type {FeatureStates} from './source_state';
import type {Cancelable} from '../types/cancelable';
import type {FilterSpecification} from '../style-spec/types';
import type {TilespaceQueryGeometry} from '../style/query_geometry';
@@ -441,16 +440,11 @@ class Tile {
layers: {
[_: string]: StyleLayer;
},
- serializedLayers: {
- [key: string]: any;
- },
sourceFeatureState: SourceFeatureState,
tileResult: TilespaceQueryGeometry,
- params: {
- filter: FilterSpecification;
- layers: Array;
- availableImages: Array;
- },
+ filter: FilterSpecification,
+ layerIds: string[],
+ availableImages: Array,
transform: Transform,
pixelPosMatrix: Float32Array,
visualizeQueryGeometry: boolean,
@@ -478,12 +472,14 @@ class Tile {
tileResult,
pixelPosMatrix,
transform,
- params,
+ filter,
+ layers: layerIds,
+ availableImages,
tileTransform: this.tileTransform
- }, layers, serializedLayers, sourceFeatureState);
+ }, layers, sourceFeatureState);
}
- querySourceFeatures(result: Array, params?: {
+ querySourceFeatures(result: Array, params?: {
sourceLayer?: string;
filter?: FilterSpecification;
validate?: boolean;
@@ -587,11 +583,8 @@ class Tile {
}
}
- setFeatureState(states: LayerFeatureStates, painter?: Painter | null) {
- if (!this.latestFeatureIndex ||
- !this.latestFeatureIndex.rawTileData ||
- Object.keys(states).length === 0 ||
- !painter) {
+ refreshFeatureState(painter?: Painter) {
+ if (!this.latestFeatureIndex || !this.latestFeatureIndex.rawTileData || !painter) {
return;
}
@@ -608,13 +601,15 @@ class Tile {
if (!painter.style.hasLayer(id)) continue;
const bucket = this.buckets[id];
+ const bucketLayer = bucket.layers[0] as StyleLayer;
// Buckets are grouped by common source-layer
- const sourceLayerId = bucket.layers[0]['sourceLayer'] || '_geojsonTileLayer';
+ const sourceLayerId = bucketLayer['sourceLayer'] || '_geojsonTileLayer';
const sourceLayer = vtLayers[sourceLayerId];
- const sourceCache = painter.style.getOwnSourceCache(bucket.layers[0].source);
- let sourceLayerStates: Record = {};
+ const sourceCache = painter.style.getSourceCache(bucketLayer.source, bucketLayer.scope);
+
+ let sourceLayerStates: FeatureStates = {};
if (sourceCache) {
- sourceLayerStates = sourceCache._state.getState(sourceLayerId, undefined);
+ sourceLayerStates = sourceCache._state.getState(sourceLayerId, undefined) as FeatureStates;
}
const imagePositions: SpritePositions = (this.imageAtlas && this.imageAtlas.patternPositions) || {};
@@ -771,13 +766,13 @@ class Tile {
y: number,
id: CanonicalTileID,
tr: Transform,
- normalizationMatrix: Float64Array,
- worldToECEFMatrix: Float64Array | null | undefined,
+ normalizationMatrix: mat4,
+ worldToECEFMatrix: mat4 | null | undefined,
phase: number,
): vec3 {
// The following is equivalent to doing globe.projectTilePoint.
// This way we don't recompute the normalization matrix everytime since it remains the same for all points.
- let ecef = tileCoordToECEF(x, y, id);
+ let ecef = tileCoordToECEF(x, y, id) as vec3;
if (worldToECEFMatrix) {
// When in globe-to-Mercator transition, interpolate between globe and Mercator positions in ECEF
const tileCount = 1 << id.z;
@@ -799,18 +794,15 @@ class Tile {
let mercatorY = (y / EXTENT + id.y) / tileCount;
mercatorX = (mercatorX - camX) * tr._pixelsPerMercatorPixel + camX;
mercatorY = (mercatorY - camY) * tr._pixelsPerMercatorPixel + camY;
- const mercatorPos = [mercatorX * tr.worldSize, mercatorY * tr.worldSize, 0];
- // @ts-expect-error - TS2345 - Argument of type 'Float64Array' is not assignable to parameter of type 'ReadonlyMat4'.
- vec3.transformMat4(mercatorPos as [number, number, number], mercatorPos as [number, number, number], worldToECEFMatrix);
- // @ts-expect-error - TS2345 - Argument of type 'number[]' is not assignable to parameter of type 'vec3'.
+ const mercatorPos: vec3 = [mercatorX * tr.worldSize, mercatorY * tr.worldSize, 0];
+ vec3.transformMat4(mercatorPos, mercatorPos, worldToECEFMatrix as unknown as mat4);
ecef = interpolateVec3(ecef, mercatorPos, phase);
}
- // @ts-expect-error - TS2345 - Argument of type 'Float64Array' is not assignable to parameter of type 'ReadonlyMat4'.
- const gp = vec3.transformMat4(ecef, ecef, normalizationMatrix);
+ const gp = vec3.transformMat4(ecef, ecef, normalizationMatrix as unknown as mat4);
return gp;
}
- _makeGlobeTileDebugBorderBuffer(context: Context, id: CanonicalTileID, tr: Transform, normalizationMatrix: Float64Array, worldToECEFMatrix: Float64Array | null | undefined, phase: number) {
+ _makeGlobeTileDebugBorderBuffer(context: Context, id: CanonicalTileID, tr: Transform, normalizationMatrix: mat4, worldToECEFMatrix: mat4 | null | undefined, phase: number) {
const vertices = new PosArray();
const indices = new LineStripIndexArray();
const extraGlobe = new PosGlobeExtArray();
@@ -845,7 +837,7 @@ class Tile {
this._tileDebugSegments = SegmentVector.simpleSegment(0, 0, vertices.length, indices.length);
}
- _makeGlobeTileDebugTextBuffer(context: Context, id: CanonicalTileID, tr: Transform, normalizationMatrix: Float64Array, worldToECEFMatrix: Float64Array | null | undefined, phase: number) {
+ _makeGlobeTileDebugTextBuffer(context: Context, id: CanonicalTileID, tr: Transform, normalizationMatrix: mat4, worldToECEFMatrix: mat4 | null | undefined, phase: number) {
const SEGMENTS = 4;
const numVertices = SEGMENTS + 1;
const step = EXTENT / SEGMENTS;
diff --git a/src/source/tile_id.ts b/src/source/tile_id.ts
index 72ff62f9a72..e3258e8a058 100644
--- a/src/source/tile_id.ts
+++ b/src/source/tile_id.ts
@@ -2,6 +2,8 @@ import {getTileBBox} from '@mapbox/whoots-js';
import assert from 'assert';
import {register} from '../util/web_worker_transfer';
+import type {mat4} from 'gl-matrix';
+
export class CanonicalTileID {
z: number;
x: number;
@@ -58,8 +60,8 @@ export class OverscaledTileID {
wrap: number;
canonical: CanonicalTileID;
key: number;
- projMatrix: Float32Array;
- expandedProjMatrix: Float32Array;
+ projMatrix: mat4;
+ expandedProjMatrix: mat4;
visibleQuadrants?: number;
constructor(overscaledZ: number, wrap: number, z: number, x: number, y: number) {
diff --git a/src/source/vector_tile_source.ts b/src/source/vector_tile_source.ts
index 8e222d99fdf..8e15e05fe8d 100644
--- a/src/source/vector_tile_source.ts
+++ b/src/source/vector_tile_source.ts
@@ -246,7 +246,8 @@ class VectorTileSource extends Evented implements ISource {
isSymbolTile: tile.isSymbolTile,
brightness: this.map.style ? (this.map.style.getBrightness() || 0.0) : 0.0,
extraShadowCaster: tile.isExtraShadowCaster,
- tessellationStep: this.map._tessellationStep
+ tessellationStep: this.map._tessellationStep,
+ scaleFactor: this.map.getScaleFactor(),
};
params.request.collectResourceTiming = this._collectResourceTiming;
diff --git a/src/source/vector_tile_worker_source.ts b/src/source/vector_tile_worker_source.ts
index 1c0adccce49..8b751722299 100644
--- a/src/source/vector_tile_worker_source.ts
+++ b/src/source/vector_tile_worker_source.ts
@@ -145,6 +145,7 @@ class VectorTileWorkerSource extends Evented implements WorkerSource {
if (loaded && loaded[uid]) {
const workerTile = loaded[uid];
+ workerTile.scaleFactor = params.scaleFactor;
workerTile.showCollisionBoxes = params.showCollisionBoxes;
workerTile.projection = params.projection;
workerTile.brightness = params.brightness;
diff --git a/src/source/video_source.ts b/src/source/video_source.ts
index 99daf95aac2..4e79cbd257c 100644
--- a/src/source/video_source.ts
+++ b/src/source/video_source.ts
@@ -42,8 +42,8 @@ import type {VideoSourceSpecification} from '../style-spec/types';
* @see [Example: Add a video](https://www.mapbox.com/mapbox-gl-js/example/video-on-a-map/)
*/
class VideoSource extends ImageSource<'video'> {
- type: 'video';
- options: VideoSourceSpecification;
+ override type: 'video';
+ override options: VideoSourceSpecification;
urls: Array;
video: HTMLVideoElement;
@@ -57,7 +57,7 @@ class VideoSource extends ImageSource<'video'> {
this.options = options;
}
- load() {
+ override load() {
this._loaded = false;
const options = this.options;
@@ -151,7 +151,7 @@ class VideoSource extends ImageSource<'video'> {
return this.video;
}
- onAdd(map: Map) {
+ override onAdd(map: Map) {
if (this.map) return;
this.map = map;
this.load();
@@ -195,7 +195,7 @@ class VideoSource extends ImageSource<'video'> {
*/
// setCoordinates inherited from ImageSource
- prepare() {
+ override prepare() {
if (Object.keys(this.tiles).length === 0 || this.video.readyState < 2) {
return; // not enough data for current position
}
@@ -216,7 +216,7 @@ class VideoSource extends ImageSource<'video'> {
this._prepareData(context);
}
- serialize(): VideoSourceSpecification {
+ override serialize(): VideoSourceSpecification {
return {
type: 'video',
urls: this.urls,
@@ -224,7 +224,7 @@ class VideoSource extends ImageSource<'video'> {
};
}
- hasTransition(): boolean {
+ override hasTransition(): boolean {
return this.video && !this.video.paused;
}
}
diff --git a/src/source/worker_source.ts b/src/source/worker_source.ts
index 5234815dcbb..f8f5cd4b7bb 100644
--- a/src/source/worker_source.ts
+++ b/src/source/worker_source.ts
@@ -41,6 +41,7 @@ export type WorkerTileParameters = RequestedTileParameters & {
collectResourceTiming?: boolean;
projection: Projection;
brightness: number;
+ scaleFactor: number;
extraShadowCaster?: boolean;
tessellationStep?: number // test purpose only;
partial?: boolean;
diff --git a/src/source/worker_tile.ts b/src/source/worker_tile.ts
index 2af374bcb00..e4b662332ad 100644
--- a/src/source/worker_tile.ts
+++ b/src/source/worker_tile.ts
@@ -15,6 +15,7 @@ import EvaluationParameters from '../style/evaluation_parameters';
import {OverscaledTileID} from './tile_id';
import {PerformanceUtils} from '../util/performance';
import tileTransform from '../geo/projection/tile_transform';
+import {makeFQID} from "../util/fqid";
import type {CanonicalTileID} from './tile_id';
import type Projection from '../geo/projection/projection';
@@ -55,6 +56,7 @@ class WorkerTile {
projection: Projection;
tileTransform: TileTransform;
brightness: number;
+ scaleFactor: number;
status: 'parsing' | 'done';
data: VectorTile;
@@ -85,6 +87,7 @@ class WorkerTile {
this.brightness = params.brightness;
this.extraShadowCaster = !!params.extraShadowCaster;
this.tessellationStep = params.tessellationStep;
+ this.scaleFactor = params.scaleFactor;
}
parse(data: VectorTile, layerIndex: StyleLayerIndex, availableImages: Array, actor: Actor, callback: WorkerTileCallback) {
@@ -193,7 +196,7 @@ class WorkerTile {
assert(this.tileTransform.projection.name === this.projection.name);
bucket.populate(features, options, this.tileID.canonical, this.tileTransform);
- featureIndex.bucketLayerIDs.push(family.map((l) => l.id));
+ featureIndex.bucketLayerIDs.push(family.map((l) => makeFQID(l.id, l.scope)));
}
}
@@ -257,6 +260,7 @@ class WorkerTile {
this.tileID.canonical,
this.tileZoom,
this.projection,
+ this.scaleFactor,
this.brightness);
} else if (bucket.hasPattern &&
(bucket instanceof LineBucket ||
diff --git a/src/style-spec/expression/definitions/at.ts b/src/style-spec/expression/definitions/at.ts
index 09d7f085bde..dae046a4721 100644
--- a/src/style-spec/expression/definitions/at.ts
+++ b/src/style-spec/expression/definitions/at.ts
@@ -40,15 +40,28 @@ class At implements Expression {
throw new RuntimeError(`Array index out of bounds: ${index} < 0.`);
}
- if (index >= array.length) {
+ if (index > array.length - 1) {
throw new RuntimeError(`Array index out of bounds: ${index} > ${array.length - 1}.`);
}
- if (index !== Math.floor(index)) {
- throw new RuntimeError(`Array index must be an integer, but found ${index} instead.`);
+ if (index === Math.floor(index)) {
+ return array[index];
}
- return array[index];
+ // Interpolation logic for non-integer indices
+ const lowerIndex = Math.floor(index);
+ const upperIndex = Math.ceil(index);
+
+ const lowerValue = array[lowerIndex];
+ const upperValue = array[upperIndex];
+
+ if (typeof lowerValue !== 'number' || typeof upperValue !== 'number') {
+ throw new RuntimeError(`Cannot interpolate between non-number values at index ${index}.`);
+ }
+
+ // Linear interpolation
+ const fraction = index - lowerIndex;
+ return lowerValue * (1 - fraction) + upperValue * fraction;
}
eachChild(fn: (_: Expression) => void) {
diff --git a/src/style-spec/expression/definitions/distance.ts b/src/style-spec/expression/definitions/distance.ts
index a9fc5922cb3..791d90f8d68 100644
--- a/src/style-spec/expression/definitions/distance.ts
+++ b/src/style-spec/expression/definitions/distance.ts
@@ -80,20 +80,18 @@ function splitRange(range: IndexRange, isLine: boolean) {
}
function getBBox(pointSets: Array, range: IndexRange) {
- const bbox = [Infinity, Infinity, -Infinity, -Infinity];
+ const bbox: BBox = [Infinity, Infinity, -Infinity, -Infinity];
if (!isRangeSafe(range, pointSets.length)) return bbox;
for (let i = range[0]; i <= range[1]; ++i) {
- // @ts-expect-error - TS2345 - Argument of type 'number[]' is not assignable to parameter of type 'BBox'.
updateBBox(bbox, pointSets[i]);
}
return bbox;
}
function getPolygonBBox(polygon: Array>) {
- const bbox = [Infinity, Infinity, -Infinity, -Infinity];
+ const bbox: BBox = [Infinity, Infinity, -Infinity, -Infinity];
for (let i = 0; i < polygon.length; ++i) {
for (let j = 0; j < polygon[i].length; ++j) {
- // @ts-expect-error - TS2345 - Argument of type 'number[]' is not assignable to parameter of type 'BBox'.
updateBBox(bbox, polygon[i][j]);
}
}
@@ -263,11 +261,9 @@ function polygonIntersect(polygon1: Array>, polygon2: Ar
function polygonToPolygonDistance(polygon1: Array>, polygon2: Array>, ruler: CheapRuler, currentMiniDist: number = Infinity) {
const bbox1 = getPolygonBBox(polygon1);
const bbox2 = getPolygonBBox(polygon2);
- // @ts-expect-error - TS2345 - Argument of type 'number[]' is not assignable to parameter of type 'BBox'.
if (currentMiniDist !== Infinity && bboxToBBoxDistance(bbox1, bbox2, ruler) >= currentMiniDist) {
return currentMiniDist;
}
- // @ts-expect-error - TS2345 - Argument of type 'number[]' is not assignable to parameter of type 'BBox'.
if (boxWithinBox(bbox1, bbox2)) {
if (polygonIntersect(polygon1, polygon2)) return 0.0;
} else if (polygonIntersect(polygon2, polygon1)) {
@@ -289,7 +285,6 @@ function polygonToPolygonDistance(polygon1: Array>, poly
function updateQueue(distQueue: any, miniDist: number, ruler: CheapRuler, pointSet1: Array, pointSet2: Array, r1: IndexRange | null, r2: IndexRange | null) {
if (r1 === null || r2 === null) return;
- // @ts-expect-error - TS2345 - Argument of type 'number[]' is not assignable to parameter of type 'BBox'.
const tempDist = bboxToBBoxDistance(getBBox(pointSet1, r1), getBBox(pointSet2, r2), ruler);
// Insert new pair to the queue if the bbox distance is less than miniDist, the pair with biggest distance will be at the top
if (tempDist < miniDist) distQueue.push({dist: tempDist, range1: r1, range2: r2});
@@ -330,12 +325,10 @@ function pointSetToPolygonDistance(pointSets: Array, isLine: b
} else {
const newRanges = splitRange(range, isLine);
if (newRanges[0] !== null) {
- // @ts-expect-error - TS2345 - Argument of type 'number[]' is not assignable to parameter of type 'BBox'.
const tempDist = bboxToBBoxDistance(getBBox(pointSets, newRanges[0]), polyBBox, ruler);
if (tempDist < miniDist) distQueue.push({dist: tempDist, range1: newRanges[0], range2: [0, 0]});
}
if (newRanges[1] !== null) {
- // @ts-expect-error - TS2345 - Argument of type 'number[]' is not assignable to parameter of type 'BBox'.
const tempDist = bboxToBBoxDistance(getBBox(pointSets, newRanges[1]), polyBBox, ruler);
if (tempDist < miniDist) distQueue.push({dist: tempDist, range1: newRanges[1], range2: [0, 0]});
}
@@ -394,7 +387,6 @@ function pointSetToLinesDistance(pointSet: Array, isLine: bool
let dist = currentMiniDist;
const bbox1 = getBBox(pointSet, [0, pointSet.length - 1]);
for (const line of lines) {
- // @ts-expect-error - TS2345 - Argument of type 'number[]' is not assignable to parameter of type 'BBox'.
if (dist !== Infinity && bboxToBBoxDistance(bbox1, getBBox(line, [0, line.length - 1]), ruler) >= dist) continue;
dist = Math.min(dist, pointSetsDistance(pointSet, isLine, line, true /*isLine*/, ruler, dist));
if (dist === 0.0) return dist;
@@ -406,7 +398,6 @@ function pointSetToPolygonsDistance(points: Array, isLine: boo
let dist = currentMiniDist;
const bbox1 = getBBox(points, [0, points.length - 1]);
for (const polygon of polygons) {
- // @ts-expect-error - TS2345 - Argument of type 'number[]' is not assignable to parameter of type 'BBox'.
if (dist !== Infinity && bboxToBBoxDistance(bbox1, getPolygonBBox(polygon), ruler) >= dist) continue;
const tempDist = pointSetToPolygonDistance(points, isLine, polygon, ruler, dist);
if (isNaN(tempDist)) return tempDist;
diff --git a/src/style-spec/expression/definitions/within.ts b/src/style-spec/expression/definitions/within.ts
index 01cc5bd484e..a6f4102563d 100644
--- a/src/style-spec/expression/definitions/within.ts
+++ b/src/style-spec/expression/definitions/within.ts
@@ -155,8 +155,8 @@ function getTileLines(geometry: Array> | null | undefined, lineBBox
}
function pointsWithinPolygons(ctx: EvaluationContext, polygonGeometry: GeoJSONPolygons) {
- const pointBBox = [Infinity, Infinity, -Infinity, -Infinity];
- const polyBBox = [Infinity, Infinity, -Infinity, -Infinity];
+ const pointBBox: BBox = [Infinity, Infinity, -Infinity, -Infinity];
+ const polyBBox: BBox = [Infinity, Infinity, -Infinity, -Infinity];
const canonical = ctx.canonicalID();
if (!canonical) {
@@ -164,11 +164,8 @@ function pointsWithinPolygons(ctx: EvaluationContext, polygonGeometry: GeoJSONPo
}
if (polygonGeometry.type === 'Polygon') {
- // @ts-expect-error - TS2345 - Argument of type 'number[]' is not assignable to parameter of type 'BBox'.
const tilePolygon = getTilePolygon(polygonGeometry.coordinates, polyBBox, canonical);
- // @ts-expect-error - TS2345 - Argument of type 'number[]' is not assignable to parameter of type 'BBox'.
const tilePoints = getTilePoints(ctx.geometry(), pointBBox, polyBBox, canonical);
- // @ts-expect-error - TS2345 - Argument of type 'number[]' is not assignable to parameter of type 'BBox'.
if (!boxWithinBox(pointBBox, polyBBox)) return false;
for (const point of tilePoints) {
@@ -176,11 +173,8 @@ function pointsWithinPolygons(ctx: EvaluationContext, polygonGeometry: GeoJSONPo
}
}
if (polygonGeometry.type === 'MultiPolygon') {
- // @ts-expect-error - TS2345 - Argument of type 'number[]' is not assignable to parameter of type 'BBox'.
const tilePolygons = getTilePolygons(polygonGeometry.coordinates, polyBBox, canonical);
- // @ts-expect-error - TS2345 - Argument of type 'number[]' is not assignable to parameter of type 'BBox'.
const tilePoints = getTilePoints(ctx.geometry(), pointBBox, polyBBox, canonical);
- // @ts-expect-error - TS2345 - Argument of type 'number[]' is not assignable to parameter of type 'BBox'.
if (!boxWithinBox(pointBBox, polyBBox)) return false;
for (const point of tilePoints) {
@@ -192,8 +186,8 @@ function pointsWithinPolygons(ctx: EvaluationContext, polygonGeometry: GeoJSONPo
}
function linesWithinPolygons(ctx: EvaluationContext, polygonGeometry: GeoJSONPolygons) {
- const lineBBox = [Infinity, Infinity, -Infinity, -Infinity];
- const polyBBox = [Infinity, Infinity, -Infinity, -Infinity];
+ const lineBBox: BBox = [Infinity, Infinity, -Infinity, -Infinity];
+ const polyBBox: BBox = [Infinity, Infinity, -Infinity, -Infinity];
const canonical = ctx.canonicalID();
if (!canonical) {
@@ -201,11 +195,8 @@ function linesWithinPolygons(ctx: EvaluationContext, polygonGeometry: GeoJSONPol
}
if (polygonGeometry.type === 'Polygon') {
- // @ts-expect-error - TS2345 - Argument of type 'number[]' is not assignable to parameter of type 'BBox'.
const tilePolygon = getTilePolygon(polygonGeometry.coordinates, polyBBox, canonical);
- // @ts-expect-error - TS2345 - Argument of type 'number[]' is not assignable to parameter of type 'BBox'.
const tileLines = getTileLines(ctx.geometry(), lineBBox, polyBBox, canonical);
- // @ts-expect-error - TS2345 - Argument of type 'number[]' is not assignable to parameter of type 'BBox'.
if (!boxWithinBox(lineBBox, polyBBox)) return false;
for (const line of tileLines) {
@@ -213,11 +204,8 @@ function linesWithinPolygons(ctx: EvaluationContext, polygonGeometry: GeoJSONPol
}
}
if (polygonGeometry.type === 'MultiPolygon') {
- // @ts-expect-error - TS2345 - Argument of type 'number[]' is not assignable to parameter of type 'BBox'.
const tilePolygons = getTilePolygons(polygonGeometry.coordinates, polyBBox, canonical);
- // @ts-expect-error - TS2345 - Argument of type 'number[]' is not assignable to parameter of type 'BBox'.
const tileLines = getTileLines(ctx.geometry(), lineBBox, polyBBox, canonical);
- // @ts-expect-error - TS2345 - Argument of type 'number[]' is not assignable to parameter of type 'BBox'.
if (!boxWithinBox(lineBBox, polyBBox)) return false;
for (const line of tileLines) {
@@ -238,9 +226,8 @@ class Within implements Expression {
this.geometries = geometries;
}
- static parse(args: ReadonlyArray, context: ParsingContext): Within | null | undefined {
+ static parse(args: ReadonlyArray, context: ParsingContext): Within | void {
if (args.length !== 2)
- // @ts-expect-error - TS2322 - Type 'void' is not assignable to type 'Within'.
return context.error(`'within' expression requires exactly one argument, but found ${args.length - 1} instead.`);
if (isValue(args[1])) {
const geojson = (args[1] as any);
@@ -256,11 +243,10 @@ class Within implements Expression {
if (type === 'Polygon' || type === 'MultiPolygon') {
return new Within(geojson, geojson.geometry);
}
- } else if (geojson.type === 'Polygon' || geojson.type === 'MultiPolygon') {
+ } else if (geojson.type === 'Polygon' || geojson.type === 'MultiPolygon') {
return new Within(geojson, geojson);
}
}
- // @ts-expect-error - TS2322 - Type 'void' is not assignable to type 'Within'.
return context.error(`'within' expression requires valid geojson object that contains polygon geometry type.`);
}
diff --git a/src/style-spec/expression/parsing_error.ts b/src/style-spec/expression/parsing_error.ts
index b381fe4bc92..4d1a9529669 100644
--- a/src/style-spec/expression/parsing_error.ts
+++ b/src/style-spec/expression/parsing_error.ts
@@ -1,6 +1,6 @@
class ParsingError extends Error {
key: string;
- message: string;
+ override message: string;
constructor(key: string, message: string) {
super(message);
this.message = message;
diff --git a/src/style-spec/package.json b/src/style-spec/package.json
index ada4af95991..99217ce3596 100644
--- a/src/style-spec/package.json
+++ b/src/style-spec/package.json
@@ -1,6 +1,6 @@
{
"name": "@mapbox/mapbox-gl-style-spec",
- "version": "14.7.1",
+ "version": "14.8.0-beta.1",
"description": "a specification for mapbox gl styles",
"author": "Mapbox",
"license": "SEE LICENSE IN LICENSE.txt",
diff --git a/src/style-spec/reference/v8.json b/src/style-spec/reference/v8.json
index 092f69a5ef7..cbd963e024d 100644
--- a/src/style-spec/reference/v8.json
+++ b/src/style-spec/reference/v8.json
@@ -1322,7 +1322,6 @@
},
"clip": {
"doc": "Layer that removes 3D content from map.",
- "experimental": true,
"sdk-support": {
"basic functionality": {
"js": "3.5.0",
@@ -1915,7 +1914,11 @@
"line-z-offset": {
"type": "number",
"experimental": true,
- "doc": "Vertical offset from ground, in meters. Defaults to 0. Not supported for globe projection at the moment.",
+ "doc": "Vertical offset from ground, in meters. Defaults to 0. This is an experimental property with some known issues:\n * Not supported for globe projection at the moment \n * Elevated line discontinuity is possible on tile borders with terrain enabled \n * Rendering artifacts can happen near line joins and line caps depending on the line styling \n * Rendering artifacts relating to `line-opacity` and `line-blur` \n * Elevated line visibility is determined by layer order \n * Z-fighting issues can happen with intersecting elevated lines \n * Elevated lines don't cast shadows",
+ "default": 0,
+ "requires": [
+ "line-elevation-reference"
+ ],
"sdk-support": {
"basic functionality": {
"js": "3.5.0",
@@ -1938,6 +1941,57 @@
},
"property-type": "data-driven"
},
+ "line-elevation-reference": {
+ "type": "enum",
+ "doc": "Selects the base of line-elevation. Some modes might require precomputed elevation data in the tileset.",
+ "values": {
+ "none": {
+ "doc": "Elevated rendering is disabled."
+ },
+ "sea": {
+ "doc": "Elevated rendering is enabled. Use this mode to elevate lines relative to the sea level."
+ },
+ "ground": {
+ "doc": "Elevated rendering is enabled. Use this mode to elevate lines relative to the ground's height below them."
+ },
+ "hd-road-markup": {
+ "doc": "Elevated rendering is enabled. Use this mode to describe additive and stackable features that should exist only on top of road polygons."
+ }
+ },
+ "default": "none",
+ "experimental": true,
+ "transition": false,
+ "sdk-support": {
+ "basic functionality": {
+ "js": "3.8.0",
+ "android": "11.9.0",
+ "ios": "11.9.0"
+ }
+ },
+ "expression": {
+ "interpolated": false
+ },
+ "property-type": "data-constant"
+ },
+ "line-cross-slope": {
+ "type": "number",
+ "experimental": true,
+ "doc": "Defines the slope of an elevated line. A value of 0 creates a horizontal line. A value of 1 creates a vertical line. Other values are currently not supported. If undefined, the line follows the terrain slope. This is an experimental property with some known issues:\n * Vertical lines don't support line caps \n * `line-join: round` is not supported with this property",
+ "requires": [
+ "line-z-offset"
+ ],
+ "sdk-support": {
+ "basic functionality": {
+ "js": "3.8.0",
+ "android": "11.9.0",
+ "ios": "11.9.0"
+ }
+ },
+ "expression": {
+ "interpolated": false
+ },
+ "property-type": "constant"
+ },
"visibility": {
"type": "enum",
"values": {
@@ -2269,6 +2323,31 @@
},
"property-type": "data-driven"
},
+ "icon-size-scale-range": {
+ "type": "array",
+ "value": "number",
+ "length": 2,
+ "default": [
+ 0.8,
+ 2
+ ],
+ "doc": "Defines the minimum and maximum scaling factors for icon related properties like `icon-size`, `icon-halo-width`, `icon-halo-blur`",
+ "minimum": 0.1,
+ "maximum": 10,
+ "experimental": true,
+ "private": true,
+ "expression": {
+ "interpolated": false
+ },
+ "sdk-support": {
+ "basic functionality": {
+ "js": "3.8.0",
+ "android": "11.8.0",
+ "ios": "11.8.0"
+ }
+ },
+ "property-type": "data-constant"
+ },
"icon-text-fit": {
"type": "enum",
"values": {
@@ -2758,6 +2837,31 @@
},
"property-type": "data-driven"
},
+ "text-size-scale-range": {
+ "type": "array",
+ "value": "number",
+ "length": 2,
+ "default": [
+ 0.8,
+ 2
+ ],
+ "doc": "Defines the minimum and maximum scaling factors for text related properties like `text-size`, `text-max-width`, `text-halo-width`, `font-size`",
+ "minimum": 0.1,
+ "maximum": 10,
+ "experimental": true,
+ "private": true,
+ "expression": {
+ "interpolated": false
+ },
+ "sdk-support": {
+ "basic functionality": {
+ "js": "3.8.0",
+ "android": "11.8.0",
+ "ios": "11.8.0"
+ }
+ },
+ "property-type": "data-constant"
+ },
"text-max-width": {
"type": "number",
"default": 10,
@@ -4952,6 +5056,360 @@
}
}
},
+ "snow": {
+ "density": {
+ "type": "number",
+ "property-type": "data-constant",
+ "default": 1,
+ "minimum": 0,
+ "maximum": 1,
+ "experimental": true,
+ "expression": {
+ "interpolated": true,
+ "parameters": [
+ "zoom",
+ "measure-light"
+ ],
+ "relaxZoomRestriction": true
+ },
+ "transition": true,
+ "doc": "Snow particles density.",
+ "sdk-support": {
+ "basic functionality": {
+ "android": "11.8.0",
+ "ios": "11.8.0"
+ }
+ }
+ },
+ "intensity": {
+ "type": "number",
+ "property-type": "data-constant",
+ "default": 1,
+ "minimum": 0,
+ "maximum": 1,
+ "experimental": true,
+ "expression": {
+ "interpolated": true,
+ "parameters": [
+ "zoom",
+ "measure-light"
+ ],
+ "relaxZoomRestriction": true
+ },
+ "transition": true,
+ "doc": "Snow particles movement factor.",
+ "sdk-support": {
+ "basic functionality": {
+ "android": "11.8.0",
+ "ios": "11.8.0"
+ }
+ }
+ },
+ "color": {
+ "type": "color",
+ "property-type": "data-constant",
+ "default": "#ffffff",
+ "experimental": true,
+ "expression": {
+ "interpolated": true,
+ "parameters": [
+ "zoom",
+ "measure-light"
+ ],
+ "relaxZoomRestriction": true
+ },
+ "transition": true,
+ "doc": "Snow particles color.",
+ "sdk-support": {
+ "basic functionality": {
+ "android": "11.8.0",
+ "ios": "11.8.0"
+ }
+ }
+ },
+ "opacity": {
+ "type": "number",
+ "property-type": "data-constant",
+ "default": 1,
+ "minimum": 0,
+ "maximum": 1,
+ "experimental": true,
+ "expression": {
+ "interpolated": true,
+ "parameters": [
+ "zoom",
+ "measure-light"
+ ],
+ "relaxZoomRestriction": true
+ },
+ "transition": true,
+ "doc": "Snow particles opacity.",
+ "sdk-support": {
+ "basic functionality": {
+ "android": "11.8.0",
+ "ios": "11.8.0"
+ }
+ }
+ },
+ "vignette": {
+ "type": "number",
+ "property-type": "data-constant",
+ "default": 0,
+ "minimum": 0,
+ "maximum": 1,
+ "experimental": true,
+ "expression": {
+ "interpolated": true,
+ "parameters": [
+ "zoom",
+ "measure-light"
+ ],
+ "relaxZoomRestriction": true
+ },
+ "transition": true,
+ "doc": "Snow vignette screen-space effect.",
+ "sdk-support": {
+ "basic functionality": {
+ "android": "11.8.0",
+ "ios": "11.8.0"
+ }
+ }
+ },
+ "centerThinning": {
+ "type": "number",
+ "property-type": "data-constant",
+ "default": 1,
+ "minimum": 0,
+ "maximum": 1,
+ "experimental": true,
+ "expression": {
+ "interpolated": true,
+ "parameters": [
+ "zoom",
+ "measure-light"
+ ],
+ "relaxZoomRestriction": true
+ },
+ "transition": true,
+ "doc": "Thinning factor of snow particles from center. 0 - no thinning. 1 - maximal central area thinning.",
+ "sdk-support": {
+ "basic functionality": {
+ "android": "11.8.0",
+ "ios": "11.8.0"
+ }
+ }
+ },
+ "direction": {
+ "type": "array",
+ "default": [
+ 0.0,
+ 90.0
+ ],
+ "minimum": 0,
+ "maximum": 360,
+ "length": 2,
+ "value": "number",
+ "property-type": "data-constant",
+ "transition": true,
+ "experimental": true,
+ "expression": {
+ "interpolated": true,
+ "parameters": [
+ "zoom",
+ "measure-light"
+ ],
+ "relaxZoomRestriction": true
+ },
+ "doc": "Main snow particles direction. Heading & pitch",
+ "example": [
+ 0,
+ 45
+ ],
+ "sdk-support": {
+ "basic functionality": {
+ "android": "11.8.0",
+ "ios": "11.8.0"
+ }
+ }
+ }
+ },
+ "rain": {
+ "density": {
+ "type": "number",
+ "property-type": "data-constant",
+ "default": 1,
+ "minimum": 0,
+ "maximum": 1,
+ "experimental": true,
+ "expression": {
+ "interpolated": true,
+ "parameters": [
+ "zoom",
+ "measure-light"
+ ],
+ "relaxZoomRestriction": true
+ },
+ "transition": true,
+ "doc": "Rain particles density.",
+ "sdk-support": {
+ "basic functionality": {
+ "android": "11.8.0",
+ "ios": "11.8.0"
+ }
+ }
+ },
+ "intensity": {
+ "type": "number",
+ "property-type": "data-constant",
+ "default": 1,
+ "minimum": 0,
+ "maximum": 1,
+ "experimental": true,
+ "expression": {
+ "interpolated": true,
+ "parameters": [
+ "zoom",
+ "measure-light"
+ ],
+ "relaxZoomRestriction": true
+ },
+ "transition": true,
+ "doc": "Rain particles movement factor.",
+ "sdk-support": {
+ "basic functionality": {
+ "android": "11.8.0",
+ "ios": "11.8.0"
+ }
+ }
+ },
+ "color": {
+ "type": "color",
+ "property-type": "data-constant",
+ "default": "#ffffff",
+ "experimental": true,
+ "expression": {
+ "interpolated": true,
+ "parameters": [
+ "zoom",
+ "measure-light"
+ ],
+ "relaxZoomRestriction": true
+ },
+ "transition": true,
+ "doc": "",
+ "sdk-support": {
+ "basic functionality": {
+ "android": "11.8.0",
+ "ios": "11.8.0"
+ }
+ }
+ },
+ "opacity": {
+ "type": "number",
+ "property-type": "data-constant",
+ "default": 1,
+ "minimum": 0,
+ "maximum": 1,
+ "experimental": true,
+ "expression": {
+ "interpolated": true,
+ "parameters": [
+ "zoom",
+ "measure-light"
+ ],
+ "relaxZoomRestriction": true
+ },
+ "transition": true,
+ "doc": "Rain particles opacity.",
+ "sdk-support": {
+ "basic functionality": {
+ "android": "11.8.0",
+ "ios": "11.8.0"
+ }
+ }
+ },
+ "vignette": {
+ "type": "number",
+ "property-type": "data-constant",
+ "default": 0,
+ "minimum": 0,
+ "maximum": 1,
+ "experimental": true,
+ "expression": {
+ "interpolated": true,
+ "parameters": [
+ "zoom",
+ "measure-light"
+ ],
+ "relaxZoomRestriction": true
+ },
+ "transition": true,
+ "doc": "Rain vignette screen-space effect.",
+ "sdk-support": {
+ "basic functionality": {
+ "android": "11.8.0",
+ "ios": "11.8.0"
+ }
+ }
+ },
+ "centerThinning": {
+ "type": "number",
+ "property-type": "data-constant",
+ "default": 1,
+ "minimum": 0,
+ "maximum": 1,
+ "experimental": true,
+ "expression": {
+ "interpolated": true,
+ "parameters": [
+ "zoom",
+ "measure-light"
+ ],
+ "relaxZoomRestriction": true
+ },
+ "transition": true,
+ "doc": "Thinning factor of rain particles from center. 0 - no thinning. 1 - maximal central area thinning.",
+ "sdk-support": {
+ "basic functionality": {
+ "android": "11.8.0",
+ "ios": "11.8.0"
+ }
+ }
+ },
+ "direction": {
+ "type": "array",
+ "default": [
+ 0.0,
+ 80.0
+ ],
+ "minimum": 0,
+ "maximum": 360,
+ "length": 2,
+ "value": "number",
+ "property-type": "data-constant",
+ "transition": true,
+ "experimental": true,
+ "expression": {
+ "interpolated": true,
+ "parameters": [
+ "zoom",
+ "measure-light"
+ ],
+ "relaxZoomRestriction": true
+ },
+ "doc": "Main rain particles direction. Heading & pitch",
+ "example": [
+ 0,
+ 45
+ ],
+ "sdk-support": {
+ "basic functionality": {
+ "android": "11.8.0",
+ "ios": "11.8.0"
+ }
+ }
+ }
+ },
"camera": {
"camera-projection" : {
"doc": "Camera projection describes how 3D world geometry get projected into 2D screen",
@@ -5693,6 +6151,56 @@
},
"property-type": "data-driven"
},
+ "fill-extrusion-height-alignment": {
+ "type": "enum",
+ "experimental": true,
+ "values": {
+ "terrain": {
+ "doc": "The fill extrusion height follows terrain slope."
+ },
+ "flat": {
+ "doc": "The fill extrusion height is flat over terrain."
+ }
+ },
+ "doc": "Controls the behavior of fill extrusion height over terrain",
+ "default": "flat",
+ "requires": [
+ "fill-extrusion-height"
+ ],
+ "sdk-support": {
+ "basic functionality": {
+ "js": "3.8.0",
+ "android": "11.8.0",
+ "ios": "11.8.0"
+ }
+ },
+ "property-type": "data-constant"
+ },
+ "fill-extrusion-base-alignment": {
+ "type": "enum",
+ "experimental": true,
+ "values": {
+ "terrain": {
+ "doc": "The fill extrusion base follows terrain slope."
+ },
+ "flat": {
+ "doc": "The fill extrusion base is flat over terrain."
+ }
+ },
+ "doc": "Controls the behavior of fill extrusion base over terrain",
+ "default": "terrain",
+ "requires": [
+ "fill-extrusion-base"
+ ],
+ "sdk-support": {
+ "basic functionality": {
+ "js": "3.8.0",
+ "android": "11.8.0",
+ "ios": "11.8.0"
+ }
+ },
+ "property-type": "data-constant"
+ },
"fill-extrusion-vertical-gradient": {
"type": "boolean",
"default": true,
diff --git a/src/style-spec/types.ts b/src/style-spec/types.ts
index e2f09ea0f8c..c3842c218f7 100644
--- a/src/style-spec/types.ts
+++ b/src/style-spec/types.ts
@@ -437,6 +437,14 @@ export type LineLayerSpecification = {
* @experimental This property is experimental and subject to change in future versions.
*/
"line-z-offset"?: DataDrivenPropertyValueSpecification,
+ /**
+ * @experimental This property is experimental and subject to change in future versions.
+ */
+ "line-elevation-reference"?: "none" | "sea" | "ground" | "hd-road-markup" | ExpressionSpecification,
+ /**
+ * @experimental This property is experimental and subject to change in future versions.
+ */
+ "line-cross-slope"?: ExpressionSpecification,
"visibility"?: "visible" | "none" | ExpressionSpecification
},
"paint"?: {
@@ -508,6 +516,10 @@ export type SymbolLayerSpecification = {
"icon-optional"?: PropertyValueSpecification,
"icon-rotation-alignment"?: PropertyValueSpecification<"map" | "viewport" | "auto">,
"icon-size"?: DataDrivenPropertyValueSpecification,
+ /**
+ * @experimental This property is experimental and subject to change in future versions.
+ */
+ "icon-size-scale-range"?: ExpressionSpecification,
"icon-text-fit"?: DataDrivenPropertyValueSpecification<"none" | "width" | "height" | "both">,
"icon-text-fit-padding"?: DataDrivenPropertyValueSpecification<[number, number, number, number]>,
"icon-image"?: DataDrivenPropertyValueSpecification,
@@ -522,6 +534,10 @@ export type SymbolLayerSpecification = {
"text-field"?: DataDrivenPropertyValueSpecification,
"text-font"?: DataDrivenPropertyValueSpecification>,
"text-size"?: DataDrivenPropertyValueSpecification,
+ /**
+ * @experimental This property is experimental and subject to change in future versions.
+ */
+ "text-size-scale-range"?: ExpressionSpecification,
"text-max-width"?: DataDrivenPropertyValueSpecification,
"text-line-height"?: DataDrivenPropertyValueSpecification,
"text-letter-spacing"?: DataDrivenPropertyValueSpecification,
@@ -715,6 +731,14 @@ export type FillExtrusionLayerSpecification = {
"fill-extrusion-height-transition"?: TransitionSpecification,
"fill-extrusion-base"?: DataDrivenPropertyValueSpecification,
"fill-extrusion-base-transition"?: TransitionSpecification,
+ /**
+ * @experimental This property is experimental and subject to change in future versions.
+ */
+ "fill-extrusion-height-alignment"?: "terrain" | "flat",
+ /**
+ * @experimental This property is experimental and subject to change in future versions.
+ */
+ "fill-extrusion-base-alignment"?: "terrain" | "flat",
"fill-extrusion-vertical-gradient"?: PropertyValueSpecification,
"fill-extrusion-ambient-occlusion-intensity"?: PropertyValueSpecification,
"fill-extrusion-ambient-occlusion-intensity-transition"?: TransitionSpecification,
diff --git a/src/style-spec/validate/validate_enum.ts b/src/style-spec/validate/validate_enum.ts
index dbba171baf6..601bae00339 100644
--- a/src/style-spec/validate/validate_enum.ts
+++ b/src/style-spec/validate/validate_enum.ts
@@ -14,8 +14,7 @@ export default function validateEnum(options: ValidationOptions): Array=v8
- // @ts-expect-error - TS2345 - Argument of type 'unknown' is not assignable to parameter of type 'string'.
- if (Object.keys(valueSpec.values).indexOf(unbundle(value)) === -1) {
+ if (Object.keys(valueSpec.values).indexOf(unbundle(value) as string) === -1) {
errors.push(new ValidationError(key, value, `expected one of [${Object.keys(valueSpec.values).join(', ')}], ${JSON.stringify(value)} found`));
}
}
diff --git a/src/style-spec/validate/validate_layer.ts b/src/style-spec/validate/validate_layer.ts
index 2b54bad2a8f..d98133b9ccb 100644
--- a/src/style-spec/validate/validate_layer.ts
+++ b/src/style-spec/validate/validate_layer.ts
@@ -8,7 +8,7 @@ import validateSpec from './validate';
import extend from '../util/extend';
import type {ValidationOptions} from './validate';
-import type {LayerSpecification} from '../types';
+import type {LayerSpecification, GeoJSONSourceSpecification} from '../types';
type Options = ValidationOptions & {
value: LayerSpecification;
@@ -26,7 +26,7 @@ export default function validateLayer(options: Options): Array
if (!layer.type && !layer.ref) {
errors.push(new ValidationError(key, layer, 'either "type" or "ref" is required'));
}
- let type = unbundle(layer.type);
+ let type = unbundle(layer.type) as string;
const ref = unbundle(layer.ref);
if (layer.id) {
@@ -59,7 +59,7 @@ export default function validateLayer(options: Options): Array
} else if (parent.ref) {
errors.push(new ValidationError(key, layer.ref, 'ref cannot reference another ref layer'));
} else {
- type = unbundle(parent.type);
+ type = unbundle(parent.type) as string;
}
} else if (!(type === 'background' || type === 'sky' || type === 'slot')) {
if (!layer.source) {
@@ -77,12 +77,10 @@ export default function validateLayer(options: Options): Array
errors.push(new ValidationError(key, layer, `layer "${layer.id}" must specify a "source-layer"`));
} else if (sourceType === 'raster-dem' && type !== 'hillshade') {
errors.push(new ValidationError(key, layer.source, 'raster-dem source can only be used with layer type \'hillshade\'.'));
- // @ts-expect-error - TS2345 - Argument of type 'unknown' is not assignable to parameter of type 'string'.
} else if (sourceType === 'raster-array' && !['raster', 'raster-particle'].includes(type)) {
errors.push(new ValidationError(key, layer.source, `raster-array source can only be used with layer type \'raster\'.`));
} else if (type === 'line' && layer.paint && (layer.paint['line-gradient'] || layer.paint['line-trim-offset']) &&
- // @ts-expect-error - TS2339 - Property 'lineMetrics' does not exist on type 'SourceSpecification'.
- (sourceType !== 'geojson' || !source.lineMetrics)) {
+ (sourceType !== 'geojson' || !(source as GeoJSONSourceSpecification).lineMetrics)) {
errors.push(new ValidationError(key, layer, `layer "${layer.id}" specifies a line-gradient, which requires a GeoJSON source with \`lineMetrics\` enabled.`));
} else if (type === 'raster-particle' && sourceType !== 'raster-array') {
errors.push(new ValidationError(key, layer.source, `layer "${layer.id}" requires a \'raster-array\' source.`));
diff --git a/src/style/fog.ts b/src/style/fog.ts
index 90cf1f729a8..bb4c49dadee 100644
--- a/src/style/fog.ts
+++ b/src/style/fog.ts
@@ -30,16 +30,6 @@ type Props = {
["vertical-range"]: DataConstantProperty<[number, number]>;
};
-const fogProperties: Properties = new Properties({
- "range": new DataConstantProperty(styleSpec.fog.range),
- "color": new DataConstantProperty(styleSpec.fog.color),
- "high-color": new DataConstantProperty(styleSpec.fog["high-color"]),
- "space-color": new DataConstantProperty(styleSpec.fog["space-color"]),
- "horizon-blend": new DataConstantProperty(styleSpec.fog["horizon-blend"]),
- "star-intensity": new DataConstantProperty(styleSpec.fog["star-intensity"]),
- "vertical-range": new DataConstantProperty(styleSpec.fog["vertical-range"]),
-});
-
class Fog extends Evented {
_transitionable: Transitionable;
_transitioning: Transitioning;
@@ -53,6 +43,17 @@ class Fog extends Evented {
constructor(fogOptions: FogSpecification | null | undefined, transform: Transform, scope: string, configOptions?: ConfigOptions | null) {
super();
+
+ const fogProperties: Properties = new Properties({
+ "range": new DataConstantProperty(styleSpec.fog.range),
+ "color": new DataConstantProperty(styleSpec.fog.color),
+ "high-color": new DataConstantProperty(styleSpec.fog["high-color"]),
+ "space-color": new DataConstantProperty(styleSpec.fog["space-color"]),
+ "horizon-blend": new DataConstantProperty(styleSpec.fog["horizon-blend"]),
+ "star-intensity": new DataConstantProperty(styleSpec.fog["star-intensity"]),
+ "vertical-range": new DataConstantProperty(styleSpec.fog["vertical-range"]),
+ });
+
this._transitionable = new Transitionable(fogProperties, scope, new Map(configOptions));
this.set(fogOptions, configOptions);
this._transitioning = this._transitionable.untransitioned();
diff --git a/src/style/fog_helpers.ts b/src/style/fog_helpers.ts
index d94c265b7cf..a834ed08de8 100644
--- a/src/style/fog_helpers.ts
+++ b/src/style/fog_helpers.ts
@@ -85,7 +85,7 @@ export function getFogOpacityForBounds(
y1: number,
transform: Transform,
): [number, number] {
- const points = [
+ const points: vec3[] = [
[x0, y0, 0],
[x1, y0, 0],
[x1, y1, 0],
@@ -96,8 +96,7 @@ export function getFogOpacityForBounds(
let max = -Number.MAX_VALUE;
for (const point of points) {
- // @ts-expect-error - TS2345 - Argument of type 'number[]' is not assignable to parameter of type 'ReadonlyVec3'.
- const transformedPoint = vec3.transformMat4([] as any, point, matrix);
+ const transformedPoint = vec3.transformMat4([] as unknown as vec3, point, matrix);
const distance = vec3.length(transformedPoint);
min = Math.min(min, distance);
diff --git a/src/style/pauseable_placement.ts b/src/style/pauseable_placement.ts
index 42a8061f761..2e6e2c1f573 100644
--- a/src/style/pauseable_placement.ts
+++ b/src/style/pauseable_placement.ts
@@ -35,12 +35,13 @@ class LayerPlacement {
showCollisionBoxes: boolean,
styleLayer: StyleLayer,
shouldPausePlacement: () => boolean,
+ scaleFactor: number
): boolean {
const bucketParts = this._bucketParts;
while (this._currentTileIndex < tiles.length) {
const tile = tiles[this._currentTileIndex];
- placement.getBucketParts(bucketParts, styleLayer, tile, this._sortAcrossTiles);
+ placement.getBucketParts(bucketParts, styleLayer, tile, this._sortAcrossTiles, scaleFactor);
this._currentTileIndex++;
if (shouldPausePlacement()) {
@@ -55,7 +56,7 @@ class LayerPlacement {
while (this._currentPartIndex < bucketParts.length) {
const bucketPart = bucketParts[this._currentPartIndex];
- placement.placeLayerBucketPart(bucketPart, this._seenCrossTileIDs, showCollisionBoxes, bucketPart.symbolInstanceStart === 0);
+ placement.placeLayerBucketPart(bucketPart, this._seenCrossTileIDs, showCollisionBoxes, bucketPart.symbolInstanceStart === 0, scaleFactor);
this._currentPartIndex++;
if (shouldPausePlacement()) {
return true;
@@ -99,7 +100,8 @@ class PauseablePlacement {
[_: string]: Array;
}, layerTilesInYOrder: {
[_: string]: Array;
- }) {
+ },
+ scaleFactor: number) {
const startTime = browser.now();
const shouldPausePlacement = () => {
@@ -133,7 +135,7 @@ class PauseablePlacement {
const sourceId = makeFQID(layer.source, layer.scope);
const sortTileByY = zOffset || sortSymbolByViewportY;
- const pausePlacement = inProgressLayer.continuePlacement(sortTileByY ? layerTilesInYOrder[sourceId] : layerTiles[sourceId], this.placement, this._showCollisionBoxes, layer, shouldPausePlacement);
+ const pausePlacement = inProgressLayer.continuePlacement(sortTileByY ? layerTilesInYOrder[sourceId] : layerTiles[sourceId], this.placement, this._showCollisionBoxes, layer, shouldPausePlacement, scaleFactor);
if (pausePlacement) {
PerformanceUtils.recordPlacementTime(browser.now() - startTime);
diff --git a/src/style/query_geometry.ts b/src/style/query_geometry.ts
index ca9983fa4ae..43f2f5955b6 100644
--- a/src/style/query_geometry.ts
+++ b/src/style/query_geometry.ts
@@ -410,7 +410,6 @@ export function unwrapQueryPolygon(polygon: Point[], tr: Transform): {
// Finding projection of these kind of polygons is more involving as projecting just the corners will
// produce a degenerate (self-intersecting, non-continuous, etc.) polygon in mercator coordinates
export function projectPolygonCoveringPoles(polygon: Point[], tr: Transform): CachedPolygon | null | undefined {
-// @ts-expect-error - TS2345 - Argument of type 'Float64Array' is not assignable to parameter of type 'ReadonlyMat4'.
const matrix = mat4.multiply([] as any, tr.pixelMatrix, tr.globeMatrix);
// Transform north and south pole coordinates to the screen to see if they're
diff --git a/src/style/style.ts b/src/style/style.ts
index ebd34736b89..fd0794a76b1 100644
--- a/src/style/style.ts
+++ b/src/style/style.ts
@@ -83,7 +83,8 @@ import type {ColorThemeSpecification,
TransitionSpecification,
ConfigSpecification,
SchemaSpecification,
- CameraSpecification
+ CameraSpecification,
+ FeaturesetSpecification
} from '../style-spec/types';
import type {Callback} from '../types/callback';
import type {StyleGlyph} from './style_glyph';
@@ -100,15 +101,26 @@ import type {RequestParameters, ResponseCallback} from '../util/ajax';
import type {CustomLayerInterface} from './style_layer/custom_style_layer';
import type {Validator, ValidationErrors} from './validate_style';
import type {OverscaledTileID} from '../source/tile_id';
-import type {FeatureState} from '../style-spec/expression/index';
+import type {FeatureState, StyleExpression} from '../style-spec/expression/index';
import type {PointLike} from '../types/point-like';
import type {ISource, Source, SourceClass} from '../source/source';
import type {TransitionParameters, ConfigOptions} from './properties';
-import type {QueryResult, QueryRenderedFeaturesParams} from '../source/query_features';
-import type {GeoJSONFeature} from '../util/vectortile_to_geojson';
+import type {QueryResult} from '../source/query_features';
+import type {GeoJSONFeature, FeaturesetDescriptor, default as Feature} from '../util/vectortile_to_geojson';
import type {LUT} from '../util/lut';
import type {SerializedExpression} from '../style-spec/expression/expression';
+export type QueryRenderedFeaturesParams = {
+ layers?: string[];
+ filter?: FilterSpecification;
+ validate?: boolean;
+};
+
+export type FeaturesetQueryTarget = {
+ featureset: FeaturesetDescriptor;
+ filter?: FilterSpecification;
+};
+
// We're skipping validation errors with the `source.canvas` identifier in order
// to continue to allow canvas sources to be added at runtime/updated in
// smart setStyle (see https://github.com/mapbox/mapbox-gl-js/pull/6424):
@@ -204,6 +216,12 @@ type StyleColorTheme = {
colorTheme: ColorThemeSpecification | null;
};
+type FeaturesetSelector = {
+ id: string;
+ featureNamespace?: string;
+ properties?: Record;
+};
+
const MAX_IMPORT_DEPTH = 5;
const defaultTransition = {duration: 300, delay: 0};
@@ -251,6 +269,7 @@ class Style extends Evented {
_mergedSourceCaches: Record;
_mergedOtherSourceCaches: Record;
_mergedSymbolSourceCaches: Record;
+ _featuresets: Map>;
_clipLayerPresent: boolean;
_request: Cancelable | null | undefined;
@@ -258,9 +277,6 @@ class Style extends Evented {
_layers: {
[_: string]: StyleLayer;
};
- _serializedLayers: {
- [_: string]: any;
- };
_order: Array;
_drapedFirstOrder: Array;
_sourceCaches: {
@@ -331,6 +347,7 @@ class Style extends Evented {
this._mergedOtherSourceCaches = {};
this._mergedSymbolSourceCaches = {};
this._clipLayerPresent = false;
+ this._featuresets = new Map();
this._has3DLayers = false;
this._hasCircleLayers = false;
@@ -370,7 +387,6 @@ class Style extends Evented {
}
this._layers = {};
- this._serializedLayers = {};
this._sourceCaches = {};
this._otherSourceCaches = {};
this._symbolSourceCaches = {};
@@ -740,13 +756,11 @@ class Style extends Evented {
}
this._layers = {};
- this._serializedLayers = {};
for (const layer of layers) {
const styleLayer = createStyleLayer(layer, this.scope, this._styleColorTheme.lut, this.options);
if (styleLayer.configDependencies.size !== 0) this._configDependentLayers.add(styleLayer.fqid);
styleLayer.setEventedParent(this, {layer: {id: styleLayer.id}});
this._layers[styleLayer.id] = styleLayer;
- this._serializedLayers[styleLayer.id] = styleLayer.serialize();
const sourceCache = this.getOwnLayerSourceCache(styleLayer);
const shadowsEnabled = !!this.directionalLight && this.directionalLight.shadowsEnabled();
@@ -1001,6 +1015,7 @@ class Style extends Evented {
this._has3DLayers = false;
this._hasCircleLayers = false;
this._hasSymbolLayers = false;
+ this._featuresets.clear();
this.forEachFragmentStyle((style: Style) => {
for (const layerId of style._order) {
@@ -1018,6 +1033,33 @@ class Style extends Evented {
mergedOrder.push(layer);
}
+
+ const {featuresets} = style.stylesheet || {};
+ if (featuresets) {
+ for (const featureset of Object.keys(featuresets)) {
+ const {selectors} = featuresets[featureset];
+ for (const selector of selectors) {
+ const layer = style._layers[selector.layer];
+ const layers = this._featuresets.get(layer.fqid) || [];
+ let properties;
+ if (selector.properties) {
+ for (const name of Object.keys(selector.properties)) {
+ const expression = createExpression(selector.properties[name]);
+ if (expression.result === 'success') {
+ properties = properties || {};
+ properties[name] = expression.value;
+ }
+ }
+ }
+ layers.push({
+ id: featureset,
+ featureNamespace: selector.featureNamespace,
+ properties
+ });
+ this._featuresets.set(layer.fqid, layers);
+ }
+ }
+ }
});
this._mergedOrder = [];
@@ -1960,6 +2002,37 @@ class Style extends Evented {
}
}
+ getFeatureset(featuresetId: string, fragmentId?: string): FeaturesetSpecification | null | undefined {
+ const style = fragmentId ? this.getFragmentStyle(fragmentId) : this;
+ if (!style || !style.stylesheet.featuresets) return;
+ return style.stylesheet.featuresets[featuresetId];
+ }
+
+ getFeaturesets(fragmentId?: string): Array {
+ const style = fragmentId ? this.getFragmentStyle(fragmentId) : this;
+ if (!style || !style.stylesheet.featuresets) return [];
+
+ const featuresets: FeaturesetDescriptor[] = [];
+ for (const id in style.stylesheet.featuresets) {
+ featuresets.push({featuresetId: id, importId: style.scope ? style.scope : undefined});
+ }
+
+ return featuresets;
+ }
+
+ getOwnFeaturesetLayers(id: string): Array {
+ const layers = [];
+ const featuresets = this.stylesheet.featuresets;
+ if (!featuresets || !featuresets[id]) {
+ this.fire(new ErrorEvent(new Error(`The featureset '${id}' does not exist in the map's style and cannot be queried.`)));
+ return [];
+ }
+ for (const selector of featuresets[id].selectors) {
+ layers.push(this._layers[selector.layer]);
+ }
+ return layers;
+ }
+
getConfigProperty(fragmentId: string, key: string): SerializedExpression | null {
const fragmentStyle = this.getFragmentStyle(fragmentId);
if (!fragmentStyle) return null;
@@ -2170,7 +2243,6 @@ class Style extends Evented {
this._validateLayer(layer);
layer.setEventedParent(this, {layer: {id}});
- this._serializedLayers[layer.id] = layer.serialize();
}
if (layer.configDependencies.size !== 0) this._configDependentLayers.add(layer.fqid);
@@ -2296,7 +2368,6 @@ class Style extends Evented {
this._order.splice(index, 1);
delete this._layers[id];
- delete this._serializedLayers[id];
this._changes.setDirty();
this._layerOrderChanged = true;
@@ -2512,6 +2583,17 @@ class Style extends Evented {
setFeatureState(target: FeatureSelector | GeoJSONFeature, state: FeatureState) {
this._checkLoaded();
+
+ const featureset = (target as GeoJSONFeature).featureset;
+ if (featureset && 'featuresetId' in featureset) {
+ const fragment = this.getFragmentStyle(featureset.importId);
+ const layers = fragment.getOwnFeaturesetLayers(featureset.featuresetId);
+ for (const {source, sourceLayer} of layers) {
+ fragment.setFeatureState({id: target.id, source, sourceLayer}, state);
+ }
+ return;
+ }
+
const sourceId = target.source;
const sourceLayer = target.sourceLayer;
@@ -2539,6 +2621,18 @@ class Style extends Evented {
removeFeatureState(target: Omit & {id?: FeatureSelector['id']} | GeoJSONFeature, key?: string) {
this._checkLoaded();
+
+ const layer = (target as GeoJSONFeature).layer;
+
+ if (layer && isFQID(layer.id)) {
+ const fragment = this.getFragmentStyle(getScopeFromFQID(layer.id));
+ const layers = fragment.getOwnFeaturesetLayers(getNameFromFQID(layer.id));
+ for (const {source, sourceLayer} of layers) {
+ fragment.removeFeatureState({id: target.id, source, sourceLayer}, key);
+ }
+ return;
+ }
+
const sourceId = target.source;
const source = this._checkSource(sourceId);
@@ -2565,6 +2659,27 @@ class Style extends Evented {
getFeatureState(target: FeatureSelector | GeoJSONFeature): FeatureState | null | undefined {
this._checkLoaded();
+
+ const featureset = (target as GeoJSONFeature).featureset;
+ if (featureset && 'featuresetId' in featureset) {
+ const fragment = this.getFragmentStyle(featureset.importId);
+ const layers = fragment.getOwnFeaturesetLayers(featureset.featuresetId);
+
+ let finalState: FeatureState;
+ for (const {source, sourceLayer} of layers) {
+ const state = fragment.getFeatureState({id: target.id, source, sourceLayer});
+ // There is possibility that the same feature id exists in multiple sources, and the states of the
+ // features must be consistent through all the sources
+ if (state && !finalState) {
+ finalState = state;
+ } else if (!deepEqual(finalState, state)) {
+ this.fire(new ErrorEvent(new Error(`The same feature id exists in multiple sources in the featureset, but their feature states are not consistent through the sources.`)));
+ return;
+ }
+ }
+ return finalState;
+ }
+
const sourceId = target.source;
const sourceLayer = target.sourceLayer;
@@ -2628,6 +2743,14 @@ class Style extends Evented