maplibre-gl 6.4.1 → 6.5.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.
@@ -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.4.1/LICENSE.txt
3
+ * @license 3-Clause BSD. Full text of license: https://github.com/maplibre/maplibre-gl-js/blob/v6.5.0/LICENSE.txt
4
4
  */
5
5
  import { $ as tileCoordinatesToMercatorCoordinates, $n as deepEqual, $r as mul, $t as TRANSITION_SUFFIX, A as evaluateSizeForFeature, Ai as perspective, An as getVideo, Ar as remapSaturate, At as toEvaluationFeature, Bi as invert, Br as wrap, Bt as SegmentVector, C as isCustomStyleLayer, Ci as equals, Cn as Event, Cr as nextPowerOfTwo, Ct as HEATMAP_FULL_RENDER_FBO_KEY, D as SymbolBucket, Di as invert$1, Dn as getArrayBuffer, Dr as radiansToDegrees, Dt as RGBAImage, E as isSymbolStyleLayer, Ei as identity, En as GLOBAL_DISPATCHER_ID, Er as pointPlaneSignedDistance, Et as AlphaImage, F as ImagePosition, Fi as translate, Fn as removeProtocol, Fr as subscribe, Ft as Uniform4f, G as isFillExtrusionStyleLayer, Gn as bezier, Gr as length, Gt as PosArray, H as isLineStyleLayer, Hi as isOffscreenCanvasDistorted, Hn as angleToRotateBetweenVectors2D, Hr as pixelsToTileUnits, Ht as CollisionCircleLayoutArray, I as potpack, Ii as create$4, In as config, Ir as threePlaneIntersection, It as UniformColor, J as cameraDirectionFromPitchBearing, Jn as createIdentityMat4f32, Jr as zero, Jt as TriangleIndexArray, Kn as clamp, Kr as scale$1, Kt as QuadTriangleArray, L as isStyleImageWebGLData, Li as fromRotation, Ln as AbortError, Lr as translatePosition, Lt as UniformColorArray, Mi as rotateY$1, Mn as sameOrigin, Mr as rollPitchBearingToQuat, Mt as Uniform1i, N as getAnchorAlignment, Ni as rotateZ, Nn as addProtocol, Nr as scaleZoom, Nt as Uniform2f, O as addDynamicAttributes, Oi as multiply, On as getJSON, Or as rayPlaneIntersection, Ot as isCircleStyleLayer, Pi as scale, Pn as getProtocol, Pr as sphericalToCartesian, Pt as Uniform3f, Q as projectToWorldCoordinates, Qn as createVec4f64, Qr as slerp, Qt as Properties, R as renderStyleImage, Ri as create$2, Rn as isAbortError, Rr as uniqueId, Rt as UniformFloatArray, S as createStyleLayer, Si as create$1, Sn as ErrorEvent, Sr as mod, St as isHillshadeStyleLayer, T as isBackgroundStyleLayer, Ti as fromScaling, Tn as AJAXError, Tr as pick, Tt as renderColorRamp, Ui as offscreenCanvasSupported, Un as arrayBufferToImage, Ur as EXTENT, Ut as LineStripIndexArray, V as collisionCircleLayout, Vi as rotate, Vn as MAX_VALID_LATITUDE, Vr as zoomScale, Vt as CollisionBoxArray, Wi as Point, Wn as arrayBufferToImageBitmap, Wr as create$3, Wt as Pos3dArray, X as getMercatorHorizon, Xn as createMat4f64, Xr as fromValues, Xt as isRasterStyleLayer, Y as cameraMercatorCoordinateFromCenterAndRotation, Yn as createIdentityMat4f64, Yr as fromEuler, Yt as createLayout, Z as maxMercatorHorizonAngle, Zn as createVec3f64, Zr as multiply$1, Zt as DataConstantProperty, _ as UnwrappedTileID, _i as transformMat4$1, _n as emptyStyle, _r as isTouchableEvent, _t as SubdivisionGranularityExpression, a as clipLine, ai as dot, ar as evaluateZoomSnap, at as mercatorXfromLng, b as isInBoundsForZoomLngLat, bi as clone$1, bn as interpolateFactory, br as lerp, ci as negate, cn as validateAndEmit, cr as findLineIntersection, ct as LngLat, di as rotateY, dn as Color, dr as getEdgeTiles, dt as EXTENT_BOUNDS, ei as scale$3, en as Transitionable, er as defaultEasing, et as unprojectFromWorldCoordinates, f as GEOJSON_TILE_LAYER_NAME, fi as rotateZ$1, fn as ProjectionDefinition, ft as Bounds, g as OverscaledTileID, gi as transformMat3, gn as diff, gr as isSafari, gt as SOUTH_POLE_Y, h as CanonicalTileID, hi as sub, hn as derefLayers, hr as isPointableEvent, ht as NORTH_POLE_Y, ii as cross, in as ZoomHistory, ir as ensureError, it as lngFromMercatorX, j as evaluateSizeForZoom, ji as rotateX, jn as makeRequest, jr as rollPitchBearingEqual, jt as Uniform1f, k as getOverlapMode, ki as ortho, kn as getReferrer, kr as readImageUsingVideoFrame, kt as polygonIntersectsPolygon, li as normalize, ln as validateStyle, lr as getAABB, lt as earthRadius, mi as scaleAndAdd, mr as isImageBitmap, ni as add, nr as differenceOfAnglesDegrees, nt as altitudeFromMercatorZ, oi as len, on as SPEC_SOURCE_TYPES, or as extend, ot as mercatorYfromLat, pi as scale$2, pn as ValidationError, pr as getRollPitchBearing, pt as isFillStyleLayer, q as calculateTileMatrix, qn as clone$2, qr as sqrLen, qt as RasterBoundsArray, r as TextAnchorEnum, ri as clone, rn as codePointUsesLocalIdeographFontFamily, rr as distanceOfAnglesRadians, rt as latFromMercatorY, s as TileCache, si as length$1, sn as emitValidationErrors, sr as filterObject, st as mercatorZfromAltitude, t as getAnchorJustification, ti as transformMat4, tn as EvaluationParameters, tr as degreesToRadians, tt as MercatorCoordinate, u as GeoJSONFeature, ui as rotateX$1, un as validateStyleAndEmit, ur as getAngleDelta, v as calculateTileKey, vi as transformQuat, vn as featureFilter, vr as isTouchableOrPointableType, vt as SubdivisionGranularitySetting, w as validateCustomStyleLayer, wi as exactEquals, wn as Evented, wr as parseCacheControl, wt as isHeatmapStyleLayer, x as Actor, xi as copy, xn as latest, xr as mapObject, xt as Texture, y as compareTileId, yi as zero$1, yr as isWorker, yt as isColorReliefStyleLayer, z as parseGlyphPbf, zi as determinant, zn as throwIfAborted, zr as warnOnce, zt as UniformMatrix4f } from "./maplibre-gl-shared-dev.mjs";
