@cesium/engine 22.0.0 → 22.1.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.
Files changed (151) hide show
  1. package/Build/ThirdParty/Workers/zip-web-worker.js +10 -7
  2. package/Build/Workers/chunk-23T2IPHV.js +55 -0
  3. package/Build/Workers/{chunk-VVZ667H6.js → chunk-2AM4E2WD.js} +2 -2
  4. package/Build/Workers/{chunk-XQ347YWU.js → chunk-2MWF4IES.js} +16 -14
  5. package/Build/Workers/{chunk-75HAJIDT.js → chunk-2RCIRXNI.js} +1 -1
  6. package/Build/Workers/{chunk-RQRODXVN.js → chunk-3YTMGEXW.js} +5 -1424
  7. package/Build/Workers/{chunk-N52ZRKUE.js → chunk-4BHWJWS3.js} +6 -6
  8. package/Build/Workers/{chunk-5T5SY63I.js → chunk-5JKH4AMT.js} +2 -2
  9. package/Build/Workers/{chunk-EJO3NKMS.js → chunk-6HKAPCSO.js} +1 -1
  10. package/Build/Workers/{chunk-BJSNGGBM.js → chunk-A53R2F2L.js} +4 -4
  11. package/Build/Workers/{chunk-H7B7FU2U.js → chunk-A6YFUGJO.js} +5 -5
  12. package/Build/Workers/{chunk-VCVA7BMD.js → chunk-AJYWXC6I.js} +4 -4
  13. package/Build/Workers/{chunk-3GL53OCU.js → chunk-AOIO5VUS.js} +276 -2277
  14. package/Build/Workers/{chunk-SZN34LQ5.js → chunk-B7JRBTT6.js} +10 -10
  15. package/Build/Workers/{chunk-726NINF5.js → chunk-CHNDJRYA.js} +20 -18
  16. package/Build/Workers/{chunk-L7U26FFD.js → chunk-CJOV55CW.js} +20 -18
  17. package/Build/Workers/{chunk-NE5JTQJP.js → chunk-COGPE5Z2.js} +10 -8
  18. package/Build/Workers/{chunk-XPVZWY4A.js → chunk-CW7W27IZ.js} +12 -8
  19. package/Build/Workers/{chunk-GYRDA3XK.js → chunk-DICY26ID.js} +20 -16
  20. package/Build/Workers/{chunk-AOM3FHBN.js → chunk-DMEFNTUV.js} +69 -7
  21. package/Build/Workers/{chunk-XZO6F23E.js → chunk-DQSJEOZY.js} +1 -1
  22. package/Build/Workers/{chunk-MXHRZHDF.js → chunk-GDU4RZSZ.js} +16 -36
  23. package/Build/Workers/{chunk-JDJAPBZP.js → chunk-GKWOUMYA.js} +1 -1
  24. package/Build/Workers/{chunk-OUBBMEWX.js → chunk-GTY4K4IA.js} +9 -7
  25. package/Build/Workers/{chunk-LWJXCI3F.js → chunk-H6Q7E4BQ.js} +8 -6
  26. package/Build/Workers/{chunk-YLXWC7OW.js → chunk-HHGOFZVQ.js} +7 -5
  27. package/Build/Workers/{chunk-34YXP222.js → chunk-HXKUEOOD.js} +5 -5
  28. package/Build/Workers/{chunk-EZ7NJXQN.js → chunk-I4REFVXB.js} +4 -4
  29. package/Build/Workers/{chunk-OE22564R.js → chunk-IL5F6WEE.js} +3 -3
  30. package/Build/Workers/{chunk-QSMIHPUM.js → chunk-JKXPC5HD.js} +2 -2
  31. package/Build/Workers/{chunk-7KAXDKRU.js → chunk-KKGD7HAW.js} +13 -11
  32. package/Build/Workers/{chunk-YLILBDWK.js → chunk-KROSQJUA.js} +2 -2
  33. package/Build/Workers/{chunk-NHZNMTIR.js → chunk-L4JLDVCM.js} +5 -5
  34. package/Build/Workers/{chunk-2D3GLFZD.js → chunk-LIYMRHGR.js} +15 -13
  35. package/Build/Workers/{chunk-P2H75UV5.js → chunk-MKMZHRB3.js} +16 -11
  36. package/Build/Workers/{chunk-KUB64XW6.js → chunk-MO25ZQ2I.js} +12 -10
  37. package/Build/Workers/{chunk-ECHAJNQJ.js → chunk-O6RZEKHZ.js} +12 -12
  38. package/Build/Workers/{chunk-5ZF53EY6.js → chunk-OOCGX2OD.js} +4 -4
  39. package/Build/Workers/{chunk-NGKF5NTR.js → chunk-OXFU5HNU.js} +13 -5
  40. package/Build/Workers/{chunk-FA3SCJDX.js → chunk-P5CGIJUY.js} +2 -2
  41. package/Build/Workers/{chunk-W4PIP5PG.js → chunk-QEANVUGT.js} +2 -2
  42. package/Build/Workers/{chunk-AARZSH4V.js → chunk-QFBCIX7J.js} +8 -6
  43. package/Build/Workers/{chunk-JZFU2LEM.js → chunk-QUAH3XOT.js} +4 -4
  44. package/Build/Workers/{chunk-6HBKE43B.js → chunk-RXZDTDIY.js} +13 -9
  45. package/Build/Workers/{chunk-LEFQBK6H.js → chunk-SPA2KPH3.js} +14 -12
  46. package/Build/Workers/chunk-TDSVSW5A.js +1460 -0
  47. package/Build/Workers/{chunk-A6JAFSZT.js → chunk-UG2DPFOL.js} +8 -6
  48. package/Build/Workers/{chunk-U4XMLGSR.js → chunk-URGEDZBS.js} +7 -7
  49. package/Build/Workers/{chunk-A4DPJIWS.js → chunk-V35NQOJC.js} +8 -6
  50. package/Build/Workers/chunk-W4XUEDU5.js +2058 -0
  51. package/Build/Workers/{chunk-7XEJGXX2.js → chunk-WB4TSSBQ.js} +779 -24
  52. package/Build/Workers/{chunk-RCCYW6E7.js → chunk-WTLYD4FE.js} +19 -15
  53. package/Build/Workers/{chunk-5B7VZQZY.js → chunk-Y4ALZ4SS.js} +9 -7
  54. package/Build/Workers/{chunk-KGLDJRSO.js → chunk-YF2NVO5B.js} +19 -13
  55. package/Build/Workers/{chunk-IGX772ZQ.js → chunk-YSYSXSHF.js} +1 -1
  56. package/Build/Workers/{chunk-M7HRE4QR.js → chunk-YX562XOB.js} +15 -11
  57. package/Build/Workers/{chunk-QCMRUVVF.js → chunk-YZWA5B4R.js} +15 -13
  58. package/Build/Workers/{chunk-U7CX3HHE.js → chunk-Z6DFT4D3.js} +15 -11
  59. package/Build/Workers/combineGeometry.js +24 -21
  60. package/Build/Workers/createBoxGeometry.js +18 -15
  61. package/Build/Workers/createBoxOutlineGeometry.js +16 -13
  62. package/Build/Workers/createCircleGeometry.js +28 -24
  63. package/Build/Workers/createCircleOutlineGeometry.js +21 -17
  64. package/Build/Workers/createCoplanarPolygonGeometry.js +35 -31
  65. package/Build/Workers/createCoplanarPolygonOutlineGeometry.js +33 -29
  66. package/Build/Workers/createCorridorGeometry.js +32 -28
  67. package/Build/Workers/createCorridorOutlineGeometry.js +30 -26
  68. package/Build/Workers/createCylinderGeometry.js +20 -17
  69. package/Build/Workers/createCylinderOutlineGeometry.js +20 -16
  70. package/Build/Workers/createEllipseGeometry.js +28 -24
  71. package/Build/Workers/createEllipseOutlineGeometry.js +21 -17
  72. package/Build/Workers/createEllipsoidGeometry.js +19 -16
  73. package/Build/Workers/createEllipsoidOutlineGeometry.js +18 -15
  74. package/Build/Workers/createFrustumGeometry.js +18 -15
  75. package/Build/Workers/createFrustumOutlineGeometry.js +18 -15
  76. package/Build/Workers/createGeometry.js +25 -21
  77. package/Build/Workers/createGroundPolylineGeometry.js +25 -21
  78. package/Build/Workers/createPlaneGeometry.js +16 -13
  79. package/Build/Workers/createPlaneOutlineGeometry.js +15 -12
  80. package/Build/Workers/createPolygonGeometry.js +35 -31
  81. package/Build/Workers/createPolygonOutlineGeometry.js +32 -28
  82. package/Build/Workers/createPolylineGeometry.js +27 -23
  83. package/Build/Workers/createPolylineVolumeGeometry.js +33 -29
  84. package/Build/Workers/createPolylineVolumeOutlineGeometry.js +29 -25
  85. package/Build/Workers/createRectangleGeometry.js +30 -26
  86. package/Build/Workers/createRectangleOutlineGeometry.js +23 -19
  87. package/Build/Workers/createSimplePolylineGeometry.js +25 -21
  88. package/Build/Workers/createSphereGeometry.js +19 -16
  89. package/Build/Workers/createSphereOutlineGeometry.js +18 -15
  90. package/Build/Workers/createTaskProcessorWorker.js +3 -3
  91. package/Build/Workers/createVectorTileClampedPolylines.js +16 -13
  92. package/Build/Workers/createVectorTileGeometries.js +24 -21
  93. package/Build/Workers/createVectorTilePoints.js +15 -12
  94. package/Build/Workers/createVectorTilePolygons.js +24 -20
  95. package/Build/Workers/createVectorTilePolylines.js +16 -13
  96. package/Build/Workers/createVerticesFromCesium3DTilesTerrain.js +25 -22
  97. package/Build/Workers/createVerticesFromGoogleEarthEnterpriseBuffer.js +26 -21
  98. package/Build/Workers/createVerticesFromHeightmap.js +26 -21
  99. package/Build/Workers/createVerticesFromQuantizedTerrainMesh.js +24 -19
  100. package/Build/Workers/createWallGeometry.js +26 -22
  101. package/Build/Workers/createWallOutlineGeometry.js +25 -21
  102. package/Build/Workers/decodeDraco.js +10 -10
  103. package/Build/Workers/decodeGoogleEarthEnterprisePacket.js +5 -5
  104. package/Build/Workers/decodeI3S.js +13 -11
  105. package/Build/Workers/gaussianSplatSorter.js +4 -4
  106. package/Build/Workers/gaussianSplatTextureGenerator.js +4 -4
  107. package/Build/Workers/incrementallyBuildTerrainPicker.js +121 -0
  108. package/Build/Workers/transcodeKTX2.js +6 -6
  109. package/Build/Workers/transferTypedArrayTest.js +1 -1
  110. package/Build/Workers/upsampleQuantizedTerrainMesh.js +24 -20
  111. package/Build/Workers/upsampleVerticesFromCesium3DTilesTerrain.js +25 -22
  112. package/Source/Core/AxisAlignedBoundingBox.js +36 -0
  113. package/Source/Core/Cesium3DTilesTerrainData.js +2 -0
  114. package/Source/Core/Cesium3DTilesTerrainGeometryProcessor.js +2 -0
  115. package/Source/Core/GoogleEarthEnterpriseTerrainData.js +1 -0
  116. package/Source/Core/HeightmapTerrainData.js +2 -0
  117. package/Source/Core/IntersectionTests.js +80 -0
  118. package/Source/Core/Ion.js +1 -1
  119. package/Source/Core/QuantizedMeshTerrainData.js +1 -0
  120. package/Source/Core/TerrainMesh.js +207 -0
  121. package/Source/Core/TerrainPicker.js +607 -0
  122. package/Source/Core/TexturePacker.js +27 -12
  123. package/Source/Core/Transforms.js +28 -19
  124. package/Source/DataSources/BillboardGraphics.js +1 -1
  125. package/Source/DataSources/BillboardVisualizer.js +7 -4
  126. package/Source/Renderer/Buffer.js +32 -0
  127. package/Source/Renderer/BufferUsage.js +3 -1
  128. package/Source/Renderer/Context.js +85 -7
  129. package/Source/Renderer/Sync.js +104 -0
  130. package/Source/Renderer/TextureAtlas.js +67 -27
  131. package/Source/Scene/ArcGisMapService.js +1 -1
  132. package/Source/Scene/Azure2DImageryProvider.js +96 -12
  133. package/Source/Scene/Billboard.js +75 -28
  134. package/Source/Scene/BillboardCollection.js +7 -2
  135. package/Source/Scene/BillboardTexture.js +56 -7
  136. package/Source/Scene/Globe.js +3 -1
  137. package/Source/Scene/GlobeSurfaceTile.js +18 -66
  138. package/Source/Scene/GlobeSurfaceTileProvider.js +11 -0
  139. package/Source/Scene/Google2DImageryProvider.js +10 -15
  140. package/Source/Scene/PickFramebuffer.js +124 -36
  141. package/Source/Scene/Picking.js +99 -17
  142. package/Source/Scene/Scene.js +36 -4
  143. package/Source/Scene/TerrainFillMesh.js +1 -0
  144. package/Source/Shaders/BillboardCollectionFS.glsl +22 -9
  145. package/Source/Shaders/BillboardCollectionFS.js +22 -9
  146. package/Source/ThirdParty/Workers/zip-web-worker.js +1 -1
  147. package/Source/ThirdParty/zip-module.wasm +0 -0
  148. package/Source/Workers/incrementallyBuildTerrainPicker.js +108 -0
  149. package/index.d.ts +207 -4
  150. package/index.js +28 -26
  151. package/package.json +2 -2
