@cesium/engine 26.0.0 → 26.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 (160) hide show
  1. package/Build/Workers/{chunk-EF2QYXGA.js → chunk-2EFYUSUY.js} +14 -14
  2. package/Build/Workers/{chunk-KFSTQKNM.js → chunk-5LSOO2KD.js} +7 -7
  3. package/Build/Workers/{chunk-VQYETPWC.js → chunk-6HK6IXK2.js} +4 -4
  4. package/Build/Workers/{chunk-AYKR4VBR.js → chunk-6YR6JBMY.js} +2 -2
  5. package/Build/Workers/{chunk-DOBXCNC3.js → chunk-76FDC45O.js} +13 -13
  6. package/Build/Workers/{chunk-54I6Y66F.js → chunk-7D2HZKH7.js} +6 -6
  7. package/Build/Workers/{chunk-4MGMYHOO.js → chunk-7KVKHY7O.js} +6 -6
  8. package/Build/Workers/{chunk-IRBKFCEJ.js → chunk-A3O6EDBK.js} +2 -2
  9. package/Build/Workers/{chunk-V7VQKN6N.js → chunk-A6X24AZI.js} +5 -5
  10. package/Build/Workers/{chunk-ZP7JMQV4.js → chunk-AHWAZRBV.js} +6 -2
  11. package/Build/Workers/{chunk-YLY7NKAB.js → chunk-B4CQSLZJ.js} +4 -4
  12. package/Build/Workers/{chunk-J6BWOHUF.js → chunk-C7JQVRLM.js} +3 -3
  13. package/Build/Workers/{chunk-KSSWJIZW.js → chunk-CDJDJ5LK.js} +2 -2
  14. package/Build/Workers/{chunk-G7PXZRVF.js → chunk-CEEZE3YZ.js} +7 -7
  15. package/Build/Workers/{chunk-INUEEEQA.js → chunk-CLCTQVVL.js} +8 -8
  16. package/Build/Workers/{chunk-O3EA5HS7.js → chunk-DBD5WWG2.js} +10 -10
  17. package/Build/Workers/{chunk-E7VQ76KE.js → chunk-DIGUUD6G.js} +6 -6
  18. package/Build/Workers/{chunk-424RNO3D.js → chunk-E7NZJOK7.js} +196 -22
  19. package/Build/Workers/{chunk-ACXQXN46.js → chunk-EHTS2YPT.js} +16 -16
  20. package/Build/Workers/{chunk-VWV2IJRB.js → chunk-ENNFMWDW.js} +11 -11
  21. package/Build/Workers/{chunk-FRQZECAO.js → chunk-FCP2QY4G.js} +5 -5
  22. package/Build/Workers/{chunk-ZZ46LWL6.js → chunk-FDK4K5IA.js} +1 -1
  23. package/Build/Workers/{chunk-C6KNZ7T4.js → chunk-FGQFQHN5.js} +17 -17
  24. package/Build/Workers/{chunk-MYP774IS.js → chunk-GSWMAFTE.js} +8 -8
  25. package/Build/Workers/{chunk-Y5BF6AFU.js → chunk-GXWQZBAI.js} +2 -2
  26. package/Build/Workers/{chunk-DDWSZVMY.js → chunk-HHV3MCGV.js} +5 -5
  27. package/Build/Workers/{chunk-52JDLOEM.js → chunk-HS6AD4P2.js} +14 -14
  28. package/Build/Workers/{chunk-Q3PY526V.js → chunk-IGAZBTFZ.js} +6 -6
  29. package/Build/Workers/{chunk-EBSIOBXY.js → chunk-ILME5BXA.js} +8 -8
  30. package/Build/Workers/{chunk-C6J67V5A.js → chunk-JKXV6PG5.js} +1 -1
  31. package/Build/Workers/{chunk-SMQZZOW6.js → chunk-JW6OZT4R.js} +10 -10
  32. package/Build/Workers/{chunk-F6QDY6HU.js → chunk-KGXSYGBG.js} +13 -13
  33. package/Build/Workers/{chunk-UOOIQ3KX.js → chunk-LD64RPYV.js} +12 -12
  34. package/Build/Workers/{chunk-CFQP6LYM.js → chunk-LGNDTZVX.js} +4 -4
  35. package/Build/Workers/{chunk-U3ZA64U7.js → chunk-LNSQVXFH.js} +2 -2
  36. package/Build/Workers/{chunk-TKKIREQ6.js → chunk-N7CCOFLX.js} +1 -1
  37. package/Build/Workers/{chunk-UA25D5MX.js → chunk-NIWITKQK.js} +10 -10
  38. package/Build/Workers/{chunk-KKOSKAZB.js → chunk-OBEU25PI.js} +17 -17
  39. package/Build/Workers/{chunk-M3B5JKSM.js → chunk-QVLAFFJY.js} +1 -1
  40. package/Build/Workers/{chunk-6YEE6JDR.js → chunk-R4FPNAZ2.js} +6 -6
  41. package/Build/Workers/{chunk-7J2HKPRH.js → chunk-RG4F5R57.js} +9 -9
  42. package/Build/Workers/{chunk-CXOYE2WM.js → chunk-SF6K72D7.js} +5 -5
  43. package/Build/Workers/{chunk-CZEYZU4N.js → chunk-SGRGNDOD.js} +10 -10
  44. package/Build/Workers/{chunk-DBOEKL43.js → chunk-SM2CDCYF.js} +7 -7
  45. package/Build/Workers/{chunk-Y57HREW5.js → chunk-SS5ABQGY.js} +4 -4
  46. package/Build/Workers/{chunk-QRWGUWI6.js → chunk-T5QBPLE3.js} +11 -11
  47. package/Build/Workers/{chunk-ZK3CF7ZD.js → chunk-TVZD72WJ.js} +12 -12
  48. package/Build/Workers/{chunk-IYOUHCZB.js → chunk-UEY73NRN.js} +1 -1
  49. package/Build/Workers/{chunk-7WM2PX4V.js → chunk-UVO6COT2.js} +5 -5
  50. package/Build/Workers/{chunk-P3CK7MCY.js → chunk-VAL7DYNR.js} +4 -4
  51. package/Build/Workers/{chunk-EPYXRCDB.js → chunk-WBSY7HDY.js} +12 -12
  52. package/Build/Workers/{chunk-4S7IE3LB.js → chunk-XDWCTQCZ.js} +2 -2
  53. package/Build/Workers/{chunk-QN67VG36.js → chunk-XLXSDIP5.js} +6 -6
  54. package/Build/Workers/{chunk-S4MCOY6I.js → chunk-XQ3SKCMM.js} +5 -5
  55. package/Build/Workers/{chunk-XZMBNNDX.js → chunk-YKU2Q3A2.js} +9 -9
  56. package/Build/Workers/{chunk-3VFEWOBI.js → chunk-ZMBHFYOX.js} +7 -7
  57. package/Build/Workers/{chunk-MPZHGZU6.js → chunk-ZSGUV73H.js} +4 -4
  58. package/Build/Workers/combineGeometry.js +24 -24
  59. package/Build/Workers/createBoxGeometry.js +18 -18
  60. package/Build/Workers/createBoxOutlineGeometry.js +16 -16
  61. package/Build/Workers/createCircleGeometry.js +26 -26
  62. package/Build/Workers/createCircleOutlineGeometry.js +19 -19
  63. package/Build/Workers/createCoplanarPolygonGeometry.js +33 -33
  64. package/Build/Workers/createCoplanarPolygonOutlineGeometry.js +31 -31
  65. package/Build/Workers/createCorridorGeometry.js +29 -29
  66. package/Build/Workers/createCorridorOutlineGeometry.js +28 -28
  67. package/Build/Workers/createCylinderGeometry.js +20 -20
  68. package/Build/Workers/createCylinderOutlineGeometry.js +18 -18
  69. package/Build/Workers/createEllipseGeometry.js +26 -26
  70. package/Build/Workers/createEllipseOutlineGeometry.js +19 -19
  71. package/Build/Workers/createEllipsoidGeometry.js +19 -19
  72. package/Build/Workers/createEllipsoidOutlineGeometry.js +18 -18
  73. package/Build/Workers/createFrustumGeometry.js +18 -18
  74. package/Build/Workers/createFrustumOutlineGeometry.js +18 -18
  75. package/Build/Workers/createGeometry.js +24 -24
  76. package/Build/Workers/createGroundPolylineGeometry.js +22 -22
  77. package/Build/Workers/createPlaneGeometry.js +16 -16
  78. package/Build/Workers/createPlaneOutlineGeometry.js +15 -15
  79. package/Build/Workers/createPolygonGeometry.js +32 -32
  80. package/Build/Workers/createPolygonOutlineGeometry.js +30 -30
  81. package/Build/Workers/createPolylineGeometry.js +25 -25
  82. package/Build/Workers/createPolylineVolumeGeometry.js +31 -31
  83. package/Build/Workers/createPolylineVolumeOutlineGeometry.js +27 -27
  84. package/Build/Workers/createRectangleGeometry.js +27 -27
  85. package/Build/Workers/createRectangleOutlineGeometry.js +20 -20
  86. package/Build/Workers/createSimplePolylineGeometry.js +23 -23
  87. package/Build/Workers/createSphereGeometry.js +19 -19
  88. package/Build/Workers/createSphereOutlineGeometry.js +18 -18
  89. package/Build/Workers/createTaskProcessorWorker.js +3 -3
  90. package/Build/Workers/createVectorTileClampedPolylines.js +14 -14
  91. package/Build/Workers/createVectorTileGeometries.js +24 -24
  92. package/Build/Workers/createVectorTilePoints.js +13 -13
  93. package/Build/Workers/createVectorTilePolygons.js +22 -22
  94. package/Build/Workers/createVectorTilePolylines.js +14 -14
  95. package/Build/Workers/createVerticesFromCesium3DTilesTerrain.js +25 -25
  96. package/Build/Workers/createVerticesFromGoogleEarthEnterpriseBuffer.js +22 -22
  97. package/Build/Workers/createVerticesFromHeightmap.js +22 -22
  98. package/Build/Workers/createVerticesFromQuantizedTerrainMesh.js +20 -20
  99. package/Build/Workers/createWallGeometry.js +24 -24
  100. package/Build/Workers/createWallOutlineGeometry.js +23 -23
  101. package/Build/Workers/decodeDraco.js +10 -10
  102. package/Build/Workers/decodeGoogleEarthEnterprisePacket.js +987 -2320
  103. package/Build/Workers/decodeI3S.js +10 -10
  104. package/Build/Workers/gaussianSplatSorter.js +4 -4
  105. package/Build/Workers/gaussianSplatTextureGenerator.js +4 -4
  106. package/Build/Workers/incrementallyBuildTerrainPicker.js +10 -10
  107. package/Build/Workers/transcodeKTX2.js +6 -6
  108. package/Build/Workers/transferTypedArrayTest.js +1 -1
  109. package/Build/Workers/upsampleQuantizedTerrainMesh.js +22 -22
  110. package/Build/Workers/upsampleVerticesFromCesium3DTilesTerrain.js +25 -25
  111. package/Source/Core/BoundingRectangle.js +6 -8
  112. package/Source/Core/Color.js +1 -0
  113. package/Source/Core/InterpolationAlgorithm.js +57 -50
  114. package/Source/Core/Ion.js +1 -1
  115. package/Source/Core/TerrainMesh.js +3 -3
  116. package/Source/Core/TerrainPicker.js +1 -0
  117. package/Source/Core/writeTextToCanvas.js +1 -0
  118. package/Source/DataSources/CzmlDataSource.js +12 -0
  119. package/Source/DataSources/KmlDataSource.js +528 -555
  120. package/Source/DataSources/PathGraphics.js +8 -1
  121. package/Source/DataSources/PathMode.js +27 -0
  122. package/Source/DataSources/PathVisualizer.js +298 -1
  123. package/Source/Renderer/Texture.js +1 -1
  124. package/Source/Renderer/VertexArray.js +1 -0
  125. package/Source/Scene/ArcGisMapService.js +1 -1
  126. package/Source/Scene/BillboardTexture.js +5 -3
  127. package/Source/Scene/Cesium3DTileOptimizations.js +4 -6
  128. package/Source/Scene/ClippingPlaneCollection.js +2 -2
  129. package/Source/Scene/ClippingPolygon.js +2 -0
  130. package/Source/Scene/ClippingPolygonCollection.js +2 -2
  131. package/Source/Scene/DerivedCommand.js +4 -0
  132. package/Source/Scene/Expression.js +6 -8
  133. package/Source/Scene/GlobeSurfaceShaderSet.js +501 -409
  134. package/Source/Scene/GlobeSurfaceTile.js +540 -401
  135. package/Source/Scene/GlobeSurfaceTileProvider.js +1259 -1146
  136. package/Source/Scene/GltfBufferViewLoader.js +3 -3
  137. package/Source/Scene/GltfLoader.js +1 -0
  138. package/Source/Scene/GltfLoaderUtil.js +20 -4
  139. package/Source/Scene/GltfPipeline/forEachTextureInMaterial.js +10 -0
  140. package/Source/Scene/GltfPipeline/removeUnusedElements.js +21 -11
  141. package/Source/Scene/ImageryLayer.js +2 -2
  142. package/Source/Scene/ImageryLayerCollection.js +2 -2
  143. package/Source/Scene/Material.js +1 -0
  144. package/Source/Scene/Model/Extensions/Gpm/GltfGpmLoader.js +4 -0
  145. package/Source/Scene/Model/Model.js +3 -0
  146. package/Source/Scene/Model/ModelUtility.js +1 -0
  147. package/Source/Scene/Picking.js +5 -0
  148. package/Source/Scene/PntsParser.js +1 -0
  149. package/Source/Scene/QuadtreePrimitive.js +3 -2
  150. package/Source/Scene/ResourceCacheKey.js +5 -5
  151. package/Source/Scene/Scene.js +1 -0
  152. package/Source/Scene/findMeshoptExtension.js +23 -0
  153. package/Source/Scene/renderBufferPointCollection.js +13 -8
  154. package/Source/Scene/renderBufferPolygonCollection.js +9 -13
  155. package/Source/Scene/renderBufferPolylineCollection.js +120 -192
  156. package/Source/Workers/decodeGoogleEarthEnterprisePacket.js +2 -2
  157. package/Source/Workers/incrementallyBuildTerrainPicker.js +2 -0
  158. package/index.d.ts +59 -254
  159. package/index.js +155 -153
  160. package/package.json +4 -4
@@ -52,1021 +52,1370 @@ import TerrainState from "./TerrainState.js";
52
52
  import TileBoundingRegion from "./TileBoundingRegion.js";
53
53
  import TileSelectionResult from "./TileSelectionResult.js";
54
54
 
55
+ /** @import Context from "../Renderer/Context.js"; */
56
+ /** @import EllipsoidalOccluder from "../Core/EllipsoidalOccluder.js"; */
57
+ /** @import FrameState from "./FrameState.js"; */
58
+ /** @import GlobeSurfaceShaderSet from "./GlobeSurfaceShaderSet.js"; */
59
+ /** @import ImageryLayerCollection from "./ImageryLayerCollection.js"; */
60
+ /** @import QuadtreeOccluders from "./QuadtreeOccluders.js"; */
61
+ /** @import QuadtreePrimitive from "./QuadtreePrimitive.js"; */
62
+ /** @import QuadtreeTile from "./QuadtreeTile.js"; */
63
+ /** @import TerrainMesh from "../Core/TerrainMesh.js"; */
64
+ /** @import TerrainProvider from "../Core/TerrainProvider.js"; */
65
+ /** @import TilingScheme from "../Core/TilingScheme.js"; */
66
+ /** @import { GlobeSurfaceShaderSetOptions } from "./GlobeSurfaceShaderSet.js"; */
67
+
55
68
  /**
56
69
  * Provides quadtree tiles representing the surface of the globe. This type is intended to be used
57
70
  * with {@link QuadtreePrimitive}.
58
71
  *
59
- * @alias GlobeSurfaceTileProvider
60
- * @constructor
61
- *
62
- * @param {TerrainProvider} options.terrainProvider The terrain provider that describes the surface geometry.
63
- * @param {ImageryLayerCollection} option.imageryLayers The collection of imagery layers describing the shading of the surface.
64
- * @param {GlobeSurfaceShaderSet} options.surfaceShaderSet The set of shaders used to render the surface.
65
- *
66
72
  * @private
67
73
  */
