@cesium/engine 17.0.0 → 18.0.1-splats.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 (188) hide show
  1. package/Build/ThirdParty/Workers/z-worker-pako.js +1 -1
  2. package/Build/Workers/{chunk-UC7KH56Y.js → chunk-2AXKROJA.js} +5 -5
  3. package/Build/Workers/{chunk-IKDQX7DY.js → chunk-2J5ZZ7CY.js} +4 -4
  4. package/Build/Workers/{chunk-4TIR5UPL.js → chunk-2SYY3UBI.js} +1 -1
  5. package/Build/Workers/{chunk-CC2WKHIW.js → chunk-2WKW3BEB.js} +6 -6
  6. package/Build/Workers/{chunk-CBFJVM6I.js → chunk-2ZO6BCHN.js} +11 -11
  7. package/Build/Workers/{chunk-7PHT4JHA.js → chunk-3UKG5X7F.js} +12 -12
  8. package/Build/Workers/{chunk-PM4Q36WX.js → chunk-4GYIDPXP.js} +9 -9
  9. package/Build/Workers/{chunk-QUFN3GEO.js → chunk-6EP7ED36.js} +3 -3
  10. package/Build/Workers/{chunk-QJTIOB2Z.js → chunk-6QOBORNG.js} +6 -6
  11. package/Build/Workers/{chunk-YE6MDFDA.js → chunk-6WWHK2ER.js} +14 -14
  12. package/Build/Workers/{chunk-RX65FA7X.js → chunk-6Y6TVYHS.js} +7 -7
  13. package/Build/Workers/{chunk-P2N5IDWU.js → chunk-744VWE2U.js} +13 -13
  14. package/Build/Workers/{chunk-LVGYWPEX.js → chunk-7PQ52XCW.js} +4 -4
  15. package/Build/Workers/{chunk-PS3OKVOQ.js → chunk-A5UFJW2M.js} +12 -12
  16. package/Build/Workers/{chunk-CAKU6ZPR.js → chunk-AQKVFTWV.js} +8 -8
  17. package/Build/Workers/{chunk-236N6BJN.js → chunk-BKTEHJFD.js} +2 -2
  18. package/Build/Workers/{chunk-5PC577K7.js → chunk-CQXYKPAW.js} +16 -16
  19. package/Build/Workers/{chunk-DRMXU674.js → chunk-DI7PHKC6.js} +5 -5
  20. package/Build/Workers/{chunk-CQMXZF4A.js → chunk-DKKIQS6F.js} +6 -6
  21. package/Build/Workers/{chunk-J2HTPGC7.js → chunk-DTVWE5YL.js} +2 -2
  22. package/Build/Workers/{chunk-SSLK4U3V.js → chunk-ERPS2WZC.js} +4 -4
  23. package/Build/Workers/chunk-EYMZ5FSQ.js +280 -0
  24. package/Build/Workers/{chunk-LPGOAMYH.js → chunk-F43TQW5B.js} +2 -2
  25. package/Build/Workers/{chunk-5RPUEFSA.js → chunk-FOMRN6II.js} +6 -6
  26. package/Build/Workers/{chunk-2BJXFXD7.js → chunk-FOTXJYKS.js} +4 -4
  27. package/Build/Workers/{chunk-VXAKU6EV.js → chunk-G2Y7EA4W.js} +5 -5
  28. package/Build/Workers/{chunk-KE45DUDH.js → chunk-GY4E4ZP6.js} +10 -10
  29. package/Build/Workers/{chunk-NZSBSY5K.js → chunk-HDG3VHYL.js} +2 -2
  30. package/Build/Workers/{chunk-WP3IJYLC.js → chunk-HOEUXPBL.js} +9 -9
  31. package/Build/Workers/{chunk-5YEFZMMM.js → chunk-IWDYVJ56.js} +12 -12
  32. package/Build/Workers/{chunk-SQKTLDSD.js → chunk-JA4KPQJL.js} +12 -12
  33. package/Build/Workers/{chunk-MAIKDIBS.js → chunk-JZZQEZMA.js} +6 -6
  34. package/Build/Workers/{chunk-77MDEA47.js → chunk-KPLU3WDY.js} +5 -5
  35. package/Build/Workers/{chunk-E7SMO47Q.js → chunk-LHM6V4D6.js} +5 -5
  36. package/Build/Workers/{chunk-HBNWBMAM.js → chunk-LMTGCD6P.js} +1 -1
  37. package/Build/Workers/{chunk-XYGBWBD5.js → chunk-LWZOYSSF.js} +1 -1
  38. package/Build/Workers/{chunk-OBHLT34A.js → chunk-M6U7SV4T.js} +7 -7
  39. package/Build/Workers/{chunk-MS5NWDHH.js → chunk-O25M56DO.js} +2 -2
  40. package/Build/Workers/{chunk-UX5JWAC7.js → chunk-OE2WXO2Z.js} +10 -10
  41. package/Build/Workers/{chunk-C5DCX2YQ.js → chunk-PFD462OE.js} +6 -6
  42. package/Build/Workers/{chunk-37PA7GZW.js → chunk-PPI33PXH.js} +7 -7
  43. package/Build/Workers/{chunk-4BGKMM7J.js → chunk-PRQQHLUB.js} +1 -1
  44. package/Build/Workers/{chunk-IFIS4CVK.js → chunk-RTUZ7MJB.js} +2 -2
  45. package/Build/Workers/{chunk-G6JUXZUO.js → chunk-S6QBTP5U.js} +4 -4
  46. package/Build/Workers/{chunk-UFV3YUIN.js → chunk-SMFCIGM3.js} +5 -5
  47. package/Build/Workers/{chunk-P57PR3WM.js → chunk-TC3LEKFJ.js} +5 -5
  48. package/Build/Workers/{chunk-7IIMO7ZZ.js → chunk-UTLYCPFY.js} +16 -16
  49. package/Build/Workers/{chunk-HGEGZ67N.js → chunk-V7LEBY53.js} +6 -6
  50. package/Build/Workers/{chunk-GO3RZX2R.js → chunk-VE3UKRDB.js} +9 -9
  51. package/Build/Workers/{chunk-ZTBZMRQT.js → chunk-W3FBD4FE.js} +8 -8
  52. package/Build/Workers/{chunk-K5JTWJPE.js → chunk-YRR6CJGG.js} +4 -4
  53. package/Build/Workers/{chunk-UZ6KXWCA.js → chunk-ZVTKMLU6.js} +4 -4
  54. package/Build/Workers/combineGeometry.js +21 -21
  55. package/Build/Workers/createBoxGeometry.js +15 -15
  56. package/Build/Workers/createBoxOutlineGeometry.js +13 -13
  57. package/Build/Workers/createCircleGeometry.js +23 -23
  58. package/Build/Workers/createCircleOutlineGeometry.js +16 -16
  59. package/Build/Workers/createCoplanarPolygonGeometry.js +30 -30
  60. package/Build/Workers/createCoplanarPolygonOutlineGeometry.js +28 -28
  61. package/Build/Workers/createCorridorGeometry.js +26 -26
  62. package/Build/Workers/createCorridorOutlineGeometry.js +25 -25
  63. package/Build/Workers/createCylinderGeometry.js +17 -17
  64. package/Build/Workers/createCylinderOutlineGeometry.js +15 -15
  65. package/Build/Workers/createEllipseGeometry.js +23 -23
  66. package/Build/Workers/createEllipseOutlineGeometry.js +16 -16
  67. package/Build/Workers/createEllipsoidGeometry.js +16 -16
  68. package/Build/Workers/createEllipsoidOutlineGeometry.js +15 -15
  69. package/Build/Workers/createFrustumGeometry.js +15 -15
  70. package/Build/Workers/createFrustumOutlineGeometry.js +15 -15
  71. package/Build/Workers/createGeometry.js +23 -21
  72. package/Build/Workers/createGroundPolylineGeometry.js +19 -19
  73. package/Build/Workers/createPlaneGeometry.js +13 -13
  74. package/Build/Workers/createPlaneOutlineGeometry.js +12 -12
  75. package/Build/Workers/createPolygonGeometry.js +29 -29
  76. package/Build/Workers/createPolygonOutlineGeometry.js +27 -27
  77. package/Build/Workers/createPolylineGeometry.js +22 -22
  78. package/Build/Workers/createPolylineVolumeGeometry.js +28 -28
  79. package/Build/Workers/createPolylineVolumeOutlineGeometry.js +24 -24
  80. package/Build/Workers/createRectangleGeometry.js +24 -24
  81. package/Build/Workers/createRectangleOutlineGeometry.js +17 -17
  82. package/Build/Workers/createSimplePolylineGeometry.js +20 -20
  83. package/Build/Workers/createSphereGeometry.js +16 -16
  84. package/Build/Workers/createSphereOutlineGeometry.js +15 -15
  85. package/Build/Workers/createTaskProcessorWorker.js +3 -3
  86. package/Build/Workers/createVectorTileClampedPolylines.js +12 -12
  87. package/Build/Workers/createVectorTileGeometries.js +21 -21
  88. package/Build/Workers/createVectorTilePoints.js +11 -11
  89. package/Build/Workers/createVectorTilePolygons.js +19 -19
  90. package/Build/Workers/createVectorTilePolylines.js +12 -12
  91. package/Build/Workers/createVerticesFromGoogleEarthEnterpriseBuffer.js +19 -19
  92. package/Build/Workers/createVerticesFromHeightmap.js +19 -19
  93. package/Build/Workers/createVerticesFromQuantizedTerrainMesh.js +16 -16
  94. package/Build/Workers/createWallGeometry.js +21 -21
  95. package/Build/Workers/createWallOutlineGeometry.js +20 -20
  96. package/Build/Workers/decodeDraco.js +10 -10
  97. package/Build/Workers/decodeGoogleEarthEnterprisePacket.js +5 -5
  98. package/Build/Workers/decodeI3S.js +9 -9
  99. package/Build/Workers/gaussianSplatSorter.js +62 -0
  100. package/Build/Workers/gaussianSplatTextureGenerator.js +68 -0
  101. package/Build/Workers/transcodeKTX2.js +78 -7
  102. package/Build/Workers/transferTypedArrayTest.js +1 -1
  103. package/Build/Workers/upsampleQuantizedTerrainMesh.js +19 -19
  104. package/Source/Core/Ion.js +1 -1
  105. package/Source/Core/PixelFormat.js +98 -0
  106. package/Source/Renderer/Context.js +2 -0
  107. package/Source/Renderer/Pass.js +3 -2
  108. package/Source/Renderer/Texture.js +1 -0
  109. package/Source/Renderer/Texture3D.js +568 -0
  110. package/Source/Renderer/VertexArray.js +33 -8
  111. package/Source/Renderer/createUniform.js +3 -0
  112. package/Source/Renderer/createUniformArray.js +1 -0
  113. package/Source/Scene/ArcGisMapService.js +1 -1
  114. package/Source/Scene/Cesium3DTileContentFactory.js +23 -0
  115. package/Source/Scene/Cesium3DTileset.js +197 -2
  116. package/Source/Scene/GaussianSplat3DTileContent.js +504 -0
  117. package/Source/Scene/GaussianSplatPrimitive.js +932 -0
  118. package/Source/Scene/GaussianSplatRenderResources.js +81 -0
  119. package/Source/Scene/GaussianSplatSorter.js +73 -0
  120. package/Source/Scene/GaussianSplatTextureGenerator.js +64 -0
  121. package/Source/Scene/GlobeSurfaceShaderSet.js +4 -5
  122. package/Source/Scene/GltfLoader.js +82 -4
  123. package/Source/Scene/GltfSpzLoader.js +222 -0
  124. package/Source/Scene/GltfVertexBufferLoader.js +98 -3
  125. package/Source/Scene/ImageryLayer.js +19 -4
  126. package/Source/Scene/ImageryLayerCollection.js +3 -2
  127. package/Source/Scene/Model/CartesianRectangle.js +108 -0
  128. package/Source/Scene/Model/ImageryConfiguration.js +25 -0
  129. package/Source/Scene/Model/ImageryCoverage.js +488 -0
  130. package/Source/Scene/Model/ImageryFlags.js +31 -0
  131. package/Source/Scene/Model/ImageryInput.js +60 -0
  132. package/Source/Scene/Model/ImageryPipelineStage.js +1040 -0
  133. package/Source/Scene/Model/MappedPositions.js +84 -0
  134. package/Source/Scene/Model/Model.js +38 -0
  135. package/Source/Scene/Model/ModelImagery.js +403 -0
  136. package/Source/Scene/Model/ModelImageryMapping.js +489 -0
  137. package/Source/Scene/Model/ModelPrimitiveImagery.js +972 -0
  138. package/Source/Scene/Model/ModelReader.js +810 -0
  139. package/Source/Scene/Model/ModelRenderResources.js +13 -0
  140. package/Source/Scene/Model/ModelRuntimePrimitive.js +20 -0
  141. package/Source/Scene/Model/ModelSceneGraph.js +133 -27
  142. package/Source/Scene/Model/ModelUtility.js +2 -0
  143. package/Source/Scene/Model/NodeRenderResources.js +10 -0
  144. package/Source/Scene/ModelComponents.js +10 -0
  145. package/Source/Scene/PrimitiveLoadPlan.js +59 -0
  146. package/Source/Scene/ResourceCache.js +60 -3
  147. package/Source/Scene/ResourceCacheKey.js +39 -1
  148. package/Source/Scene/Scene.js +32 -1
  149. package/Source/Scene/VertexAttributeSemantic.js +30 -0
  150. package/Source/Scene/VoxelPrimitive.js +22 -37
  151. package/Source/Scene/VoxelRenderResources.js +1 -1
  152. package/Source/Scene/processVoxelProperties.js +41 -100
  153. package/Source/Shaders/Builtin/Constants/passGaussianSplats.glsl +9 -0
  154. package/Source/Shaders/Builtin/Constants/passGaussianSplats.js +11 -0
  155. package/Source/Shaders/Builtin/Constants/passOverlay.glsl +1 -1
  156. package/Source/Shaders/Builtin/Constants/passOverlay.js +1 -1
  157. package/Source/Shaders/Builtin/CzmBuiltins.js +2 -0
  158. package/Source/Shaders/Builtin/Functions/windowToEyeCoordinates.glsl +0 -1
  159. package/Source/Shaders/Builtin/Functions/windowToEyeCoordinates.js +0 -1
  160. package/Source/Shaders/GlobeFS.glsl +22 -0
  161. package/Source/Shaders/GlobeFS.js +22 -0
  162. package/Source/Shaders/Model/MaterialStageFS.glsl +4 -0
  163. package/Source/Shaders/Model/MaterialStageFS.js +4 -0
  164. package/Source/Shaders/Model/ModelFS.glsl +3 -1
  165. package/Source/Shaders/Model/ModelFS.js +3 -1
  166. package/Source/Shaders/Model/ModelVS.glsl +5 -1
  167. package/Source/Shaders/Model/ModelVS.js +5 -1
  168. package/Source/Shaders/Model/PointCloudStylingStageVS.glsl +1 -1
  169. package/Source/Shaders/Model/PointCloudStylingStageVS.js +2 -1
  170. package/Source/Shaders/PrimitiveGaussianSplatFS.glsl +18 -0
  171. package/Source/Shaders/PrimitiveGaussianSplatFS.js +20 -0
  172. package/Source/Shaders/PrimitiveGaussianSplatVS.glsl +108 -0
  173. package/Source/Shaders/PrimitiveGaussianSplatVS.js +109 -0
  174. package/Source/Shaders/Voxels/IntersectDepth.glsl +10 -3
  175. package/Source/Shaders/Voxels/IntersectDepth.js +10 -3
  176. package/Source/Shaders/Voxels/Intersection.glsl +1 -3
  177. package/Source/Shaders/Voxels/Intersection.js +1 -3
  178. package/Source/Shaders/Voxels/IntersectionUtils.glsl +1 -0
  179. package/Source/Shaders/Voxels/IntersectionUtils.js +1 -0
  180. package/Source/Shaders/Voxels/VoxelFS.glsl +37 -24
  181. package/Source/Shaders/Voxels/VoxelFS.js +37 -24
  182. package/Source/ThirdParty/Workers/z-worker-pako.js +1 -1
  183. package/Source/ThirdParty/wasm_splats_bg.wasm +0 -0
  184. package/Source/Workers/gaussianSplatSorter.js +34 -0
  185. package/Source/Workers/gaussianSplatTextureGenerator.js +39 -0
  186. package/index.d.ts +66 -2
  187. package/index.js +101 -80
  188. package/package.json +6 -4
