maplibre-gl 6.11.1 → 6.11.2

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.
Files changed (70) hide show
  1. package/dist/maplibre-gl-dev.mjs +213 -110
  2. package/dist/maplibre-gl-dev.mjs.map +1 -1
  3. package/dist/maplibre-gl-shared-dev.mjs +6 -6
  4. package/dist/maplibre-gl-shared-dev.mjs.map +1 -1
  5. package/dist/maplibre-gl-shared.mjs +2 -2
  6. package/dist/maplibre-gl-shared.mjs.map +1 -1
  7. package/dist/maplibre-gl-worker-dev.mjs +23 -20
  8. package/dist/maplibre-gl-worker-dev.mjs.map +1 -1
  9. package/dist/maplibre-gl-worker.mjs +2 -2
  10. package/dist/maplibre-gl-worker.mjs.map +1 -1
  11. package/dist/maplibre-gl.d.ts +78 -32
  12. package/dist/maplibre-gl.mjs +6 -6
  13. package/dist/maplibre-gl.mjs.map +1 -1
  14. package/package.json +1 -1
  15. package/src/data/bucket/symbol_bucket.test.ts +7 -6
  16. package/src/data/bucket/symbol_bucket.ts +2 -2
  17. package/src/data/bucket.ts +6 -4
  18. package/src/geo/projection/camera_helper.ts +6 -0
  19. package/src/geo/projection/globe_transform.test.ts +10 -1
  20. package/src/geo/projection/globe_utils.ts +5 -2
  21. package/src/geo/projection/mercator_camera_helper.ts +31 -7
  22. package/src/geo/projection/mercator_transform.test.ts +12 -0
  23. package/src/geo/projection/mercator_transform.ts +1 -1
  24. package/src/geo/projection/projection_data.ts +4 -1
  25. package/src/geo/projection/vertical_perspective_camera_helper.test.ts +24 -1
  26. package/src/geo/projection/vertical_perspective_camera_helper.ts +3 -0
  27. package/src/geo/transform_helper.ts +2 -2
  28. package/src/index.ts +2 -1
  29. package/src/render/glyph_atlas.test.ts +45 -0
  30. package/src/render/glyph_atlas.ts +28 -25
  31. package/src/render/glyph_manager.test.ts +92 -68
  32. package/src/render/glyph_manager.ts +41 -25
  33. package/src/render/painter.ts +7 -3
  34. package/src/render/render_context.ts +5 -1
  35. package/src/shaders/glsl/hillshade.fragment.glsl +1 -1
  36. package/src/shaders/glsl/hillshade.fragment.glsl.g.ts +1 -1
  37. package/src/shaders/glsl/hillshade_prepare.fragment.glsl +3 -2
  38. package/src/shaders/glsl/hillshade_prepare.fragment.glsl.g.ts +1 -1
  39. package/src/source/worker_source.ts +2 -2
  40. package/src/source/worker_tile.test.ts +3 -3
  41. package/src/source/worker_tile.ts +4 -3
  42. package/src/style/style.ts +2 -2
  43. package/src/style/style_glyph.ts +6 -0
  44. package/src/symbol/shaping.test.ts +8 -8
  45. package/src/symbol/shaping.ts +12 -12
  46. package/src/symbol/symbol_layout.ts +4 -12
  47. package/src/symbol/tagged_string.test.ts +8 -6
  48. package/src/symbol/tagged_string.ts +5 -5
  49. package/src/ui/camera.test.ts +22 -2
  50. package/src/ui/camera.ts +44 -15
  51. package/src/ui/handler/click_zoom.ts +1 -1
  52. package/src/ui/handler/dblclick_zoom.test.ts +35 -0
  53. package/src/ui/handler/drag_pan.test.ts +18 -0
  54. package/src/ui/handler/scroll_zoom.test.ts +26 -0
  55. package/src/ui/handler/tap_zoom.ts +2 -2
  56. package/src/ui/handler_manager.test.ts +3 -2
  57. package/src/ui/handler_manager.ts +5 -0
  58. package/src/ui/map.ts +41 -50
  59. package/src/ui/map_tests/map_bounds.test.ts +17 -1
  60. package/src/ui/map_tests/map_events.test.ts +20 -1
  61. package/src/ui/map_tests/map_pixel_ratio.test.ts +31 -0
  62. package/src/ui/map_tests/map_terrain.test.ts +106 -0
  63. package/src/util/actor_messages.ts +4 -9
  64. package/src/util/test/util.ts +3 -1
  65. package/src/webgl/context.ts +7 -3
  66. package/src/webgl/program.ts +2 -5
  67. package/src/webgl/projection_uniform_buffer.test.ts +76 -0
  68. package/src/webgl/projection_uniform_buffer.ts +34 -3
  69. package/src/webgl/render_to_texture.test.ts +1 -1
  70. package/src/webgl/uniform_buffer.ts +8 -8
@@ -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.11.1/LICENSE.txt
3
+ * @license 3-Clause BSD. Full text of license: https://github.com/maplibre/maplibre-gl-js/blob/v6.11.2/LICENSE.txt
4
4
  */
5
5
  import { $ as projectToWorldCoordinates, $n as differenceOfAnglesDegrees, $r as add, $t as Transitionable, A as evaluateSizeForZoom, Ai as rotateX, An as addProtocol, Ar as scaleZoom, At as toEvaluationFeature, B as isCluster, Bi as rotate, Bn as arrayBufferToImage, Br as EXTENT, Bt as SegmentVector, C as addDynamicAttributes, Ci as exactEquals, Cn as GLOBAL_DISPATCHER_ID, Cr as pointPlaneSignedDistance, Ct as HEATMAP_FULL_RENDER_FBO_KEY, Di as multiply, Dn as getVideo, Dr as remapSaturate, Dt as RGBAImage, E as TextAnchorEnum, Ei as invert$1, En as getReferrer, Er as readImageUsingVideoFrame, Et as AlphaImage, F as potpack, Fi as create$4, Fn as isAbortError, Fr as uniqueId, Ft as Uniform4f, Gn as createIdentityMat4f32, Gr as zero, Gt as PosArray, Hi as offscreenCanvasSupported, Hn as bezier, Hr as length$1, Ht as CollisionCircleLayoutArray, I as isStyleImageWebGLData, Ii as fromRotation, In as throwIfAborted, Ir as warnOnce, It as UniformColor, J as cameraDirectionFromPitchBearing, Jn as createVec3f64, Jr as multiply$1, Jt as TriangleIndexArray, K as isFillExtrusionStyleLayer, Kn as createIdentityMat4f64, Kr as fromEuler, Kt as QuadTriangleArray, L as renderStyleImage, Li as create$2, Lr as wrap, Lt as UniformColorArray, M as getAnchorAlignment, Mi as rotateZ, Mn as removeProtocol, Mr as subscribe, Mt as Uniform1i, Ni as scale, Nn as config, Nr as threePlaneIntersection, Nt as Uniform2f, O as clipLine, Oi as ortho, On as makeRequest, Or as rollPitchBearingEqual, Ot as isCircleStyleLayer, P as ImagePosition, Pi as translate, Pn as AbortError, Pr as translatePosition, Pt as Uniform3f, Q as maxMercatorHorizonAngle, Qn as degreesToRadians, Qr as transformMat4, Qt as Properties, R as parseGlyphPbf, Ri as determinant, Rn as MAX_VALID_LATITUDE, Rr as zoomScale, Rt as UniformFloatArray, S as SymbolBucket, Si as equals, Sn as AJAXError, Sr as pick, St as isHillshadeStyleLayer, T as getAnchorJustification, Ti as identity, Tn as getJSON, Tr as rayPlaneIntersection, Tt as renderColorRamp, U as collisionCircleLayout, Ui as Point, Un as clamp, Ur as scale$3, Ut as LineStripIndexArray, V as codePointUsesLocalIdeographFontFamily, Vi as isOffscreenCanvasDistorted, Vn as arrayBufferToImageBitmap, Vr as create$3, Vt as CollisionBoxArray, W as isLineStyleLayer, Wn as clone$2, Wr as sqrLen, Wt as Pos3dArray, X as cameraMercatorCoordinateFromCenterAndRotation, Xn as deepEqual, Xr as mul, Xt as isRasterStyleLayer, Y as cameraMercatorCoordinate, Yn as createVec4f64, Yr as slerp, Yt as createLayout, Z as getMercatorHorizon, Zn as defaultEasing, Zr as scale$2, Zt as DataConstantProperty, _ as createStyleLayer, _i as transformQuat, _n as derefLayers, _r as lerp, _t as SubdivisionGranularityExpression, a as GeoJSONFeature, ai as length, an as validateAndEmit, ar as findLineIntersection, at as lngFromMercatorX, b as isBackgroundStyleLayer, bi as copy, bn as Event, br as nextPowerOfTwo, ci as rotateX$1, cn as emptyStyle, cr as getEdgeTiles, ct as mercatorZfromAltitude, d as OverscaledTileID, di as scale$1, dr as isImageBitmap, ei as clone, en as EvaluationParameters, er as distanceOfAnglesRadians, et as tileCoordinatesToMercatorCoordinates, f as UnwrappedTileID, fi as scaleAndAdd, fn as interpolateFactory, fr as isPointableEvent, ft as EXTENT_BOUNDS, g as Actor, gi as transformMat4$1, gn as diff, gr as isWorker, gt as SOUTH_POLE_Y, h as isInBoundsForZoomLngLat, hi as transformMat3, hn as ValidationError, hr as isTouchableOrPointableType, ht as NORTH_POLE_Y, ii as len, in as emitValidationErrors, ir as filterObject, it as latFromMercatorY, ji as rotateY$1, jn as getProtocol, jr as sphericalToCartesian, jt as Uniform1f, k as evaluateSizeForFeature, ki as perspective, kn as sameOrigin, kr as rollPitchBearingToQuat, kt as polygonIntersectsPolygon, li as rotateY, lt as LngLat, m as compareTileId, mi as subtract, mn as Color, mr as isTouchableEvent, mt as isFillStyleLayer, n as TileCache, ni as distance, nr as evaluateZoomSnap, nt as MercatorCoordinate, oi as negate, on as validateStyle, or as getAABB, ot as mercatorXfromLng, p as calculateTileKey, pi as sub, pn as ProjectionDefinition, pr as isSafari, pt as Bounds, q as calculateTileMatrix, qn as createMat4f64, qr as fromValues, qt as RasterBoundsArray, ri as dot, rn as SPEC_SOURCE_TYPES, rr as extend, rt as altitudeFromMercatorZ, s as GEOJSON_TILE_LAYER_NAME, si as normalize, sn as validateStyleAndEmit, sr as getAngleDelta, st as mercatorYfromLat, ti as cross, tn as ZoomHistory, tr as ensureError, tt as unprojectFromWorldCoordinates, u as CanonicalTileID, ui as rotateZ$1, un as featureFilter, ur as getRollPitchBearing, ut as earthRadius, v as isCustomStyleLayer, vi as zero$1, vn as latest, vr as mapObject, vt as SubdivisionGranularitySetting, w as getOverlapMode, wi as fromScaling, wn as getArrayBuffer, wr as radiansToDegrees, wt as isHeatmapStyleLayer, x as isSymbolStyleLayer, xi as create$1, xn as Evented, xr as parseCacheControl, xt as Texture, y as validateCustomStyleLayer, yi as clone$1, yn as ErrorEvent, yr as mod, yt as isColorReliefStyleLayer, zi as invert, zn as angleToRotateBetweenVectors2D, zr as pixelsToTileUnits, zt as UniformMatrix4f } from "./maplibre-gl-shared-dev.mjs";
