maplibre-gl 6.5.0 → 6.6.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/maplibre-gl-dev.mjs +1296 -1165
- package/dist/maplibre-gl-dev.mjs.map +1 -1
- package/dist/maplibre-gl-shared-dev.mjs +232 -102
- package/dist/maplibre-gl-shared-dev.mjs.map +1 -1
- package/dist/maplibre-gl-shared.mjs +2 -2
- package/dist/maplibre-gl-shared.mjs.map +1 -1
- package/dist/maplibre-gl-worker-dev.mjs +2 -2
- package/dist/maplibre-gl-worker.mjs +2 -2
- package/dist/maplibre-gl-worker.mjs.map +1 -1
- package/dist/maplibre-gl.d.ts +104 -88
- package/dist/maplibre-gl.mjs +20 -20
- package/dist/maplibre-gl.mjs.map +1 -1
- package/package.json +8 -8
- package/src/data/array_types.g.ts +43 -32
- package/src/data/bucket/symbol_attributes.ts +6 -3
- package/src/data/bucket/symbol_bucket.ts +12 -8
- package/src/data/feature_index.ts +3 -3
- package/src/geo/projection/covering_tiles.test.ts +36 -0
- package/src/geo/projection/covering_tiles.ts +2 -3
- package/src/geo/projection/globe_transform.test.ts +4 -5
- package/src/geo/projection/globe_transform.ts +7 -2
- package/src/geo/projection/globe_utils.ts +57 -0
- package/src/geo/projection/mercator_transform.bench.ts +55 -0
- package/src/geo/projection/mercator_transform.test.ts +203 -13
- package/src/geo/projection/mercator_transform.ts +118 -27
- package/src/geo/projection/mercator_utils.test.ts +50 -1
- package/src/geo/projection/mercator_utils.ts +20 -1
- package/src/geo/projection/vertical_perspective_transform.test.ts +97 -0
- package/src/geo/projection/vertical_perspective_transform.ts +72 -68
- package/src/geo/transform_helper.ts +14 -5
- package/src/geo/transform_interface.ts +22 -1
- package/src/render/painter.test.ts +1 -3
- package/src/render/painter.ts +7 -20
- package/src/render/terrain.test.ts +73 -84
- package/src/render/terrain.ts +125 -114
- package/src/shaders/glsl/symbol_icon.vertex.glsl +4 -1
- package/src/shaders/glsl/symbol_icon.vertex.glsl.g.ts +1 -1
- package/src/shaders/glsl/symbol_sdf.vertex.glsl +4 -1
- package/src/shaders/glsl/symbol_sdf.vertex.glsl.g.ts +1 -1
- package/src/shaders/glsl/symbol_text_and_icon.vertex.glsl +4 -1
- package/src/shaders/glsl/symbol_text_and_icon.vertex.glsl.g.ts +1 -1
- package/src/shaders/shaders.ts +0 -4
- package/src/source/raster_dem_tile_source.ts +1 -0
- package/src/style/query_utils.ts +8 -8
- package/src/style/style_layer/symbol_style_layer_properties.g.ts +6 -0
- package/src/style/style_layer.ts +4 -6
- package/src/symbol/collision_index.ts +25 -19
- package/src/symbol/placement.test.ts +1 -1
- package/src/symbol/placement.ts +28 -13
- package/src/symbol/projection.test.ts +79 -15
- package/src/symbol/projection.ts +38 -20
- package/src/symbol/symbol_elevation.ts +28 -0
- package/src/symbol/symbol_layout.ts +14 -6
- package/src/symbol/symbol_size.test.ts +100 -0
- package/src/symbol/symbol_size.ts +78 -50
- package/src/tile/terrain_tile_manager.ts +2 -2
- package/src/tile/tile.ts +3 -2
- package/src/tile/tile_manager_raster_dem.ts +1 -0
- package/src/ui/handler_manager.test.ts +11 -23
- package/src/ui/handler_manager.ts +1 -1
- package/src/ui/map_tests/map_pitch.test.ts +12 -0
- package/src/ui/map_tests/map_style.test.ts +49 -27
- package/src/ui/map_tests/map_zoom.test.ts +12 -0
- package/src/util/test/util.ts +34 -3
- package/src/webgl/draw/draw_color_relief.ts +7 -10
- package/src/webgl/draw/draw_symbol.ts +16 -12
- package/src/webgl/draw/draw_terrain.ts +4 -39
- package/src/webgl/draw/index.ts +2 -4
- package/src/webgl/program/program_uniforms.ts +1 -3
- package/src/webgl/program/symbol_program.ts +15 -5
- package/src/webgl/program/terrain_program.ts +1 -22
- package/src/webgl/render_to_texture.test.ts +0 -1
- package/src/shaders/glsl/terrain_coords.fragment.glsl +0 -11
- package/src/shaders/glsl/terrain_coords.fragment.glsl.g.ts +0 -2
- package/src/shaders/glsl/terrain_coords.vertex.glsl +0 -12
- package/src/shaders/glsl/terrain_coords.vertex.glsl.g.ts +0 -2
package/dist/maplibre-gl-dev.mjs
CHANGED
|
@@ -1,10 +1,10 @@
|
|
|
1
1
|
/**
|
|
2
2
|
* MapLibre GL JS
|
|
3
|
-
* @license 3-Clause BSD. Full text of license: https://github.com/maplibre/maplibre-gl-js/blob/v6.
|
|
3
|
+
* @license 3-Clause BSD. Full text of license: https://github.com/maplibre/maplibre-gl-js/blob/v6.6.0/LICENSE.txt
|
|
4
4
|
*/
|
|
5
|
-
import { $ as
|
|
5
|
+
import { $ as projectToWorldCoordinates, $n as createVec4f64, $r as slerp, $t as Properties, A as evaluateSizeForFeature, Ai as perspective, An as getReferrer, Ar as readImageUsingVideoFrame, At as polygonIntersectsPolygon, Bi as invert, Bn as throwIfAborted, Br as warnOnce, Bt as UniformMatrix4f, C as isCustomStyleLayer, Ci as create$1, Cn as ErrorEvent, Cr as mod, Ct as isHillshadeStyleLayer, D as SymbolBucket, Di as invert$1, Dn as GLOBAL_DISPATCHER_ID, Dr as pointPlaneSignedDistance, Dt as AlphaImage, E as isSymbolStyleLayer, Ei as identity, En as AJAXError, Er as pick, Et as renderColorRamp, F as ImagePosition, Fi as translate, Fn as getProtocol, Fr as sphericalToCartesian, Ft as Uniform3f, G as isFillExtrusionStyleLayer, Gn as arrayBufferToImageBitmap, Gr as create$3, Gt as Pos3dArray, H as isLineStyleLayer, Hi as isOffscreenCanvasDistorted, Hn as MAX_VALID_LATITUDE, Hr as zoomScale, Ht as CollisionBoxArray, I as potpack, Ii as create$4, In as removeProtocol, Ir as subscribe, It as Uniform4f, J as cameraDirectionFromPitchBearing, Jn as clone$2, Jr as sqrLen, Jt as RasterBoundsArray, Kn as bezier, Kr as length, Kt as PosArray, L as isStyleImageWebGLData, Li as fromRotation, Ln as config, Lr as threePlaneIntersection, Lt as UniformColor, Mi as rotateY$1, Mn as makeRequest, Mr as rollPitchBearingEqual, Mt as Uniform1f, N as getAnchorAlignment, Ni as rotateZ, Nn as sameOrigin, Nr as rollPitchBearingToQuat, Nt as Uniform1i, O as addDynamicAttributes, Oi as multiply, On as getArrayBuffer, Or as radiansToDegrees, Ot as RGBAImage, Pi as scale, Pn as addProtocol, Pr as scaleZoom, Pt as Uniform2f, Q as maxMercatorHorizonAngle, Qn as createVec3f64, Qr as multiply$1, Qt as DataConstantProperty, R as renderStyleImage, Ri as create$2, Rn as AbortError, Rr as translatePosition, Rt as UniformColorArray, S as createStyleLayer, Si as copy, Sn as latest, Sr as mapObject, St as Texture, T as isBackgroundStyleLayer, Ti as fromScaling, Tn as Evented, Tr as parseCacheControl, Tt as isHeatmapStyleLayer, Ui as offscreenCanvasSupported, Un as angleToRotateBetweenVectors2D, Ur as pixelsToTileUnits, Ut as CollisionCircleLayoutArray, V as collisionCircleLayout, Vi as rotate, Vr as wrap, Vt as SegmentVector, Wi as Point, Wn as arrayBufferToImage, Wr as EXTENT, Wt as LineStripIndexArray, X as cameraMercatorCoordinateFromCenterAndRotation, Xn as createIdentityMat4f64, Xr as fromEuler, Xt as createLayout, Y as cameraMercatorCoordinate, Yn as createIdentityMat4f32, Yr as zero, Yt as TriangleIndexArray, Z as getMercatorHorizon, Zn as createMat4f64, Zr as fromValues, Zt as isRasterStyleLayer, _ as UnwrappedTileID, _i as transformMat3, _n as diff, _r as isSafari, _t as SOUTH_POLE_Y, a as clipLine, ai as cross, an as ZoomHistory, ar as ensureError, at as lngFromMercatorX, b as isInBoundsForZoomLngLat, bi as zero$1, br as isWorker, bt as isColorReliefStyleLayer, ci as length$1, cn as emitValidationErrors, cr as filterObject, ct as mercatorZfromAltitude, di as rotateX$1, dn as validateStyleAndEmit, dr as getAngleDelta, ei as mul, en as TRANSITION_SUFFIX, er as deepEqual, et as tileCoordinatesToMercatorCoordinates, f as GEOJSON_TILE_LAYER_NAME, fi as rotateY, fn as Color, fr as getEdgeTiles, ft as EXTENT_BOUNDS, g as OverscaledTileID, gi as sub, gn as derefLayers, gr as isPointableEvent, gt as NORTH_POLE_Y, h as CanonicalTileID, hi as scaleAndAdd, hr as isImageBitmap, ii as clone, in as codePointUsesLocalIdeographFontFamily, ir as distanceOfAnglesRadians, it as latFromMercatorY, j as evaluateSizeForZoom, ji as rotateX, jn as getVideo, jr as remapSaturate, jt as toEvaluationFeature, k as getOverlapMode, ki as ortho, kn as getJSON, kr as rayPlaneIntersection, kt as isCircleStyleLayer, li as negate, ln as validateAndEmit, lr as findLineIntersection, lt as LngLat, mi as scale$2, mn as ValidationError, mr as getRollPitchBearing, mt as isFillStyleLayer, ni as transformMat4, nn as EvaluationParameters, nr as degreesToRadians, nt as MercatorCoordinate, oi as dot, or as evaluateZoomSnap, ot as mercatorXfromLng, pi as rotateZ$1, pn as ProjectionDefinition, pt as Bounds, q as calculateTileMatrix, qn as clamp, qr as scale$1, qt as QuadTriangleArray, r as TextAnchorEnum, ri as add, rr as differenceOfAnglesDegrees, rt as altitudeFromMercatorZ, s as TileCache, si as len, sn as SPEC_SOURCE_TYPES, sr as extend, st as mercatorYfromLat, t as getAnchorJustification, ti as scale$3, tn as Transitionable, tr as defaultEasing, tt as unprojectFromWorldCoordinates, u as GeoJSONFeature, ui as normalize, un as validateStyle, ur as getAABB, ut as earthRadius, v as calculateTileKey, vi as transformMat4$1, vn as emptyStyle, vr as isTouchableEvent, vt as SubdivisionGranularityExpression, w as validateCustomStyleLayer, wi as equals, wn as Event, wr as nextPowerOfTwo, wt as HEATMAP_FULL_RENDER_FBO_KEY, x as Actor, xi as clone$1, xn as interpolateFactory, xr as lerp, y as compareTileId, yi as transformQuat, yn as featureFilter, yr as isTouchableOrPointableType, yt as SubdivisionGranularitySetting, z as parseGlyphPbf, zi as determinant, zn as isAbortError, zr as uniqueId, zt as UniformFloatArray } from "./maplibre-gl-shared-dev.mjs";
|
|
6
6
|
//#region package.json
|
|
7
|
-
var version$2 = "6.
|
|
7
|
+
var version$2 = "6.6.0";
|
|
8
8
|
//#endregion
|
|
9
9
|
//#region src/util/browser.ts
|
|
10
10
|
let linkEl;
|
|
@@ -3013,6 +3013,7 @@ var RasterDEMTileSource = class extends RasterTileSource {
|
|
|
3013
3013
|
});
|
|
3014
3014
|
tile.needsHillshadePrepare = true;
|
|
3015
3015
|
tile.needsTerrainPrepare = true;
|
|
3016
|
+
tile.needsColorReliefPrepare = true;
|
|
3016
3017
|
tile.state = "loaded";
|
|
3017
3018
|
}
|
|
3018
3019
|
} catch (err) {
|
|
@@ -5322,9 +5323,8 @@ function getElevationForTileCulling(transform) {
|
|
|
5322
5323
|
function coveringTiles(transform, options) {
|
|
5323
5324
|
const frustum = transform.getCameraFrustum();
|
|
5324
5325
|
const plane = transform.getClippingPlane();
|
|
5325
|
-
const cameraCoord =
|
|
5326
|
+
const cameraCoord = cameraMercatorCoordinate(transform);
|
|
5326
5327
|
const centerCoord = MercatorCoordinate.fromLngLat(transform.center, transform.elevation);
|
|
5327
|
-
cameraCoord.z = centerCoord.z + Math.cos(transform.pitchInRadians) * transform.cameraToCenterDistance / transform.worldSize;
|
|
5328
5328
|
const elevationForTileCulling = getElevationForTileCulling(transform);
|
|
5329
5329
|
const detailsProvider = transform.getCoveringTilesDetailsProvider();
|
|
5330
5330
|
const allowVariableZoom = detailsProvider.allowVariableZoom(transform, options);
|
|
@@ -5565,6 +5565,7 @@ function backfillDEM(tile, inViewTiles) {
|
|
|
5565
5565
|
function fillBorder(tile, borderTile) {
|
|
5566
5566
|
tile.needsHillshadePrepare = true;
|
|
5567
5567
|
tile.needsTerrainPrepare = true;
|
|
5568
|
+
tile.needsColorReliefPrepare = true;
|
|
5568
5569
|
let dx = borderTile.tileID.canonical.x - tile.tileID.canonical.x;
|
|
5569
5570
|
const dy = borderTile.tileID.canonical.y - tile.tileID.canonical.y;
|
|
5570
5571
|
const dim = Math.pow(2, tile.tileID.canonical.z);
|
|
@@ -6285,6 +6286,30 @@ var PathInterpolator = class {
|
|
|
6285
6286
|
}
|
|
6286
6287
|
};
|
|
6287
6288
|
//#endregion
|
|
6289
|
+
//#region src/symbol/symbol_elevation.ts
|
|
6290
|
+
/**
|
|
6291
|
+
* Resolves the elevation of a symbol at a tile coordinate, combining the terrain elevation with the
|
|
6292
|
+
* symbol's `symbol-height-offset`. `symbol-height-anchor` selects the datum the offset is measured
|
|
6293
|
+
* from: the terrain surface below the symbol (`ground`) or the zero elevation datum (`absolute`),
|
|
6294
|
+
* in which case the terrain below the symbol is ignored.
|
|
6295
|
+
*
|
|
6296
|
+
* Call this where the elevation is needed, so that `getElevation` keeps returning the plain terrain
|
|
6297
|
+
* elevation and never has to be substituted with a wrapper.
|
|
6298
|
+
*
|
|
6299
|
+
* @param getElevation - the terrain elevation function, absent when the map has no terrain
|
|
6300
|
+
* @param x - the tile x coordinate to evaluate the elevation at
|
|
6301
|
+
* @param y - the tile y coordinate to evaluate the elevation at
|
|
6302
|
+
* @param heightOffset - the evaluated `symbol-height-offset` of the symbol, in meters
|
|
6303
|
+
* @param heightAnchorGround - whether `symbol-height-anchor` is `ground`
|
|
6304
|
+
* @returns the elevation in meters, or undefined when the symbol sits at the zero elevation datum,
|
|
6305
|
+
* which lets the projection take its fast path that ignores the z coordinate
|
|
6306
|
+
*/
|
|
6307
|
+
function getSymbolElevation(getElevation, x, y, heightOffset, heightAnchorGround) {
|
|
6308
|
+
if (!heightAnchorGround) return heightOffset;
|
|
6309
|
+
if (!getElevation) return heightOffset !== 0 ? heightOffset : void 0;
|
|
6310
|
+
return getElevation(x, y) + heightOffset;
|
|
6311
|
+
}
|
|
6312
|
+
//#endregion
|
|
6288
6313
|
//#region src/symbol/grid_index.ts
|
|
6289
6314
|
function overlapAllowed(overlapA, overlapB) {
|
|
6290
6315
|
let allowed = true;
|
|
@@ -6678,16 +6703,22 @@ function getTileSkewVectors(transform) {
|
|
|
6678
6703
|
};
|
|
6679
6704
|
}
|
|
6680
6705
|
/**
|
|
6706
|
+
* Resolves the elevation of the symbol described by `projectionContext` at a tile coordinate.
|
|
6707
|
+
*/
|
|
6708
|
+
function elevationAt(projectionContext, x, y) {
|
|
6709
|
+
return getSymbolElevation(projectionContext.getElevation, x, y, projectionContext.heightOffset ?? 0, projectionContext.heightAnchorGround ?? true);
|
|
6710
|
+
}
|
|
6711
|
+
/**
|
|
6681
6712
|
* Projects a point using a specified matrix, including the perspective divide.
|
|
6682
|
-
* Uses a fast path if `
|
|
6713
|
+
* Uses a fast path if `elevation` is undefined.
|
|
6683
6714
|
*/
|
|
6684
|
-
function projectWithMatrix(x, y, matrix,
|
|
6715
|
+
function projectWithMatrix(x, y, matrix, elevation) {
|
|
6685
6716
|
let pos;
|
|
6686
|
-
if (
|
|
6717
|
+
if (elevation != null) {
|
|
6687
6718
|
pos = [
|
|
6688
6719
|
x,
|
|
6689
6720
|
y,
|
|
6690
|
-
|
|
6721
|
+
elevation,
|
|
6691
6722
|
1
|
|
6692
6723
|
];
|
|
6693
6724
|
transformMat4(pos, pos, matrix);
|
|
@@ -6901,10 +6932,10 @@ function projectTileCoordinatesToLabelPlane(x, y, projectionContext) {
|
|
|
6901
6932
|
const translatedY = y + projectionContext.translation[1];
|
|
6902
6933
|
let projection;
|
|
6903
6934
|
if (projectionContext.pitchWithMap) {
|
|
6904
|
-
projection = projectWithMatrix(translatedX, translatedY, projectionContext.pitchedLabelPlaneMatrix, projectionContext
|
|
6935
|
+
projection = projectWithMatrix(translatedX, translatedY, projectionContext.pitchedLabelPlaneMatrix, elevationAt(projectionContext, translatedX, translatedY));
|
|
6905
6936
|
projection.isOccluded = false;
|
|
6906
6937
|
} else {
|
|
6907
|
-
projection = projectionContext.transform.projectTileCoordinates(translatedX, translatedY, projectionContext.unwrappedTileID, projectionContext
|
|
6938
|
+
projection = projectionContext.transform.projectTileCoordinates(translatedX, translatedY, projectionContext.unwrappedTileID, elevationAt(projectionContext, translatedX, translatedY));
|
|
6908
6939
|
projection.point.x = (projection.point.x * .5 + .5) * projectionContext.width;
|
|
6909
6940
|
projection.point.y = (-projection.point.y * .5 + .5) * projectionContext.height;
|
|
6910
6941
|
}
|
|
@@ -6919,7 +6950,9 @@ function projectFromLabelPlaneToClipSpace(x, y, projectionContext, pitchedLabelP
|
|
|
6919
6950
|
1
|
|
6920
6951
|
];
|
|
6921
6952
|
transformMat4(pos, pos, pitchedLabelPlaneMatrixInverse);
|
|
6922
|
-
|
|
6953
|
+
const tileX = pos[0] / pos[3];
|
|
6954
|
+
const tileY = pos[1] / pos[3];
|
|
6955
|
+
return projectionContext.transform.projectTileCoordinates(tileX, tileY, projectionContext.unwrappedTileID, elevationAt(projectionContext, tileX, tileY)).point;
|
|
6923
6956
|
} else return {
|
|
6924
6957
|
x: x / projectionContext.width * 2 - 1,
|
|
6925
6958
|
y: 1 - y / projectionContext.height * 2
|
|
@@ -6929,7 +6962,7 @@ function projectFromLabelPlaneToClipSpace(x, y, projectionContext, pitchedLabelP
|
|
|
6929
6962
|
* Projects the given point in tile coordinates to the GL clip space (-1..1).
|
|
6930
6963
|
*/
|
|
6931
6964
|
function projectTileCoordinatesToClipSpace(x, y, projectionContext) {
|
|
6932
|
-
return projectionContext.transform.projectTileCoordinates(x, y, projectionContext.unwrappedTileID, projectionContext
|
|
6965
|
+
return projectionContext.transform.projectTileCoordinates(x, y, projectionContext.unwrappedTileID, elevationAt(projectionContext, x, y));
|
|
6933
6966
|
}
|
|
6934
6967
|
/**
|
|
6935
6968
|
* Calculate the normal vector for a line segment
|
|
@@ -7070,8 +7103,8 @@ function projectPathSpecialProjection(projectedPath, projectionContext) {
|
|
|
7070
7103
|
const inverseLabelPlaneMatrix = tmpMat4;
|
|
7071
7104
|
fastInvertSkewMat4(inverseLabelPlaneMatrix, projectionContext.pitchedLabelPlaneMatrix);
|
|
7072
7105
|
return projectedPath.map((p) => {
|
|
7073
|
-
const backProjected = projectWithMatrix(p.x, p.y, inverseLabelPlaneMatrix, projectionContext.
|
|
7074
|
-
const projected = projectionContext.transform.projectTileCoordinates(backProjected.point.x, backProjected.point.y, projectionContext.unwrappedTileID, projectionContext.
|
|
7106
|
+
const backProjected = projectWithMatrix(p.x, p.y, inverseLabelPlaneMatrix, elevationAt(projectionContext, p.x, p.y));
|
|
7107
|
+
const projected = projectionContext.transform.projectTileCoordinates(backProjected.point.x, backProjected.point.y, projectionContext.unwrappedTileID, elevationAt(projectionContext, backProjected.point.x, backProjected.point.y));
|
|
7075
7108
|
projected.point.x = (projected.point.x * .5 + .5) * projectionContext.width;
|
|
7076
7109
|
projected.point.y = (-projected.point.y * .5 + .5) * projectionContext.height;
|
|
7077
7110
|
return projected;
|
|
@@ -7122,10 +7155,10 @@ var CollisionIndex = class {
|
|
|
7122
7155
|
this.gridBottomBoundary = transform.height + 200;
|
|
7123
7156
|
this.perspectiveRatioCutoff = .6;
|
|
7124
7157
|
}
|
|
7125
|
-
placeCollisionBox(collisionBox, overlapMode, textPixelRatio, tileID, unwrappedTileID, pitchWithMap, rotateWithMap, translation, collisionGroupPredicate, getElevation, shift, simpleProjectionMatrix) {
|
|
7158
|
+
placeCollisionBox(collisionBox, overlapMode, textPixelRatio, tileID, unwrappedTileID, pitchWithMap, rotateWithMap, translation, collisionGroupPredicate, getElevation, shift, simpleProjectionMatrix, heightOffset = 0, heightAnchorGround = true) {
|
|
7126
7159
|
const x = collisionBox.anchorPointX + translation[0];
|
|
7127
7160
|
const y = collisionBox.anchorPointY + translation[1];
|
|
7128
|
-
const projectedPoint = this.projectAndGetPerspectiveRatio(x, y, unwrappedTileID, getElevation, simpleProjectionMatrix);
|
|
7161
|
+
const projectedPoint = this.projectAndGetPerspectiveRatio(x, y, unwrappedTileID, getSymbolElevation(getElevation, x, y, heightOffset, heightAnchorGround), simpleProjectionMatrix);
|
|
7129
7162
|
const tileToViewport = textPixelRatio * projectedPoint.perspectiveRatio;
|
|
7130
7163
|
let projectedBox;
|
|
7131
7164
|
if (!pitchWithMap && !rotateWithMap) {
|
|
@@ -7140,7 +7173,7 @@ var CollisionIndex = class {
|
|
|
7140
7173
|
pointY + collisionBox.y2 * tileToViewport
|
|
7141
7174
|
]
|
|
7142
7175
|
};
|
|
7143
|
-
} else projectedBox = this._projectCollisionBox(collisionBox, tileToViewport, tileID, unwrappedTileID, pitchWithMap, rotateWithMap, translation, projectedPoint, getElevation, shift, simpleProjectionMatrix);
|
|
7176
|
+
} else projectedBox = this._projectCollisionBox(collisionBox, tileToViewport, tileID, unwrappedTileID, pitchWithMap, rotateWithMap, translation, projectedPoint, getElevation, shift, simpleProjectionMatrix, heightOffset, heightAnchorGround);
|
|
7144
7177
|
const [tlX, tlY, brX, brY] = projectedBox.box;
|
|
7145
7178
|
const occluded = pitchWithMap ? projectedBox.allPointsOccluded : projectedPoint.isOccluded;
|
|
7146
7179
|
let unplaceable = occluded;
|
|
@@ -7172,7 +7205,7 @@ var CollisionIndex = class {
|
|
|
7172
7205
|
placeCollisionCircles(overlapMode, symbol, lineVertexArray, glyphOffsetArray, fontSize, unwrappedTileID, pitchedLabelPlaneMatrix, showCollisionCircles, pitchWithMap, collisionGroupPredicate, circlePixelDiameter, textPixelPadding, translation, getElevation) {
|
|
7173
7206
|
const placedCollisionCircles = [];
|
|
7174
7207
|
const tileUnitAnchorPoint = new Point(symbol.anchorX, symbol.anchorY);
|
|
7175
|
-
const perspectiveRatio = this.getPerspectiveRatio(tileUnitAnchorPoint.x, tileUnitAnchorPoint.y, unwrappedTileID, getElevation);
|
|
7208
|
+
const perspectiveRatio = this.getPerspectiveRatio(tileUnitAnchorPoint.x, tileUnitAnchorPoint.y, unwrappedTileID, getElevation?.(tileUnitAnchorPoint.x, tileUnitAnchorPoint.y));
|
|
7176
7209
|
const labelPlaneFontScale = (pitchWithMap ? fontSize * this.transform.getPitchedTextCorrection(symbol.anchorX, symbol.anchorY, unwrappedTileID) / perspectiveRatio : fontSize * perspectiveRatio) / 24;
|
|
7177
7210
|
const projectionCache = {
|
|
7178
7211
|
projections: {},
|
|
@@ -7321,14 +7354,14 @@ var CollisionIndex = class {
|
|
|
7321
7354
|
};
|
|
7322
7355
|
for (let k = 0; k < collisionCircles.length; k += 4) grid.insertCircle(key, collisionCircles[k], collisionCircles[k + 1], collisionCircles[k + 2]);
|
|
7323
7356
|
}
|
|
7324
|
-
projectAndGetPerspectiveRatio(x, y, unwrappedTileID,
|
|
7357
|
+
projectAndGetPerspectiveRatio(x, y, unwrappedTileID, elevation, simpleProjectionMatrix) {
|
|
7325
7358
|
if (simpleProjectionMatrix) {
|
|
7326
7359
|
let pos;
|
|
7327
|
-
if (
|
|
7360
|
+
if (elevation != null) {
|
|
7328
7361
|
pos = [
|
|
7329
7362
|
x,
|
|
7330
7363
|
y,
|
|
7331
|
-
|
|
7364
|
+
elevation,
|
|
7332
7365
|
1
|
|
7333
7366
|
];
|
|
7334
7367
|
transformMat4(pos, pos, simpleProjectionMatrix);
|
|
@@ -7350,7 +7383,7 @@ var CollisionIndex = class {
|
|
|
7350
7383
|
signedDistanceFromCamera: w
|
|
7351
7384
|
};
|
|
7352
7385
|
} else {
|
|
7353
|
-
const projected = this.transform.projectTileCoordinates(x, y, unwrappedTileID,
|
|
7386
|
+
const projected = this.transform.projectTileCoordinates(x, y, unwrappedTileID, elevation);
|
|
7354
7387
|
return {
|
|
7355
7388
|
x: (projected.point.x + 1) / 2 * this.transform.width + 100,
|
|
7356
7389
|
y: (-projected.point.y + 1) / 2 * this.transform.height + 100,
|
|
@@ -7360,8 +7393,8 @@ var CollisionIndex = class {
|
|
|
7360
7393
|
};
|
|
7361
7394
|
}
|
|
7362
7395
|
}
|
|
7363
|
-
getPerspectiveRatio(x, y, unwrappedTileID,
|
|
7364
|
-
const projected = this.transform.projectTileCoordinates(x, y, unwrappedTileID,
|
|
7396
|
+
getPerspectiveRatio(x, y, unwrappedTileID, elevation) {
|
|
7397
|
+
const projected = this.transform.projectTileCoordinates(x, y, unwrappedTileID, elevation);
|
|
7365
7398
|
return .5 + .5 * (this.transform.cameraToCenterDistance / projected.signedDistanceFromCamera);
|
|
7366
7399
|
}
|
|
7367
7400
|
isOffscreen(x1, y1, x2, y2) {
|
|
@@ -7382,7 +7415,7 @@ var CollisionIndex = class {
|
|
|
7382
7415
|
/**
|
|
7383
7416
|
* Applies all layout+paint properties of the given box in order to find as good approximation of its screen-space bounding box as possible.
|
|
7384
7417
|
*/
|
|
7385
|
-
_projectCollisionBox(collisionBox, tileToViewport, tileID, unwrappedTileID, pitchWithMap, rotateWithMap, translation, projectedPoint, getElevation, shift, simpleProjectionMatrix) {
|
|
7418
|
+
_projectCollisionBox(collisionBox, tileToViewport, tileID, unwrappedTileID, pitchWithMap, rotateWithMap, translation, projectedPoint, getElevation, shift, simpleProjectionMatrix, heightOffset = 0, heightAnchorGround = true) {
|
|
7386
7419
|
let vecEastX = 1;
|
|
7387
7420
|
let vecEastY = 0;
|
|
7388
7421
|
let vecSouthX = 0;
|
|
@@ -7390,7 +7423,7 @@ var CollisionIndex = class {
|
|
|
7390
7423
|
const translatedAnchorX = collisionBox.anchorPointX + translation[0];
|
|
7391
7424
|
const translatedAnchorY = collisionBox.anchorPointY + translation[1];
|
|
7392
7425
|
if (rotateWithMap && !pitchWithMap) {
|
|
7393
|
-
const projectedEast = this.projectAndGetPerspectiveRatio(translatedAnchorX + 1, translatedAnchorY, unwrappedTileID, getElevation, simpleProjectionMatrix);
|
|
7426
|
+
const projectedEast = this.projectAndGetPerspectiveRatio(translatedAnchorX + 1, translatedAnchorY, unwrappedTileID, getSymbolElevation(getElevation, translatedAnchorX + 1, translatedAnchorY, heightOffset, heightAnchorGround), simpleProjectionMatrix);
|
|
7394
7427
|
const toEastX = projectedEast.x - projectedPoint.x;
|
|
7395
7428
|
const toEastY = projectedEast.y - projectedPoint.y;
|
|
7396
7429
|
const angle = Math.atan(toEastY / toEastX) + (toEastX < 0 ? Math.PI : 0);
|
|
@@ -7470,7 +7503,7 @@ var CollisionIndex = class {
|
|
|
7470
7503
|
for (const { offsetX, offsetY } of offsetsArray) points.push(new Point(basePointX + vecEastX * offsetX + vecSouthX * offsetY, basePointY + vecEastY * offsetX + vecSouthY * offsetY));
|
|
7471
7504
|
let anyPointVisible = false;
|
|
7472
7505
|
if (pitchWithMap) {
|
|
7473
|
-
const projected = points.map((p) => this.projectAndGetPerspectiveRatio(p.x, p.y, unwrappedTileID, getElevation, simpleProjectionMatrix));
|
|
7506
|
+
const projected = points.map((p) => this.projectAndGetPerspectiveRatio(p.x, p.y, unwrappedTileID, getSymbolElevation(getElevation, p.x, p.y, heightOffset, heightAnchorGround), simpleProjectionMatrix));
|
|
7474
7507
|
anyPointVisible = projected.some((p) => !p.isOccluded);
|
|
7475
7508
|
points = projected.map((p) => new Point(p.x, p.y));
|
|
7476
7509
|
} else anyPointVisible = true;
|
|
@@ -7568,7 +7601,7 @@ var Placement = class {
|
|
|
7568
7601
|
}
|
|
7569
7602
|
_getTerrainElevationFunc(tileID) {
|
|
7570
7603
|
const terrain = this.terrain;
|
|
7571
|
-
if (!terrain) return
|
|
7604
|
+
if (!terrain) return void 0;
|
|
7572
7605
|
return (x, y) => terrain.getElevation(tileID, x, y);
|
|
7573
7606
|
}
|
|
7574
7607
|
getBucketParts(results, styleLayer, tile, sortAcrossTiles) {
|
|
@@ -7616,13 +7649,13 @@ var Placement = class {
|
|
|
7616
7649
|
parameters
|
|
7617
7650
|
});
|
|
7618
7651
|
}
|
|
7619
|
-
attemptAnchorPlacement(textAnchorOffset, textBox, width, height, textBoxScale, rotateWithMap, pitchWithMap, textPixelRatio, tileID, unwrappedTileID, collisionGroup, textOverlapMode, symbolInstance, bucket, orientation, translationText, translationIcon, iconBox, getElevation, simpleProjectionMatrix) {
|
|
7652
|
+
attemptAnchorPlacement(textAnchorOffset, textBox, width, height, textBoxScale, rotateWithMap, pitchWithMap, textPixelRatio, tileID, unwrappedTileID, collisionGroup, textOverlapMode, symbolInstance, bucket, orientation, translationText, translationIcon, iconBox, getElevation, simpleProjectionMatrix, heightOffset, heightAnchorGround) {
|
|
7620
7653
|
const anchor = TextAnchorEnum[textAnchorOffset.textAnchor];
|
|
7621
7654
|
const textOffset = [textAnchorOffset.textOffset0, textAnchorOffset.textOffset1];
|
|
7622
7655
|
const shift = calculateVariableLayoutShift(anchor, width, height, textOffset, textBoxScale);
|
|
7623
|
-
const placedGlyphBoxes = this.collisionIndex.placeCollisionBox(textBox, textOverlapMode, textPixelRatio, tileID, unwrappedTileID, pitchWithMap, rotateWithMap, translationText, collisionGroup.predicate, getElevation, shift, simpleProjectionMatrix);
|
|
7656
|
+
const placedGlyphBoxes = this.collisionIndex.placeCollisionBox(textBox, textOverlapMode, textPixelRatio, tileID, unwrappedTileID, pitchWithMap, rotateWithMap, translationText, collisionGroup.predicate, getElevation, shift, simpleProjectionMatrix, heightOffset, heightAnchorGround);
|
|
7624
7657
|
if (iconBox) {
|
|
7625
|
-
if (!this.collisionIndex.placeCollisionBox(iconBox, textOverlapMode, textPixelRatio, tileID, unwrappedTileID, pitchWithMap, rotateWithMap, translationIcon, collisionGroup.predicate, getElevation, shift, simpleProjectionMatrix).placeable) return;
|
|
7658
|
+
if (!this.collisionIndex.placeCollisionBox(iconBox, textOverlapMode, textPixelRatio, tileID, unwrappedTileID, pitchWithMap, rotateWithMap, translationIcon, collisionGroup.predicate, getElevation, shift, simpleProjectionMatrix, heightOffset, heightAnchorGround).placeable) return;
|
|
7626
7659
|
}
|
|
7627
7660
|
if (placedGlyphBoxes.placeable) {
|
|
7628
7661
|
let prevAnchor;
|
|
@@ -7659,6 +7692,7 @@ var Placement = class {
|
|
|
7659
7692
|
const pitchWithMap = layout.get("text-pitch-alignment") === "map";
|
|
7660
7693
|
const hasIconTextFit = layout.get("icon-text-fit") !== "none";
|
|
7661
7694
|
const zOrderByViewportY = layout.get("symbol-z-order") === "viewport-y";
|
|
7695
|
+
const heightAnchorGround = layout.get("symbol-height-anchor") === "ground";
|
|
7662
7696
|
const alwaysShowText = textAlwaysOverlap && (iconAlwaysOverlap || !bucket.hasIconData() || iconOptional);
|
|
7663
7697
|
const alwaysShowIcon = iconAlwaysOverlap && (textAlwaysOverlap || !bucket.hasTextData() || textOptional);
|
|
7664
7698
|
if (!bucket.collisionArrays && collisionBoxArray) bucket.deserializeCollisionBoxes(collisionBoxArray);
|
|
@@ -7671,6 +7705,7 @@ var Placement = class {
|
|
|
7671
7705
|
this.placements[symbolInstance.crossTileID] = new JointPlacement(false, false, false);
|
|
7672
7706
|
return;
|
|
7673
7707
|
}
|
|
7708
|
+
const symbolHeightOffset = symbolInstance.heightOffset;
|
|
7674
7709
|
let placeText = false;
|
|
7675
7710
|
let placeIcon = false;
|
|
7676
7711
|
let offscreen = true;
|
|
@@ -7723,7 +7758,7 @@ var Placement = class {
|
|
|
7723
7758
|
const textAnchorOffsetEnd = symbolInstance.textAnchorOffsetEndIndex;
|
|
7724
7759
|
if (textAnchorOffsetEnd === textAnchorOffsetStart) {
|
|
7725
7760
|
const placeBox = (collisionTextBox, orientation) => {
|
|
7726
|
-
const placedFeature = this.collisionIndex.placeCollisionBox(collisionTextBox, textOverlapMode, textPixelRatio, tileID, unwrappedTileID, pitchWithMap, rotateWithMap, translationText, collisionGroup.predicate, getElevation, void 0, simpleProjectionMatrix);
|
|
7761
|
+
const placedFeature = this.collisionIndex.placeCollisionBox(collisionTextBox, textOverlapMode, textPixelRatio, tileID, unwrappedTileID, pitchWithMap, rotateWithMap, translationText, collisionGroup.predicate, getElevation, void 0, simpleProjectionMatrix, symbolHeightOffset, heightAnchorGround);
|
|
7727
7762
|
if (placedFeature?.placeable) {
|
|
7728
7763
|
this.markUsedOrientation(bucket, orientation, symbolInstance);
|
|
7729
7764
|
this.placedOrientations[symbolInstance.crossTileID] = orientation;
|
|
@@ -7758,7 +7793,7 @@ var Placement = class {
|
|
|
7758
7793
|
for (let i = textAnchorOffsetStart; i < textAnchorOffsetEnd; i++) {
|
|
7759
7794
|
const textAnchorOffset = bucket.textAnchorOffsets.get(i);
|
|
7760
7795
|
if (prevAnchor && textAnchorOffset.textAnchor !== prevAnchor) continue;
|
|
7761
|
-
const result = this.attemptAnchorPlacement(textAnchorOffset, collisionTextBox, width, height, textBoxScale, rotateWithMap, pitchWithMap, textPixelRatio, tileID, unwrappedTileID, collisionGroup, overlapMode, symbolInstance, bucket, orientation, translationText, translationIcon, variableIconBox, getElevation);
|
|
7796
|
+
const result = this.attemptAnchorPlacement(textAnchorOffset, collisionTextBox, width, height, textBoxScale, rotateWithMap, pitchWithMap, textPixelRatio, tileID, unwrappedTileID, collisionGroup, overlapMode, symbolInstance, bucket, orientation, translationText, translationIcon, variableIconBox, getElevation, simpleProjectionMatrix, symbolHeightOffset, heightAnchorGround);
|
|
7762
7797
|
if (result) {
|
|
7763
7798
|
placedBox = result.placedGlyphBoxes;
|
|
7764
7799
|
if (placedBox?.placeable) {
|
|
@@ -7772,7 +7807,7 @@ var Placement = class {
|
|
|
7772
7807
|
else overlapMode = textOverlapMode;
|
|
7773
7808
|
}
|
|
7774
7809
|
if (showCollisionBoxes && !placedBox) placedBox = {
|
|
7775
|
-
box: this.collisionIndex.placeCollisionBox(textBox, "always", textPixelRatio, tileID, unwrappedTileID, pitchWithMap, rotateWithMap, translationText, collisionGroup.predicate, getElevation, void 0, simpleProjectionMatrix).box,
|
|
7810
|
+
box: this.collisionIndex.placeCollisionBox(textBox, "always", textPixelRatio, tileID, unwrappedTileID, pitchWithMap, rotateWithMap, translationText, collisionGroup.predicate, getElevation, void 0, simpleProjectionMatrix, symbolHeightOffset, heightAnchorGround).box,
|
|
7776
7811
|
offscreen: false,
|
|
7777
7812
|
placeable: false,
|
|
7778
7813
|
occluded: false
|
|
@@ -7823,7 +7858,7 @@ var Placement = class {
|
|
|
7823
7858
|
if (collisionArrays.iconFeatureIndex) iconFeatureIndex = collisionArrays.iconFeatureIndex;
|
|
7824
7859
|
if (collisionArrays.iconBox) {
|
|
7825
7860
|
const placeIconFeature = (iconBox) => {
|
|
7826
|
-
return this.collisionIndex.placeCollisionBox(iconBox, iconOverlapMode, textPixelRatio, tileID, unwrappedTileID, pitchWithMap, rotateWithMap, translationIcon, collisionGroup.predicate, getElevation, hasIconTextFit && shift ? shift : void 0, simpleProjectionMatrix);
|
|
7861
|
+
return this.collisionIndex.placeCollisionBox(iconBox, iconOverlapMode, textPixelRatio, tileID, unwrappedTileID, pitchWithMap, rotateWithMap, translationIcon, collisionGroup.predicate, getElevation, hasIconTextFit && shift ? shift : void 0, simpleProjectionMatrix, symbolHeightOffset, heightAnchorGround);
|
|
7827
7862
|
};
|
|
7828
7863
|
if (placedVerticalText && placedVerticalText.placeable && collisionArrays.verticalIconBox) {
|
|
7829
7864
|
placedIconBoxes = placeIconFeature(collisionArrays.verticalIconBox);
|
|
@@ -8778,12 +8813,11 @@ const shaders = {
|
|
|
8778
8813
|
lineGradientSDF: prepare("uniform lowp float u_device_pixel_ratio;uniform sampler2D u_image;uniform sampler2D u_image_dash;uniform float u_mix;uniform lowp float u_lineatlas_width;in vec2 v_normal;flat in vec2 v_width2;in vec2 v_tex_a;in vec2 v_tex_b;in float v_gamma_scale;in highp vec2 v_uv;\n#ifdef GLOBE\nin float v_depth;\n#endif\n#pragma maplibre: define lowp float blur\n#pragma maplibre: define lowp float opacity\n#pragma maplibre: define mediump float width\n#pragma maplibre: define lowp float floorwidth\n#pragma maplibre: define mediump vec4 dasharray_from\n#pragma maplibre: define mediump vec4 dasharray_to\nvoid main() {\n#pragma maplibre: initialize lowp float blur\n#pragma maplibre: initialize lowp float opacity\n#pragma maplibre: initialize mediump float width\n#pragma maplibre: initialize lowp float floorwidth\n#pragma maplibre: initialize mediump vec4 dasharray_from\n#pragma maplibre: initialize mediump vec4 dasharray_to\nclipAntimeridian();float dist=length(v_normal)*v_width2.s;float blur2=(blur+1.0/u_device_pixel_ratio)*v_gamma_scale;float alpha=clamp(min(dist-(v_width2.t-blur2),v_width2.s-dist)/blur2,0.0,1.0);vec4 color=texture(u_image,v_uv);float sdfdist_a=texture(u_image_dash,v_tex_a).a;float sdfdist_b=texture(u_image_dash,v_tex_b).a;float sdfdist=mix(sdfdist_a,sdfdist_b,u_mix);float sdfgamma=(u_lineatlas_width/256.0)/min(dasharray_from.w,dasharray_to.w);float dash_alpha=smoothstep(0.5-sdfgamma/floorwidth,0.5+sdfgamma/floorwidth,sdfdist);fragColor=color*(alpha*dash_alpha*opacity);\n#ifdef GLOBE\nif (v_depth > 1.0) {discard;}\n#endif\n#ifdef OVERDRAW_INSPECTOR\nfragColor=vec4(1.0);\n#endif\n}", "\n#define scale 0.015873016\n#define LINE_DISTANCE_SCALE 2.0\nlayout(location=0) in ivec2 a_pos_normal;layout(location=1) in uvec4 a_data;layout(location=2) in float a_uv_x;layout(location=3) in float a_split_index;uniform vec2 u_translation;uniform mediump float u_ratio;uniform lowp float u_device_pixel_ratio;uniform vec2 u_units_to_pixels;uniform float u_image_height;uniform float u_tileratio;uniform float u_crossfade_from;uniform float u_crossfade_to;uniform float u_lineatlas_height;out vec2 v_normal;flat out vec2 v_width2;out float v_gamma_scale;out highp vec2 v_uv;out vec2 v_tex_a;out vec2 v_tex_b;\n#ifdef GLOBE\nout float v_depth;\n#endif\n#pragma maplibre: define lowp float blur\n#pragma maplibre: define lowp float opacity\n#pragma maplibre: define mediump float gapwidth\n#pragma maplibre: define lowp float offset\n#pragma maplibre: define mediump float width\n#pragma maplibre: define lowp float floorwidth\n#pragma maplibre: define mediump vec4 dasharray_from\n#pragma maplibre: define mediump vec4 dasharray_to\nvoid main() {\n#pragma maplibre: initialize lowp float blur\n#pragma maplibre: initialize lowp float opacity\n#pragma maplibre: initialize mediump float gapwidth\n#pragma maplibre: initialize lowp float offset\n#pragma maplibre: initialize mediump float width\n#pragma maplibre: initialize lowp float floorwidth\n#pragma maplibre: initialize mediump vec4 dasharray_from\n#pragma maplibre: initialize mediump vec4 dasharray_to\nif (opacity < 0.01) {gl_Position=vec4(-2.0,-2.0,-2.0,1.0);return;}float ANTIALIASING=1.0/u_device_pixel_ratio/2.0;vec2 a_extrude=vec2(ivec2(a_data.xy)-128);float a_direction=float(int(a_data.z & 3u)-1);float a_linesofar=float((a_data.z >> 2u)+a_data.w*64u)*LINE_DISTANCE_SCALE;float texel_height=1.0/u_image_height;float half_texel_height=0.5*texel_height;v_uv=vec2(a_uv_x,a_split_index*texel_height-half_texel_height);vec2 pos=vec2(a_pos_normal >> 1);mediump vec2 normal=vec2(a_pos_normal & 1);normal.y=normal.y*2.0-1.0;v_normal=normal;gapwidth=gapwidth/2.0;float halfwidth=width/2.0;offset=-1.0*offset;float inset=gapwidth+(gapwidth > 0.0 ? ANTIALIASING : 0.0);float outset=gapwidth+halfwidth*(gapwidth > 0.0 ? 2.0 : 1.0)+(halfwidth==0.0 ? 0.0 : ANTIALIASING);mediump vec2 dist=outset*a_extrude*scale;mediump float u=0.5*a_direction;mediump float t=1.0-abs(u);mediump vec2 offset2=offset*a_extrude*scale*normal.y*mat2(t,-u,u,t);float adjustedThickness=projectLineThickness(pos.y);vec4 projected_no_extrude=projectTile(pos+offset2/u_ratio*adjustedThickness+u_translation);vec4 projected_with_extrude=projectTile(pos+offset2/u_ratio*adjustedThickness+u_translation+dist/u_ratio*adjustedThickness);gl_Position=projected_with_extrude;\n#ifdef GLOBE\nv_depth=gl_Position.z/gl_Position.w;\n#endif\n#ifdef TERRAIN3D\nv_gamma_scale=1.0;\n#else\nfloat extrude_length_without_perspective=length(dist);float extrude_length_with_perspective=length((projected_with_extrude.xy-projected_no_extrude.xy)/projected_with_extrude.w*u_units_to_pixels);v_gamma_scale=extrude_length_without_perspective/extrude_length_with_perspective;\n#endif\nfloat u_patternscale_a_x=u_tileratio/dasharray_from.w/u_crossfade_from;float u_patternscale_a_y=-dasharray_from.z/2.0/u_lineatlas_height;float u_patternscale_b_x=u_tileratio/dasharray_to.w/u_crossfade_to;float u_patternscale_b_y=-dasharray_to.z/2.0/u_lineatlas_height;v_tex_a=vec2(a_linesofar*u_patternscale_a_x/floorwidth,normal.y*u_patternscale_a_y+(float(dasharray_from.y)+0.5)/u_lineatlas_height);v_tex_b=vec2(a_linesofar*u_patternscale_b_x/floorwidth,normal.y*u_patternscale_b_y+(float(dasharray_to.y)+0.5)/u_lineatlas_height);v_width2=vec2(outset,inset);}"),
|
|
8779
8814
|
layerOpacity: prepare("uniform sampler2D u_image;uniform float u_opacity;in vec2 v_pos;void main() {fragColor=texture(u_image,v_pos)*u_opacity;\n#ifdef OVERDRAW_INSPECTOR\nfragColor=vec4(0.0);\n#endif\n}", "layout(location=0) in vec2 a_pos;out vec2 v_pos;void main() {gl_Position=vec4(a_pos.x*2.0-1.0,1.0-a_pos.y*2.0,0.0,1.0);v_pos.x=a_pos.x;v_pos.y=1.0-a_pos.y;}"),
|
|
8780
8815
|
raster: prepare("uniform float u_fade_t;uniform float u_opacity;uniform sampler2D u_image0;uniform sampler2D u_image1;in vec3 v_pos0;in vec3 v_pos1;uniform float u_brightness_low;uniform float u_brightness_high;uniform float u_saturation_factor;uniform float u_contrast_factor;uniform vec3 u_spin_weights;void main() {vec4 color0=texture(u_image0,v_pos0.xy/v_pos0.z);vec4 color1=texture(u_image1,v_pos1.xy/v_pos1.z);if (color0.a > 0.0) {color0.rgb=color0.rgb/color0.a;}if (color1.a > 0.0) {color1.rgb=color1.rgb/color1.a;}vec4 color=mix(color0,color1,u_fade_t);color.a*=u_opacity;vec3 rgb=color.rgb;rgb=vec3(dot(rgb,u_spin_weights.xyz),dot(rgb,u_spin_weights.zxy),dot(rgb,u_spin_weights.yzx));float average=(color.r+color.g+color.b)/3.0;rgb+=(average-rgb)*u_saturation_factor;rgb=(rgb-0.5)*u_contrast_factor+0.5;vec3 u_high_vec=vec3(u_brightness_low,u_brightness_low,u_brightness_low);vec3 u_low_vec=vec3(u_brightness_high,u_brightness_high,u_brightness_high);fragColor=vec4(mix(u_high_vec,u_low_vec,rgb)*color.a,color.a);\n#ifdef OVERDRAW_INSPECTOR\nfragColor=vec4(1.0);\n#endif\n}", "uniform vec2 u_tl_parent;uniform float u_scale_parent;uniform float u_buffer_scale;uniform vec3 u_image_warp;uniform vec4 u_coords_top;uniform vec4 u_coords_bottom;layout(location=0) in vec2 a_pos;out vec3 v_pos0;out vec3 v_pos1;void main() {vec2 fractionalPos=a_pos/8192.0;vec2 topLeft=u_coords_top.xy;vec2 topRight=u_coords_top.zw;vec2 bottomLeft=u_coords_bottom.xy;vec2 bottomRight=u_coords_bottom.zw;vec2 bilinearPos=mix(mix(topLeft,topRight,fractionalPos.x),mix(bottomLeft,bottomRight,fractionalPos.x),fractionalPos.y);float denominator=dot(u_image_warp.xy,fractionalPos)+1.0;vec2 acrossTop=topRight-topLeft+u_image_warp.x*topRight;vec2 downLeft=bottomLeft-topLeft+u_image_warp.y*bottomLeft;vec2 projectivePos=(acrossTop*fractionalPos.x+downLeft*fractionalPos.y+topLeft)/denominator;vec2 position=mix(projectivePos,bilinearPos,u_image_warp.z);gl_Position=projectTile(position,position);vec2 texturePos=((fractionalPos-0.5)/u_buffer_scale)+0.5;\n#ifdef GLOBE\nif (a_pos.y <-32767.5) {texturePos.y=0.0;}if (a_pos.y > 32766.5) {texturePos.y=1.0;}\n#endif\nfloat perspectiveRatio=mix(1.0/denominator,1.0,u_image_warp.z);v_pos0=vec3(texturePos*perspectiveRatio,perspectiveRatio);vec2 parentPos=(texturePos*u_scale_parent)+u_tl_parent;v_pos1=vec3(parentPos*perspectiveRatio,perspectiveRatio);}"),
|
|
8781
|
-
symbolIcon: prepare("uniform sampler2D u_texture;in vec2 v_tex;flat in float v_total_opacity;void main() {fragColor=texture(u_texture,v_tex)*v_total_opacity;\n#ifdef OVERDRAW_INSPECTOR\nfragColor=vec4(1.0);\n#endif\n}", "layout(location=0) in vec4 a_pos_offset;layout(location=1) in uvec4 a_data;layout(location=2) in vec4 a_pixeloffset;layout(location=3) in vec3 a_projected_pos;layout(location=4) in uint a_fade_opacity;uniform bool u_is_size_zoom_constant;uniform bool u_is_size_feature_constant;uniform highp float u_size_t;uniform highp float u_size;uniform highp float u_camera_to_center_distance;uniform highp float u_pitch;uniform bool u_rotate_symbol;uniform highp float u_aspect_ratio;uniform float u_fade_change;uniform mat4 u_label_plane_matrix;uniform mat4 u_coord_matrix;uniform bool u_is_text;uniform bool u_pitch_with_map;uniform vec2 u_texsize;uniform bool u_is_along_line;uniform bool u_is_variable_anchor;uniform vec2 u_translation;uniform float u_pitched_scale;uniform bool u_is_offset;out vec2 v_tex;flat out float v_total_opacity;\n#pragma maplibre: define lowp float opacity\nvoid main() {\n#pragma maplibre: initialize lowp float opacity\nvec2 a_pos=a_pos_offset.xy;vec2 a_offset=a_pos_offset.zw;vec2 a_tex=vec2(a_data.xy);vec2 a_size=vec2(a_data.zw);float a_size_min=float(a_data.z >> 1u);vec2 a_pxoffset=a_pixeloffset.xy;vec2 a_minFontScale=a_pixeloffset.zw/256.0;float ele=get_elevation(a_pos);highp float segment_angle=-a_projected_pos[2];float size;if (!u_is_size_zoom_constant && !u_is_size_feature_constant) {size=mix(a_size_min,a_size[1],u_size_t)/128.0;} else if (u_is_size_zoom_constant && !u_is_size_feature_constant) {size=a_size_min/128.0;} else {size=u_size;}vec2 translated_a_pos=a_pos+u_translation;vec4 projectedPoint=projectTileWithElevation(translated_a_pos,ele);vec2 fade_opacity=unpack_opacity(a_fade_opacity);float fade_change=fade_opacity[1] > 0.5 ? u_fade_change :-u_fade_change;float visibility=calculate_visibility(projectedPoint);v_total_opacity=opacity*max(0.0,min(visibility,fade_opacity[0]+fade_change));if (v_total_opacity < 0.1){gl_Position=vec4(-2.,-2.,-2.,1.);return;}highp float camera_to_anchor_distance=projectedPoint.w;highp float distance_ratio=u_pitch_with_map ?\ncamera_to_anchor_distance/u_camera_to_center_distance :\nu_camera_to_center_distance/camera_to_anchor_distance;highp float perspective_ratio=clamp(0.5+0.5*distance_ratio,0.0,4.0);if (!u_is_offset) {size*=perspective_ratio;}float fontScale=u_is_text ? size/24.0 : size;highp float symbol_rotation=0.0;if (u_rotate_symbol) {vec4 offsetProjectedPoint=projectTileWithElevation(translated_a_pos+vec2(1,0),ele);vec2 a=projectedPoint.xy/projectedPoint.w;vec2 b=offsetProjectedPoint.xy/offsetProjectedPoint.w;symbol_rotation=atan((b.y-a.y)/u_aspect_ratio,b.x-a.x);}highp float angle_sin=sin(segment_angle+symbol_rotation);highp float angle_cos=cos(segment_angle+symbol_rotation);mat2 rotation_matrix=mat2(angle_cos,-1.0*angle_sin,angle_sin,angle_cos);vec4 projected_pos;if (u_is_along_line || u_is_variable_anchor) {projected_pos=vec4(a_projected_pos.xy,ele,1.0);} else if (u_pitch_with_map) {projected_pos=u_label_plane_matrix*vec4(a_projected_pos.xy+u_translation,ele,1.0);} else {projected_pos=u_label_plane_matrix*projectTileWithElevation(a_projected_pos.xy+u_translation,ele);}float z=float(u_pitch_with_map)*projected_pos.z/projected_pos.w;float projectionScaling=1.0;\n#ifdef GLOBE\nif(u_pitch_with_map) {float anchor_pos_tile_y=(u_coord_matrix*vec4(projected_pos.xy/projected_pos.w,z,1.0)).y;projectionScaling=mix(projectionScaling,1.0/circumferenceRatioAtTileY(anchor_pos_tile_y)*u_pitched_scale,u_projection_transition);}\n#endif\nvec4 finalPos=u_coord_matrix*vec4(projected_pos.xy/projected_pos.w+rotation_matrix*(a_offset/32.0*max(a_minFontScale,fontScale)+a_pxoffset/16.0)*projectionScaling,z,1.0);if(u_pitch_with_map) {finalPos=projectTileWithElevation(finalPos.xy,finalPos.z);}gl_Position=finalPos;v_tex=a_tex/u_texsize;}"),
|
|
8782
|
-
symbolSDF: prepare("#define SDF_PX 8.0\nuniform bool u_is_halo;uniform bool u_is_plain;uniform sampler2D u_texture;uniform highp float u_gamma_scale;uniform lowp float u_device_pixel_ratio;uniform bool u_is_text;in vec2 v_data0;in vec3 v_data1;\n#pragma maplibre: define highp vec4 fill_color\n#pragma maplibre: define highp vec4 halo_color\n#pragma maplibre: define lowp float halo_width\n#pragma maplibre: define lowp float halo_blur\nvoid main() {\n#pragma maplibre: initialize highp vec4 fill_color\n#pragma maplibre: initialize highp vec4 halo_color\n#pragma maplibre: initialize lowp float halo_width\n#pragma maplibre: initialize lowp float halo_blur\nfloat EDGE_GAMMA=0.105/u_device_pixel_ratio;vec2 tex=v_data0.xy;float gamma_scale=v_data1.x;float size=v_data1.y;float total_opacity=v_data1[2];float fontScale=u_is_text ? size/24.0 : size;highp float gamma=EDGE_GAMMA/(fontScale*u_gamma_scale);lowp float inner_edge=(256.0-64.0)/256.0;lowp float dist=texture(u_texture,tex).a;lowp vec4 color_alpha_out_text,color_alpha_out_halo;if (u_is_plain){highp float gamma_scaled=gamma*gamma_scale;highp float alpha=smoothstep(inner_edge-gamma_scaled,inner_edge+gamma_scaled,dist);color_alpha_out_text=total_opacity*alpha*fill_color;}if (u_is_halo) {float gamma_halo=(halo_blur*1.19/SDF_PX+EDGE_GAMMA)/(fontScale*u_gamma_scale);float inner_edge_halo=inner_edge+gamma_halo*gamma_scale;highp float gamma_scaled_halo=gamma_halo*gamma_scale;highp float alpha_halo=smoothstep(inner_edge_halo-gamma_scaled_halo,inner_edge_halo+gamma_scaled_halo,dist);highp float halo_edge=(6.0-halo_width/fontScale)/SDF_PX;alpha_halo= min(smoothstep(halo_edge-gamma_scaled_halo,halo_edge+gamma_scaled_halo,dist),1.0-alpha_halo);color_alpha_out_halo=total_opacity*alpha_halo*halo_color;}if (u_is_plain && u_is_halo) {fragColor=color_alpha_out_text+(1.-color_alpha_out_text.a)*color_alpha_out_halo;} else if (u_is_halo){fragColor=color_alpha_out_halo;} else {fragColor=color_alpha_out_text;}\n#ifdef OVERDRAW_INSPECTOR\nfragColor=vec4(1.0);\n#endif\n}", "layout(location=0) in vec4 a_pos_offset;layout(location=1) in uvec4 a_data;layout(location=2) in vec4 a_pixeloffset;layout(location=3) in vec3 a_projected_pos;layout(location=4) in uint a_fade_opacity;uniform bool u_is_size_zoom_constant;uniform bool u_is_size_feature_constant;uniform highp float u_size_t;uniform highp float u_size;uniform mat4 u_label_plane_matrix;uniform mat4 u_coord_matrix;uniform bool u_is_text;uniform bool u_pitch_with_map;uniform bool u_is_along_line;uniform bool u_is_variable_anchor;uniform highp float u_pitch;uniform bool u_rotate_symbol;uniform highp float u_aspect_ratio;uniform highp float u_camera_to_center_distance;uniform float u_fade_change;uniform vec2 u_texsize;uniform vec2 u_translation;uniform float u_pitched_scale;uniform bool u_is_offset;out vec2 v_data0;out vec3 v_data1;\n#pragma maplibre: define highp vec4 fill_color\n#pragma maplibre: define highp vec4 halo_color\n#pragma maplibre: define lowp float opacity\n#pragma maplibre: define lowp float halo_width\n#pragma maplibre: define lowp float halo_blur\nvoid main() {\n#pragma maplibre: initialize highp vec4 fill_color\n#pragma maplibre: initialize highp vec4 halo_color\n#pragma maplibre: initialize lowp float opacity\n#pragma maplibre: initialize lowp float halo_width\n#pragma maplibre: initialize lowp float halo_blur\nvec2 a_pos=a_pos_offset.xy;vec2 a_offset=a_pos_offset.zw;vec2 a_tex=vec2(a_data.xy);vec2 a_size=vec2(a_data.zw);float a_size_min=float(a_data.z >> 1u);vec2 a_pxoffset=a_pixeloffset.xy/16.0;vec2 a_minFontScale=a_pixeloffset.zw/256.0;float ele=get_elevation(a_pos);highp float segment_angle=-a_projected_pos[2];float size;if (!u_is_size_zoom_constant && !u_is_size_feature_constant) {size=mix(a_size_min,a_size[1],u_size_t)/128.0;} else if (u_is_size_zoom_constant && !u_is_size_feature_constant) {size=a_size_min/128.0;} else {size=u_size;}vec2 translated_a_pos=a_pos+u_translation;vec4 projectedPoint=projectTileWithElevation(translated_a_pos,ele);vec2 fade_opacity=unpack_opacity(a_fade_opacity);float visibility=calculate_visibility(projectedPoint);float fade_change=fade_opacity[1] > 0.5 ? u_fade_change :-u_fade_change;float interpolated_fade_opacity=max(0.0,min(visibility,fade_opacity[0]+fade_change));float total_opacity=opacity*interpolated_fade_opacity;if (total_opacity < 0.1){gl_Position=vec4(-2.,-2.,-2.,1.);return;}highp float camera_to_anchor_distance=projectedPoint.w;highp float distance_ratio=u_pitch_with_map ?\ncamera_to_anchor_distance/u_camera_to_center_distance :\nu_camera_to_center_distance/camera_to_anchor_distance;highp float perspective_ratio=clamp(0.5+0.5*distance_ratio,0.0,4.0);if (!u_is_offset) {size*=perspective_ratio;}float fontScale=u_is_text ? size/24.0 : size;highp float symbol_rotation=0.0;if (u_rotate_symbol) {vec4 offsetProjectedPoint=projectTileWithElevation(translated_a_pos+vec2(1,0),ele);vec2 a=projectedPoint.xy/projectedPoint.w;vec2 b=offsetProjectedPoint.xy/offsetProjectedPoint.w;symbol_rotation=atan((b.y-a.y)/u_aspect_ratio,b.x-a.x);}highp float angle_sin=sin(segment_angle+symbol_rotation);highp float angle_cos=cos(segment_angle+symbol_rotation);mat2 rotation_matrix=mat2(angle_cos,-1.0*angle_sin,angle_sin,angle_cos);vec4 projected_pos;if (u_is_along_line || u_is_variable_anchor) {projected_pos=vec4(a_projected_pos.xy,ele,1.0);} else if (u_pitch_with_map) {projected_pos=u_label_plane_matrix*vec4(a_projected_pos.xy+u_translation,ele,1.0);} else {projected_pos=u_label_plane_matrix*projectTileWithElevation(a_projected_pos.xy+u_translation,ele);}float z=float(u_pitch_with_map)*projected_pos.z/projected_pos.w;float projectionScaling=1.0;\n#ifdef GLOBE\nif(u_pitch_with_map) {float anchor_pos_tile_y=(u_coord_matrix*vec4(projected_pos.xy/projected_pos.w,z,1.0)).y;projectionScaling=mix(projectionScaling,1.0/circumferenceRatioAtTileY(anchor_pos_tile_y)*u_pitched_scale,u_projection_transition);}\n#endif\nvec4 finalPos=u_coord_matrix*vec4(projected_pos.xy/projected_pos.w+rotation_matrix*(a_offset/32.0*max(a_minFontScale,fontScale)+a_pxoffset)*projectionScaling,z,1.0);if(u_pitch_with_map) {finalPos=projectTileWithElevation(finalPos.xy,finalPos.z);}float gamma_scale=finalPos.w;gl_Position=finalPos;v_data0=a_tex/u_texsize;v_data1=vec3(gamma_scale,size,total_opacity);}"),
|
|
8783
|
-
symbolTextAndIcon: prepare("#define SDF_PX 8.0\n#define SDF 1.0\n#define ICON 0.0\nuniform bool u_is_halo;uniform bool u_is_text;uniform sampler2D u_texture;uniform sampler2D u_texture_icon;uniform highp float u_gamma_scale;uniform lowp float u_device_pixel_ratio;in vec4 v_data0;in vec3 v_data1;flat in float v_is_sdf;\n#pragma maplibre: define highp vec4 fill_color\n#pragma maplibre: define highp vec4 halo_color\n#pragma maplibre: define lowp float halo_width\n#pragma maplibre: define lowp float halo_blur\nvoid main() {\n#pragma maplibre: initialize highp vec4 fill_color\n#pragma maplibre: initialize highp vec4 halo_color\n#pragma maplibre: initialize lowp float halo_width\n#pragma maplibre: initialize lowp float halo_blur\nfloat total_opacity=v_data1[2];if (v_is_sdf==ICON) {vec2 tex_icon=v_data0.zw;fragColor=texture(u_texture_icon,tex_icon)*total_opacity;\n#ifdef OVERDRAW_INSPECTOR\nfragColor=vec4(1.0);\n#endif\nreturn;}vec2 tex=v_data0.xy;float EDGE_GAMMA=0.105/u_device_pixel_ratio;float gamma_scale=v_data1.x;float size=v_data1.y;float fontScale=size/24.0;highp float gamma=EDGE_GAMMA/(fontScale*u_gamma_scale);lowp float buff=(256.0-64.0)/256.0;lowp float dist=texture(u_texture,tex).a;lowp vec4 color_alpha_out,color_alpha_out_halo;if (u_is_text) {highp float gamma_scaled=gamma*gamma_scale;highp float alpha=smoothstep(buff-gamma_scaled,buff+gamma_scaled,dist);color_alpha_out=fill_color*(alpha*total_opacity);}if (u_is_halo) {highp float gamma_halo=(halo_blur*1.19/SDF_PX+EDGE_GAMMA)/(fontScale*u_gamma_scale);lowp float buff_halo=(6.0-halo_width/fontScale)/SDF_PX;highp float gamma_scaled_halo=gamma_halo*gamma_scale;highp float alpha_halo=smoothstep(buff_halo-gamma_scaled_halo,buff_halo+gamma_scaled_halo,dist);color_alpha_out_halo=halo_color*(alpha_halo*total_opacity);}if (u_is_text && u_is_halo) {fragColor=color_alpha_out+(1.-color_alpha_out.a)*color_alpha_out_halo;} else if (u_is_halo) {fragColor=color_alpha_out_halo;} else {fragColor=color_alpha_out;}\n#ifdef OVERDRAW_INSPECTOR\nfragColor=vec4(1.0);\n#endif\n}", "layout(location=0) in vec4 a_pos_offset;layout(location=1) in uvec4 a_data;layout(location=2) in vec3 a_projected_pos;layout(location=3) in uint a_fade_opacity;uniform bool u_is_size_zoom_constant;uniform bool u_is_size_feature_constant;uniform highp float u_size_t;uniform highp float u_size;uniform mat4 u_label_plane_matrix;uniform mat4 u_coord_matrix;uniform bool u_is_text;uniform bool u_pitch_with_map;uniform highp float u_pitch;uniform bool u_rotate_symbol;uniform highp float u_aspect_ratio;uniform highp float u_camera_to_center_distance;uniform float u_fade_change;uniform vec2 u_texsize;uniform vec2 u_texsize_icon;uniform bool u_is_along_line;uniform bool u_is_variable_anchor;uniform vec2 u_translation;uniform float u_pitched_scale;uniform bool u_is_offset;out vec4 v_data0;out vec3 v_data1;flat out float v_is_sdf;\n#pragma maplibre: define highp vec4 fill_color\n#pragma maplibre: define highp vec4 halo_color\n#pragma maplibre: define lowp float opacity\n#pragma maplibre: define lowp float halo_width\n#pragma maplibre: define lowp float halo_blur\nvoid main() {\n#pragma maplibre: initialize highp vec4 fill_color\n#pragma maplibre: initialize highp vec4 halo_color\n#pragma maplibre: initialize lowp float opacity\n#pragma maplibre: initialize lowp float halo_width\n#pragma maplibre: initialize lowp float halo_blur\nvec2 a_pos=a_pos_offset.xy;vec2 a_offset=a_pos_offset.zw;vec2 a_tex=vec2(a_data.xy);vec2 a_size=vec2(a_data.zw);float a_size_min=float(a_data.z >> 1u);float is_sdf=float(a_data.z & 1u);float ele=get_elevation(a_pos);highp float segment_angle=-a_projected_pos[2];float size;if (!u_is_size_zoom_constant && !u_is_size_feature_constant) {size=mix(a_size_min,a_size[1],u_size_t)/128.0;} else if (u_is_size_zoom_constant && !u_is_size_feature_constant) {size=a_size_min/128.0;} else {size=u_size;}vec2 translated_a_pos=a_pos+u_translation;vec4 projectedPoint=projectTileWithElevation(translated_a_pos,ele);vec2 fade_opacity=unpack_opacity(a_fade_opacity);float visibility=calculate_visibility(projectedPoint);float fade_change=fade_opacity[1] > 0.5 ? u_fade_change :-u_fade_change;float interpolated_fade_opacity=max(0.0,min(visibility,fade_opacity[0]+fade_change));float total_opacity=opacity*interpolated_fade_opacity;if (total_opacity < 0.1){gl_Position=vec4(-2.,-2.,-2.,1.);return;}highp float camera_to_anchor_distance=projectedPoint.w;highp float distance_ratio=u_pitch_with_map ?\ncamera_to_anchor_distance/u_camera_to_center_distance :\nu_camera_to_center_distance/camera_to_anchor_distance;highp float perspective_ratio=clamp(0.5+0.5*distance_ratio,0.0,4.0);if (!u_is_offset) {size*=perspective_ratio;}float fontScale=size/24.0;highp float symbol_rotation=0.0;if (u_rotate_symbol) {vec4 offsetProjectedPoint=projectTileWithElevation(translated_a_pos+vec2(1,0),ele);vec2 a=projectedPoint.xy/projectedPoint.w;vec2 b=offsetProjectedPoint.xy/offsetProjectedPoint.w;symbol_rotation=atan((b.y-a.y)/u_aspect_ratio,b.x-a.x);}highp float angle_sin=sin(segment_angle+symbol_rotation);highp float angle_cos=cos(segment_angle+symbol_rotation);mat2 rotation_matrix=mat2(angle_cos,-1.0*angle_sin,angle_sin,angle_cos);vec4 projected_pos;if (u_is_along_line || u_is_variable_anchor) {projected_pos=vec4(a_projected_pos.xy,ele,1.0);} else if (u_pitch_with_map) {projected_pos=u_label_plane_matrix*vec4(a_projected_pos.xy+u_translation,ele,1.0);} else {projected_pos=u_label_plane_matrix*projectTileWithElevation(a_projected_pos.xy+u_translation,ele);}float z=float(u_pitch_with_map)*projected_pos.z/projected_pos.w;float projectionScaling=1.0;\n#ifdef GLOBE\nif(u_pitch_with_map && !u_is_along_line) {float anchor_pos_tile_y=(u_coord_matrix*vec4(projected_pos.xy/projected_pos.w,z,1.0)).y;projectionScaling=mix(projectionScaling,1.0/circumferenceRatioAtTileY(anchor_pos_tile_y)*u_pitched_scale,u_projection_transition);}\n#endif\nvec4 finalPos=u_coord_matrix*vec4(projected_pos.xy/projected_pos.w+rotation_matrix*(a_offset/32.0*fontScale)*projectionScaling,z,1.0);if(u_pitch_with_map) {finalPos=projectTileWithElevation(finalPos.xy,finalPos.z);}float gamma_scale=finalPos.w;gl_Position=finalPos;v_data0.xy=a_tex/u_texsize;v_data0.zw=a_tex/u_texsize_icon;v_data1=vec3(gamma_scale,size,total_opacity);v_is_sdf=is_sdf;}"),
|
|
8816
|
+
symbolIcon: prepare("uniform sampler2D u_texture;in vec2 v_tex;flat in float v_total_opacity;void main() {fragColor=texture(u_texture,v_tex)*v_total_opacity;\n#ifdef OVERDRAW_INSPECTOR\nfragColor=vec4(1.0);\n#endif\n}", "layout(location=0) in vec4 a_pos_offset;layout(location=1) in uvec4 a_data;layout(location=2) in vec4 a_pixeloffset;layout(location=3) in vec3 a_projected_pos;layout(location=4) in uint a_fade_opacity;layout(location=5) in float a_height_offset;uniform bool u_is_size_zoom_constant;uniform bool u_is_size_feature_constant;uniform highp float u_size_t;uniform highp float u_size;uniform highp float u_camera_to_center_distance;uniform highp float u_pitch;uniform bool u_rotate_symbol;uniform highp float u_aspect_ratio;uniform float u_fade_change;uniform mat4 u_label_plane_matrix;uniform mat4 u_coord_matrix;uniform bool u_is_text;uniform bool u_pitch_with_map;uniform vec2 u_texsize;uniform bool u_is_along_line;uniform bool u_is_variable_anchor;uniform vec2 u_translation;uniform float u_pitched_scale;uniform bool u_is_offset;uniform bool u_height_anchor_ground;out vec2 v_tex;flat out float v_total_opacity;\n#pragma maplibre: define lowp float opacity\nvoid main() {\n#pragma maplibre: initialize lowp float opacity\nvec2 a_pos=a_pos_offset.xy;vec2 a_offset=a_pos_offset.zw;vec2 a_tex=vec2(a_data.xy);vec2 a_size=vec2(a_data.zw);float a_size_min=float(a_data.z >> 1u);vec2 a_pxoffset=a_pixeloffset.xy;vec2 a_minFontScale=a_pixeloffset.zw/256.0;float ele=a_height_offset+(u_height_anchor_ground ? get_elevation(a_pos) : 0.0);highp float segment_angle=-a_projected_pos[2];float size;if (!u_is_size_zoom_constant && !u_is_size_feature_constant) {size=mix(a_size_min,a_size[1],u_size_t)/128.0;} else if (u_is_size_zoom_constant && !u_is_size_feature_constant) {size=a_size_min/128.0;} else {size=u_size;}vec2 translated_a_pos=a_pos+u_translation;vec4 projectedPoint=projectTileWithElevation(translated_a_pos,ele);vec2 fade_opacity=unpack_opacity(a_fade_opacity);float fade_change=fade_opacity[1] > 0.5 ? u_fade_change :-u_fade_change;float visibility=calculate_visibility(projectedPoint);v_total_opacity=opacity*max(0.0,min(visibility,fade_opacity[0]+fade_change));if (v_total_opacity < 0.1){gl_Position=vec4(-2.,-2.,-2.,1.);return;}highp float camera_to_anchor_distance=projectedPoint.w;highp float distance_ratio=u_pitch_with_map ?\ncamera_to_anchor_distance/u_camera_to_center_distance :\nu_camera_to_center_distance/camera_to_anchor_distance;highp float perspective_ratio=clamp(0.5+0.5*distance_ratio,0.0,4.0);if (!u_is_offset) {size*=perspective_ratio;}float fontScale=u_is_text ? size/24.0 : size;highp float symbol_rotation=0.0;if (u_rotate_symbol) {vec4 offsetProjectedPoint=projectTileWithElevation(translated_a_pos+vec2(1,0),ele);vec2 a=projectedPoint.xy/projectedPoint.w;vec2 b=offsetProjectedPoint.xy/offsetProjectedPoint.w;symbol_rotation=atan((b.y-a.y)/u_aspect_ratio,b.x-a.x);}highp float angle_sin=sin(segment_angle+symbol_rotation);highp float angle_cos=cos(segment_angle+symbol_rotation);mat2 rotation_matrix=mat2(angle_cos,-1.0*angle_sin,angle_sin,angle_cos);vec4 projected_pos;if (u_is_along_line || u_is_variable_anchor) {projected_pos=vec4(a_projected_pos.xy,ele,1.0);} else if (u_pitch_with_map) {projected_pos=u_label_plane_matrix*vec4(a_projected_pos.xy+u_translation,ele,1.0);} else {projected_pos=u_label_plane_matrix*projectTileWithElevation(a_projected_pos.xy+u_translation,ele);}float z=float(u_pitch_with_map)*projected_pos.z/projected_pos.w;float projectionScaling=1.0;\n#ifdef GLOBE\nif(u_pitch_with_map) {float anchor_pos_tile_y=(u_coord_matrix*vec4(projected_pos.xy/projected_pos.w,z,1.0)).y;projectionScaling=mix(projectionScaling,1.0/circumferenceRatioAtTileY(anchor_pos_tile_y)*u_pitched_scale,u_projection_transition);}\n#endif\nvec4 finalPos=u_coord_matrix*vec4(projected_pos.xy/projected_pos.w+rotation_matrix*(a_offset/32.0*max(a_minFontScale,fontScale)+a_pxoffset/16.0)*projectionScaling,z,1.0);if(u_pitch_with_map) {finalPos=projectTileWithElevation(finalPos.xy,finalPos.z);}gl_Position=finalPos;v_tex=a_tex/u_texsize;}"),
|
|
8817
|
+
symbolSDF: prepare("#define SDF_PX 8.0\nuniform bool u_is_halo;uniform bool u_is_plain;uniform sampler2D u_texture;uniform highp float u_gamma_scale;uniform lowp float u_device_pixel_ratio;uniform bool u_is_text;in vec2 v_data0;in vec3 v_data1;\n#pragma maplibre: define highp vec4 fill_color\n#pragma maplibre: define highp vec4 halo_color\n#pragma maplibre: define lowp float halo_width\n#pragma maplibre: define lowp float halo_blur\nvoid main() {\n#pragma maplibre: initialize highp vec4 fill_color\n#pragma maplibre: initialize highp vec4 halo_color\n#pragma maplibre: initialize lowp float halo_width\n#pragma maplibre: initialize lowp float halo_blur\nfloat EDGE_GAMMA=0.105/u_device_pixel_ratio;vec2 tex=v_data0.xy;float gamma_scale=v_data1.x;float size=v_data1.y;float total_opacity=v_data1[2];float fontScale=u_is_text ? size/24.0 : size;highp float gamma=EDGE_GAMMA/(fontScale*u_gamma_scale);lowp float inner_edge=(256.0-64.0)/256.0;lowp float dist=texture(u_texture,tex).a;lowp vec4 color_alpha_out_text,color_alpha_out_halo;if (u_is_plain){highp float gamma_scaled=gamma*gamma_scale;highp float alpha=smoothstep(inner_edge-gamma_scaled,inner_edge+gamma_scaled,dist);color_alpha_out_text=total_opacity*alpha*fill_color;}if (u_is_halo) {float gamma_halo=(halo_blur*1.19/SDF_PX+EDGE_GAMMA)/(fontScale*u_gamma_scale);float inner_edge_halo=inner_edge+gamma_halo*gamma_scale;highp float gamma_scaled_halo=gamma_halo*gamma_scale;highp float alpha_halo=smoothstep(inner_edge_halo-gamma_scaled_halo,inner_edge_halo+gamma_scaled_halo,dist);highp float halo_edge=(6.0-halo_width/fontScale)/SDF_PX;alpha_halo= min(smoothstep(halo_edge-gamma_scaled_halo,halo_edge+gamma_scaled_halo,dist),1.0-alpha_halo);color_alpha_out_halo=total_opacity*alpha_halo*halo_color;}if (u_is_plain && u_is_halo) {fragColor=color_alpha_out_text+(1.-color_alpha_out_text.a)*color_alpha_out_halo;} else if (u_is_halo){fragColor=color_alpha_out_halo;} else {fragColor=color_alpha_out_text;}\n#ifdef OVERDRAW_INSPECTOR\nfragColor=vec4(1.0);\n#endif\n}", "layout(location=0) in vec4 a_pos_offset;layout(location=1) in uvec4 a_data;layout(location=2) in vec4 a_pixeloffset;layout(location=3) in vec3 a_projected_pos;layout(location=4) in uint a_fade_opacity;layout(location=5) in float a_height_offset;uniform bool u_is_size_zoom_constant;uniform bool u_is_size_feature_constant;uniform highp float u_size_t;uniform highp float u_size;uniform mat4 u_label_plane_matrix;uniform mat4 u_coord_matrix;uniform bool u_is_text;uniform bool u_pitch_with_map;uniform bool u_is_along_line;uniform bool u_is_variable_anchor;uniform highp float u_pitch;uniform bool u_rotate_symbol;uniform highp float u_aspect_ratio;uniform highp float u_camera_to_center_distance;uniform float u_fade_change;uniform vec2 u_texsize;uniform vec2 u_translation;uniform float u_pitched_scale;uniform bool u_is_offset;uniform bool u_height_anchor_ground;out vec2 v_data0;out vec3 v_data1;\n#pragma maplibre: define highp vec4 fill_color\n#pragma maplibre: define highp vec4 halo_color\n#pragma maplibre: define lowp float opacity\n#pragma maplibre: define lowp float halo_width\n#pragma maplibre: define lowp float halo_blur\nvoid main() {\n#pragma maplibre: initialize highp vec4 fill_color\n#pragma maplibre: initialize highp vec4 halo_color\n#pragma maplibre: initialize lowp float opacity\n#pragma maplibre: initialize lowp float halo_width\n#pragma maplibre: initialize lowp float halo_blur\nvec2 a_pos=a_pos_offset.xy;vec2 a_offset=a_pos_offset.zw;vec2 a_tex=vec2(a_data.xy);vec2 a_size=vec2(a_data.zw);float a_size_min=float(a_data.z >> 1u);vec2 a_pxoffset=a_pixeloffset.xy/16.0;vec2 a_minFontScale=a_pixeloffset.zw/256.0;float ele=a_height_offset+(u_height_anchor_ground ? get_elevation(a_pos) : 0.0);highp float segment_angle=-a_projected_pos[2];float size;if (!u_is_size_zoom_constant && !u_is_size_feature_constant) {size=mix(a_size_min,a_size[1],u_size_t)/128.0;} else if (u_is_size_zoom_constant && !u_is_size_feature_constant) {size=a_size_min/128.0;} else {size=u_size;}vec2 translated_a_pos=a_pos+u_translation;vec4 projectedPoint=projectTileWithElevation(translated_a_pos,ele);vec2 fade_opacity=unpack_opacity(a_fade_opacity);float visibility=calculate_visibility(projectedPoint);float fade_change=fade_opacity[1] > 0.5 ? u_fade_change :-u_fade_change;float interpolated_fade_opacity=max(0.0,min(visibility,fade_opacity[0]+fade_change));float total_opacity=opacity*interpolated_fade_opacity;if (total_opacity < 0.1){gl_Position=vec4(-2.,-2.,-2.,1.);return;}highp float camera_to_anchor_distance=projectedPoint.w;highp float distance_ratio=u_pitch_with_map ?\ncamera_to_anchor_distance/u_camera_to_center_distance :\nu_camera_to_center_distance/camera_to_anchor_distance;highp float perspective_ratio=clamp(0.5+0.5*distance_ratio,0.0,4.0);if (!u_is_offset) {size*=perspective_ratio;}float fontScale=u_is_text ? size/24.0 : size;highp float symbol_rotation=0.0;if (u_rotate_symbol) {vec4 offsetProjectedPoint=projectTileWithElevation(translated_a_pos+vec2(1,0),ele);vec2 a=projectedPoint.xy/projectedPoint.w;vec2 b=offsetProjectedPoint.xy/offsetProjectedPoint.w;symbol_rotation=atan((b.y-a.y)/u_aspect_ratio,b.x-a.x);}highp float angle_sin=sin(segment_angle+symbol_rotation);highp float angle_cos=cos(segment_angle+symbol_rotation);mat2 rotation_matrix=mat2(angle_cos,-1.0*angle_sin,angle_sin,angle_cos);vec4 projected_pos;if (u_is_along_line || u_is_variable_anchor) {projected_pos=vec4(a_projected_pos.xy,ele,1.0);} else if (u_pitch_with_map) {projected_pos=u_label_plane_matrix*vec4(a_projected_pos.xy+u_translation,ele,1.0);} else {projected_pos=u_label_plane_matrix*projectTileWithElevation(a_projected_pos.xy+u_translation,ele);}float z=float(u_pitch_with_map)*projected_pos.z/projected_pos.w;float projectionScaling=1.0;\n#ifdef GLOBE\nif(u_pitch_with_map) {float anchor_pos_tile_y=(u_coord_matrix*vec4(projected_pos.xy/projected_pos.w,z,1.0)).y;projectionScaling=mix(projectionScaling,1.0/circumferenceRatioAtTileY(anchor_pos_tile_y)*u_pitched_scale,u_projection_transition);}\n#endif\nvec4 finalPos=u_coord_matrix*vec4(projected_pos.xy/projected_pos.w+rotation_matrix*(a_offset/32.0*max(a_minFontScale,fontScale)+a_pxoffset)*projectionScaling,z,1.0);if(u_pitch_with_map) {finalPos=projectTileWithElevation(finalPos.xy,finalPos.z);}float gamma_scale=finalPos.w;gl_Position=finalPos;v_data0=a_tex/u_texsize;v_data1=vec3(gamma_scale,size,total_opacity);}"),
|
|
8818
|
+
symbolTextAndIcon: prepare("#define SDF_PX 8.0\n#define SDF 1.0\n#define ICON 0.0\nuniform bool u_is_halo;uniform bool u_is_text;uniform sampler2D u_texture;uniform sampler2D u_texture_icon;uniform highp float u_gamma_scale;uniform lowp float u_device_pixel_ratio;in vec4 v_data0;in vec3 v_data1;flat in float v_is_sdf;\n#pragma maplibre: define highp vec4 fill_color\n#pragma maplibre: define highp vec4 halo_color\n#pragma maplibre: define lowp float halo_width\n#pragma maplibre: define lowp float halo_blur\nvoid main() {\n#pragma maplibre: initialize highp vec4 fill_color\n#pragma maplibre: initialize highp vec4 halo_color\n#pragma maplibre: initialize lowp float halo_width\n#pragma maplibre: initialize lowp float halo_blur\nfloat total_opacity=v_data1[2];if (v_is_sdf==ICON) {vec2 tex_icon=v_data0.zw;fragColor=texture(u_texture_icon,tex_icon)*total_opacity;\n#ifdef OVERDRAW_INSPECTOR\nfragColor=vec4(1.0);\n#endif\nreturn;}vec2 tex=v_data0.xy;float EDGE_GAMMA=0.105/u_device_pixel_ratio;float gamma_scale=v_data1.x;float size=v_data1.y;float fontScale=size/24.0;highp float gamma=EDGE_GAMMA/(fontScale*u_gamma_scale);lowp float buff=(256.0-64.0)/256.0;lowp float dist=texture(u_texture,tex).a;lowp vec4 color_alpha_out,color_alpha_out_halo;if (u_is_text) {highp float gamma_scaled=gamma*gamma_scale;highp float alpha=smoothstep(buff-gamma_scaled,buff+gamma_scaled,dist);color_alpha_out=fill_color*(alpha*total_opacity);}if (u_is_halo) {highp float gamma_halo=(halo_blur*1.19/SDF_PX+EDGE_GAMMA)/(fontScale*u_gamma_scale);lowp float buff_halo=(6.0-halo_width/fontScale)/SDF_PX;highp float gamma_scaled_halo=gamma_halo*gamma_scale;highp float alpha_halo=smoothstep(buff_halo-gamma_scaled_halo,buff_halo+gamma_scaled_halo,dist);color_alpha_out_halo=halo_color*(alpha_halo*total_opacity);}if (u_is_text && u_is_halo) {fragColor=color_alpha_out+(1.-color_alpha_out.a)*color_alpha_out_halo;} else if (u_is_halo) {fragColor=color_alpha_out_halo;} else {fragColor=color_alpha_out;}\n#ifdef OVERDRAW_INSPECTOR\nfragColor=vec4(1.0);\n#endif\n}", "layout(location=0) in vec4 a_pos_offset;layout(location=1) in uvec4 a_data;layout(location=2) in vec3 a_projected_pos;layout(location=3) in uint a_fade_opacity;layout(location=4) in float a_height_offset;uniform bool u_is_size_zoom_constant;uniform bool u_is_size_feature_constant;uniform highp float u_size_t;uniform highp float u_size;uniform mat4 u_label_plane_matrix;uniform mat4 u_coord_matrix;uniform bool u_is_text;uniform bool u_pitch_with_map;uniform highp float u_pitch;uniform bool u_rotate_symbol;uniform highp float u_aspect_ratio;uniform highp float u_camera_to_center_distance;uniform float u_fade_change;uniform vec2 u_texsize;uniform vec2 u_texsize_icon;uniform bool u_is_along_line;uniform bool u_is_variable_anchor;uniform vec2 u_translation;uniform float u_pitched_scale;uniform bool u_is_offset;uniform bool u_height_anchor_ground;out vec4 v_data0;out vec3 v_data1;flat out float v_is_sdf;\n#pragma maplibre: define highp vec4 fill_color\n#pragma maplibre: define highp vec4 halo_color\n#pragma maplibre: define lowp float opacity\n#pragma maplibre: define lowp float halo_width\n#pragma maplibre: define lowp float halo_blur\nvoid main() {\n#pragma maplibre: initialize highp vec4 fill_color\n#pragma maplibre: initialize highp vec4 halo_color\n#pragma maplibre: initialize lowp float opacity\n#pragma maplibre: initialize lowp float halo_width\n#pragma maplibre: initialize lowp float halo_blur\nvec2 a_pos=a_pos_offset.xy;vec2 a_offset=a_pos_offset.zw;vec2 a_tex=vec2(a_data.xy);vec2 a_size=vec2(a_data.zw);float a_size_min=float(a_data.z >> 1u);float is_sdf=float(a_data.z & 1u);float ele=a_height_offset+(u_height_anchor_ground ? get_elevation(a_pos) : 0.0);highp float segment_angle=-a_projected_pos[2];float size;if (!u_is_size_zoom_constant && !u_is_size_feature_constant) {size=mix(a_size_min,a_size[1],u_size_t)/128.0;} else if (u_is_size_zoom_constant && !u_is_size_feature_constant) {size=a_size_min/128.0;} else {size=u_size;}vec2 translated_a_pos=a_pos+u_translation;vec4 projectedPoint=projectTileWithElevation(translated_a_pos,ele);vec2 fade_opacity=unpack_opacity(a_fade_opacity);float visibility=calculate_visibility(projectedPoint);float fade_change=fade_opacity[1] > 0.5 ? u_fade_change :-u_fade_change;float interpolated_fade_opacity=max(0.0,min(visibility,fade_opacity[0]+fade_change));float total_opacity=opacity*interpolated_fade_opacity;if (total_opacity < 0.1){gl_Position=vec4(-2.,-2.,-2.,1.);return;}highp float camera_to_anchor_distance=projectedPoint.w;highp float distance_ratio=u_pitch_with_map ?\ncamera_to_anchor_distance/u_camera_to_center_distance :\nu_camera_to_center_distance/camera_to_anchor_distance;highp float perspective_ratio=clamp(0.5+0.5*distance_ratio,0.0,4.0);if (!u_is_offset) {size*=perspective_ratio;}float fontScale=size/24.0;highp float symbol_rotation=0.0;if (u_rotate_symbol) {vec4 offsetProjectedPoint=projectTileWithElevation(translated_a_pos+vec2(1,0),ele);vec2 a=projectedPoint.xy/projectedPoint.w;vec2 b=offsetProjectedPoint.xy/offsetProjectedPoint.w;symbol_rotation=atan((b.y-a.y)/u_aspect_ratio,b.x-a.x);}highp float angle_sin=sin(segment_angle+symbol_rotation);highp float angle_cos=cos(segment_angle+symbol_rotation);mat2 rotation_matrix=mat2(angle_cos,-1.0*angle_sin,angle_sin,angle_cos);vec4 projected_pos;if (u_is_along_line || u_is_variable_anchor) {projected_pos=vec4(a_projected_pos.xy,ele,1.0);} else if (u_pitch_with_map) {projected_pos=u_label_plane_matrix*vec4(a_projected_pos.xy+u_translation,ele,1.0);} else {projected_pos=u_label_plane_matrix*projectTileWithElevation(a_projected_pos.xy+u_translation,ele);}float z=float(u_pitch_with_map)*projected_pos.z/projected_pos.w;float projectionScaling=1.0;\n#ifdef GLOBE\nif(u_pitch_with_map && !u_is_along_line) {float anchor_pos_tile_y=(u_coord_matrix*vec4(projected_pos.xy/projected_pos.w,z,1.0)).y;projectionScaling=mix(projectionScaling,1.0/circumferenceRatioAtTileY(anchor_pos_tile_y)*u_pitched_scale,u_projection_transition);}\n#endif\nvec4 finalPos=u_coord_matrix*vec4(projected_pos.xy/projected_pos.w+rotation_matrix*(a_offset/32.0*fontScale)*projectionScaling,z,1.0);if(u_pitch_with_map) {finalPos=projectTileWithElevation(finalPos.xy,finalPos.z);}float gamma_scale=finalPos.w;gl_Position=finalPos;v_data0.xy=a_tex/u_texsize;v_data0.zw=a_tex/u_texsize_icon;v_data1=vec3(gamma_scale,size,total_opacity);v_is_sdf=is_sdf;}"),
|
|
8784
8819
|
terrain: prepare("uniform sampler2D u_texture;uniform vec4 u_fog_color;uniform vec4 u_horizon_color;uniform float u_fog_ground_blend;uniform float u_fog_ground_blend_opacity;uniform float u_horizon_fog_blend;uniform bool u_is_globe_mode;in vec2 v_texture_pos;in float v_fog_depth;const float gamma=2.2;vec4 gammaToLinear(vec4 color) {return pow(color,vec4(gamma));}vec4 linearToGamma(vec4 color) {return pow(color,vec4(1.0/gamma));}void main() {vec4 surface_color=texture(u_texture,vec2(v_texture_pos.x,1.0-v_texture_pos.y));if (!u_is_globe_mode && u_fog_ground_blend_opacity > 0.0 && v_fog_depth > u_fog_ground_blend) {vec4 surface_color_linear=gammaToLinear(surface_color);float blend_color=smoothstep(0.0,1.0,max((v_fog_depth-u_horizon_fog_blend)/(1.0-u_horizon_fog_blend),0.0));vec4 fog_horizon_color_linear=mix(gammaToLinear(u_fog_color),gammaToLinear(u_horizon_color),blend_color);float factor_fog=max(v_fog_depth-u_fog_ground_blend,0.0)/(1.0-u_fog_ground_blend);fragColor=linearToGamma(mix(surface_color_linear,fog_horizon_color_linear,pow(factor_fog,2.0)*u_fog_ground_blend_opacity));} else {fragColor=surface_color;}}", "layout(location=0) in vec3 a_pos3d;uniform mat4 u_fog_matrix;uniform float u_ele_delta;out vec2 v_texture_pos;out float v_fog_depth;void main() {float ele=get_elevation(a_pos3d.xy);float ele_delta=a_pos3d.z==1.0 ? u_ele_delta : 0.0;v_texture_pos=a_pos3d.xy/8192.0;gl_Position=projectTileFor3D(a_pos3d.xy,ele-ele_delta);vec4 pos=u_fog_matrix*vec4(a_pos3d.xy,ele,1.0);v_fog_depth=pos.z/pos.w*0.5+0.5;}"),
|
|
8785
8820
|
terrainDepth: prepare("in float v_depth;const highp vec4 bitSh=vec4(256.*256.*256.,256.*256.,256.,1.);const highp vec4 bitMsk=vec4(0.,vec3(1./256.0));highp vec4 pack(highp float value) {highp vec4 comp=fract(value*bitSh);comp-=comp.xxyz*bitMsk;return comp;}void main() {fragColor=pack(v_depth);}", "layout(location=0) in vec3 a_pos3d;uniform float u_ele_delta;out float v_depth;void main() {float ele=get_elevation(a_pos3d.xy);float ele_delta=a_pos3d.z==1.0 ? u_ele_delta : 0.0;gl_Position=projectTileFor3D(a_pos3d.xy,ele-ele_delta);v_depth=gl_Position.z/gl_Position.w;}"),
|
|
8786
|
-
terrainCoords: prepare("precision mediump float;uniform sampler2D u_texture;uniform float u_terrain_coords_id;in vec2 v_texture_pos;void main() {vec4 rgba=texture(u_texture,v_texture_pos);fragColor=vec4(rgba.r,rgba.g,rgba.b,u_terrain_coords_id);}", "layout(location=0) in vec3 a_pos3d;uniform float u_ele_delta;out vec2 v_texture_pos;void main() {float ele=get_elevation(a_pos3d.xy);float ele_delta=a_pos3d.z==1.0 ? u_ele_delta : 0.0;v_texture_pos=a_pos3d.xy/8192.0;gl_Position=projectTileFor3D(a_pos3d.xy,ele-ele_delta);}"),
|
|
8787
8821
|
atmosphere: prepare("#ifdef GL_ES\nprecision highp float;\n#endif\nin vec3 view_direction;uniform vec3 u_sun_pos;uniform vec3 u_globe_position;uniform float u_globe_radius;uniform float u_atmosphere_blend;/**Shader use from https:*Made some change to adapt to MapLibre Globe geometry*/const float PI=3.141592653589793;const int iSteps=5;const int jSteps=3;/*radius of the planet*/const float EARTH_RADIUS=6371e3;/*radius of the atmosphere*/const float ATMOS_RADIUS=6471e3;vec2 rsi(vec3 r0,vec3 rd,float sr) {float a=dot(rd,rd);float b=2.0*dot(rd,r0);float c=dot(r0,r0)-(sr*sr);float d=(b*b)-4.0*a*c;if (d < 0.0) return vec2(1e5,-1e5);return vec2((-b-sqrt(d))/(2.0*a),(-b+sqrt(d))/(2.0*a));}vec4 atmosphere(vec3 r,vec3 r0,vec3 pSun,float iSun,float rPlanet,float rAtmos,vec3 kRlh,float kMie,float shRlh,float shMie,float g) {pSun=normalize(pSun);r=normalize(r);vec2 p=rsi(r0,r,rAtmos);if (p.x > p.y) {return vec4(0.0,0.0,0.0,1.0);}if (p.x < 0.0) {p.x=0.0;}vec3 pos=r0+r*p.x;vec2 p2=rsi(r0,r,rPlanet);if (p2.x <=p2.y && p2.x > 0.0) {p.y=min(p.y,p2.x);}float iStepSize=(p.y-p.x)/float(iSteps);float iTime=p.x+iStepSize*0.5;vec3 totalRlh=vec3(0,0,0);vec3 totalMie=vec3(0,0,0);float iOdRlh=0.0;float iOdMie=0.0;float mu=dot(r,pSun);float mumu=mu*mu;float gg=g*g;float pRlh=3.0/(16.0*PI)*(1.0+mumu);float pMie=3.0/(8.0*PI)*((1.0-gg)*(mumu+1.0))/(pow(1.0+gg-2.0*mu*g,1.5)*(2.0+gg));for (int i=0; i < iSteps; i++) {vec3 iPos=r0+r*iTime;float iHeight=length(iPos)-rPlanet;float odStepRlh=exp(-iHeight/shRlh)*iStepSize;float odStepMie=exp(-iHeight/shMie)*iStepSize;iOdRlh+=odStepRlh;iOdMie+=odStepMie;float jStepSize=rsi(iPos,pSun,rAtmos).y/float(jSteps);float jTime=jStepSize*0.5;float jOdRlh=0.0;float jOdMie=0.0;for (int j=0; j < jSteps; j++) {vec3 jPos=iPos+pSun*jTime;float jHeight=length(jPos)-rPlanet;jOdRlh+=exp(-jHeight/shRlh)*jStepSize;jOdMie+=exp(-jHeight/shMie)*jStepSize;jTime+=jStepSize;}vec3 attn=exp(-(kMie*(iOdMie+jOdMie)+kRlh*(iOdRlh+jOdRlh)));totalRlh+=odStepRlh*attn;totalMie+=odStepMie*attn;iTime+=iStepSize;}float opacity=exp(-(length(kRlh)*length(totalRlh)+kMie*length(totalMie)));vec3 color=iSun*(pRlh*kRlh*totalRlh+pMie*kMie*totalMie);return vec4(color,opacity);}void main() {vec3 scale_camera_pos=-u_globe_position*EARTH_RADIUS/u_globe_radius;vec4 color=atmosphere(normalize(view_direction),scale_camera_pos,u_sun_pos,22.0,EARTH_RADIUS,ATMOS_RADIUS,vec3(5.5e-6,13.0e-6,22.4e-6),21e-6,8e3,1.2e3,0.758\n);color.rgb=1.0-exp(-1.0*color.rgb);color=pow(color,vec4(1.0/2.2));fragColor=vec4(color.rgb,1.0-color.a)*u_atmosphere_blend;}", "layout(location=0) in vec2 a_pos;uniform mat4 u_inv_proj_matrix;out vec3 view_direction;void main() {view_direction=(u_inv_proj_matrix*vec4(a_pos,0.0,1.0)).xyz;gl_Position=vec4(a_pos,0.0,1.0);}"),
|
|
8788
8822
|
sky: prepare("uniform vec4 u_sky_color;uniform vec4 u_horizon_color;uniform vec2 u_horizon;uniform vec2 u_horizon_normal;uniform float u_sky_horizon_blend;uniform float u_sky_blend;void main() {float x=gl_FragCoord.x;float y=gl_FragCoord.y;float blend=(y-u_horizon.y)*u_horizon_normal.y+(x-u_horizon.x)*u_horizon_normal.x;if (blend > 0.0) {if (blend < u_sky_horizon_blend) {fragColor=mix(u_sky_color,u_horizon_color,pow(1.0-blend/u_sky_horizon_blend,2.0));} else {fragColor=u_sky_color;}}fragColor=mix(fragColor,vec4(vec3(0.0),0.0),u_sky_blend);}", "layout(location=0) in vec2 a_pos;void main() {gl_Position=vec4(a_pos,1.0,1.0);}")
|
|
8789
8823
|
};
|
|
@@ -9127,7 +9161,9 @@ var TransformHelper = class {
|
|
|
9127
9161
|
setMinZoom(zoom) {
|
|
9128
9162
|
if (this._minZoom === zoom) return;
|
|
9129
9163
|
this._minZoom = zoom;
|
|
9164
|
+
const unmodified = this._unmodified;
|
|
9130
9165
|
this.setZoom(this.applyConstrain(this._center, this.zoom).zoom);
|
|
9166
|
+
this._unmodified = unmodified;
|
|
9131
9167
|
}
|
|
9132
9168
|
get maxZoom() {
|
|
9133
9169
|
return this._maxZoom;
|
|
@@ -9135,7 +9171,9 @@ var TransformHelper = class {
|
|
|
9135
9171
|
setMaxZoom(zoom) {
|
|
9136
9172
|
if (this._maxZoom === zoom) return;
|
|
9137
9173
|
this._maxZoom = zoom;
|
|
9174
|
+
const unmodified = this._unmodified;
|
|
9138
9175
|
this.setZoom(this.applyConstrain(this._center, this.zoom).zoom);
|
|
9176
|
+
this._unmodified = unmodified;
|
|
9139
9177
|
}
|
|
9140
9178
|
get minPitch() {
|
|
9141
9179
|
return this._minPitch;
|
|
@@ -9143,7 +9181,9 @@ var TransformHelper = class {
|
|
|
9143
9181
|
setMinPitch(pitch) {
|
|
9144
9182
|
if (this._minPitch === pitch) return;
|
|
9145
9183
|
this._minPitch = pitch;
|
|
9184
|
+
const unmodified = this._unmodified;
|
|
9146
9185
|
this.setPitch(Math.max(this.pitch, pitch));
|
|
9186
|
+
this._unmodified = unmodified;
|
|
9147
9187
|
}
|
|
9148
9188
|
get maxPitch() {
|
|
9149
9189
|
return this._maxPitch;
|
|
@@ -9151,7 +9191,9 @@ var TransformHelper = class {
|
|
|
9151
9191
|
setMaxPitch(pitch) {
|
|
9152
9192
|
if (this._maxPitch === pitch) return;
|
|
9153
9193
|
this._maxPitch = pitch;
|
|
9194
|
+
const unmodified = this._unmodified;
|
|
9154
9195
|
this.setPitch(Math.min(this.pitch, pitch));
|
|
9196
|
+
this._unmodified = unmodified;
|
|
9155
9197
|
}
|
|
9156
9198
|
get renderWorldCopies() {
|
|
9157
9199
|
return this._renderWorldCopies;
|
|
@@ -9523,9 +9565,7 @@ var TransformHelper = class {
|
|
|
9523
9565
|
return Math.cos(this.pitchInRadians) * this._cameraToCenterDistance / this._pixelPerMeter + this.elevation;
|
|
9524
9566
|
}
|
|
9525
9567
|
getCameraLngLat() {
|
|
9526
|
-
|
|
9527
|
-
const cameraToCenterDistanceMeters = this.cameraToCenterDistance / pixelPerMeter;
|
|
9528
|
-
return cameraMercatorCoordinateFromCenterAndRotation(this.center, this.elevation, this.pitch, this.bearing, cameraToCenterDistanceMeters).toLngLat();
|
|
9568
|
+
return cameraMercatorCoordinate(this).toLngLat();
|
|
9529
9569
|
}
|
|
9530
9570
|
getMercatorTileCoordinates(overscaledTileID) {
|
|
9531
9571
|
if (!overscaledTileID) return [
|
|
@@ -9883,180 +9923,903 @@ function getIdealNearFarPlaneDistance(horizonPlane, nearPlaneNormalized) {
|
|
|
9883
9923
|
} else return null;
|
|
9884
9924
|
}
|
|
9885
9925
|
//#endregion
|
|
9886
|
-
//#region src/
|
|
9887
|
-
|
|
9888
|
-
|
|
9889
|
-
|
|
9890
|
-
|
|
9891
|
-
|
|
9892
|
-
|
|
9893
|
-
|
|
9894
|
-
|
|
9895
|
-
|
|
9896
|
-
|
|
9897
|
-
|
|
9898
|
-
|
|
9926
|
+
//#region src/data/pos3d_attributes.ts
|
|
9927
|
+
const pos3dAttributes = createLayout([{
|
|
9928
|
+
name: "a_pos3d",
|
|
9929
|
+
type: "Int16",
|
|
9930
|
+
components: 3
|
|
9931
|
+
}]);
|
|
9932
|
+
//#endregion
|
|
9933
|
+
//#region src/tile/terrain_tile_manager.ts
|
|
9934
|
+
/**
|
|
9935
|
+
* @internal
|
|
9936
|
+
* This class is a helper for the Terrain-class, it:
|
|
9937
|
+
*
|
|
9938
|
+
* - loads raster-dem tiles
|
|
9939
|
+
* - manages all renderToTexture tiles.
|
|
9940
|
+
* - caches previous rendered tiles.
|
|
9941
|
+
* - finds all necessary renderToTexture tiles for a OverscaledTileID area
|
|
9942
|
+
* - finds the corresponding raster-dem tile for OverscaledTileID
|
|
9943
|
+
*/
|
|
9944
|
+
var TerrainTileManager = class extends Evented {
|
|
9945
|
+
constructor(tileManager) {
|
|
9946
|
+
super();
|
|
9947
|
+
this._lastTilesetChange = now();
|
|
9948
|
+
this.tileManager = tileManager;
|
|
9949
|
+
this._tiles = {};
|
|
9950
|
+
this._renderableTilesKeys = [];
|
|
9951
|
+
this._sourceTileCache = {};
|
|
9952
|
+
this.minzoom = 0;
|
|
9953
|
+
this.maxzoom = 22;
|
|
9954
|
+
this.deltaZoom = 1;
|
|
9955
|
+
this.tileSize = tileManager._source.tileSize * 2 ** this.deltaZoom;
|
|
9956
|
+
tileManager.usedForTerrain = true;
|
|
9957
|
+
tileManager.tileSize = this.tileSize;
|
|
9899
9958
|
}
|
|
9900
|
-
|
|
9901
|
-
|
|
9959
|
+
destruct() {
|
|
9960
|
+
this.tileManager.usedForTerrain = false;
|
|
9961
|
+
this.tileManager.tileSize = null;
|
|
9962
|
+
this.releaseAllRTT();
|
|
9902
9963
|
}
|
|
9903
|
-
|
|
9904
|
-
return this.
|
|
9964
|
+
getSource() {
|
|
9965
|
+
return this.tileManager._source;
|
|
9905
9966
|
}
|
|
9906
|
-
|
|
9907
|
-
|
|
9967
|
+
/**
|
|
9968
|
+
* Load Terrain Tiles, create internal render-to-texture tiles, free GPU memory.
|
|
9969
|
+
* @param transform - the operation to do
|
|
9970
|
+
* @param terrain - the terrain
|
|
9971
|
+
*/
|
|
9972
|
+
update(transform, terrain) {
|
|
9973
|
+
this.tileManager.update(transform, terrain);
|
|
9974
|
+
this._renderableTilesKeys = [];
|
|
9975
|
+
const keys = {};
|
|
9976
|
+
for (const tileID of coveringTiles(transform, {
|
|
9977
|
+
tileSize: this.tileSize,
|
|
9978
|
+
minzoom: this.minzoom,
|
|
9979
|
+
maxzoom: this.maxzoom,
|
|
9980
|
+
reparseOverscaled: false,
|
|
9981
|
+
terrain,
|
|
9982
|
+
calculateTileZoom: this.tileManager._source.calculateTileZoom
|
|
9983
|
+
})) {
|
|
9984
|
+
keys[tileID.key] = true;
|
|
9985
|
+
this._renderableTilesKeys.push(tileID.key);
|
|
9986
|
+
if (!this._tiles[tileID.key]) {
|
|
9987
|
+
tileID.terrainRttPosMatrix32f = /* @__PURE__ */ new Float32Array(16);
|
|
9988
|
+
ortho(tileID.terrainRttPosMatrix32f, 0, EXTENT, EXTENT, 0, 0, 1);
|
|
9989
|
+
this._tiles[tileID.key] = new Tile(tileID, this.tileSize);
|
|
9990
|
+
this._lastTilesetChange = now();
|
|
9991
|
+
}
|
|
9992
|
+
}
|
|
9993
|
+
for (const key in this._tiles) if (!keys[key]) {
|
|
9994
|
+
this._tiles[key].releaseRTT(this.tileManager.map.painter);
|
|
9995
|
+
delete this._tiles[key];
|
|
9996
|
+
}
|
|
9908
9997
|
}
|
|
9909
|
-
|
|
9910
|
-
|
|
9998
|
+
/**
|
|
9999
|
+
* Release the RTT objects for `tileID` (and its ancestors/descendants),
|
|
10000
|
+
*/
|
|
10001
|
+
releaseRTT(tileID) {
|
|
10002
|
+
for (const key in this._tiles) {
|
|
10003
|
+
const tile = this._tiles[key];
|
|
10004
|
+
if (tile.tileID.equals(tileID) || tile.tileID.isChildOf(tileID) || tileID.isChildOf(tile.tileID)) tile.releaseRTT(this.tileManager.map.painter);
|
|
10005
|
+
}
|
|
9911
10006
|
}
|
|
9912
|
-
|
|
9913
|
-
|
|
10007
|
+
/**
|
|
10008
|
+
* Release the A RTT objects for all tiles.
|
|
10009
|
+
*/
|
|
10010
|
+
releaseAllRTT() {
|
|
10011
|
+
for (const key in this._tiles) this._tiles[key].releaseRTT(this.tileManager.map.painter);
|
|
9914
10012
|
}
|
|
9915
|
-
|
|
9916
|
-
|
|
10013
|
+
/**
|
|
10014
|
+
* get a list of tiles, which are loaded and should be rendered in the current scene
|
|
10015
|
+
* @returns the renderable tiles
|
|
10016
|
+
*/
|
|
10017
|
+
getRenderableTiles() {
|
|
10018
|
+
return this._renderableTilesKeys.map((key) => this.getTileByID(key));
|
|
9917
10019
|
}
|
|
9918
|
-
|
|
9919
|
-
|
|
10020
|
+
/**
|
|
10021
|
+
* get terrain tile by the TileID key
|
|
10022
|
+
* @param id - the tile id
|
|
10023
|
+
* @returns the tile
|
|
10024
|
+
*/
|
|
10025
|
+
getTileByID(id) {
|
|
10026
|
+
return this._tiles[id];
|
|
9920
10027
|
}
|
|
9921
|
-
|
|
9922
|
-
|
|
10028
|
+
/**
|
|
10029
|
+
* Searches for the corresponding current renderable terrain-tiles
|
|
10030
|
+
* @param tileID - the tile to look for
|
|
10031
|
+
* @returns the tiles that were found
|
|
10032
|
+
*/
|
|
10033
|
+
getTerrainCoords(tileID, terrainTileRanges) {
|
|
10034
|
+
if (terrainTileRanges) return this._getTerrainCoordsForTileRanges(tileID, terrainTileRanges);
|
|
10035
|
+
else return this._getTerrainCoordsForRegularTile(tileID);
|
|
9923
10036
|
}
|
|
9924
|
-
|
|
9925
|
-
|
|
10037
|
+
/**
|
|
10038
|
+
* Searches for the corresponding current renderable terrain-tiles.
|
|
10039
|
+
* Includes terrain tiles that are either:
|
|
10040
|
+
* - the same as the tileID
|
|
10041
|
+
* - a parent of the tileID
|
|
10042
|
+
* - a child of the tileID
|
|
10043
|
+
* @param tileID - the tile to look for
|
|
10044
|
+
* @returns the tiles that were found
|
|
10045
|
+
*/
|
|
10046
|
+
_getTerrainCoordsForRegularTile(tileID) {
|
|
10047
|
+
const coords = {};
|
|
10048
|
+
for (const key of this._renderableTilesKeys) {
|
|
10049
|
+
const terrainTileID = this._tiles[key].tileID;
|
|
10050
|
+
const coord = tileID.clone();
|
|
10051
|
+
const mat = createMat4f64();
|
|
10052
|
+
if (terrainTileID.canonical.equals(tileID.canonical)) ortho(mat, 0, EXTENT, EXTENT, 0, 0, 1);
|
|
10053
|
+
else if (terrainTileID.canonical.isChildOf(tileID.canonical)) {
|
|
10054
|
+
const dz = terrainTileID.canonical.z - tileID.canonical.z;
|
|
10055
|
+
const dx = terrainTileID.canonical.x - (terrainTileID.canonical.x >> dz << dz);
|
|
10056
|
+
const dy = terrainTileID.canonical.y - (terrainTileID.canonical.y >> dz << dz);
|
|
10057
|
+
const size = EXTENT >> dz;
|
|
10058
|
+
ortho(mat, 0, size, size, 0, 0, 1);
|
|
10059
|
+
translate(mat, mat, [
|
|
10060
|
+
-dx * size,
|
|
10061
|
+
-dy * size,
|
|
10062
|
+
0
|
|
10063
|
+
]);
|
|
10064
|
+
} else if (tileID.canonical.isChildOf(terrainTileID.canonical)) {
|
|
10065
|
+
const dz = tileID.canonical.z - terrainTileID.canonical.z;
|
|
10066
|
+
const dx = tileID.canonical.x - (tileID.canonical.x >> dz << dz);
|
|
10067
|
+
const dy = tileID.canonical.y - (tileID.canonical.y >> dz << dz);
|
|
10068
|
+
const size = EXTENT >> dz;
|
|
10069
|
+
ortho(mat, 0, EXTENT, EXTENT, 0, 0, 1);
|
|
10070
|
+
translate(mat, mat, [
|
|
10071
|
+
dx * size,
|
|
10072
|
+
dy * size,
|
|
10073
|
+
0
|
|
10074
|
+
]);
|
|
10075
|
+
scale(mat, mat, [
|
|
10076
|
+
1 / 2 ** dz,
|
|
10077
|
+
1 / 2 ** dz,
|
|
10078
|
+
0
|
|
10079
|
+
]);
|
|
10080
|
+
} else continue;
|
|
10081
|
+
coord.terrainRttPosMatrix32f = new Float32Array(mat);
|
|
10082
|
+
coords[key] = coord;
|
|
10083
|
+
}
|
|
10084
|
+
return coords;
|
|
9926
10085
|
}
|
|
9927
|
-
|
|
9928
|
-
|
|
10086
|
+
/**
|
|
10087
|
+
* Searches for the corresponding current renderable terrain-tiles.
|
|
10088
|
+
* Includes terrain tiles that are within terrain tile ranges.
|
|
10089
|
+
* @param tileID - the tile to look for
|
|
10090
|
+
* @returns the tiles that were found
|
|
10091
|
+
*/
|
|
10092
|
+
_getTerrainCoordsForTileRanges(tileID, terrainTileRanges) {
|
|
10093
|
+
const coords = {};
|
|
10094
|
+
for (const key of this._renderableTilesKeys) {
|
|
10095
|
+
const terrainTileID = this._tiles[key].tileID;
|
|
10096
|
+
if (!this._isWithinTileRanges(terrainTileID, terrainTileRanges)) continue;
|
|
10097
|
+
const coord = tileID.clone();
|
|
10098
|
+
const mat = createMat4f64();
|
|
10099
|
+
if (terrainTileID.canonical.z === tileID.canonical.z) {
|
|
10100
|
+
const dx = tileID.canonical.x - terrainTileID.canonical.x + tileID.wrap * (1 << tileID.canonical.z);
|
|
10101
|
+
const dy = tileID.canonical.y - terrainTileID.canonical.y;
|
|
10102
|
+
ortho(mat, 0, EXTENT, EXTENT, 0, 0, 1);
|
|
10103
|
+
translate(mat, mat, [
|
|
10104
|
+
dx * EXTENT,
|
|
10105
|
+
dy * EXTENT,
|
|
10106
|
+
0
|
|
10107
|
+
]);
|
|
10108
|
+
} else if (terrainTileID.canonical.z > tileID.canonical.z) {
|
|
10109
|
+
const dz = terrainTileID.canonical.z - tileID.canonical.z;
|
|
10110
|
+
const dx = terrainTileID.canonical.x - (terrainTileID.canonical.x >> dz << dz) + tileID.wrap * (1 << terrainTileID.canonical.z);
|
|
10111
|
+
const dy = terrainTileID.canonical.y - (terrainTileID.canonical.y >> dz << dz);
|
|
10112
|
+
const dx2 = tileID.canonical.x - (terrainTileID.canonical.x >> dz);
|
|
10113
|
+
const dy2 = tileID.canonical.y - (terrainTileID.canonical.y >> dz);
|
|
10114
|
+
const size = EXTENT >> dz;
|
|
10115
|
+
ortho(mat, 0, size, size, 0, 0, 1);
|
|
10116
|
+
translate(mat, mat, [
|
|
10117
|
+
-dx * size + dx2 * EXTENT,
|
|
10118
|
+
-dy * size + dy2 * EXTENT,
|
|
10119
|
+
0
|
|
10120
|
+
]);
|
|
10121
|
+
} else {
|
|
10122
|
+
const dz = tileID.canonical.z - terrainTileID.canonical.z;
|
|
10123
|
+
const dx = tileID.canonical.x - (tileID.canonical.x >> dz << dz) + tileID.wrap * (1 << tileID.canonical.z);
|
|
10124
|
+
const dy = tileID.canonical.y - (tileID.canonical.y >> dz << dz);
|
|
10125
|
+
const dx2 = (tileID.canonical.x >> dz) - terrainTileID.canonical.x;
|
|
10126
|
+
const dy2 = (tileID.canonical.y >> dz) - terrainTileID.canonical.y;
|
|
10127
|
+
const size = EXTENT << dz;
|
|
10128
|
+
ortho(mat, 0, size, size, 0, 0, 1);
|
|
10129
|
+
translate(mat, mat, [
|
|
10130
|
+
dx * EXTENT + dx2 * size,
|
|
10131
|
+
dy * EXTENT + dy2 * size,
|
|
10132
|
+
0
|
|
10133
|
+
]);
|
|
10134
|
+
}
|
|
10135
|
+
coord.terrainRttPosMatrix32f = new Float32Array(mat);
|
|
10136
|
+
coords[key] = coord;
|
|
10137
|
+
}
|
|
10138
|
+
return coords;
|
|
9929
10139
|
}
|
|
9930
|
-
|
|
9931
|
-
|
|
9932
|
-
|
|
9933
|
-
|
|
9934
|
-
|
|
9935
|
-
|
|
9936
|
-
|
|
9937
|
-
this.
|
|
9938
|
-
|
|
9939
|
-
|
|
9940
|
-
|
|
9941
|
-
|
|
9942
|
-
|
|
9943
|
-
this.
|
|
9944
|
-
|
|
9945
|
-
setElevation(elevation) {
|
|
9946
|
-
this._helper.setElevation(elevation);
|
|
9947
|
-
}
|
|
9948
|
-
setMinElevationForCurrentTile(elevation) {
|
|
9949
|
-
this._helper.setMinElevationForCurrentTile(elevation);
|
|
9950
|
-
}
|
|
9951
|
-
setPadding(padding) {
|
|
9952
|
-
this._helper.setPadding(padding);
|
|
9953
|
-
}
|
|
9954
|
-
interpolatePadding(start, target, t) {
|
|
9955
|
-
this._helper.interpolatePadding(start, target, t);
|
|
9956
|
-
}
|
|
9957
|
-
isPaddingEqual(padding) {
|
|
9958
|
-
return this._helper.isPaddingEqual(padding);
|
|
9959
|
-
}
|
|
9960
|
-
resize(width, height, constrain = true) {
|
|
9961
|
-
this._helper.resize(width, height, constrain);
|
|
10140
|
+
/**
|
|
10141
|
+
* find the covering raster-dem tile
|
|
10142
|
+
* @param tileID - the tile to look for
|
|
10143
|
+
* @param searchForDEM - Optional parameter to search for (parent) source tiles with loaded dem.
|
|
10144
|
+
* @returns the tile
|
|
10145
|
+
*/
|
|
10146
|
+
getSourceTile(tileID, searchForDEM) {
|
|
10147
|
+
const source = this.tileManager._source;
|
|
10148
|
+
let z = tileID.overscaledZ - this.deltaZoom;
|
|
10149
|
+
if (z > source.maxzoom) z = source.maxzoom;
|
|
10150
|
+
if (z < source.minzoom) return void 0;
|
|
10151
|
+
this._sourceTileCache[tileID.key] ||= tileID.scaledTo(z).key;
|
|
10152
|
+
let tile = this.findTileInCaches(this._sourceTileCache[tileID.key]);
|
|
10153
|
+
if (!tile?.dem && searchForDEM) while (z >= source.minzoom && !tile?.dem) tile = this.findTileInCaches(tileID.scaledTo(z--).key);
|
|
10154
|
+
return tile;
|
|
9962
10155
|
}
|
|
9963
|
-
|
|
9964
|
-
|
|
10156
|
+
findTileInCaches(key) {
|
|
10157
|
+
let tile = this.tileManager.getTileByID(key);
|
|
10158
|
+
if (tile) return tile;
|
|
10159
|
+
tile = this.tileManager._outOfViewCache.getByKey(key);
|
|
10160
|
+
return tile;
|
|
9965
10161
|
}
|
|
9966
|
-
|
|
9967
|
-
|
|
10162
|
+
/**
|
|
10163
|
+
* gets whether any tiles were loaded after a specific time. This is used to update the depth framebuffer.
|
|
10164
|
+
* @param time - the time
|
|
10165
|
+
* @returns true if any tiles came into view at or after the specified time
|
|
10166
|
+
*/
|
|
10167
|
+
anyTilesAfterTime(time = now()) {
|
|
10168
|
+
return this._lastTilesetChange >= time;
|
|
9968
10169
|
}
|
|
9969
|
-
|
|
9970
|
-
|
|
10170
|
+
/**
|
|
10171
|
+
* Checks whether a tile is within the canonical tile ranges.
|
|
10172
|
+
* @param tileID - Tile to check
|
|
10173
|
+
* @param canonicalTileRanges - Canonical tile ranges
|
|
10174
|
+
* @returns
|
|
10175
|
+
*/
|
|
10176
|
+
_isWithinTileRanges(tileID, canonicalTileRanges) {
|
|
10177
|
+
const range = canonicalTileRanges[tileID.canonical.z];
|
|
10178
|
+
return !!range && (tileID.wrap > range.minWrap || tileID.wrap < range.maxWrap || tileID.canonical.x >= range.minTileXWrapped && tileID.canonical.x <= range.maxTileXWrapped && tileID.canonical.y >= range.minTileY && tileID.canonical.y <= range.maxTileY);
|
|
9971
10179
|
}
|
|
9972
|
-
|
|
9973
|
-
|
|
10180
|
+
};
|
|
10181
|
+
//#endregion
|
|
10182
|
+
//#region src/render/terrain.ts
|
|
10183
|
+
const MAX_BISECTIONS = 40;
|
|
10184
|
+
const HIT_EPSILON_M = 1e-6;
|
|
10185
|
+
/** Keeps the elevation bracket non-degenerate when the terrain is entirely flat, such as unloaded DEMs. */
|
|
10186
|
+
const BRACKET_PADDING_M = 10;
|
|
10187
|
+
/** `DEMData.sampleBilinear` throws on the far tile edge, so samples stop just short of it. */
|
|
10188
|
+
const MAX_TILE_COORD = EXTENT * (1 - 1e-12);
|
|
10189
|
+
/**
|
|
10190
|
+
* @internal
|
|
10191
|
+
* This is the main class which handles most of the 3D Terrain logic. It has the following topics:
|
|
10192
|
+
*
|
|
10193
|
+
* 1. loads raster-dem tiles via the internal tileManager this.tileManager
|
|
10194
|
+
* 2. creates a depth-framebuffer, which is used to calculate the visibility of coordinates
|
|
10195
|
+
* 3. stores all render-to-texture tiles in the this.tileManager._tiles
|
|
10196
|
+
* 4. calculates the elevation for a specific tile-coordinate
|
|
10197
|
+
* 5. creates a terrain-mesh
|
|
10198
|
+
*
|
|
10199
|
+
* A note about the GPU resource-usage:
|
|
10200
|
+
*
|
|
10201
|
+
* Framebuffers:
|
|
10202
|
+
*
|
|
10203
|
+
* - one for the depth framebuffer with the size of the map-div.
|
|
10204
|
+
* - one for rendering a tile to texture with the size of tileSize (= 512x512).
|
|
10205
|
+
*
|
|
10206
|
+
* Textures:
|
|
10207
|
+
*
|
|
10208
|
+
* - one texture for an empty raster-dem tile with size 1x1
|
|
10209
|
+
* - one texture for an empty depth-buffer, when terrain is disabled with size 1x1
|
|
10210
|
+
* - one texture for an each loaded raster-dem with size of the source.tileSize
|
|
10211
|
+
* - one texture for the depth-framebuffer with the size of the map-div.
|
|
10212
|
+
* - finally for each render-to-texture tile (= this._tiles) a set of textures
|
|
10213
|
+
* for each render stack (The stack-concept is documented in painter.ts).
|
|
10214
|
+
*
|
|
10215
|
+
* Normally there exists 1-3 Textures per tile, depending on the stylesheet.
|
|
10216
|
+
* Each Textures has the size 2*tileSize (= 1024x1024). Also there exists a
|
|
10217
|
+
* cache of the last 150 newest rendered tiles.
|
|
10218
|
+
*
|
|
10219
|
+
*/
|
|
10220
|
+
var Terrain = class {
|
|
10221
|
+
constructor(painter, tileManager, options, terrainSkirtLength = "auto") {
|
|
10222
|
+
this._meshCache = {};
|
|
10223
|
+
this.painter = painter;
|
|
10224
|
+
this.tileManager = new TerrainTileManager(tileManager);
|
|
10225
|
+
this.options = options;
|
|
10226
|
+
this.exaggeration = typeof options.exaggeration === "number" ? options.exaggeration : 1;
|
|
10227
|
+
this._terrainSkirtLength = terrainSkirtLength;
|
|
10228
|
+
this.qualityFactor = 2;
|
|
10229
|
+
this.meshSize = 128;
|
|
10230
|
+
this._demMatrixCache = /* @__PURE__ */ new Map();
|
|
10231
|
+
this._elevationSamplerCache = /* @__PURE__ */ new Map();
|
|
9974
10232
|
}
|
|
9975
|
-
|
|
9976
|
-
this.
|
|
10233
|
+
destroy() {
|
|
10234
|
+
if (this._fbo) {
|
|
10235
|
+
this._fbo.destroy();
|
|
10236
|
+
this._fbo = null;
|
|
10237
|
+
}
|
|
10238
|
+
if (this._fboDepthTexture) {
|
|
10239
|
+
this._fboDepthTexture.destroy();
|
|
10240
|
+
this._fboDepthTexture = null;
|
|
10241
|
+
}
|
|
10242
|
+
if (this._emptyDemTexture) {
|
|
10243
|
+
this._emptyDemTexture.destroy();
|
|
10244
|
+
this._emptyDemTexture = null;
|
|
10245
|
+
}
|
|
10246
|
+
if (this._emptyDepthTexture) {
|
|
10247
|
+
this._emptyDepthTexture.destroy();
|
|
10248
|
+
this._emptyDepthTexture = null;
|
|
10249
|
+
}
|
|
10250
|
+
for (const key in this._meshCache) this._meshCache[key].destroy();
|
|
10251
|
+
this._meshCache = {};
|
|
10252
|
+
this.tileManager.destruct();
|
|
9977
10253
|
}
|
|
9978
|
-
|
|
9979
|
-
|
|
10254
|
+
/**
|
|
10255
|
+
* Get the elevation-value from original dem-data for a given tile-coordinate.
|
|
10256
|
+
* Coordinates that fall outside `[0, extent)` are normalized to the
|
|
10257
|
+
* appropriate neighbor tile before lookup.
|
|
10258
|
+
* @param tileID - the tile to get the elevation for
|
|
10259
|
+
* @param x - x coordinate relative to the tile, may be outside `[0, extent)`
|
|
10260
|
+
* @param y - y coordinate relative to the tile, may be outside `[0, extent)`
|
|
10261
|
+
* @param extent - optional, default 8192
|
|
10262
|
+
* @returns the elevation
|
|
10263
|
+
*/
|
|
10264
|
+
getDEMElevation(tileID, x, y, extent = EXTENT) {
|
|
10265
|
+
const normalized = tileID.normalizeCoordinates(x, y, extent);
|
|
10266
|
+
if (!normalized) return 0;
|
|
10267
|
+
const sampler = this.getElevationSampler(normalized.tileID);
|
|
10268
|
+
return sampler ? sampler(normalized.x, normalized.y, extent) : 0;
|
|
9980
10269
|
}
|
|
9981
|
-
|
|
9982
|
-
|
|
10270
|
+
/**
|
|
10271
|
+
* Get the elevation for given {@link LngLat} in respect of exaggeration.
|
|
10272
|
+
* @param lnglat - the location
|
|
10273
|
+
* @param zoom - the zoom, use {@link getElevationForLngLat} if you don't want a specific zoom level, but more accurate results.
|
|
10274
|
+
* @returns the elevation
|
|
10275
|
+
*/
|
|
10276
|
+
getElevationForLngLatZoom(lnglat, zoom) {
|
|
10277
|
+
if (!isInBoundsForZoomLngLat(zoom, lnglat.wrap())) return 0;
|
|
10278
|
+
const { tileID, mercatorX, mercatorY } = this._getOverscaledTileIDFromLngLatZoom(lnglat, zoom);
|
|
10279
|
+
return this.getElevation(tileID, mercatorX % EXTENT, mercatorY % EXTENT, EXTENT);
|
|
9983
10280
|
}
|
|
9984
|
-
|
|
9985
|
-
|
|
10281
|
+
/**
|
|
10282
|
+
* Get the elevation for given {@link LngLat} in respect of exaggeration.
|
|
10283
|
+
* This will traverse up the zoom levels to find the first tile with data to return.
|
|
10284
|
+
* @param lnglat - the location
|
|
10285
|
+
* @returns the elevation
|
|
10286
|
+
*/
|
|
10287
|
+
getElevationForLngLat(lnglat, transform) {
|
|
10288
|
+
const terrainCoveringTiles = coveringTiles(transform, {
|
|
10289
|
+
maxzoom: this.tileManager.maxzoom,
|
|
10290
|
+
minzoom: this.tileManager.minzoom,
|
|
10291
|
+
tileSize: 512,
|
|
10292
|
+
terrain: this
|
|
10293
|
+
});
|
|
10294
|
+
let zoom = 0;
|
|
10295
|
+
for (const tile of terrainCoveringTiles) if (tile.canonical.z > zoom) zoom = Math.min(tile.canonical.z, this.tileManager.maxzoom);
|
|
10296
|
+
return this.getElevationForLngLatZoom(lnglat, zoom);
|
|
9986
10297
|
}
|
|
9987
|
-
|
|
9988
|
-
|
|
10298
|
+
/**
|
|
10299
|
+
* Get the elevation for given coordinate in respect of exaggeration.
|
|
10300
|
+
* @param tileID - the tile id
|
|
10301
|
+
* @param x - x coordinate relative to the tile, may be outside `[0, extent)`
|
|
10302
|
+
* @param y - y coordinate relative to the tile, may be outside `[0, extent)`
|
|
10303
|
+
* @param extent - optional, default 8192
|
|
10304
|
+
* @returns the elevation
|
|
10305
|
+
*/
|
|
10306
|
+
getElevation(tileID, x, y, extent = EXTENT) {
|
|
10307
|
+
return this.getDEMElevation(tileID, x, y, extent) * this.exaggeration;
|
|
9989
10308
|
}
|
|
9990
|
-
|
|
9991
|
-
|
|
10309
|
+
/**
|
|
10310
|
+
* Clear CPU elevation samplers that may retain a previously selected DEM tile.
|
|
10311
|
+
* @internal
|
|
10312
|
+
*/
|
|
10313
|
+
resetElevationCache() {
|
|
10314
|
+
this._elevationSamplerCache.clear();
|
|
10315
|
+
this._coverageIndex = void 0;
|
|
10316
|
+
}
|
|
10317
|
+
/**
|
|
10318
|
+
* Index of the tiles the terrain currently renders, for sampling the terrain surface on the CPU.
|
|
10319
|
+
* Built on first use and kept until {@link resetElevationCache}.
|
|
10320
|
+
* @returns the index, or null when no terrain tile is renderable
|
|
10321
|
+
*/
|
|
10322
|
+
getCoverageIndex() {
|
|
10323
|
+
if (this._coverageIndex === void 0) this._coverageIndex = this._buildCoverageIndex();
|
|
10324
|
+
return this._coverageIndex;
|
|
10325
|
+
}
|
|
10326
|
+
_buildCoverageIndex() {
|
|
10327
|
+
const zooms = [];
|
|
10328
|
+
const samplerPerTile = /* @__PURE__ */ new Map();
|
|
10329
|
+
let minElevation = 0;
|
|
10330
|
+
let maxElevation = 0;
|
|
10331
|
+
for (const tile of this.tileManager.getRenderableTiles()) {
|
|
10332
|
+
if (!tile) continue;
|
|
10333
|
+
const { canonical, wrap } = tile.tileID;
|
|
10334
|
+
if (!zooms.includes(canonical.z)) zooms.push(canonical.z);
|
|
10335
|
+
const sampler = this.getElevationSampler(tile.tileID);
|
|
10336
|
+
samplerPerTile.set(`${wrap}/${canonical.z}/${canonical.x}/${canonical.y}`, sampler);
|
|
10337
|
+
const { minElevation: tileMin, maxElevation: tileMax } = this.getMinMaxElevation(tile.tileID);
|
|
10338
|
+
minElevation = Math.min(minElevation, tileMin ?? 0);
|
|
10339
|
+
maxElevation = Math.max(maxElevation, tileMax ?? 0);
|
|
10340
|
+
}
|
|
10341
|
+
if (samplerPerTile.size === 0) return null;
|
|
10342
|
+
zooms.sort((a, b) => b - a);
|
|
10343
|
+
return {
|
|
10344
|
+
zooms,
|
|
10345
|
+
samplerPerTile,
|
|
10346
|
+
minElevation: minElevation - BRACKET_PADDING_M,
|
|
10347
|
+
maxElevation: maxElevation + BRACKET_PADDING_M
|
|
10348
|
+
};
|
|
9992
10349
|
}
|
|
9993
|
-
|
|
9994
|
-
|
|
10350
|
+
/**
|
|
10351
|
+
* Get a function that samples the raw DEM elevation of a tile, without exaggeration.
|
|
10352
|
+
* @param tileID - the tile id
|
|
10353
|
+
* @returns the sampler, or null when the tile's DEM data is not loaded
|
|
10354
|
+
*/
|
|
10355
|
+
getElevationSampler(tileID) {
|
|
10356
|
+
const key = tileID.key;
|
|
10357
|
+
const cachedSampler = this._elevationSamplerCache.get(key);
|
|
10358
|
+
if (cachedSampler) return cachedSampler;
|
|
10359
|
+
const sourceTile = this.tileManager.getSourceTile(tileID, true);
|
|
10360
|
+
const dem = sourceTile?.dem;
|
|
10361
|
+
if (!sourceTile || !dem) return null;
|
|
10362
|
+
const matrix = this._getDEMTileMatrix(tileID, sourceTile);
|
|
10363
|
+
const demPixelScaleX = matrix[0] * dem.dim;
|
|
10364
|
+
const demPixelScaleY = matrix[5] * dem.dim;
|
|
10365
|
+
const demPixelOffsetX = matrix[12] * dem.dim;
|
|
10366
|
+
const demPixelOffsetY = matrix[13] * dem.dim;
|
|
10367
|
+
const sampler = (x, y, extent) => {
|
|
10368
|
+
const extentScale = extent === 8192 ? 1 : EXTENT / extent;
|
|
10369
|
+
return dem.sampleBilinear(x * extentScale * demPixelScaleX + demPixelOffsetX, y * extentScale * demPixelScaleY + demPixelOffsetY);
|
|
10370
|
+
};
|
|
10371
|
+
this._elevationSamplerCache.set(key, sampler);
|
|
10372
|
+
return sampler;
|
|
9995
10373
|
}
|
|
9996
|
-
|
|
9997
|
-
|
|
10374
|
+
_getDEMTileMatrix(tileID, sourceTile) {
|
|
10375
|
+
const matrixKey = `${sourceTile.tileID.key}/${tileID.key}`;
|
|
10376
|
+
const cachedMatrix = this._demMatrixCache.get(matrixKey);
|
|
10377
|
+
if (cachedMatrix) return cachedMatrix;
|
|
10378
|
+
const maxzoom = this.tileManager.getSource().maxzoom;
|
|
10379
|
+
let dz = tileID.canonical.z - sourceTile.tileID.canonical.z;
|
|
10380
|
+
if (tileID.overscaledZ > tileID.canonical.z) {
|
|
10381
|
+
if (tileID.canonical.z >= maxzoom) dz = tileID.canonical.z - maxzoom;
|
|
10382
|
+
else warnOnce("cannot calculate elevation if elevation maxzoom > source.maxzoom");
|
|
10383
|
+
}
|
|
10384
|
+
const dx = tileID.canonical.x - (tileID.canonical.x >> dz << dz);
|
|
10385
|
+
const dy = tileID.canonical.y - (tileID.canonical.y >> dz << dz);
|
|
10386
|
+
const demMatrix = fromScaling(/* @__PURE__ */ new Float64Array(16), [
|
|
10387
|
+
1 / (EXTENT << dz),
|
|
10388
|
+
1 / (EXTENT << dz),
|
|
10389
|
+
0
|
|
10390
|
+
]);
|
|
10391
|
+
translate(demMatrix, demMatrix, [
|
|
10392
|
+
dx * EXTENT,
|
|
10393
|
+
dy * EXTENT,
|
|
10394
|
+
0
|
|
10395
|
+
]);
|
|
10396
|
+
this._demMatrixCache.set(matrixKey, demMatrix);
|
|
10397
|
+
return demMatrix;
|
|
9998
10398
|
}
|
|
9999
|
-
|
|
10000
|
-
|
|
10399
|
+
/**
|
|
10400
|
+
* returns a Terrain Object for a tile. Unless the tile corresponds to data (e.g. tile is loading), return a flat dem object
|
|
10401
|
+
* @param tileID - the tile to get the terrain for
|
|
10402
|
+
* @returns the terrain data to use in the program
|
|
10403
|
+
*/
|
|
10404
|
+
getTerrainData(tileID) {
|
|
10405
|
+
if (!this._emptyDemTexture) {
|
|
10406
|
+
const context = this.painter.context;
|
|
10407
|
+
const image = new RGBAImage({
|
|
10408
|
+
width: 1,
|
|
10409
|
+
height: 1
|
|
10410
|
+
}, /* @__PURE__ */ new Uint8Array(4));
|
|
10411
|
+
this._emptyDepthTexture = new Texture(context, image, context.gl.RGBA, { premultiply: false });
|
|
10412
|
+
this._emptyDemUnpack = [
|
|
10413
|
+
0,
|
|
10414
|
+
0,
|
|
10415
|
+
0,
|
|
10416
|
+
0
|
|
10417
|
+
];
|
|
10418
|
+
this._emptyDemTexture = new Texture(context, new RGBAImage({
|
|
10419
|
+
width: 1,
|
|
10420
|
+
height: 1
|
|
10421
|
+
}), context.gl.RGBA, { premultiply: false });
|
|
10422
|
+
this._emptyDemTexture.bind(context.gl.NEAREST, context.gl.CLAMP_TO_EDGE);
|
|
10423
|
+
this._emptyDemMatrix = identity([]);
|
|
10424
|
+
}
|
|
10425
|
+
const sourceTile = this.tileManager.getSourceTile(tileID, true);
|
|
10426
|
+
if (sourceTile?.dem && (!sourceTile.demTexture || sourceTile.needsTerrainPrepare)) {
|
|
10427
|
+
const context = this.painter.context;
|
|
10428
|
+
sourceTile.demTexture ||= this.painter.getTileTexture(sourceTile.dem.stride);
|
|
10429
|
+
if (sourceTile.demTexture) sourceTile.demTexture.update(sourceTile.dem.getPixels(), { premultiply: false });
|
|
10430
|
+
else sourceTile.demTexture = new Texture(context, sourceTile.dem.getPixels(), context.gl.RGBA, { premultiply: false });
|
|
10431
|
+
sourceTile.demTexture.bind(context.gl.NEAREST, context.gl.CLAMP_TO_EDGE);
|
|
10432
|
+
sourceTile.needsTerrainPrepare = false;
|
|
10433
|
+
}
|
|
10434
|
+
const terrainMatrix = sourceTile ? this._getDEMTileMatrix(tileID, sourceTile) : this._emptyDemMatrix;
|
|
10435
|
+
return {
|
|
10436
|
+
"u_depth": 2,
|
|
10437
|
+
"u_terrain": 3,
|
|
10438
|
+
"u_terrain_dim": sourceTile?.dem?.dim || 1,
|
|
10439
|
+
"u_terrain_matrix": terrainMatrix,
|
|
10440
|
+
"u_terrain_unpack": sourceTile?.dem?.getUnpackVector() || this._emptyDemUnpack,
|
|
10441
|
+
"u_terrain_exaggeration": this.exaggeration,
|
|
10442
|
+
texture: (sourceTile?.demTexture || this._emptyDemTexture).texture,
|
|
10443
|
+
depthTexture: (this._fboDepthTexture || this._emptyDepthTexture).texture,
|
|
10444
|
+
tile: sourceTile
|
|
10445
|
+
};
|
|
10001
10446
|
}
|
|
10002
|
-
|
|
10003
|
-
|
|
10447
|
+
/**
|
|
10448
|
+
* get a framebuffer as big as the map-div, which will be used to render depth into a texture
|
|
10449
|
+
* @returns the frame buffer
|
|
10450
|
+
*/
|
|
10451
|
+
getFramebuffer() {
|
|
10452
|
+
const painter = this.painter;
|
|
10453
|
+
const width = painter.width / devicePixelRatio;
|
|
10454
|
+
const height = painter.height / devicePixelRatio;
|
|
10455
|
+
if (this._fbo && (this._fbo.width !== width || this._fbo.height !== height)) {
|
|
10456
|
+
this._fbo.destroy();
|
|
10457
|
+
this._fboDepthTexture.destroy();
|
|
10458
|
+
delete this._fbo;
|
|
10459
|
+
delete this._fboDepthTexture;
|
|
10460
|
+
}
|
|
10461
|
+
if (!this._fboDepthTexture) {
|
|
10462
|
+
this._fboDepthTexture = new Texture(painter.context, {
|
|
10463
|
+
width,
|
|
10464
|
+
height,
|
|
10465
|
+
data: null
|
|
10466
|
+
}, painter.context.gl.RGBA, { premultiply: false });
|
|
10467
|
+
this._fboDepthTexture.bind(painter.context.gl.NEAREST, painter.context.gl.CLAMP_TO_EDGE);
|
|
10468
|
+
}
|
|
10469
|
+
if (!this._fbo) {
|
|
10470
|
+
this._fbo = painter.context.createFramebuffer(width, height, true, false);
|
|
10471
|
+
this._fbo.depthAttachment.set(painter.context.createRenderbuffer(painter.context.gl.DEPTH_COMPONENT16, width, height));
|
|
10472
|
+
}
|
|
10473
|
+
this._fbo.colorAttachment.set(this._fboDepthTexture.texture);
|
|
10474
|
+
return this._fbo;
|
|
10004
10475
|
}
|
|
10005
|
-
|
|
10006
|
-
|
|
10476
|
+
/**
|
|
10477
|
+
* Reads the depth value from the depth-framebuffer at a given screen pixel
|
|
10478
|
+
* @param p - Screen coordinate
|
|
10479
|
+
* @returns depth value in clip space (between 0 and 1)
|
|
10480
|
+
*/
|
|
10481
|
+
depthAtPoint(p) {
|
|
10482
|
+
const rgba = /* @__PURE__ */ new Uint8Array(4);
|
|
10483
|
+
const context = this.painter.context, gl = context.gl;
|
|
10484
|
+
context.bindFramebuffer.set(this.getFramebuffer().framebuffer);
|
|
10485
|
+
gl.readPixels(p.x, this.painter.height / devicePixelRatio - p.y - 1, 1, 1, gl.RGBA, gl.UNSIGNED_BYTE, rgba);
|
|
10486
|
+
context.bindFramebuffer.set(null);
|
|
10487
|
+
return (rgba[0] / 16777216 + rgba[1] / 65536 + rgba[2] / 256 + rgba[3]) / 256;
|
|
10007
10488
|
}
|
|
10008
|
-
|
|
10009
|
-
|
|
10489
|
+
/**
|
|
10490
|
+
* create a regular mesh which will be used by all terrain-tiles
|
|
10491
|
+
* @returns the created regular mesh
|
|
10492
|
+
*/
|
|
10493
|
+
getTerrainMesh(tileId) {
|
|
10494
|
+
const globeEnabled = this.painter.style.projection?.transitionState > 0;
|
|
10495
|
+
const northPole = globeEnabled && tileId.canonical.y === 0;
|
|
10496
|
+
const southPole = globeEnabled && tileId.canonical.y === (1 << tileId.canonical.z) - 1;
|
|
10497
|
+
const key = `m_${northPole ? "n" : ""}_${southPole ? "s" : ""}`;
|
|
10498
|
+
if (this._meshCache[key]) return this._meshCache[key];
|
|
10499
|
+
const context = this.painter.context;
|
|
10500
|
+
const vertexArray = new Pos3dArray();
|
|
10501
|
+
const indexArray = new TriangleIndexArray();
|
|
10502
|
+
const meshSize = this.meshSize;
|
|
10503
|
+
const delta = EXTENT / meshSize;
|
|
10504
|
+
const meshSize2 = meshSize * meshSize;
|
|
10505
|
+
for (let y = 0; y <= meshSize; y++) for (let x = 0; x <= meshSize; x++) vertexArray.emplaceBack(x * delta, y * delta, 0);
|
|
10506
|
+
for (let y = 0; y < meshSize2; y += meshSize + 1) for (let x = 0; x < meshSize; x++) {
|
|
10507
|
+
indexArray.emplaceBack(x + y, meshSize + x + y + 1, meshSize + x + y + 2);
|
|
10508
|
+
indexArray.emplaceBack(x + y, meshSize + x + y + 2, x + y + 1);
|
|
10509
|
+
}
|
|
10510
|
+
if (this._terrainSkirtLength !== "none") this._buildSkirts(vertexArray, indexArray, meshSize, delta, northPole, southPole);
|
|
10511
|
+
const mesh = new Mesh(context.createVertexBuffer(vertexArray, pos3dAttributes.members), context.createIndexBuffer(indexArray), SegmentVector.simpleSegment(0, 0, vertexArray.length, indexArray.length));
|
|
10512
|
+
this._meshCache[key] = mesh;
|
|
10513
|
+
return mesh;
|
|
10010
10514
|
}
|
|
10011
|
-
|
|
10012
|
-
|
|
10515
|
+
/**
|
|
10516
|
+
* Calculates the height of the tile skirts for the "auto" strategy.
|
|
10517
|
+
* @see {@link MapOptions.terrainSkirtLength}
|
|
10518
|
+
* @param zoom - current zoomlevel
|
|
10519
|
+
* @returns the elevation delta in meters
|
|
10520
|
+
*/
|
|
10521
|
+
getSkirtLength(zoom) {
|
|
10522
|
+
return 2 * Math.PI * earthRadius / Math.pow(2, Math.max(zoom, 0)) / 5;
|
|
10013
10523
|
}
|
|
10014
|
-
|
|
10015
|
-
return
|
|
10524
|
+
getMinTileElevationForLngLatZoom(lnglat, zoom) {
|
|
10525
|
+
if (!isInBoundsForZoomLngLat(zoom, lnglat.wrap())) return 0;
|
|
10526
|
+
const { tileID } = this._getOverscaledTileIDFromLngLatZoom(lnglat, zoom);
|
|
10527
|
+
return this.getMinMaxElevation(tileID).minElevation ?? 0;
|
|
10016
10528
|
}
|
|
10017
|
-
|
|
10018
|
-
|
|
10529
|
+
/**
|
|
10530
|
+
* Get the minimum and maximum elevation contained in a tile. This includes any
|
|
10531
|
+
* exaggeration included in the terrain.
|
|
10532
|
+
*
|
|
10533
|
+
* @param tileID - ID of the tile to be used as a source for the min/max elevation
|
|
10534
|
+
* @returns the minimum and maximum elevation found in the tile, including the terrain's
|
|
10535
|
+
* exaggeration
|
|
10536
|
+
*/
|
|
10537
|
+
getMinMaxElevation(tileID) {
|
|
10538
|
+
const tile = this.tileManager.getSourceTile(tileID, true);
|
|
10539
|
+
const minMax = {
|
|
10540
|
+
minElevation: null,
|
|
10541
|
+
maxElevation: null
|
|
10542
|
+
};
|
|
10543
|
+
if (tile?.dem) {
|
|
10544
|
+
minMax.minElevation = tile.dem.min * this.exaggeration;
|
|
10545
|
+
minMax.maxElevation = tile.dem.max * this.exaggeration;
|
|
10546
|
+
}
|
|
10547
|
+
return minMax;
|
|
10019
10548
|
}
|
|
10020
|
-
|
|
10021
|
-
|
|
10549
|
+
_getOverscaledTileIDFromLngLatZoom(lnglat, zoom) {
|
|
10550
|
+
const mercatorCoordinate = MercatorCoordinate.fromLngLat(lnglat.wrap());
|
|
10551
|
+
const worldSize = (1 << zoom) * EXTENT;
|
|
10552
|
+
const mercatorX = mercatorCoordinate.x * worldSize;
|
|
10553
|
+
const mercatorY = mercatorCoordinate.y * worldSize;
|
|
10554
|
+
const tileX = Math.floor(mercatorX / EXTENT), tileY = Math.floor(mercatorY / EXTENT);
|
|
10555
|
+
return {
|
|
10556
|
+
tileID: new OverscaledTileID(zoom, 0, zoom, tileX, tileY),
|
|
10557
|
+
mercatorX,
|
|
10558
|
+
mercatorY
|
|
10559
|
+
};
|
|
10022
10560
|
}
|
|
10023
|
-
|
|
10024
|
-
|
|
10561
|
+
/** Add an extra frame around the mesh to avoid hairline gaps (stitching) on tile boundaries with different zoomlevels.
|
|
10562
|
+
* @see {@link MapOptions.terrainSkirtLength}
|
|
10563
|
+
*/
|
|
10564
|
+
_buildSkirts(vertexArray, indexArray, meshSize, delta, northPole, southPole) {
|
|
10565
|
+
const offsetTop = vertexArray.length;
|
|
10566
|
+
const offsetTopEdge = 0;
|
|
10567
|
+
const offsetBottom = offsetTop + (meshSize + 1);
|
|
10568
|
+
const offsetBottomEdge = (meshSize + 1) * meshSize;
|
|
10569
|
+
const northY = northPole ? NORTH_POLE_Y : 0;
|
|
10570
|
+
const northZ = northPole ? 0 : 1;
|
|
10571
|
+
const southY = southPole ? SOUTH_POLE_Y : EXTENT;
|
|
10572
|
+
const southZ = southPole ? 0 : 1;
|
|
10573
|
+
for (let x = 0; x <= meshSize; x++) vertexArray.emplaceBack(x * delta, northY, northZ);
|
|
10574
|
+
for (let x = 0; x <= meshSize; x++) vertexArray.emplaceBack(x * delta, southY, southZ);
|
|
10575
|
+
for (let x = 0; x < meshSize; x++) {
|
|
10576
|
+
indexArray.emplaceBack(offsetBottomEdge + x, offsetBottom + x, offsetBottom + x + 1);
|
|
10577
|
+
indexArray.emplaceBack(offsetBottomEdge + x, offsetBottom + x + 1, offsetBottomEdge + x + 1);
|
|
10578
|
+
indexArray.emplaceBack(offsetTopEdge + x, offsetTop + x + 1, offsetTop + x);
|
|
10579
|
+
indexArray.emplaceBack(offsetTopEdge + x, offsetTopEdge + x + 1, offsetTop + x + 1);
|
|
10580
|
+
}
|
|
10581
|
+
const offsetLeft = vertexArray.length;
|
|
10582
|
+
const offsetRight = offsetLeft + (meshSize + 1) * 2;
|
|
10583
|
+
for (const x of [0, 1]) for (let y = 0; y <= meshSize; y++) for (const z of [0, 1]) vertexArray.emplaceBack(x * EXTENT, y * delta, z);
|
|
10584
|
+
for (let y = 0; y < meshSize * 2; y += 2) {
|
|
10585
|
+
indexArray.emplaceBack(offsetLeft + y, offsetLeft + y + 1, offsetLeft + y + 3);
|
|
10586
|
+
indexArray.emplaceBack(offsetLeft + y, offsetLeft + y + 3, offsetLeft + y + 2);
|
|
10587
|
+
indexArray.emplaceBack(offsetRight + y, offsetRight + y + 3, offsetRight + y + 1);
|
|
10588
|
+
indexArray.emplaceBack(offsetRight + y, offsetRight + y + 2, offsetRight + y + 3);
|
|
10589
|
+
}
|
|
10025
10590
|
}
|
|
10026
|
-
|
|
10027
|
-
|
|
10591
|
+
};
|
|
10592
|
+
const NOT_COVERED = {
|
|
10593
|
+
covered: false,
|
|
10594
|
+
elevation: 0
|
|
10595
|
+
};
|
|
10596
|
+
/**
|
|
10597
|
+
* Elevation of the rendered terrain surface at a mercator position, and whether it is covered at all.
|
|
10598
|
+
* A covered tile whose DEM has not loaded yet is flat at zero, which is what the terrain mesh renders.
|
|
10599
|
+
*/
|
|
10600
|
+
function sampleAt(index, exaggeration, mercatorX, mercatorY) {
|
|
10601
|
+
if (mercatorY < 0 || mercatorY >= 1) return NOT_COVERED;
|
|
10602
|
+
const wrap = Math.floor(mercatorX);
|
|
10603
|
+
const wrappedX = mercatorX - wrap;
|
|
10604
|
+
for (const z of index.zooms) {
|
|
10605
|
+
const scale = 1 << z;
|
|
10606
|
+
const scaledX = wrappedX * scale;
|
|
10607
|
+
const scaledY = mercatorY * scale;
|
|
10608
|
+
const tileX = Math.floor(scaledX);
|
|
10609
|
+
const tileY = Math.floor(scaledY);
|
|
10610
|
+
const key = `${wrap}/${z}/${tileX}/${tileY}`;
|
|
10611
|
+
if (!index.samplerPerTile.has(key)) continue;
|
|
10612
|
+
const sampler = index.samplerPerTile.get(key);
|
|
10613
|
+
if (!sampler) return {
|
|
10614
|
+
covered: true,
|
|
10615
|
+
elevation: 0
|
|
10616
|
+
};
|
|
10617
|
+
return {
|
|
10618
|
+
covered: true,
|
|
10619
|
+
elevation: sampler(Math.min((scaledX - tileX) * EXTENT, MAX_TILE_COORD), Math.min((scaledY - tileY) * EXTENT, MAX_TILE_COORD), EXTENT) * exaggeration
|
|
10620
|
+
};
|
|
10028
10621
|
}
|
|
10029
|
-
|
|
10030
|
-
|
|
10622
|
+
return NOT_COVERED;
|
|
10623
|
+
}
|
|
10624
|
+
/**
|
|
10625
|
+
* Whether a height in meters is at or below the sampled terrain surface.
|
|
10626
|
+
* The epsilon absorbs rounding when a bracket endpoint lands exactly on the surface.
|
|
10627
|
+
*/
|
|
10628
|
+
function isBelowTerrainSample(sample, height) {
|
|
10629
|
+
return sample.covered && height <= sample.elevation + HIT_EPSILON_M;
|
|
10630
|
+
}
|
|
10631
|
+
/**
|
|
10632
|
+
* Narrows the bracket `[lo, hi]` around the surface crossing until it is shorter than `tolerance` in ray parameter units.
|
|
10633
|
+
*/
|
|
10634
|
+
function bisect(ray, isBelowTerrain, lo, hi, tolerance) {
|
|
10635
|
+
for (let j = 0; j < MAX_BISECTIONS && hi - lo > tolerance; j++) {
|
|
10636
|
+
const mid = (lo + hi) / 2;
|
|
10637
|
+
if (isBelowTerrain(ray, mid)) hi = mid;
|
|
10638
|
+
else lo = mid;
|
|
10031
10639
|
}
|
|
10032
|
-
|
|
10033
|
-
|
|
10640
|
+
return {
|
|
10641
|
+
lo,
|
|
10642
|
+
hi
|
|
10643
|
+
};
|
|
10644
|
+
}
|
|
10645
|
+
//#endregion
|
|
10646
|
+
//#region src/geo/projection/mercator_transform.ts
|
|
10647
|
+
const TARGET_WORLD_STEP_PX = 4;
|
|
10648
|
+
const MAX_SAMPLES = 512;
|
|
10649
|
+
const MERCATOR_BISECT_EPSILON_WORLD_PX = .001;
|
|
10650
|
+
var MercatorTransform = class MercatorTransform {
|
|
10651
|
+
get pixelsToClipSpaceMatrix() {
|
|
10652
|
+
return this._helper.pixelsToClipSpaceMatrix;
|
|
10034
10653
|
}
|
|
10035
|
-
get
|
|
10036
|
-
return this._helper.
|
|
10654
|
+
get clipSpaceToPixelsMatrix() {
|
|
10655
|
+
return this._helper.clipSpaceToPixelsMatrix;
|
|
10037
10656
|
}
|
|
10038
|
-
get
|
|
10039
|
-
return this._helper.
|
|
10657
|
+
get pixelsToGLUnits() {
|
|
10658
|
+
return this._helper.pixelsToGLUnits;
|
|
10040
10659
|
}
|
|
10041
|
-
get
|
|
10042
|
-
return this._helper.
|
|
10660
|
+
get centerOffset() {
|
|
10661
|
+
return this._helper.centerOffset;
|
|
10043
10662
|
}
|
|
10044
|
-
get
|
|
10045
|
-
return this._helper.
|
|
10663
|
+
get size() {
|
|
10664
|
+
return this._helper.size;
|
|
10046
10665
|
}
|
|
10047
|
-
get
|
|
10048
|
-
return this._helper.
|
|
10666
|
+
get rotationMatrix() {
|
|
10667
|
+
return this._helper.rotationMatrix;
|
|
10049
10668
|
}
|
|
10050
|
-
get
|
|
10051
|
-
return this._helper.
|
|
10669
|
+
get centerPoint() {
|
|
10670
|
+
return this._helper.centerPoint;
|
|
10052
10671
|
}
|
|
10053
|
-
get
|
|
10054
|
-
return this._helper.
|
|
10672
|
+
get pixelsPerMeter() {
|
|
10673
|
+
return this._helper.pixelsPerMeter;
|
|
10055
10674
|
}
|
|
10056
|
-
|
|
10057
|
-
|
|
10675
|
+
setMinZoom(zoom) {
|
|
10676
|
+
this._helper.setMinZoom(zoom);
|
|
10058
10677
|
}
|
|
10059
|
-
|
|
10678
|
+
setMaxZoom(zoom) {
|
|
10679
|
+
this._helper.setMaxZoom(zoom);
|
|
10680
|
+
}
|
|
10681
|
+
setMinPitch(pitch) {
|
|
10682
|
+
this._helper.setMinPitch(pitch);
|
|
10683
|
+
}
|
|
10684
|
+
setMaxPitch(pitch) {
|
|
10685
|
+
this._helper.setMaxPitch(pitch);
|
|
10686
|
+
}
|
|
10687
|
+
setRenderWorldCopies(renderWorldCopies) {
|
|
10688
|
+
this._helper.setRenderWorldCopies(renderWorldCopies);
|
|
10689
|
+
}
|
|
10690
|
+
setBearing(bearing) {
|
|
10691
|
+
this._helper.setBearing(bearing);
|
|
10692
|
+
}
|
|
10693
|
+
setPitch(pitch) {
|
|
10694
|
+
this._helper.setPitch(pitch);
|
|
10695
|
+
}
|
|
10696
|
+
setRoll(roll) {
|
|
10697
|
+
this._helper.setRoll(roll);
|
|
10698
|
+
}
|
|
10699
|
+
setFov(fov) {
|
|
10700
|
+
this._helper.setFov(fov);
|
|
10701
|
+
}
|
|
10702
|
+
setZoom(zoom) {
|
|
10703
|
+
this._helper.setZoom(zoom);
|
|
10704
|
+
}
|
|
10705
|
+
setCenter(center) {
|
|
10706
|
+
this._helper.setCenter(center);
|
|
10707
|
+
}
|
|
10708
|
+
setElevation(elevation) {
|
|
10709
|
+
this._helper.setElevation(elevation);
|
|
10710
|
+
}
|
|
10711
|
+
setMinElevationForCurrentTile(elevation) {
|
|
10712
|
+
this._helper.setMinElevationForCurrentTile(elevation);
|
|
10713
|
+
}
|
|
10714
|
+
setPadding(padding) {
|
|
10715
|
+
this._helper.setPadding(padding);
|
|
10716
|
+
}
|
|
10717
|
+
interpolatePadding(start, target, t) {
|
|
10718
|
+
this._helper.interpolatePadding(start, target, t);
|
|
10719
|
+
}
|
|
10720
|
+
isPaddingEqual(padding) {
|
|
10721
|
+
return this._helper.isPaddingEqual(padding);
|
|
10722
|
+
}
|
|
10723
|
+
resize(width, height, constrain = true) {
|
|
10724
|
+
this._helper.resize(width, height, constrain);
|
|
10725
|
+
}
|
|
10726
|
+
getMaxBounds() {
|
|
10727
|
+
return this._helper.getMaxBounds();
|
|
10728
|
+
}
|
|
10729
|
+
setMaxBounds(bounds) {
|
|
10730
|
+
this._helper.setMaxBounds(bounds);
|
|
10731
|
+
}
|
|
10732
|
+
setConstrainOverride(constrain) {
|
|
10733
|
+
this._helper.setConstrainOverride(constrain);
|
|
10734
|
+
}
|
|
10735
|
+
overrideNearFarZ(nearZ, farZ) {
|
|
10736
|
+
this._helper.overrideNearFarZ(nearZ, farZ);
|
|
10737
|
+
}
|
|
10738
|
+
clearNearFarZOverride() {
|
|
10739
|
+
this._helper.clearNearFarZOverride();
|
|
10740
|
+
}
|
|
10741
|
+
getCameraQueryGeometry(queryGeometry) {
|
|
10742
|
+
return this._helper.getCameraQueryGeometry(this.getCameraPoint(), queryGeometry);
|
|
10743
|
+
}
|
|
10744
|
+
get tileSize() {
|
|
10745
|
+
return this._helper.tileSize;
|
|
10746
|
+
}
|
|
10747
|
+
get tileZoom() {
|
|
10748
|
+
return this._helper.tileZoom;
|
|
10749
|
+
}
|
|
10750
|
+
get scale() {
|
|
10751
|
+
return this._helper.scale;
|
|
10752
|
+
}
|
|
10753
|
+
get worldSize() {
|
|
10754
|
+
return this._helper.worldSize;
|
|
10755
|
+
}
|
|
10756
|
+
get width() {
|
|
10757
|
+
return this._helper.width;
|
|
10758
|
+
}
|
|
10759
|
+
get height() {
|
|
10760
|
+
return this._helper.height;
|
|
10761
|
+
}
|
|
10762
|
+
get lngRange() {
|
|
10763
|
+
return this._helper.lngRange;
|
|
10764
|
+
}
|
|
10765
|
+
get latRange() {
|
|
10766
|
+
return this._helper.latRange;
|
|
10767
|
+
}
|
|
10768
|
+
get minZoom() {
|
|
10769
|
+
return this._helper.minZoom;
|
|
10770
|
+
}
|
|
10771
|
+
get maxZoom() {
|
|
10772
|
+
return this._helper.maxZoom;
|
|
10773
|
+
}
|
|
10774
|
+
get zoom() {
|
|
10775
|
+
return this._helper.zoom;
|
|
10776
|
+
}
|
|
10777
|
+
get center() {
|
|
10778
|
+
return this._helper.center;
|
|
10779
|
+
}
|
|
10780
|
+
get minPitch() {
|
|
10781
|
+
return this._helper.minPitch;
|
|
10782
|
+
}
|
|
10783
|
+
get maxPitch() {
|
|
10784
|
+
return this._helper.maxPitch;
|
|
10785
|
+
}
|
|
10786
|
+
get pitch() {
|
|
10787
|
+
return this._helper.pitch;
|
|
10788
|
+
}
|
|
10789
|
+
get pitchInRadians() {
|
|
10790
|
+
return this._helper.pitchInRadians;
|
|
10791
|
+
}
|
|
10792
|
+
get roll() {
|
|
10793
|
+
return this._helper.roll;
|
|
10794
|
+
}
|
|
10795
|
+
get rollInRadians() {
|
|
10796
|
+
return this._helper.rollInRadians;
|
|
10797
|
+
}
|
|
10798
|
+
get bearing() {
|
|
10799
|
+
return this._helper.bearing;
|
|
10800
|
+
}
|
|
10801
|
+
get bearingInRadians() {
|
|
10802
|
+
return this._helper.bearingInRadians;
|
|
10803
|
+
}
|
|
10804
|
+
get fov() {
|
|
10805
|
+
return this._helper.fov;
|
|
10806
|
+
}
|
|
10807
|
+
get fovInRadians() {
|
|
10808
|
+
return this._helper.fovInRadians;
|
|
10809
|
+
}
|
|
10810
|
+
get elevation() {
|
|
10811
|
+
return this._helper.elevation;
|
|
10812
|
+
}
|
|
10813
|
+
get minElevationForCurrentTile() {
|
|
10814
|
+
return this._helper.minElevationForCurrentTile;
|
|
10815
|
+
}
|
|
10816
|
+
get padding() {
|
|
10817
|
+
return this._helper.padding;
|
|
10818
|
+
}
|
|
10819
|
+
get unmodified() {
|
|
10820
|
+
return this._helper.unmodified;
|
|
10821
|
+
}
|
|
10822
|
+
get renderWorldCopies() {
|
|
10060
10823
|
return this._helper.renderWorldCopies;
|
|
10061
10824
|
}
|
|
10062
10825
|
get cameraToCenterDistance() {
|
|
@@ -10228,17 +10991,64 @@ var MercatorTransform = class MercatorTransform {
|
|
|
10228
10991
|
}
|
|
10229
10992
|
screenPointToMercatorCoordinate(p, terrain) {
|
|
10230
10993
|
if (terrain) {
|
|
10231
|
-
const coordinate =
|
|
10994
|
+
const coordinate = this.screenTerrainPointToMercatorCoordinate(p, terrain);
|
|
10232
10995
|
if (coordinate != null) return coordinate;
|
|
10233
10996
|
}
|
|
10234
10997
|
return this.screenPointToMercatorCoordinateAtZ(p);
|
|
10235
10998
|
}
|
|
10999
|
+
/** {@inheritDoc ITransform.screenTerrainPointToMercatorCoordinate} */
|
|
11000
|
+
screenTerrainPointToMercatorCoordinate(p, terrain) {
|
|
11001
|
+
const index = terrain.getCoverageIndex();
|
|
11002
|
+
if (!index) return null;
|
|
11003
|
+
const { near, far } = this.getRaySegmentFromPixel(p);
|
|
11004
|
+
const worldSize = this.worldSize;
|
|
11005
|
+
const dx = far[0] - near[0];
|
|
11006
|
+
const dy = far[1] - near[1];
|
|
11007
|
+
const dz = far[2] - near[2];
|
|
11008
|
+
const ray = {
|
|
11009
|
+
index,
|
|
11010
|
+
exaggeration: terrain.exaggeration,
|
|
11011
|
+
near,
|
|
11012
|
+
dx,
|
|
11013
|
+
dy,
|
|
11014
|
+
dz,
|
|
11015
|
+
worldSize
|
|
11016
|
+
};
|
|
11017
|
+
let tStart = 0;
|
|
11018
|
+
let tEnd = 1;
|
|
11019
|
+
if (dz === 0) {
|
|
11020
|
+
if (near[2] > index.maxElevation || near[2] < index.minElevation) return null;
|
|
11021
|
+
} else {
|
|
11022
|
+
const tHigh = (index.maxElevation - near[2]) / dz;
|
|
11023
|
+
const tLow = (index.minElevation - near[2]) / dz;
|
|
11024
|
+
tStart = Math.max(tStart, Math.min(tHigh, tLow));
|
|
11025
|
+
tEnd = Math.min(tEnd, Math.max(tHigh, tLow));
|
|
11026
|
+
if (tStart > tEnd) return null;
|
|
11027
|
+
}
|
|
11028
|
+
const horizontalLength = Math.hypot(dx, dy);
|
|
11029
|
+
const samples = clamp(Math.ceil(horizontalLength * (tEnd - tStart) / TARGET_WORLD_STEP_PX), 1, MAX_SAMPLES);
|
|
11030
|
+
let previousT = 0;
|
|
11031
|
+
let aboveTerrain = !mercatorIsBelowTerrain(ray, 0);
|
|
11032
|
+
for (let i = 0; i <= samples; i++) {
|
|
11033
|
+
const t = tStart + (tEnd - tStart) * i / samples;
|
|
11034
|
+
if (!aboveTerrain) aboveTerrain = !mercatorIsBelowTerrain(ray, t);
|
|
11035
|
+
else if (mercatorIsBelowTerrain(ray, t)) {
|
|
11036
|
+
const { lo, hi } = bisect(ray, mercatorIsBelowTerrain, previousT, t, MERCATOR_BISECT_EPSILON_WORLD_PX / horizontalLength);
|
|
11037
|
+
const sampleLo = mercatorSampleAt(ray, lo);
|
|
11038
|
+
const sampleHi = mercatorSampleAt(ray, hi);
|
|
11039
|
+
const fLo = near[2] + lo * dz - sampleLo.elevation;
|
|
11040
|
+
const fHi = near[2] + hi * dz - sampleHi.elevation;
|
|
11041
|
+
const hit = sampleLo.covered && fLo > fHi ? clamp(lo + fLo * (hi - lo) / (fLo - fHi), lo, hi) : hi;
|
|
11042
|
+
return new MercatorCoordinate((near[0] + hit * dx) / worldSize, (near[1] + hit * dy) / worldSize, mercatorSampleAt(ray, hit).elevation);
|
|
11043
|
+
}
|
|
11044
|
+
previousT = t;
|
|
11045
|
+
}
|
|
11046
|
+
return null;
|
|
11047
|
+
}
|
|
10236
11048
|
/**
|
|
10237
|
-
*
|
|
10238
|
-
* given in meters relative to the plane at the center's elevation (not mercator units).
|
|
11049
|
+
* Returns the segment of the ray through the given screen pixel that lies inside the view frustum.
|
|
10239
11050
|
*/
|
|
10240
|
-
|
|
10241
|
-
const targetZ = z ? z : 0;
|
|
11051
|
+
getRaySegmentFromPixel(p) {
|
|
10242
11052
|
const coord0 = [
|
|
10243
11053
|
p.x,
|
|
10244
11054
|
p.y,
|
|
@@ -10255,14 +11065,29 @@ var MercatorTransform = class MercatorTransform {
|
|
|
10255
11065
|
transformMat4(coord1, coord1, this._pixelMatrixInverse);
|
|
10256
11066
|
const w0 = coord0[3];
|
|
10257
11067
|
const w1 = coord1[3];
|
|
10258
|
-
const
|
|
10259
|
-
|
|
10260
|
-
|
|
10261
|
-
|
|
10262
|
-
|
|
10263
|
-
|
|
10264
|
-
|
|
10265
|
-
|
|
11068
|
+
const elevation = this.elevation;
|
|
11069
|
+
return {
|
|
11070
|
+
near: [
|
|
11071
|
+
coord0[0] / w0,
|
|
11072
|
+
coord0[1] / w0,
|
|
11073
|
+
coord0[2] / w0 + elevation
|
|
11074
|
+
],
|
|
11075
|
+
far: [
|
|
11076
|
+
coord1[0] / w1,
|
|
11077
|
+
coord1[1] / w1,
|
|
11078
|
+
coord1[2] / w1 + elevation
|
|
11079
|
+
]
|
|
11080
|
+
};
|
|
11081
|
+
}
|
|
11082
|
+
/**
|
|
11083
|
+
* Intersects the ray through a screen point with the horizontal plane at `z`,
|
|
11084
|
+
* given in meters relative to the plane at the center's elevation (not mercator units).
|
|
11085
|
+
*/
|
|
11086
|
+
screenPointToMercatorCoordinateAtZ(p, z) {
|
|
11087
|
+
const targetZ = z ? z : 0;
|
|
11088
|
+
const { near, far } = this.getRaySegmentFromPixel(p);
|
|
11089
|
+
const t = near[2] === far[2] ? 0 : (targetZ + this.elevation - near[2]) / (far[2] - near[2]);
|
|
11090
|
+
return new MercatorCoordinate(interpolateFactory.number(near[0], far[0], t) / this.worldSize, interpolateFactory.number(near[1], far[1], t) / this.worldSize, targetZ);
|
|
10266
11091
|
}
|
|
10267
11092
|
/**
|
|
10268
11093
|
* Given a coordinate, return the screen point that corresponds to it
|
|
@@ -10286,7 +11111,7 @@ var MercatorTransform = class MercatorTransform {
|
|
|
10286
11111
|
return new LngLatBounds().extend(this.screenPointToLocation(new Point(0, top))).extend(this.screenPointToLocation(new Point(this._helper._width, top))).extend(this.screenPointToLocation(new Point(this._helper._width, this._helper._height))).extend(this.screenPointToLocation(new Point(0, this._helper._height)));
|
|
10287
11112
|
}
|
|
10288
11113
|
isPointOnMapSurface(p, terrain) {
|
|
10289
|
-
if (terrain) return
|
|
11114
|
+
if (terrain) return this.screenTerrainPointToMercatorCoordinate(p, terrain) != null;
|
|
10290
11115
|
return p.y > this.height / 2 - getMercatorHorizon(this);
|
|
10291
11116
|
}
|
|
10292
11117
|
calculatePosMatrix(tileID, aligned = false, useFloat32 = false) {
|
|
@@ -10523,14 +11348,14 @@ var MercatorTransform = class MercatorTransform {
|
|
|
10523
11348
|
getRayDirectionFromPixel(_p) {
|
|
10524
11349
|
throw new Error("Not implemented.");
|
|
10525
11350
|
}
|
|
10526
|
-
projectTileCoordinates(x, y, unwrappedTileID,
|
|
11351
|
+
projectTileCoordinates(x, y, unwrappedTileID, elevation) {
|
|
10527
11352
|
const matrix = this.calculatePosMatrix(unwrappedTileID);
|
|
10528
11353
|
let pos;
|
|
10529
|
-
if (
|
|
11354
|
+
if (elevation != null) {
|
|
10530
11355
|
pos = [
|
|
10531
11356
|
x,
|
|
10532
11357
|
y,
|
|
10533
|
-
|
|
11358
|
+
elevation,
|
|
10534
11359
|
1
|
|
10535
11360
|
];
|
|
10536
11361
|
transformMat4(pos, pos, matrix);
|
|
@@ -10584,6 +11409,12 @@ var MercatorTransform = class MercatorTransform {
|
|
|
10584
11409
|
return this.calculatePosMatrix(tileID);
|
|
10585
11410
|
}
|
|
10586
11411
|
};
|
|
11412
|
+
function mercatorSampleAt(ray, t) {
|
|
11413
|
+
return sampleAt(ray.index, ray.exaggeration, (ray.near[0] + t * ray.dx) / ray.worldSize, (ray.near[1] + t * ray.dy) / ray.worldSize);
|
|
11414
|
+
}
|
|
11415
|
+
function mercatorIsBelowTerrain(ray, t) {
|
|
11416
|
+
return isBelowTerrainSample(mercatorSampleAt(ray, t), ray.near[2] + t * ray.dz);
|
|
11417
|
+
}
|
|
10587
11418
|
//#endregion
|
|
10588
11419
|
//#region src/geo/projection/camera_helper.ts
|
|
10589
11420
|
/**
|
|
@@ -11234,6 +12065,36 @@ function interpolateLngLatForGlobe(start, deltaLng, deltaLat, t) {
|
|
|
11234
12065
|
return new LngLat(interpolatedLng, interpolatedLat);
|
|
11235
12066
|
}
|
|
11236
12067
|
}
|
|
12068
|
+
/**
|
|
12069
|
+
* Returns the two intersection points of the ray and a sphere centered at the origin,
|
|
12070
|
+
* or null if no intersection occurs.
|
|
12071
|
+
* The intersections are encoded as the parameter for parametric ray equation,
|
|
12072
|
+
* with `tMin` being the first intersection and `tMax` being the second.
|
|
12073
|
+
* The quadratic is solved as suggested in Ray Tracing Gems, chapter 7, since the
|
|
12074
|
+
* schoolbook approach leads to floating point precision issues:
|
|
12075
|
+
* https://www.realtimerendering.com/raytracinggems/rtg/index.html
|
|
12076
|
+
* @param origin - The ray origin.
|
|
12077
|
+
* @param direction - The normalized ray direction.
|
|
12078
|
+
* @param radius - The sphere radius, defaults to the unit sphere of the planet.
|
|
12079
|
+
*/
|
|
12080
|
+
function raySphereIntersection(origin, direction, radius = 1) {
|
|
12081
|
+
const originDotDirection = dot(origin, direction);
|
|
12082
|
+
const radiusSquared = radius * radius;
|
|
12083
|
+
const inner = createVec3f64();
|
|
12084
|
+
const scaledDir = createVec3f64();
|
|
12085
|
+
scale$2(scaledDir, direction, originDotDirection);
|
|
12086
|
+
sub(inner, origin, scaledDir);
|
|
12087
|
+
const discriminant = radiusSquared - dot(inner, inner);
|
|
12088
|
+
if (discriminant < 0) return null;
|
|
12089
|
+
const c = dot(origin, origin) - radiusSquared;
|
|
12090
|
+
const q = -originDotDirection + (originDotDirection < 0 ? 1 : -1) * Math.sqrt(discriminant);
|
|
12091
|
+
const t0 = c / q;
|
|
12092
|
+
const t1 = q;
|
|
12093
|
+
return {
|
|
12094
|
+
tMin: Math.min(t0, t1),
|
|
12095
|
+
tMax: Math.max(t0, t1)
|
|
12096
|
+
};
|
|
12097
|
+
}
|
|
11237
12098
|
//#endregion
|
|
11238
12099
|
//#region src/util/primitives/bounding_volume_cache.ts
|
|
11239
12100
|
var BoundingVolumeCache = class {
|
|
@@ -11669,6 +12530,10 @@ function findAxisMinMax(axis, points) {
|
|
|
11669
12530
|
}
|
|
11670
12531
|
//#endregion
|
|
11671
12532
|
//#region src/geo/projection/vertical_perspective_transform.ts
|
|
12533
|
+
const GLOBE_SAMPLES = 256;
|
|
12534
|
+
const GLOBE_BISECT_EPSILON_T = 1e-12;
|
|
12535
|
+
/** Latitudes outside the mercator range project past the world edge; the globe mesh still covers them. */
|
|
12536
|
+
const MAX_MERCATOR_Y = 1 - 1e-9;
|
|
11672
12537
|
var VerticalPerspectiveTransform = class VerticalPerspectiveTransform {
|
|
11673
12538
|
get pixelsToClipSpaceMatrix() {
|
|
11674
12539
|
return this._helper.pixelsToClipSpaceMatrix;
|
|
@@ -12008,10 +12873,10 @@ var VerticalPerspectiveTransform = class VerticalPerspectiveTransform {
|
|
|
12008
12873
|
const angular = mercatorCoordinatesToAngularCoordinatesRadians(mercator.x, mercator.y);
|
|
12009
12874
|
return this.getCircleRadiusCorrection() / Math.cos(angular[1]);
|
|
12010
12875
|
}
|
|
12011
|
-
projectTileCoordinates(x, y, unwrappedTileID,
|
|
12876
|
+
projectTileCoordinates(x, y, unwrappedTileID, elevation) {
|
|
12012
12877
|
const canonical = unwrappedTileID.canonical;
|
|
12013
12878
|
const spherePos = projectTileCoordinatesToSphere(x, y, canonical.x, canonical.y, canonical.z);
|
|
12014
|
-
const vectorMultiplier = 1 + (
|
|
12879
|
+
const vectorMultiplier = 1 + (elevation ?? 0) / earthRadius;
|
|
12015
12880
|
const pos = [
|
|
12016
12881
|
spherePos[0] * vectorMultiplier,
|
|
12017
12882
|
spherePos[1] * vectorMultiplier,
|
|
@@ -12271,11 +13136,41 @@ var VerticalPerspectiveTransform = class VerticalPerspectiveTransform {
|
|
|
12271
13136
|
}
|
|
12272
13137
|
screenPointToMercatorCoordinate(p, terrain) {
|
|
12273
13138
|
if (terrain) {
|
|
12274
|
-
const coordinate =
|
|
13139
|
+
const coordinate = this.screenTerrainPointToMercatorCoordinate(p, terrain);
|
|
12275
13140
|
if (coordinate) return coordinate;
|
|
12276
13141
|
}
|
|
12277
13142
|
return MercatorCoordinate.fromLngLat(this.unprojectScreenPoint(p));
|
|
12278
13143
|
}
|
|
13144
|
+
/** {@inheritDoc ITransform.screenTerrainPointToMercatorCoordinate} */
|
|
13145
|
+
screenTerrainPointToMercatorCoordinate(p, terrain) {
|
|
13146
|
+
const index = terrain.getCoverageIndex();
|
|
13147
|
+
if (!index) return null;
|
|
13148
|
+
const origin = this.cameraPosition;
|
|
13149
|
+
const direction = this.getRayDirectionFromPixel(p);
|
|
13150
|
+
const outer = raySphereIntersection(origin, direction, 1 + index.maxElevation / earthRadius);
|
|
13151
|
+
if (!outer) return null;
|
|
13152
|
+
const inner = raySphereIntersection(origin, direction, 1 + index.minElevation / earthRadius);
|
|
13153
|
+
const tStart = Math.max(outer.tMin, 0);
|
|
13154
|
+
const tEnd = inner ? inner.tMin : outer.tMax;
|
|
13155
|
+
if (tEnd <= tStart) return null;
|
|
13156
|
+
const ray = {
|
|
13157
|
+
index,
|
|
13158
|
+
exaggeration: terrain.exaggeration,
|
|
13159
|
+
origin,
|
|
13160
|
+
direction
|
|
13161
|
+
};
|
|
13162
|
+
let previousT = 0;
|
|
13163
|
+
for (let i = 0; i <= GLOBE_SAMPLES; i++) {
|
|
13164
|
+
const t = tStart + (tEnd - tStart) * i / GLOBE_SAMPLES;
|
|
13165
|
+
if (globeIsBelowTerrain(ray, t)) {
|
|
13166
|
+
const { hi } = bisect(ray, globeIsBelowTerrain, previousT, t, GLOBE_BISECT_EPSILON_T);
|
|
13167
|
+
const { sample, mercator } = globeSampleAt(ray, hi);
|
|
13168
|
+
return new MercatorCoordinate(mercator.x, mercator.y, sample.elevation);
|
|
13169
|
+
}
|
|
13170
|
+
previousT = t;
|
|
13171
|
+
}
|
|
13172
|
+
return null;
|
|
13173
|
+
}
|
|
12279
13174
|
screenPointToLocation(p, terrain) {
|
|
12280
13175
|
return this.screenPointToMercatorCoordinate(p, terrain)?.toLngLat();
|
|
12281
13176
|
}
|
|
@@ -12284,8 +13179,7 @@ var VerticalPerspectiveTransform = class VerticalPerspectiveTransform {
|
|
|
12284
13179
|
}
|
|
12285
13180
|
isPointOnMapSurface(p, _terrain) {
|
|
12286
13181
|
const rayOrigin = this._cameraPosition;
|
|
12287
|
-
|
|
12288
|
-
return !!this.rayPlanetIntersection(rayOrigin, rayDirection);
|
|
13182
|
+
return !!raySphereIntersection(rayOrigin, this.getRayDirectionFromPixel(p));
|
|
12289
13183
|
}
|
|
12290
13184
|
/**
|
|
12291
13185
|
* Computes normalized direction of a ray from the camera to the given screen pixel.
|
|
@@ -12330,33 +13224,6 @@ var VerticalPerspectiveTransform = class VerticalPerspectiveTransform {
|
|
|
12330
13224
|
return projected[0] > -1 && projected[0] < 1 && projected[1] > -1 && projected[1] < 1 && projected[2] > -1 && projected[2] < 1;
|
|
12331
13225
|
}
|
|
12332
13226
|
/**
|
|
12333
|
-
* Returns the two intersection points of the ray and the planet's sphere,
|
|
12334
|
-
* or null if no intersection occurs.
|
|
12335
|
-
* The intersections are encoded as the parameter for parametric ray equation,
|
|
12336
|
-
* with `tMin` being the first intersection and `tMax` being the second.
|
|
12337
|
-
* Eg. the nearer intersection point can then be computed as `origin + direction * tMin`.
|
|
12338
|
-
* @param origin - The ray origin.
|
|
12339
|
-
* @param direction - The normalized ray direction.
|
|
12340
|
-
*/
|
|
12341
|
-
rayPlanetIntersection(origin, direction) {
|
|
12342
|
-
const originDotDirection = dot(origin, direction);
|
|
12343
|
-
const planetRadiusSquared = 1;
|
|
12344
|
-
const inner = createVec3f64();
|
|
12345
|
-
const scaledDir = createVec3f64();
|
|
12346
|
-
scale$2(scaledDir, direction, originDotDirection);
|
|
12347
|
-
sub(inner, origin, scaledDir);
|
|
12348
|
-
const discriminant = planetRadiusSquared - dot(inner, inner);
|
|
12349
|
-
if (discriminant < 0) return null;
|
|
12350
|
-
const c = dot(origin, origin) - planetRadiusSquared;
|
|
12351
|
-
const q = -originDotDirection + (originDotDirection < 0 ? 1 : -1) * Math.sqrt(discriminant);
|
|
12352
|
-
const t0 = c / q;
|
|
12353
|
-
const t1 = q;
|
|
12354
|
-
return {
|
|
12355
|
-
tMin: Math.min(t0, t1),
|
|
12356
|
-
tMax: Math.max(t0, t1)
|
|
12357
|
-
};
|
|
12358
|
-
}
|
|
12359
|
-
/**
|
|
12360
13227
|
* @internal
|
|
12361
13228
|
* Returns a {@link LngLat} representing geographical coordinates that correspond to the specified pixel coordinates.
|
|
12362
13229
|
* Note: if the point does not lie on the globe, returns a location on the visible globe horizon (edge) that is
|
|
@@ -12367,7 +13234,7 @@ var VerticalPerspectiveTransform = class VerticalPerspectiveTransform {
|
|
|
12367
13234
|
unprojectScreenPoint(p) {
|
|
12368
13235
|
const rayOrigin = this._cameraPosition;
|
|
12369
13236
|
const rayDirection = this.getRayDirectionFromPixel(p);
|
|
12370
|
-
const intersection =
|
|
13237
|
+
const intersection = raySphereIntersection(rayOrigin, rayDirection);
|
|
12371
13238
|
if (intersection) {
|
|
12372
13239
|
const intersectionPoint = createVec3f64();
|
|
12373
13240
|
add(intersectionPoint, rayOrigin, [
|
|
@@ -12421,6 +13288,30 @@ var VerticalPerspectiveTransform = class VerticalPerspectiveTransform {
|
|
|
12421
13288
|
}
|
|
12422
13289
|
getFastPathSimpleProjectionMatrix(_tileID) {}
|
|
12423
13290
|
};
|
|
13291
|
+
function globeSampleAt(ray, t) {
|
|
13292
|
+
const position = createVec3f64();
|
|
13293
|
+
scaleAndAdd(position, ray.origin, ray.direction, t);
|
|
13294
|
+
const radius = length$1(position);
|
|
13295
|
+
const surface = createVec3f64();
|
|
13296
|
+
scale$2(surface, position, 1 / radius);
|
|
13297
|
+
const lngLat = sphereSurfacePointToCoordinates(surface);
|
|
13298
|
+
const projected = MercatorCoordinate.fromLngLat(lngLat);
|
|
13299
|
+
const mercator = new MercatorCoordinate(projected.x, clamp(projected.y, 0, MAX_MERCATOR_Y));
|
|
13300
|
+
const sample = sampleAt(ray.index, ray.exaggeration, mercator.x, mercator.y);
|
|
13301
|
+
const elevation = Math.abs(lngLat.lat) > 85.051129 ? 0 : sample.elevation;
|
|
13302
|
+
return {
|
|
13303
|
+
sample: {
|
|
13304
|
+
covered: sample.covered,
|
|
13305
|
+
elevation
|
|
13306
|
+
},
|
|
13307
|
+
radius,
|
|
13308
|
+
mercator
|
|
13309
|
+
};
|
|
13310
|
+
}
|
|
13311
|
+
function globeIsBelowTerrain(ray, t) {
|
|
13312
|
+
const { sample, radius } = globeSampleAt(ray, t);
|
|
13313
|
+
return isBelowTerrainSample(sample, (radius - 1) * earthRadius);
|
|
13314
|
+
}
|
|
12424
13315
|
//#endregion
|
|
12425
13316
|
//#region src/geo/projection/globe_transform.ts
|
|
12426
13317
|
/**
|
|
@@ -12703,8 +13594,8 @@ var GlobeTransform = class GlobeTransform {
|
|
|
12703
13594
|
const verticalCorrection = this._verticalPerspectiveTransform.getPitchedTextCorrection(textAnchorX, textAnchorY, tileID);
|
|
12704
13595
|
return lerp(mercatorCorrection, verticalCorrection, this._globeness);
|
|
12705
13596
|
}
|
|
12706
|
-
projectTileCoordinates(x, y, unwrappedTileID,
|
|
12707
|
-
return this.currentTransform.projectTileCoordinates(x, y, unwrappedTileID,
|
|
13597
|
+
projectTileCoordinates(x, y, unwrappedTileID, elevation) {
|
|
13598
|
+
return this.currentTransform.projectTileCoordinates(x, y, unwrappedTileID, elevation);
|
|
12708
13599
|
}
|
|
12709
13600
|
_calcMatrices() {
|
|
12710
13601
|
if (!this._helper._width || !this._helper._height) return;
|
|
@@ -12777,6 +13668,10 @@ var GlobeTransform = class GlobeTransform {
|
|
|
12777
13668
|
screenPointToMercatorCoordinate(p, terrain) {
|
|
12778
13669
|
return this.currentTransform.screenPointToMercatorCoordinate(p, terrain);
|
|
12779
13670
|
}
|
|
13671
|
+
/** {@inheritDoc ITransform.screenTerrainPointToMercatorCoordinate} */
|
|
13672
|
+
screenTerrainPointToMercatorCoordinate(p, terrain) {
|
|
13673
|
+
return this.currentTransform.screenTerrainPointToMercatorCoordinate(p, terrain);
|
|
13674
|
+
}
|
|
12780
13675
|
screenPointToLocation(p, terrain) {
|
|
12781
13676
|
return this.currentTransform.screenPointToLocation(p, terrain);
|
|
12782
13677
|
}
|
|
@@ -14556,11 +15451,6 @@ const terrainUniforms = (context, locations) => ({
|
|
|
14556
15451
|
"u_is_globe_mode": new Uniform1f(context, locations.u_is_globe_mode)
|
|
14557
15452
|
});
|
|
14558
15453
|
const terrainDepthUniforms = (context, locations) => ({ "u_ele_delta": new Uniform1f(context, locations.u_ele_delta) });
|
|
14559
|
-
const terrainCoordsUniforms = (context, locations) => ({
|
|
14560
|
-
"u_texture": new Uniform1i(context, locations.u_texture),
|
|
14561
|
-
"u_terrain_coords_id": new Uniform1f(context, locations.u_terrain_coords_id),
|
|
14562
|
-
"u_ele_delta": new Uniform1f(context, locations.u_ele_delta)
|
|
14563
|
-
});
|
|
14564
15454
|
const terrainUniformValues = (eleDelta, fogMatrix, sky, pitch, isGlobeMode) => ({
|
|
14565
15455
|
"u_texture": 0,
|
|
14566
15456
|
"u_ele_delta": eleDelta,
|
|
@@ -14573,11 +15463,6 @@ const terrainUniformValues = (eleDelta, fogMatrix, sky, pitch, isGlobeMode) => (
|
|
|
14573
15463
|
"u_is_globe_mode": isGlobeMode ? 1 : 0
|
|
14574
15464
|
});
|
|
14575
15465
|
const terrainDepthUniformValues = (eleDelta) => ({ "u_ele_delta": eleDelta });
|
|
14576
|
-
const terrainCoordsUniformValues = (coordsId, eleDelta) => ({
|
|
14577
|
-
"u_terrain_coords_id": coordsId / 255,
|
|
14578
|
-
"u_texture": 0,
|
|
14579
|
-
"u_ele_delta": eleDelta
|
|
14580
|
-
});
|
|
14581
15466
|
//#endregion
|
|
14582
15467
|
//#region src/webgl/program/projection_program.ts
|
|
14583
15468
|
const projectionUniforms = (context, locations) => ({
|
|
@@ -15207,7 +16092,8 @@ const symbolIconUniforms = (context, locations) => ({
|
|
|
15207
16092
|
"u_texture": new Uniform1i(context, locations.u_texture),
|
|
15208
16093
|
"u_translation": new Uniform2f(context, locations.u_translation),
|
|
15209
16094
|
"u_pitched_scale": new Uniform1f(context, locations.u_pitched_scale),
|
|
15210
|
-
"u_is_offset": new Uniform1i(context, locations.u_is_offset)
|
|
16095
|
+
"u_is_offset": new Uniform1i(context, locations.u_is_offset),
|
|
16096
|
+
"u_height_anchor_ground": new Uniform1i(context, locations.u_height_anchor_ground)
|
|
15211
16097
|
});
|
|
15212
16098
|
const symbolSDFUniforms = (context, locations) => ({
|
|
15213
16099
|
"u_is_size_zoom_constant": new Uniform1i(context, locations.u_is_size_zoom_constant),
|
|
@@ -15233,7 +16119,8 @@ const symbolSDFUniforms = (context, locations) => ({
|
|
|
15233
16119
|
"u_is_plain": new Uniform1i(context, locations.u_is_plain),
|
|
15234
16120
|
"u_translation": new Uniform2f(context, locations.u_translation),
|
|
15235
16121
|
"u_pitched_scale": new Uniform1f(context, locations.u_pitched_scale),
|
|
15236
|
-
"u_is_offset": new Uniform1i(context, locations.u_is_offset)
|
|
16122
|
+
"u_is_offset": new Uniform1i(context, locations.u_is_offset),
|
|
16123
|
+
"u_height_anchor_ground": new Uniform1i(context, locations.u_height_anchor_ground)
|
|
15237
16124
|
});
|
|
15238
16125
|
const symbolTextAndIconUniforms = (context, locations) => ({
|
|
15239
16126
|
"u_is_size_zoom_constant": new Uniform1i(context, locations.u_is_size_zoom_constant),
|
|
@@ -15260,9 +16147,10 @@ const symbolTextAndIconUniforms = (context, locations) => ({
|
|
|
15260
16147
|
"u_is_halo": new Uniform1i(context, locations.u_is_halo),
|
|
15261
16148
|
"u_translation": new Uniform2f(context, locations.u_translation),
|
|
15262
16149
|
"u_pitched_scale": new Uniform1f(context, locations.u_pitched_scale),
|
|
15263
|
-
"u_is_offset": new Uniform1i(context, locations.u_is_offset)
|
|
16150
|
+
"u_is_offset": new Uniform1i(context, locations.u_is_offset),
|
|
16151
|
+
"u_height_anchor_ground": new Uniform1i(context, locations.u_height_anchor_ground)
|
|
15264
16152
|
});
|
|
15265
|
-
const symbolIconUniformValues = (functionType, size, rotateInShader, pitchWithMap, isAlongLine, isVariableAnchor, painter, labelPlaneMatrix, glCoordMatrix, translation, isText, texSize, pitchedScale, isOffset) => {
|
|
16153
|
+
const symbolIconUniformValues = (functionType, size, rotateInShader, pitchWithMap, isAlongLine, isVariableAnchor, painter, labelPlaneMatrix, glCoordMatrix, translation, isText, texSize, pitchedScale, isOffset, heightAnchorGround) => {
|
|
15266
16154
|
const transform = painter.transform;
|
|
15267
16155
|
return {
|
|
15268
16156
|
"u_is_size_zoom_constant": +(functionType === "constant" || functionType === "source"),
|
|
@@ -15284,20 +16172,21 @@ const symbolIconUniformValues = (functionType, size, rotateInShader, pitchWithMa
|
|
|
15284
16172
|
"u_texture": 0,
|
|
15285
16173
|
"u_translation": translation,
|
|
15286
16174
|
"u_pitched_scale": pitchedScale,
|
|
15287
|
-
"u_is_offset": isOffset
|
|
16175
|
+
"u_is_offset": isOffset,
|
|
16176
|
+
"u_height_anchor_ground": +heightAnchorGround
|
|
15288
16177
|
};
|
|
15289
16178
|
};
|
|
15290
|
-
const symbolSDFUniformValues = (functionType, size, rotateInShader, pitchWithMap, isAlongLine, isVariableAnchor, painter, labelPlaneMatrix, glCoordMatrix, translation, isText, texSize, isHalo, pitchedScale, isOffset) => {
|
|
16179
|
+
const symbolSDFUniformValues = (functionType, size, rotateInShader, pitchWithMap, isAlongLine, isVariableAnchor, painter, labelPlaneMatrix, glCoordMatrix, translation, isText, texSize, isHalo, pitchedScale, isOffset, heightAnchorGround) => {
|
|
15291
16180
|
const transform = painter.transform;
|
|
15292
|
-
return extend(symbolIconUniformValues(functionType, size, rotateInShader, pitchWithMap, isAlongLine, isVariableAnchor, painter, labelPlaneMatrix, glCoordMatrix, translation, isText, texSize, pitchedScale, isOffset), {
|
|
16181
|
+
return extend(symbolIconUniformValues(functionType, size, rotateInShader, pitchWithMap, isAlongLine, isVariableAnchor, painter, labelPlaneMatrix, glCoordMatrix, translation, isText, texSize, pitchedScale, isOffset, heightAnchorGround), {
|
|
15293
16182
|
"u_gamma_scale": pitchWithMap ? Math.cos(transform.pitch * Math.PI / 180) * transform.cameraToCenterDistance : 1,
|
|
15294
16183
|
"u_device_pixel_ratio": painter.pixelRatio,
|
|
15295
16184
|
"u_is_halo": isHalo ? 1 : 0,
|
|
15296
16185
|
"u_is_plain": 1
|
|
15297
16186
|
});
|
|
15298
16187
|
};
|
|
15299
|
-
const symbolTextAndIconUniformValues = (functionType, size, rotateInShader, pitchWithMap, isAlongLine, isVariableAnchor, painter, labelPlaneMatrix, glCoordMatrix, translation, texSizeSDF, texSizeIcon, pitchedScale, isOffset) => {
|
|
15300
|
-
return extend(symbolSDFUniformValues(functionType, size, rotateInShader, pitchWithMap, isAlongLine, isVariableAnchor, painter, labelPlaneMatrix, glCoordMatrix, translation, true, texSizeSDF, true, pitchedScale, isOffset), {
|
|
16188
|
+
const symbolTextAndIconUniformValues = (functionType, size, rotateInShader, pitchWithMap, isAlongLine, isVariableAnchor, painter, labelPlaneMatrix, glCoordMatrix, translation, texSizeSDF, texSizeIcon, pitchedScale, isOffset, heightAnchorGround) => {
|
|
16189
|
+
return extend(symbolSDFUniformValues(functionType, size, rotateInShader, pitchWithMap, isAlongLine, isVariableAnchor, painter, labelPlaneMatrix, glCoordMatrix, translation, true, texSizeSDF, true, pitchedScale, isOffset, heightAnchorGround), {
|
|
15301
16190
|
"u_texsize_icon": texSizeIcon,
|
|
15302
16191
|
"u_texture_icon": 1
|
|
15303
16192
|
});
|
|
@@ -15409,7 +16298,6 @@ const programUniforms = {
|
|
|
15409
16298
|
backgroundPattern: backgroundPatternUniforms,
|
|
15410
16299
|
terrain: terrainUniforms,
|
|
15411
16300
|
terrainDepth: terrainDepthUniforms,
|
|
15412
|
-
terrainCoords: terrainCoordsUniforms,
|
|
15413
16301
|
atmosphere: atmosphereUniforms,
|
|
15414
16302
|
sky: skyUniforms
|
|
15415
16303
|
};
|
|
@@ -16412,8 +17300,8 @@ function updateVariableAnchors(coords, painter, layer, tileManager, rotationAlig
|
|
|
16412
17300
|
const updateTextFitIcon = layer.layout.get("icon-text-fit") !== "none" && bucket.hasIconData();
|
|
16413
17301
|
if (size) {
|
|
16414
17302
|
const tileScale = Math.pow(2, transform.zoom - tile.tileID.overscaledZ);
|
|
16415
|
-
const getElevation = terrain ? (x, y) => terrain.getElevation(coord, x, y) :
|
|
16416
|
-
updateVariableAnchorsForBucket(bucket, rotateWithMap, pitchWithMap, variableOffsets, transform, pitchedLabelPlaneMatrix, tileScale, size, updateTextFitIcon, translatePosition(transform, tile, translate, translateAnchor), coord.toUnwrapped(), getElevation);
|
|
17303
|
+
const getElevation = terrain ? (x, y) => terrain.getElevation(coord, x, y) : void 0;
|
|
17304
|
+
updateVariableAnchorsForBucket(bucket, rotateWithMap, pitchWithMap, variableOffsets, transform, pitchedLabelPlaneMatrix, tileScale, size, updateTextFitIcon, translatePosition(transform, tile, translate, translateAnchor), coord.toUnwrapped(), getElevation, layer.layout.get("symbol-height-anchor") === "ground");
|
|
16417
17305
|
}
|
|
16418
17306
|
}
|
|
16419
17307
|
}
|
|
@@ -16423,14 +17311,14 @@ function getShiftedAnchor(projectedAnchorPoint, projectionContext, rotateWithMap
|
|
|
16423
17311
|
let adjustedShift = shift.mult(pitchedTextShiftCorrection);
|
|
16424
17312
|
if (!rotateWithMap) adjustedShift = adjustedShift.rotate(-transformAngle);
|
|
16425
17313
|
const tileAnchorShifted = translatedAnchor.add(adjustedShift);
|
|
16426
|
-
return projectWithMatrix(tileAnchorShifted.x, tileAnchorShifted.y, projectionContext.pitchedLabelPlaneMatrix, projectionContext.
|
|
17314
|
+
return projectWithMatrix(tileAnchorShifted.x, tileAnchorShifted.y, projectionContext.pitchedLabelPlaneMatrix, elevationAt(projectionContext, tileAnchorShifted.x, tileAnchorShifted.y)).point;
|
|
16427
17315
|
} else if (rotateWithMap) {
|
|
16428
17316
|
const east = projectTileCoordinatesToLabelPlane(projectionContext.tileAnchorPoint.x + 1, projectionContext.tileAnchorPoint.y, projectionContext).point.sub(projectedAnchorPoint);
|
|
16429
17317
|
const angle = Math.atan(east.y / east.x) + (east.x < 0 ? Math.PI : 0);
|
|
16430
17318
|
return projectedAnchorPoint.add(shift.rotate(angle));
|
|
16431
17319
|
} else return projectedAnchorPoint.add(shift);
|
|
16432
17320
|
}
|
|
16433
|
-
function updateVariableAnchorsForBucket(bucket, rotateWithMap, pitchWithMap, variableOffsets, transform, pitchedLabelPlaneMatrix, tileScale, size, updateTextFitIcon, translation, unwrappedTileID, getElevation) {
|
|
17321
|
+
function updateVariableAnchorsForBucket(bucket, rotateWithMap, pitchWithMap, variableOffsets, transform, pitchedLabelPlaneMatrix, tileScale, size, updateTextFitIcon, translation, unwrappedTileID, getElevation, heightAnchorGround) {
|
|
16434
17322
|
const placedSymbols = bucket.text.placedSymbolArray;
|
|
16435
17323
|
const dynamicTextLayoutVertexArray = bucket.text.dynamicLayoutVertexArray;
|
|
16436
17324
|
const dynamicIconLayoutVertexArray = bucket.icon.dynamicLayoutVertexArray;
|
|
@@ -16445,6 +17333,8 @@ function updateVariableAnchorsForBucket(bucket, rotateWithMap, pitchWithMap, var
|
|
|
16445
17333
|
const tileAnchor = new Point(symbol.anchorX, symbol.anchorY);
|
|
16446
17334
|
const projectionContext = {
|
|
16447
17335
|
getElevation,
|
|
17336
|
+
heightOffset: symbol.heightOffset,
|
|
17337
|
+
heightAnchorGround,
|
|
16448
17338
|
width: transform.width,
|
|
16449
17339
|
height: transform.height,
|
|
16450
17340
|
pitchedLabelPlaneMatrix,
|
|
@@ -16554,10 +17444,11 @@ function drawLayerSymbols(painter, tileManager, layer, coords, isText, translate
|
|
|
16554
17444
|
const hasVariableAnchors = hasVariablePlacement && bucket.hasTextData();
|
|
16555
17445
|
const updateTextFitIcon = layer.layout.get("icon-text-fit") !== "none" && hasVariableAnchors && bucket.hasIconData();
|
|
16556
17446
|
const isOffset = layer._unevaluatedLayout.hasValue("icon-offset");
|
|
17447
|
+
const heightAnchorGround = layer.layout.get("symbol-height-anchor") === "ground";
|
|
16557
17448
|
if (alongLine) {
|
|
16558
17449
|
const pitchedLabelPlaneMatrixInverse = create$1();
|
|
16559
17450
|
fastInvertTransformMat4(pitchedLabelPlaneMatrixInverse, pitchedLabelPlaneMatrix);
|
|
16560
|
-
const getElevation = painter.style.map.terrain ? (x, y) => painter.style.map.terrain.getElevation(coord, x, y) :
|
|
17451
|
+
const getElevation = painter.style.map.terrain ? (x, y) => painter.style.map.terrain.getElevation(coord, x, y) : void 0;
|
|
16561
17452
|
updateLineLabels(bucket, painter, isText, pitchedLabelPlaneMatrix, pitchedLabelPlaneMatrixInverse, pitchWithMap, keepUpright, layer.layout.get("text-rotation-alignment") === "map", coord.toUnwrapped(), transform.width, transform.height, translation, getElevation);
|
|
16562
17453
|
}
|
|
16563
17454
|
const shaderVariableAnchor = isText && hasVariablePlacement || updateTextFitIcon;
|
|
@@ -16566,9 +17457,9 @@ function drawLayerSymbols(painter, tileManager, layer, coords, isText, translate
|
|
|
16566
17457
|
const hasHalo = isSDF && layer.paint.get(isText ? "text-halo-width" : "icon-halo-width").constantOr(1) !== 0;
|
|
16567
17458
|
let uniformValues;
|
|
16568
17459
|
if (isSDF) {
|
|
16569
|
-
if (!bucket.iconsInText) uniformValues = symbolSDFUniformValues(sizeData.kind, size, rotateInShader, pitchWithMap, alongLine, shaderVariableAnchor, painter, uLabelPlaneMatrix, glCoordMatrixForShader, translation, isText, texSize, hasHalo, pitchedTextRescaling, isOffset);
|
|
16570
|
-
else uniformValues = symbolTextAndIconUniformValues(sizeData.kind, size, rotateInShader, pitchWithMap, alongLine, shaderVariableAnchor, painter, uLabelPlaneMatrix, glCoordMatrixForShader, translation, texSize, texSizeIcon, pitchedTextRescaling, isOffset);
|
|
16571
|
-
} else uniformValues = symbolIconUniformValues(sizeData.kind, size, rotateInShader, pitchWithMap, alongLine, shaderVariableAnchor, painter, uLabelPlaneMatrix, glCoordMatrixForShader, translation, isText, texSize, pitchedTextRescaling, isOffset);
|
|
17460
|
+
if (!bucket.iconsInText) uniformValues = symbolSDFUniformValues(sizeData.kind, size, rotateInShader, pitchWithMap, alongLine, shaderVariableAnchor, painter, uLabelPlaneMatrix, glCoordMatrixForShader, translation, isText, texSize, hasHalo, pitchedTextRescaling, isOffset, heightAnchorGround);
|
|
17461
|
+
else uniformValues = symbolTextAndIconUniformValues(sizeData.kind, size, rotateInShader, pitchWithMap, alongLine, shaderVariableAnchor, painter, uLabelPlaneMatrix, glCoordMatrixForShader, translation, texSize, texSizeIcon, pitchedTextRescaling, isOffset, heightAnchorGround);
|
|
17462
|
+
} else uniformValues = symbolIconUniformValues(sizeData.kind, size, rotateInShader, pitchWithMap, alongLine, shaderVariableAnchor, painter, uLabelPlaneMatrix, glCoordMatrixForShader, translation, isText, texSize, pitchedTextRescaling, isOffset, heightAnchorGround);
|
|
16572
17463
|
const state = {
|
|
16573
17464
|
program,
|
|
16574
17465
|
buffers,
|
|
@@ -17380,18 +18271,18 @@ function renderColorRelief(painter, tileManager, layer, coords, stencilModes, de
|
|
|
17380
18271
|
}
|
|
17381
18272
|
if (!dem?.data) continue;
|
|
17382
18273
|
const textureStride = dem.stride;
|
|
17383
|
-
const pixelData = dem.getPixels();
|
|
17384
18274
|
context.activeTexture.set(gl.TEXTURE0);
|
|
17385
|
-
|
|
17386
|
-
|
|
17387
|
-
|
|
17388
|
-
|
|
17389
|
-
|
|
17390
|
-
|
|
17391
|
-
|
|
17392
|
-
tile.demTexture
|
|
17393
|
-
tile.
|
|
18275
|
+
if (!tile.demTexture || tile.needsColorReliefPrepare) {
|
|
18276
|
+
context.pixelStoreUnpackPremultiplyAlpha.set(false);
|
|
18277
|
+
tile.demTexture ||= painter.getTileTexture(textureStride) ?? new Texture(context, {
|
|
18278
|
+
width: textureStride,
|
|
18279
|
+
height: textureStride,
|
|
18280
|
+
data: null
|
|
18281
|
+
}, gl.RGBA);
|
|
18282
|
+
tile.demTexture.update(dem.getPixels(), { premultiply: false });
|
|
18283
|
+
tile.needsColorReliefPrepare = false;
|
|
17394
18284
|
}
|
|
18285
|
+
tile.demTexture.bind(textureFilter, gl.CLAMP_TO_EDGE);
|
|
17395
18286
|
const mesh = projection.getMeshFromTileID(context, coord.canonical, useBorder, true, "raster");
|
|
17396
18287
|
const terrainData = painter.getTerrainDataForTile(coord, isRenderingToTexture);
|
|
17397
18288
|
const projectionData = transform.getProjectionData({
|
|
@@ -17746,7 +18637,7 @@ function drawDepth(painter, terrain) {
|
|
|
17746
18637
|
const depthMode = new DepthMode(gl.LEQUAL, DepthMode.ReadWrite, [0, 1]);
|
|
17747
18638
|
const tiles = terrain.tileManager.getRenderableTiles();
|
|
17748
18639
|
const program = painter.useProgram("terrainDepth");
|
|
17749
|
-
context.bindFramebuffer.set(terrain.getFramebuffer(
|
|
18640
|
+
context.bindFramebuffer.set(terrain.getFramebuffer().framebuffer);
|
|
17750
18641
|
context.viewport.set([
|
|
17751
18642
|
0,
|
|
17752
18643
|
0,
|
|
@@ -17754,7 +18645,7 @@ function drawDepth(painter, terrain) {
|
|
|
17754
18645
|
painter.height / devicePixelRatio
|
|
17755
18646
|
]);
|
|
17756
18647
|
context.clear({
|
|
17757
|
-
color: Color.
|
|
18648
|
+
color: Color.white,
|
|
17758
18649
|
depth: 1
|
|
17759
18650
|
});
|
|
17760
18651
|
for (const tile of tiles) {
|
|
@@ -17776,54 +18667,6 @@ function drawDepth(painter, terrain) {
|
|
|
17776
18667
|
painter.height
|
|
17777
18668
|
]);
|
|
17778
18669
|
}
|
|
17779
|
-
/**
|
|
17780
|
-
* Redraw the Coords Framebuffers
|
|
17781
|
-
* @param painter - the painter
|
|
17782
|
-
* @param terrain - the terrain
|
|
17783
|
-
*/
|
|
17784
|
-
function drawCoords(painter, terrain) {
|
|
17785
|
-
const context = painter.context;
|
|
17786
|
-
const gl = context.gl;
|
|
17787
|
-
const tr = painter.transform;
|
|
17788
|
-
const colorMode = ColorMode.unblended;
|
|
17789
|
-
const depthMode = new DepthMode(gl.LEQUAL, DepthMode.ReadWrite, [0, 1]);
|
|
17790
|
-
const coords = terrain.getCoordsTexture();
|
|
17791
|
-
const tiles = terrain.tileManager.getRenderableTiles();
|
|
17792
|
-
const program = painter.useProgram("terrainCoords");
|
|
17793
|
-
context.bindFramebuffer.set(terrain.getFramebuffer("coords").framebuffer);
|
|
17794
|
-
context.viewport.set([
|
|
17795
|
-
0,
|
|
17796
|
-
0,
|
|
17797
|
-
painter.width / devicePixelRatio,
|
|
17798
|
-
painter.height / devicePixelRatio
|
|
17799
|
-
]);
|
|
17800
|
-
context.clear({
|
|
17801
|
-
color: Color.transparent,
|
|
17802
|
-
depth: 1
|
|
17803
|
-
});
|
|
17804
|
-
terrain.coordsIndex = [];
|
|
17805
|
-
for (const tile of tiles) {
|
|
17806
|
-
const mesh = terrain.getTerrainMesh(tile.tileID);
|
|
17807
|
-
const terrainData = terrain.getTerrainData(tile.tileID);
|
|
17808
|
-
context.activeTexture.set(gl.TEXTURE0);
|
|
17809
|
-
gl.bindTexture(gl.TEXTURE_2D, coords.texture);
|
|
17810
|
-
const uniformValues = terrainCoordsUniformValues(255 - terrain.coordsIndex.length, terrain.getSkirtLength(tr.zoom));
|
|
17811
|
-
const projectionData = tr.getProjectionData({
|
|
17812
|
-
overscaledTileID: tile.tileID,
|
|
17813
|
-
applyTerrainMatrix: false,
|
|
17814
|
-
applyGlobeMatrix: true
|
|
17815
|
-
});
|
|
17816
|
-
program.draw(context, gl.TRIANGLES, depthMode, StencilMode.disabled, colorMode, CullFaceMode.backCCW, uniformValues, terrainData, projectionData, "terrain", mesh.vertexBuffer, mesh.indexBuffer, mesh.segments);
|
|
17817
|
-
terrain.coordsIndex.push(tile.tileID.key);
|
|
17818
|
-
}
|
|
17819
|
-
context.bindFramebuffer.set(null);
|
|
17820
|
-
context.viewport.set([
|
|
17821
|
-
0,
|
|
17822
|
-
0,
|
|
17823
|
-
painter.width,
|
|
17824
|
-
painter.height
|
|
17825
|
-
]);
|
|
17826
|
-
}
|
|
17827
18670
|
function drawTerrain(painter, terrain, tiles, renderOptions) {
|
|
17828
18671
|
const { isRenderingGlobe } = renderOptions;
|
|
17829
18672
|
const context = painter.context;
|
|
@@ -17952,8 +18795,7 @@ const webglDrawFunctions = {
|
|
|
17952
18795
|
custom: drawCustom,
|
|
17953
18796
|
debug: drawDebug,
|
|
17954
18797
|
debugPadding: drawDebugPadding,
|
|
17955
|
-
terrainDepth: drawDepth
|
|
17956
|
-
terrainCoords: drawCoords
|
|
18798
|
+
terrainDepth: drawDepth
|
|
17957
18799
|
};
|
|
17958
18800
|
//#endregion
|
|
17959
18801
|
//#region src/render/painter.ts
|
|
@@ -17972,7 +18814,6 @@ var Painter = class Painter {
|
|
|
17972
18814
|
this._rttSharedFbo = null;
|
|
17973
18815
|
this.terrainFacilitator = {
|
|
17974
18816
|
depthDirty: true,
|
|
17975
|
-
coordsDirty: false,
|
|
17976
18817
|
matrix: identity(/* @__PURE__ */ new Float64Array(16)),
|
|
17977
18818
|
renderTime: 0
|
|
17978
18819
|
};
|
|
@@ -18273,7 +19114,7 @@ var Painter = class Painter {
|
|
|
18273
19114
|
break;
|
|
18274
19115
|
}
|
|
18275
19116
|
}
|
|
18276
|
-
this.maybeDrawDepth(
|
|
19117
|
+
this.maybeDrawDepth();
|
|
18277
19118
|
if (this.renderToTexture) {
|
|
18278
19119
|
this.renderToTexture.prepareForRender(this.style, this.transform.zoom);
|
|
18279
19120
|
this.opaquePassCutoff = 0;
|
|
@@ -18335,30 +19176,20 @@ var Painter = class Painter {
|
|
|
18335
19176
|
}
|
|
18336
19177
|
/**
|
|
18337
19178
|
* Update the depth framebuffer if the camera has moved or tiles have reloaded.
|
|
18338
|
-
* Marks coords as depthDirty so they are re-rendered on next demand.
|
|
18339
19179
|
*/
|
|
18340
|
-
maybeDrawDepth(
|
|
19180
|
+
maybeDrawDepth() {
|
|
18341
19181
|
if (!this.style?.map?.terrain) return;
|
|
18342
19182
|
const prevMatrix = this.terrainFacilitator.matrix;
|
|
18343
19183
|
const currMatrix = this.transform.modelViewProjectionMatrix;
|
|
18344
19184
|
let doUpdate = this.terrainFacilitator.depthDirty;
|
|
18345
|
-
doUpdate ||=
|
|
19185
|
+
doUpdate ||= !equals(prevMatrix, currMatrix);
|
|
18346
19186
|
doUpdate ||= this.style.map.terrain.tileManager.anyTilesAfterTime(this.terrainFacilitator.renderTime);
|
|
18347
19187
|
if (!doUpdate) return;
|
|
18348
19188
|
copy(prevMatrix, currMatrix);
|
|
18349
19189
|
this.terrainFacilitator.renderTime = now();
|
|
18350
19190
|
this.terrainFacilitator.depthDirty = false;
|
|
18351
|
-
this.terrainFacilitator.coordsDirty = true;
|
|
18352
19191
|
this.drawFunctions.terrainDepth(this, this.style.map.terrain);
|
|
18353
19192
|
}
|
|
18354
|
-
/**
|
|
18355
|
-
* Render the coords framebuffer if it is coordsDirty
|
|
18356
|
-
*/
|
|
18357
|
-
maybeDrawCoords() {
|
|
18358
|
-
if (!this.style?.map?.terrain || !this.terrainFacilitator.coordsDirty) return;
|
|
18359
|
-
this.terrainFacilitator.coordsDirty = false;
|
|
18360
|
-
this.drawFunctions.terrainCoords(this, this.style.map.terrain);
|
|
18361
|
-
}
|
|
18362
19193
|
renderLayer(painter, tileManager, layer, coords, renderOptions) {
|
|
18363
19194
|
if (layer.isHidden(this.transform.zoom)) return;
|
|
18364
19195
|
if (layer.type !== "background" && layer.type !== "custom" && !(coords || []).length) return;
|
|
@@ -21094,7 +21925,7 @@ var HandlerManager = class {
|
|
|
21094
21925
|
_terrainGestureElevation(terrain, around, aroundOnSurface, tr, combinedEventsInProgress) {
|
|
21095
21926
|
if (!aroundOnSurface) return;
|
|
21096
21927
|
if (!this._terrainMovement && (combinedEventsInProgress.drag || combinedEventsInProgress.zoom)) {
|
|
21097
|
-
const anchor =
|
|
21928
|
+
const anchor = tr.screenTerrainPointToMercatorCoordinate(around, terrain);
|
|
21098
21929
|
this._terrainGestureAnchorElevation = anchor ? anchor.z : null;
|
|
21099
21930
|
}
|
|
21100
21931
|
if (this._terrainGestureAnchorElevation === null) return;
|
|
@@ -21908,855 +22739,155 @@ var AttributionControl = class {
|
|
|
21908
22739
|
this._container.remove();
|
|
21909
22740
|
this._map.off("styledata", this._updateData);
|
|
21910
22741
|
this._map.off("sourcedata", this._updateData);
|
|
21911
|
-
this._map.off("terrain", this._updateData);
|
|
21912
|
-
this._map.off("resize", this._updateCompact);
|
|
21913
|
-
this._map.off("drag", this._updateCompactMinimize);
|
|
21914
|
-
this._map = void 0;
|
|
21915
|
-
this._compact = void 0;
|
|
21916
|
-
this._attribHTML = void 0;
|
|
21917
|
-
}
|
|
21918
|
-
_setElementTitle(element, title) {
|
|
21919
|
-
const str = this._map._getUIString(`AttributionControl.${title}`);
|
|
21920
|
-
element.title = str;
|
|
21921
|
-
element.setAttribute("aria-label", str);
|
|
21922
|
-
}
|
|
21923
|
-
_updateAttributions() {
|
|
21924
|
-
if (!this._map.style) return;
|
|
21925
|
-
let attributions = [];
|
|
21926
|
-
if (this.options.customAttribution) {
|
|
21927
|
-
if (Array.isArray(this.options.customAttribution)) attributions = attributions.concat(this.options.customAttribution.map((attribution) => {
|
|
21928
|
-
if (typeof attribution !== "string") return "";
|
|
21929
|
-
return attribution;
|
|
21930
|
-
}));
|
|
21931
|
-
else if (typeof this.options.customAttribution === "string") attributions.push(this.options.customAttribution);
|
|
21932
|
-
}
|
|
21933
|
-
if (this._map.style.stylesheet) {
|
|
21934
|
-
const stylesheet = this._map.style.stylesheet;
|
|
21935
|
-
this.styleOwner = stylesheet.owner;
|
|
21936
|
-
this.styleId = stylesheet.id;
|
|
21937
|
-
}
|
|
21938
|
-
const tileManagers = this._map.style.tileManagers;
|
|
21939
|
-
for (const id in tileManagers) {
|
|
21940
|
-
const tileManager = tileManagers[id];
|
|
21941
|
-
if (tileManager.used || tileManager.usedForTerrain) {
|
|
21942
|
-
const source = tileManager.getSource();
|
|
21943
|
-
if (source.attribution && !attributions.includes(source.attribution)) attributions.push(source.attribution);
|
|
21944
|
-
}
|
|
21945
|
-
}
|
|
21946
|
-
attributions = attributions.filter((e) => String(e).trim());
|
|
21947
|
-
attributions.sort((a, b) => a.length - b.length);
|
|
21948
|
-
attributions = attributions.filter((attrib, i) => {
|
|
21949
|
-
for (let j = i + 1; j < attributions.length; j++) if (attributions[j].includes(attrib)) return false;
|
|
21950
|
-
return true;
|
|
21951
|
-
});
|
|
21952
|
-
const attribHTML = attributions.join(" | ");
|
|
21953
|
-
if (attribHTML === this._attribHTML) return;
|
|
21954
|
-
this._attribHTML = attribHTML;
|
|
21955
|
-
if (attributions.length) {
|
|
21956
|
-
this._innerContainer.innerHTML = DOM.sanitize(attribHTML);
|
|
21957
|
-
this._container.classList.remove("maplibregl-attrib-empty");
|
|
21958
|
-
} else this._container.classList.add("maplibregl-attrib-empty");
|
|
21959
|
-
this._updateCompact();
|
|
21960
|
-
this._editLink = null;
|
|
21961
|
-
}
|
|
21962
|
-
};
|
|
21963
|
-
//#endregion
|
|
21964
|
-
//#region src/ui/control/logo_control.ts
|
|
21965
|
-
/**
|
|
21966
|
-
* A `LogoControl` is a control that adds the watermark.
|
|
21967
|
-
*
|
|
21968
|
-
* @group Markers and Controls
|
|
21969
|
-
*
|
|
21970
|
-
* @example
|
|
21971
|
-
* ```ts
|
|
21972
|
-
* map.addControl(new LogoControl({compact: false}));
|
|
21973
|
-
* ```
|
|
21974
|
-
**/
|
|
21975
|
-
var LogoControl = class {
|
|
21976
|
-
/**
|
|
21977
|
-
* @param options - the control's options
|
|
21978
|
-
*/
|
|
21979
|
-
constructor(options = {}) {
|
|
21980
|
-
this._updateCompact = () => {
|
|
21981
|
-
const containerChildren = this._container.children;
|
|
21982
|
-
if (containerChildren.length) {
|
|
21983
|
-
const anchor = containerChildren[0];
|
|
21984
|
-
if (this._map.getCanvasContainer().offsetWidth <= 640 || this._compact) {
|
|
21985
|
-
if (this._compact !== false) anchor.classList.add("maplibregl-compact");
|
|
21986
|
-
} else anchor.classList.remove("maplibregl-compact");
|
|
21987
|
-
}
|
|
21988
|
-
};
|
|
21989
|
-
this.options = options;
|
|
21990
|
-
}
|
|
21991
|
-
getDefaultPosition() {
|
|
21992
|
-
return "bottom-left";
|
|
21993
|
-
}
|
|
21994
|
-
/** {@inheritDoc IControl.onAdd} */
|
|
21995
|
-
onAdd(map) {
|
|
21996
|
-
this._map = map;
|
|
21997
|
-
this._compact = this.options?.compact;
|
|
21998
|
-
this._container = DOM.create("div", "maplibregl-ctrl");
|
|
21999
|
-
const anchor = DOM.create("a", "maplibregl-ctrl-logo");
|
|
22000
|
-
anchor.target = "_blank";
|
|
22001
|
-
anchor.rel = "noopener nofollow";
|
|
22002
|
-
anchor.href = "https://maplibre.org/";
|
|
22003
|
-
anchor.setAttribute("aria-label", this._map._getUIString("LogoControl.Title"));
|
|
22004
|
-
anchor.setAttribute("rel", "noopener nofollow");
|
|
22005
|
-
this._container.appendChild(anchor);
|
|
22006
|
-
this._container.style.display = "block";
|
|
22007
|
-
this._map.on("resize", this._updateCompact);
|
|
22008
|
-
this._updateCompact();
|
|
22009
|
-
return this._container;
|
|
22010
|
-
}
|
|
22011
|
-
/** {@inheritDoc IControl.onRemove} */
|
|
22012
|
-
onRemove() {
|
|
22013
|
-
this._container.remove();
|
|
22014
|
-
this._map.off("resize", this._updateCompact);
|
|
22015
|
-
this._map = void 0;
|
|
22016
|
-
this._compact = void 0;
|
|
22017
|
-
}
|
|
22018
|
-
};
|
|
22019
|
-
//#endregion
|
|
22020
|
-
//#region src/util/task_queue.ts
|
|
22021
|
-
var TaskQueue = class {
|
|
22022
|
-
constructor() {
|
|
22023
|
-
this._queue = [];
|
|
22024
|
-
this._id = 0;
|
|
22025
|
-
this._cleared = false;
|
|
22026
|
-
this._currentlyRunning = false;
|
|
22027
|
-
}
|
|
22028
|
-
add(callback) {
|
|
22029
|
-
const id = ++this._id;
|
|
22030
|
-
this._queue.push({
|
|
22031
|
-
callback,
|
|
22032
|
-
id,
|
|
22033
|
-
cancelled: false
|
|
22034
|
-
});
|
|
22035
|
-
return id;
|
|
22036
|
-
}
|
|
22037
|
-
remove(id) {
|
|
22038
|
-
const running = this._currentlyRunning;
|
|
22039
|
-
const queue = running ? this._queue.concat(running) : this._queue;
|
|
22040
|
-
for (const task of queue) if (task.id === id) {
|
|
22041
|
-
task.cancelled = true;
|
|
22042
|
-
return;
|
|
22043
|
-
}
|
|
22044
|
-
}
|
|
22045
|
-
run(timeStamp = 0) {
|
|
22046
|
-
if (this._currentlyRunning) throw new Error("Attempting to run(), but is already running.");
|
|
22047
|
-
const queue = this._currentlyRunning = this._queue;
|
|
22048
|
-
this._queue = [];
|
|
22049
|
-
for (const task of queue) {
|
|
22050
|
-
if (task.cancelled) continue;
|
|
22051
|
-
task.callback(timeStamp);
|
|
22052
|
-
if (this._cleared) break;
|
|
22053
|
-
}
|
|
22054
|
-
this._cleared = false;
|
|
22055
|
-
this._currentlyRunning = false;
|
|
22056
|
-
}
|
|
22057
|
-
clear() {
|
|
22058
|
-
if (this._currentlyRunning) this._cleared = true;
|
|
22059
|
-
this._queue = [];
|
|
22060
|
-
}
|
|
22061
|
-
};
|
|
22062
|
-
//#endregion
|
|
22063
|
-
//#region src/data/pos3d_attributes.ts
|
|
22064
|
-
const pos3dAttributes = createLayout([{
|
|
22065
|
-
name: "a_pos3d",
|
|
22066
|
-
type: "Int16",
|
|
22067
|
-
components: 3
|
|
22068
|
-
}]);
|
|
22069
|
-
//#endregion
|
|
22070
|
-
//#region src/tile/terrain_tile_manager.ts
|
|
22071
|
-
/**
|
|
22072
|
-
* @internal
|
|
22073
|
-
* This class is a helper for the Terrain-class, it:
|
|
22074
|
-
*
|
|
22075
|
-
* - loads raster-dem tiles
|
|
22076
|
-
* - manages all renderToTexture tiles.
|
|
22077
|
-
* - caches previous rendered tiles.
|
|
22078
|
-
* - finds all necessary renderToTexture tiles for a OverscaledTileID area
|
|
22079
|
-
* - finds the corresponding raster-dem tile for OverscaledTileID
|
|
22080
|
-
*/
|
|
22081
|
-
var TerrainTileManager = class extends Evented {
|
|
22082
|
-
constructor(tileManager) {
|
|
22083
|
-
super();
|
|
22084
|
-
this._lastTilesetChange = now();
|
|
22085
|
-
this.tileManager = tileManager;
|
|
22086
|
-
this._tiles = {};
|
|
22087
|
-
this._renderableTilesKeys = [];
|
|
22088
|
-
this._sourceTileCache = {};
|
|
22089
|
-
this.minzoom = 0;
|
|
22090
|
-
this.maxzoom = 22;
|
|
22091
|
-
this.deltaZoom = 1;
|
|
22092
|
-
this.tileSize = tileManager._source.tileSize * 2 ** this.deltaZoom;
|
|
22093
|
-
tileManager.usedForTerrain = true;
|
|
22094
|
-
tileManager.tileSize = this.tileSize;
|
|
22095
|
-
}
|
|
22096
|
-
destruct() {
|
|
22097
|
-
this.tileManager.usedForTerrain = false;
|
|
22098
|
-
this.tileManager.tileSize = null;
|
|
22099
|
-
this.releaseAllRTT();
|
|
22100
|
-
}
|
|
22101
|
-
getSource() {
|
|
22102
|
-
return this.tileManager._source;
|
|
22103
|
-
}
|
|
22104
|
-
/**
|
|
22105
|
-
* Load Terrain Tiles, create internal render-to-texture tiles, free GPU memory.
|
|
22106
|
-
* @param transform - the operation to do
|
|
22107
|
-
* @param terrain - the terrain
|
|
22108
|
-
*/
|
|
22109
|
-
update(transform, terrain) {
|
|
22110
|
-
this.tileManager.update(transform, terrain);
|
|
22111
|
-
this._renderableTilesKeys = [];
|
|
22112
|
-
const keys = {};
|
|
22113
|
-
for (const tileID of coveringTiles(transform, {
|
|
22114
|
-
tileSize: this.tileSize,
|
|
22115
|
-
minzoom: this.minzoom,
|
|
22116
|
-
maxzoom: this.maxzoom,
|
|
22117
|
-
reparseOverscaled: false,
|
|
22118
|
-
terrain,
|
|
22119
|
-
calculateTileZoom: this.tileManager._source.calculateTileZoom
|
|
22120
|
-
})) {
|
|
22121
|
-
keys[tileID.key] = true;
|
|
22122
|
-
this._renderableTilesKeys.push(tileID.key);
|
|
22123
|
-
if (!this._tiles[tileID.key]) {
|
|
22124
|
-
tileID.terrainRttPosMatrix32f = /* @__PURE__ */ new Float32Array(16);
|
|
22125
|
-
ortho(tileID.terrainRttPosMatrix32f, 0, EXTENT, EXTENT, 0, 0, 1);
|
|
22126
|
-
this._tiles[tileID.key] = new Tile(tileID, this.tileSize);
|
|
22127
|
-
this._lastTilesetChange = now();
|
|
22128
|
-
}
|
|
22129
|
-
}
|
|
22130
|
-
for (const key in this._tiles) if (!keys[key]) {
|
|
22131
|
-
this._tiles[key].releaseRTT(this.tileManager.map.painter);
|
|
22132
|
-
delete this._tiles[key];
|
|
22133
|
-
}
|
|
22134
|
-
}
|
|
22135
|
-
/**
|
|
22136
|
-
* Release the RTT objects for `tileID` (and its ancestors/descendants),
|
|
22137
|
-
*/
|
|
22138
|
-
releaseRTT(tileID) {
|
|
22139
|
-
for (const key in this._tiles) {
|
|
22140
|
-
const tile = this._tiles[key];
|
|
22141
|
-
if (tile.tileID.equals(tileID) || tile.tileID.isChildOf(tileID) || tileID.isChildOf(tile.tileID)) tile.releaseRTT(this.tileManager.map.painter);
|
|
22142
|
-
}
|
|
22143
|
-
}
|
|
22144
|
-
/**
|
|
22145
|
-
* Release the A RTT objects for all tiles.
|
|
22146
|
-
*/
|
|
22147
|
-
releaseAllRTT() {
|
|
22148
|
-
for (const key in this._tiles) this._tiles[key].releaseRTT(this.tileManager.map.painter);
|
|
22149
|
-
}
|
|
22150
|
-
/**
|
|
22151
|
-
* get a list of tiles, which are loaded and should be rendered in the current scene
|
|
22152
|
-
* @returns the renderable tiles
|
|
22153
|
-
*/
|
|
22154
|
-
getRenderableTiles() {
|
|
22155
|
-
return this._renderableTilesKeys.map((key) => this.getTileByID(key));
|
|
22156
|
-
}
|
|
22157
|
-
/**
|
|
22158
|
-
* get terrain tile by the TileID key
|
|
22159
|
-
* @param id - the tile id
|
|
22160
|
-
* @returns the tile
|
|
22161
|
-
*/
|
|
22162
|
-
getTileByID(id) {
|
|
22163
|
-
return this._tiles[id];
|
|
22164
|
-
}
|
|
22165
|
-
/**
|
|
22166
|
-
* Searches for the corresponding current renderable terrain-tiles
|
|
22167
|
-
* @param tileID - the tile to look for
|
|
22168
|
-
* @returns the tiles that were found
|
|
22169
|
-
*/
|
|
22170
|
-
getTerrainCoords(tileID, terrainTileRanges) {
|
|
22171
|
-
if (terrainTileRanges) return this._getTerrainCoordsForTileRanges(tileID, terrainTileRanges);
|
|
22172
|
-
else return this._getTerrainCoordsForRegularTile(tileID);
|
|
22173
|
-
}
|
|
22174
|
-
/**
|
|
22175
|
-
* Searches for the corresponding current renderable terrain-tiles.
|
|
22176
|
-
* Includes terrain tiles that are either:
|
|
22177
|
-
* - the same as the tileID
|
|
22178
|
-
* - a parent of the tileID
|
|
22179
|
-
* - a child of the tileID
|
|
22180
|
-
* @param tileID - the tile to look for
|
|
22181
|
-
* @returns the tiles that were found
|
|
22182
|
-
*/
|
|
22183
|
-
_getTerrainCoordsForRegularTile(tileID) {
|
|
22184
|
-
const coords = {};
|
|
22185
|
-
for (const key of this._renderableTilesKeys) {
|
|
22186
|
-
const terrainTileID = this._tiles[key].tileID;
|
|
22187
|
-
const coord = tileID.clone();
|
|
22188
|
-
const mat = createMat4f64();
|
|
22189
|
-
if (terrainTileID.canonical.equals(tileID.canonical)) ortho(mat, 0, EXTENT, EXTENT, 0, 0, 1);
|
|
22190
|
-
else if (terrainTileID.canonical.isChildOf(tileID.canonical)) {
|
|
22191
|
-
const dz = terrainTileID.canonical.z - tileID.canonical.z;
|
|
22192
|
-
const dx = terrainTileID.canonical.x - (terrainTileID.canonical.x >> dz << dz);
|
|
22193
|
-
const dy = terrainTileID.canonical.y - (terrainTileID.canonical.y >> dz << dz);
|
|
22194
|
-
const size = EXTENT >> dz;
|
|
22195
|
-
ortho(mat, 0, size, size, 0, 0, 1);
|
|
22196
|
-
translate(mat, mat, [
|
|
22197
|
-
-dx * size,
|
|
22198
|
-
-dy * size,
|
|
22199
|
-
0
|
|
22200
|
-
]);
|
|
22201
|
-
} else if (tileID.canonical.isChildOf(terrainTileID.canonical)) {
|
|
22202
|
-
const dz = tileID.canonical.z - terrainTileID.canonical.z;
|
|
22203
|
-
const dx = tileID.canonical.x - (tileID.canonical.x >> dz << dz);
|
|
22204
|
-
const dy = tileID.canonical.y - (tileID.canonical.y >> dz << dz);
|
|
22205
|
-
const size = EXTENT >> dz;
|
|
22206
|
-
ortho(mat, 0, EXTENT, EXTENT, 0, 0, 1);
|
|
22207
|
-
translate(mat, mat, [
|
|
22208
|
-
dx * size,
|
|
22209
|
-
dy * size,
|
|
22210
|
-
0
|
|
22211
|
-
]);
|
|
22212
|
-
scale(mat, mat, [
|
|
22213
|
-
1 / 2 ** dz,
|
|
22214
|
-
1 / 2 ** dz,
|
|
22215
|
-
0
|
|
22216
|
-
]);
|
|
22217
|
-
} else continue;
|
|
22218
|
-
coord.terrainRttPosMatrix32f = new Float32Array(mat);
|
|
22219
|
-
coords[key] = coord;
|
|
22220
|
-
}
|
|
22221
|
-
return coords;
|
|
22222
|
-
}
|
|
22223
|
-
/**
|
|
22224
|
-
* Searches for the corresponding current renderable terrain-tiles.
|
|
22225
|
-
* Includes terrain tiles that are within terrain tile ranges.
|
|
22226
|
-
* @param tileID - the tile to look for
|
|
22227
|
-
* @returns the tiles that were found
|
|
22228
|
-
*/
|
|
22229
|
-
_getTerrainCoordsForTileRanges(tileID, terrainTileRanges) {
|
|
22230
|
-
const coords = {};
|
|
22231
|
-
for (const key of this._renderableTilesKeys) {
|
|
22232
|
-
const terrainTileID = this._tiles[key].tileID;
|
|
22233
|
-
if (!this._isWithinTileRanges(terrainTileID, terrainTileRanges)) continue;
|
|
22234
|
-
const coord = tileID.clone();
|
|
22235
|
-
const mat = createMat4f64();
|
|
22236
|
-
if (terrainTileID.canonical.z === tileID.canonical.z) {
|
|
22237
|
-
const dx = tileID.canonical.x - terrainTileID.canonical.x + tileID.wrap * (1 << tileID.canonical.z);
|
|
22238
|
-
const dy = tileID.canonical.y - terrainTileID.canonical.y;
|
|
22239
|
-
ortho(mat, 0, EXTENT, EXTENT, 0, 0, 1);
|
|
22240
|
-
translate(mat, mat, [
|
|
22241
|
-
dx * EXTENT,
|
|
22242
|
-
dy * EXTENT,
|
|
22243
|
-
0
|
|
22244
|
-
]);
|
|
22245
|
-
} else if (terrainTileID.canonical.z > tileID.canonical.z) {
|
|
22246
|
-
const dz = terrainTileID.canonical.z - tileID.canonical.z;
|
|
22247
|
-
const dx = terrainTileID.canonical.x - (terrainTileID.canonical.x >> dz << dz) + tileID.wrap * (1 << terrainTileID.canonical.z);
|
|
22248
|
-
const dy = terrainTileID.canonical.y - (terrainTileID.canonical.y >> dz << dz);
|
|
22249
|
-
const dx2 = tileID.canonical.x - (terrainTileID.canonical.x >> dz);
|
|
22250
|
-
const dy2 = tileID.canonical.y - (terrainTileID.canonical.y >> dz);
|
|
22251
|
-
const size = EXTENT >> dz;
|
|
22252
|
-
ortho(mat, 0, size, size, 0, 0, 1);
|
|
22253
|
-
translate(mat, mat, [
|
|
22254
|
-
-dx * size + dx2 * EXTENT,
|
|
22255
|
-
-dy * size + dy2 * EXTENT,
|
|
22256
|
-
0
|
|
22257
|
-
]);
|
|
22258
|
-
} else {
|
|
22259
|
-
const dz = tileID.canonical.z - terrainTileID.canonical.z;
|
|
22260
|
-
const dx = tileID.canonical.x - (tileID.canonical.x >> dz << dz) + tileID.wrap * (1 << tileID.canonical.z);
|
|
22261
|
-
const dy = tileID.canonical.y - (tileID.canonical.y >> dz << dz);
|
|
22262
|
-
const dx2 = (tileID.canonical.x >> dz) - terrainTileID.canonical.x;
|
|
22263
|
-
const dy2 = (tileID.canonical.y >> dz) - terrainTileID.canonical.y;
|
|
22264
|
-
const size = EXTENT << dz;
|
|
22265
|
-
ortho(mat, 0, size, size, 0, 0, 1);
|
|
22266
|
-
translate(mat, mat, [
|
|
22267
|
-
dx * EXTENT + dx2 * size,
|
|
22268
|
-
dy * EXTENT + dy2 * size,
|
|
22269
|
-
0
|
|
22270
|
-
]);
|
|
22271
|
-
}
|
|
22272
|
-
coord.terrainRttPosMatrix32f = new Float32Array(mat);
|
|
22273
|
-
coords[key] = coord;
|
|
22274
|
-
}
|
|
22275
|
-
return coords;
|
|
22276
|
-
}
|
|
22277
|
-
/**
|
|
22278
|
-
* find the covering raster-dem tile
|
|
22279
|
-
* @param tileID - the tile to look for
|
|
22280
|
-
* @param searchForDEM - Optional parameter to search for (parent) source tiles with loaded dem.
|
|
22281
|
-
* @returns the tile
|
|
22282
|
-
*/
|
|
22283
|
-
getSourceTile(tileID, searchForDEM) {
|
|
22284
|
-
const source = this.tileManager._source;
|
|
22285
|
-
let z = tileID.overscaledZ - this.deltaZoom;
|
|
22286
|
-
if (z > source.maxzoom) z = source.maxzoom;
|
|
22287
|
-
if (z < source.minzoom) return void 0;
|
|
22288
|
-
this._sourceTileCache[tileID.key] ||= tileID.scaledTo(z).key;
|
|
22289
|
-
let tile = this.findTileInCaches(this._sourceTileCache[tileID.key]);
|
|
22290
|
-
if (!tile?.dem && searchForDEM) while (z >= source.minzoom && !tile?.dem) tile = this.findTileInCaches(tileID.scaledTo(z--).key);
|
|
22291
|
-
return tile;
|
|
22292
|
-
}
|
|
22293
|
-
findTileInCaches(key) {
|
|
22294
|
-
let tile = this.tileManager.getTileByID(key);
|
|
22295
|
-
if (tile) return tile;
|
|
22296
|
-
tile = this.tileManager._outOfViewCache.getByKey(key);
|
|
22297
|
-
return tile;
|
|
22298
|
-
}
|
|
22299
|
-
/**
|
|
22300
|
-
* gets whether any tiles were loaded after a specific time. This is used to update depth & coords framebuffers.
|
|
22301
|
-
* @param time - the time
|
|
22302
|
-
* @returns true if any tiles came into view at or after the specified time
|
|
22303
|
-
*/
|
|
22304
|
-
anyTilesAfterTime(time = now()) {
|
|
22305
|
-
return this._lastTilesetChange >= time;
|
|
22306
|
-
}
|
|
22307
|
-
/**
|
|
22308
|
-
* Checks whether a tile is within the canonical tile ranges.
|
|
22309
|
-
* @param tileID - Tile to check
|
|
22310
|
-
* @param canonicalTileRanges - Canonical tile ranges
|
|
22311
|
-
* @returns
|
|
22312
|
-
*/
|
|
22313
|
-
_isWithinTileRanges(tileID, canonicalTileRanges) {
|
|
22314
|
-
const range = canonicalTileRanges[tileID.canonical.z];
|
|
22315
|
-
return !!range && (tileID.wrap > range.minWrap || tileID.wrap < range.maxWrap || tileID.canonical.x >= range.minTileXWrapped && tileID.canonical.x <= range.maxTileXWrapped && tileID.canonical.y >= range.minTileY && tileID.canonical.y <= range.maxTileY);
|
|
22316
|
-
}
|
|
22317
|
-
};
|
|
22318
|
-
//#endregion
|
|
22319
|
-
//#region src/render/terrain.ts
|
|
22320
|
-
/**
|
|
22321
|
-
* @internal
|
|
22322
|
-
* This is the main class which handles most of the 3D Terrain logic. It has the following topics:
|
|
22323
|
-
*
|
|
22324
|
-
* 1. loads raster-dem tiles via the internal tileManager this.tileManager
|
|
22325
|
-
* 2. creates a depth-framebuffer, which is used to calculate the visibility of coordinates
|
|
22326
|
-
* 3. creates a coords-framebuffer, which is used the get to tile-coordinate for a screen-pixel
|
|
22327
|
-
* 4. stores all render-to-texture tiles in the this.tileManager._tiles
|
|
22328
|
-
* 5. calculates the elevation for a specific tile-coordinate
|
|
22329
|
-
* 6. creates a terrain-mesh
|
|
22330
|
-
*
|
|
22331
|
-
* A note about the GPU resource-usage:
|
|
22332
|
-
*
|
|
22333
|
-
* Framebuffers:
|
|
22334
|
-
*
|
|
22335
|
-
* - one for the depth & coords framebuffer with the size of the map-div.
|
|
22336
|
-
* - one for rendering a tile to texture with the size of tileSize (= 512x512).
|
|
22337
|
-
*
|
|
22338
|
-
* Textures:
|
|
22339
|
-
*
|
|
22340
|
-
* - one texture for an empty raster-dem tile with size 1x1
|
|
22341
|
-
* - one texture for an empty depth-buffer, when terrain is disabled with size 1x1
|
|
22342
|
-
* - one texture for an each loaded raster-dem with size of the source.tileSize
|
|
22343
|
-
* - one texture for the coords-framebuffer with the size of the map-div.
|
|
22344
|
-
* - one texture for the depth-framebuffer with the size of the map-div.
|
|
22345
|
-
* - one texture for the encoded tile-coords with the size 2*tileSize (=1024x1024)
|
|
22346
|
-
* - finally for each render-to-texture tile (= this._tiles) a set of textures
|
|
22347
|
-
* for each render stack (The stack-concept is documented in painter.ts).
|
|
22348
|
-
*
|
|
22349
|
-
* Normally there exists 1-3 Textures per tile, depending on the stylesheet.
|
|
22350
|
-
* Each Textures has the size 2*tileSize (= 1024x1024). Also there exists a
|
|
22351
|
-
* cache of the last 150 newest rendered tiles.
|
|
22352
|
-
*
|
|
22353
|
-
*/
|
|
22354
|
-
var Terrain = class {
|
|
22355
|
-
constructor(painter, tileManager, options, terrainSkirtLength = "auto") {
|
|
22356
|
-
this._meshCache = {};
|
|
22357
|
-
this.painter = painter;
|
|
22358
|
-
this.tileManager = new TerrainTileManager(tileManager);
|
|
22359
|
-
this.options = options;
|
|
22360
|
-
this.exaggeration = typeof options.exaggeration === "number" ? options.exaggeration : 1;
|
|
22361
|
-
this._terrainSkirtLength = terrainSkirtLength;
|
|
22362
|
-
this.qualityFactor = 2;
|
|
22363
|
-
this.meshSize = 128;
|
|
22364
|
-
this._demMatrixCache = /* @__PURE__ */ new Map();
|
|
22365
|
-
this._elevationSamplerCache = /* @__PURE__ */ new Map();
|
|
22366
|
-
this.coordsIndex = [];
|
|
22367
|
-
this._coordsTextureSize = 1024;
|
|
22368
|
-
}
|
|
22369
|
-
destroy() {
|
|
22370
|
-
if (this._fbo) {
|
|
22371
|
-
this._fbo.destroy();
|
|
22372
|
-
this._fbo = null;
|
|
22373
|
-
}
|
|
22374
|
-
if (this._fboCoordsTexture) {
|
|
22375
|
-
this._fboCoordsTexture.destroy();
|
|
22376
|
-
this._fboCoordsTexture = null;
|
|
22377
|
-
}
|
|
22378
|
-
if (this._fboDepthTexture) {
|
|
22379
|
-
this._fboDepthTexture.destroy();
|
|
22380
|
-
this._fboDepthTexture = null;
|
|
22381
|
-
}
|
|
22382
|
-
if (this._emptyDemTexture) {
|
|
22383
|
-
this._emptyDemTexture.destroy();
|
|
22384
|
-
this._emptyDemTexture = null;
|
|
22385
|
-
}
|
|
22386
|
-
if (this._emptyDepthTexture) {
|
|
22387
|
-
this._emptyDepthTexture.destroy();
|
|
22388
|
-
this._emptyDepthTexture = null;
|
|
22389
|
-
}
|
|
22390
|
-
if (this._coordsTexture) {
|
|
22391
|
-
this._coordsTexture.destroy();
|
|
22392
|
-
this._coordsTexture = null;
|
|
22393
|
-
}
|
|
22394
|
-
for (const key in this._meshCache) this._meshCache[key].destroy();
|
|
22395
|
-
this._meshCache = {};
|
|
22396
|
-
this.tileManager.destruct();
|
|
22397
|
-
}
|
|
22398
|
-
/**
|
|
22399
|
-
* Get the elevation-value from original dem-data for a given tile-coordinate.
|
|
22400
|
-
* Coordinates that fall outside `[0, extent)` are normalized to the
|
|
22401
|
-
* appropriate neighbor tile before lookup.
|
|
22402
|
-
* @param tileID - the tile to get the elevation for
|
|
22403
|
-
* @param x - x coordinate relative to the tile, may be outside `[0, extent)`
|
|
22404
|
-
* @param y - y coordinate relative to the tile, may be outside `[0, extent)`
|
|
22405
|
-
* @param extent - optional, default 8192
|
|
22406
|
-
* @returns the elevation
|
|
22407
|
-
*/
|
|
22408
|
-
getDEMElevation(tileID, x, y, extent = EXTENT) {
|
|
22409
|
-
const normalized = tileID.normalizeCoordinates(x, y, extent);
|
|
22410
|
-
if (!normalized) return 0;
|
|
22411
|
-
const sampler = this._getElevationSampler(normalized.tileID);
|
|
22412
|
-
return sampler ? sampler(normalized.x, normalized.y, extent) : 0;
|
|
22413
|
-
}
|
|
22414
|
-
/**
|
|
22415
|
-
* Get the elevation for given {@link LngLat} in respect of exaggeration.
|
|
22416
|
-
* @param lnglat - the location
|
|
22417
|
-
* @param zoom - the zoom, use {@link getElevationForLngLat} if you don't want a specific zoom level, but more accurate results.
|
|
22418
|
-
* @returns the elevation
|
|
22419
|
-
*/
|
|
22420
|
-
getElevationForLngLatZoom(lnglat, zoom) {
|
|
22421
|
-
if (!isInBoundsForZoomLngLat(zoom, lnglat.wrap())) return 0;
|
|
22422
|
-
const { tileID, mercatorX, mercatorY } = this._getOverscaledTileIDFromLngLatZoom(lnglat, zoom);
|
|
22423
|
-
return this.getElevation(tileID, mercatorX % EXTENT, mercatorY % EXTENT, EXTENT);
|
|
22424
|
-
}
|
|
22425
|
-
/**
|
|
22426
|
-
* Get the elevation for given {@link LngLat} in respect of exaggeration.
|
|
22427
|
-
* This will traverse up the zoom levels to find the first tile with data to return.
|
|
22428
|
-
* @param lnglat - the location
|
|
22429
|
-
* @returns the elevation
|
|
22430
|
-
*/
|
|
22431
|
-
getElevationForLngLat(lnglat, transform) {
|
|
22432
|
-
const terrainCoveringTiles = coveringTiles(transform, {
|
|
22433
|
-
maxzoom: this.tileManager.maxzoom,
|
|
22434
|
-
minzoom: this.tileManager.minzoom,
|
|
22435
|
-
tileSize: 512,
|
|
22436
|
-
terrain: this
|
|
22437
|
-
});
|
|
22438
|
-
let zoom = 0;
|
|
22439
|
-
for (const tile of terrainCoveringTiles) if (tile.canonical.z > zoom) zoom = Math.min(tile.canonical.z, this.tileManager.maxzoom);
|
|
22440
|
-
return this.getElevationForLngLatZoom(lnglat, zoom);
|
|
22441
|
-
}
|
|
22442
|
-
/**
|
|
22443
|
-
* Get the elevation for given coordinate in respect of exaggeration.
|
|
22444
|
-
* @param tileID - the tile id
|
|
22445
|
-
* @param x - x coordinate relative to the tile, may be outside `[0, extent)`
|
|
22446
|
-
* @param y - y coordinate relative to the tile, may be outside `[0, extent)`
|
|
22447
|
-
* @param extent - optional, default 8192
|
|
22448
|
-
* @returns the elevation
|
|
22449
|
-
*/
|
|
22450
|
-
getElevation(tileID, x, y, extent = EXTENT) {
|
|
22451
|
-
return this.getDEMElevation(tileID, x, y, extent) * this.exaggeration;
|
|
22452
|
-
}
|
|
22453
|
-
/**
|
|
22454
|
-
* Clear CPU elevation samplers that may retain a previously selected DEM tile.
|
|
22455
|
-
* @internal
|
|
22456
|
-
*/
|
|
22457
|
-
resetElevationCache() {
|
|
22458
|
-
this._elevationSamplerCache.clear();
|
|
22459
|
-
}
|
|
22460
|
-
_getElevationSampler(tileID) {
|
|
22461
|
-
const key = tileID.key;
|
|
22462
|
-
const cachedSampler = this._elevationSamplerCache.get(key);
|
|
22463
|
-
if (cachedSampler) return cachedSampler;
|
|
22464
|
-
const sourceTile = this.tileManager.getSourceTile(tileID, true);
|
|
22465
|
-
const dem = sourceTile?.dem;
|
|
22466
|
-
if (!sourceTile || !dem) return null;
|
|
22467
|
-
const matrix = this._getDEMTileMatrix(tileID, sourceTile);
|
|
22468
|
-
const demPixelScaleX = matrix[0] * dem.dim;
|
|
22469
|
-
const demPixelScaleY = matrix[5] * dem.dim;
|
|
22470
|
-
const demPixelOffsetX = matrix[12] * dem.dim;
|
|
22471
|
-
const demPixelOffsetY = matrix[13] * dem.dim;
|
|
22472
|
-
const sampler = (x, y, extent) => {
|
|
22473
|
-
const extentScale = extent === 8192 ? 1 : EXTENT / extent;
|
|
22474
|
-
return dem.sampleBilinear(x * extentScale * demPixelScaleX + demPixelOffsetX, y * extentScale * demPixelScaleY + demPixelOffsetY);
|
|
22475
|
-
};
|
|
22476
|
-
this._elevationSamplerCache.set(key, sampler);
|
|
22477
|
-
return sampler;
|
|
22478
|
-
}
|
|
22479
|
-
_getDEMTileMatrix(tileID, sourceTile) {
|
|
22480
|
-
const matrixKey = `${sourceTile.tileID.key}/${tileID.key}`;
|
|
22481
|
-
const cachedMatrix = this._demMatrixCache.get(matrixKey);
|
|
22482
|
-
if (cachedMatrix) return cachedMatrix;
|
|
22483
|
-
const maxzoom = this.tileManager.getSource().maxzoom;
|
|
22484
|
-
let dz = tileID.canonical.z - sourceTile.tileID.canonical.z;
|
|
22485
|
-
if (tileID.overscaledZ > tileID.canonical.z) {
|
|
22486
|
-
if (tileID.canonical.z >= maxzoom) dz = tileID.canonical.z - maxzoom;
|
|
22487
|
-
else warnOnce("cannot calculate elevation if elevation maxzoom > source.maxzoom");
|
|
22488
|
-
}
|
|
22489
|
-
const dx = tileID.canonical.x - (tileID.canonical.x >> dz << dz);
|
|
22490
|
-
const dy = tileID.canonical.y - (tileID.canonical.y >> dz << dz);
|
|
22491
|
-
const demMatrix = fromScaling(/* @__PURE__ */ new Float64Array(16), [
|
|
22492
|
-
1 / (EXTENT << dz),
|
|
22493
|
-
1 / (EXTENT << dz),
|
|
22494
|
-
0
|
|
22495
|
-
]);
|
|
22496
|
-
translate(demMatrix, demMatrix, [
|
|
22497
|
-
dx * EXTENT,
|
|
22498
|
-
dy * EXTENT,
|
|
22499
|
-
0
|
|
22500
|
-
]);
|
|
22501
|
-
this._demMatrixCache.set(matrixKey, demMatrix);
|
|
22502
|
-
return demMatrix;
|
|
22503
|
-
}
|
|
22504
|
-
/**
|
|
22505
|
-
* returns a Terrain Object for a tile. Unless the tile corresponds to data (e.g. tile is loading), return a flat dem object
|
|
22506
|
-
* @param tileID - the tile to get the terrain for
|
|
22507
|
-
* @returns the terrain data to use in the program
|
|
22508
|
-
*/
|
|
22509
|
-
getTerrainData(tileID) {
|
|
22510
|
-
if (!this._emptyDemTexture) {
|
|
22511
|
-
const context = this.painter.context;
|
|
22512
|
-
const image = new RGBAImage({
|
|
22513
|
-
width: 1,
|
|
22514
|
-
height: 1
|
|
22515
|
-
}, /* @__PURE__ */ new Uint8Array(4));
|
|
22516
|
-
this._emptyDepthTexture = new Texture(context, image, context.gl.RGBA, { premultiply: false });
|
|
22517
|
-
this._emptyDemUnpack = [
|
|
22518
|
-
0,
|
|
22519
|
-
0,
|
|
22520
|
-
0,
|
|
22521
|
-
0
|
|
22522
|
-
];
|
|
22523
|
-
this._emptyDemTexture = new Texture(context, new RGBAImage({
|
|
22524
|
-
width: 1,
|
|
22525
|
-
height: 1
|
|
22526
|
-
}), context.gl.RGBA, { premultiply: false });
|
|
22527
|
-
this._emptyDemTexture.bind(context.gl.NEAREST, context.gl.CLAMP_TO_EDGE);
|
|
22528
|
-
this._emptyDemMatrix = identity([]);
|
|
22529
|
-
}
|
|
22530
|
-
const sourceTile = this.tileManager.getSourceTile(tileID, true);
|
|
22531
|
-
if (sourceTile?.dem && (!sourceTile.demTexture || sourceTile.needsTerrainPrepare)) {
|
|
22532
|
-
const context = this.painter.context;
|
|
22533
|
-
sourceTile.demTexture ||= this.painter.getTileTexture(sourceTile.dem.stride);
|
|
22534
|
-
if (sourceTile.demTexture) sourceTile.demTexture.update(sourceTile.dem.getPixels(), { premultiply: false });
|
|
22535
|
-
else sourceTile.demTexture = new Texture(context, sourceTile.dem.getPixels(), context.gl.RGBA, { premultiply: false });
|
|
22536
|
-
sourceTile.demTexture.bind(context.gl.NEAREST, context.gl.CLAMP_TO_EDGE);
|
|
22537
|
-
sourceTile.needsTerrainPrepare = false;
|
|
22538
|
-
}
|
|
22539
|
-
const terrainMatrix = sourceTile ? this._getDEMTileMatrix(tileID, sourceTile) : this._emptyDemMatrix;
|
|
22540
|
-
return {
|
|
22541
|
-
"u_depth": 2,
|
|
22542
|
-
"u_terrain": 3,
|
|
22543
|
-
"u_terrain_dim": sourceTile?.dem?.dim || 1,
|
|
22544
|
-
"u_terrain_matrix": terrainMatrix,
|
|
22545
|
-
"u_terrain_unpack": sourceTile?.dem?.getUnpackVector() || this._emptyDemUnpack,
|
|
22546
|
-
"u_terrain_exaggeration": this.exaggeration,
|
|
22547
|
-
texture: (sourceTile?.demTexture || this._emptyDemTexture).texture,
|
|
22548
|
-
depthTexture: (this._fboDepthTexture || this._emptyDepthTexture).texture,
|
|
22549
|
-
tile: sourceTile
|
|
22550
|
-
};
|
|
22551
|
-
}
|
|
22552
|
-
/**
|
|
22553
|
-
* get a framebuffer as big as the map-div, which will be used to render depth & coords into a texture
|
|
22554
|
-
* @param texture - the texture
|
|
22555
|
-
* @returns the frame buffer
|
|
22556
|
-
*/
|
|
22557
|
-
getFramebuffer(texture) {
|
|
22558
|
-
const painter = this.painter;
|
|
22559
|
-
const width = painter.width / devicePixelRatio;
|
|
22560
|
-
const height = painter.height / devicePixelRatio;
|
|
22561
|
-
if (this._fbo && (this._fbo.width !== width || this._fbo.height !== height)) {
|
|
22562
|
-
this._fbo.destroy();
|
|
22563
|
-
this._fboCoordsTexture.destroy();
|
|
22564
|
-
this._fboDepthTexture.destroy();
|
|
22565
|
-
delete this._fbo;
|
|
22566
|
-
delete this._fboDepthTexture;
|
|
22567
|
-
delete this._fboCoordsTexture;
|
|
22568
|
-
}
|
|
22569
|
-
if (!this._fboCoordsTexture) {
|
|
22570
|
-
this._fboCoordsTexture = new Texture(painter.context, {
|
|
22571
|
-
width,
|
|
22572
|
-
height,
|
|
22573
|
-
data: null
|
|
22574
|
-
}, painter.context.gl.RGBA, { premultiply: false });
|
|
22575
|
-
this._fboCoordsTexture.bind(painter.context.gl.NEAREST, painter.context.gl.CLAMP_TO_EDGE);
|
|
22742
|
+
this._map.off("terrain", this._updateData);
|
|
22743
|
+
this._map.off("resize", this._updateCompact);
|
|
22744
|
+
this._map.off("drag", this._updateCompactMinimize);
|
|
22745
|
+
this._map = void 0;
|
|
22746
|
+
this._compact = void 0;
|
|
22747
|
+
this._attribHTML = void 0;
|
|
22748
|
+
}
|
|
22749
|
+
_setElementTitle(element, title) {
|
|
22750
|
+
const str = this._map._getUIString(`AttributionControl.${title}`);
|
|
22751
|
+
element.title = str;
|
|
22752
|
+
element.setAttribute("aria-label", str);
|
|
22753
|
+
}
|
|
22754
|
+
_updateAttributions() {
|
|
22755
|
+
if (!this._map.style) return;
|
|
22756
|
+
let attributions = [];
|
|
22757
|
+
if (this.options.customAttribution) {
|
|
22758
|
+
if (Array.isArray(this.options.customAttribution)) attributions = attributions.concat(this.options.customAttribution.map((attribution) => {
|
|
22759
|
+
if (typeof attribution !== "string") return "";
|
|
22760
|
+
return attribution;
|
|
22761
|
+
}));
|
|
22762
|
+
else if (typeof this.options.customAttribution === "string") attributions.push(this.options.customAttribution);
|
|
22576
22763
|
}
|
|
22577
|
-
if (
|
|
22578
|
-
|
|
22579
|
-
|
|
22580
|
-
|
|
22581
|
-
data: null
|
|
22582
|
-
}, painter.context.gl.RGBA, { premultiply: false });
|
|
22583
|
-
this._fboDepthTexture.bind(painter.context.gl.NEAREST, painter.context.gl.CLAMP_TO_EDGE);
|
|
22764
|
+
if (this._map.style.stylesheet) {
|
|
22765
|
+
const stylesheet = this._map.style.stylesheet;
|
|
22766
|
+
this.styleOwner = stylesheet.owner;
|
|
22767
|
+
this.styleId = stylesheet.id;
|
|
22584
22768
|
}
|
|
22585
|
-
|
|
22586
|
-
|
|
22587
|
-
|
|
22769
|
+
const tileManagers = this._map.style.tileManagers;
|
|
22770
|
+
for (const id in tileManagers) {
|
|
22771
|
+
const tileManager = tileManagers[id];
|
|
22772
|
+
if (tileManager.used || tileManager.usedForTerrain) {
|
|
22773
|
+
const source = tileManager.getSource();
|
|
22774
|
+
if (source.attribution && !attributions.includes(source.attribution)) attributions.push(source.attribution);
|
|
22775
|
+
}
|
|
22588
22776
|
}
|
|
22589
|
-
|
|
22590
|
-
|
|
22591
|
-
|
|
22592
|
-
|
|
22593
|
-
|
|
22594
|
-
|
|
22595
|
-
|
|
22596
|
-
|
|
22597
|
-
|
|
22598
|
-
|
|
22599
|
-
|
|
22600
|
-
|
|
22601
|
-
|
|
22602
|
-
|
|
22603
|
-
|
|
22604
|
-
if (this._coordsTexture) return this._coordsTexture;
|
|
22605
|
-
const data = new Uint8Array(this._coordsTextureSize * this._coordsTextureSize * 4);
|
|
22606
|
-
for (let y = 0, i = 0; y < this._coordsTextureSize; y++) for (let x = 0; x < this._coordsTextureSize; x++, i += 4) {
|
|
22607
|
-
data[i + 0] = x & 255;
|
|
22608
|
-
data[i + 1] = y & 255;
|
|
22609
|
-
data[i + 2] = x >> 8 << 4 | y >> 8;
|
|
22610
|
-
data[i + 3] = 0;
|
|
22611
|
-
}
|
|
22612
|
-
const image = new RGBAImage({
|
|
22613
|
-
width: this._coordsTextureSize,
|
|
22614
|
-
height: this._coordsTextureSize
|
|
22615
|
-
}, new Uint8Array(data.buffer));
|
|
22616
|
-
const texture = new Texture(context, image, context.gl.RGBA, { premultiply: false });
|
|
22617
|
-
texture.bind(context.gl.NEAREST, context.gl.CLAMP_TO_EDGE);
|
|
22618
|
-
this._coordsTexture = texture;
|
|
22619
|
-
return texture;
|
|
22620
|
-
}
|
|
22621
|
-
/**
|
|
22622
|
-
* Reads a pixel from the coords-framebuffer and translate this to mercator, or null, if the pixel doesn't lie on the terrain's surface (but the sky instead).
|
|
22623
|
-
* @param p - Screen-Coordinate
|
|
22624
|
-
* @returns Mercator coordinate for a screen pixel, or null, if the pixel is not covered by terrain (is in the sky).
|
|
22625
|
-
*/
|
|
22626
|
-
pointCoordinate(p) {
|
|
22627
|
-
this.painter.maybeDrawDepth(true);
|
|
22628
|
-
this.painter.maybeDrawCoords();
|
|
22629
|
-
const rgba = /* @__PURE__ */ new Uint8Array(4);
|
|
22630
|
-
const context = this.painter.context, gl = context.gl;
|
|
22631
|
-
const px = Math.round(p.x * this.painter.pixelRatio / devicePixelRatio);
|
|
22632
|
-
const py = Math.round(p.y * this.painter.pixelRatio / devicePixelRatio);
|
|
22633
|
-
const fbHeight = Math.round(this.painter.height / devicePixelRatio);
|
|
22634
|
-
context.bindFramebuffer.set(this.getFramebuffer("coords").framebuffer);
|
|
22635
|
-
gl.readPixels(px, fbHeight - py - 1, 1, 1, gl.RGBA, gl.UNSIGNED_BYTE, rgba);
|
|
22636
|
-
context.bindFramebuffer.set(null);
|
|
22637
|
-
const x = rgba[0] + (rgba[2] >> 4 << 8);
|
|
22638
|
-
const y = rgba[1] + ((rgba[2] & 15) << 8);
|
|
22639
|
-
const tileID = this.coordsIndex[255 - rgba[3]];
|
|
22640
|
-
const tile = tileID && this.tileManager.getTileByID(tileID);
|
|
22641
|
-
if (!tile) return null;
|
|
22642
|
-
const coordsSize = this._coordsTextureSize;
|
|
22643
|
-
const worldSize = (1 << tile.tileID.canonical.z) * coordsSize;
|
|
22644
|
-
return new MercatorCoordinate((tile.tileID.canonical.x * coordsSize + x) / worldSize + tile.tileID.wrap, (tile.tileID.canonical.y * coordsSize + y) / worldSize, this.getElevation(tile.tileID, x, y, coordsSize));
|
|
22777
|
+
attributions = attributions.filter((e) => String(e).trim());
|
|
22778
|
+
attributions.sort((a, b) => a.length - b.length);
|
|
22779
|
+
attributions = attributions.filter((attrib, i) => {
|
|
22780
|
+
for (let j = i + 1; j < attributions.length; j++) if (attributions[j].includes(attrib)) return false;
|
|
22781
|
+
return true;
|
|
22782
|
+
});
|
|
22783
|
+
const attribHTML = attributions.join(" | ");
|
|
22784
|
+
if (attribHTML === this._attribHTML) return;
|
|
22785
|
+
this._attribHTML = attribHTML;
|
|
22786
|
+
if (attributions.length) {
|
|
22787
|
+
this._innerContainer.innerHTML = DOM.sanitize(attribHTML);
|
|
22788
|
+
this._container.classList.remove("maplibregl-attrib-empty");
|
|
22789
|
+
} else this._container.classList.add("maplibregl-attrib-empty");
|
|
22790
|
+
this._updateCompact();
|
|
22791
|
+
this._editLink = null;
|
|
22645
22792
|
}
|
|
22793
|
+
};
|
|
22794
|
+
//#endregion
|
|
22795
|
+
//#region src/ui/control/logo_control.ts
|
|
22796
|
+
/**
|
|
22797
|
+
* A `LogoControl` is a control that adds the watermark.
|
|
22798
|
+
*
|
|
22799
|
+
* @group Markers and Controls
|
|
22800
|
+
*
|
|
22801
|
+
* @example
|
|
22802
|
+
* ```ts
|
|
22803
|
+
* map.addControl(new LogoControl({compact: false}));
|
|
22804
|
+
* ```
|
|
22805
|
+
**/
|
|
22806
|
+
var LogoControl = class {
|
|
22646
22807
|
/**
|
|
22647
|
-
*
|
|
22648
|
-
* @param p - Screen coordinate
|
|
22649
|
-
* @returns depth value in clip space (between 0 and 1)
|
|
22808
|
+
* @param options - the control's options
|
|
22650
22809
|
*/
|
|
22651
|
-
|
|
22652
|
-
|
|
22653
|
-
|
|
22654
|
-
|
|
22655
|
-
|
|
22656
|
-
|
|
22657
|
-
|
|
22810
|
+
constructor(options = {}) {
|
|
22811
|
+
this._updateCompact = () => {
|
|
22812
|
+
const containerChildren = this._container.children;
|
|
22813
|
+
if (containerChildren.length) {
|
|
22814
|
+
const anchor = containerChildren[0];
|
|
22815
|
+
if (this._map.getCanvasContainer().offsetWidth <= 640 || this._compact) {
|
|
22816
|
+
if (this._compact !== false) anchor.classList.add("maplibregl-compact");
|
|
22817
|
+
} else anchor.classList.remove("maplibregl-compact");
|
|
22818
|
+
}
|
|
22819
|
+
};
|
|
22820
|
+
this.options = options;
|
|
22658
22821
|
}
|
|
22659
|
-
|
|
22660
|
-
|
|
22661
|
-
* @returns the created regular mesh
|
|
22662
|
-
*/
|
|
22663
|
-
getTerrainMesh(tileId) {
|
|
22664
|
-
const globeEnabled = this.painter.style.projection?.transitionState > 0;
|
|
22665
|
-
const northPole = globeEnabled && tileId.canonical.y === 0;
|
|
22666
|
-
const southPole = globeEnabled && tileId.canonical.y === (1 << tileId.canonical.z) - 1;
|
|
22667
|
-
const key = `m_${northPole ? "n" : ""}_${southPole ? "s" : ""}`;
|
|
22668
|
-
if (this._meshCache[key]) return this._meshCache[key];
|
|
22669
|
-
const context = this.painter.context;
|
|
22670
|
-
const vertexArray = new Pos3dArray();
|
|
22671
|
-
const indexArray = new TriangleIndexArray();
|
|
22672
|
-
const meshSize = this.meshSize;
|
|
22673
|
-
const delta = EXTENT / meshSize;
|
|
22674
|
-
const meshSize2 = meshSize * meshSize;
|
|
22675
|
-
for (let y = 0; y <= meshSize; y++) for (let x = 0; x <= meshSize; x++) vertexArray.emplaceBack(x * delta, y * delta, 0);
|
|
22676
|
-
for (let y = 0; y < meshSize2; y += meshSize + 1) for (let x = 0; x < meshSize; x++) {
|
|
22677
|
-
indexArray.emplaceBack(x + y, meshSize + x + y + 1, meshSize + x + y + 2);
|
|
22678
|
-
indexArray.emplaceBack(x + y, meshSize + x + y + 2, x + y + 1);
|
|
22679
|
-
}
|
|
22680
|
-
if (this._terrainSkirtLength !== "none") this._buildSkirts(vertexArray, indexArray, meshSize, delta, northPole, southPole);
|
|
22681
|
-
const mesh = new Mesh(context.createVertexBuffer(vertexArray, pos3dAttributes.members), context.createIndexBuffer(indexArray), SegmentVector.simpleSegment(0, 0, vertexArray.length, indexArray.length));
|
|
22682
|
-
this._meshCache[key] = mesh;
|
|
22683
|
-
return mesh;
|
|
22822
|
+
getDefaultPosition() {
|
|
22823
|
+
return "bottom-left";
|
|
22684
22824
|
}
|
|
22685
|
-
/**
|
|
22686
|
-
|
|
22687
|
-
|
|
22688
|
-
|
|
22689
|
-
|
|
22690
|
-
|
|
22691
|
-
|
|
22692
|
-
|
|
22825
|
+
/** {@inheritDoc IControl.onAdd} */
|
|
22826
|
+
onAdd(map) {
|
|
22827
|
+
this._map = map;
|
|
22828
|
+
this._compact = this.options?.compact;
|
|
22829
|
+
this._container = DOM.create("div", "maplibregl-ctrl");
|
|
22830
|
+
const anchor = DOM.create("a", "maplibregl-ctrl-logo");
|
|
22831
|
+
anchor.target = "_blank";
|
|
22832
|
+
anchor.rel = "noopener nofollow";
|
|
22833
|
+
anchor.href = "https://maplibre.org/";
|
|
22834
|
+
anchor.setAttribute("aria-label", this._map._getUIString("LogoControl.Title"));
|
|
22835
|
+
anchor.setAttribute("rel", "noopener nofollow");
|
|
22836
|
+
this._container.appendChild(anchor);
|
|
22837
|
+
this._container.style.display = "block";
|
|
22838
|
+
this._map.on("resize", this._updateCompact);
|
|
22839
|
+
this._updateCompact();
|
|
22840
|
+
return this._container;
|
|
22693
22841
|
}
|
|
22694
|
-
|
|
22695
|
-
|
|
22696
|
-
|
|
22697
|
-
|
|
22842
|
+
/** {@inheritDoc IControl.onRemove} */
|
|
22843
|
+
onRemove() {
|
|
22844
|
+
this._container.remove();
|
|
22845
|
+
this._map.off("resize", this._updateCompact);
|
|
22846
|
+
this._map = void 0;
|
|
22847
|
+
this._compact = void 0;
|
|
22698
22848
|
}
|
|
22699
|
-
|
|
22700
|
-
|
|
22701
|
-
|
|
22702
|
-
|
|
22703
|
-
|
|
22704
|
-
|
|
22705
|
-
|
|
22706
|
-
|
|
22707
|
-
|
|
22708
|
-
const tile = this.tileManager.getSourceTile(tileID, true);
|
|
22709
|
-
const minMax = {
|
|
22710
|
-
minElevation: null,
|
|
22711
|
-
maxElevation: null
|
|
22712
|
-
};
|
|
22713
|
-
if (tile?.dem) {
|
|
22714
|
-
minMax.minElevation = tile.dem.min * this.exaggeration;
|
|
22715
|
-
minMax.maxElevation = tile.dem.max * this.exaggeration;
|
|
22716
|
-
}
|
|
22717
|
-
return minMax;
|
|
22849
|
+
};
|
|
22850
|
+
//#endregion
|
|
22851
|
+
//#region src/util/task_queue.ts
|
|
22852
|
+
var TaskQueue = class {
|
|
22853
|
+
constructor() {
|
|
22854
|
+
this._queue = [];
|
|
22855
|
+
this._id = 0;
|
|
22856
|
+
this._cleared = false;
|
|
22857
|
+
this._currentlyRunning = false;
|
|
22718
22858
|
}
|
|
22719
|
-
|
|
22720
|
-
const
|
|
22721
|
-
|
|
22722
|
-
|
|
22723
|
-
|
|
22724
|
-
|
|
22725
|
-
|
|
22726
|
-
|
|
22727
|
-
mercatorX,
|
|
22728
|
-
mercatorY
|
|
22729
|
-
};
|
|
22859
|
+
add(callback) {
|
|
22860
|
+
const id = ++this._id;
|
|
22861
|
+
this._queue.push({
|
|
22862
|
+
callback,
|
|
22863
|
+
id,
|
|
22864
|
+
cancelled: false
|
|
22865
|
+
});
|
|
22866
|
+
return id;
|
|
22730
22867
|
}
|
|
22731
|
-
|
|
22732
|
-
|
|
22733
|
-
|
|
22734
|
-
|
|
22735
|
-
|
|
22736
|
-
|
|
22737
|
-
const offsetBottom = offsetTop + (meshSize + 1);
|
|
22738
|
-
const offsetBottomEdge = (meshSize + 1) * meshSize;
|
|
22739
|
-
const northY = northPole ? NORTH_POLE_Y : 0;
|
|
22740
|
-
const northZ = northPole ? 0 : 1;
|
|
22741
|
-
const southY = southPole ? SOUTH_POLE_Y : EXTENT;
|
|
22742
|
-
const southZ = southPole ? 0 : 1;
|
|
22743
|
-
for (let x = 0; x <= meshSize; x++) vertexArray.emplaceBack(x * delta, northY, northZ);
|
|
22744
|
-
for (let x = 0; x <= meshSize; x++) vertexArray.emplaceBack(x * delta, southY, southZ);
|
|
22745
|
-
for (let x = 0; x < meshSize; x++) {
|
|
22746
|
-
indexArray.emplaceBack(offsetBottomEdge + x, offsetBottom + x, offsetBottom + x + 1);
|
|
22747
|
-
indexArray.emplaceBack(offsetBottomEdge + x, offsetBottom + x + 1, offsetBottomEdge + x + 1);
|
|
22748
|
-
indexArray.emplaceBack(offsetTopEdge + x, offsetTop + x + 1, offsetTop + x);
|
|
22749
|
-
indexArray.emplaceBack(offsetTopEdge + x, offsetTopEdge + x + 1, offsetTop + x + 1);
|
|
22868
|
+
remove(id) {
|
|
22869
|
+
const running = this._currentlyRunning;
|
|
22870
|
+
const queue = running ? this._queue.concat(running) : this._queue;
|
|
22871
|
+
for (const task of queue) if (task.id === id) {
|
|
22872
|
+
task.cancelled = true;
|
|
22873
|
+
return;
|
|
22750
22874
|
}
|
|
22751
|
-
|
|
22752
|
-
|
|
22753
|
-
|
|
22754
|
-
|
|
22755
|
-
|
|
22756
|
-
|
|
22757
|
-
|
|
22758
|
-
|
|
22875
|
+
}
|
|
22876
|
+
run(timeStamp = 0) {
|
|
22877
|
+
if (this._currentlyRunning) throw new Error("Attempting to run(), but is already running.");
|
|
22878
|
+
const queue = this._currentlyRunning = this._queue;
|
|
22879
|
+
this._queue = [];
|
|
22880
|
+
for (const task of queue) {
|
|
22881
|
+
if (task.cancelled) continue;
|
|
22882
|
+
task.callback(timeStamp);
|
|
22883
|
+
if (this._cleared) break;
|
|
22759
22884
|
}
|
|
22885
|
+
this._cleared = false;
|
|
22886
|
+
this._currentlyRunning = false;
|
|
22887
|
+
}
|
|
22888
|
+
clear() {
|
|
22889
|
+
if (this._currentlyRunning) this._cleared = true;
|
|
22890
|
+
this._queue = [];
|
|
22760
22891
|
}
|
|
22761
22892
|
};
|
|
22762
22893
|
//#endregion
|