68
- function GlobeSurfaceTileProvider(options) {
69
- //>>includeStart('debug', pragmas.debug);
70
- if (!defined(options)) {
71
- throw new DeveloperError("options is required.");
72
- }
73
- if (!defined(options.terrainProvider)) {
74
- throw new DeveloperError("options.terrainProvider is required.");
75
- } else if (!defined(options.imageryLayers)) {
76
- throw new DeveloperError("options.imageryLayers is required.");
77
- } else if (!defined(options.surfaceShaderSet)) {
78
- throw new DeveloperError("options.surfaceShaderSet is required.");
79
- }
80
- //>>includeEnd('debug');
81
-
82
- this.lightingFadeOutDistance = 6500000.0;
83
- this.lightingFadeInDistance = 9000000.0;
84
- this.hasWaterMask = false;
85
- this.showWaterEffect = false;
86
- this.oceanNormalMap = undefined;
87
- this.zoomedOutOceanSpecularIntensity = 0.5;
88
- this.enableLighting = false;
89
- this.dynamicAtmosphereLighting = false;
90
- this.dynamicAtmosphereLightingFromSun = false;
91
- this.showGroundAtmosphere = false;
92
- this.shadows = ShadowMode.RECEIVE_ONLY;
93
- this.vertexShadowDarkness = 0.3;
94
-
74
+ class GlobeSurfaceTileProvider {
95
75
  /**
96
- * The color to use to highlight terrain fill tiles. If undefined, fill tiles are not
97
- * highlighted at all. The alpha value is used to alpha blend with the tile's
98
- * actual color. Because terrain fill tiles do not represent the actual terrain surface,
99
- * it may be useful in some applications to indicate visually that they are not to be trusted.
100
- * @type {Color}
101
- * @default undefined
76
+ * @param {object} options
77
+ * @param {TerrainProvider} options.terrainProvider The terrain provider that describes the surface geometry.
78
+ * @param {ImageryLayerCollection} options.imageryLayers The collection of imagery layers describing the shading of the surface.
79
+ * @param {GlobeSurfaceShaderSet} options.surfaceShaderSet The set of shaders used to render the surface.
102
80
  */
103
- this.fillHighlightColor = undefined;
104
-
105
- this.hueShift = 0.0;
106
- this.saturationShift = 0.0;
107
- this.brightnessShift = 0.0;
108
-
109
- this.showSkirts = true;
110
- this.backFaceCulling = true;
111
- this.undergroundColor = undefined;
112
- this.undergroundColorAlphaByDistance = undefined;
113
-
114
- this.lambertDiffuseMultiplier = 0.0;
115
-
116
- this.materialUniformMap = undefined;
117
- this._materialUniformMap = undefined;
118
-
119
- this._quadtree = undefined;
120
- this._terrainProvider = options.terrainProvider;
121
- this._imageryLayers = options.imageryLayers;
122
- this._surfaceShaderSet = options.surfaceShaderSet;
81
+ constructor(options) {
82
+ //>>includeStart('debug', pragmas.debug);
83
+ if (!defined(options)) {
84
+ throw new DeveloperError("options is required.");
85
+ }
86
+ if (!defined(options.terrainProvider)) {
87
+ throw new DeveloperError("options.terrainProvider is required.");
88
+ } else if (!defined(options.imageryLayers)) {
89
+ throw new DeveloperError("options.imageryLayers is required.");
90
+ } else if (!defined(options.surfaceShaderSet)) {
91
+ throw new DeveloperError("options.surfaceShaderSet is required.");
92
+ }
93
+ //>>includeEnd('debug');
94
+
95
+ this.lightingFadeOutDistance = 6500000.0;
96
+ this.lightingFadeInDistance = 9000000.0;
97
+ this.hasWaterMask = false;
98
+ this.showWaterEffect = false;
99
+ this.oceanNormalMap = undefined;
100
+ this.zoomedOutOceanSpecularIntensity = 0.5;
101
+ this.enableLighting = false;
102
+ this.dynamicAtmosphereLighting = false;
103
+ this.dynamicAtmosphereLightingFromSun = false;
104
+ this.showGroundAtmosphere = false;
105
+ this.shadows = ShadowMode.RECEIVE_ONLY;
106
+ this.vertexShadowDarkness = 0.3;
107
+
108
+ /**
109
+ * The color to use to highlight terrain fill tiles. If undefined, fill tiles are not
110
+ * highlighted at all. The alpha value is used to alpha blend with the tile's
111
+ * actual color. Because terrain fill tiles do not represent the actual terrain surface,
112
+ * it may be useful in some applications to indicate visually that they are not to be trusted.
113
+ * @type {Color}
114
+ * @default undefined
115
+ */
116
+ this.fillHighlightColor = undefined;
117
+
118
+ this.hueShift = 0.0;
119
+ this.saturationShift = 0.0;
120
+ this.brightnessShift = 0.0;
121
+
122
+ this.showSkirts = true;
123
+ this.backFaceCulling = true;
124
+ this.undergroundColor = undefined;
125
+ this.undergroundColorAlphaByDistance = undefined;
126
+
127
+ this.lambertDiffuseMultiplier = 0.0;
128
+
129
+ this.materialUniformMap = undefined;
130
+ this._materialUniformMap = undefined;
131
+
132
+ this._quadtree = undefined;
133
+ this._terrainProvider = options.terrainProvider;
134
+ this._imageryLayers = options.imageryLayers;
135
+ this._surfaceShaderSet = options.surfaceShaderSet;
136
+
137
+ this._renderState = undefined;
138
+ this._blendRenderState = undefined;
139
+ this._disableCullingRenderState = undefined;
140
+ this._disableCullingBlendRenderState = undefined;
141
+
142
+ this._errorEvent = new Event();
143
+
144
+ this._removeLayerAddedListener =
145
+ this._imageryLayers.layerAdded.addEventListener(
146
+ GlobeSurfaceTileProvider.prototype._onLayerAdded,
147
+ this,
148
+ );
149
+ this._removeLayerRemovedListener =
150
+ this._imageryLayers.layerRemoved.addEventListener(
151
+ GlobeSurfaceTileProvider.prototype._onLayerRemoved,
152
+ this,
153
+ );
154
+ this._removeLayerMovedListener =
155
+ this._imageryLayers.layerMoved.addEventListener(
156
+ GlobeSurfaceTileProvider.prototype._onLayerMoved,
157
+ this,
158
+ );
159
+ this._removeLayerShownListener =
160
+ this._imageryLayers.layerShownOrHidden.addEventListener(
161
+ GlobeSurfaceTileProvider.prototype._onLayerShownOrHidden,
162
+ this,
163
+ );
164
+ this._imageryLayersUpdatedEvent = new Event();
123
165
 
124
- this._renderState = undefined;
125
- this._blendRenderState = undefined;
126
- this._disableCullingRenderState = undefined;
127
- this._disableCullingBlendRenderState = undefined;
166
+ this._layerOrderChanged = false;
128
167
 
129
- this._errorEvent = new Event();
168
+ /** @type {QuadtreeTile[][]} */
169
+ this._tilesToRenderByTextureCount = [];
130
170
 
131
- this._removeLayerAddedListener =
132
- this._imageryLayers.layerAdded.addEventListener(
133
- GlobeSurfaceTileProvider.prototype._onLayerAdded,
134
- this,
135
- );
136
- this._removeLayerRemovedListener =
137
- this._imageryLayers.layerRemoved.addEventListener(
138
- GlobeSurfaceTileProvider.prototype._onLayerRemoved,
139
- this,
140
- );
141
- this._removeLayerMovedListener =
142
- this._imageryLayers.layerMoved.addEventListener(
143
- GlobeSurfaceTileProvider.prototype._onLayerMoved,
144
- this,
145
- );
146
- this._removeLayerShownListener =
147
- this._imageryLayers.layerShownOrHidden.addEventListener(
148
- GlobeSurfaceTileProvider.prototype._onLayerShownOrHidden,
149
- this,
150
- );
151
- this._imageryLayersUpdatedEvent = new Event();
171
+ /** @type {DrawCommand[]} */
172
+ this._drawCommands = [];
152
173
 
153
- this._layerOrderChanged = false;
174
+ /** @type {object[]} */
175
+ this._uniformMaps = [];
154
176
 
155
- this._tilesToRenderByTextureCount = [];
156
- this._drawCommands = [];
157
- this._uniformMaps = [];
158
- this._usedDrawCommands = 0;
177
+ this._usedDrawCommands = 0;
159
178
 
160
- this._vertexArraysToDestroy = [];
179
+ /** @type {VertexArray[]} */
180
+ this._vertexArraysToDestroy = [];
161
181
 
162
- this._debug = {
163
- wireframe: false,
164
- boundingSphereTile: undefined,
165
- };
182
+ this._debug = {
183
+ wireframe: false,
184
+ boundingSphereTile: undefined,
185
+ tilesRendered: 0,
186
+ texturesRendered: 0,
187
+ };
166
188
 
167
- this._baseColor = undefined;
168
- this._firstPassInitialColor = undefined;
169
- this.baseColor = new Color(0.0, 0.0, 0.5, 1.0);
189
+ this._baseColor = undefined;
190
+ this._firstPassInitialColor = undefined;
191
+ this.baseColor = new Color(0.0, 0.0, 0.5, 1.0);
170
192
 
171
- /**
172
- * A property specifying a {@link ClippingPlaneCollection} used to selectively disable rendering on the outside of each plane.
173
- * @type {ClippingPlaneCollection}
174
- * @private
175
- */
176
- this._clippingPlanes = undefined;
193
+ /**
194
+ * A property specifying a {@link ClippingPlaneCollection} used to selectively disable rendering on the outside of each plane.
195
+ * @type {ClippingPlaneCollection}
196
+ * @ignore
197
+ */
198
+ this._clippingPlanes = undefined;
177
199
 
178
- /**
179
- * A property specifying a {@link ClippingPolygonCollection} used to selectively disable rendering inside or outside a list of polygons.
180
- * @type {ClippingPolygonCollection}
181
- * @private
182
- */
183
- this._clippingPolygons = undefined;
200
+ /**
201
+ * A property specifying a {@link ClippingPolygonCollection} used to selectively disable rendering inside or outside a list of polygons.
202
+ * @type {ClippingPolygonCollection}
203
+ * @ignore
204
+ */
205
+ this._clippingPolygons = undefined;
184
206
 
185
- /**
186
- * A property specifying a {@link Rectangle} used to selectively limit terrain and imagery rendering.
187
- * @type {Rectangle}
188
- */
189
- this.cartographicLimitRectangle = Rectangle.clone(Rectangle.MAX_VALUE);
207
+ /**
208
+ * A property specifying a {@link Rectangle} used to selectively limit terrain and imagery rendering.
209
+ * @type {Rectangle}
210
+ */
211
+ this.cartographicLimitRectangle = Rectangle.clone(Rectangle.MAX_VALUE);
190
212
 
191
- this._hasLoadedTilesThisFrame = false;
192
- this._hasFillTilesThisFrame = false;
213
+ this._hasLoadedTilesThisFrame = false;
214
+ this._hasFillTilesThisFrame = false;
193
215
 
194
- this._oldVerticalExaggeration = undefined;
195
- this._oldVerticalExaggerationRelativeHeight = undefined;
196
- this._oldSceneMode = SceneMode.SCENE3D;
197
- }
216
+ this._oldVerticalExaggeration = undefined;
217
+ this._oldVerticalExaggerationRelativeHeight = undefined;
218
+ this._oldSceneMode = SceneMode.SCENE3D;
219
+ }
198
220
 
199
- Object.defineProperties(GlobeSurfaceTileProvider.prototype, {
200
221
  /**
201
222
  * Gets or sets the color of the globe when no imagery is available.
202
- * @memberof GlobeSurfaceTileProvider.prototype
203
223
  * @type {Color}
204
224
  */
205
- baseColor: {
206
- get: function () {
207
- return this._baseColor;
208
- },
209
- set: function (value) {
210
- //>>includeStart('debug', pragmas.debug);
211
- if (!defined(value)) {
212
- throw new DeveloperError("value is required.");
213
- }
214
- //>>includeEnd('debug');
225
+ get baseColor() {
226
+ return this._baseColor;
227
+ }
228
+
229
+ set baseColor(value) {
230
+ //>>includeStart('debug', pragmas.debug);
231
+ if (!defined(value)) {
232
+ throw new DeveloperError("value is required.");
233
+ }
234
+ //>>includeEnd('debug');
235
+
236
+ this._baseColor = value;
237
+ this._firstPassInitialColor = Cartesian4.fromColor(
238
+ value,
239
+ this._firstPassInitialColor,
240
+ );
241
+ }
215
242
 
216
- this._baseColor = value;
217
- this._firstPassInitialColor = Cartesian4.fromColor(
218
- value,
219
- this._firstPassInitialColor,
220
- );
221
- },
222
- },
223
243
  /**
224
244
  * Gets or sets the {@link QuadtreePrimitive} for which this provider is
225
245
  * providing tiles. This property may be undefined if the provider is not yet associated
226
246
  * with a {@link QuadtreePrimitive}.
227
- * @memberof GlobeSurfaceTileProvider.prototype
228
247
  * @type {QuadtreePrimitive}
229
248
  */
230
- quadtree: {
231
- get: function () {
232
- return this._quadtree;
233
- },
234
- set: function (value) {
235
- //>>includeStart('debug', pragmas.debug);
236
- if (!defined(value)) {
237
- throw new DeveloperError("value is required.");
238
- }
239
- //>>includeEnd('debug');
249
+ get quadtree() {
250
+ return this._quadtree;
251
+ }
240
252
 
241
- this._quadtree = value;
242
- },
243
- },
253
+ set quadtree(value) {
254
+ //>>includeStart('debug', pragmas.debug);
255
+ if (!defined(value)) {
256
+ throw new DeveloperError("value is required.");
257
+ }
258
+ //>>includeEnd('debug');
259
+
260
+ this._quadtree = value;
261
+ }
244
262
 
245
263
  /**
246
264
  * Gets the tiling scheme used by the provider.
247
- * @memberof GlobeSurfaceTileProvider.prototype
248
265
  * @type {TilingScheme}
249
266
  */
250
- tilingScheme: {
251
- get: function () {
252
- if (!defined(this._terrainProvider)) {
253
- return undefined;
254
- }
267
+ get tilingScheme() {
268
+ if (!defined(this._terrainProvider)) {
269
+ return undefined;
270
+ }
255
271
 
256
- return this._terrainProvider.tilingScheme;
257
- },
258
- },
272
+ // @ts-expect-error Missing types.
273
+ return this._terrainProvider.tilingScheme;
274
+ }
259
275
 
260
276
  /**
261
277
  * Gets an event that is raised when the geometry provider encounters an asynchronous error. By subscribing
262
278
  * to the event, you will be notified of the error and can potentially recover from it. Event listeners
263
279
  * are passed an instance of {@link TileProviderError}.
264
- * @memberof GlobeSurfaceTileProvider.prototype
265
- * @type {Event}
280
+ * @type {Event<*>}
266
281
  */
267
- errorEvent: {
268
- get: function () {
269
- return this._errorEvent;
270
- },
271
- },
282
+ get errorEvent() {
283
+ return this._errorEvent;
284
+ }
272
285
 
273
286
  /**
274
287
  * Gets an event that is raised when an imagery layer is added, shown, hidden, moved, or removed.
275
- * @memberof GlobeSurfaceTileProvider.prototype
276
- * @type {Event}
288
+ * @type {Event<*>}
277
289
  */
278
- imageryLayersUpdatedEvent: {
279
- get: function () {
280
- return this._imageryLayersUpdatedEvent;
281
- },
282
- },
290
+ get imageryLayersUpdatedEvent() {
291
+ return this._imageryLayersUpdatedEvent;
292
+ }
283
293
 
284
294
  /**
285
295
  * Gets or sets the terrain provider that describes the surface geometry.
286
- * @memberof GlobeSurfaceTileProvider.prototype
287
296
  * @type {TerrainProvider}
288
297
  */
289
- terrainProvider: {
290
- get: function () {
291
- return this._terrainProvider;
292
- },
293
- set: function (terrainProvider) {
294
- if (this._terrainProvider === terrainProvider) {
295
- return;
296
- }
298
+ get terrainProvider() {
299
+ return this._terrainProvider;
300
+ }
297
301
 
298
- this._terrainProvider = terrainProvider;
302
+ set terrainProvider(terrainProvider) {
303
+ if (this._terrainProvider === terrainProvider) {
304
+ return;
305
+ }
306
+
307
+ this._terrainProvider = terrainProvider;
308
+
309
+ if (defined(this._quadtree)) {
310
+ this._quadtree.invalidateAllTiles();
311
+ }
312
+ }
299
313
 
300
- if (defined(this._quadtree)) {
301
- this._quadtree.invalidateAllTiles();
302
- }
303
- },
304
- },
305
314
  /**
306
315
  * The {@link ClippingPlaneCollection} used to selectively disable rendering.
307
316
  *
308
317
  * @type {ClippingPlaneCollection}
309
318
  *
310
- * @private
319
+ * @ignore
311
320
  */
312
- clippingPlanes: {
313
- get: function () {
314
- return this._clippingPlanes;
315
- },
316
- set: function (value) {
317
- ClippingPlaneCollection.setOwner(value, this, "_clippingPlanes");
318
- },
319
- },
321
+ get clippingPlanes() {
322
+ return this._clippingPlanes;
323
+ }
324
+
325
+ set clippingPlanes(value) {
326
+ ClippingPlaneCollection.setOwner(value, this, "_clippingPlanes");
327
+ }
320
328
 
321
329
  /**
322
330
  * The {@link ClippingPolygonCollection} used to selectively disable rendering inside or outside a list of polygons.
323
331
  *
324
332
  * @type {ClippingPolygonCollection}
325
333
  *
326
- * @private
334
+ * @ignore
327
335
  */
328
- clippingPolygons: {
329
- get: function () {
330
- return this._clippingPolygons;
331
- },
332
- set: function (value) {
333
- ClippingPolygonCollection.setOwner(value, this, "_clippingPolygons");
334
- },
335
- },
336
- });
336
+ get clippingPolygons() {
337
+ return this._clippingPolygons;
338
+ }
337
339
 
338
- function sortTileImageryByLayerIndex(a, b) {
339
- let aImagery = a.loadingImagery;
340
- if (!defined(aImagery)) {
341
- aImagery = a.readyImagery;
340
+ set clippingPolygons(value) {
341
+ ClippingPolygonCollection.setOwner(value, this, "_clippingPolygons");
342
342
  }
343
343
 
344
- let bImagery = b.loadingImagery;
345
- if (!defined(bImagery)) {
346
- bImagery = b.readyImagery;
344
+ /**
345
+ * Make updates to the tile provider that are not involved in rendering. Called before the render update cycle.
346
+ * @param {FrameState} frameState
347
+ */
348
+ update(frameState) {
349
+ // update collection: imagery indices, base layers, raise layer show/hide event
350
+ this._imageryLayers._update();
347
351
  }
348
352
 
349
- return aImagery.imageryLayer._layerIndex - bImagery.imageryLayer._layerIndex;
350
- }
353
+ /**
354
+ * Called at the beginning of each render frame, before {@link QuadtreeTileProvider#showTileThisFrame}
355
+ * @param {FrameState} frameState The frame state.
356
+ */
357
+ initialize(frameState) {
358
+ // update each layer for texture reprojection.
359
+ this._imageryLayers.queueReprojectionCommands(frameState);
360
+
361
+ if (this._layerOrderChanged) {
362
+ this._layerOrderChanged = false;
363
+
364
+ // Sort the TileImagery instances in each tile by the layer index.
365
+ this._quadtree.forEachLoadedTile(
366
+ /** @param {QuadtreeTile} tile */
367
+ function (tile) {
368
+ const surfaceTile = /** @type {GlobeSurfaceTile} */ (tile.data);
369
+ surfaceTile.imagery.sort(sortTileImageryByLayerIndex);
370
+ },
371
+ );
372
+ }
351
373
 
352
- /**
353
- * Make updates to the tile provider that are not involved in rendering. Called before the render update cycle.
354
- */
355
- GlobeSurfaceTileProvider.prototype.update = function (frameState) {
356
- // update collection: imagery indices, base layers, raise layer show/hide event
357
- this._imageryLayers._update();
358
- };
374
+ // Add credits for terrain and imagery providers.
375
+ updateCredits(this, frameState);
359
376
 
360
- function updateCredits(surface, frameState) {
361
- const creditDisplay = frameState.creditDisplay;
362
- const terrainProvider = surface._terrainProvider;
363
- if (defined(terrainProvider) && defined(terrainProvider.credit)) {
364
- creditDisplay.addCreditToNextFrame(terrainProvider.credit);
377
+ const vertexArraysToDestroy = this._vertexArraysToDestroy;
378
+ const length = vertexArraysToDestroy.length;
379
+ for (let j = 0; j < length; ++j) {
380
+ GlobeSurfaceTile._freeVertexArray(vertexArraysToDestroy[j]);
381
+ }
382
+ vertexArraysToDestroy.length = 0;
365
383
  }
366
384
 
367
- const imageryLayers = surface._imageryLayers;
368
- for (let i = 0, len = imageryLayers.length; i < len; ++i) {
369
- const layer = imageryLayers.get(i);
370
- if (layer.ready && layer.show && defined(layer.imageryProvider.credit)) {
371
- creditDisplay.addCreditToNextFrame(layer.imageryProvider.credit);
385
+ /**
386
+ * Called at the beginning of the update cycle for each render frame, before {@link QuadtreeTileProvider#showTileThisFrame}
387
+ * or any other functions.
388
+ *
389
+ * @param {FrameState} frameState The frame state.
390
+ */
391
+ beginUpdate(frameState) {
392
+ const tilesToRenderByTextureCount = this._tilesToRenderByTextureCount;
393
+ for (let i = 0, len = tilesToRenderByTextureCount.length; i < len; ++i) {
394
+ const tiles = tilesToRenderByTextureCount[i];
395
+ if (defined(tiles)) {
396
+ tiles.length = 0;
397
+ }
398
+ }
399
+ // update clipping planes
400
+ const clippingPlanes = this._clippingPlanes;
401
+ // @ts-expect-error Missing types.
402
+ if (defined(clippingPlanes) && clippingPlanes.enabled) {
403
+ clippingPlanes.update(frameState);
372
404
  }
373
- }
374
- }
375
405
 
376
- /**
377
- * Called at the beginning of each render frame, before {@link QuadtreeTileProvider#showTileThisFrame}
378
- * @param {FrameState} frameState The frame state.
379
- */
380
- GlobeSurfaceTileProvider.prototype.initialize = function (frameState) {
381
- // update each layer for texture reprojection.
382
- this._imageryLayers.queueReprojectionCommands(frameState);
406
+ // update clipping polygons
407
+ const clippingPolygons = this._clippingPolygons;
408
+ if (defined(clippingPolygons) && clippingPolygons.enabled) {
409
+ // @ts-expect-error Missing types.
410
+ clippingPolygons.update(frameState);
411
+ // @ts-expect-error Missing types.
412
+ clippingPolygons.queueCommands(frameState);
413
+ }
383
414
 
384
- if (this._layerOrderChanged) {
385
- this._layerOrderChanged = false;
415
+ this._usedDrawCommands = 0;
386
416
 
387
- // Sort the TileImagery instances in each tile by the layer index.
388
- this._quadtree.forEachLoadedTile(function (tile) {
389
- tile.data.imagery.sort(sortTileImageryByLayerIndex);
390
- });
417
+ this._hasLoadedTilesThisFrame = false;
418
+ this._hasFillTilesThisFrame = false;
391
419
  }
392
420
 
393
- // Add credits for terrain and imagery providers.
394
- updateCredits(this, frameState);
421
+ /**
422
+ * Called at the end of the update cycle for each render frame, after {@link QuadtreeTileProvider#showTileThisFrame}
423
+ * and any other functions.
424
+ *
425
+ * @param {FrameState} frameState The frame state.
426
+ */
427
+ endUpdate(frameState) {
428
+ if (!defined(this._renderState)) {
429
+ this._renderState = RenderState.fromCache({
430
+ // Write color and depth
431
+ cull: {
432
+ enabled: true,
433
+ },
434
+ depthTest: {
435
+ enabled: true,
436
+ func: DepthFunction.LESS,
437
+ },
438
+ });
439
+
440
+ this._blendRenderState = RenderState.fromCache({
441
+ // Write color and depth
442
+ cull: {
443
+ enabled: true,
444
+ },
445
+ depthTest: {
446
+ enabled: true,
447
+ func: DepthFunction.LESS_OR_EQUAL,
448
+ },
449
+ blending: BlendingState.ALPHA_BLEND,
450
+ });
395
451
 
396
- const vertexArraysToDestroy = this._vertexArraysToDestroy;
397
- const length = vertexArraysToDestroy.length;
398
- for (let j = 0; j < length; ++j) {
399
- GlobeSurfaceTile._freeVertexArray(vertexArraysToDestroy[j]);
400
- }
401
- vertexArraysToDestroy.length = 0;
402
- };
452
+ let rs = /** @type {RenderState} */ (clone(this._renderState, true));
453
+ rs.cull.enabled = false;
454
+ this._disableCullingRenderState = RenderState.fromCache(rs);
403
455
 
404
- /**
405
- * Called at the beginning of the update cycle for each render frame, before {@link QuadtreeTileProvider#showTileThisFrame}
406
- * or any other functions.
407
- *
408
- * @param {FrameState} frameState The frame state.
409
- */
410
- GlobeSurfaceTileProvider.prototype.beginUpdate = function (frameState) {
411
- const tilesToRenderByTextureCount = this._tilesToRenderByTextureCount;
412
- for (let i = 0, len = tilesToRenderByTextureCount.length; i < len; ++i) {
413
- const tiles = tilesToRenderByTextureCount[i];
414
- if (defined(tiles)) {
415
- tiles.length = 0;
456
+ rs = /** @type {RenderState} */ (clone(this._blendRenderState, true));
457
+ rs.cull.enabled = false;
458
+ this._disableCullingBlendRenderState = RenderState.fromCache(rs);
416
459
  }
417
- }
418
- // update clipping planes
419
- const clippingPlanes = this._clippingPlanes;
420
- if (defined(clippingPlanes) && clippingPlanes.enabled) {
421
- clippingPlanes.update(frameState);
422
- }
423
460
 
424
- // update clipping polygons
425
- const clippingPolygons = this._clippingPolygons;
426
- if (defined(clippingPolygons) && clippingPolygons.enabled) {
427
- clippingPolygons.update(frameState);
428
- clippingPolygons.queueCommands(frameState);
429
- }
461
+ // If this frame has a mix of loaded and fill tiles, we need to propagate
462
+ // loaded heights to the fill tiles.
463
+ if (this._hasFillTilesThisFrame && this._hasLoadedTilesThisFrame) {
464
+ TerrainFillMesh.updateFillTiles(
465
+ this,
466
+ this._quadtree._tilesToRender,
467
+ frameState,
468
+ this._vertexArraysToDestroy,
469
+ );
470
+ }
430
471
 
431
- this._usedDrawCommands = 0;
472
+ // When vertical exaggeration changes, all of the loaded tiles need to generate
473
+ // geodetic surface normals so they can scale properly when rendered.
474
+ // When exaggeration is reset, geodetic surface normals are removed to decrease
475
+ // memory usage. Some tiles might have been constructed with the correct
476
+ // exaggeration already, so skip over them.
432
477
 
433
- this._hasLoadedTilesThisFrame = false;
434
- this._hasFillTilesThisFrame = false;
435
- };
478
+ // If the geodetic surface normals can't be created because the tile doesn't
479
+ // have a mesh, keep checking until the tile does have a mesh. This can happen
480
+ // if the tile's mesh starts construction in a worker thread right before the
481
+ // exaggeration changes.
436
482
 
437
- /**
438
- * Called at the end of the update cycle for each render frame, after {@link QuadtreeTileProvider#showTileThisFrame}
439
- * and any other functions.
440
- *
441
- * @param {FrameState} frameState The frame state.
442
- */
443
- GlobeSurfaceTileProvider.prototype.endUpdate = function (frameState) {
444
- if (!defined(this._renderState)) {
445
- this._renderState = RenderState.fromCache({
446
- // Write color and depth
447
- cull: {
448
- enabled: true,
449
- },
450
- depthTest: {
451
- enabled: true,
452
- func: DepthFunction.LESS,
453
- },
454
- });
483
+ const quadtree = this.quadtree;
484
+ const exaggeration = frameState.verticalExaggeration;
485
+ const exaggerationRelativeHeight =
486
+ frameState.verticalExaggerationRelativeHeight;
487
+ const exaggerationChanged =
488
+ this._oldVerticalExaggeration !== exaggeration ||
489
+ this._oldVerticalExaggerationRelativeHeight !==
490
+ exaggerationRelativeHeight;
491
+
492
+ // Keep track of the next time there is a change in exaggeration
493
+ this._oldVerticalExaggeration = exaggeration;
494
+ this._oldVerticalExaggerationRelativeHeight = exaggerationRelativeHeight;
495
+
496
+ if (exaggerationChanged) {
497
+ quadtree.forEachLoadedTile(
498
+ /** @param {QuadtreeTile} tile */
499
+ function (tile) {
500
+ const surfaceTile = /** @type {GlobeSurfaceTile} */ (tile.data);
501
+ surfaceTile.updateExaggeration(tile, frameState, quadtree);
502
+ },
503
+ );
504
+ }
455
505
 
456
- this._blendRenderState = RenderState.fromCache({
457
- // Write color and depth
458
- cull: {
459
- enabled: true,
460
- },
461
- depthTest: {
462
- enabled: true,
463
- func: DepthFunction.LESS_OR_EQUAL,
464
- },
465
- blending: BlendingState.ALPHA_BLEND,
466
- });
506
+ const sceneModeChanged = this._oldSceneMode !== frameState.mode;
507
+ this._oldSceneMode = frameState.mode;
467
508
 
468
- let rs = clone(this._renderState, true);
469
- rs.cull.enabled = false;
470
- this._disableCullingRenderState = RenderState.fromCache(rs);
509
+ if (sceneModeChanged) {
510
+ quadtree.forEachLoadedTile(
511
+ /** @param {QuadtreeTile} tile */
512
+ function (tile) {
513
+ const surfaceTile = /** @type {GlobeSurfaceTile} */ (tile.data);
514
+ surfaceTile.updateSceneMode(frameState.mode);
515
+ },
516
+ );
517
+ }
471
518
 
472
- rs = clone(this._blendRenderState, true);
473
- rs.cull.enabled = false;
474
- this._disableCullingBlendRenderState = RenderState.fromCache(rs);
475
- }
519
+ // Add the tile render commands to the command list, sorted by texture count.
520
+ const tilesToRenderByTextureCount = this._tilesToRenderByTextureCount;
521
+ for (
522
+ let textureCountIndex = 0,
523
+ textureCountLength = tilesToRenderByTextureCount.length;
524
+ textureCountIndex < textureCountLength;
525
+ ++textureCountIndex
526
+ ) {
527
+ const tilesToRender = tilesToRenderByTextureCount[textureCountIndex];
528
+ if (!defined(tilesToRender)) {
529
+ continue;
530
+ }
476
531
 
477
- // If this frame has a mix of loaded and fill tiles, we need to propagate
478
- // loaded heights to the fill tiles.
479
- if (this._hasFillTilesThisFrame && this._hasLoadedTilesThisFrame) {
480
- TerrainFillMesh.updateFillTiles(
481
- this,
482
- this._quadtree._tilesToRender,
483
- frameState,
484
- this._vertexArraysToDestroy,
485
- );
532
+ for (
533
+ let tileIndex = 0, tileLength = tilesToRender.length;
534
+ tileIndex < tileLength;
535
+ ++tileIndex
536
+ ) {
537
+ const tile = tilesToRender[tileIndex];
538
+ const surfaceTile = /** @type {GlobeSurfaceTile} */ (tile.data);
539
+ const tileBoundingRegion = surfaceTile.tileBoundingRegion;
540
+ addDrawCommandsForTile(this, tile, frameState);
541
+ frameState.minimumTerrainHeight = Math.min(
542
+ frameState.minimumTerrainHeight,
543
+ tileBoundingRegion.minimumHeight,
544
+ );
545
+ }
546
+ }
486
547
  }
487
548
 
488
- // When vertical exaggeration changes, all of the loaded tiles need to generate
489
- // geodetic surface normals so they can scale properly when rendered.
490
- // When exaggeration is reset, geodetic surface normals are removed to decrease
491
- // memory usage. Some tiles might have been constructed with the correct
492
- // exaggeration already, so skip over them.
493
-
494
- // If the geodetic surface normals can't be created because the tile doesn't
495
- // have a mesh, keep checking until the tile does have a mesh. This can happen
496
- // if the tile's mesh starts construction in a worker thread right before the
497
- // exaggeration changes.
498
-
499
- const quadtree = this.quadtree;
500
- const exaggeration = frameState.verticalExaggeration;
501
- const exaggerationRelativeHeight =
502
- frameState.verticalExaggerationRelativeHeight;
503
- const exaggerationChanged =
504
- this._oldVerticalExaggeration !== exaggeration ||
505
- this._oldVerticalExaggerationRelativeHeight !== exaggerationRelativeHeight;
506
-
507
- // Keep track of the next time there is a change in exaggeration
508
- this._oldVerticalExaggeration = exaggeration;
509
- this._oldVerticalExaggerationRelativeHeight = exaggerationRelativeHeight;
510
-
511
- if (exaggerationChanged) {
512
- quadtree.forEachLoadedTile(function (tile) {
513
- const surfaceTile = tile.data;
514
- surfaceTile.updateExaggeration(tile, frameState, quadtree);
515
- });
549
+ /**
550
+ * Adds draw commands for tiles rendered in the previous frame for a pick pass.
551
+ *
552
+ * @param {FrameState} frameState The frame state.
553
+ */
554
+ updateForPick(frameState) {
555
+ // Add the tile pick commands from the tiles drawn last frame.
556
+ const drawCommands = this._drawCommands;
557
+ for (let i = 0, length = this._usedDrawCommands; i < length; ++i) {
558
+ pushCommand(drawCommands[i], frameState);
559
+ }
516
560
  }
517
561
 
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
- });
562
+ /**
563
+ * Cancels any imagery re-projections in the queue.
564
+ */
565
+ cancelReprojections() {
566
+ this._imageryLayers.cancelReprojections();
526
567
  }
527
568
 
528
- // Add the tile render commands to the command list, sorted by texture count.
529
- const tilesToRenderByTextureCount = this._tilesToRenderByTextureCount;
530
- for (
531
- let textureCountIndex = 0,
532
- textureCountLength = tilesToRenderByTextureCount.length;
533
- textureCountIndex < textureCountLength;
534
- ++textureCountIndex
535
- ) {
536
- const tilesToRender = tilesToRenderByTextureCount[textureCountIndex];
537
- if (!defined(tilesToRender)) {
538
- continue;
569
+ /**
570
+ * Gets the maximum geometric error allowed in a tile at a given level, in meters.
571
+ *
572
+ * @param {number} level The tile level for which to get the maximum geometric error.
573
+ * @returns {number} The maximum geometric error in meters.
574
+ */
575
+ getLevelMaximumGeometricError(level) {
576
+ if (!defined(this._terrainProvider)) {
577
+ return 0;
539
578
  }
540
579
 
541
- for (
542
- let tileIndex = 0, tileLength = tilesToRender.length;
543
- tileIndex < tileLength;
544
- ++tileIndex
545
- ) {
546
- const tile = tilesToRender[tileIndex];
547
- const tileBoundingRegion = tile.data.tileBoundingRegion;
548
- addDrawCommandsForTile(this, tile, frameState);
549
- frameState.minimumTerrainHeight = Math.min(
550
- frameState.minimumTerrainHeight,
551
- tileBoundingRegion.minimumHeight,
552
- );
553
- }
580
+ // @ts-expect-error Missing types.
581
+ return this._terrainProvider.getLevelMaximumGeometricError(level);
554
582
  }
555
- };
556
583
 
557
- function pushCommand(command, frameState) {
558
- const globeTranslucencyState = frameState.globeTranslucencyState;
559
- if (globeTranslucencyState.translucent) {
560
- const isBlendCommand = command.renderState.blending.enabled;
561
- globeTranslucencyState.pushDerivedCommands(
562
- command,
563
- isBlendCommand,
584
+ /**
585
+ * Loads, or continues loading, a given tile. This function will continue to be called
586
+ * until {@link QuadtreeTile#state} is no longer {@link QuadtreeTileLoadState#LOADING}.
587
+ *
588
+ * @param {FrameState} frameState The frame state.
589
+ * @param {QuadtreeTile} tile The tile to load.
590
+ */
591
+ loadTile(frameState, tile) {
592
+ // We don't want to load imagery until we're certain that the terrain tiles are actually visible.
593
+ // So if our bounding volume isn't accurate because it came from another tile, load terrain only
594
+ // initially. If we load some terrain and suddenly have a more accurate bounding volume and the
595
+ // tile is _still_ visible, give the tile a chance to load imagery immediately rather than
596
+ // waiting for next frame.
597
+
598
+ let surfaceTile = /** @type {GlobeSurfaceTile} */ (tile.data);
599
+ let terrainOnly = true;
600
+ let terrainStateBefore;
601
+ if (defined(surfaceTile)) {
602
+ terrainOnly =
603
+ surfaceTile.boundingVolumeSourceTile !== tile ||
604
+ tile._lastSelectionResult === TileSelectionResult.CULLED_BUT_NEEDED;
605
+ terrainStateBefore = surfaceTile.terrainState;
606
+ }
607
+
608
+ GlobeSurfaceTile.processStateMachine(
609
+ tile,
564
610
  frameState,
611
+ this.terrainProvider,
612
+ this._imageryLayers,
613
+ this.quadtree,
614
+ this._vertexArraysToDestroy,
615
+ terrainOnly,
565
616
  );
566
- } else {
567
- frameState.commandList.push(command);
568
- }
569
- }
570
617
 
571
- /**
572
- * Adds draw commands for tiles rendered in the previous frame for a pick pass.
573
- *
574
- * @param {FrameState} frameState The frame state.
575
- */
576
- GlobeSurfaceTileProvider.prototype.updateForPick = function (frameState) {
577
- // Add the tile pick commands from the tiles drawn last frame.
578
- const drawCommands = this._drawCommands;
579
- for (let i = 0, length = this._usedDrawCommands; i < length; ++i) {
580
- pushCommand(drawCommands[i], frameState);
618
+ surfaceTile = /** @type {GlobeSurfaceTile} */ (tile.data);
619
+ if (terrainOnly && terrainStateBefore !== surfaceTile.terrainState) {
620
+ // Terrain state changed. If:
621
+ // a) The tile is visible, and
622
+ // b) The bounding volume is accurate (updated as a side effect of computing visibility)
623
+ // Then we'll load imagery, too.
624
+ if (
625
+ this.computeTileVisibility(
626
+ tile,
627
+ frameState,
628
+ // @ts-expect-error Missing types.
629
+ this.quadtree.occluders,
630
+ ) !== Visibility.NONE &&
631
+ surfaceTile.boundingVolumeSourceTile === tile
632
+ ) {
633
+ terrainOnly = false;
634
+ GlobeSurfaceTile.processStateMachine(
635
+ tile,
636
+ frameState,
637
+ this.terrainProvider,
638
+ this._imageryLayers,
639
+ this.quadtree,
640
+ this._vertexArraysToDestroy,
641
+ terrainOnly,
642
+ );
643
+ }
644
+ }
581
645
  }
582
- };
583
646
 
584
- /**
585
- * Cancels any imagery re-projections in the queue.
586
- */
587
- GlobeSurfaceTileProvider.prototype.cancelReprojections = function () {
588
- this._imageryLayers.cancelReprojections();
589
- };
647
+ /**
648
+ * Determines the visibility of a given tile. The tile may be fully visible, partially visible, or not
649
+ * visible at all. Tiles that are renderable and are at least partially visible will be shown by a call
650
+ * to {@link GlobeSurfaceTileProvider#showTileThisFrame}.
651
+ *
652
+ * @param {QuadtreeTile} tile The tile instance.
653
+ * @param {FrameState} frameState The state information about the current frame.
654
+ * @param {QuadtreeOccluders} occluders The objects that may occlude this tile.
655
+ *
656
+ * @returns {Visibility} Visibility.NONE if the tile is not visible,
657
+ * Visibility.PARTIAL if the tile is partially visible, or
658
+ * Visibility.FULL if the tile is fully visible.
659
+ */
660
+ computeTileVisibility(tile, frameState, occluders) {
661
+ const distance = this.computeDistanceToTile(tile, frameState);
662
+ tile._distance = distance;
590
663
 
591
- /**
592
- * Gets the maximum geometric error allowed in a tile at a given level, in meters.
593
- *
594
- * @param {number} level The tile level for which to get the maximum geometric error.
595
- * @returns {number} The maximum geometric error in meters.
596
- */
597
- GlobeSurfaceTileProvider.prototype.getLevelMaximumGeometricError = function (
598
- level,
599
- ) {
600
- if (!defined(this._terrainProvider)) {
601
- return 0;
602
- }
664
+ const undergroundVisible = isUndergroundVisible(this, frameState);
603
665
 
604
- return this._terrainProvider.getLevelMaximumGeometricError(level);
605
- };
666
+ if (frameState.fog.enabled && !undergroundVisible) {
667
+ if (CesiumMath.fog(distance, frameState.fog.density) >= 1.0) {
668
+ // Tile is completely in fog so return that it is not visible.
669
+ return Visibility.NONE;
670
+ }
671
+ }
606
672
 
607
- /**
608
- * Loads, or continues loading, a given tile. This function will continue to be called
609
- * until {@link QuadtreeTile#state} is no longer {@link QuadtreeTileLoadState#LOADING}.
610
- *
611
- * @param {FrameState} frameState The frame state.
612
- * @param {QuadtreeTile} tile The tile to load.
613
- */
614
- GlobeSurfaceTileProvider.prototype.loadTile = function (frameState, tile) {
615
- // We don't want to load imagery until we're certain that the terrain tiles are actually visible.
616
- // So if our bounding volume isn't accurate because it came from another tile, load terrain only
617
- // initially. If we load some terrain and suddenly have a more accurate bounding volume and the
618
- // tile is _still_ visible, give the tile a chance to load imagery immediately rather than
619
- // waiting for next frame.
620
-
621
- let surfaceTile = tile.data;
622
- let terrainOnly = true;
623
- let terrainStateBefore;
624
- if (defined(surfaceTile)) {
625
- terrainOnly =
626
- surfaceTile.boundingVolumeSourceTile !== tile ||
627
- tile._lastSelectionResult === TileSelectionResult.CULLED_BUT_NEEDED;
628
- terrainStateBefore = surfaceTile.terrainState;
629
- }
630
-
631
- GlobeSurfaceTile.processStateMachine(
632
- tile,
633
- frameState,
634
- this.terrainProvider,
635
- this._imageryLayers,
636
- this.quadtree,
637
- this._vertexArraysToDestroy,
638
- terrainOnly,
639
- );
673
+ const surfaceTile = /** @type {GlobeSurfaceTile} */ (tile.data);
674
+ const tileBoundingRegion = surfaceTile.tileBoundingRegion;
640
675
 
641
- surfaceTile = tile.data;
642
- if (terrainOnly && terrainStateBefore !== tile.data.terrainState) {
643
- // Terrain state changed. If:
644
- // a) The tile is visible, and
645
- // b) The bounding volume is accurate (updated as a side effect of computing visibility)
646
- // Then we'll load imagery, too.
647
- if (
648
- this.computeTileVisibility(tile, frameState, this.quadtree.occluders) !==
649
- Visibility.NONE &&
650
- surfaceTile.boundingVolumeSourceTile === tile
651
- ) {
652
- terrainOnly = false;
653
- GlobeSurfaceTile.processStateMachine(
654
- tile,
655
- frameState,
656
- this.terrainProvider,
657
- this._imageryLayers,
658
- this.quadtree,
659
- this._vertexArraysToDestroy,
660
- terrainOnly,
661
- );
676
+ if (surfaceTile.boundingVolumeSourceTile === undefined) {
677
+ // We have no idea where this tile is, so let's just call it partially visible.
678
+ return Visibility.PARTIAL;
662
679
  }
663
- }
664
- };
665
680
 
666
- const boundingSphereScratch = new BoundingSphere();
667
- const rectangleIntersectionScratch = new Rectangle();
668
- const splitCartographicLimitRectangleScratch = new Rectangle();
669
- const rectangleCenterScratch = new Cartographic();
681
+ const cullingVolume = frameState.cullingVolume;
682
+ // @ts-expect-error Missing types.
683
+ let boundingVolume = tileBoundingRegion.boundingVolume;
670
684
 
671
- // cartographicLimitRectangle may span the IDL, but tiles never will.
672
- function clipRectangleAntimeridian(tileRectangle, cartographicLimitRectangle) {
673
- if (cartographicLimitRectangle.west < cartographicLimitRectangle.east) {
674
- return cartographicLimitRectangle;
675
- }
676
- const splitRectangle = Rectangle.clone(
677
- cartographicLimitRectangle,
678
- splitCartographicLimitRectangleScratch,
679
- );
680
- const tileCenter = Rectangle.center(tileRectangle, rectangleCenterScratch);
681
- if (tileCenter.longitude > 0.0) {
682
- splitRectangle.east = CesiumMath.PI;
683
- } else {
684
- splitRectangle.west = -CesiumMath.PI;
685
- }
686
- return splitRectangle;
687
- }
685
+ if (!defined(boundingVolume)) {
686
+ // @ts-expect-error Missing types.
687
+ boundingVolume = tileBoundingRegion.boundingSphere;
688
+ }
688
689
 
689
- function isUndergroundVisible(tileProvider, frameState) {
690
- if (frameState.cameraUnderground) {
691
- return true;
692
- }
690
+ // Check if the tile is outside the limit area in cartographic space
691
+ surfaceTile.clippedByBoundaries = false;
692
+ const clippedCartographicLimitRectangle = clipRectangleAntimeridian(
693
+ tile.rectangle,
694
+ this.cartographicLimitRectangle,
695
+ );
696
+ const areaLimitIntersection = Rectangle.simpleIntersection(
697
+ clippedCartographicLimitRectangle,
698
+ tile.rectangle,
699
+ rectangleIntersectionScratch,
700
+ );
701
+ if (!defined(areaLimitIntersection)) {
702
+ return Visibility.NONE;
703
+ }
704
+ if (!Rectangle.equals(areaLimitIntersection, tile.rectangle)) {
705
+ surfaceTile.clippedByBoundaries = true;
706
+ }
693
707
 
694
- if (frameState.globeTranslucencyState.translucent) {
695
- return true;
696
- }
708
+ if (frameState.mode !== SceneMode.SCENE3D) {
709
+ boundingVolume = boundingSphereScratch;
710
+ BoundingSphere.fromRectangleWithHeights2D(
711
+ tile.rectangle,
712
+ frameState.mapProjection,
713
+ tileBoundingRegion.minimumHeight,
714
+ tileBoundingRegion.maximumHeight,
715
+ boundingVolume,
716
+ );
717
+ Cartesian3.fromElements(
718
+ boundingVolume.center.z,
719
+ boundingVolume.center.x,
720
+ boundingVolume.center.y,
721
+ boundingVolume.center,
722
+ );
697
723
 
698
- if (tileProvider.backFaceCulling) {
699
- return false;
724
+ if (
725
+ frameState.mode === SceneMode.MORPHING &&
726
+ defined(surfaceTile.renderedMesh)
727
+ ) {
728
+ boundingVolume = BoundingSphere.union(
729
+ // @ts-expect-error Missing types.
730
+ tileBoundingRegion.boundingSphere,
731
+ boundingVolume,
732
+ boundingVolume,
733
+ );
734
+ }
735
+ }
736
+
737
+ if (!defined(boundingVolume)) {
738
+ return Visibility.PARTIAL;
739
+ }
740
+
741
+ const clippingPlanes = this._clippingPlanes;
742
+ // @ts-expect-error Missing types.
743
+ if (defined(clippingPlanes) && clippingPlanes.enabled) {
744
+ const planeIntersection =
745
+ clippingPlanes.computeIntersectionWithBoundingVolume(boundingVolume);
746
+ // @ts-expect-error Possibly an error? isClipped is defined on surfaceTile, not tile.
747
+ tile.isClipped = planeIntersection !== Intersect.INSIDE;
748
+ if (planeIntersection === Intersect.OUTSIDE) {
749
+ return Visibility.NONE;
750
+ }
751
+ }
752
+
753
+ const clippingPolygons = this._clippingPolygons;
754
+ if (defined(clippingPolygons) && clippingPolygons.enabled) {
755
+ const polygonIntersection =
756
+ clippingPolygons.computeIntersectionWithBoundingVolume(
757
+ tileBoundingRegion,
758
+ );
759
+ // @ts-expect-error Possibly an error? isClipped is defined on surfaceTile, not tile.
760
+ tile.isClipped = polygonIntersection !== Intersect.OUTSIDE;
761
+ // Polygon clipping intersections are determined by outer rectangles, therefore we cannot
762
+ // preemptively determine if a tile is completely clipped or not here.
763
+ }
764
+
765
+ let visibility;
766
+ const intersection = cullingVolume.computeVisibility(boundingVolume);
767
+
768
+ if (intersection === Intersect.OUTSIDE) {
769
+ visibility = Visibility.NONE;
770
+ } else if (intersection === Intersect.INTERSECTING) {
771
+ visibility = Visibility.PARTIAL;
772
+ } else if (intersection === Intersect.INSIDE) {
773
+ visibility = Visibility.FULL;
774
+ }
775
+
776
+ if (visibility === Visibility.NONE) {
777
+ return visibility;
778
+ }
779
+
780
+ const ortho3D =
781
+ frameState.mode === SceneMode.SCENE3D &&
782
+ frameState.camera.frustum instanceof OrthographicFrustum;
783
+ if (
784
+ frameState.mode === SceneMode.SCENE3D &&
785
+ !ortho3D &&
786
+ defined(occluders) &&
787
+ !undergroundVisible
788
+ ) {
789
+ const occludeePointInScaledSpace = surfaceTile.occludeePointInScaledSpace;
790
+ if (!defined(occludeePointInScaledSpace)) {
791
+ return visibility;
792
+ }
793
+
794
+ if (
795
+ occluders.ellipsoid.isScaledSpacePointVisiblePossiblyUnderEllipsoid(
796
+ occludeePointInScaledSpace,
797
+ tileBoundingRegion.minimumHeight,
798
+ )
799
+ ) {
800
+ return visibility;
801
+ }
802
+
803
+ return Visibility.NONE;
804
+ }
805
+
806
+ return visibility;
700
807
  }
701
808
 
702
- const clippingPlanes = tileProvider._clippingPlanes;
703
- if (defined(clippingPlanes) && clippingPlanes.enabled) {
704
- return true;
809
+ /**
810
+ * Determines if the given tile can be refined
811
+ * @param {QuadtreeTile} tile The tile to check.
812
+ * @returns {boolean} True if the tile can be refined, false if it cannot.
813
+ */
814
+ canRefine(tile) {
815
+ const surfaceTile = /** @type {GlobeSurfaceTile} */ (tile.data);
816
+
817
+ // Only allow refinement it we know whether or not the children of this tile exist.
818
+ // For a tileset with `availability`, we'll always be able to refine.
819
+ // We can ask for availability of _any_ child tile because we only need to confirm
820
+ // that we get a yes or no answer, it doesn't matter what the answer is.
821
+ if (defined(surfaceTile.terrainData)) {
822
+ return true;
823
+ }
824
+ const childAvailable = this.terrainProvider.getTileDataAvailable(
825
+ // @ts-expect-error Missing types.
826
+ tile.x * 2,
827
+ tile.y * 2,
828
+ tile.level + 1,
829
+ );
830
+ return childAvailable !== undefined;
705
831
  }
706
832
 
707
- const clippingPolygons = tileProvider._clippingPolygons;
708
- if (defined(clippingPolygons) && clippingPolygons.enabled) {
833
+ /**
834
+ * Determines if the given not-fully-loaded tile can be rendered without losing detail that
835
+ * was present last frame as a result of rendering descendant tiles. This method will only be
836
+ * called if this tile's descendants were rendered last frame. If the tile is fully loaded,
837
+ * it is assumed that this method will return true and it will not be called.
838
+ * @param {QuadtreeTile} tile The tile to check.
839
+ * @returns {boolean} True if the tile can be rendered without losing detail.
840
+ */
841
+ canRenderWithoutLosingDetail(tile) {
842
+ const surfaceTile = /** @type {GlobeSurfaceTile} */ (tile.data);
843
+
844
+ const readyImagery = readyImageryScratch;
845
+ // @ts-expect-error Missing types.
846
+ readyImagery.length = this._imageryLayers.length;
847
+
848
+ let terrainReady = false;
849
+ let initialImageryState = false;
850
+ let imagery;
851
+
852
+ if (defined(surfaceTile)) {
853
+ // We can render even with non-ready terrain as long as all our rendered descendants
854
+ // are missing terrain geometry too. i.e. if we rendered fills for more detailed tiles
855
+ // last frame, it's ok to render a fill for this tile this frame.
856
+ terrainReady = surfaceTile.terrainState === TerrainState.READY;
857
+
858
+ // Initially assume all imagery layers are ready, unless imagery hasn't been initialized at all.
859
+ initialImageryState = true;
860
+
861
+ imagery = surfaceTile.imagery;
862
+ }
863
+
864
+ let i;
865
+ let len;
866
+
867
+ for (i = 0, len = readyImagery.length; i < len; ++i) {
868
+ readyImagery[i] = initialImageryState;
869
+ }
870
+
871
+ if (defined(imagery)) {
872
+ for (i = 0, len = imagery.length; i < len; ++i) {
873
+ const tileImagery = imagery[i];
874
+ const loadingImagery = tileImagery.loadingImagery;
875
+ const isReady =
876
+ !defined(loadingImagery) ||
877
+ loadingImagery.state === ImageryState.FAILED ||
878
+ loadingImagery.state === ImageryState.INVALID;
879
+ const layerIndex = (
880
+ tileImagery.loadingImagery || tileImagery.readyImagery
881
+ ).imageryLayer._layerIndex;
882
+
883
+ // For a layer to be ready, all tiles belonging to that layer must be ready.
884
+ readyImagery[layerIndex] = isReady && readyImagery[layerIndex];
885
+ }
886
+ }
887
+
888
+ const lastFrame = this.quadtree._lastSelectionFrameNumber;
889
+
890
+ // Traverse the descendants looking for one with terrain or imagery that is not loaded on this tile.
891
+ const stack = canRenderTraversalStack;
892
+ stack.length = 0;
893
+ stack.push(
894
+ tile.southwestChild,
895
+ tile.southeastChild,
896
+ tile.northwestChild,
897
+ tile.northeastChild,
898
+ );
899
+
900
+ while (stack.length > 0) {
901
+ const descendant = stack.pop();
902
+ const lastFrameSelectionResult =
903
+ descendant._lastSelectionResultFrame === lastFrame
904
+ ? descendant._lastSelectionResult
905
+ : TileSelectionResult.NONE;
906
+
907
+ if (lastFrameSelectionResult === TileSelectionResult.RENDERED) {
908
+ const descendantSurface = descendant.data;
909
+
910
+ if (!defined(descendantSurface)) {
911
+ // Descendant has no data, so it can't block rendering.
912
+ continue;
913
+ }
914
+
915
+ if (
916
+ !terrainReady &&
917
+ descendant.data.terrainState === TerrainState.READY
918
+ ) {
919
+ // Rendered descendant has real terrain, but we don't. Rendering is blocked.
920
+ return false;
921
+ }
922
+
923
+ const descendantImagery = descendant.data.imagery;
924
+ for (i = 0, len = descendantImagery.length; i < len; ++i) {
925
+ const descendantTileImagery = descendantImagery[i];
926
+ const descendantLoadingImagery = descendantTileImagery.loadingImagery;
927
+ const descendantIsReady =
928
+ !defined(descendantLoadingImagery) ||
929
+ descendantLoadingImagery.state === ImageryState.FAILED ||
930
+ descendantLoadingImagery.state === ImageryState.INVALID;
931
+ const descendantLayerIndex = (
932
+ descendantTileImagery.loadingImagery ||
933
+ descendantTileImagery.readyImagery
934
+ ).imageryLayer._layerIndex;
935
+
936
+ // If this imagery tile of a descendant is ready but the layer isn't ready in this tile,
937
+ // then rendering is blocked.
938
+ if (descendantIsReady && !readyImagery[descendantLayerIndex]) {
939
+ return false;
940
+ }
941
+ }
942
+ } else if (lastFrameSelectionResult === TileSelectionResult.REFINED) {
943
+ stack.push(
944
+ descendant.southwestChild,
945
+ descendant.southeastChild,
946
+ descendant.northwestChild,
947
+ descendant.northeastChild,
948
+ );
949
+ }
950
+ }
951
+
709
952
  return true;
710
953
  }
711
954
 
712
- if (
713
- !Rectangle.equals(
714
- tileProvider.cartographicLimitRectangle,
715
- Rectangle.MAX_VALUE,
716
- )
717
- ) {
718
- return true;
955
+ /**
956
+ * Determines the priority for loading this tile. Lower priority values load sooner.
957
+ * @param {QuadtreeTile} tile The tile.
958
+ * @param {FrameState} frameState The frame state.
959
+ * @returns {number} The load priority value.
960
+ */
961
+ computeTileLoadPriority(tile, frameState) {
962
+ const surfaceTile = /** @type {GlobeSurfaceTile} */ (tile.data);
963
+ if (surfaceTile === undefined) {
964
+ return 0.0;
965
+ }
966
+
967
+ const obb = surfaceTile.tileBoundingRegion.boundingVolume;
968
+ if (obb === undefined) {
969
+ return 0.0;
970
+ }
971
+
972
+ const cameraPosition = frameState.camera.positionWC;
973
+ const cameraDirection = frameState.camera.directionWC;
974
+ const tileDirection = Cartesian3.subtract(
975
+ obb.center,
976
+ cameraPosition,
977
+ tileDirectionScratch,
978
+ );
979
+ const magnitude = Cartesian3.magnitude(tileDirection);
980
+ if (magnitude < CesiumMath.EPSILON5) {
981
+ return 0.0;
982
+ }
983
+ Cartesian3.divideByScalar(tileDirection, magnitude, tileDirection);
984
+ return (
985
+ (1.0 - Cartesian3.dot(tileDirection, cameraDirection)) * tile._distance
986
+ );
719
987
  }
720
988
 
721
- return false;
722
- }
989
+ /**
990
+ * Shows a specified tile in this frame. The provider can cause the tile to be shown by adding
991
+ * render commands to the commandList, or use any other method as appropriate. The tile is not
992
+ * expected to be visible next frame as well, unless this method is called next frame, too.
993
+ *
994
+ * @param {QuadtreeTile} tile The tile instance.
995
+ * @param {FrameState} frameState The state information of the current rendering frame.
996
+ */
997
+ showTileThisFrame(tile, frameState) {
998
+ let readyTextureCount = 0;
999
+ const surfaceTile = /** @type {GlobeSurfaceTile} */ (tile.data);
1000
+ const tileImageryCollection = surfaceTile.imagery;
1001
+ for (let i = 0, len = tileImageryCollection.length; i < len; ++i) {
1002
+ const tileImagery = tileImageryCollection[i];
1003
+ if (
1004
+ defined(tileImagery.readyImagery) &&
1005
+ tileImagery.readyImagery.imageryLayer.alpha !== 0.0
1006
+ ) {
1007
+ ++readyTextureCount;
1008
+ }
1009
+ }
723
1010
 
724
- /**
725
- * Determines the visibility of a given tile. The tile may be fully visible, partially visible, or not
726
- * visible at all. Tiles that are renderable and are at least partially visible will be shown by a call
727
- * to {@link GlobeSurfaceTileProvider#showTileThisFrame}.
728
- *
729
- * @param {QuadtreeTile} tile The tile instance.
730
- * @param {FrameState} frameState The state information about the current frame.
731
- * @param {QuadtreeOccluders} occluders The objects that may occlude this tile.
732
- *
733
- * @returns {Visibility} Visibility.NONE if the tile is not visible,
734
- * Visibility.PARTIAL if the tile is partially visible, or
735
- * Visibility.FULL if the tile is fully visible.
736
- */
737
- GlobeSurfaceTileProvider.prototype.computeTileVisibility = function (
738
- tile,
739
- frameState,
740
- occluders,
741
- ) {
742
- const distance = this.computeDistanceToTile(tile, frameState);
743
- tile._distance = distance;
1011
+ let tileSet = this._tilesToRenderByTextureCount[readyTextureCount];
1012
+ if (!defined(tileSet)) {
1013
+ tileSet = [];
1014
+ this._tilesToRenderByTextureCount[readyTextureCount] = tileSet;
1015
+ }
744
1016
 
745
- const undergroundVisible = isUndergroundVisible(this, frameState);
1017
+ tileSet.push(tile);
746
1018
 
747
- if (frameState.fog.enabled && !undergroundVisible) {
748
- if (CesiumMath.fog(distance, frameState.fog.density) >= 1.0) {
749
- // Tile is completely in fog so return that it is not visible.
750
- return Visibility.NONE;
1019
+ if (!defined(surfaceTile.vertexArray)) {
1020
+ this._hasFillTilesThisFrame = true;
1021
+ } else {
1022
+ this._hasLoadedTilesThisFrame = true;
751
1023
  }
1024
+
1025
+ const debug = this._debug;
1026
+ ++debug.tilesRendered;
1027
+ debug.texturesRendered += readyTextureCount;
752
1028
  }
753
1029
 
754
- const surfaceTile = tile.data;
755
- const tileBoundingRegion = surfaceTile.tileBoundingRegion;
1030
+ /**
1031
+ * Gets the distance from the camera to the closest point on the tile. This is used for level-of-detail selection.
1032
+ *
1033
+ * @param {QuadtreeTile} tile The tile instance.
1034
+ * @param {FrameState} frameState The state information of the current rendering frame.
1035
+ *
1036
+ * @returns {number} The distance from the camera to the closest point on the tile, in meters.
1037
+ */
1038
+ computeDistanceToTile(tile, frameState) {
1039
+ // The distance should be:
1040
+ // 1. the actual distance to the tight-fitting bounding volume, or
1041
+ // 2. a distance that is equal to or greater than the actual distance to the tight-fitting bounding volume.
1042
+ //
1043
+ // When we don't know the min/max heights for a tile, but we do know the min/max of an ancestor tile, we can
1044
+ // build a tight-fitting bounding volume horizontally, but not vertically. The min/max heights from the
1045
+ // ancestor will likely form a volume that is much bigger than it needs to be. This means that the volume may
1046
+ // be deemed to be much closer to the camera than it really is, causing us to select tiles that are too detailed.
1047
+ // Loading too-detailed tiles is super expensive, so we don't want to do that. We don't know where the child
1048
+ // tile really lies within the parent range of heights, but we _do_ know the child tile can't be any closer than
1049
+ // the ancestor height surface (min or max) that is _farthest away_ from the camera. So if we compute distance
1050
+ // based on that conservative metric, we may end up loading tiles that are not detailed enough, but that's much
1051
+ // better (faster) than loading tiles that are too detailed.
1052
+
1053
+ updateTileBoundingRegion(tile, this, frameState);
1054
+
1055
+ const surfaceTile = /** @type {GlobeSurfaceTile} */ (tile.data);
1056
+ const boundingVolumeSourceTile = surfaceTile.boundingVolumeSourceTile;
1057
+ if (boundingVolumeSourceTile === undefined) {
1058
+ // Can't find any min/max heights anywhere? Ok, let's just say the
1059
+ // tile is really far away so we'll load and render it rather than
1060
+ // refining.
1061
+ return 9999999999.0;
1062
+ }
756
1063
 
757
- if (surfaceTile.boundingVolumeSourceTile === undefined) {
758
- // We have no idea where this tile is, so let's just call it partially visible.
759
- return Visibility.PARTIAL;
760
- }
1064
+ const tileBoundingRegion = surfaceTile.tileBoundingRegion;
1065
+ const min = tileBoundingRegion.minimumHeight;
1066
+ const max = tileBoundingRegion.maximumHeight;
1067
+
1068
+ if (surfaceTile.boundingVolumeSourceTile !== tile) {
1069
+ const cameraHeight = frameState.camera.positionCartographic.height;
1070
+ const distanceToMin = Math.abs(cameraHeight - min);
1071
+ const distanceToMax = Math.abs(cameraHeight - max);
1072
+ if (distanceToMin > distanceToMax) {
1073
+ tileBoundingRegion.minimumHeight = min;
1074
+ tileBoundingRegion.maximumHeight = min;
1075
+ } else {
1076
+ tileBoundingRegion.minimumHeight = max;
1077
+ tileBoundingRegion.maximumHeight = max;
1078
+ }
1079
+ }
761
1080
 
762
- const cullingVolume = frameState.cullingVolume;
763
- let boundingVolume = tileBoundingRegion.boundingVolume;
1081
+ const result = tileBoundingRegion.distanceToCamera(frameState);
764
1082
 
765
- if (!defined(boundingVolume)) {
766
- boundingVolume = tileBoundingRegion.boundingSphere;
767
- }
1083
+ tileBoundingRegion.minimumHeight = min;
1084
+ tileBoundingRegion.maximumHeight = max;
768
1085
 
769
- // Check if the tile is outside the limit area in cartographic space
770
- surfaceTile.clippedByBoundaries = false;
771
- const clippedCartographicLimitRectangle = clipRectangleAntimeridian(
772
- tile.rectangle,
773
- this.cartographicLimitRectangle,
774
- );
775
- const areaLimitIntersection = Rectangle.simpleIntersection(
776
- clippedCartographicLimitRectangle,
777
- tile.rectangle,
778
- rectangleIntersectionScratch,
779
- );
780
- if (!defined(areaLimitIntersection)) {
781
- return Visibility.NONE;
1086
+ return result;
782
1087
  }
783
- if (!Rectangle.equals(areaLimitIntersection, tile.rectangle)) {
784
- surfaceTile.clippedByBoundaries = true;
1088
+
1089
+ /**
1090
+ * Returns true if this object was destroyed; otherwise, false.
1091
+ * <br /><br />
1092
+ * If this object was destroyed, it should not be used; calling any function other than
1093
+ * <code>isDestroyed</code> will result in a {@link DeveloperError} exception.
1094
+ *
1095
+ * @returns {boolean} True if this object was destroyed; otherwise, false.
1096
+ *
1097
+ * @see GlobeSurfaceTileProvider#destroy
1098
+ */
1099
+ isDestroyed() {
1100
+ return false;
785
1101
  }
786
1102
 
787
- if (frameState.mode !== SceneMode.SCENE3D) {
788
- boundingVolume = boundingSphereScratch;
789
- BoundingSphere.fromRectangleWithHeights2D(
790
- tile.rectangle,
791
- frameState.mapProjection,
792
- tileBoundingRegion.minimumHeight,
793
- tileBoundingRegion.maximumHeight,
794
- boundingVolume,
795
- );
796
- Cartesian3.fromElements(
797
- boundingVolume.center.z,
798
- boundingVolume.center.x,
799
- boundingVolume.center.y,
800
- boundingVolume.center,
801
- );
1103
+ /**
1104
+ * Destroys the WebGL resources held by this object. Destroying an object allows for deterministic
1105
+ * release of WebGL resources, instead of relying on the garbage collector to destroy this object.
1106
+ * <br /><br />
1107
+ * Once an object is destroyed, it should not be used; calling any function other than
1108
+ * <code>isDestroyed</code> will result in a {@link DeveloperError} exception. Therefore,
1109
+ * assign the return value (<code>undefined</code>) to the object as done in the example.
1110
+ *
1111
+ * @exception {DeveloperError} This object was destroyed, i.e., destroy() was called.
1112
+ *
1113
+ *
1114
+ * @example
1115
+ * provider = provider && provider.destroy();
1116
+ *
1117
+ * @see GlobeSurfaceTileProvider#isDestroyed
1118
+ */
1119
+ destroy() {
1120
+ this._tileProvider = this._tileProvider && this._tileProvider.destroy();
1121
+ this._clippingPlanes =
1122
+ this._clippingPlanes && this._clippingPlanes.destroy();
1123
+ this._clippingPolygons =
1124
+ this._clippingPolygons && this._clippingPolygons.destroy();
1125
+ this._removeLayerAddedListener =
1126
+ this._removeLayerAddedListener && this._removeLayerAddedListener();
1127
+ this._removeLayerRemovedListener =
1128
+ this._removeLayerRemovedListener && this._removeLayerRemovedListener();
1129
+ this._removeLayerMovedListener =
1130
+ this._removeLayerMovedListener && this._removeLayerMovedListener();
1131
+ this._removeLayerShownListener =
1132
+ this._removeLayerShownListener && this._removeLayerShownListener();
1133
+
1134
+ return destroyObject(this);
1135
+ }
1136
+
1137
+ _onLayerAdded(layer, index) {
1138
+ if (this.isDestroyed()) {
1139
+ return;
1140
+ }
802
1141
 
803
- if (
804
- frameState.mode === SceneMode.MORPHING &&
805
- defined(surfaceTile.renderedMesh)
806
- ) {
807
- boundingVolume = BoundingSphere.union(
808
- tileBoundingRegion.boundingSphere,
809
- boundingVolume,
810
- boundingVolume,
811
- );
1142
+ if (layer.show) {
1143
+ const terrainProvider = this._terrainProvider;
1144
+
1145
+ const that = this;
1146
+ const tileImageryUpdatedEvent = this._imageryLayersUpdatedEvent;
1147
+ const reloadFunction = function () {
1148
+ // Clear the layer's cache
1149
+ layer._imageryCache = {};
1150
+
1151
+ that._quadtree.forEachLoadedTile(function (tile) {
1152
+ // If this layer is still waiting to for the loaded callback, just return
1153
+ if (defined(tile._loadedCallbacks[layer._layerIndex])) {
1154
+ return;
1155
+ }
1156
+
1157
+ let i;
1158
+
1159
+ // Figure out how many TileImageries we will need to remove and where to insert new ones
1160
+ const tileImageryCollection = tile.data.imagery;
1161
+ const length = tileImageryCollection.length;
1162
+ let startIndex = -1;
1163
+ let tileImageriesToFree = 0;
1164
+ for (i = 0; i < length; ++i) {
1165
+ const tileImagery = tileImageryCollection[i];
1166
+ const imagery =
1167
+ tileImagery.readyImagery ?? tileImagery.loadingImagery;
1168
+ if (imagery.imageryLayer === layer) {
1169
+ if (startIndex === -1) {
1170
+ startIndex = i;
1171
+ }
1172
+
1173
+ ++tileImageriesToFree;
1174
+ } else if (startIndex !== -1) {
1175
+ // iterated past the section of TileImageries belonging to this layer, no need to continue.
1176
+ break;
1177
+ }
1178
+ }
1179
+
1180
+ if (startIndex === -1) {
1181
+ return;
1182
+ }
1183
+
1184
+ // Insert immediately after existing TileImageries
1185
+ const insertionPoint = startIndex + tileImageriesToFree;
1186
+
1187
+ // Create new TileImageries for all loaded tiles
1188
+ if (
1189
+ layer._createTileImagerySkeletons(
1190
+ tile,
1191
+ terrainProvider,
1192
+ insertionPoint,
1193
+ )
1194
+ ) {
1195
+ // Add callback to remove old TileImageries when the new TileImageries are ready
1196
+ tile._loadedCallbacks[layer._layerIndex] = getTileReadyCallback(
1197
+ tileImageriesToFree,
1198
+ layer,
1199
+ terrainProvider,
1200
+ );
1201
+
1202
+ tile.state = QuadtreeTileLoadState.LOADING;
1203
+ }
1204
+ });
1205
+ };
1206
+
1207
+ if (layer.ready) {
1208
+ const imageryProvider = layer.imageryProvider;
1209
+ imageryProvider._reload = reloadFunction;
1210
+ }
1211
+
1212
+ // create TileImageries for this layer for all previously loaded tiles
1213
+ this._quadtree.forEachLoadedTile(function (tile) {
1214
+ if (layer._createTileImagerySkeletons(tile, terrainProvider)) {
1215
+ tile.state = QuadtreeTileLoadState.LOADING;
1216
+
1217
+ // Tiles that are not currently being rendered need to load the new layer before they're renderable.
1218
+ // We don't mark the rendered tiles non-renderable, though, because that would make the globe disappear.
1219
+ if (
1220
+ tile.level !== 0 &&
1221
+ (tile._lastSelectionResultFrame !==
1222
+ that.quadtree._lastSelectionFrameNumber ||
1223
+ tile._lastSelectionResult !== TileSelectionResult.RENDERED)
1224
+ ) {
1225
+ tile.renderable = false;
1226
+ }
1227
+ }
1228
+ });
1229
+
1230
+ this._layerOrderChanged = true;
1231
+ tileImageryUpdatedEvent.raiseEvent();
812
1232
  }
813
1233
  }
814
1234
 
815
- if (!defined(boundingVolume)) {
816
- return Visibility.PARTIAL;
817
- }
1235
+ _onLayerRemoved(layer, index) {
1236
+ // destroy TileImagerys for this layer for all previously loaded tiles
1237
+ this._quadtree.forEachLoadedTile(function (tile) {
1238
+ const tileImageryCollection = tile.data.imagery;
1239
+
1240
+ let startIndex = -1;
1241
+ let numDestroyed = 0;
1242
+ for (let i = 0, len = tileImageryCollection.length; i < len; ++i) {
1243
+ const tileImagery = tileImageryCollection[i];
1244
+ let imagery = tileImagery.loadingImagery;
1245
+ if (!defined(imagery)) {
1246
+ imagery = tileImagery.readyImagery;
1247
+ }
1248
+ if (imagery.imageryLayer === layer) {
1249
+ if (startIndex === -1) {
1250
+ startIndex = i;
1251
+ }
818
1252
 
819
- const clippingPlanes = this._clippingPlanes;
820
- if (defined(clippingPlanes) && clippingPlanes.enabled) {
821
- const planeIntersection =
822
- clippingPlanes.computeIntersectionWithBoundingVolume(boundingVolume);
823
- tile.isClipped = planeIntersection !== Intersect.INSIDE;
824
- if (planeIntersection === Intersect.OUTSIDE) {
825
- return Visibility.NONE;
1253
+ tileImagery.freeResources();
1254
+ ++numDestroyed;
1255
+ } else if (startIndex !== -1) {
1256
+ // iterated past the section of TileImagerys belonging to this layer, no need to continue.
1257
+ break;
1258
+ }
1259
+ }
1260
+
1261
+ if (startIndex !== -1) {
1262
+ tileImageryCollection.splice(startIndex, numDestroyed);
1263
+ }
1264
+ });
1265
+
1266
+ if (defined(layer.imageryProvider)) {
1267
+ layer.imageryProvider._reload = undefined;
826
1268
  }
1269
+
1270
+ this._imageryLayersUpdatedEvent.raiseEvent();
827
1271
  }
828
1272
 
829
- const clippingPolygons = this._clippingPolygons;
830
- if (defined(clippingPolygons) && clippingPolygons.enabled) {
831
- const polygonIntersection =
832
- clippingPolygons.computeIntersectionWithBoundingVolume(
833
- tileBoundingRegion,
834
- );
835
- tile.isClipped = polygonIntersection !== Intersect.OUTSIDE;
836
- // Polygon clipping intersections are determined by outer rectangles, therefore we cannot
837
- // preemptively determine if a tile is completely clipped or not here.
1273
+ _onLayerMoved(layer, newIndex, oldIndex) {
1274
+ this._layerOrderChanged = true;
1275
+ this._imageryLayersUpdatedEvent.raiseEvent();
838
1276
  }
839
1277
 
840
- let visibility;
841
- const intersection = cullingVolume.computeVisibility(boundingVolume);
1278
+ _onLayerShownOrHidden(layer, index, show) {
1279
+ if (show) {
1280
+ this._onLayerAdded(layer, index);
1281
+ } else {
1282
+ this._onLayerRemoved(layer, index);
1283
+ }
1284
+ }
1285
+ }
842
1286
 
843
- if (intersection === Intersect.OUTSIDE) {
844
- visibility = Visibility.NONE;
845
- } else if (intersection === Intersect.INTERSECTING) {
846
- visibility = Visibility.PARTIAL;
847
- } else if (intersection === Intersect.INSIDE) {
848
- visibility = Visibility.FULL;
1287
+ function sortTileImageryByLayerIndex(a, b) {
1288
+ let aImagery = a.loadingImagery;
1289
+ if (!defined(aImagery)) {
1290
+ aImagery = a.readyImagery;
849
1291
  }
850
1292
 
851
- if (visibility === Visibility.NONE) {
852
- return visibility;
1293
+ let bImagery = b.loadingImagery;
1294
+ if (!defined(bImagery)) {
1295
+ bImagery = b.readyImagery;
853
1296
  }
854
1297
 
855
- const ortho3D =
856
- frameState.mode === SceneMode.SCENE3D &&
857
- frameState.camera.frustum instanceof OrthographicFrustum;
858
- if (
859
- frameState.mode === SceneMode.SCENE3D &&
860
- !ortho3D &&
861
- defined(occluders) &&
862
- !undergroundVisible
863
- ) {
864
- const occludeePointInScaledSpace = surfaceTile.occludeePointInScaledSpace;
865
- if (!defined(occludeePointInScaledSpace)) {
866
- return visibility;
867
- }
1298
+ return aImagery.imageryLayer._layerIndex - bImagery.imageryLayer._layerIndex;
1299
+ }
1300
+
1301
+ /**
1302
+ * @param {GlobeSurfaceTileProvider} surface
1303
+ * @param {FrameState} frameState
1304
+ * @ignore
1305
+ */
1306
+ function updateCredits(surface, frameState) {
1307
+ const creditDisplay = frameState.creditDisplay;
1308
+ const terrainProvider = surface._terrainProvider;
1309
+ // @ts-expect-error Missing types.
1310
+ if (defined(terrainProvider) && defined(terrainProvider.credit)) {
1311
+ // @ts-expect-error Missing types.
1312
+ creditDisplay.addCreditToNextFrame(terrainProvider.credit);
1313
+ }
868
1314
 
869
- if (
870
- occluders.ellipsoid.isScaledSpacePointVisiblePossiblyUnderEllipsoid(
871
- occludeePointInScaledSpace,
872
- tileBoundingRegion.minimumHeight,
873
- )
874
- ) {
875
- return visibility;
1315
+ const imageryLayers = surface._imageryLayers;
1316
+ // @ts-expect-error Missing types.
1317
+ for (let i = 0, len = imageryLayers.length; i < len; ++i) {
1318
+ const layer = imageryLayers.get(i);
1319
+ // @ts-expect-error Missing types.
1320
+ if (layer.ready && layer.show && defined(layer.imageryProvider.credit)) {
1321
+ // @ts-expect-error Missing types.
1322
+ creditDisplay.addCreditToNextFrame(layer.imageryProvider.credit);
876
1323
  }
1324
+ }
1325
+ }
877
1326
 
878
- return Visibility.NONE;
1327
+ /**
1328
+ * @param {DrawCommand} command
1329
+ * @param {FrameState} frameState
1330
+ * @ignore
1331
+ */
1332
+ function pushCommand(command, frameState) {
1333
+ const globeTranslucencyState = frameState.globeTranslucencyState;
1334
+ if (globeTranslucencyState.translucent) {
1335
+ // @ts-expect-error Missing types.
1336
+ const isBlendCommand = command.renderState.blending.enabled;
1337
+ globeTranslucencyState.pushDerivedCommands(
1338
+ command,
1339
+ isBlendCommand,
1340
+ frameState,
1341
+ );
1342
+ } else {
1343
+ frameState.commandList.push(command);
879
1344
  }
1345
+ }
880
1346
 
881
- return visibility;
882
- };
1347
+ const boundingSphereScratch = new BoundingSphere();
1348
+ const rectangleIntersectionScratch = new Rectangle();
1349
+ const splitCartographicLimitRectangleScratch = new Rectangle();
1350
+ const rectangleCenterScratch = new Cartographic();
883
1351
 
884
1352
  /**
885
- * Determines if the given tile can be refined
886
- * @param {QuadtreeTile} tile The tile to check.
887
- * @returns {boolean} True if the tile can be refined, false if it cannot.
1353
+ * @param {Rectangle} tileRectangle
1354
+ * @param {Rectangle} cartographicLimitRectangle
1355
+ * @ignore
888
1356
  */
889
- GlobeSurfaceTileProvider.prototype.canRefine = function (tile) {
890
- // Only allow refinement it we know whether or not the children of this tile exist.
891
- // For a tileset with `availability`, we'll always be able to refine.
892
- // We can ask for availability of _any_ child tile because we only need to confirm
893
- // that we get a yes or no answer, it doesn't matter what the answer is.
894
- if (defined(tile.data.terrainData)) {
895
- return true;
1357
+ function clipRectangleAntimeridian(tileRectangle, cartographicLimitRectangle) {
1358
+ // cartographicLimitRectangle may span the IDL, but tiles never will.
1359
+ if (cartographicLimitRectangle.west < cartographicLimitRectangle.east) {
1360
+ return cartographicLimitRectangle;
896
1361
  }
897
- const childAvailable = this.terrainProvider.getTileDataAvailable(
898
- tile.x * 2,
899
- tile.y * 2,
900
- tile.level + 1,
1362
+ const splitRectangle = Rectangle.clone(
1363
+ cartographicLimitRectangle,
1364
+ splitCartographicLimitRectangleScratch,
901
1365
  );
902
- return childAvailable !== undefined;
903
- };
904
-
905
- const readyImageryScratch = [];
906
- const canRenderTraversalStack = [];
1366
+ const tileCenter = Rectangle.center(tileRectangle, rectangleCenterScratch);
1367
+ if (tileCenter.longitude > 0.0) {
1368
+ splitRectangle.east = CesiumMath.PI;
1369
+ } else {
1370
+ splitRectangle.west = -CesiumMath.PI;
1371
+ }
1372
+ return splitRectangle;
1373
+ }
907
1374
 
908
1375
  /**
909
- * Determines if the given not-fully-loaded tile can be rendered without losing detail that
910
- * was present last frame as a result of rendering descendant tiles. This method will only be
911
- * called if this tile's descendants were rendered last frame. If the tile is fully loaded,
912
- * it is assumed that this method will return true and it will not be called.
913
- * @param {QuadtreeTile} tile The tile to check.
914
- * @returns {boolean} True if the tile can be rendered without losing detail.
1376
+ * @param {GlobeSurfaceTileProvider} tileProvider
1377
+ * @param {FrameState} frameState
1378
+ * @ignore
915
1379
  */
916
- GlobeSurfaceTileProvider.prototype.canRenderWithoutLosingDetail = function (
917
- tile,
918
- frameState,
919
- ) {
920
- const surfaceTile = tile.data;
921
-
922
- const readyImagery = readyImageryScratch;
923
- readyImagery.length = this._imageryLayers.length;
924
-
925
- let terrainReady = false;
926
- let initialImageryState = false;
927
- let imagery;
928
-
929
- if (defined(surfaceTile)) {
930
- // We can render even with non-ready terrain as long as all our rendered descendants
931
- // are missing terrain geometry too. i.e. if we rendered fills for more detailed tiles
932
- // last frame, it's ok to render a fill for this tile this frame.
933
- terrainReady = surfaceTile.terrainState === TerrainState.READY;
934
-
935
- // Initially assume all imagery layers are ready, unless imagery hasn't been initialized at all.
936
- initialImageryState = true;
937
-
938
- imagery = surfaceTile.imagery;
1380
+ function isUndergroundVisible(tileProvider, frameState) {
1381
+ if (frameState.cameraUnderground) {
1382
+ return true;
939
1383
  }
940
1384
 
941
- let i;
942
- let len;
943
-
944
- for (i = 0, len = readyImagery.length; i < len; ++i) {
945
- readyImagery[i] = initialImageryState;
1385
+ if (frameState.globeTranslucencyState.translucent) {
1386
+ return true;
946
1387
  }
947
1388
 
948
- if (defined(imagery)) {
949
- for (i = 0, len = imagery.length; i < len; ++i) {
950
- const tileImagery = imagery[i];
951
- const loadingImagery = tileImagery.loadingImagery;
952
- const isReady =
953
- !defined(loadingImagery) ||
954
- loadingImagery.state === ImageryState.FAILED ||
955
- loadingImagery.state === ImageryState.INVALID;
956
- const layerIndex = (
957
- tileImagery.loadingImagery || tileImagery.readyImagery
958
- ).imageryLayer._layerIndex;
959
-
960
- // For a layer to be ready, all tiles belonging to that layer must be ready.
961
- readyImagery[layerIndex] = isReady && readyImagery[layerIndex];
962
- }
1389
+ if (tileProvider.backFaceCulling) {
1390
+ return false;
963
1391
  }
964
1392
 
965
- const lastFrame = this.quadtree._lastSelectionFrameNumber;
966
-
967
- // Traverse the descendants looking for one with terrain or imagery that is not loaded on this tile.
968
- const stack = canRenderTraversalStack;
969
- stack.length = 0;
970
- stack.push(
971
- tile.southwestChild,
972
- tile.southeastChild,
973
- tile.northwestChild,
974
- tile.northeastChild,
975
- );
976
-
977
- while (stack.length > 0) {
978
- const descendant = stack.pop();
979
- const lastFrameSelectionResult =
980
- descendant._lastSelectionResultFrame === lastFrame
981
- ? descendant._lastSelectionResult
982
- : TileSelectionResult.NONE;
983
-
984
- if (lastFrameSelectionResult === TileSelectionResult.RENDERED) {
985
- const descendantSurface = descendant.data;
986
-
987
- if (!defined(descendantSurface)) {
988
- // Descendant has no data, so it can't block rendering.
989
- continue;
990
- }
991
-
992
- if (
993
- !terrainReady &&
994
- descendant.data.terrainState === TerrainState.READY
995
- ) {
996
- // Rendered descendant has real terrain, but we don't. Rendering is blocked.
997
- return false;
998
- }
999
-
1000
- const descendantImagery = descendant.data.imagery;
1001
- for (i = 0, len = descendantImagery.length; i < len; ++i) {
1002
- const descendantTileImagery = descendantImagery[i];
1003
- const descendantLoadingImagery = descendantTileImagery.loadingImagery;
1004
- const descendantIsReady =
1005
- !defined(descendantLoadingImagery) ||
1006
- descendantLoadingImagery.state === ImageryState.FAILED ||
1007
- descendantLoadingImagery.state === ImageryState.INVALID;
1008
- const descendantLayerIndex = (
1009
- descendantTileImagery.loadingImagery ||
1010
- descendantTileImagery.readyImagery
1011
- ).imageryLayer._layerIndex;
1012
-
1013
- // If this imagery tile of a descendant is ready but the layer isn't ready in this tile,
1014
- // then rendering is blocked.
1015
- if (descendantIsReady && !readyImagery[descendantLayerIndex]) {
1016
- return false;
1017
- }
1018
- }
1019
- } else if (lastFrameSelectionResult === TileSelectionResult.REFINED) {
1020
- stack.push(
1021
- descendant.southwestChild,
1022
- descendant.southeastChild,
1023
- descendant.northwestChild,
1024
- descendant.northeastChild,
1025
- );
1026
- }
1393
+ const clippingPlanes = tileProvider._clippingPlanes;
1394
+ if (defined(clippingPlanes) && clippingPlanes.enabled) {
1395
+ return true;
1027
1396
  }
1028
1397
 
1029
- return true;
1030
- };
1031
-
1032
- const tileDirectionScratch = new Cartesian3();
1033
-
1034
- /**
1035
- * Determines the priority for loading this tile. Lower priority values load sooner.
1036
- * @param {QuadtreeTile} tile The tile.
1037
- * @param {FrameState} frameState The frame state.
1038
- * @returns {number} The load priority value.
1039
- */
1040
- GlobeSurfaceTileProvider.prototype.computeTileLoadPriority = function (
1041
- tile,
1042
- frameState,
1043
- ) {
1044
- const surfaceTile = tile.data;
1045
- if (surfaceTile === undefined) {
1046
- return 0.0;
1398
+ const clippingPolygons = tileProvider._clippingPolygons;
1399
+ if (defined(clippingPolygons) && clippingPolygons.enabled) {
1400
+ return true;
1047
1401
  }
1048
1402
 
1049
- const obb = surfaceTile.tileBoundingRegion.boundingVolume;
1050
- if (obb === undefined) {
1051
- return 0.0;
1403
+ if (
1404
+ !Rectangle.equals(
1405
+ tileProvider.cartographicLimitRectangle,
1406
+ Rectangle.MAX_VALUE,
1407
+ )
1408
+ ) {
1409
+ return true;
1052
1410
  }
1053
1411
 
1054
- const cameraPosition = frameState.camera.positionWC;
1055
- const cameraDirection = frameState.camera.directionWC;
1056
- const tileDirection = Cartesian3.subtract(
1057
- obb.center,
1058
- cameraPosition,
1059
- tileDirectionScratch,
1060
- );
1061
- const magnitude = Cartesian3.magnitude(tileDirection);
1062
- if (magnitude < CesiumMath.EPSILON5) {
1063
- return 0.0;
1064
- }
1065
- Cartesian3.divideByScalar(tileDirection, magnitude, tileDirection);
1066
- return (
1067
- (1.0 - Cartesian3.dot(tileDirection, cameraDirection)) * tile._distance
1068
- );
1069
- };
1412
+ return false;
1413
+ }
1414
+
1415
+ const readyImageryScratch = [];
1416
+ const canRenderTraversalStack = [];
1417
+
1418
+ const tileDirectionScratch = new Cartesian3();
1070
1419
 
1071
1420
  const modifiedModelViewScratch = new Matrix4();
1072
1421
  const modifiedModelViewProjectionScratch = new Matrix4();
@@ -1078,50 +1427,6 @@ const centerEyeScratch = new Cartesian3();
1078
1427
  const southwestScratch = new Cartesian3();
1079
1428
  const northeastScratch = new Cartesian3();
1080
1429
 
1081
- /**
1082
- * Shows a specified tile in this frame. The provider can cause the tile to be shown by adding
1083
- * render commands to the commandList, or use any other method as appropriate. The tile is not
1084
- * expected to be visible next frame as well, unless this method is called next frame, too.
1085
- *
1086
- * @param {QuadtreeTile} tile The tile instance.
1087
- * @param {FrameState} frameState The state information of the current rendering frame.
1088
- */
1089
- GlobeSurfaceTileProvider.prototype.showTileThisFrame = function (
1090
- tile,
1091
- frameState,
1092
- ) {
1093
- let readyTextureCount = 0;
1094
- const tileImageryCollection = tile.data.imagery;
1095
- for (let i = 0, len = tileImageryCollection.length; i < len; ++i) {
1096
- const tileImagery = tileImageryCollection[i];
1097
- if (
1098
- defined(tileImagery.readyImagery) &&
1099
- tileImagery.readyImagery.imageryLayer.alpha !== 0.0
1100
- ) {
1101
- ++readyTextureCount;
1102
- }
1103
- }
1104
-
1105
- let tileSet = this._tilesToRenderByTextureCount[readyTextureCount];
1106
- if (!defined(tileSet)) {
1107
- tileSet = [];
1108
- this._tilesToRenderByTextureCount[readyTextureCount] = tileSet;
1109
- }
1110
-
1111
- tileSet.push(tile);
1112
-
1113
- const surfaceTile = tile.data;
1114
- if (!defined(surfaceTile.vertexArray)) {
1115
- this._hasFillTilesThisFrame = true;
1116
- } else {
1117
- this._hasLoadedTilesThisFrame = true;
1118
- }
1119
-
1120
- const debug = this._debug;
1121
- ++debug.tilesRendered;
1122
- debug.texturesRendered += readyTextureCount;
1123
- };
1124
-
1125
1430
  const cornerPositionsScratch = [
1126
1431
  new Cartesian3(),
1127
1432
  new Cartesian3(),
@@ -1137,7 +1442,9 @@ function computeOccludeePoint(
1137
1442
  maximumHeight,
1138
1443
  result,
1139
1444
  ) {
1445
+ /** @type {EllipsoidalOccluder} */
1140
1446
  const ellipsoidalOccluder = tileProvider.quadtree._occluders.ellipsoid;
1447
+ // @ts-expect-error Missing types.
1141
1448
  const ellipsoid = ellipsoidalOccluder.ellipsoid;
1142
1449
 
1143
1450
  const cornerPositions = cornerPositionsScratch;
@@ -1179,69 +1486,13 @@ function computeOccludeePoint(
1179
1486
  }
1180
1487
 
1181
1488
  /**
1182
- * Gets the distance from the camera to the closest point on the tile. This is used for level-of-detail selection.
1183
- *
1184
- * @param {QuadtreeTile} tile The tile instance.
1185
- * @param {FrameState} frameState The state information of the current rendering frame.
1186
- *
1187
- * @returns {number} The distance from the camera to the closest point on the tile, in meters.
1489
+ * @param {QuadtreeTile} tile
1490
+ * @param {GlobeSurfaceTileProvider} tileProvider
1491
+ * @param {FrameState} frameState
1492
+ * @ignore
1188
1493
  */
1189
- GlobeSurfaceTileProvider.prototype.computeDistanceToTile = function (
1190
- tile,
1191
- frameState,
1192
- ) {
1193
- // The distance should be:
1194
- // 1. the actual distance to the tight-fitting bounding volume, or
1195
- // 2. a distance that is equal to or greater than the actual distance to the tight-fitting bounding volume.
1196
- //
1197
- // When we don't know the min/max heights for a tile, but we do know the min/max of an ancestor tile, we can
1198
- // build a tight-fitting bounding volume horizontally, but not vertically. The min/max heights from the
1199
- // ancestor will likely form a volume that is much bigger than it needs to be. This means that the volume may
1200
- // be deemed to be much closer to the camera than it really is, causing us to select tiles that are too detailed.
1201
- // Loading too-detailed tiles is super expensive, so we don't want to do that. We don't know where the child
1202
- // tile really lies within the parent range of heights, but we _do_ know the child tile can't be any closer than
1203
- // the ancestor height surface (min or max) that is _farthest away_ from the camera. So if we compute distance
1204
- // based on that conservative metric, we may end up loading tiles that are not detailed enough, but that's much
1205
- // better (faster) than loading tiles that are too detailed.
1206
-
1207
- updateTileBoundingRegion(tile, this, frameState);
1208
-
1209
- const surfaceTile = tile.data;
1210
- const boundingVolumeSourceTile = surfaceTile.boundingVolumeSourceTile;
1211
- if (boundingVolumeSourceTile === undefined) {
1212
- // Can't find any min/max heights anywhere? Ok, let's just say the
1213
- // tile is really far away so we'll load and render it rather than
1214
- // refining.
1215
- return 9999999999.0;
1216
- }
1217
-
1218
- const tileBoundingRegion = surfaceTile.tileBoundingRegion;
1219
- const min = tileBoundingRegion.minimumHeight;
1220
- const max = tileBoundingRegion.maximumHeight;
1221
-
1222
- if (surfaceTile.boundingVolumeSourceTile !== tile) {
1223
- const cameraHeight = frameState.camera.positionCartographic.height;
1224
- const distanceToMin = Math.abs(cameraHeight - min);
1225
- const distanceToMax = Math.abs(cameraHeight - max);
1226
- if (distanceToMin > distanceToMax) {
1227
- tileBoundingRegion.minimumHeight = min;
1228
- tileBoundingRegion.maximumHeight = min;
1229
- } else {
1230
- tileBoundingRegion.minimumHeight = max;
1231
- tileBoundingRegion.maximumHeight = max;
1232
- }
1233
- }
1234
-
1235
- const result = tileBoundingRegion.distanceToCamera(frameState);
1236
-
1237
- tileBoundingRegion.minimumHeight = min;
1238
- tileBoundingRegion.maximumHeight = max;
1239
-
1240
- return result;
1241
- };
1242
-
1243
1494
  function updateTileBoundingRegion(tile, tileProvider, frameState) {
1244
- let surfaceTile = tile.data;
1495
+ let surfaceTile = /** @type {GlobeSurfaceTile} */ (tile.data);
1245
1496
  if (surfaceTile === undefined) {
1246
1497
  surfaceTile = tile.data = new GlobeSurfaceTile();
1247
1498
  }
@@ -1291,7 +1542,9 @@ function updateTileBoundingRegion(tile, tileProvider, frameState) {
1291
1542
 
1292
1543
  let ancestorTile = tile.parent;
1293
1544
  while (ancestorTile !== undefined) {
1294
- const ancestorSurfaceTile = ancestorTile.data;
1545
+ const ancestorSurfaceTile = /** @type {GlobeSurfaceTile} */ (
1546
+ ancestorTile.data
1547
+ );
1295
1548
  if (ancestorSurfaceTile !== undefined) {
1296
1549
  const ancestorMesh = ancestorSurfaceTile.mesh;
1297
1550
  const ancestorTerrainData = ancestorSurfaceTile.terrainData;
@@ -1393,53 +1646,6 @@ function updateTileBoundingRegion(tile, tileProvider, frameState) {
1393
1646
  }
1394
1647
  }
1395
1648
 
1396
- /**
1397
- * Returns true if this object was destroyed; otherwise, false.
1398
- * <br /><br />
1399
- * If this object was destroyed, it should not be used; calling any function other than
1400
- * <code>isDestroyed</code> will result in a {@link DeveloperError} exception.
1401
- *
1402
- * @returns {boolean} True if this object was destroyed; otherwise, false.
1403
- *
1404
- * @see GlobeSurfaceTileProvider#destroy
1405
- */
1406
- GlobeSurfaceTileProvider.prototype.isDestroyed = function () {
1407
- return false;
1408
- };
1409
-
1410
- /**
1411
- * Destroys the WebGL resources held by this object. Destroying an object allows for deterministic
1412
- * release of WebGL resources, instead of relying on the garbage collector to destroy this object.
1413
- * <br /><br />
1414
- * Once an object is destroyed, it should not be used; calling any function other than
1415
- * <code>isDestroyed</code> will result in a {@link DeveloperError} exception. Therefore,
1416
- * assign the return value (<code>undefined</code>) to the object as done in the example.
1417
- *
1418
- * @exception {DeveloperError} This object was destroyed, i.e., destroy() was called.
1419
- *
1420
- *
1421
- * @example
1422
- * provider = provider && provider();
1423
- *
1424
- * @see GlobeSurfaceTileProvider#isDestroyed
1425
- */
1426
- GlobeSurfaceTileProvider.prototype.destroy = function () {
1427
- this._tileProvider = this._tileProvider && this._tileProvider.destroy();
1428
- this._clippingPlanes = this._clippingPlanes && this._clippingPlanes.destroy();
1429
- this._clippingPolygons =
1430
- this._clippingPolygons && this._clippingPolygons.destroy();
1431
- this._removeLayerAddedListener =
1432
- this._removeLayerAddedListener && this._removeLayerAddedListener();
1433
- this._removeLayerRemovedListener =
1434
- this._removeLayerRemovedListener && this._removeLayerRemovedListener();
1435
- this._removeLayerMovedListener =
1436
- this._removeLayerMovedListener && this._removeLayerMovedListener();
1437
- this._removeLayerShownListener =
1438
- this._removeLayerShownListener && this._removeLayerShownListener();
1439
-
1440
- return destroyObject(this);
1441
- };
1442
-
1443
1649
  function getTileReadyCallback(tileImageriesToFree, layer, terrainProvider) {
1444
1650
  return function (tile) {
1445
1651
  let tileImagery;
@@ -1484,165 +1690,14 @@ function getTileReadyCallback(tileImageriesToFree, layer, terrainProvider) {
1484
1690
  };
1485
1691
  }
1486
1692
 
1487
- GlobeSurfaceTileProvider.prototype._onLayerAdded = function (layer, index) {
1488
- if (this.isDestroyed()) {
1489
- return;
1490
- }
1491
-
1492
- if (layer.show) {
1493
- const terrainProvider = this._terrainProvider;
1494
-
1495
- const that = this;
1496
- const tileImageryUpdatedEvent = this._imageryLayersUpdatedEvent;
1497
- const reloadFunction = function () {
1498
- // Clear the layer's cache
1499
- layer._imageryCache = {};
1500
-
1501
- that._quadtree.forEachLoadedTile(function (tile) {
1502
- // If this layer is still waiting to for the loaded callback, just return
1503
- if (defined(tile._loadedCallbacks[layer._layerIndex])) {
1504
- return;
1505
- }
1506
-
1507
- let i;
1508
-
1509
- // Figure out how many TileImageries we will need to remove and where to insert new ones
1510
- const tileImageryCollection = tile.data.imagery;
1511
- const length = tileImageryCollection.length;
1512
- let startIndex = -1;
1513
- let tileImageriesToFree = 0;
1514
- for (i = 0; i < length; ++i) {
1515
- const tileImagery = tileImageryCollection[i];
1516
- const imagery =
1517
- tileImagery.readyImagery ?? tileImagery.loadingImagery;
1518
- if (imagery.imageryLayer === layer) {
1519
- if (startIndex === -1) {
1520
- startIndex = i;
1521
- }
1522
-
1523
- ++tileImageriesToFree;
1524
- } else if (startIndex !== -1) {
1525
- // iterated past the section of TileImageries belonging to this layer, no need to continue.
1526
- break;
1527
- }
1528
- }
1529
-
1530
- if (startIndex === -1) {
1531
- return;
1532
- }
1533
-
1534
- // Insert immediately after existing TileImageries
1535
- const insertionPoint = startIndex + tileImageriesToFree;
1536
-
1537
- // Create new TileImageries for all loaded tiles
1538
- if (
1539
- layer._createTileImagerySkeletons(
1540
- tile,
1541
- terrainProvider,
1542
- insertionPoint,
1543
- )
1544
- ) {
1545
- // Add callback to remove old TileImageries when the new TileImageries are ready
1546
- tile._loadedCallbacks[layer._layerIndex] = getTileReadyCallback(
1547
- tileImageriesToFree,
1548
- layer,
1549
- terrainProvider,
1550
- );
1551
-
1552
- tile.state = QuadtreeTileLoadState.LOADING;
1553
- }
1554
- });
1555
- };
1556
-
1557
- if (layer.ready) {
1558
- const imageryProvider = layer.imageryProvider;
1559
- imageryProvider._reload = reloadFunction;
1560
- }
1561
-
1562
- // create TileImageries for this layer for all previously loaded tiles
1563
- this._quadtree.forEachLoadedTile(function (tile) {
1564
- if (layer._createTileImagerySkeletons(tile, terrainProvider)) {
1565
- tile.state = QuadtreeTileLoadState.LOADING;
1566
-
1567
- // Tiles that are not currently being rendered need to load the new layer before they're renderable.
1568
- // We don't mark the rendered tiles non-renderable, though, because that would make the globe disappear.
1569
- if (
1570
- tile.level !== 0 &&
1571
- (tile._lastSelectionResultFrame !==
1572
- that.quadtree._lastSelectionFrameNumber ||
1573
- tile._lastSelectionResult !== TileSelectionResult.RENDERED)
1574
- ) {
1575
- tile.renderable = false;
1576
- }
1577
- }
1578
- });
1579
-
1580
- this._layerOrderChanged = true;
1581
- tileImageryUpdatedEvent.raiseEvent();
1582
- }
1583
- };
1584
-
1585
- GlobeSurfaceTileProvider.prototype._onLayerRemoved = function (layer, index) {
1586
- // destroy TileImagerys for this layer for all previously loaded tiles
1587
- this._quadtree.forEachLoadedTile(function (tile) {
1588
- const tileImageryCollection = tile.data.imagery;
1589
-
1590
- let startIndex = -1;
1591
- let numDestroyed = 0;
1592
- for (let i = 0, len = tileImageryCollection.length; i < len; ++i) {
1593
- const tileImagery = tileImageryCollection[i];
1594
- let imagery = tileImagery.loadingImagery;
1595
- if (!defined(imagery)) {
1596
- imagery = tileImagery.readyImagery;
1597
- }
1598
- if (imagery.imageryLayer === layer) {
1599
- if (startIndex === -1) {
1600
- startIndex = i;
1601
- }
1602
-
1603
- tileImagery.freeResources();
1604
- ++numDestroyed;
1605
- } else if (startIndex !== -1) {
1606
- // iterated past the section of TileImagerys belonging to this layer, no need to continue.
1607
- break;
1608
- }
1609
- }
1610
-
1611
- if (startIndex !== -1) {
1612
- tileImageryCollection.splice(startIndex, numDestroyed);
1613
- }
1614
- });
1615
-
1616
- if (defined(layer.imageryProvider)) {
1617
- layer.imageryProvider._reload = undefined;
1618
- }
1619
-
1620
- this._imageryLayersUpdatedEvent.raiseEvent();
1621
- };
1622
-
1623
- GlobeSurfaceTileProvider.prototype._onLayerMoved = function (
1624
- layer,
1625
- newIndex,
1626
- oldIndex,
1627
- ) {
1628
- this._layerOrderChanged = true;
1629
- this._imageryLayersUpdatedEvent.raiseEvent();
1630
- };
1631
-
1632
- GlobeSurfaceTileProvider.prototype._onLayerShownOrHidden = function (
1633
- layer,
1634
- index,
1635
- show,
1636
- ) {
1637
- if (show) {
1638
- this._onLayerAdded(layer, index);
1639
- } else {
1640
- this._onLayerRemoved(layer, index);
1641
- }
1642
- };
1643
-
1644
1693
  const scratchClippingPlanesMatrix = new Matrix4();
1645
1694
  const scratchInverseTransposeClippingPlanesMatrix = new Matrix4();
1695
+
1696
+ /**
1697
+ * @param {FrameState} frameState
1698
+ * @param {GlobeSurfaceTileProvider} globeSurfaceTileProvider
1699
+ * @ignore
1700
+ */
1646
1701
  function createTileUniformMap(frameState, globeSurfaceTileProvider) {
1647
1702
  const uniformMap = {
1648
1703
  u_initialColor: function () {
@@ -1823,6 +1878,7 @@ function createTileUniformMap(frameState, globeSurfaceTileProvider) {
1823
1878
  return frameState.context.defaultTexture;
1824
1879
  },
1825
1880
  u_clippingExtents: function () {
1881
+ // @ts-expect-error Missing types.
1826
1882
  const texture = globeSurfaceTileProvider._clippingPolygons.extentsTexture;
1827
1883
  if (defined(texture)) {
1828
1884
  return texture;
@@ -1931,8 +1987,13 @@ function createTileUniformMap(frameState, globeSurfaceTileProvider) {
1931
1987
  return uniformMap;
1932
1988
  }
1933
1989
 
1934
- function createWireframeVertexArrayIfNecessary(context, provider, tile) {
1935
- const surfaceTile = tile.data;
1990
+ /**
1991
+ * @param {Context} context
1992
+ * @param {QuadtreeTile} tile
1993
+ * @ignore
1994
+ */
1995
+ function createWireframeVertexArrayIfNecessary(context, tile) {
1996
+ const surfaceTile = /** @type {GlobeSurfaceTile} */ (tile.data);
1936
1997
 
1937
1998
  let mesh;
1938
1999
  let vertexArray;
@@ -2006,8 +2067,22 @@ function createWireframeVertexArray(context, vertexArray, terrainMesh) {
2006
2067
  });
2007
2068
  }
2008
2069
 
2070
+ /**
2071
+ * @type {Function}
2072
+ * @ignore
2073
+ */
2009
2074
  let getDebugOrientedBoundingBox;
2075
+
2076
+ /**
2077
+ * @type {Function}
2078
+ * @ignore
2079
+ */
2010
2080
  let getDebugBoundingSphere;
2081
+
2082
+ /**
2083
+ * @type {VoidFunction}
2084
+ * @ignore
2085
+ */
2011
2086
  let debugDestroyPrimitive;
2012
2087
 
2013
2088
  (function () {
@@ -2020,9 +2095,15 @@ let debugDestroyPrimitive;
2020
2095
  geometry: new SphereOutlineGeometry({ radius: 1.0 }),
2021
2096
  });
2022
2097
  let modelMatrix = new Matrix4();
2098
+ /** @type {OrientedBoundingBox|BoundingSphere} */
2023
2099
  let previousVolume;
2100
+ /** @type {Primitive} */
2024
2101
  let primitive;
2025
2102
 
2103
+ /**
2104
+ * @param {unknown} instance
2105
+ * @returns {Primitive}
2106
+ */
2026
2107
  function createDebugPrimitive(instance) {
2027
2108
  return new Primitive({
2028
2109
  geometryInstances: instance,
@@ -2034,6 +2115,10 @@ let debugDestroyPrimitive;
2034
2115
  });
2035
2116
  }
2036
2117
 
2118
+ /**
2119
+ * @param {OrientedBoundingBox} obb
2120
+ * @param {Color} color
2121
+ */
2037
2122
  getDebugOrientedBoundingBox = function (obb, color) {
2038
2123
  if (obb === previousVolume) {
2039
2124
  return primitive;
@@ -2048,6 +2133,7 @@ let debugDestroyPrimitive;
2048
2133
  );
2049
2134
 
2050
2135
  instanceOBB.modelMatrix = modelMatrix;
2136
+ // @ts-expect-error Missing types.
2051
2137
  instanceOBB.attributes.color =
2052
2138
  ColorGeometryInstanceAttribute.fromColor(color);
2053
2139
 
@@ -2055,6 +2141,11 @@ let debugDestroyPrimitive;
2055
2141
  return primitive;
2056
2142
  };
2057
2143
 
2144
+ /**
2145
+ * @param {BoundingSphere} sphere
2146
+ * @param {Color} color
2147
+ * @returns {Primitive}
2148
+ */
2058
2149
  getDebugBoundingSphere = function (sphere, color) {
2059
2150
  if (sphere === previousVolume) {
2060
2151
  return primitive;
@@ -2070,6 +2161,7 @@ let debugDestroyPrimitive;
2070
2161
  );
2071
2162
 
2072
2163
  instanceSphere.modelMatrix = modelMatrix;
2164
+ // @ts-expect-error Missing types.
2073
2165
  instanceSphere.attributes.color =
2074
2166
  ColorGeometryInstanceAttribute.fromColor(color);
2075
2167
 
@@ -2087,6 +2179,11 @@ let debugDestroyPrimitive;
2087
2179
  })();
2088
2180
 
2089
2181
  const otherPassesInitialColor = new Cartesian4(0.0, 0.0, 0.0, 0.0);
2182
+
2183
+ /**
2184
+ * @type {GlobeSurfaceShaderSetOptions}
2185
+ * @ignore
2186
+ */
2090
2187
  const surfaceShaderSetOptionsScratch = {
2091
2188
  frameState: undefined,
2092
2189
  surfaceTile: undefined,
@@ -2124,8 +2221,14 @@ const surfaceShaderSetOptionsScratch = {
2124
2221
  const defaultUndergroundColor = Color.TRANSPARENT;
2125
2222
  const defaultUndergroundColorAlphaByDistance = new NearFarScalar();
2126
2223
 
2224
+ /**
2225
+ * @param {GlobeSurfaceTileProvider} tileProvider
2226
+ * @param {QuadtreeTile} tile
2227
+ * @param {FrameState} frameState
2228
+ * @ignore
2229
+ */
2127
2230
  function addDrawCommandsForTile(tileProvider, tile, frameState) {
2128
- const surfaceTile = tile.data;
2231
+ const surfaceTile = /** @type {GlobeSurfaceTile} */ (tile.data);
2129
2232
 
2130
2233
  if (!defined(surfaceTile.vertexArray)) {
2131
2234
  if (surfaceTile.fill === undefined) {
@@ -2151,6 +2254,7 @@ function addDrawCommandsForTile(tileProvider, tile, frameState) {
2151
2254
  }
2152
2255
  }
2153
2256
 
2257
+ // @ts-expect-error Missing types.
2154
2258
  let maxTextures = ContextLimits.maximumTextureImageUnits;
2155
2259
 
2156
2260
  let waterMaskTexture = surfaceTile.waterMaskTexture;
@@ -2192,14 +2296,17 @@ function addDrawCommandsForTile(tileProvider, tile, frameState) {
2192
2296
  const showOceanWaves = showReflectiveOcean && defined(oceanNormalMap);
2193
2297
  const terrainProvider = tileProvider.terrainProvider;
2194
2298
  const hasVertexNormals =
2299
+ // @ts-expect-error Missing types.
2195
2300
  defined(terrainProvider) && tileProvider.terrainProvider.hasVertexNormals;
2196
2301
  const enableFog =
2197
2302
  frameState.fog.enabled && frameState.fog.renderable && !cameraUnderground;
2198
2303
  const showGroundAtmosphere =
2199
2304
  tileProvider.showGroundAtmosphere && frameState.mode === SceneMode.SCENE3D;
2200
2305
  const castShadows =
2306
+ // @ts-expect-error https://github.com/CesiumGS/cesium/issues/13420
2201
2307
  ShadowMode.castShadows(tileProvider.shadows) && !translucent;
2202
2308
  const receiveShadows =
2309
+ // @ts-expect-error https://github.com/CesiumGS/cesium/issues/13420
2203
2310
  ShadowMode.receiveShadows(tileProvider.shadows) && !translucent;
2204
2311
 
2205
2312
  const hueShift = tileProvider.hueShift;
@@ -2233,6 +2340,7 @@ function addDrawCommandsForTile(tileProvider, tile, frameState) {
2233
2340
  }
2234
2341
  if (
2235
2342
  defined(tileProvider.clippingPlanes) &&
2343
+ // @ts-expect-error Missing types.
2236
2344
  tileProvider.clippingPlanes.enabled
2237
2345
  ) {
2238
2346
  --maxTextures;
@@ -2426,7 +2534,9 @@ function addDrawCommandsForTile(tileProvider, tile, frameState) {
2426
2534
  ++tileProvider._usedDrawCommands;
2427
2535
 
2428
2536
  if (tile === tileProvider._debug.boundingSphereTile) {
2537
+ // @ts-expect-error Missing types.
2429
2538
  const obb = tileBoundingRegion.boundingVolume;
2539
+ // @ts-expect-error Missing types.
2430
2540
  const boundingSphere = tileBoundingRegion.boundingSphere;
2431
2541
  // If a debug primitive already exists for this tile, it will not be
2432
2542
  // re-created, to avoid allocation every frame. If it were possible
@@ -2851,7 +2961,7 @@ function addDrawCommandsForTile(tileProvider, tile, frameState) {
2851
2961
  command.pass = Pass.GLOBE;
2852
2962
 
2853
2963
  if (tileProvider._debug.wireframe) {
2854
- createWireframeVertexArrayIfNecessary(context, tileProvider, tile);
2964
+ createWireframeVertexArrayIfNecessary(context, tile);
2855
2965
  if (defined(surfaceTile.wireframeVertexArray)) {
2856
2966
  command.vertexArray = surfaceTile.wireframeVertexArray;
2857
2967
  command.primitiveType = PrimitiveType.LINES;
@@ -2879,6 +2989,7 @@ function addDrawCommandsForTile(tileProvider, tile, frameState) {
2879
2989
 
2880
2990
  if (frameState.mode === SceneMode.MORPHING) {
2881
2991
  boundingVolume = BoundingSphere.union(
2992
+ // @ts-expect-error Missing types.
2882
2993
  tileBoundingRegion.boundingSphere,
2883
2994
  boundingVolume,
2884
2995
  boundingVolume,
@@ -2886,10 +2997,12 @@ function addDrawCommandsForTile(tileProvider, tile, frameState) {
2886
2997
  }
2887
2998
  } else {
2888
2999
  command.boundingVolume = BoundingSphere.clone(
3000
+ // @ts-expect-error Missing types.
2889
3001
  tileBoundingRegion.boundingSphere,
2890
3002
  boundingVolume,
2891
3003
  );
2892
3004
  command.orientedBoundingBox = OrientedBoundingBox.clone(
3005
+ // @ts-expect-error Missing types.
2893
3006
  tileBoundingRegion.boundingVolume,
2894
3007
  orientedBoundingBox,
2895
3008
  );