6
6
  //#region package.json
7
- var version$2 = "6.11.1";
7
+ var version$2 = "6.11.2";
8
8
  //#endregion
9
9
  //#region src/util/browser.ts
10
10
  let linkEl;
@@ -1619,12 +1619,13 @@ var GlyphManager = class {
1619
1619
  }
1620
1620
  async getGlyphs(glyphs) {
1621
1621
  const glyphsPromises = [];
1622
- for (const stack in glyphs) for (const id of glyphs[stack]) glyphsPromises.push(this._getAndCacheGlyphsPromise(stack, id));
1622
+ for (const stack in glyphs) for (const variant in glyphs[stack]) for (const id of glyphs[stack][variant]) glyphsPromises.push(this._getAndCacheGlyphsPromise(stack, id, variant));
1623
1623
  const updatedGlyphs = await Promise.all(glyphsPromises);
1624
1624
  const result = {};
1625
- for (const { stack, id, glyph } of updatedGlyphs) {
1625
+ for (const { stack, id, variant, glyph } of updatedGlyphs) {
1626
1626
  result[stack] ||= {};
1627
- result[stack][id] = glyph && {
1627
+ result[stack][variant] ||= {};
1628
+ result[stack][variant][id] = glyph && {
1628
1629
  id: glyph.id,
1629
1630
  bitmap: glyph.bitmap.clone(),
1630
1631
  metrics: glyph.metrics
@@ -1640,39 +1641,56 @@ var GlyphManager = class {
1640
1641
  * has no way to serve the one shape they are written as. A file the style pinned with
1641
1642
  * `font-faces` draws it where one covers it, and the local fonts otherwise. For a single
1642
1643
  * codepoint a declared file still wins over the glyphs URL and the local fallbacks.
1644
+ * Providers support the `default` variant; unsupported variants return `null`.
1643
1645
  */
1644
- async _getAndCacheGlyphsPromise(stack, id) {
1646
+ async _getAndCacheGlyphsPromise(stack, id, variant) {
1645
1647
  this.entries[stack] ??= {
1646
- glyphs: {},
1648
+ glyphs: { default: {} },
1647
1649
  requests: {},
1648
1650
  ranges: {}
1649
1651
  };
1650
1652
  const entry = this.entries[stack];
1651
- let glyph = entry.glyphs[id];
1653
+ const glyphs = entry.glyphs[variant] ||= {};
1654
+ let glyph = glyphs[id];
1652
1655
  if (glyph !== void 0) return {
1653
1656
  stack,
1654
1657
  id,
1658
+ variant,
1655
1659
  glyph
1656
1660
  };
1661
+ if (variant !== "default") {
1662
+ glyphs[id] = null;
1663
+ return {
1664
+ stack,
1665
+ id,
1666
+ variant,
1667
+ glyph: null
1668
+ };
1669
+ }
1657
1670
  const codePoint = id.codePointAt(0);
1658
1671
  const fontFaceFamily = this.fontFaceManager.hasFontFaces() ? await this.fontFaceManager.getFontFamily(stack, codePoint) : null;
1659
1672
  if (fontFaceFamily) {
1660
- glyph = entry.glyphs[id] = await this._drawGlyph(entry, stack, id, fontFaceFamily);
1673
+ glyph = glyphs[id] = await this._drawGlyph(entry, stack, id, fontFaceFamily);
1661
1674
  return {
1662
1675
  stack,
1663
1676
  id,
1677
+ variant,
1664
1678
  glyph
1665
1679
  };
1666
1680
  }
1667
1681
  if (!this.url || isCluster(id) || this._charUsesLocalIdeographFontFamily(codePoint)) {
1668
- glyph = entry.glyphs[id] = await this._drawGlyph(entry, stack, id);
1682
+ glyph = glyphs[id] = await this._drawGlyph(entry, stack, id);
1669
1683
  return {
1670
1684
  stack,
1671
1685
  id,
1686
+ variant,
1672
1687
  glyph
1673
1688
  };
1674
1689
  }
1675
- return await this._downloadAndCacheRangePromise(stack, id);
1690
+ return {
1691
+ ...await this._downloadAndCacheRangePromise(stack, id),
1692
+ variant
1693
+ };
1676
1694
  }
1677
1695
  /**
1678
1696
  * Gets a glyph from the server-side cache, downloading the PBF range it falls in if need be.
@@ -1692,7 +1710,7 @@ var GlyphManager = class {
1692
1710
  entry.requests[range] ||= this._loadGlyphRange(stack, range);
1693
1711
  try {
1694
1712
  const response = await entry.requests[range];
1695
- for (const responseId in response) entry.glyphs[String.fromCodePoint(+responseId)] = response[+responseId];
1713
+ for (const responseId in response) entry.glyphs.default[String.fromCodePoint(+responseId)] = response[+responseId];
1696
1714
  entry.ranges[range] = true;
1697
1715
  return {
1698
1716
  stack,
@@ -1700,7 +1718,7 @@ var GlyphManager = class {
1700
1718
  glyph: response[codePoint] || null
1701
1719
  };
1702
1720
  } catch (e) {
1703
- const glyph = entry.glyphs[id] = await this._drawGlyph(entry, stack, id);
1721
+ const glyph = entry.glyphs.default[id] = await this._drawGlyph(entry, stack, id);
1704
1722
  this._warnOnMissingGlyphRange(glyph, range, codePoint, ensureError(e));
1705
1723
  return {
1706
1724
  stack,
@@ -1875,7 +1893,7 @@ var GlyphManager = class {
1875
1893
  entry.tinySDF = null;
1876
1894
  entry.ideographTinySDF = null;
1877
1895
  entry.fontFaceTinySDFs = {};
1878
- entry.glyphs = {};
1896
+ entry.glyphs = { default: {} };
1879
1897
  entry.requests = {};
1880
1898
  entry.ranges = {};
1881
1899
  }
@@ -9623,8 +9641,8 @@ const shaders = {
9623
9641
  fillPattern: prepare("#ifdef GL_ES\nprecision highp float;\n#endif\nuniform vec2 u_texsize;uniform float u_fade;uniform bool u_sdf_pattern;uniform sampler2D u_image;in vec2 v_pos_a;in vec2 v_pos_b;\n#pragma maplibre: define lowp float opacity\n#pragma maplibre: define highp vec4 color\n#pragma maplibre: define lowp vec4 pattern_from\n#pragma maplibre: define lowp vec4 pattern_to\nvoid main() {\n#pragma maplibre: initialize lowp float opacity\n#pragma maplibre: initialize highp vec4 color\n#pragma maplibre: initialize mediump vec4 pattern_from\n#pragma maplibre: initialize mediump vec4 pattern_to\nvec2 pattern_tl_a=pattern_from.xy;vec2 pattern_br_a=pattern_from.zw;vec2 pattern_tl_b=pattern_to.xy;vec2 pattern_br_b=pattern_to.zw;vec2 imagecoord=mod(v_pos_a,1.0);vec2 pos=mix(pattern_tl_a/u_texsize,pattern_br_a/u_texsize,imagecoord);vec4 color1=texture(u_image,pos);vec2 imagecoord_b=mod(v_pos_b,1.0);vec2 pos2=mix(pattern_tl_b/u_texsize,pattern_br_b/u_texsize,imagecoord_b);vec4 color2=texture(u_image,pos2);if (u_sdf_pattern) {highp float sdf_edge=(256.0-64.0)/256.0;highp float sdf_gamma_a=max(fwidth(color1.a)*0.5,1.0/255.0/16.0);highp float sdf_gamma_b=max(fwidth(color2.a)*0.5,1.0/255.0/16.0);float sdf_alpha_a=smoothstep(sdf_edge-sdf_gamma_a,sdf_edge+sdf_gamma_a,color1.a);float sdf_alpha_b=smoothstep(sdf_edge-sdf_gamma_b,sdf_edge+sdf_gamma_b,color2.a);fragColor=mix(color*sdf_alpha_a,color*sdf_alpha_b,u_fade)*opacity;} else {fragColor=mix(color1,color2,u_fade)*opacity;}\n#ifdef OVERDRAW_INSPECTOR\nfragColor=vec4(1.0);\n#endif\n}", "uniform vec2 u_pixel_coord_upper;uniform vec2 u_pixel_coord_lower;uniform vec3 u_scale;uniform vec2 u_fill_translate;layout(location=0) in vec2 a_pos;out vec2 v_pos_a;out vec2 v_pos_b;\n#pragma maplibre: define lowp float opacity\n#pragma maplibre: define highp vec4 color\n#pragma maplibre: define lowp vec4 pattern_from\n#pragma maplibre: define lowp vec4 pattern_to\n#pragma maplibre: define lowp float pixel_ratio_from\n#pragma maplibre: define lowp float pixel_ratio_to\nvoid main() {\n#pragma maplibre: initialize lowp float opacity\n#pragma maplibre: initialize highp vec4 color\n#pragma maplibre: initialize mediump vec4 pattern_from\n#pragma maplibre: initialize mediump vec4 pattern_to\n#pragma maplibre: initialize lowp float pixel_ratio_from\n#pragma maplibre: initialize lowp float pixel_ratio_to\nif (opacity < 0.01) {gl_Position=vec4(-2.0,-2.0,-2.0,1.0);return;}vec2 pattern_tl_a=pattern_from.xy;vec2 pattern_br_a=pattern_from.zw;vec2 pattern_tl_b=pattern_to.xy;vec2 pattern_br_b=pattern_to.zw;float tileZoomRatio=u_scale.x;float fromScale=u_scale.y;float toScale=u_scale.z;vec2 display_size_a=(pattern_br_a-pattern_tl_a)/pixel_ratio_from;vec2 display_size_b=(pattern_br_b-pattern_tl_b)/pixel_ratio_to;gl_Position=projectTile(a_pos+u_fill_translate,a_pos);v_pos_a=get_pattern_pos(u_pixel_coord_upper,u_pixel_coord_lower,fromScale*display_size_a,tileZoomRatio,a_pos);v_pos_b=get_pattern_pos(u_pixel_coord_upper,u_pixel_coord_lower,toScale*display_size_b,tileZoomRatio,a_pos);}"),
9624
9642
  fillExtrusion: prepare("in vec4 v_color;void main() {fragColor=v_color;\n#ifdef OVERDRAW_INSPECTOR\nfragColor=vec4(1.0);\n#endif\n}", "uniform vec3 u_lightcolor;uniform lowp vec3 u_lightpos;uniform lowp vec3 u_lightpos_globe;uniform lowp float u_lightintensity;uniform float u_vertical_gradient;uniform lowp float u_opacity;uniform vec2 u_fill_translate;layout(location=0) in vec2 a_pos;layout(location=1) in ivec4 a_normal_ed;\n#ifdef TERRAIN3D\nlayout(location=2) in vec2 a_centroid;\n#endif\nout vec4 v_color;\n#pragma maplibre: define highp float base\n#pragma maplibre: define highp float height\n#pragma maplibre: define highp vec4 color\nvoid main() {\n#pragma maplibre: initialize highp float base\n#pragma maplibre: initialize highp float height\n#pragma maplibre: initialize highp vec4 color\nvec3 normal=vec3(a_normal_ed.xyz);float gradient_base=max(0.0,base);float gradient_height=max(0.0,height);\n#ifdef TERRAIN3D\nfloat height_terrain3d_offset=get_elevation(a_centroid);float base_terrain3d_offset=height_terrain3d_offset-(base > 0.0 ? 0.0 : 10.0);\n#else\nfloat height_terrain3d_offset=0.0;float base_terrain3d_offset=0.0;\n#endif\nbase=max(0.0,base)+base_terrain3d_offset;height=max(0.0,height)+height_terrain3d_offset;float t=float(a_normal_ed.x & 1);float elevation=t > 0.0 ? height : base;vec2 posInTile=a_pos+u_fill_translate;\n#ifdef GLOBE\nvec3 spherePos=projectToSphere(posInTile,a_pos);gl_Position=interpolateProjectionFor3D(posInTile,spherePos,elevation);\n#else\ngl_Position=u_projection_matrix*vec4(posInTile,elevation,1.0);\n#endif\nfloat colorvalue=color.r*0.2126+color.g*0.7152+color.b*0.0722;v_color=vec4(0.0,0.0,0.0,1.0);vec4 ambientlight=vec4(0.03,0.03,0.03,1.0);color+=ambientlight;vec3 normalForLighting=normal/16384.0;float directional=clamp(dot(normalForLighting,u_lightpos),0.0,1.0);\n#ifdef GLOBE\nmat3 rotMatrix=globeGetRotationMatrix(spherePos);normalForLighting=rotMatrix*normalForLighting;directional=mix(directional,clamp(dot(normalForLighting,u_lightpos_globe),0.0,1.0),u_projection_transition);\n#endif\ndirectional=mix((1.0-u_lightintensity),max((1.0-colorvalue+u_lightintensity),1.0),directional);if (normal.y !=0.0) {directional*=((1.0-u_vertical_gradient)+(u_vertical_gradient*clamp((t+gradient_base)*pow(gradient_height/150.0,0.5),mix(0.7,0.98,1.0-u_lightintensity),1.0)));}v_color.r+=clamp(color.r*directional*u_lightcolor.r,mix(0.0,0.3,1.0-u_lightcolor.r),1.0);v_color.g+=clamp(color.g*directional*u_lightcolor.g,mix(0.0,0.3,1.0-u_lightcolor.g),1.0);v_color.b+=clamp(color.b*directional*u_lightcolor.b,mix(0.0,0.3,1.0-u_lightcolor.b),1.0);v_color*=u_opacity;}"),
9625
9643
  fillExtrusionPattern: prepare("uniform vec2 u_texsize;uniform float u_fade;uniform sampler2D u_image;in vec2 v_pos_a;in vec2 v_pos_b;in vec4 v_lighting;\n#pragma maplibre: define lowp float base\n#pragma maplibre: define lowp float height\n#pragma maplibre: define lowp vec4 pattern_from\n#pragma maplibre: define lowp vec4 pattern_to\n#pragma maplibre: define lowp float pixel_ratio_from\n#pragma maplibre: define lowp float pixel_ratio_to\nvoid main() {\n#pragma maplibre: initialize lowp float base\n#pragma maplibre: initialize lowp float height\n#pragma maplibre: initialize mediump vec4 pattern_from\n#pragma maplibre: initialize mediump vec4 pattern_to\n#pragma maplibre: initialize lowp float pixel_ratio_from\n#pragma maplibre: initialize lowp float pixel_ratio_to\nvec2 pattern_tl_a=pattern_from.xy;vec2 pattern_br_a=pattern_from.zw;vec2 pattern_tl_b=pattern_to.xy;vec2 pattern_br_b=pattern_to.zw;vec2 imagecoord=mod(v_pos_a,1.0);vec2 pos=mix(pattern_tl_a/u_texsize,pattern_br_a/u_texsize,imagecoord);vec4 color1=texture(u_image,pos);vec2 imagecoord_b=mod(v_pos_b,1.0);vec2 pos2=mix(pattern_tl_b/u_texsize,pattern_br_b/u_texsize,imagecoord_b);vec4 color2=texture(u_image,pos2);vec4 mixedColor=mix(color1,color2,u_fade);fragColor=mixedColor*v_lighting;\n#ifdef OVERDRAW_INSPECTOR\nfragColor=vec4(1.0);\n#endif\n}", "uniform vec2 u_pixel_coord_upper;uniform vec2 u_pixel_coord_lower;uniform float u_height_factor;uniform vec3 u_scale;uniform float u_vertical_gradient;uniform lowp float u_opacity;uniform vec2 u_fill_translate;uniform vec3 u_lightcolor;uniform lowp vec3 u_lightpos;uniform lowp vec3 u_lightpos_globe;uniform lowp float u_lightintensity;layout(location=0) in vec2 a_pos;layout(location=1) in ivec4 a_normal_ed;\n#ifdef TERRAIN3D\nlayout(location=2) in vec2 a_centroid;\n#endif\n#ifdef GLOBE\nout vec3 v_sphere_pos;\n#endif\nout vec2 v_pos_a;out vec2 v_pos_b;out vec4 v_lighting;\n#pragma maplibre: define lowp float base\n#pragma maplibre: define lowp float height\n#pragma maplibre: define lowp vec4 pattern_from\n#pragma maplibre: define lowp vec4 pattern_to\n#pragma maplibre: define lowp float pixel_ratio_from\n#pragma maplibre: define lowp float pixel_ratio_to\nvoid main() {\n#pragma maplibre: initialize lowp float base\n#pragma maplibre: initialize lowp float height\n#pragma maplibre: initialize mediump vec4 pattern_from\n#pragma maplibre: initialize mediump vec4 pattern_to\n#pragma maplibre: initialize lowp float pixel_ratio_from\n#pragma maplibre: initialize lowp float pixel_ratio_to\nvec2 pattern_tl_a=pattern_from.xy;vec2 pattern_br_a=pattern_from.zw;vec2 pattern_tl_b=pattern_to.xy;vec2 pattern_br_b=pattern_to.zw;float tileRatio=u_scale.x;float fromScale=u_scale.y;float toScale=u_scale.z;vec3 normal=vec3(a_normal_ed.xyz);float edgedistance=float(a_normal_ed.w);vec2 display_size_a=(pattern_br_a-pattern_tl_a)/pixel_ratio_from;vec2 display_size_b=(pattern_br_b-pattern_tl_b)/pixel_ratio_to;float gradient_base=max(0.0,base);float gradient_height=max(0.0,height);\n#ifdef TERRAIN3D\nfloat height_terrain3d_offset=get_elevation(a_centroid);float base_terrain3d_offset=height_terrain3d_offset-(base > 0.0 ? 0.0 : 10.0);\n#else\nfloat height_terrain3d_offset=0.0;float base_terrain3d_offset=0.0;\n#endif\nbase=max(0.0,base)+base_terrain3d_offset;height=max(0.0,height)+height_terrain3d_offset;float t=float(a_normal_ed.x & 1);float elevation=t > 0.0 ? height : base;vec2 posInTile=a_pos+u_fill_translate;\n#ifdef GLOBE\nvec3 spherePos=projectToSphere(posInTile,a_pos);vec3 elevatedPos=spherePos*(1.0+elevation/GLOBE_RADIUS);v_sphere_pos=elevatedPos;gl_Position=interpolateProjectionFor3D(posInTile,spherePos,elevation);\n#else\ngl_Position=u_projection_matrix*vec4(posInTile,elevation,1.0);\n#endif\nvec2 pos=a_normal_ed.x==1 && a_normal_ed.y==0 && a_normal_ed.z==16384\n? a_pos\n: vec2(edgedistance,elevation*u_height_factor);v_pos_a=get_pattern_pos(u_pixel_coord_upper,u_pixel_coord_lower,fromScale*display_size_a,tileRatio,pos);v_pos_b=get_pattern_pos(u_pixel_coord_upper,u_pixel_coord_lower,toScale*display_size_b,tileRatio,pos);v_lighting=vec4(0.0,0.0,0.0,1.0);float directional=clamp(dot(normal/16383.0,u_lightpos),0.0,1.0);directional=mix((1.0-u_lightintensity),max((0.5+u_lightintensity),1.0),directional);if (normal.y !=0.0) {directional*=((1.0-u_vertical_gradient)+(u_vertical_gradient*clamp((t+gradient_base)*pow(gradient_height/150.0,0.5),mix(0.7,0.98,1.0-u_lightintensity),1.0)));}v_lighting.rgb+=clamp(directional*u_lightcolor,mix(vec3(0.0),vec3(0.3),1.0-u_lightcolor),vec3(1.0));v_lighting*=u_opacity;}"),
9626
- hillshadePrepare: prepare("#ifdef GL_ES\nprecision highp float;\n#endif\nuniform sampler2D u_image;in vec2 v_pos;uniform vec2 u_dimension;uniform float u_zoom;uniform vec4 u_unpack;float getElevation(ivec2 texel) {vec4 data=texelFetch(u_image,texel,0)*255.0;data.a=-1.0;return dot(data,u_unpack);}void main() {ivec2 pos=ivec2(gl_FragCoord.xy)+ivec2(1);float tileSize=u_dimension.x-4.0;float a=getElevation(pos+ivec2(-1,-1));float b=getElevation(pos+ivec2(0,-1));float c=getElevation(pos+ivec2(1,-1));float d=getElevation(pos+ivec2(-1,0));float e=getElevation(pos);float f=getElevation(pos+ivec2(1,0));float g=getElevation(pos+ivec2(-1,1));float h=getElevation(pos+ivec2(0,1));float i=getElevation(pos+ivec2(1,1));float exaggerationFactor=u_zoom < 2.0 ? 0.4 : u_zoom < 4.5 ? 0.35 : 0.3;float exaggeration=u_zoom < 15.0 ? (u_zoom-15.0)*exaggerationFactor : 0.0;vec2 deriv=vec2((c+f+f+i)-(a+d+d+g),(g+h+h+i)-(a+b+b+c))*tileSize/pow(2.0,exaggeration+(28.2562-u_zoom));fragColor=clamp(vec4(deriv.x/8.0+0.5,deriv.y/8.0+0.5,1.0,1.0),0.0,1.0);\n#ifdef OVERDRAW_INSPECTOR\nfragColor=vec4(1.0);\n#endif\n}", "uniform mat4 u_matrix;uniform vec2 u_dimension;layout(location=0) in vec2 a_pos;layout(location=1) in vec2 a_texture_pos;out vec2 v_pos;void main() {gl_Position=u_matrix*vec4(a_pos,0,1);highp vec2 epsilon=1.0/u_dimension;float scale=(u_dimension.x-2.0)/u_dimension.x;v_pos=(a_texture_pos/8192.0)*scale+epsilon;}"),
9627
- hillshade: prepare("uniform sampler2D u_image;in highp vec2 v_pos;uniform vec2 u_latrange;uniform float u_exaggeration;uniform vec4 u_accent;uniform int u_method;uniform float u_altitudes[NUM_ILLUMINATION_SOURCES];uniform float u_azimuths[NUM_ILLUMINATION_SOURCES];uniform vec4 u_shadows[NUM_ILLUMINATION_SOURCES];uniform vec4 u_highlights[NUM_ILLUMINATION_SOURCES];\n#define PI 3.141592653589793\n#define STANDARD 0\n#define COMBINED 1\n#define IGOR 2\n#define MULTIDIRECTIONAL 3\n#define BASIC 4\nfloat get_aspect(vec2 deriv){return deriv.x !=0.0 ? atan(deriv.y,-deriv.x) : PI/2.0*(deriv.y > 0.0 ? 1.0 :-1.0);}void igor_hillshade(vec2 deriv){deriv=deriv*u_exaggeration*2.0;float aspect=get_aspect(deriv);float azimuth=u_azimuths[0]+PI;float slope_stength=atan(length(deriv))*2.0/PI;float aspect_strength=1.0-abs(mod((aspect+azimuth)/PI+0.5,2.0)-1.0);float shadow_strength=slope_stength*aspect_strength;float highlight_strength=slope_stength*(1.0-aspect_strength);fragColor=u_shadows[0]*shadow_strength+u_highlights[0]*highlight_strength;}void standard_hillshade(vec2 deriv){float azimuth=u_azimuths[0]+PI;float slope=atan(0.625*length(deriv));float aspect=get_aspect(deriv);float intensity=u_exaggeration;float base=1.875-intensity*1.75;float maxValue=0.5*PI;float scaledSlope=intensity !=0.5 ? ((pow(base,slope)-1.0)/(pow(base,maxValue)-1.0))*maxValue : slope;float accent=cos(scaledSlope);vec4 accent_color=(1.0-accent)*u_accent*clamp(intensity*2.0,0.0,1.0);float shade=abs(mod((aspect+azimuth)/PI+0.5,2.0)-1.0);vec4 shade_color=mix(u_shadows[0],u_highlights[0],shade)*sin(scaledSlope)*clamp(intensity*2.0,0.0,1.0);fragColor=accent_color*(1.0-shade_color.a)+shade_color;}void basic_hillshade(vec2 deriv){deriv=deriv*u_exaggeration*2.0;float azimuth=u_azimuths[0]+PI;float cos_az=cos(azimuth);float sin_az=sin(azimuth);float cos_alt=cos(u_altitudes[0]);float sin_alt=sin(u_altitudes[0]);float cang=(sin_alt-(deriv.y*cos_az*cos_alt-deriv.x*sin_az*cos_alt))/sqrt(1.0+dot(deriv,deriv));float shade=clamp(cang,0.0,1.0);if(shade > 0.5){fragColor=u_highlights[0]*(2.0*shade-1.0);}else\n{fragColor=u_shadows[0]*(1.0-2.0*shade);}}void multidirectional_hillshade(vec2 deriv){deriv=deriv*u_exaggeration*2.0;fragColor=vec4(0,0,0,0);for(int i=0; i < NUM_ILLUMINATION_SOURCES; i++){float cos_alt=cos(u_altitudes[i]);float sin_alt=sin(u_altitudes[i]);float cos_az=-cos(u_azimuths[i]);float sin_az=-sin(u_azimuths[i]);float cang=(sin_alt-(deriv.y*cos_az*cos_alt-deriv.x*sin_az*cos_alt))/sqrt(1.0+dot(deriv,deriv));float shade=clamp(cang,0.0,1.0);if(shade > 0.5){fragColor+=u_highlights[i]*(2.0*shade-1.0)/float(NUM_ILLUMINATION_SOURCES);}else\n{fragColor+=u_shadows[i]*(1.0-2.0*shade)/float(NUM_ILLUMINATION_SOURCES);}}}void combined_hillshade(vec2 deriv){deriv=deriv*u_exaggeration*2.0;float azimuth=u_azimuths[0]+PI;float cos_az=cos(azimuth);float sin_az=sin(azimuth);float cos_alt=cos(u_altitudes[0]);float sin_alt=sin(u_altitudes[0]);float cang=acos((sin_alt-(deriv.y*cos_az*cos_alt-deriv.x*sin_az*cos_alt))/sqrt(1.0+dot(deriv,deriv)));cang=clamp(cang,0.0,PI/2.0);float shade=cang*atan(length(deriv))*4.0/PI/PI;float highlight=(PI/2.0-cang)*atan(length(deriv))*4.0/PI/PI;fragColor=u_shadows[0]*shade+u_highlights[0]*highlight;}void main() {highp vec2 size=vec2(textureSize(u_image,0));highp vec2 texturePos=(v_pos*(size-2.0)+1.0)/size;vec4 pixel=texture(u_image,texturePos);float scaleFactor=cos(radians((u_latrange[0]-u_latrange[1])*(1.0-v_pos.y)+u_latrange[1]));vec2 deriv=((pixel.rg*8.0)-4.0)/scaleFactor;if (u_method==BASIC) {basic_hillshade(deriv);} else if (u_method==COMBINED) {combined_hillshade(deriv);} else if (u_method==IGOR) {igor_hillshade(deriv);} else if (u_method==MULTIDIRECTIONAL) {multidirectional_hillshade(deriv);} else if (u_method==STANDARD) {standard_hillshade(deriv);} else {standard_hillshade(deriv);}\n#ifdef OVERDRAW_INSPECTOR\nfragColor=vec4(1.0);\n#endif\n}", "uniform mat4 u_matrix;layout(location=0) in vec2 a_pos;out vec2 v_pos;void main() {gl_Position=projectTile(a_pos,a_pos);v_pos=a_pos/8192.0;if (a_pos.y <-32767.5) {v_pos.y=0.0;}if (a_pos.y > 32766.5) {v_pos.y=1.0;}}"),
9644
+ hillshadePrepare: prepare("#ifdef GL_ES\nprecision highp float;\n#endif\nuniform sampler2D u_image;in vec2 v_pos;uniform vec2 u_dimension;uniform float u_zoom;uniform vec4 u_unpack;float getElevation(ivec2 texel) {vec4 data=texelFetch(u_image,texel,0)*255.0;data.a=-1.0;return dot(data,u_unpack);}void main() {ivec2 pos=ivec2(gl_FragCoord.xy)+ivec2(1);float tileSize=u_dimension.x-4.0;float a=getElevation(pos+ivec2(-1,-1));float b=getElevation(pos+ivec2(0,-1));float c=getElevation(pos+ivec2(1,-1));float d=getElevation(pos+ivec2(-1,0));float e=getElevation(pos);float f=getElevation(pos+ivec2(1,0));float g=getElevation(pos+ivec2(-1,1));float h=getElevation(pos+ivec2(0,1));float i=getElevation(pos+ivec2(1,1));float exaggerationFactor=u_zoom < 2.0 ? 0.4 : u_zoom < 4.5 ? 0.35 : 0.3;float exaggeration=u_zoom < 15.0 ? (u_zoom-15.0)*exaggerationFactor : 0.0;vec2 deriv=vec2((c+f+f+i)-(a+d+d+g),(g+h+h+i)-(a+b+b+c))*tileSize/pow(2.0,exaggeration+(28.2562-u_zoom));fragColor=clamp(vec4(deriv.x/8.0+128.0/255.0,deriv.y/8.0+128.0/255.0,1.0,1.0),0.0,1.0);\n#ifdef OVERDRAW_INSPECTOR\nfragColor=vec4(1.0);\n#endif\n}", "uniform mat4 u_matrix;uniform vec2 u_dimension;layout(location=0) in vec2 a_pos;layout(location=1) in vec2 a_texture_pos;out vec2 v_pos;void main() {gl_Position=u_matrix*vec4(a_pos,0,1);highp vec2 epsilon=1.0/u_dimension;float scale=(u_dimension.x-2.0)/u_dimension.x;v_pos=(a_texture_pos/8192.0)*scale+epsilon;}"),
9645
+ hillshade: prepare("uniform sampler2D u_image;in highp vec2 v_pos;uniform vec2 u_latrange;uniform float u_exaggeration;uniform vec4 u_accent;uniform int u_method;uniform float u_altitudes[NUM_ILLUMINATION_SOURCES];uniform float u_azimuths[NUM_ILLUMINATION_SOURCES];uniform vec4 u_shadows[NUM_ILLUMINATION_SOURCES];uniform vec4 u_highlights[NUM_ILLUMINATION_SOURCES];\n#define PI 3.141592653589793\n#define STANDARD 0\n#define COMBINED 1\n#define IGOR 2\n#define MULTIDIRECTIONAL 3\n#define BASIC 4\nfloat get_aspect(vec2 deriv){return deriv.x !=0.0 ? atan(deriv.y,-deriv.x) : PI/2.0*(deriv.y > 0.0 ? 1.0 :-1.0);}void igor_hillshade(vec2 deriv){deriv=deriv*u_exaggeration*2.0;float aspect=get_aspect(deriv);float azimuth=u_azimuths[0]+PI;float slope_stength=atan(length(deriv))*2.0/PI;float aspect_strength=1.0-abs(mod((aspect+azimuth)/PI+0.5,2.0)-1.0);float shadow_strength=slope_stength*aspect_strength;float highlight_strength=slope_stength*(1.0-aspect_strength);fragColor=u_shadows[0]*shadow_strength+u_highlights[0]*highlight_strength;}void standard_hillshade(vec2 deriv){float azimuth=u_azimuths[0]+PI;float slope=atan(0.625*length(deriv));float aspect=get_aspect(deriv);float intensity=u_exaggeration;float base=1.875-intensity*1.75;float maxValue=0.5*PI;float scaledSlope=intensity !=0.5 ? ((pow(base,slope)-1.0)/(pow(base,maxValue)-1.0))*maxValue : slope;float accent=cos(scaledSlope);vec4 accent_color=(1.0-accent)*u_accent*clamp(intensity*2.0,0.0,1.0);float shade=abs(mod((aspect+azimuth)/PI+0.5,2.0)-1.0);vec4 shade_color=mix(u_shadows[0],u_highlights[0],shade)*sin(scaledSlope)*clamp(intensity*2.0,0.0,1.0);fragColor=accent_color*(1.0-shade_color.a)+shade_color;}void basic_hillshade(vec2 deriv){deriv=deriv*u_exaggeration*2.0;float azimuth=u_azimuths[0]+PI;float cos_az=cos(azimuth);float sin_az=sin(azimuth);float cos_alt=cos(u_altitudes[0]);float sin_alt=sin(u_altitudes[0]);float cang=(sin_alt-(deriv.y*cos_az*cos_alt-deriv.x*sin_az*cos_alt))/sqrt(1.0+dot(deriv,deriv));float shade=clamp(cang,0.0,1.0);if(shade > 0.5){fragColor=u_highlights[0]*(2.0*shade-1.0);}else\n{fragColor=u_shadows[0]*(1.0-2.0*shade);}}void multidirectional_hillshade(vec2 deriv){deriv=deriv*u_exaggeration*2.0;fragColor=vec4(0,0,0,0);for(int i=0; i < NUM_ILLUMINATION_SOURCES; i++){float cos_alt=cos(u_altitudes[i]);float sin_alt=sin(u_altitudes[i]);float cos_az=-cos(u_azimuths[i]);float sin_az=-sin(u_azimuths[i]);float cang=(sin_alt-(deriv.y*cos_az*cos_alt-deriv.x*sin_az*cos_alt))/sqrt(1.0+dot(deriv,deriv));float shade=clamp(cang,0.0,1.0);if(shade > 0.5){fragColor+=u_highlights[i]*(2.0*shade-1.0)/float(NUM_ILLUMINATION_SOURCES);}else\n{fragColor+=u_shadows[i]*(1.0-2.0*shade)/float(NUM_ILLUMINATION_SOURCES);}}}void combined_hillshade(vec2 deriv){deriv=deriv*u_exaggeration*2.0;float azimuth=u_azimuths[0]+PI;float cos_az=cos(azimuth);float sin_az=sin(azimuth);float cos_alt=cos(u_altitudes[0]);float sin_alt=sin(u_altitudes[0]);float cang=acos((sin_alt-(deriv.y*cos_az*cos_alt-deriv.x*sin_az*cos_alt))/sqrt(1.0+dot(deriv,deriv)));cang=clamp(cang,0.0,PI/2.0);float shade=cang*atan(length(deriv))*4.0/PI/PI;float highlight=(PI/2.0-cang)*atan(length(deriv))*4.0/PI/PI;fragColor=u_shadows[0]*shade+u_highlights[0]*highlight;}void main() {highp vec2 size=vec2(textureSize(u_image,0));highp vec2 texturePos=(v_pos*(size-2.0)+1.0)/size;vec4 pixel=texture(u_image,texturePos);float scaleFactor=cos(radians((u_latrange[0]-u_latrange[1])*(1.0-v_pos.y)+u_latrange[1]));vec2 deriv=(pixel.rg-128.0/255.0)*8.0/scaleFactor;if (u_method==BASIC) {basic_hillshade(deriv);} else if (u_method==COMBINED) {combined_hillshade(deriv);} else if (u_method==IGOR) {igor_hillshade(deriv);} else if (u_method==MULTIDIRECTIONAL) {multidirectional_hillshade(deriv);} else if (u_method==STANDARD) {standard_hillshade(deriv);} else {standard_hillshade(deriv);}\n#ifdef OVERDRAW_INSPECTOR\nfragColor=vec4(1.0);\n#endif\n}", "uniform mat4 u_matrix;layout(location=0) in vec2 a_pos;out vec2 v_pos;void main() {gl_Position=projectTile(a_pos,a_pos);v_pos=a_pos/8192.0;if (a_pos.y <-32767.5) {v_pos.y=0.0;}if (a_pos.y > 32766.5) {v_pos.y=1.0;}}"),
9628
9646
  line: prepare("flat in vec2 v_width2;in vec2 v_normal;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\nvoid main() {\n#pragma maplibre: initialize highp vec4 color\n#pragma maplibre: initialize lowp float blur\n#pragma maplibre: initialize lowp float opacity\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);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\nlayout(location=0) in ivec2 a_pos_normal;layout(location=1) in uvec4 a_data;uniform vec2 u_translation;uniform mediump float u_ratio;out vec2 v_normal;flat out vec2 v_width2;out float v_gamma_scale;out highp float v_linesofar;\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\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\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);v_linesofar=float((a_data.z >> 2u)+a_data.w*64u)*2.0;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\nv_width2=vec2(outset,inset);}"),
9629
9647
  lineGradient: prepare("uniform sampler2D u_image;flat in vec2 v_width2;in vec2 v_normal;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\nvoid main() {\n#pragma maplibre: initialize lowp float blur\n#pragma maplibre: initialize lowp float opacity\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);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\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 float u_image_height;out vec2 v_normal;flat out vec2 v_width2;out float v_gamma_scale;out highp vec2 v_uv;\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\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\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);highp float texel_height=1.0/u_image_height;highp 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\nv_width2=vec2(outset,inset);}"),
9630
9648
  linePattern: prepare("#ifdef GL_ES\nprecision highp float;\n#endif\nuniform vec2 u_texsize;uniform float u_fade;uniform mediump vec3 u_scale;uniform sampler2D u_image;in vec2 v_normal;flat in vec2 v_width2;in float v_linesofar;in float v_gamma_scale;flat in float v_width;\n#ifdef GLOBE\nin float v_depth;\n#endif\n#pragma maplibre: define lowp vec4 pattern_from\n#pragma maplibre: define lowp vec4 pattern_to\n#pragma maplibre: define lowp float pixel_ratio_from\n#pragma maplibre: define lowp float pixel_ratio_to\n#pragma maplibre: define lowp float blur\n#pragma maplibre: define lowp float opacity\nvoid main() {\n#pragma maplibre: initialize mediump vec4 pattern_from\n#pragma maplibre: initialize mediump vec4 pattern_to\n#pragma maplibre: initialize lowp float pixel_ratio_from\n#pragma maplibre: initialize lowp float pixel_ratio_to\n#pragma maplibre: initialize lowp float blur\n#pragma maplibre: initialize lowp float opacity\nclipAntimeridian();vec2 pattern_tl_a=pattern_from.xy;vec2 pattern_br_a=pattern_from.zw;vec2 pattern_tl_b=pattern_to.xy;vec2 pattern_br_b=pattern_to.zw;float tileZoomRatio=u_scale.x;float fromScale=u_scale.y;float toScale=u_scale.z;vec2 display_size_a=(pattern_br_a-pattern_tl_a)/pixel_ratio_from;vec2 display_size_b=(pattern_br_b-pattern_tl_b)/pixel_ratio_to;vec2 pattern_size_a=vec2(display_size_a.x*fromScale/tileZoomRatio,display_size_a.y);vec2 pattern_size_b=vec2(display_size_b.x*toScale/tileZoomRatio,display_size_b.y);float aspect_a=display_size_a.y/v_width;float aspect_b=display_size_b.y/v_width;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 x_a=mod(v_linesofar/pattern_size_a.x*aspect_a,1.0);float x_b=mod(v_linesofar/pattern_size_b.x*aspect_b,1.0);float y=0.5*v_normal.y+0.5;vec2 texel_size=1.0/u_texsize;vec2 pos_a=mix(pattern_tl_a*texel_size-texel_size,pattern_br_a*texel_size+texel_size,vec2(x_a,y));vec2 pos_b=mix(pattern_tl_b*texel_size-texel_size,pattern_br_b*texel_size+texel_size,vec2(x_b,y));vec4 color=mix(texture(u_image,pos_a),texture(u_image,pos_b),u_fade);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;out vec2 v_normal;flat out vec2 v_width2;out float v_linesofar;out float v_gamma_scale;flat out float v_width;\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 lowp float offset\n#pragma maplibre: define mediump float gapwidth\n#pragma maplibre: define mediump float width\n#pragma maplibre: define lowp float floorwidth\n#pragma maplibre: define lowp vec4 pattern_from\n#pragma maplibre: define lowp vec4 pattern_to\n#pragma maplibre: define lowp float pixel_ratio_from\n#pragma maplibre: define lowp float pixel_ratio_to\nvoid main() {\n#pragma maplibre: initialize lowp float blur\n#pragma maplibre: initialize lowp float opacity\n#pragma maplibre: initialize lowp float offset\n#pragma maplibre: initialize mediump float gapwidth\n#pragma maplibre: initialize mediump float width\n#pragma maplibre: initialize lowp float floorwidth\n#pragma maplibre: initialize mediump vec4 pattern_from\n#pragma maplibre: initialize mediump vec4 pattern_to\n#pragma maplibre: initialize lowp float pixel_ratio_from\n#pragma maplibre: initialize lowp float pixel_ratio_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\nv_linesofar=a_linesofar;v_width2=vec2(outset,inset);v_width=floorwidth;}"),
@@ -10367,7 +10385,7 @@ var TransformHelper = class {
10367
10385
  const altitudeAGL = alt - elevation;
10368
10386
  let distanceToCenter;
10369
10387
  let clampedElevation = elevation;
10370
- if (dzNormalized * altitudeAGL >= 0 || Math.abs(dzNormalized) < .1) {
10388
+ if (dzNormalized * altitudeAGL >= 0 || Math.abs(dzNormalized) < Math.cos(degreesToRadians(89.25))) {
10371
10389
  distanceToCenter = 1e4;
10372
10390
  clampedElevation = alt + distanceToCenter * dzNormalized;
10373
10391
  } else distanceToCenter = -altitudeAGL / dzNormalized;
@@ -11685,7 +11703,7 @@ var MercatorTransform = class MercatorTransform {
11685
11703
  }
11686
11704
  isPointOnMapSurface(p, terrain) {
11687
11705
  if (terrain) return this.screenTerrainPointToMercatorCoordinate(p, terrain) != null;
11688
- return p.y > this.height / 2 - getMercatorHorizon(this);
11706
+ return p.y > this.centerPoint.y - getMercatorHorizon(this);
11689
11707
  }
11690
11708
  calculatePosMatrix(tileID, aligned = false, useFloat32 = false) {
11691
11709
  const posMatrixKey = tileID.key ?? calculateTileKey(tileID.wrap, tileID.canonical.z, tileID.canonical.z, tileID.canonical.x, tileID.canonical.y);
@@ -12171,42 +12189,64 @@ var MercatorCameraHelper = class {
12171
12189
  tr.setLocationAtPoint(tr.renderWorldCopies ? newCenter.wrap() : newCenter, pointAtOffset);
12172
12190
  }
12173
12191
  };
12192
+ const endTransform = this._transformAtAnimationEnd(tr, endZoom, endEulerAngles, options.padding);
12193
+ if (options.around) endTransform.setLocationAtPoint(options.around, options.aroundPoint);
12194
+ else endTransform.setLocationAtPoint(center, endTransform.centerPoint.add(options.offsetAsPoint));
12174
12195
  return {
12175
12196
  easeFunc,
12176
12197
  isZooming,
12177
- elevationCenter: center
12198
+ elevationCenter: endTransform.center
12178
12199
  };
12179
12200
  }
12180
12201
  handleFlyTo(tr, options) {
12181
12202
  const optionsZoom = typeof options.zoom !== "undefined";
12182
12203
  const startZoom = tr.zoom;
12183
12204
  const constrained = tr.applyConstrain(LngLat.convert(options.center || options.locationAtOffset), optionsZoom ? +options.zoom : startZoom);
12184
- const targetCenter = constrained.center;
12205
+ const constrainedCenter = constrained.center;
12185
12206
  const targetZoom = constrained.zoom;
12186
- normalizeCenter(tr, targetCenter);
12207
+ normalizeCenter(tr, constrainedCenter);
12187
12208
  const startWorldSize = tr.worldSize;
12188
12209
  const from = projectToWorldCoordinates(startWorldSize, options.locationAtOffset);
12189
- const delta = projectToWorldCoordinates(startWorldSize, targetCenter).sub(from);
12210
+ const delta = projectToWorldCoordinates(startWorldSize, constrainedCenter).sub(from);
12190
12211
  const pixelPathLength = delta.mag();
12191
12212
  const scaleOfZoom = zoomScale(targetZoom - startZoom);
12192
12213
  const requestedMinZoom = typeof options.minZoom !== "undefined" ? +options.minZoom : tr.minZoom;
12193
12214
  const effectiveMinZoom = Math.max(requestedMinZoom, tr.minZoom);
12194
12215
  const minZoomPreConstrain = Math.min(effectiveMinZoom, startZoom, targetZoom);
12195
- const minZoom = tr.applyConstrain(targetCenter, minZoomPreConstrain).zoom;
12216
+ const minZoom = tr.applyConstrain(constrainedCenter, minZoomPreConstrain).zoom;
12196
12217
  const scaleOfMinZoom = zoomScale(minZoom - startZoom);
12197
12218
  const easeFunc = (k, scale, centerFactor, pointAtOffset) => {
12198
12219
  tr.setZoom(k === 1 ? targetZoom : startZoom + scaleZoom(scale));
12199
- const newCenter = k === 1 ? targetCenter : unprojectFromWorldCoordinates(startWorldSize, from.add(delta.mult(centerFactor)));
12220
+ const newCenter = k === 1 ? constrainedCenter : unprojectFromWorldCoordinates(startWorldSize, from.add(delta.mult(centerFactor)));
12200
12221
  tr.setLocationAtPoint(tr.renderWorldCopies ? newCenter.wrap() : newCenter, pointAtOffset);
12201
12222
  };
12223
+ const endTransform = this._transformAtAnimationEnd(tr, targetZoom, {
12224
+ roll: options.roll,
12225
+ pitch: options.pitch,
12226
+ bearing: options.bearing
12227
+ }, options.padding);
12228
+ endTransform.setLocationAtPoint(constrainedCenter, endTransform.centerPoint.add(options.offsetAsPoint));
12202
12229
  return {
12203
12230
  easeFunc,
12204
12231
  scaleOfZoom,
12205
- targetCenter,
12232
+ targetCenter: endTransform.center,
12206
12233
  scaleOfMinZoom,
12207
12234
  pixelPathLength
12208
12235
  };
12209
12236
  }
12237
+ /**
12238
+ * A copy of the transform at the animation's end zoom, angles and padding, for reading where the map center
12239
+ * ends up once a location is placed at its screen point.
12240
+ */
12241
+ _transformAtAnimationEnd(tr, zoom, angles, padding) {
12242
+ const endTransform = tr.clone();
12243
+ endTransform.setZoom(zoom);
12244
+ endTransform.setRoll(angles.roll);
12245
+ endTransform.setPitch(angles.pitch);
12246
+ endTransform.setBearing(angles.bearing);
12247
+ endTransform.setPadding(padding);
12248
+ return endTransform;
12249
+ }
12210
12250
  };
12211
12251
  //#endregion
12212
12252
  //#region src/style/projection_properties.g.ts
@@ -12714,9 +12754,11 @@ function raySphereIntersection(origin, direction, radius = 1) {
12714
12754
  const q = -originDotDirection + (originDotDirection < 0 ? 1 : -1) * Math.sqrt(discriminant);
12715
12755
  const t0 = c / q;
12716
12756
  const t1 = q;
12757
+ const tMax = Math.max(t0, t1);
12758
+ if (tMax < 0) return null;
12717
12759
  return {
12718
12760
  tMin: Math.min(t0, t1),
12719
- tMax: Math.max(t0, t1)
12761
+ tMax
12720
12762
  };
12721
12763
  }
12722
12764
  /** Height of the atmosphere relative to the globe radius, 100 km for Earth. */
@@ -14539,6 +14581,7 @@ var VerticalPerspectiveCameraHelper = class VerticalPerspectiveCameraHelper {
14539
14581
  }
14540
14582
  cameraForBoxAndBearing(options, padding, bounds, bearing, tr) {
14541
14583
  const result = cameraForBoxAndBearing(options, padding, bounds, bearing, tr);
14584
+ if (!result) return;
14542
14585
  const xLeft = padding.left / tr.width * 2 - 1;
14543
14586
  const xRight = (tr.width - padding.right) / tr.width * 2 - 1;
14544
14587
  const yTop = padding.top / tr.height * -2 + 1;
@@ -16330,13 +16373,11 @@ var UniformBuffer = class {
16330
16373
  this.buffer = gl.createBuffer();
16331
16374
  gl.bindBuffer(gl.UNIFORM_BUFFER, this.buffer);
16332
16375
  gl.bufferData(gl.UNIFORM_BUFFER, layout.sizeWords * 4, gl.DYNAMIC_DRAW);
16333
- gl.bindBufferBase(gl.UNIFORM_BUFFER, binding, this.buffer);
16334
16376
  this.uploaded = new Float32Array(layout.sizeWords);
16335
16377
  this.pending = new Float32Array(layout.sizeWords);
16336
16378
  this.uploadedWords = new Uint32Array(this.uploaded.buffer);
16337
16379
  this.pendingWords = new Uint32Array(this.pending.buffer);
16338
16380
  this.hasData = false;
16339
- this.bindingDirty = false;
16340
16381
  }
16341
16382
  upload() {
16342
16383
  const gl = this.context.gl;
@@ -16349,19 +16390,23 @@ var UniformBuffer = class {
16349
16390
  break;
16350
16391
  }
16351
16392
  }
16352
- this.bind();
16353
- if (!changed) return;
16393
+ if (!changed) {
16394
+ this.bind();
16395
+ return;
16396
+ }
16354
16397
  gl.bindBufferBase(gl.UNIFORM_BUFFER, this.binding, this.buffer);
16398
+ this.context.boundUniformBuffers[this.binding] = this.buffer;
16355
16399
  gl.bufferData(gl.UNIFORM_BUFFER, this.pending, gl.DYNAMIC_DRAW);
16356
16400
  this.uploaded.set(this.pending);
16357
16401
  this.hasData = true;
16358
16402
  }
16359
16403
  /** Restores the indexed binding after external rendering without uploading unchanged data. */
16360
16404
  bind() {
16361
- if (!this.bindingDirty) return;
16405
+ const boundUniformBuffers = this.context.boundUniformBuffers;
16406
+ if (boundUniformBuffers[this.binding] === this.buffer) return;
16362
16407
  const gl = this.context.gl;
16363
16408
  gl.bindBufferBase(gl.UNIFORM_BUFFER, this.binding, this.buffer);
16364
- this.bindingDirty = false;
16409
+ boundUniformBuffers[this.binding] = this.buffer;
16365
16410
  }
16366
16411
  destroy() {
16367
16412
  const gl = this.context.gl;
@@ -16402,7 +16447,7 @@ const layout$2 = std140Layout([
16402
16447
  const offsets$2 = layout$2.offsets;
16403
16448
  /**
16404
16449
  * @internal
16405
- * The buffer behind the `ProjectionUBO` block in the shader preludes, written by `Program.draw` before each draw.
16450
+ * The buffer behind the `ProjectionUBO` block in the shader preludes.
16406
16451
  */
16407
16452
  function createProjectionUniformBuffer(context) {
16408
16453
  return new UniformBuffer(context, UBO_BINDINGS.ProjectionUBO, layout$2);
@@ -16417,6 +16462,34 @@ function updateProjectionUniformBuffer(buffer, projectionData) {
16417
16462
  buffer.pendingWords[offsets$2.u_projection_clip_antimeridian] = projectionData.clipAntimeridian ? 1 : 0;
16418
16463
  buffer.upload();
16419
16464
  }
16465
+ function bindProjectionUniformBuffer(context, projectionData) {
16466
+ if (!projectionData) {
16467
+ context.projectionUniformBuffer.bind();
16468
+ return;
16469
+ }
16470
+ const key = projectionData.uniformBufferKey;
16471
+ if (key === void 0) {
16472
+ updateProjectionUniformBuffer(context.projectionUniformBuffer, projectionData);
16473
+ return;
16474
+ }
16475
+ const keyedBuffer = context.keyedProjectionUniformBuffers.get(key);
16476
+ if (keyedBuffer) {
16477
+ keyedBuffer.bind();
16478
+ return;
16479
+ }
16480
+ const buffer = context.freeProjectionUniformBuffers.pop() ?? createProjectionUniformBuffer(context);
16481
+ context.keyedProjectionUniformBuffers.set(key, buffer);
16482
+ updateProjectionUniformBuffer(buffer, projectionData);
16483
+ }
16484
+ function releaseProjectionUniformBuffers(context) {
16485
+ context.freeProjectionUniformBuffers.push(...context.keyedProjectionUniformBuffers.values());
16486
+ context.keyedProjectionUniformBuffers.clear();
16487
+ }
16488
+ function destroyProjectionUniformBuffers(context) {
16489
+ context.projectionUniformBuffer.destroy();
16490
+ for (const buffer of context.keyedProjectionUniformBuffers.values()) buffer.destroy();
16491
+ for (const buffer of context.freeProjectionUniformBuffers) buffer.destroy();
16492
+ }
16420
16493
  //#endregion
16421
16494
  //#region src/webgl/terrain_uniform_buffer.ts
16422
16495
  const layout$1 = std140Layout([
@@ -16561,7 +16634,6 @@ var Program = class {
16561
16634
  const gl = context.gl;
16562
16635
  if (this.failedToCreate) return;
16563
16636
  context.program.set(this.program);
16564
- context.projectionUniformBuffer.bind();
16565
16637
  context.terrainUniformBuffer.bind();
16566
16638
  context.frameUniformBuffer.bind();
16567
16639
  context.setDepthMode(depthMode);
@@ -16576,7 +16648,7 @@ var Program = class {
16576
16648
  for (const name in this.terrainUniforms) this.terrainUniforms[name].set(terrain[name]);
16577
16649
  updateTerrainUniformBuffer(context.terrainUniformBuffer, terrain);
16578
16650
  }
16579
- if (projectionData) updateProjectionUniformBuffer(context.projectionUniformBuffer, projectionData);
16651
+ bindProjectionUniformBuffer(context, projectionData);
16580
16652
  if (uniformValues) for (const name in this.fixedUniforms) this.fixedUniforms[name].set(uniformValues[name]);
16581
16653
  if (configuration) configuration.setUniforms(context, this.binderUniforms, currentProperties, { zoom });
16582
16654
  let primitiveSize = 0;
@@ -17964,7 +18036,10 @@ var Context = class {
17964
18036
  this.maxTextureSize = gl.getParameter(gl.MAX_TEXTURE_SIZE);
17965
18037
  gl.getExtension("EXT_color_buffer_half_float");
17966
18038
  gl.getExtension("EXT_color_buffer_float");
18039
+ this.boundUniformBuffers = [];
17967
18040
  this.projectionUniformBuffer = createProjectionUniformBuffer(this);
18041
+ this.keyedProjectionUniformBuffers = /* @__PURE__ */ new Map();
18042
+ this.freeProjectionUniformBuffers = [];
17968
18043
  this.terrainUniformBuffer = createTerrainUniformBuffer(this);
17969
18044
  this.frameUniformBuffer = createFrameUniformBuffer(this);
17970
18045
  }
@@ -18028,9 +18103,7 @@ var Context = class {
18028
18103
  this.pixelStoreUnpack.dirty = true;
18029
18104
  this.pixelStoreUnpackPremultiplyAlpha.dirty = true;
18030
18105
  this.pixelStoreUnpackFlipY.dirty = true;
18031
- this.projectionUniformBuffer.bindingDirty = true;
18032
- this.terrainUniformBuffer.bindingDirty = true;
18033
- this.frameUniformBuffer.bindingDirty = true;
18106
+ this.boundUniformBuffers = [];
18034
18107
  }
18035
18108
  /**
18036
18109
  * Reset some GL state to default values before handing users the raw context, as we do for
@@ -18209,12 +18282,15 @@ function createRenderContext(transform, projection, terrain) {
18209
18282
  };
18210
18283
  }
18211
18284
  function getProjectionDataForTile(renderContext, tileID, options = {}) {
18212
- return renderContext.transform.getProjectionData({
18285
+ const projectionData = renderContext.transform.getProjectionData({
18213
18286
  overscaledTileID: tileID,
18214
18287
  aligned: options.aligned,
18215
18288
  applyGlobeMatrix: !renderContext.isRenderingToTexture,
18216
18289
  applyTerrainMatrix: options.applyTerrainMatrix ?? true
18217
18290
  });
18291
+ if (renderContext.isRenderingToTexture) return projectionData;
18292
+ projectionData.uniformBufferKey = options.aligned ? `${tileID.key}/aligned` : tileID.key;
18293
+ return projectionData;
18218
18294
  }
18219
18295
  /**
18220
18296
  * Returns terrain data for a tile.
@@ -19767,8 +19843,8 @@ var Painter = class Painter {
19767
19843
  this.crossTileSymbolIndex = new CrossTileSymbolIndex();
19768
19844
  }
19769
19845
  resize(width, height, pixelRatio) {
19770
- this.width = Math.floor(width * pixelRatio);
19771
- this.height = Math.floor(height * pixelRatio);
19846
+ this.width = Math.round(width * pixelRatio);
19847
+ this.height = Math.round(height * pixelRatio);
19772
19848
  this.pixelRatio = pixelRatio;
19773
19849
  this.context.viewport.set([
19774
19850
  0,
@@ -20024,6 +20100,7 @@ var Painter = class Painter {
20024
20100
  this.symbolFadeChange = style.placement.symbolFadeChange(now());
20025
20101
  updateFrameUniformBuffer(this.context.frameUniformBuffer, this);
20026
20102
  this.imageManager.beginFrame();
20103
+ releaseProjectionUniformBuffers(this.context);
20027
20104
  const layerIds = this.style._order;
20028
20105
  const tileManagers = this.style.tileManagers;
20029
20106
  const coordsAscending = {};
@@ -20329,7 +20406,7 @@ var Painter = class Painter {
20329
20406
  if (this.tileExtentMesh) this.tileExtentMesh.vertexBuffer?.destroy();
20330
20407
  if (this.tileExtentMesh) this.tileExtentMesh.indexBuffer?.destroy();
20331
20408
  if (this.debugOverlayTexture) this.debugOverlayTexture.destroy();
20332
- this.context.projectionUniformBuffer.destroy();
20409
+ destroyProjectionUniformBuffers(this.context);
20333
20410
  this.context.terrainUniformBuffer.destroy();
20334
20411
  this.context.frameUniformBuffer.destroy();
20335
20412
  if (this.cache) {
@@ -21065,7 +21142,7 @@ var TapZoomHandler = class {
21065
21142
  return { cameraAnimation: (map) => map.easeTo({
21066
21143
  duration: 300,
21067
21144
  zoom: evaluateZoomSnap(tr.zoom + 1, map.getZoomSnap()),
21068
- around: tr.unproject(zoomInPoint)
21145
+ around: tr.transform.isPointOnMapSurface(zoomInPoint) ? tr.unproject(zoomInPoint) : void 0
21069
21146
  }, { originalEvent: e }) };
21070
21147
  } else if (zoomOutPoint) {
21071
21148
  this._active = true;
@@ -21074,7 +21151,7 @@ var TapZoomHandler = class {
21074
21151
  return { cameraAnimation: (map) => map.easeTo({
21075
21152
  duration: 300,
21076
21153
  zoom: evaluateZoomSnap(tr.zoom - 1, map.getZoomSnap()),
21077
- around: tr.unproject(zoomOutPoint)
21154
+ around: tr.transform.isPointOnMapSurface(zoomOutPoint) ? tr.unproject(zoomOutPoint) : void 0
21078
21155
  }, { originalEvent: e }) };
21079
21156
  }
21080
21157
  }
@@ -22125,7 +22202,7 @@ var ClickZoomHandler = class {
22125
22202
  map.easeTo({
22126
22203
  duration: 300,
22127
22204
  zoom: evaluateZoomSnap(this._tr.zoom + (e.shiftKey ? -1 : 1), map.getZoomSnap()),
22128
- around: this._tr.unproject(point)
22205
+ around: this._tr.transform.isPointOnMapSurface(point) ? this._tr.unproject(point) : void 0
22129
22206
  }, { originalEvent: e });
22130
22207
  } };
22131
22208
  }
@@ -22994,6 +23071,10 @@ var HandlerManager = class {
22994
23071
  _handleMapControls({ terrain, tr, deltasForHelper, preZoomAroundLoc, combinedEventsInProgress, panDelta }) {
22995
23072
  const cameraHelper = this._camera.cameraHelper;
22996
23073
  cameraHelper.handleMapControlsRollPitchBearingZoom(deltasForHelper, tr);
23074
+ if (!terrain && !cameraHelper.useGlobeControls && !tr.isPointOnMapSurface(deltasForHelper.around)) {
23075
+ if (panDelta) tr.setCenter(tr.screenPointToLocation(tr.centerPoint.sub(panDelta)));
23076
+ return;
23077
+ }
22997
23078
  if (!terrain) {
22998
23079
  cameraHelper.handleMapControlsPan(deltasForHelper, tr, preZoomAroundLoc);
22999
23080
  return;
@@ -23185,7 +23266,7 @@ var Camera = class extends Evented {
23185
23266
  }
23186
23267
  setVerticalFieldOfView(fov, eventData) {
23187
23268
  if (fov != this.transform.fov) {
23188
- this.transform.setFov(fov);
23269
+ this.applyTransformChange((tr) => tr.setFov(fov));
23189
23270
  this.fire(new MapMovementEvent("movestart", eventData)).fire(new MapMovementEvent("move", eventData)).fire(new MapMovementEvent("moveend", eventData));
23190
23271
  }
23191
23272
  return this;
@@ -23422,10 +23503,10 @@ var Camera = class extends Evented {
23422
23503
  this._zooming ||= easeHandler.isZooming;
23423
23504
  this._easeId = options.easeId;
23424
23505
  this._prepareEase(eventData, options.noMoveStart, currently);
23425
- if (this.terrain) this._prepareElevation(easeHandler.elevationCenter);
23506
+ if (this.terrain) this._prepareElevation(easeHandler.elevationCenter, tr);
23426
23507
  this._ease((k) => {
23427
23508
  easeHandler.easeFunc(k);
23428
- if (this.terrain && !options.freezeElevation) this._updateElevation(k);
23509
+ if (this.terrain && !options.freezeElevation) this._updateElevation(k, tr);
23429
23510
  this.applyUpdatedTransform(tr);
23430
23511
  this._fireMoveEvents(eventData);
23431
23512
  }, (interruptingEaseId) => {
@@ -23443,23 +23524,37 @@ var Camera = class extends Evented {
23443
23524
  if (this._pitching && !currently.pitching) this.fire(new MapMovementEvent("pitchstart", eventData));
23444
23525
  if (this._rolling && !currently.rolling) this.fire(new MapMovementEvent("rollstart", eventData));
23445
23526
  }
23446
- _prepareElevation(center) {
23527
+ /**
23528
+ * @internal
23529
+ * Starts easing the center elevation: records where it stands on the transform the animation edits and
23530
+ * samples the terrain under the map center the animation ends on.
23531
+ * @param center - the map center when the animation ends
23532
+ * @param tr - the transform the animation edits
23533
+ */
23534
+ _prepareElevation(center, tr) {
23447
23535
  this._elevationCenter = center;
23448
- this._elevationStart = this.transform.elevation;
23449
- this._elevationTarget = this.terrain.getElevationForLngLat(center, this.transform);
23536
+ this._elevationStart = tr.elevation;
23537
+ this._elevationTarget = this.terrain.getElevationForLngLat(center, tr);
23450
23538
  this.elevationFreeze = true;
23451
23539
  }
23452
- _updateElevation(k) {
23453
- if (this._elevationStart === void 0 || this._elevationCenter === void 0) this._prepareElevation(this.transform.center);
23454
- this.transform.setMinElevationForCurrentTile(this.terrain.getMinTileElevationForLngLatZoom(this._elevationCenter, this.transform.tileZoom));
23455
- const elevation = this.terrain.getElevationForLngLat(this._elevationCenter, this.transform);
23540
+ /**
23541
+ * @internal
23542
+ * Eases the center elevation towards the terrain under `_elevationCenter`, on the transform the
23543
+ * animation edits, so that `applyUpdatedTransform` carries it to the rendered transform.
23544
+ * @param k - the animation's progress, 0 to 1
23545
+ * @param tr - the transform the animation edits
23546
+ */
23547
+ _updateElevation(k, tr) {
23548
+ if (this._elevationStart === void 0 || this._elevationCenter === void 0) this._prepareElevation(tr.center, tr);
23549
+ tr.setMinElevationForCurrentTile(this.terrain.getMinTileElevationForLngLatZoom(this._elevationCenter, tr.tileZoom));
23550
+ const elevation = this.terrain.getElevationForLngLat(this._elevationCenter, tr);
23456
23551
  if (k < 1 && elevation !== this._elevationTarget) {
23457
23552
  const pitch1 = this._elevationTarget - this._elevationStart;
23458
23553
  const pitch2 = (elevation - (pitch1 * k + this._elevationStart)) / (1 - k);
23459
23554
  this._elevationStart += k * (pitch1 - pitch2);
23460
23555
  this._elevationTarget = elevation;
23461
23556
  }
23462
- this.transform.setElevation(interpolateFactory.number(this._elevationStart, this._elevationTarget, k));
23557
+ tr.setElevation(interpolateFactory.number(this._elevationStart, this._elevationTarget, k));
23463
23558
  }
23464
23559
  _finalizeElevation() {
23465
23560
  this.elevationFreeze = false;
@@ -23547,6 +23642,19 @@ var Camera = class extends Evented {
23547
23642
  }
23548
23643
  this.transform.apply(finalTransform, false);
23549
23644
  }
23645
+ /**
23646
+ * @internal
23647
+ * Applies a change that is not itself a movement, such as new bounds, limits or field of view, the way
23648
+ * any camera update is applied. A requested camera state created only for this change is dropped again,
23649
+ * so a later movement cannot restore the old values.
23650
+ */
23651
+ applyTransformChange(change) {
23652
+ const hadRequestedCameraState = this._requestedCameraState !== void 0;
23653
+ const tr = this.getTransformForUpdate();
23654
+ change(tr);
23655
+ this.applyUpdatedTransform(tr);
23656
+ if (!hadRequestedCameraState) delete this._requestedCameraState;
23657
+ }
23550
23658
  _fireMoveEvents(eventData) {
23551
23659
  this.fire(new MapMovementEvent("move", eventData));
23552
23660
  if (this._zooming) this.fire(new MapMovementEvent("zoom", eventData));
@@ -23665,7 +23773,7 @@ var Camera = class extends Evented {
23665
23773
  this._rolling = roll !== startRoll;
23666
23774
  this._padding = !tr.isPaddingEqual(padding);
23667
23775
  this._prepareEase(eventData, false);
23668
- if (this.terrain) this._prepareElevation(flyToHandler.targetCenter);
23776
+ if (this.terrain) this._prepareElevation(flyToHandler.targetCenter, tr);
23669
23777
  this._ease((k) => {
23670
23778
  const s = k * S;
23671
23779
  const scale = 1 / w(s);
@@ -23678,7 +23786,7 @@ var Camera = class extends Evented {
23678
23786
  pointAtOffset = tr.centerPoint.add(offsetAsPoint);
23679
23787
  }
23680
23788
  flyToHandler.easeFunc(k, scale, centerFactor, pointAtOffset);
23681
- if (this.terrain && !options.freezeElevation) this._updateElevation(k);
23789
+ if (this.terrain && !options.freezeElevation) this._updateElevation(k, tr);
23682
23790
  this.applyUpdatedTransform(tr);
23683
23791
  this._fireMoveEvents(eventData);
23684
23792
  }, () => {
@@ -25411,7 +25519,7 @@ var Map$1 = class extends Evented {
25411
25519
  * ```
25412
25520
  */
25413
25521
  setMaxBounds(bounds) {
25414
- this._camera.transform.setMaxBounds(LngLatBounds.convert(bounds));
25522
+ this._camera.applyTransformChange((tr) => tr.setMaxBounds(LngLatBounds.convert(bounds)));
25415
25523
  return this._update();
25416
25524
  }
25417
25525
  /**
@@ -25438,9 +25546,7 @@ var Map$1 = class extends Evented {
25438
25546
  minZoom = minZoom === null || minZoom === void 0 ? defaultMinZoom : minZoom;
25439
25547
  if (minZoom >= defaultMinZoom && minZoom <= this._camera.transform.maxZoom) {
25440
25548
  const zoomBefore = this._camera.transform.zoom;
25441
- const tr = this._camera.getTransformForUpdate();
25442
- tr.setMinZoom(minZoom);
25443
- this._camera.applyUpdatedTransform(tr);
25549
+ this._camera.applyTransformChange((tr) => tr.setMinZoom(minZoom));
25444
25550
  this._update();
25445
25551
  if (zoomBefore !== this._camera.transform.zoom) this.fire(new MapMovementEvent("zoomstart")).fire(new MapMovementEvent("zoom")).fire(new MapMovementEvent("zoomend")).fire(new MapMovementEvent("movestart")).fire(new MapMovementEvent("move")).fire(new MapMovementEvent("moveend"));
25446
25552
  return this;
@@ -25480,9 +25586,7 @@ var Map$1 = class extends Evented {
25480
25586
  maxZoom = maxZoom === null || maxZoom === void 0 ? defaultMaxZoom : maxZoom;
25481
25587
  if (maxZoom >= this._camera.transform.minZoom) {
25482
25588
  const zoomBefore = this._camera.transform.zoom;
25483
- const tr = this._camera.getTransformForUpdate();
25484
- tr.setMaxZoom(maxZoom);
25485
- this._camera.applyUpdatedTransform(tr);
25589
+ this._camera.applyTransformChange((tr) => tr.setMaxZoom(maxZoom));
25486
25590
  this._update();
25487
25591
  if (zoomBefore !== this._camera.transform.zoom) this.fire(new MapMovementEvent("zoomstart")).fire(new MapMovementEvent("zoom")).fire(new MapMovementEvent("zoomend")).fire(new MapMovementEvent("movestart")).fire(new MapMovementEvent("move")).fire(new MapMovementEvent("moveend"));
25488
25592
  return this;
@@ -25516,9 +25620,7 @@ var Map$1 = class extends Evented {
25516
25620
  if (minPitch < defaultMinPitch) throw new Error(`minPitch must be greater than or equal to ${defaultMinPitch}`);
25517
25621
  if (minPitch >= defaultMinPitch && minPitch <= this._camera.transform.maxPitch) {
25518
25622
  const pitchBefore = this._camera.transform.pitch;
25519
- const tr = this._camera.getTransformForUpdate();
25520
- tr.setMinPitch(minPitch);
25521
- this._camera.applyUpdatedTransform(tr);
25623
+ this._camera.applyTransformChange((tr) => tr.setMinPitch(minPitch));
25522
25624
  this._update();
25523
25625
  if (pitchBefore !== this._camera.transform.pitch) this.fire(new MapMovementEvent("pitchstart")).fire(new MapMovementEvent("pitch")).fire(new MapMovementEvent("pitchend")).fire(new MapMovementEvent("movestart")).fire(new MapMovementEvent("move")).fire(new MapMovementEvent("moveend"));
25524
25626
  return this;
@@ -25548,9 +25650,7 @@ var Map$1 = class extends Evented {
25548
25650
  if (maxPitch > maxPitchThreshold) throw new Error(`maxPitch must be less than or equal to ${maxPitchThreshold}`);
25549
25651
  if (maxPitch >= this._camera.transform.minPitch) {
25550
25652
  const pitchBefore = this._camera.transform.pitch;
25551
- const tr = this._camera.getTransformForUpdate();
25552
- tr.setMaxPitch(maxPitch);
25553
- this._camera.applyUpdatedTransform(tr);
25653
+ this._camera.applyTransformChange((tr) => tr.setMaxPitch(maxPitch));
25554
25654
  this._update();
25555
25655
  if (pitchBefore !== this._camera.transform.pitch) this.fire(new MapMovementEvent("pitchstart")).fire(new MapMovementEvent("pitch")).fire(new MapMovementEvent("pitchend")).fire(new MapMovementEvent("movestart")).fire(new MapMovementEvent("move")).fire(new MapMovementEvent("moveend"));
25556
25656
  return this;
@@ -25633,7 +25733,7 @@ var Map$1 = class extends Evented {
25633
25733
  * @see [Render world copies](https://maplibre.org/maplibre-gl-js/docs/examples/render-world-copies/)
25634
25734
  */
25635
25735
  setRenderWorldCopies(renderWorldCopies) {
25636
- this._camera.transform.setRenderWorldCopies(renderWorldCopies);
25736
+ this._camera.applyTransformChange((tr) => tr.setRenderWorldCopies(renderWorldCopies));
25637
25737
  return this._update();
25638
25738
  }
25639
25739
  /** Sets or clears the callback overriding how the map constrains the viewport's lnglat and zoom to respect the longitude and latitude bounds.
@@ -25651,7 +25751,7 @@ var Map$1 = class extends Evented {
25651
25751
  * @see [Customize the map transform constrain](https://maplibre.org/maplibre-gl-js/docs/examples/customize-the-map-transform-constrain/)
25652
25752
  */
25653
25753
  setTransformConstrain(constrain) {
25654
- this._camera.transform.setConstrainOverride(constrain);
25754
+ this._camera.applyTransformChange((tr) => tr.setConstrainOverride(constrain));
25655
25755
  return this._update();
25656
25756
  }
25657
25757
  /**
@@ -25723,7 +25823,7 @@ var Map$1 = class extends Evented {
25723
25823
  isRotating() {
25724
25824
  return this._camera.isRotating() || this._handlers?.isRotating() || false;
25725
25825
  }
25726
- _createDelegatedListener(type, layerIds, listener) {
25826
+ _createDelegates(type, layerIds, listener) {
25727
25827
  if (type === "mouseenter" || type === "mouseover") {
25728
25828
  let mousein = false;
25729
25829
  const mousemove = (e) => {
@@ -25739,12 +25839,8 @@ var Map$1 = class extends Evented {
25739
25839
  mousein = false;
25740
25840
  };
25741
25841
  return {
25742
- layers: layerIds,
25743
- listener,
25744
- delegates: {
25745
- mousemove,
25746
- mouseout
25747
- }
25842
+ mousemove,
25843
+ mouseout
25748
25844
  };
25749
25845
  } else if (type === "mouseleave" || type === "mouseout") {
25750
25846
  let mousein = false;
@@ -25763,12 +25859,8 @@ var Map$1 = class extends Evented {
25763
25859
  }
25764
25860
  };
25765
25861
  return {
25766
- layers: layerIds,
25767
- listener,
25768
- delegates: {
25769
- mousemove,
25770
- mouseout
25771
- }
25862
+ mousemove,
25863
+ mouseout
25772
25864
  };
25773
25865
  } else {
25774
25866
  const delegate = (e) => {
@@ -25780,17 +25872,14 @@ var Map$1 = class extends Evented {
25780
25872
  delete e.features;
25781
25873
  }
25782
25874
  };
25783
- return {
25784
- layers: layerIds,
25785
- listener,
25786
- delegates: { [type]: delegate }
25787
- };
25875
+ return { [type]: delegate };
25788
25876
  }
25789
25877
  }
25790
- _saveDelegatedListener(type, delegatedListener) {
25878
+ _addDelegatedListener(type, delegatedListener) {
25791
25879
  this._delegatedListeners ||= {};
25792
25880
  this._delegatedListeners[type] ||= [];
25793
25881
  this._delegatedListeners[type].push(delegatedListener);
25882
+ for (const event in delegatedListener.delegates) this.on(event, delegatedListener.delegates[event]);
25794
25883
  }
25795
25884
  _removeDelegatedListener(type, layerIds, listener) {
25796
25885
  if (!this._delegatedListeners?.[type]) return;
@@ -25807,9 +25896,12 @@ var Map$1 = class extends Evented {
25807
25896
  on(type, layerIdsOrListener, listener) {
25808
25897
  if (listener === void 0) return super.on(type, layerIdsOrListener);
25809
25898
  const layerIds = typeof layerIdsOrListener === "string" ? [layerIdsOrListener] : layerIdsOrListener;
25810
- const delegatedListener = this._createDelegatedListener(type, layerIds, listener);
25811
- this._saveDelegatedListener(type, delegatedListener);
25812
- for (const event in delegatedListener.delegates) this.on(event, delegatedListener.delegates[event]);
25899
+ const delegatedListener = {
25900
+ layers: layerIds,
25901
+ listener,
25902
+ delegates: this._createDelegates(type, layerIds, listener)
25903
+ };
25904
+ this._addDelegatedListener(type, delegatedListener);
25813
25905
  return { unsubscribe: () => {
25814
25906
  this._removeDelegatedListener(type, layerIds, listener);
25815
25907
  } };
@@ -25817,16 +25909,15 @@ var Map$1 = class extends Evented {
25817
25909
  once(type, layerIdsOrListener, listener) {
25818
25910
  if (listener === void 0) return super.once(type, layerIdsOrListener);
25819
25911
  const layerIds = typeof layerIdsOrListener === "string" ? [layerIdsOrListener] : layerIdsOrListener;
25820
- const delegatedListener = this._createDelegatedListener(type, layerIds, listener);
25821
- for (const key in delegatedListener.delegates) {
25822
- const delegate = delegatedListener.delegates[key];
25823
- delegatedListener.delegates[key] = (...args) => {
25912
+ const delegatedListener = {
25913
+ layers: layerIds,
25914
+ listener,
25915
+ delegates: this._createDelegates(type, layerIds, (e) => {
25824
25916
  this._removeDelegatedListener(type, layerIds, listener);
25825
- delegate(...args);
25826
- };
25827
- }
25828
- this._saveDelegatedListener(type, delegatedListener);
25829
- for (const event in delegatedListener.delegates) this.once(event, delegatedListener.delegates[event]);
25917
+ listener.call(this, e);
25918
+ })
25919
+ };
25920
+ this._addDelegatedListener(type, delegatedListener);
25830
25921
  return this;
25831
25922
  }
25832
25923
  off(type, layerIdsOrListener, listener) {
@@ -27246,12 +27337,16 @@ var Map$1 = class extends Evented {
27246
27337
  getCanvas() {
27247
27338
  return this._canvas;
27248
27339
  }
27340
+ /**
27341
+ * @internal
27342
+ * The viewport in whole CSS pixels, shared by the canvas, the painter and the transform.
27343
+ */
27249
27344
  _containerDimensions() {
27250
27345
  let width = 0;
27251
27346
  let height = 0;
27252
27347
  if (this._container) {
27253
- width = this._container.clientWidth || 400;
27254
- height = this._container.clientHeight || 300;
27348
+ width = Math.floor(this._container.clientWidth) || 400;
27349
+ height = Math.floor(this._container.clientHeight) || 300;
27255
27350
  }
27256
27351
  return [width, height];
27257
27352
  }
@@ -27339,11 +27434,19 @@ var Map$1 = class extends Evented {
27339
27434
  this._container.removeEventListener("scroll", this._onMapScroll, false);
27340
27435
  this._container.classList.remove("maplibregl-map");
27341
27436
  }
27437
+ /**
27438
+ * @internal
27439
+ * Sizes the backing store to whole device pixels and the CSS box to cover exactly that many, so
27440
+ * the compositor never rescales the canvas. A pixel ratio can sit a fraction below a whole
27441
+ * number, where truncating the count would cost a whole pixel per axis.
27442
+ */
27342
27443
  _resizeCanvas(width, height, pixelRatio) {
27343
- this._canvas.width = Math.floor(pixelRatio * width);
27344
- this._canvas.height = Math.floor(pixelRatio * height);
27345
- this._canvas.style.width = `${width}px`;
27346
- this._canvas.style.height = `${height}px`;
27444
+ const canvasWidth = Math.round(pixelRatio * width);
27445
+ const canvasHeight = Math.round(pixelRatio * height);
27446
+ this._canvas.width = canvasWidth;
27447
+ this._canvas.height = canvasHeight;
27448
+ this._canvas.style.width = `${canvasWidth / pixelRatio}px`;
27449
+ this._canvas.style.height = `${canvasHeight / pixelRatio}px`;
27347
27450
  }
27348
27451
  /**
27349
27452
  * @internal