@@ -1,4 +1,5 @@
1
1
  import Check from "../Core/Check.js";
2
+ import Frozen from "../Core/Frozen.js";
2
3
  import Credit from "../Core/Credit.js";
3
4
  import defined from "../Core/defined.js";
4
5
  import Resource from "../Core/Resource.js";
@@ -29,7 +30,6 @@ const trailingSlashRegex = /\/$/;
29
30
  *
30
31
  * @alias Azure2DImageryProvider
31
32
  * @constructor
32
- * @private
33
33
  * @param {Azure2DImageryProvider.ConstructorOptions} options Object describing initialization options
34
34
  *
35
35
  * @example
@@ -41,16 +41,18 @@ const trailingSlashRegex = /\/$/;
41
41
  */
42
42
  function Azure2DImageryProvider(options) {
43
43
  options = options ?? {};
44
- const maximumLevel = options.maximumLevel ?? 22;
45
- const minimumLevel = options.minimumLevel ?? 0;
46
44
  const tilesetId = options.tilesetId ?? "microsoft.imagery";
45
+ this._maximumLevel = options.maximumLevel ?? 22;
46
+ this._minimumLevel = options.minimumLevel ?? 0;
47
47
 
48
- const subscriptionKey =
48
+ this._subscriptionKey =
49
49
  options.subscriptionKey ?? options["subscription-key"];
50
50
  //>>includeStart('debug', pragmas.debug);
51
- Check.defined("options.subscriptionKey", subscriptionKey);
51
+ Check.defined("options.subscriptionKey", this._subscriptionKey);
52
52
  //>>includeEnd('debug');
53
53
 
54
+ this._tilesetId = options.tilesetId;
55
+
54
56
  const resource =
55
57
  options.url instanceof IonResource
56
58
  ? options.url
@@ -60,19 +62,23 @@ function Azure2DImageryProvider(options) {
60
62
  if (!trailingSlashRegex.test(templateUrl)) {
61
63
  templateUrl += "/";
62
64
  }
63
- templateUrl += `map/tile`;
64
65
 
65
- resource.url = templateUrl;
66
+ const tilesUrl = `${templateUrl}map/tile`;
67
+ this._viewportUrl = `${templateUrl}map/attribution`;
68
+
69
+ resource.url = tilesUrl;
66
70
 
67
71
  resource.setQueryParameters({
68
72
  "api-version": "2024-04-01",
69
73
  tilesetId: tilesetId,
74
+ "subscription-key": this._subscriptionKey,
70
75
  zoom: `{z}`,
71
76
  x: `{x}`,
72
77
  y: `{y}`,
73
- "subscription-key": subscriptionKey,
74
78
  });
75
79
 
80
+ this._resource = resource;
81
+
76
82
  let credit;
77
83
  if (defined(options.credit)) {
78
84
  credit = options.credit;
@@ -83,8 +89,8 @@ function Azure2DImageryProvider(options) {
83
89
 
84
90
  const provider = new UrlTemplateImageryProvider({
85
91
  ...options,
86
- maximumLevel,
87
- minimumLevel,
92
+ maximumLevel: this._maximumLevel,
93
+ minimumLevel: this._minimumLevel,
88
94
  url: resource,
89
95
  credit: credit,
90
96
  });
@@ -93,6 +99,7 @@ function Azure2DImageryProvider(options) {
93
99
 
94
100
  // This will be defined for ion resources
95
101
  this._tileCredits = resource.credits;
102
+ this._attributionsByLevel = undefined;
96
103
  }
97
104
 
98
105
  Object.defineProperties(Azure2DImageryProvider.prototype, {
@@ -263,7 +270,18 @@ Object.defineProperties(Azure2DImageryProvider.prototype, {
263
270
  * @returns {Credit[]|undefined} The credits to be displayed when the tile is displayed.
264
271
  */
265
272
  Azure2DImageryProvider.prototype.getTileCredits = function (x, y, level) {
266
- return this._imageryProvider.getTileCredits(x, y, level);
273
+ const hasAttributions = defined(this._attributionsByLevel);
274
+
275
+ if (!hasAttributions || !defined(this._tileCredits)) {
276
+ return undefined;
277
+ }
278
+
279
+ const innerCredits = this._attributionsByLevel.get(level);
280
+ if (!defined(this._tileCredits)) {
281
+ return innerCredits;
282
+ }
283
+
284
+ return this._tileCredits.concat(innerCredits);
267
285
  };
268
286
 
269
287
  /**
@@ -282,7 +300,21 @@ Azure2DImageryProvider.prototype.requestImage = function (
282
300
  level,
283
301
  request,
284
302
  ) {
285
- return this._imageryProvider.requestImage(x, y, level, request);
303
+ const promise = this._imageryProvider.requestImage(x, y, level, request);
304
+
305
+ // If the requestImage call returns undefined, it couldn't be scheduled this frame. Make sure to return undefined so this can be handled upstream.
306
+ if (!defined(promise)) {
307
+ return undefined;
308
+ }
309
+
310
+ // Asynchronously request and populate _attributionsByLevel if it hasn't been already. We do this here so that the promise can be properly awaited.
311
+ if (!defined(this._attributionsByLevel)) {
312
+ return Promise.all([promise, this.getViewportCredits()]).then(
313
+ (results) => results[0],
314
+ );
315
+ }
316
+
317
+ return promise;
286
318
  };
287
319
 
288
320
  /**
@@ -306,5 +338,57 @@ Azure2DImageryProvider.prototype.pickFeatures = function (
306
338
  return undefined;
307
339
  };
308
340
 
341
+ /**
342
+ * Get attribution for imagery from Azure Maps to display in the credits
343
+ * @private
344
+ * @return {Promise<Map<Credit[]>>} The list of attribution sources to display in the credits.
345
+ */
346
+ Azure2DImageryProvider.prototype.getViewportCredits = async function () {
347
+ const maximumLevel = this._maximumLevel;
348
+
349
+ const promises = [];
350
+ for (let level = 0; level < maximumLevel + 1; level++) {
351
+ promises.push(
352
+ fetchViewportAttribution(
353
+ this._resource,
354
+ this._viewportUrl,
355
+ this._subscriptionKey,
356
+ this._tilesetId,
357
+ level,
358
+ ),
359
+ );
360
+ }
361
+ const results = await Promise.all(promises);
362
+
363
+ const attributionsByLevel = new Map();
364
+ for (let level = 0; level < maximumLevel + 1; level++) {
365
+ const credits = [];
366
+ const attributions = results[level].join(",");
367
+ if (attributions) {
368
+ const levelCredits = new Credit(attributions);
369
+ credits.push(levelCredits);
370
+ }
371
+ attributionsByLevel.set(level, credits);
372
+ }
373
+
374
+ this._attributionsByLevel = attributionsByLevel;
375
+
376
+ return attributionsByLevel;
377
+ };
378
+
379
+ async function fetchViewportAttribution(resource, url, key, tilesetId, level) {
380
+ const viewportResource = resource.getDerivedResource({
381
+ url,
382
+ queryParameters: {
383
+ zoom: level,
384
+ bounds: "-180,-90,180,90",
385
+ },
386
+ data: JSON.stringify(Frozen.EMPTY_OBJECT),
387
+ });
388
+
389
+ const viewportJson = await viewportResource.fetchJson();
390
+ return viewportJson.copyrights;
391
+ }
392
+
309
393
  // Exposed for tests
310
394
  export default Azure2DImageryProvider;
@@ -23,6 +23,8 @@ import SceneMode from "./SceneMode.js";
23
23
  import SceneTransforms from "./SceneTransforms.js";
24
24
  import VerticalOrigin from "./VerticalOrigin.js";
25
25
  import SplitDirection from "./SplitDirection.js";
26
+ import getExtensionFromUri from "../Core/getExtensionFromUri.js";
27
+ import isDataUri from "../Core/isDataUri.js";
26
28
 
27
29
  /**
28
30
  * @typedef {object} Billboard.ConstructorOptions
@@ -32,7 +34,7 @@ import SplitDirection from "./SplitDirection.js";
32
34
  * @property {Cartesian3} position The cartesian position of the billboard.
33
35
  * @property {*} [id] A user-defined object to return when the billboard is picked with {@link Scene#pick}.
34
36
  * @property {boolean} [show=true] Determines if this billboard will be shown.
35
- * @property {string | HTMLCanvasElement} [image] A loaded HTMLImageElement, ImageData, or a url to an image to use for the billboard.
37
+ * @property {string | HTMLImageElement | HTMLCanvasElement} [image] A loaded HTMLImageElement, ImageData, or a url to an image to use for the billboard.
36
38
  * @property {number} [scale=1.0] A number specifying the uniform scale that is multiplied with the billboard's image size in pixels.
37
39
  * @property {Cartesian2} [pixelOffset=Cartesian2.ZERO] A {@link Cartesian2} Specifying the pixel offset in screen space from the origin of this billboard.
38
40
  * @property {Cartesian3} [eyeOffset=Cartesian3.ZERO] A {@link Cartesian3} Specifying the 3D Cartesian offset applied to this billboard in eye coordinates.
@@ -189,31 +191,27 @@ function Billboard(options, billboardCollection) {
189
191
  this._batchIndex = undefined; // Used only by Vector3DTilePoints and BillboardCollection
190
192
 
191
193
  this._imageTexture = new BillboardTexture(billboardCollection);
194
+
195
+ this._imageId = options.imageId;
192
196
  this._imageWidth = undefined;
193
197
  this._imageHeight = undefined;
194
-
195
198
  this._labelDimensions = undefined;
196
199
  this._labelHorizontalOrigin = undefined;
197
200
  this._labelTranslate = undefined;
198
201
 
199
202
  const image = options.image;
200
- let imageId = options.imageId;
201
203
  if (defined(image)) {
202
- if (!defined(imageId)) {
203
- if (typeof image === "string") {
204
- imageId = image;
205
- } else if (defined(image.src)) {
206
- imageId = image.src;
207
- } else {
208
- imageId = createGuid();
209
- }
210
- }
211
-
212
- this._imageTexture.loadImage(imageId, image);
204
+ this._computeImageTextureProperties(options.imageId, image);
205
+ this._imageTexture.loadImage(
206
+ this._imageId,
207
+ image,
208
+ this._imageWidth,
209
+ this._imageHeight,
210
+ );
213
211
  }
214
212
 
215
213
  if (defined(options.imageSubRegion)) {
216
- this._imageTexture.addImageSubRegion(imageId, options.imageSubRegion);
214
+ this._imageTexture.addImageSubRegion(this._imageId, options.imageSubRegion);
217
215
  }
218
216
 
219
217
  this._actualClampedPosition = undefined;
@@ -947,18 +945,13 @@ Object.defineProperties(Billboard.prototype, {
947
945
  return;
948
946
  }
949
947
 
950
- let id;
951
- if (typeof value === "string") {
952
- id = value;
953
- } else if (value instanceof Resource) {
954
- id = value._url;
955
- } else if (defined(value.src)) {
956
- id = value.src;
957
- } else {
958
- id = createGuid();
959
- }
960
-
961
- this._imageTexture.loadImage(id, value);
948
+ this._computeImageTextureProperties(undefined, value);
949
+ this._imageTexture.loadImage(
950
+ this._imageId,
951
+ value,
952
+ this._imageWidth,
953
+ this._imageHeight,
954
+ );
962
955
  },
963
956
  },
964
957
 
@@ -1252,7 +1245,13 @@ Billboard.prototype.setImage = function (id, image) {
1252
1245
  Check.defined("image", image);
1253
1246
  //>>includeEnd('debug');
1254
1247
 
1255
- this._imageTexture.loadImage(id, image);
1248
+ this._computeImageTextureProperties(id, image);
1249
+ this._imageTexture.loadImage(
1250
+ this._imageId,
1251
+ image,
1252
+ this._imageWidth,
1253
+ this._imageHeight,
1254
+ );
1256
1255
  };
1257
1256
 
1258
1257
  /**
@@ -1268,6 +1267,54 @@ Billboard.prototype.setImageTexture = function (billboardTexture) {
1268
1267
  BillboardTexture.clone(billboardTexture, this._imageTexture);
1269
1268
  };
1270
1269
 
1270
+ /** Arbitrary limit on allocated SVG size, in pixels. Raster images use image resolution. */
1271
+ const SVG_MAX_SIZE_PX = 512;
1272
+
1273
+ /**
1274
+ * Computes billboard texture ID, width, and height. For raster images, width and height are left
1275
+ * undefined, defaulting to image resolution. For SVG, use billboard pixel width and height.
1276
+ * @param {string | undefined} id The id of the image.
1277
+ * @param {string | HTMLImageElement | HTMLCanvasElement | undefined} image A loaded HTMLImageElement, ImageData, or a url to an image to use for the billboard.
1278
+ * @private
1279
+ */
1280
+ Billboard.prototype._computeImageTextureProperties = function (id, image) {
1281
+ this._imageWidth = undefined;
1282
+ this._imageHeight = undefined;
1283
+
1284
+ if (!defined(image)) {
1285
+ this._imageId = createGuid();
1286
+ return;
1287
+ }
1288
+
1289
+ let imageUri;
1290
+ if (typeof image === "string") {
1291
+ imageUri = image;
1292
+ } else if (image instanceof Resource) {
1293
+ imageUri = image._url;
1294
+ } else if (defined(image.src)) {
1295
+ imageUri = image.src;
1296
+ }
1297
+
1298
+ this._imageId = id ?? imageUri ?? createGuid();
1299
+
1300
+ const hasSizeInPixels =
1301
+ defined(this._width) && defined(this._height) && !this._sizeInMeters;
1302
+
1303
+ if (hasSizeInPixels && isSvgUri(imageUri)) {
1304
+ this._imageWidth = Math.min(this._width, SVG_MAX_SIZE_PX);
1305
+ this._imageHeight = Math.min(this._height, SVG_MAX_SIZE_PX);
1306
+ }
1307
+ };
1308
+
1309
+ function isSvgUri(uri) {
1310
+ if (!defined(uri)) {
1311
+ return false;
1312
+ }
1313
+ return isDataUri(uri)
1314
+ ? uri.startsWith("data:image/svg+xml")
1315
+ : getExtensionFromUri(uri) === "svg";
1316
+ }
1317
+
1271
1318
  /**
1272
1319
  * Uses a sub-region of the image with the given id as the image for this billboard,
1273
1320
  * measured in pixels from the bottom-left.
@@ -34,6 +34,7 @@ import SDFSettings from "./SDFSettings.js";
34
34
  import TextureAtlas from "../Renderer/TextureAtlas.js";
35
35
  import VerticalOrigin from "./VerticalOrigin.js";
36
36
  import Ellipsoid from "../Core/Ellipsoid.js";
37
+ import WebGLConstants from "../Core/WebGLConstants.js";
37
38
 
38
39
  const SHOW_INDEX = Billboard.SHOW_INDEX;
39
40
  const POSITION_INDEX = Billboard.POSITION_INDEX;
@@ -2039,7 +2040,8 @@ BillboardCollection.prototype.update = function (frameState) {
2039
2040
  ) {
2040
2041
  this._rsOpaque = RenderState.fromCache({
2041
2042
  depthTest: {
2042
- enabled: false,
2043
+ enabled: true,
2044
+ func: WebGLConstants.LESS,
2043
2045
  },
2044
2046
  depthMask: true,
2045
2047
  });
@@ -2059,7 +2061,10 @@ BillboardCollection.prototype.update = function (frameState) {
2059
2061
  ) {
2060
2062
  this._rsTranslucent = RenderState.fromCache({
2061
2063
  depthTest: {
2062
- enabled: false,
2064
+ enabled: true,
2065
+ func: useTranslucentDepthMask
2066
+ ? WebGLConstants.LEQUAL
2067
+ : WebGLConstants.LESS,
2063
2068
  },
2064
2069
  depthMask: useTranslucentDepthMask,
2065
2070
  blending: BlendingState.ALPHA_BLEND,
@@ -160,8 +160,15 @@ BillboardTexture.prototype.unload = async function () {
160
160
  * @param {string} id An identifier to detect whether the image already exists in the atlas.
161
161
  * @param {HTMLImageElement|HTMLCanvasElement|string|Resource|Promise|TextureAtlas.CreateImageCallback} image An image or canvas to add to the texture atlas,
162
162
  * or a URL to an Image, or a Promise for an image, or a function that creates an image.
163
+ * @param {number} width A number specifying the width of the texture. If undefined, the image width will be used.
164
+ * @param {number} height A number specifying the height of the texture. If undefined, the image height will be used.
163
165
  */
164
- BillboardTexture.prototype.loadImage = async function (id, image) {
166
+ BillboardTexture.prototype.loadImage = async function (
167
+ id,
168
+ image,
169
+ width,
170
+ height,
171
+ ) {
165
172
  if (this._id === id) {
166
173
  // This image has already been loaded
167
174
  return;
@@ -192,7 +199,7 @@ BillboardTexture.prototype.loadImage = async function (id, image) {
192
199
  let index;
193
200
  const atlas = this._billboardCollection.textureAtlas;
194
201
  try {
195
- index = await atlas.addImage(id, image);
202
+ index = await atlas.addImage(id, image, width, height);
196
203
  } catch (error) {
197
204
  // There was an error loading the image
198
205
  billboardTexture._loadState = BillboardLoadState.ERROR;
@@ -251,16 +258,38 @@ BillboardTexture.prototype.loadImage = async function (id, image) {
251
258
  * @param {string} id An identifier to detect whether the image already exists in the atlas.
252
259
  * @param {BoundingRectangle} subRegion An {@link BoundingRectangle} defining a region of an existing image, measured in pixels from the bottom-left of the image.
253
260
  */
254
- BillboardTexture.prototype.addImageSubRegion = async function (id, subRegion) {
261
+ BillboardTexture.prototype.addImageSubRegion = function (id, subRegion) {
255
262
  this._id = id;
256
- this._loadState = BillboardLoadState.LOADING;
257
263
  this._loadError = undefined;
258
264
  this._hasSubregion = true;
259
265
 
260
- let index;
261
266
  const atlas = this._billboardCollection.textureAtlas;
267
+ const indexOrPromise = atlas.addImageSubRegion(id, subRegion);
268
+
269
+ if (typeof indexOrPromise === "number") {
270
+ this.setImageSubRegion(indexOrPromise, subRegion);
271
+ return;
272
+ }
273
+
274
+ this.loadImageSubRegion(id, subRegion, indexOrPromise);
275
+ };
276
+
277
+ /**
278
+ * @see {TextureAtlas#addImageSubRegion}
279
+ * @private
280
+ * @param {string} id An identifier to detect whether the image already exists in the atlas.
281
+ * @param {BoundingRectangle} subRegion An {@link BoundingRectangle} defining a region of an existing image, measured in pixels from the bottom-left of the image.
282
+ * @param {Promise<number>} indexPromise A promise that resolves to the image region index.
283
+ */
284
+ BillboardTexture.prototype.loadImageSubRegion = async function (
285
+ id,
286
+ subRegion,
287
+ indexPromise,
288
+ ) {
289
+ let index;
262
290
  try {
263
- index = await atlas.addImageSubRegion(id, subRegion);
291
+ this._loadState = BillboardLoadState.LOADING;
292
+ index = await indexPromise;
264
293
  } catch (error) {
265
294
  // There was an error loading the referenced image
266
295
  this._loadState = BillboardLoadState.ERROR;
@@ -268,6 +297,27 @@ BillboardTexture.prototype.addImageSubRegion = async function (id, subRegion) {
268
297
  return;
269
298
  }
270
299
 
300
+ if (this._id !== id) {
301
+ // Another load was initiated and resolved resolved before this one. This operation is cancelled.
302
+ return;
303
+ }
304
+
305
+ this._loadState = BillboardLoadState.LOADED;
306
+
307
+ this.setImageSubRegion(index, subRegion);
308
+ };
309
+
310
+ /**
311
+ * @see {TextureAtlas#addImageSubRegion}
312
+ * @private
313
+ * @param {number} index The resolved index in the {@link TextureAtlas}
314
+ * @param {BoundingRectangle} subRegion An {@link BoundingRectangle} defining a region of an existing image, measured in pixels from the bottom-left of the image.
315
+ */
316
+ BillboardTexture.prototype.setImageSubRegion = function (index, subRegion) {
317
+ if (this._index === index) {
318
+ return;
319
+ }
320
+
271
321
  if (!defined(index) || index === -1) {
272
322
  this._loadState = BillboardLoadState.FAILED;
273
323
  this._index = -1;
@@ -280,7 +330,6 @@ BillboardTexture.prototype.addImageSubRegion = async function (id, subRegion) {
280
330
  this._height = subRegion.height;
281
331
 
282
332
  this._index = index;
283
- this._loadState = BillboardLoadState.LOADED;
284
333
 
285
334
  this.dirty = true;
286
335
  };
@@ -943,7 +943,9 @@ Globe.prototype.getHeight = function (cartographic) {
943
943
 
944
944
  const intersection = tile.data.pick(
945
945
  ray,
946
- undefined,
946
+ // Globe height is the same at a given cartographic regardless of the scene mode,
947
+ // but the ray is constructed via a surface normal (which assumes 3D), so pick in 3D mode.
948
+ SceneMode.SCENE3D,
947
949
  projection,
948
950
  false,
949
951
  scratchGetHeightIntersection,
@@ -1,12 +1,9 @@
1
1
  import BoundingSphere from "../Core/BoundingSphere.js";
2
2
  import Cartesian3 from "../Core/Cartesian3.js";
3
3
  import Cartesian4 from "../Core/Cartesian4.js";
4
- import Cartographic from "../Core/Cartographic.js";
5
4
  import defined from "../Core/defined.js";
6
5
  import IndexDatatype from "../Core/IndexDatatype.js";
7
- import IntersectionTests from "../Core/IntersectionTests.js";
8
6
  import PixelFormat from "../Core/PixelFormat.js";
9
- import Ray from "../Core/Ray.js";
10
7
  import Request from "../Core/Request.js";
11
8
  import RequestState from "../Core/RequestState.js";
12
9
  import RequestType from "../Core/RequestType.js";
@@ -23,7 +20,6 @@ import TextureWrap from "../Renderer/TextureWrap.js";
23
20
  import VertexArray from "../Renderer/VertexArray.js";
24
21
  import ImageryState from "./ImageryState.js";
25
22
  import QuadtreeTileLoadState from "./QuadtreeTileLoadState.js";
26
- import SceneMode from "./SceneMode.js";
27
23
  import TerrainState from "./TerrainState.js";
28
24
 
29
25
  /**
@@ -126,33 +122,6 @@ Object.defineProperties(GlobeSurfaceTile.prototype, {
126
122
  },
127
123
  });
128
124
 
129
- const scratchCartographic = new Cartographic();
130
-
131
- function getPosition(encoding, mode, projection, vertices, index, result) {
132
- let position = encoding.getExaggeratedPosition(vertices, index, result);
133
-
134
- if (defined(mode) && mode !== SceneMode.SCENE3D) {
135
- const ellipsoid = projection.ellipsoid;
136
- const positionCartographic = ellipsoid.cartesianToCartographic(
137
- position,
138
- scratchCartographic,
139
- );
140
- position = projection.project(positionCartographic, result);
141
- position = Cartesian3.fromElements(
142
- position.z,
143
- position.x,
144
- position.y,
145
- result,
146
- );
147
- }
148
-
149
- return position;
150
- }
151
-
152
- const scratchV0 = new Cartesian3();
153
- const scratchV1 = new Cartesian3();
154
- const scratchV2 = new Cartesian3();
155
-
156
125
  GlobeSurfaceTile.prototype.pick = function (
157
126
  ray,
158
127
  mode,
@@ -160,42 +129,11 @@ GlobeSurfaceTile.prototype.pick = function (
160
129
  cullBackFaces,
161
130
  result,
162
131
  ) {
163
- const mesh = this.renderedMesh;
164
- if (!defined(mesh)) {
132
+ if (!defined(this.renderedMesh)) {
165
133
  return undefined;
166
134
  }
167
-
168
- const vertices = mesh.vertices;
169
- const indices = mesh.indices;
170
- const encoding = mesh.encoding;
171
- const indicesLength = indices.length;
172
-
173
- let minT = Number.MAX_VALUE;
174
-
175
- for (let i = 0; i < indicesLength; i += 3) {
176
- const i0 = indices[i];
177
- const i1 = indices[i + 1];
178
- const i2 = indices[i + 2];
179
-
180
- const v0 = getPosition(encoding, mode, projection, vertices, i0, scratchV0);
181
- const v1 = getPosition(encoding, mode, projection, vertices, i1, scratchV1);
182
- const v2 = getPosition(encoding, mode, projection, vertices, i2, scratchV2);
183
-
184
- const t = IntersectionTests.rayTriangleParametric(
185
- ray,
186
- v0,
187
- v1,
188
- v2,
189
- cullBackFaces,
190
- );
191
- if (defined(t) && t < minT && t >= 0.0) {
192
- minT = t;
193
- }
194
- }
195
-
196
- return minT !== Number.MAX_VALUE
197
- ? Ray.getPoint(ray, minT, result)
198
- : undefined;
135
+ const value = this.renderedMesh.pick(ray, cullBackFaces, mode, projection);
136
+ return Cartesian3.clone(value, result);
199
137
  };
200
138
 
201
139
  GlobeSurfaceTile.prototype.freeResources = function () {
@@ -473,8 +411,10 @@ GlobeSurfaceTile.prototype.updateExaggeration = function (
473
411
  encoding.exaggeration !== exaggeration;
474
412
  const encodingRelativeHeightChanged =
475
413
  encoding.exaggerationRelativeHeight !== exaggerationRelativeHeight;
414
+ const exaggerationChanged =
415
+ encodingExaggerationScaleChanged || encodingRelativeHeightChanged;
476
416
 
477
- if (encodingExaggerationScaleChanged || encodingRelativeHeightChanged) {
417
+ if (exaggerationChanged) {
478
418
  // Turning exaggeration scale on/off requires adding or removing geodetic surface normals
479
419
  // Relative height only translates, so it has no effect on normals
480
420
  if (encodingExaggerationScaleChanged) {
@@ -498,7 +438,19 @@ GlobeSurfaceTile.prototype.updateExaggeration = function (
498
438
  data.level = -1;
499
439
  }
500
440
  }
441
+
442
+ mesh.updateExaggeration(exaggeration, exaggerationRelativeHeight);
443
+ }
444
+ };
445
+
446
+ GlobeSurfaceTile.prototype.updateSceneMode = function (mode) {
447
+ const surfaceTile = this;
448
+ const mesh = surfaceTile.renderedMesh;
449
+ if (mesh === undefined) {
450
+ return;
501
451
  }
452
+
453
+ mesh.updateSceneMode(mode);
502
454
  };
503
455
 
504
456
  function prepareNewTile(tile, terrainProvider, imageryLayerCollection) {
@@ -193,6 +193,7 @@ function GlobeSurfaceTileProvider(options) {
193
193
 
194
194
  this._oldVerticalExaggeration = undefined;
195
195
  this._oldVerticalExaggerationRelativeHeight = undefined;
196
+ this._oldSceneMode = SceneMode.SCENE3D;
196
197
  }
197
198
 
198
199
  Object.defineProperties(GlobeSurfaceTileProvider.prototype, {
@@ -514,6 +515,16 @@ GlobeSurfaceTileProvider.prototype.endUpdate = function (frameState) {
514
515
  });
515
516
  }
516
517
 
518
+ const sceneModeChanged = this._oldSceneMode !== frameState.mode;
519
+ this._oldSceneMode = frameState.mode;
520
+
521
+ if (sceneModeChanged) {
522
+ quadtree.forEachLoadedTile(function (tile) {
523
+ const surfaceTile = tile.data;
524
+ surfaceTile.updateSceneMode(frameState.mode);
525
+ });
526
+ }
527
+
517
528
  // Add the tile render commands to the command list, sorted by texture count.
518
529
  const tilesToRenderByTextureCount = this._tilesToRenderByTextureCount;
519
530
  for (