@@ -0,0 +1,972 @@
1
+ import defined from "../../Core/defined.js";
2
+ import DeveloperError from "../../Core/DeveloperError.js";
3
+ import Matrix4 from "../../Core/Matrix4.js";
4
+ import Check from "../../Core/Check.js";
5
+ import destroyObject from "../../Core/destroyObject.js";
6
+
7
+ import ImageryState from "../ImageryState.js";
8
+ import ImageryCoverage from "./ImageryCoverage.js";
9
+ import ModelImageryMapping from "./ModelImageryMapping.js";
10
+ import ModelUtility from "./ModelUtility.js";
11
+ import MappedPositions from "./MappedPositions.js";
12
+
13
+ import Buffer from "../../Renderer/Buffer.js";
14
+ import BufferUsage from "../../Renderer/BufferUsage.js";
15
+
16
+ /**
17
+ * A class managing the draping of imagery on a single model primitive.
18
+ *
19
+ * The <code>ModelImagery</code> class creates one instance of this
20
+ * class for each primitive that appears in the model.
21
+ *
22
+ * It is responsible for computing
23
+ * - the mapped (cartographic) positions of the primitive
24
+ * - the imagery tiles that are covered by these mapped positions
25
+ * - the texture coordinates (attributes) that correspond to these mapped positions
26
+ *
27
+ * @private
28
+ */
29
+ class ModelPrimitiveImagery {
30
+ /**
31
+ * Creates a new instance
32
+ *
33
+ * @param {Model} model The model
34
+ * @param {ModelRuntimeNode} runtimeNode The node that the primitive is attached to
35
+ * @param {ModelRuntimePrimitive} runtimePrimitive The primitive
36
+ * @throws {DeveloperError} If any argument is not defined
37
+ */
38
+ constructor(model, runtimeNode, runtimePrimitive) {
39
+ //>>includeStart('debug', pragmas.debug);
40
+ Check.defined("model", model);
41
+ Check.defined("runtimeNode", runtimeNode);
42
+ Check.defined("runtimePrimitive", runtimePrimitive);
43
+ //>>includeEnd('debug');
44
+
45
+ /**
46
+ * The model that this instance was created for.
47
+ *
48
+ * @type {Model}
49
+ * @readonly
50
+ * @private
51
+ */
52
+ this._model = model;
53
+
54
+ /**
55
+ * The node that the primitive is attached to
56
+ *
57
+ * @type {ModelRuntimeNode}
58
+ * @readonly
59
+ * @private
60
+ */
61
+ this._runtimeNode = runtimeNode;
62
+
63
+ /**
64
+ * The primitive that this instance was created for.
65
+ *
66
+ * @type {ModelRuntimePrimitive}
67
+ * @readonly
68
+ * @private
69
+ */
70
+ this._runtimePrimitive = runtimePrimitive;
71
+
72
+ /**
73
+ * The <code>MappedPositions</code> objects, one for each ellipsoid
74
+ * of one of the imagery layers
75
+ *
76
+ * These objects are just plain structures that summarize the
77
+ * cartographic positions of the primitive for one specific
78
+ * ellipsoid
79
+ *
80
+ * @type {MappedPositions[]|undefined}
81
+ * @private
82
+ */
83
+ this._mappedPositionsPerEllipsoid = undefined;
84
+
85
+ /**
86
+ * The last <code>model.modelMatrix</code> for which the mapped
87
+ * positions have been computed.
88
+ *
89
+ * This is used for detecting changes in the model matrix that
90
+ * make it necessary to re-compute the mapped positions.
91
+ *
92
+ * @type {Matrix4}
93
+ * @readonly
94
+ * @private
95
+ */
96
+ this._mappedPositionsModelMatrix = new Matrix4();
97
+
98
+ /**
99
+ * The value that the <code>Cesium3DTileset.imageryLayersModificationCounter</code>
100
+ * had during the last update call. This is used for triggering updates when the
101
+ * imagery layer collection in the tileset changes.
102
+ */
103
+ this._lastImageryLayersModificationCounter = 0;
104
+
105
+ /**
106
+ * The texture coordinate attributes, one for each projection.
107
+ *
108
+ * This contains one <code>ModelComponents.Attribute</code> for each
109
+ * unique projection that is used in the imagery layers. These
110
+ * texture coordinate attributes are computed based on the mapped
111
+ * positions for the respective ellipsoid of that projection.
112
+ */
113
+ this._imageryTexCoordAttributesPerProjection = undefined;
114
+
115
+ /**
116
+ * The current imagery layers.
117
+ *
118
+ * This is initialized when the _coveragesPerLayer are computed,
119
+ * and tracked to that the reference counters of the imageries
120
+ * can be decreased when the coverages per layer are deleted.
121
+ *
122
+ * @type {ImageryLayer[]|undefined}
123
+ * @private
124
+ */
125
+ this._currentImageryLayers = undefined;
126
+
127
+ /**
128
+ * Information about the imagery tiles that are covered by the positions
129
+ * of the primitive.
130
+ *
131
+ * This is computed in the <code>update</code> function, based on the
132
+ * mapped positions of the primitive. After this computation,
133
+ * <code>_coveragesPerLayer[layerIndex]</code> is an array that contains
134
+ * the <code>ImageryCoverage</code> objects that describe the imagery
135
+ * tiles that are covered, including their texture coordinate rectangle.
136
+ *
137
+ * @type {ImageryCoverage[][]|undefined}
138
+ * @private
139
+ */
140
+ this._coveragesPerLayer = undefined;
141
+
142
+ /**
143
+ * A flag indicating whether all imagery objects that are covered
144
+ * are "ready".
145
+ *
146
+ * This is initially <code>false</code>. During the calls to the
147
+ * <code>update</code> function (which are triggered from the
148
+ * <code>Model.update</code> function, each frame), the
149
+ * <code>_updateImageries</code> function will be called, and
150
+ * process the imagery tiles, until all them them are in a
151
+ * state like <code>ImageryState.READY</code>, at which point
152
+ * this flag is set to <code>true</code>.
153
+ *
154
+ * @type {boolean}
155
+ * @private
156
+ */
157
+ this._allImageriesReady = false;
158
+ }
159
+
160
+ /**
161
+ * Returns the <code>ImageryCoverage</code> array that has been
162
+ * computed for the given imagery layer.
163
+ *
164
+ * This assumes that the given imagery layer is part of the
165
+ * imagery layer collection of the model, and that this
166
+ * model primitive imagery is "ready", meaning that the
167
+ * coverages have already been computed.
168
+ *
169
+ * Clients may <b>not</b> modify the returned array or any
170
+ * of its objects!
171
+ *
172
+ * @param {ImageryLayer} imageryLayer The imagery layer
173
+ * @returns {ImageryCoverage[]} The coverage information
174
+ */
175
+ coveragesForImageryLayer(imageryLayer) {
176
+ const model = this._model;
177
+ const imageryLayers = model.imageryLayers;
178
+ const index = imageryLayers.indexOf(imageryLayer);
179
+ if (index === -1) {
180
+ throw new DeveloperError("Imagery layer is not part of the model");
181
+ }
182
+ const coveragesPerLayer = this._coveragesPerLayer;
183
+ if (!defined(coveragesPerLayer)) {
184
+ throw new DeveloperError(
185
+ `The coveragesPerLayer have not been computed yet`,
186
+ );
187
+ }
188
+ return coveragesPerLayer[index];
189
+ }
190
+
191
+ /**
192
+ * Update the state of this instance.
193
+ *
194
+ * This is called as part of <code>ModelImagery.update</code>, which in
195
+ * turn is part of the <code>Model.update</code> that is called in each
196
+ * frame.
197
+ *
198
+ * This will perform the computations that are required to establish
199
+ * the mapping between the imagery and the primitive. It will...
200
+ * <ul>
201
+ * <li>
202
+ * Compute the <code>MappedPositions</code> of the primitive,
203
+ * one instance for each ellipsoid
204
+ * </li>
205
+ * <li>
206
+ * Compute the "coverages per layer", containing the information
207
+ * about which parts of the respective imagery layer are covered
208
+ * by the mapped positions
209
+ * </li>
210
+ * <li>
211
+ * Compute the texture coordinate attributes for the imagery, one
212
+ * for each projection, and store them as the
213
+ * <code>_imageryTexCoordAttributesPerProjection</code>
214
+ * </li>
215
+ * <li>
216
+ * Update the imageries (i.e. processing their state machine by
217
+ * calling <code>Imagery.processStateMachine</code>) until they
218
+ * are in the <code>ImageryState.READY</code> state
219
+ * </li>
220
+ * </ul>
221
+ *
222
+ * @param {FrameState} frameState The frame state
223
+ */
224
+ update(frameState) {
225
+ //>>includeStart('debug', pragmas.debug);
226
+ Check.defined("frameState", frameState);
227
+ //>>includeEnd('debug');
228
+
229
+ // If the imagery layers have been modified since the last call
230
+ // to this function, then re-build everything
231
+ const model = this._model;
232
+ const content = model.content;
233
+ const tileset = content.tileset;
234
+ const modificationCounter = tileset.imageryLayersModificationCounter;
235
+ if (this._lastImageryLayersModificationCounter !== modificationCounter) {
236
+ delete this._mappedPositionsPerEllipsoid;
237
+ this._lastImageryLayersModificationCounter = modificationCounter;
238
+ }
239
+
240
+ if (this._mappedPositionsNeedUpdate) {
241
+ model.resetDrawCommands();
242
+ this._mappedPositionsPerEllipsoid =
243
+ this._computeMappedPositionsPerEllipsoid();
244
+ this._deleteCoveragesPerLayer();
245
+ this._destroyImageryTexCoordAttributes();
246
+ }
247
+
248
+ if (!defined(this._imageryTexCoordAttributesPerProjection)) {
249
+ this._imageryTexCoordAttributesPerProjection =
250
+ this._computeImageryTexCoordsAttributesPerProjection();
251
+ this._uploadImageryTexCoordAttributes(frameState.context);
252
+ }
253
+
254
+ if (!defined(this._coveragesPerLayer)) {
255
+ this._computeCoveragesPerLayer();
256
+ this._allImageriesReady = false;
257
+ }
258
+ if (!this._allImageriesReady) {
259
+ this._updateImageries(frameState);
260
+ }
261
+ }
262
+
263
+ /**
264
+ * Delete the <code>_coveragesPerLayer</code> if they are defined.
265
+ *
266
+ * This will call <code>deleteCoverages</code> for each set of coverages,
267
+ * and eventually delete the <code>_coveragesPerLayer</code>.
268
+ *
269
+ * This will cause the reference counters of the imageries to be
270
+ * decreased.
271
+ */
272
+ _deleteCoveragesPerLayer() {
273
+ const coveragesPerLayer = this._coveragesPerLayer;
274
+ if (!defined(coveragesPerLayer)) {
275
+ return;
276
+ }
277
+ const imageryLayers = this._currentImageryLayers;
278
+ const length = coveragesPerLayer.length;
279
+ for (let i = 0; i < length; i++) {
280
+ const imageryLayer = imageryLayers[i];
281
+ const coverages = coveragesPerLayer[i];
282
+ this._deleteCoverages(imageryLayer, coverages);
283
+ }
284
+ delete this._currentImageryLayers;
285
+ delete this._coveragesPerLayer;
286
+ }
287
+
288
+ /**
289
+ * Delete the given imagery coverage objects for the given imagery
290
+ * layer, meaning that it will cause the reference counters of the
291
+ * imageries to be decreased.
292
+ *
293
+ * If the imagery layer already has been destroyed, then nothing
294
+ * will be done.
295
+ *
296
+ * @param {ImageryLayer} imageryLayer The imagery layer
297
+ * @param {ImageryCoverage[]} coverages The coverages
298
+ */
299
+ _deleteCoverages(imageryLayer, coverages) {
300
+ if (imageryLayer.isDestroyed()) {
301
+ return;
302
+ }
303
+ const length = coverages.length;
304
+ for (let i = 0; i < length; i++) {
305
+ const coverage = coverages[i];
306
+ const imagery = coverage.imagery;
307
+ imagery.releaseReference();
308
+ }
309
+ }
310
+
311
+ /**
312
+ * Create the GPU buffers for the typed arrays that are contained
313
+ * in the <code>_imageryTexCoordAttributesPerProjection</code>
314
+ *
315
+ * @param {Context} context The GL context
316
+ */
317
+ _uploadImageryTexCoordAttributes(context) {
318
+ //>>includeStart('debug', pragmas.debug);
319
+ Check.defined("context", context);
320
+ //>>includeEnd('debug');
321
+
322
+ const attributes = this._imageryTexCoordAttributesPerProjection;
323
+ if (!defined(attributes)) {
324
+ return;
325
+ }
326
+ const n = attributes.length;
327
+ for (let i = 0; i < n; i++) {
328
+ const attribute = attributes[i];
329
+
330
+ // Allocate the GL resources for the new attribute
331
+ const imageryTexCoordBuffer = Buffer.createVertexBuffer({
332
+ context: context,
333
+ typedArray: attribute.typedArray,
334
+ usage: BufferUsage.STATIC_DRAW,
335
+ });
336
+
337
+ // TODO_DRAPING Review this. Probably, some cleanup
338
+ // has to happen somewhere else after setting this.
339
+ // Check that the call to "destroy" in
340
+ // _destroyImageryTexCoordAttributes is the right
341
+ // thing to do here.
342
+ imageryTexCoordBuffer.vertexArrayDestroyable = false;
343
+
344
+ attribute.buffer = imageryTexCoordBuffer;
345
+ }
346
+ }
347
+
348
+ /**
349
+ * Destroy the <code>_imageryTexCoordAttributesPerProjection</code>
350
+ * array.
351
+ *
352
+ * This is called for cleaning up the allocated GPU resources, before
353
+ * they are supposed to be re-computed with
354
+ * <code>_computeImageryTexCoordsAttributesPerProjection</code>
355
+ */
356
+ _destroyImageryTexCoordAttributes() {
357
+ const attributes = this._imageryTexCoordAttributesPerProjection;
358
+ if (!defined(attributes)) {
359
+ return;
360
+ }
361
+ const n = attributes.length;
362
+ for (let i = 0; i < n; i++) {
363
+ const attribute = attributes[i];
364
+ if (defined(attribute)) {
365
+ if (defined(attribute.buffer)) {
366
+ if (!attribute.buffer.isDestroyed()) {
367
+ attribute.buffer.destroy();
368
+ }
369
+ }
370
+ attributes[i] = undefined;
371
+ }
372
+ }
373
+ delete this._imageryTexCoordAttributesPerProjection;
374
+ }
375
+
376
+ /**
377
+ * Returns whether the <code>MappedPositions</code> have to be
378
+ * re-computed with <code>_computeMappedPositionsPerEllipsoid</code>.
379
+ *
380
+ * This is <code>true</code> when the positions have not yet been
381
+ * computed, or when the <code>modelMatrix</code> of the model
382
+ * changed since the previous call.
383
+ *
384
+ * @returns {boolean} Whether the mapped positions need an update
385
+ * @private
386
+ */
387
+ get _mappedPositionsNeedUpdate() {
388
+ if (!defined(this._mappedPositionsPerEllipsoid)) {
389
+ return true;
390
+ }
391
+ const model = this._model;
392
+ const lastModelMatrix = this._mappedPositionsModelMatrix;
393
+ if (!Matrix4.equals(model.modelMatrix, lastModelMatrix)) {
394
+ return true;
395
+ }
396
+ return false;
397
+ }
398
+
399
+ /**
400
+ * Computes the mapped positions of the primitive, one for each ellipsoid.
401
+ *
402
+ * This computes the <i>unique</i> ellipsoids that appear in the imagery
403
+ * layers of the model, and creates one <code>MappedPositions</code>
404
+ * object for each of them.
405
+ *
406
+ * The respective <code>MappedPositions</code> objects will contain
407
+ * the cartographic positions that are computed from the positions
408
+ * of the primitive. These will serve as the basis for computing the
409
+ * part of the imagery that is covered by the primitive.
410
+ *
411
+ * These mapped positions depend on the current <code>modelMatrix</code>
412
+ * of the model. So they have to be re-computed when the model matrix
413
+ * changes.
414
+ *
415
+ * @returns {MappedPositions[]} The mapped positions
416
+ * @private
417
+ */
418
+ _computeMappedPositionsPerEllipsoid() {
419
+ const model = this._model;
420
+ const runtimeNode = this._runtimeNode;
421
+ const runtimePrimitive = this._runtimePrimitive;
422
+
423
+ const primitivePositionAttribute =
424
+ ModelPrimitiveImagery._obtainPrimitivePositionAttribute(
425
+ runtimePrimitive.primitive,
426
+ );
427
+ const numPositions = primitivePositionAttribute.count;
428
+
429
+ const primitivePositionTransform =
430
+ ModelPrimitiveImagery._computePrimitivePositionTransform(
431
+ model,
432
+ runtimeNode,
433
+ undefined,
434
+ );
435
+
436
+ const mappedPositionsPerEllipsoid = [];
437
+ const ellipsoids = ModelPrimitiveImagery._computeUniqueEllipsoids(
438
+ model.imageryLayers,
439
+ );
440
+
441
+ const length = ellipsoids.length;
442
+ for (let i = 0; i < length; i++) {
443
+ const ellipsoid = ellipsoids[i];
444
+ const cartographicPositions =
445
+ ModelImageryMapping.createCartographicPositions(
446
+ primitivePositionAttribute,
447
+ primitivePositionTransform,
448
+ ellipsoid,
449
+ );
450
+ const cartographicBoundingRectangle =
451
+ ModelImageryMapping.computeCartographicBoundingRectangle(
452
+ cartographicPositions,
453
+ );
454
+
455
+ const mappedPositions = new MappedPositions(
456
+ cartographicPositions,
457
+ numPositions,
458
+ cartographicBoundingRectangle,
459
+ ellipsoid,
460
+ );
461
+ mappedPositionsPerEllipsoid.push(mappedPositions);
462
+ }
463
+ Matrix4.clone(model.modelMatrix, this._mappedPositionsModelMatrix);
464
+ return mappedPositionsPerEllipsoid;
465
+ }
466
+
467
+ /**
468
+ * Computes an array containing the <i>unique</i> ellipsoids that
469
+ * appear in the imagery layers of the given collection.
470
+ *
471
+ * @param {ImageryLayerCollection} imageryLayers
472
+ * @returns {Ellipsoid[]} The ellipsoids
473
+ * @private
474
+ */
475
+ static _computeUniqueEllipsoids(imageryLayers) {
476
+ //>>includeStart('debug', pragmas.debug);
477
+ Check.defined("imageryLayers", imageryLayers);
478
+ //>>includeEnd('debug');
479
+
480
+ const ellipsoidsSet = new Set();
481
+ const length = imageryLayers.length;
482
+ for (let i = 0; i < length; i++) {
483
+ const imageryLayer = imageryLayers.get(i);
484
+ const ellipsoid = ModelPrimitiveImagery._getEllipsoid(imageryLayer);
485
+ ellipsoidsSet.add(ellipsoid);
486
+ }
487
+ return [...ellipsoidsSet];
488
+ }
489
+
490
+ /**
491
+ * Computes one coordinate attribute for each unique projection
492
+ * that is used in the imagery layers.
493
+ *
494
+ * This is taking the mapped positions, projecting them with
495
+ * the respective projection, and creating a texture coordinate
496
+ * attribute that describes the texture coordinates of these
497
+ * positions, relative to the cartographic bounding rectangle
498
+ * of the mapped positions.
499
+ *
500
+ * @returns {ModelComponents.Attribute[]} The attributes
501
+ */
502
+ _computeImageryTexCoordsAttributesPerProjection() {
503
+ const model = this._model;
504
+ const imageryLayers = model.imageryLayers;
505
+
506
+ // Compute the arrays containing ALL projections and the array
507
+ // containing the UNIQUE projections from the imagery layers.
508
+ // Texture coordinate attributes only have to be created once
509
+ // for each projection.
510
+ const allProjections =
511
+ ModelPrimitiveImagery._extractProjections(imageryLayers);
512
+ const uniqueProjections = [...new Set(allProjections)];
513
+
514
+ // Create one texture coordinate attribute for each distinct
515
+ // projection that is used in the imagery layers
516
+ const attributes = this._createImageryTexCoordAttributes(uniqueProjections);
517
+ return attributes;
518
+ }
519
+
520
+ /**
521
+ * Computes an array containing the projections that are used in
522
+ * the given imagery layers.
523
+ *
524
+ * (Note that this array may contain duplicates)
525
+ *
526
+ * @param {ImageryLayerCollection} imageryLayers The imagery layers
527
+ * @returns {MapProjection[]} The projections
528
+ * @private
529
+ */
530
+ static _extractProjections(imageryLayers) {
531
+ //>>includeStart('debug', pragmas.debug);
532
+ Check.defined("imageryLayers", imageryLayers);
533
+ //>>includeEnd('debug');
534
+
535
+ const projections = [];
536
+ const length = imageryLayers.length;
537
+ for (let i = 0; i < length; i++) {
538
+ const imageryLayer = imageryLayers.get(i);
539
+ const projection = ModelPrimitiveImagery._getProjection(imageryLayer);
540
+ projections.push(projection);
541
+ }
542
+ return projections;
543
+ }
544
+
545
+ /**
546
+ * Returns the projection of the given imagery layer.
547
+ *
548
+ * This only exists to hide a train wreck
549
+ *
550
+ * @param {ImageryLayer} imageryLayer The imagery layer
551
+ * @returns {MapProjection} The projection
552
+ * @private
553
+ */
554
+ static _getProjection(imageryLayer) {
555
+ //>>includeStart('debug', pragmas.debug);
556
+ Check.defined("imageryLayer", imageryLayer);
557
+ //>>includeEnd('debug');
558
+ const projection = imageryLayer.imageryProvider.tilingScheme.projection;
559
+ return projection;
560
+ }
561
+
562
+ /**
563
+ * Create texture coordinates, one for each projection.
564
+ *
565
+ * This will create a texture coordinate attribute for each of the given projections,
566
+ * using <code>ModelImageryMapping.createTextureCoordinatesAttributeForMappedPositions</code>,
567
+ *
568
+ * (This means that the given projections should indeed be unique,
569
+ * i.e. contain no duplicates)
570
+ *
571
+ * @param {MapProjection[]} uniqueProjections The projections
572
+ * @returns {ModelComponents.Attribute[]} The attributes
573
+ */
574
+ _createImageryTexCoordAttributes(uniqueProjections) {
575
+ //>>includeStart('debug', pragmas.debug);
576
+ Check.defined("uniqueProjections", uniqueProjections);
577
+ //>>includeEnd('debug');
578
+
579
+ const imageryTexCoordAttributePerUniqueProjection = [];
580
+ const length = uniqueProjections.length;
581
+ for (let i = 0; i < length; i++) {
582
+ // Obtain the mapped positions for the ellipsoid that is used
583
+ // in the projection (i.e. the cartographic positions of the
584
+ // primitive, for the respective ellipsoid)
585
+ const projection = uniqueProjections[i];
586
+ const ellipsoid = projection.ellipsoid;
587
+ const mappedPositions = this.mappedPositionsForEllipsoid(ellipsoid);
588
+
589
+ // Create the actual attribute
590
+ const imageryTexCoordAttribute =
591
+ ModelImageryMapping.createTextureCoordinatesAttributeForMappedPositions(
592
+ mappedPositions,
593
+ projection,
594
+ );
595
+ imageryTexCoordAttributePerUniqueProjection.push(
596
+ imageryTexCoordAttribute,
597
+ );
598
+ }
599
+ return imageryTexCoordAttributePerUniqueProjection;
600
+ }
601
+
602
+ /**
603
+ * Compute the coverage information for the primitive, based on the
604
+ * imagery layers that are associated with the model.
605
+ *
606
+ * This updates the <code>_coveragesPerLayer[layerIndex]</code>, which
607
+ * is an array that contains the <code>ImageryCoverage</code> objects that
608
+ * describe the imagery tiles that are covered by the primitive, including
609
+ * their texture coordinate rectangle.
610
+ *
611
+ * This has to be called after the mapped positions for the primitive
612
+ * have been computed with <code>_computeMappedPositionsPerEllipsoid</code>.
613
+ *
614
+ * @private
615
+ */
616
+ _computeCoveragesPerLayer() {
617
+ const coveragesPerLayer = [];
618
+ const currentImageryLayers = [];
619
+
620
+ const model = this._model;
621
+ const imageryLayers = model.imageryLayers;
622
+ const length = imageryLayers.length;
623
+ for (let i = 0; i < length; i++) {
624
+ const imageryLayer = imageryLayers.get(i);
625
+ const coverages = this._computeCoverage(imageryLayer);
626
+ coveragesPerLayer.push(coverages);
627
+ currentImageryLayers.push(imageryLayer);
628
+ }
629
+
630
+ this._coveragesPerLayer = coveragesPerLayer;
631
+ this._currentImageryLayers = currentImageryLayers;
632
+ }
633
+
634
+ /**
635
+ * Compute the coverage information for the primitive, based on the
636
+ * given imagery layer.
637
+ *
638
+ * This returns an array that contains the <code>ImageryCoverage</code>
639
+ * objects that describe the imagery tiles that are covered by the
640
+ * primitive, including their texture coordinate rectangle.
641
+ *
642
+ * This has to be called after the mapped positions for the primitive
643
+ * have been computed with <code>_computeMappedPositionsPerEllipsoid</code>.
644
+ *
645
+ * @param {ImageryLayer} imageryLayer The imagery layer
646
+ * @returns {ImageryCoverage[]} The coverage information
647
+ * @private
648
+ */
649
+ _computeCoverage(imageryLayer) {
650
+ const mappedPositions = this.mappedPositionsForImageryLayer(imageryLayer);
651
+ const cartographicBoundingRectangle =
652
+ mappedPositions.cartographicBoundingRectangle;
653
+
654
+ const imageryLevel = this._computeImageryLevel(
655
+ imageryLayer,
656
+ cartographicBoundingRectangle,
657
+ );
658
+
659
+ const coverages = ImageryCoverage.createImageryCoverages(
660
+ cartographicBoundingRectangle,
661
+ imageryLayer,
662
+ imageryLevel,
663
+ );
664
+ return coverages;
665
+ }
666
+
667
+ /**
668
+ * Compute a <code>level</code> for accessing the imagery from the given
669
+ * imagery layer that is suitable for a primitive with the given bounding
670
+ * rectangle.
671
+ *
672
+ * @param {ImageryLayer} imageryLayer The imagery layer
673
+ * @param {Rectangle} cartographicBoundingRectangle The cartographic
674
+ * bounding rectangle, as obtained from the MappedPositions for
675
+ * the given imagery layer
676
+ * @returns {number} The imagery level
677
+ */
678
+ _computeImageryLevel(imageryLayer, cartographicBoundingRectangle) {
679
+ const imageryProvider = imageryLayer.imageryProvider;
680
+ const tilingScheme = imageryProvider.tilingScheme;
681
+ const rectangle = tilingScheme.rectangle;
682
+
683
+ // The number of tiles covered by the boundingRectangle (b)
684
+ // for a certain level, based on the tiling scheme rectangle (r) is
685
+ // numberOfTilesCovered = b / (r / 2^level)
686
+ // Solving for "level" yields
687
+ // level = log2( numberOfTilesCovered * r / b)
688
+
689
+ // The goal here is to drape approximately (!) one imagery
690
+ // tile on each primitive. In practice, it may be more
691
+ // (up to 9 in theory)
692
+ const desiredNumberOfTilesCovered = 1;
693
+
694
+ // Perform the computation of the desired level, based on the
695
+ // number of tiles that should be covered (by whatever is
696
+ // larger, the width or the height)
697
+ let boundingRectangleSize = cartographicBoundingRectangle.width;
698
+ let rectangleSize = rectangle.width;
699
+ if (
700
+ cartographicBoundingRectangle.height > cartographicBoundingRectangle.width
701
+ ) {
702
+ boundingRectangleSize = cartographicBoundingRectangle.height;
703
+ rectangleSize = rectangle.height;
704
+ }
705
+ const desiredLevel = Math.log2(
706
+ (desiredNumberOfTilesCovered * rectangleSize) / boundingRectangleSize,
707
+ );
708
+
709
+ // Clamp the level to a valid range, and an integer value
710
+ const imageryLevel = ImageryCoverage._clampImageryLevel(
711
+ imageryProvider,
712
+ desiredLevel,
713
+ );
714
+ return imageryLevel;
715
+ }
716
+
717
+ /**
718
+ * Update all <code>Imagery</code> objects.
719
+ *
720
+ * This is called as part of <code>update</code>, until all required
721
+ * imagery tiles are "ready", as indicated by their <code>state</code>
722
+ * being <code>ImageryState.READY</code>.
723
+ *
724
+ * This is called after it has been determined which imagery tiles are
725
+ * covered by the primitive (i.e. after the <code>_coveragesPerLayer</code>
726
+ * have been computed by calling <code>_computeCoverages</code>).
727
+ *
728
+ * For each covered imagery tile, this will call
729
+ * <code>Imagery.processStateMachine</code> until they are either
730
+ * READY, FAILED, or INVALID.
731
+ *
732
+ * Once they all are in one of these final states, it will set the
733
+ * <code>_allImageriesReady</code> flag to <code>true</code>.
734
+ *
735
+ * @param {FrameState} frameState The frame state, to be passed to
736
+ * <code>imagery.processStateMachine</code>
737
+ * @private
738
+ */
739
+ _updateImageries(frameState) {
740
+ const model = this._model;
741
+ const coveragesPerLayer = this._coveragesPerLayer;
742
+ const length = coveragesPerLayer.length;
743
+ let allImageriesReady = true;
744
+ for (let i = 0; i < length; i++) {
745
+ const coverages = coveragesPerLayer[i];
746
+ const n = coverages.length;
747
+ for (let j = 0; j < n; j++) {
748
+ const coverage = coverages[j];
749
+ const imagery = coverage.imagery;
750
+
751
+ // In the context of loading the imagery for draping
752
+ // it over the primitive, the imagery counts as "ready"
753
+ // when it is really ready, but also when it failed
754
+ // or was invalid (otherwise, the primitive would
755
+ // never turn "ready"
756
+ const countsAsReady =
757
+ imagery.state === ImageryState.READY ||
758
+ imagery.state === ImageryState.FAILED ||
759
+ imagery.state === ImageryState.INVALID;
760
+ if (!countsAsReady) {
761
+ allImageriesReady = false;
762
+ imagery.processStateMachine(frameState, false, false);
763
+ }
764
+ }
765
+ }
766
+
767
+ // When the imageries turned ready, reset the draw commands
768
+ // to trigger a rendering with the updated draw commands
769
+ // that include the imagery now.
770
+ if (allImageriesReady) {
771
+ model.resetDrawCommands();
772
+ }
773
+ this._allImageriesReady = allImageriesReady;
774
+ }
775
+
776
+ /**
777
+ * Returns the <code>MappedPositions</code> object that contains
778
+ * information about the primitive positions that have been computed
779
+ * for the given imagery layer.
780
+ *
781
+ * This assumes that <code>_computeMappedPositionsPerEllipsoid</code> has
782
+ * already been called.
783
+ *
784
+ * @param {ImageryLayer} imageryLayer The imageryLayer
785
+ * @returns {MappedPositions} The mapped positions
786
+ * @throws {DeveloperError} If the mapped positions for the
787
+ * ellipsoid could not be found.
788
+ */
789
+ mappedPositionsForImageryLayer(imageryLayer) {
790
+ const ellipsoid = ModelPrimitiveImagery._getEllipsoid(imageryLayer);
791
+ return this.mappedPositionsForEllipsoid(ellipsoid);
792
+ }
793
+
794
+ /**
795
+ * Returns the <code>MappedPositions</code> object that contains
796
+ * information about the primitive positions that have been computed
797
+ * from the given ellipsoid.
798
+ *
799
+ * This assumes that <code>_computeMappedPositions</code> has
800
+ * already been called.
801
+ *
802
+ * @param {Ellipsoid} ellipsoid The ellipsoid
803
+ * @returns {MappedPositions} The mapped positions
804
+ * @throws {DeveloperError} If the mapped positions for the
805
+ * given ellipsoid could not be found.
806
+ */
807
+ mappedPositionsForEllipsoid(ellipsoid) {
808
+ const mappedPositionsPerEllipsoid = this._mappedPositionsPerEllipsoid;
809
+ if (!defined(mappedPositionsPerEllipsoid)) {
810
+ throw new DeveloperError(
811
+ `The mappedPositions have not been computed yet`,
812
+ );
813
+ }
814
+
815
+ const length = mappedPositionsPerEllipsoid.length;
816
+ for (let i = 0; i < length; i++) {
817
+ const mappedPositions = mappedPositionsPerEllipsoid[i];
818
+ if (mappedPositions.ellipsoid === ellipsoid) {
819
+ return mappedPositions;
820
+ }
821
+ }
822
+ throw new DeveloperError(
823
+ `Could not find mapped positions for ellipsoid ${ellipsoid}`,
824
+ );
825
+ }
826
+
827
+ /**
828
+ * Returns the texture coordinate attributes for the primitive that
829
+ * are used for draping the imagery.
830
+ *
831
+ * This will be available when this object is <code>ready</code>, and
832
+ * will contain one attribute for each unique projection that appears
833
+ * in the imagery layers.
834
+ *
835
+ * @returns {ModelComponents.Attribute[]} The attributes
836
+ */
837
+ imageryTexCoordAttributesPerProjection() {
838
+ const imageryTexCoordAttributesPerProjection =
839
+ this._imageryTexCoordAttributesPerProjection;
840
+ if (!defined(imageryTexCoordAttributesPerProjection)) {
841
+ throw new DeveloperError(
842
+ `The imagery texture coordinate attributes have not been computed yet`,
843
+ );
844
+ }
845
+ return this._imageryTexCoordAttributesPerProjection;
846
+ }
847
+
848
+ /**
849
+ * Returns whether the draping computations are "ready".
850
+ *
851
+ * This means that the <code>coveragesPerLayer</code> information
852
+ * has been computed, which describes the set of imagery tiles
853
+ * that are covered by the primitive, <b>and</b> that all the
854
+ * covered imagery tiles are in a state that counts as "ready"
855
+ * (i.e. <code>ImageryState.READY</code>, <code>FAILED</code>,
856
+ * or <code>INVALID</code>).
857
+ *
858
+ * @returns {boolean} Whether the draping computations are ready
859
+ */
860
+ get ready() {
861
+ const coveragesPerLayer = this._coveragesPerLayer;
862
+ if (!defined(coveragesPerLayer)) {
863
+ return false;
864
+ }
865
+ return this._allImageriesReady;
866
+ }
867
+
868
+ /**
869
+ * Returns whether this object was destroyed.
870
+ *
871
+ * If this object was destroyed, calling any function other than
872
+ * <code>isDestroyed</code> will result in a {@link DeveloperError}.
873
+ *
874
+ * @returns {boolean} Whether this object was destroyed
875
+ */
876
+ isDestroyed() {
877
+ return false;
878
+ }
879
+
880
+ /**
881
+ * Destroys this object and all its resources.
882
+ */
883
+ destroy() {
884
+ if (this.isDestroyed()) {
885
+ return;
886
+ }
887
+ this._deleteCoveragesPerLayer();
888
+ this._destroyImageryTexCoordAttributes();
889
+ return destroyObject(this);
890
+ }
891
+
892
+ /**
893
+ * Compute the transform that apparently has to be applied to
894
+ * the positions attribute of a primitive, to compute the
895
+ * actual, final positions in ECEF coordinates.
896
+ *
897
+ * This is based on the computation of the bounding
898
+ * sphere that is done at the end of buildDrawCommands
899
+ *
900
+ * @param {Model} model The model
901
+ * @param {ModelComponents.Node} runtimeNode The runtime node
902
+ * that the primitive is attached to
903
+ * @param {Matrix4} [result] The result
904
+ * @returns {Matrix4} The result
905
+ * @private
906
+ */
907
+ static _computePrimitivePositionTransform(model, runtimeNode, result) {
908
+ //>>includeStart('debug', pragmas.debug);
909
+ Check.defined("model", model);
910
+ Check.defined("runtimeNode", runtimeNode);
911
+ //>>includeEnd('debug');
912
+
913
+ if (!defined(result)) {
914
+ result = new Matrix4();
915
+ }
916
+
917
+ const modelSceneGraph = model.sceneGraph;
918
+
919
+ Matrix4.clone(Matrix4.IDENTITY, result);
920
+ Matrix4.multiply(result, model.modelMatrix, result);
921
+ Matrix4.multiply(result, modelSceneGraph.components.transform, result);
922
+ Matrix4.multiply(result, modelSceneGraph.axisCorrectionMatrix, result);
923
+ Matrix4.multiply(result, runtimeNode.computedTransform, result);
924
+ return result;
925
+ }
926
+
927
+ /**
928
+ * Returns the <code>"POSITION"</code> attribute from the given primitive.
929
+ *
930
+ * The <code>"POSITION"</code> attribute is required. If it is not
931
+ * defined for the given primitive, then a <code>DeveloperError</code>
932
+ * is thrown.
933
+ *
934
+ * @param {ModelComponents.Primitive} primitive The primitive
935
+ * @returns {ModelComponents.Attribute} The position attribute
936
+ * @throws {DeveloperError} If there is no position attribute
937
+ * @private
938
+ */
939
+ static _obtainPrimitivePositionAttribute(primitive) {
940
+ //>>includeStart('debug', pragmas.debug);
941
+ Check.defined("primitive", primitive);
942
+ //>>includeEnd('debug');
943
+
944
+ const primitivePositionAttribute = ModelUtility.getAttributeBySemantic(
945
+ primitive,
946
+ "POSITION",
947
+ );
948
+ if (!defined(primitivePositionAttribute)) {
949
+ throw new DeveloperError(
950
+ "The primitive does not have a POSITION attribute",
951
+ );
952
+ }
953
+ return primitivePositionAttribute;
954
+ }
955
+
956
+ /**
957
+ * Returns the ellipsoid of the given imagery layer.
958
+ *
959
+ * This only exists to hide a train wreck
960
+ *
961
+ * @param {ImageryLayer} imageryLayer The imagery layer
962
+ * @returns {Ellipsoid} The ellipsoid
963
+ * @private
964
+ */
965
+ static _getEllipsoid(imageryLayer) {
966
+ const ellipsoid =
967
+ imageryLayer.imageryProvider.tilingScheme.projection.ellipsoid;
968
+ return ellipsoid;
969
+ }
970
+ }
971
+
972
+ export default ModelPrimitiveImagery;