6
6
  //#region package.json
7
- var version$2 = "6.4.1";
7
+ var version$2 = "6.5.0";
8
8
  //#endregion
9
9
  //#region src/util/browser.ts
10
10
  let linkEl;
@@ -3808,10 +3808,8 @@ var GeoJSONSource = class extends Evented {
3808
3808
  };
3809
3809
  //#endregion
3810
3810
  //#region src/webgl/program/raster_program.ts
3811
- /**
3812
- * Affine texture coordinates represented as a homogeneous transform.
3813
- */
3814
- const identityPerspectiveTransform = [
3811
+ /** The bilinear warp, which is also the affine one that a rectangle or a parallelogram needs. */
3812
+ const bilinearImageWarp = [
3815
3813
  0,
3816
3814
  0,
3817
3815
  1
@@ -3820,7 +3818,7 @@ const rasterUniforms = (context, locations) => ({
3820
3818
  "u_tl_parent": new Uniform2f(context, locations.u_tl_parent),
3821
3819
  "u_scale_parent": new Uniform1f(context, locations.u_scale_parent),
3822
3820
  "u_buffer_scale": new Uniform1f(context, locations.u_buffer_scale),
3823
- "u_perspective_transform": new Uniform3f(context, locations.u_perspective_transform),
3821
+ "u_image_warp": new Uniform3f(context, locations.u_image_warp),
3824
3822
  "u_fade_t": new Uniform1f(context, locations.u_fade_t),
3825
3823
  "u_opacity": new Uniform1f(context, locations.u_opacity),
3826
3824
  "u_image0": new Uniform1i(context, locations.u_image0),
@@ -3833,11 +3831,11 @@ const rasterUniforms = (context, locations) => ({
3833
3831
  "u_coords_top": new Uniform4f(context, locations.u_coords_top),
3834
3832
  "u_coords_bottom": new Uniform4f(context, locations.u_coords_bottom)
3835
3833
  });
3836
- const rasterUniformValues = (parentTL, parentScaleBy, fade, layer, cornerCoords, perspectiveTransform) => ({
3834
+ const rasterUniformValues = (parentTL, parentScaleBy, fade, layer, cornerCoords, imageWarp) => ({
3837
3835
  "u_tl_parent": parentTL,
3838
3836
  "u_scale_parent": parentScaleBy,
3839
3837
  "u_buffer_scale": 1,
3840
- "u_perspective_transform": perspectiveTransform,
3838
+ "u_image_warp": imageWarp,
3841
3839
  "u_fade_t": fade.mix,
3842
3840
  "u_opacity": fade.opacity * layer.paint.get("raster-opacity"),
3843
3841
  "u_image0": 0,
@@ -3877,8 +3875,150 @@ function saturationFactor(saturation) {
3877
3875
  return saturation > 0 ? 1 - 1 / (1.001 - saturation) : -saturation;
3878
3876
  }
3879
3877
  //#endregion
3878
+ //#region src/render/mesh.ts
3879
+ var Mesh = class {
3880
+ constructor(vertexBuffer, indexBuffer, segments) {
3881
+ this.vertexBuffer = vertexBuffer;
3882
+ this.indexBuffer = indexBuffer;
3883
+ this.segments = segments;
3884
+ }
3885
+ destroy() {
3886
+ this.vertexBuffer.destroy();
3887
+ this.indexBuffer.destroy();
3888
+ this.segments.destroy();
3889
+ this.vertexBuffer = null;
3890
+ this.indexBuffer = null;
3891
+ this.segments = null;
3892
+ }
3893
+ };
3894
+ //#endregion
3895
+ //#region src/data/pos_attributes.ts
3896
+ const posAttributes = createLayout([{
3897
+ name: "a_pos",
3898
+ type: "Int16",
3899
+ components: 2
3900
+ }]);
3901
+ //#endregion
3902
+ //#region src/util/create_tile_mesh.ts
3903
+ /**
3904
+ * The size of border region for stencil masks, in internal tile coordinates.
3905
+ * Used for globe rendering.
3906
+ */
3907
+ const EXTENT_STENCIL_BORDER = EXTENT / 128;
3908
+ /**
3909
+ * @internal
3910
+ * Creates a mesh of a quad that covers the entire tile (covering positions in range 0..EXTENT),
3911
+ * is optionally subdivided into finer quads, optionally includes a border
3912
+ * and optionally extends to the north and/or special pole vertices.
3913
+ * Also allocates and populates WebGL buffers for the mesh.
3914
+ * Forces 16 bit indices that are used throughout MapLibre.
3915
+ * @param context - The WebGL context wrapper.
3916
+ * @param options - Specify options for tile mesh creation such as granularity or border.
3917
+ * @returns The mesh vertices and indices, already allocated and uploaded into WebGL buffers.
3918
+ */
3919
+ function createTileMeshWithBuffers(context, options) {
3920
+ const tileMesh = createTileMesh(options, "16bit");
3921
+ const vertices = PosArray.deserialize({
3922
+ arrayBuffer: tileMesh.vertices,
3923
+ length: tileMesh.vertices.byteLength / 2 / 2
3924
+ });
3925
+ const indices = TriangleIndexArray.deserialize({
3926
+ arrayBuffer: tileMesh.indices,
3927
+ length: tileMesh.indices.byteLength / 2 / 3
3928
+ });
3929
+ return new Mesh(context.createVertexBuffer(vertices, posAttributes.members), context.createIndexBuffer(indices), SegmentVector.simpleSegment(0, 0, vertices.length, indices.length));
3930
+ }
3931
+ /**
3932
+ * Creates a mesh of a quad that covers the entire tile (covering positions in range 0..EXTENT),
3933
+ * is optionally subdivided into finer quads, optionally includes a border
3934
+ * and optionally extends to the north and/or special pole vertices.
3935
+ * Additionally the resulting mesh indices type can be specified using `forceIndicesSize`.
3936
+ * @example
3937
+ * ```
3938
+ * // Creating a mesh for a tile that can be used for raster layers, hillshade, etc.
3939
+ * const meshBuffers = createTileMesh({
3940
+ * granularity: map.style.projection.subdivisionGranularity.tile.getGranularityForZoomLevel(tileID.z),
3941
+ * generateBorders: true,
3942
+ * extendToNorthPole: tileID.y === 0,
3943
+ * extendToSouthPole: tileID.y === (1 << tileID.z) - 1,
3944
+ * }, '16bit');
3945
+ * ```
3946
+ * @see [Add a custom layer with tiles to a globe](https://maplibre.org/maplibre-gl-js/docs/examples/add-a-custom-layer-with-tiles-to-a-globe/)
3947
+ * @param options - Specify options for tile mesh creation such as granularity or border.
3948
+ * @param forceIndicesSize - Specifies what indices type to use. The values '32bit' and '16bit' force their respective indices size. If undefined, the mesh may use either size, and will pick 16 bit indices if possible. If '16bit' is specified and the mesh exceeds 65536 vertices, an exception is thrown.
3949
+ * @returns Typed arrays of the mesh vertices and indices.
3950
+ */
3951
+ function createTileMesh(options, forceIndicesSize) {
3952
+ const granularity = options.granularity !== void 0 ? Math.max(options.granularity, 1) : 1;
3953
+ const quadsPerAxisX = granularity + (options.generateBorders ? 2 : 0);
3954
+ const quadsPerAxisY = granularity + (options.extendToNorthPole || options.generateBorders ? 1 : 0) + (options.extendToSouthPole || options.generateBorders ? 1 : 0);
3955
+ const verticesPerAxisX = quadsPerAxisX + 1;
3956
+ const verticesPerAxisY = quadsPerAxisY + 1;
3957
+ const offsetX = options.generateBorders ? -1 : 0;
3958
+ const offsetY = options.generateBorders || options.extendToNorthPole ? -1 : 0;
3959
+ const endX = granularity + (options.generateBorders ? 1 : 0);
3960
+ const endY = granularity + (options.generateBorders || options.extendToSouthPole ? 1 : 0);
3961
+ const vertexCount = verticesPerAxisX * verticesPerAxisY;
3962
+ const indexCount = quadsPerAxisX * quadsPerAxisY * 6;
3963
+ const overflows16bitIndices = verticesPerAxisX * verticesPerAxisY > 65536;
3964
+ if (overflows16bitIndices && forceIndicesSize === "16bit") throw new Error("Granularity is too large and meshes would not fit inside 16 bit vertex indices.");
3965
+ const use32bitIndices = overflows16bitIndices || forceIndicesSize === "32bit";
3966
+ const vertices = new Int16Array(vertexCount * 2);
3967
+ let vertexId = 0;
3968
+ for (let y = offsetY; y <= endY; y++) for (let x = offsetX; x <= endX; x++) {
3969
+ let vx = x / granularity * EXTENT;
3970
+ if (x === -1) vx = -EXTENT_STENCIL_BORDER;
3971
+ if (x === granularity + 1) vx = EXTENT + EXTENT_STENCIL_BORDER;
3972
+ let vy = y / granularity * EXTENT;
3973
+ if (y === -1) vy = options.extendToNorthPole ? NORTH_POLE_Y : -EXTENT_STENCIL_BORDER;
3974
+ if (y === granularity + 1) vy = options.extendToSouthPole ? SOUTH_POLE_Y : EXTENT + EXTENT_STENCIL_BORDER;
3975
+ vertices[vertexId++] = vx;
3976
+ vertices[vertexId++] = vy;
3977
+ }
3978
+ const indices = use32bitIndices ? new Uint32Array(indexCount) : new Uint16Array(indexCount);
3979
+ let indexId = 0;
3980
+ for (let y = 0; y < quadsPerAxisY; y++) for (let x = 0; x < quadsPerAxisX; x++) {
3981
+ const v0 = x + y * verticesPerAxisX;
3982
+ const v1 = x + 1 + y * verticesPerAxisX;
3983
+ const v2 = x + (y + 1) * verticesPerAxisX;
3984
+ const v3 = x + 1 + (y + 1) * verticesPerAxisX;
3985
+ indices[indexId++] = v0;
3986
+ indices[indexId++] = v2;
3987
+ indices[indexId++] = v1;
3988
+ indices[indexId++] = v1;
3989
+ indices[indexId++] = v2;
3990
+ indices[indexId++] = v3;
3991
+ }
3992
+ return {
3993
+ vertices: vertices.buffer.slice(0),
3994
+ indices: indices.buffer.slice(0),
3995
+ uses32bitIndices: use32bitIndices
3996
+ };
3997
+ }
3998
+ //#endregion
3880
3999
  //#region src/source/image_source.ts
3881
4000
  /**
4001
+ * How many grid cells per axis the mesh of a subdivided quad has. Within a cell the bilinear warp
4002
+ * is still approximated by one mapping per triangle, so the error falls off with the cell size.
4003
+ */
4004
+ const SUBDIVIDED_QUAD_GRANULARITY = 16;
4005
+ /**
4006
+ * How much a warp may foreshorten the image, as the ratio between the largest and the smallest
4007
+ * homogeneous denominator over the quad, while staying purely projective. Ordinary oblique imagery
4008
+ * stays well below it.
4009
+ */
4010
+ const PROJECTIVE_FORESHORTENING = 4;
4011
+ /**
4012
+ * The foreshortening at which a warp is taken to be purely bilinear.
4013
+ *
4014
+ * The denominator vanishes on the warp's vanishing line, and that line touches the quad exactly when
4015
+ * the quad degenerates into a triangle, so foreshortening grows without bound as a corner approaches
4016
+ * the diagonal between its neighbours. Left alone, such a quad keeps a valid but wildly lopsided
4017
+ * warp, squeezing nearly the whole image into a sliver along one edge and magnifying a handful of
4018
+ * texels over the rest of the quad.
4019
+ */
4020
+ const BILINEAR_FORESHORTENING = 512;
4021
+ /**
3882
4022
  * A data source containing an image.
3883
4023
  * (See the [Style Specification](https://maplibre.org/maplibre-style-spec/#sources-image) for detailed documentation of options.)
3884
4024
  *
@@ -3929,9 +4069,12 @@ var ImageSource = class extends Evented {
3929
4069
  /** @internal */
3930
4070
  constructor(id, options, dispatcher, eventedParent) {
3931
4071
  super();
3932
- this.perspectiveTransform = identityPerspectiveTransform;
4072
+ this.imageWarp = bilinearImageWarp;
3933
4073
  this.flippedWindingOrder = false;
4074
+ this._warp = "auto";
3934
4075
  this._imageDirty = false;
4076
+ this._subdividedQuad = false;
4077
+ this._subdividedMesh = null;
3935
4078
  this.id = id;
3936
4079
  this.dispatcher = dispatcher;
3937
4080
  this.coordinates = options.coordinates;
@@ -4000,6 +4143,23 @@ var ImageSource = class extends Evented {
4000
4143
  this.image = image;
4001
4144
  this._imageDirty = true;
4002
4145
  }
4146
+ /**
4147
+ * @internal
4148
+ * The mesh the image is drawn with, or null to use the tile mesh of the current projection.
4149
+ *
4150
+ * The raster vertex shader evaluates {@link imageWarp} per vertex, so a pair of triangles only
4151
+ * samples it at the four corners. That is enough for the affine mapping of a parallelogram, and
4152
+ * for a purely projective mapping, whose straight lines survive linear interpolation across the
4153
+ * diagonal. Anything in between is neither, and would be textured as two independently warped
4154
+ * halves with a visible seam along that diagonal, so it needs the warp evaluated per grid cell.
4155
+ *
4156
+ * A projection that subdivides its own tile meshes already does this, so it keeps them.
4157
+ */
4158
+ getMesh(context, projectionSubdividesTiles) {
4159
+ if (!this._subdividedQuad || projectionSubdividesTiles) return null;
4160
+ this._subdividedMesh ??= createTileMeshWithBuffers(context, { granularity: SUBDIVIDED_QUAD_GRANULARITY });
4161
+ return this._subdividedMesh;
4162
+ }
4003
4163
  /** Teardown only: dropping the reference alone leaves the allocation to the GC. */
4004
4164
  _disposeTexture() {
4005
4165
  this.texture?.destroy();
@@ -4021,10 +4181,42 @@ var ImageSource = class extends Evented {
4021
4181
  this._abortController = null;
4022
4182
  }
4023
4183
  this._disposeTexture();
4184
+ this._subdividedMesh?.destroy();
4185
+ this._subdividedMesh = null;
4024
4186
  this.image = null;
4025
4187
  this.tiles = {};
4026
4188
  }
4027
4189
  /**
4190
+ * @experimental
4191
+ * Sets how the image is warped onto its coordinates and re-renders the map.
4192
+ *
4193
+ * This only has an effect while the coordinates do not form a rectangle, and it is not part of
4194
+ * the style specification, so it does not survive `map.setStyle`.
4195
+ *
4196
+ * @param warp - The warp to use, see {@link ImageSourceWarp}.
4197
+ *
4198
+ * @example
4199
+ * ```ts
4200
+ * // Keep the image pinned to its corners while the user drags them around.
4201
+ * map.getSource('some id').setWarp('flat');
4202
+ * ```
4203
+ */
4204
+ setWarp(warp) {
4205
+ if (this._warp === warp) return this;
4206
+ this._warp = warp;
4207
+ if (this.tileCoords) this.setCoordinates(this.coordinates);
4208
+ return this;
4209
+ }
4210
+ /**
4211
+ * @experimental
4212
+ * Returns how the image is warped onto its coordinates.
4213
+ *
4214
+ * @returns The warp in use, see {@link ImageSourceWarp}.
4215
+ */
4216
+ getWarp() {
4217
+ return this._warp;
4218
+ }
4219
+ /**
4028
4220
  * Sets the image's coordinates and re-renders the map.
4029
4221
  *
4030
4222
  * @param coordinates - Four geographical coordinates,
@@ -4039,7 +4231,8 @@ var ImageSource = class extends Evented {
4039
4231
  this.terrainTileRanges = this._getOverlappingTileRanges(cornerCoords);
4040
4232
  this.minzoom = this.maxzoom = this.tileID.z;
4041
4233
  this.tileCoords = cornerCoords.map((coord) => this.tileID.getTilePoint(coord)._round());
4042
- this.perspectiveTransform = calculateRasterPerspectiveTransform(this.tileCoords);
4234
+ this.imageWarp = calculateImageWarp(this.tileCoords, this._warp);
4235
+ this._subdividedQuad = this.imageWarp[2] > 0 && !isParallelogram(this.tileCoords);
4043
4236
  this.flippedWindingOrder = hasWrongWindingOrder(this.tileCoords);
4044
4237
  this.fire(new MapSourceDataEvent("data", { sourceDataType: "content" }));
4045
4238
  return this;
@@ -4137,13 +4330,11 @@ function hasWrongWindingOrder(coords) {
4137
4330
  const e1x = coords[2].x - coords[0].x;
4138
4331
  return e0x * (coords[2].y - coords[0].y) - e0y * e1x < 0;
4139
4332
  }
4140
- const perspectiveEpsilon = Number.EPSILON;
4141
- const perspectiveErrorFactor = 8;
4142
4333
  /**
4143
- * Calculates the inverse-homography denominator used to sample non-affine
4144
- * image-source texture coordinates. Image source tile coordinates are rounded
4145
- * to integers before this runs, so singularity checks use exact zero or
4146
- * Number.EPSILON scaled to the corner denominators.
4334
+ * How the image is warped onto its coordinates, given the corners in tile space and what the user
4335
+ * asked for. The projective warp is the perspective view of a plane, so it is the one a photograph
4336
+ * wants; the bilinear warp is a rubber sheet pinned at the corners, and is the only one left once
4337
+ * the corners stop describing a perspective view at all.
4147
4338
  *
4148
4339
  * Based on Paul S. Heckbert, "Fundamentals of Texture Mapping and Image
4149
4340
  * Warping", UCB/CSD-89-516, 1989, section 2.2.3 and appendix A.2.
@@ -4151,68 +4342,50 @@ const perspectiveErrorFactor = 8;
4151
4342
  * @see https://www2.eecs.berkeley.edu/Pubs/TechRpts/1989/5504.html
4152
4343
  * @see https://www.cs.cmu.edu/~ph/texfund/texfund.pdf
4153
4344
  */
4154
- function calculateRasterPerspectiveTransform(cornerCoords) {
4155
- if (isParallelogram(cornerCoords)) return identityPerspectiveTransform;
4345
+ function calculateImageWarp(cornerCoords, warp) {
4346
+ if (warp === "flat" || isParallelogram(cornerCoords)) return bilinearImageWarp;
4156
4347
  const [topLeft, topRight, bottomRight, bottomLeft] = cornerCoords;
4157
- const sx = topLeft.x - topRight.x + bottomRight.x - bottomLeft.x;
4158
- const sy = topLeft.y - topRight.y + bottomRight.y - bottomLeft.y;
4159
- const dx1 = topRight.x - bottomRight.x;
4160
- const dy1 = topRight.y - bottomRight.y;
4161
- const dx2 = bottomLeft.x - bottomRight.x;
4162
- const dy2 = bottomLeft.y - bottomRight.y;
4163
- const determinant$1 = determinant([
4164
- dx1,
4165
- dy1,
4166
- dx2,
4167
- dy2
4168
- ]);
4169
- if (Math.abs(determinant$1) < perspectiveEpsilon) return identityPerspectiveTransform;
4170
- const perspectiveX = (sx * dy2 - dx2 * sy) / determinant$1;
4171
- const perspectiveY = (dx1 * sy - sx * dy1) / determinant$1;
4172
- const forwardDenominators = [
4348
+ const sumX = topLeft.x - topRight.x + bottomRight.x - bottomLeft.x;
4349
+ const sumY = topLeft.y - topRight.y + bottomRight.y - bottomLeft.y;
4350
+ const basis = [
4351
+ topRight.x - bottomRight.x,
4352
+ topRight.y - bottomRight.y,
4353
+ bottomLeft.x - bottomRight.x,
4354
+ bottomLeft.y - bottomRight.y
4355
+ ];
4356
+ const [rightX, rightY, downX, downY] = basis;
4357
+ const determinant$1 = determinant(basis);
4358
+ const perspectiveX = (sumX * downY - downX * sumY) / determinant$1;
4359
+ const perspectiveY = (rightX * sumY - sumX * rightY) / determinant$1;
4360
+ const denominators = [
4173
4361
  1,
4174
4362
  1 + perspectiveX,
4175
4363
  1 + perspectiveX + perspectiveY,
4176
4364
  1 + perspectiveY
4177
4365
  ];
4178
- const forwardDenominatorScale = Math.max(...forwardDenominators.map((value) => Math.abs(value)));
4179
- const hasInvalidForwardDenominator = forwardDenominators.some((value) => !Number.isFinite(value) || value <= perspectiveErrorFactor * perspectiveEpsilon * forwardDenominatorScale);
4180
- if (!Number.isFinite(forwardDenominatorScale) || forwardDenominatorScale === 0 || hasInvalidForwardDenominator) return identityPerspectiveTransform;
4181
- const a = topRight.x - topLeft.x + perspectiveX * topRight.x;
4182
- const b = bottomLeft.x - topLeft.x + perspectiveY * bottomLeft.x;
4183
- const d = topRight.y - topLeft.y + perspectiveX * topRight.y;
4184
- const e = bottomLeft.y - topLeft.y + perspectiveY * bottomLeft.y;
4185
- const inverseDenominator = [
4186
- 0,
4187
- 0,
4188
- 0
4366
+ const foreshortening = Math.max(...denominators) / Math.min(...denominators);
4367
+ const blend = warp === "perspective" ? 0 : bilinearBlend(foreshortening);
4368
+ if (!(foreshortening >= 1 && foreshortening <= BILINEAR_FORESHORTENING) || blend >= 1) return bilinearImageWarp;
4369
+ return [
4370
+ perspectiveX,
4371
+ perspectiveY,
4372
+ blend
4189
4373
  ];
4190
- cross(inverseDenominator, [
4191
- a,
4192
- d,
4193
- perspectiveX
4194
- ], [
4195
- b,
4196
- e,
4197
- perspectiveY
4198
- ]);
4199
- const normalizationScale = Math.max(...inverseDenominator.map((value) => Math.abs(value)));
4200
- const cornerDenominators = cornerCoords.map(({ x, y }) => dot(inverseDenominator, [
4201
- x,
4202
- y,
4203
- 1
4204
- ]));
4205
- const cornerDenominatorErrors = cornerCoords.map(({ x, y }) => perspectiveErrorFactor * perspectiveEpsilon * (Math.abs(inverseDenominator[0] * x) + Math.abs(inverseDenominator[1] * y) + Math.abs(inverseDenominator[2])));
4206
- const denominatorScale = Math.max(...cornerDenominators.map((value) => Math.abs(value)));
4207
- const denominatorSign = Math.sign(cornerDenominators[0]);
4208
- const hasInvalidDenominator = cornerDenominators.some((value, index) => !Number.isFinite(value) || Math.abs(value) <= Math.max(perspectiveEpsilon * denominatorScale, cornerDenominatorErrors[index]) || Math.sign(value) !== denominatorSign);
4209
- if (!Number.isFinite(normalizationScale) || normalizationScale === 0 || !Number.isFinite(denominatorScale) || denominatorScale === 0 || hasInvalidDenominator) return identityPerspectiveTransform;
4210
- const transform = inverseDenominator.map((value) => value / normalizationScale);
4211
- return transform.every(Number.isFinite) ? transform : identityPerspectiveTransform;
4374
+ }
4375
+ /**
4376
+ * How far a warp of the given foreshortening is blended towards the bilinear one, ramping from
4377
+ * purely projective at {@link PROJECTIVE_FORESHORTENING} to purely bilinear at
4378
+ * {@link BILINEAR_FORESHORTENING}. Blending rather than switching keeps the image continuous as the
4379
+ * quad is reshaped: the two warps only agree for a parallelogram, and diverge by roughly a tenth of
4380
+ * the quad per unit of foreshortening, so a switch would visibly displace the image.
4381
+ */
4382
+ function bilinearBlend(foreshortening) {
4383
+ const ramp = (1 - PROJECTIVE_FORESHORTENING / foreshortening) / (1 - PROJECTIVE_FORESHORTENING / BILINEAR_FORESHORTENING);
4384
+ return Math.max(0, ramp);
4212
4385
  }
4213
4386
  function isParallelogram(cornerCoords) {
4214
- const [tl, tr, br, bl] = cornerCoords;
4215
- return Math.abs(tl.x + br.x - tr.x - bl.x) < perspectiveEpsilon && Math.abs(tl.y + br.y - tr.y - bl.y) < perspectiveEpsilon;
4387
+ const [topLeft, topRight, bottomRight, bottomLeft] = cornerCoords;
4388
+ return topLeft.x + bottomRight.x === topRight.x + bottomLeft.x && topLeft.y + bottomRight.y === topRight.y + bottomLeft.y;
4216
4389
  }
4217
4390
  //#endregion
4218
4391
  //#region src/source/video_source.ts
@@ -8604,7 +8777,7 @@ const shaders = {
8604
8777
  lineSDF: prepare("uniform lowp float u_device_pixel_ratio;uniform lowp float u_lineatlas_width;uniform sampler2D u_image;uniform float u_mix;in vec2 v_normal;flat in vec2 v_width2;in vec2 v_tex_a;in vec2 v_tex_b;in float v_gamma_scale;\n#ifdef GLOBE\nin float v_depth;\n#endif\n#pragma maplibre: define highp vec4 color\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 highp vec4 color\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);float sdfdist_a=texture(u_image,v_tex_a).a;float sdfdist_b=texture(u_image,v_tex_b).a;float sdfdist=mix(sdfdist_a,sdfdist_b,u_mix);float sdfgamma=(u_lineatlas_width/256.0/u_device_pixel_ratio)/min(dasharray_from.w,dasharray_to.w);alpha*=smoothstep(0.5-sdfgamma/floorwidth,0.5+sdfgamma/floorwidth,sdfdist);fragColor=color*(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;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_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 vec2 v_tex_a;out vec2 v_tex_b;out float v_gamma_scale;\n#ifdef GLOBE\nout float v_depth;\n#endif\n#pragma maplibre: define highp vec4 color\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 highp vec4 color\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;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);}"),
8605
8778
  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);}"),
8606
8779
  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;}"),
8607
- 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_perspective_transform;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 position=mix(mix(u_coords_top.xy,u_coords_top.zw,fractionalPos.x),mix(u_coords_bottom.xy,u_coords_bottom.zw,fractionalPos.x),fractionalPos.y);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=dot(u_perspective_transform,vec3(position,1.0));v_pos0=vec3(texturePos*perspectiveRatio,perspectiveRatio);vec2 parentPos=(texturePos*u_scale_parent)+u_tl_parent;v_pos1=vec3(parentPos*perspectiveRatio,perspectiveRatio);}"),
8780
+ 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);}"),
8608
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;}"),
8609
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);}"),
8610
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;}"),
@@ -8696,30 +8869,6 @@ uniform ${precision} ${type} u_${name};
8696
8869
  };
8697
8870
  }
8698
8871
  //#endregion
8699
- //#region src/render/mesh.ts
8700
- var Mesh = class {
8701
- constructor(vertexBuffer, indexBuffer, segments) {
8702
- this.vertexBuffer = vertexBuffer;
8703
- this.indexBuffer = indexBuffer;
8704
- this.segments = segments;
8705
- }
8706
- destroy() {
8707
- this.vertexBuffer.destroy();
8708
- this.indexBuffer.destroy();
8709
- this.segments.destroy();
8710
- this.vertexBuffer = null;
8711
- this.indexBuffer = null;
8712
- this.segments = null;
8713
- }
8714
- };
8715
- //#endregion
8716
- //#region src/data/pos_attributes.ts
8717
- const posAttributes = createLayout([{
8718
- name: "a_pos",
8719
- type: "Int16",
8720
- components: 2
8721
- }]);
8722
- //#endregion
8723
8872
  //#region src/geo/projection/mercator_projection.ts
8724
8873
  const MercatorShaderDefine = "#define PROJECTION_MERCATOR";
8725
8874
  const MercatorShaderVariantKey = "mercator";
@@ -10626,103 +10775,6 @@ var MercatorCameraHelper = class {
10626
10775
  let properties;
10627
10776
  const getProperties = () => properties = properties || new Properties({ "type": new DataConstantProperty(latest["projection"]["type"], "type") });
10628
10777
  //#endregion
10629
- //#region src/util/create_tile_mesh.ts
10630
- /**
10631
- * The size of border region for stencil masks, in internal tile coordinates.
10632
- * Used for globe rendering.
10633
- */
10634
- const EXTENT_STENCIL_BORDER = EXTENT / 128;
10635
- /**
10636
- * @internal
10637
- * Creates a mesh of a quad that covers the entire tile (covering positions in range 0..EXTENT),
10638
- * is optionally subdivided into finer quads, optionally includes a border
10639
- * and optionally extends to the north and/or special pole vertices.
10640
- * Also allocates and populates WebGL buffers for the mesh.
10641
- * Forces 16 bit indices that are used throughout MapLibre.
10642
- * @param context - The WebGL context wrapper.
10643
- * @param options - Specify options for tile mesh creation such as granularity or border.
10644
- * @returns The mesh vertices and indices, already allocated and uploaded into WebGL buffers.
10645
- */
10646
- function createTileMeshWithBuffers(context, options) {
10647
- const tileMesh = createTileMesh(options, "16bit");
10648
- const vertices = PosArray.deserialize({
10649
- arrayBuffer: tileMesh.vertices,
10650
- length: tileMesh.vertices.byteLength / 2 / 2
10651
- });
10652
- const indices = TriangleIndexArray.deserialize({
10653
- arrayBuffer: tileMesh.indices,
10654
- length: tileMesh.indices.byteLength / 2 / 3
10655
- });
10656
- return new Mesh(context.createVertexBuffer(vertices, posAttributes.members), context.createIndexBuffer(indices), SegmentVector.simpleSegment(0, 0, vertices.length, indices.length));
10657
- }
10658
- /**
10659
- * Creates a mesh of a quad that covers the entire tile (covering positions in range 0..EXTENT),
10660
- * is optionally subdivided into finer quads, optionally includes a border
10661
- * and optionally extends to the north and/or special pole vertices.
10662
- * Additionally the resulting mesh indices type can be specified using `forceIndicesSize`.
10663
- * @example
10664
- * ```
10665
- * // Creating a mesh for a tile that can be used for raster layers, hillshade, etc.
10666
- * const meshBuffers = createTileMesh({
10667
- * granularity: map.style.projection.subdivisionGranularity.tile.getGranularityForZoomLevel(tileID.z),
10668
- * generateBorders: true,
10669
- * extendToNorthPole: tileID.y === 0,
10670
- * extendToSouthPole: tileID.y === (1 << tileID.z) - 1,
10671
- * }, '16bit');
10672
- * ```
10673
- * @see [Add a custom layer with tiles to a globe](https://maplibre.org/maplibre-gl-js/docs/examples/add-a-custom-layer-with-tiles-to-a-globe/)
10674
- * @param options - Specify options for tile mesh creation such as granularity or border.
10675
- * @param forceIndicesSize - Specifies what indices type to use. The values '32bit' and '16bit' force their respective indices size. If undefined, the mesh may use either size, and will pick 16 bit indices if possible. If '16bit' is specified and the mesh exceeds 65536 vertices, an exception is thrown.
10676
- * @returns Typed arrays of the mesh vertices and indices.
10677
- */
10678
- function createTileMesh(options, forceIndicesSize) {
10679
- const granularity = options.granularity !== void 0 ? Math.max(options.granularity, 1) : 1;
10680
- const quadsPerAxisX = granularity + (options.generateBorders ? 2 : 0);
10681
- const quadsPerAxisY = granularity + (options.extendToNorthPole || options.generateBorders ? 1 : 0) + (options.extendToSouthPole || options.generateBorders ? 1 : 0);
10682
- const verticesPerAxisX = quadsPerAxisX + 1;
10683
- const verticesPerAxisY = quadsPerAxisY + 1;
10684
- const offsetX = options.generateBorders ? -1 : 0;
10685
- const offsetY = options.generateBorders || options.extendToNorthPole ? -1 : 0;
10686
- const endX = granularity + (options.generateBorders ? 1 : 0);
10687
- const endY = granularity + (options.generateBorders || options.extendToSouthPole ? 1 : 0);
10688
- const vertexCount = verticesPerAxisX * verticesPerAxisY;
10689
- const indexCount = quadsPerAxisX * quadsPerAxisY * 6;
10690
- const overflows16bitIndices = verticesPerAxisX * verticesPerAxisY > 65536;
10691
- if (overflows16bitIndices && forceIndicesSize === "16bit") throw new Error("Granularity is too large and meshes would not fit inside 16 bit vertex indices.");
10692
- const use32bitIndices = overflows16bitIndices || forceIndicesSize === "32bit";
10693
- const vertices = new Int16Array(vertexCount * 2);
10694
- let vertexId = 0;
10695
- for (let y = offsetY; y <= endY; y++) for (let x = offsetX; x <= endX; x++) {
10696
- let vx = x / granularity * EXTENT;
10697
- if (x === -1) vx = -EXTENT_STENCIL_BORDER;
10698
- if (x === granularity + 1) vx = EXTENT + EXTENT_STENCIL_BORDER;
10699
- let vy = y / granularity * EXTENT;
10700
- if (y === -1) vy = options.extendToNorthPole ? NORTH_POLE_Y : -EXTENT_STENCIL_BORDER;
10701
- if (y === granularity + 1) vy = options.extendToSouthPole ? SOUTH_POLE_Y : EXTENT + EXTENT_STENCIL_BORDER;
10702
- vertices[vertexId++] = vx;
10703
- vertices[vertexId++] = vy;
10704
- }
10705
- const indices = use32bitIndices ? new Uint32Array(indexCount) : new Uint16Array(indexCount);
10706
- let indexId = 0;
10707
- for (let y = 0; y < quadsPerAxisY; y++) for (let x = 0; x < quadsPerAxisX; x++) {
10708
- const v0 = x + y * verticesPerAxisX;
10709
- const v1 = x + 1 + y * verticesPerAxisX;
10710
- const v2 = x + (y + 1) * verticesPerAxisX;
10711
- const v3 = x + 1 + (y + 1) * verticesPerAxisX;
10712
- indices[indexId++] = v0;
10713
- indices[indexId++] = v2;
10714
- indices[indexId++] = v1;
10715
- indices[indexId++] = v1;
10716
- indices[indexId++] = v2;
10717
- indices[indexId++] = v3;
10718
- }
10719
- return {
10720
- vertices: vertices.buffer.slice(0),
10721
- indices: indices.buffer.slice(0),
10722
- uses32bitIndices: use32bitIndices
10723
- };
10724
- }
10725
- //#endregion
10726
10778
  //#region src/geo/projection/vertical_perspective_projection.ts
10727
10779
  const VerticalPerspectiveShaderDefine = "#define GLOBE";
10728
10780
  const VerticalPerspectiveShaderVariantKey = "globe";
@@ -11043,11 +11095,12 @@ function versorSetLocationAtPoint(tr, lnglat, point, panDelta, fixedBearing = tr
11043
11095
  const delta = l ? fromValues(w[1] / l * s, -w[0] / l * s, w[2] / l * s, Math.cos(t)) : fromValues(0, 0, 0, 1);
11044
11096
  const { lng: newCenterLng, lat: newCenterLat, bearing: newBearing } = lngLatBearingFromOrientation(multiply$1(createVec4f64(), centerQuat, delta));
11045
11097
  const oldLat = tr.center.lat;
11098
+ const oldZoom = tr.zoom;
11046
11099
  const finalLat = clamp(newCenterLat, -90, 90);
11047
11100
  const finalLng = fixedBearing ? fixedBearingLongitude(tr, point, panDelta, newCenterLng) : newCenterLng;
11048
11101
  tr.setCenter(new LngLat(wrap(finalLng, -180, 180), finalLat));
11049
11102
  if (!fixedBearing) tr.setBearing(newBearing);
11050
- tr.setZoom(tr.zoom + getZoomAdjustment(oldLat, tr.center.lat));
11103
+ tr.setZoom(oldZoom + getZoomAdjustment(oldLat, tr.center.lat));
11051
11104
  }
11052
11105
  /**
11053
11106
  * Returns the center longitude for a bearing-preserving drag.
@@ -12856,7 +12909,7 @@ var VerticalPerspectiveCameraHelper = class VerticalPerspectiveCameraHelper {
12856
12909
  */
12857
12910
  handleMapControlsPan(deltas, tr, preZoomAroundLoc) {
12858
12911
  if (!deltas.panDelta) return;
12859
- versorSetLocationAtPoint(tr, preZoomAroundLoc, deltas.around, deltas.panDelta);
12912
+ versorSetLocationAtPoint(tr, preZoomAroundLoc, tr.isPointOnMapSurface(deltas.around) ? deltas.around : tr.centerPoint, deltas.panDelta);
12860
12913
  }
12861
12914
  cameraForBoxAndBearing(options, padding, bounds, bearing, tr) {
12862
12915
  const result = cameraForBoxAndBearing(options, padding, bounds, bearing, tr);
@@ -17365,17 +17418,17 @@ function drawRaster(painter, tileManager, layer, tileIDs, renderOptions) {
17365
17418
  const { isRenderingToTexture } = renderOptions;
17366
17419
  const source = tileManager.getSource();
17367
17420
  const useSubdivision = painter.style.projection.useSubdivision;
17368
- if (source instanceof ImageSource) drawTiles(painter, tileManager, layer, tileIDs, null, false, false, source.tileCoords, source.perspectiveTransform, source.flippedWindingOrder, isRenderingToTexture);
17421
+ if (source instanceof ImageSource) drawTiles(painter, tileManager, layer, tileIDs, null, false, false, source.tileCoords, source.imageWarp, source.flippedWindingOrder, isRenderingToTexture, source.getMesh(painter.context, useSubdivision));
17369
17422
  else if (useSubdivision) {
17370
17423
  const [stencilBorderless, stencilBorders, coords] = painter.stencilConfigForOverlapTwoPass(tileIDs);
17371
- drawTiles(painter, tileManager, layer, coords, stencilBorderless, false, true, cornerCoords, identityPerspectiveTransform, false, isRenderingToTexture);
17372
- drawTiles(painter, tileManager, layer, coords, stencilBorders, true, true, cornerCoords, identityPerspectiveTransform, false, isRenderingToTexture);
17424
+ drawTiles(painter, tileManager, layer, coords, stencilBorderless, false, true, cornerCoords, bilinearImageWarp, false, isRenderingToTexture);
17425
+ drawTiles(painter, tileManager, layer, coords, stencilBorders, true, true, cornerCoords, bilinearImageWarp, false, isRenderingToTexture);
17373
17426
  } else {
17374
17427
  const [stencil, coords] = painter.getStencilConfigForOverlapAndUpdateStencilID(tileIDs);
17375
- drawTiles(painter, tileManager, layer, coords, stencil, false, true, cornerCoords, identityPerspectiveTransform, false, isRenderingToTexture);
17428
+ drawTiles(painter, tileManager, layer, coords, stencil, false, true, cornerCoords, bilinearImageWarp, false, isRenderingToTexture);
17376
17429
  }
17377
17430
  }
17378
- function drawTiles(painter, tileManager, layer, coords, stencilModes, useBorder, allowPoles, corners, perspectiveTransform, flipCullfaceMode = false, isRenderingToTexture = false) {
17431
+ function drawTiles(painter, tileManager, layer, coords, stencilModes, useBorder, allowPoles, corners, imageWarp, flipCullfaceMode = false, isRenderingToTexture = false, sourceMesh = null) {
17379
17432
  const minTileZ = coords[coords.length - 1].overscaledZ;
17380
17433
  const context = painter.context;
17381
17434
  const gl = context.gl;
@@ -17408,8 +17461,8 @@ function drawTiles(painter, tileManager, layer, coords, stencilModes, useBorder,
17408
17461
  applyGlobeMatrix: !isRenderingToTexture,
17409
17462
  applyTerrainMatrix: true
17410
17463
  });
17411
- const uniformValues = rasterUniformValues(parentTopLeft, parentScaleBy, fadeValues.fadeMix, layer, corners, perspectiveTransform);
17412
- const mesh = projection.getMeshFromTileID(context, coord.canonical, useBorder, allowPoles, "raster");
17464
+ const uniformValues = rasterUniformValues(parentTopLeft, parentScaleBy, fadeValues.fadeMix, layer, corners, imageWarp);
17465
+ const mesh = sourceMesh ?? projection.getMeshFromTileID(context, coord.canonical, useBorder, allowPoles, "raster");
17413
17466
  const stencilMode = stencilModes ? stencilModes[coord.overscaledZ] : StencilMode.disabled;
17414
17467
  program.draw(context, gl.TRIANGLES, depthMode, stencilMode, colorMode, flipCullfaceMode ? CullFaceMode.frontCCW : CullFaceMode.backCCW, uniformValues, terrainData, projectionData, layer.id, mesh.vertexBuffer, mesh.indexBuffer, mesh.segments);
17415
17468
  }