easy-three-utils 0.0.1

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 (166) hide show
  1. package/package.json +12 -0
  2. package/src/common/index.ts +24 -0
  3. package/src/common/useLine2.ts +87 -0
  4. package/src/common/useLoader.ts +184 -0
  5. package/src/common/useLocationCalculator.ts +145 -0
  6. package/src/common/useMark.ts +42 -0
  7. package/src/common/useTween.ts +86 -0
  8. package/src/core/basic/camera.ts +28 -0
  9. package/src/core/basic/clock.ts +11 -0
  10. package/src/core/basic/control.ts +32 -0
  11. package/src/core/basic/index.ts +35 -0
  12. package/src/core/basic/labelRenderer.ts +26 -0
  13. package/src/core/basic/light.ts +63 -0
  14. package/src/core/basic/renderer.ts +37 -0
  15. package/src/core/basic/scene.ts +11 -0
  16. package/src/core/basic/stats.ts +16 -0
  17. package/src/core/event.ts +74 -0
  18. package/src/core/index.ts +11 -0
  19. package/src/core/main.ts +389 -0
  20. package/src/draco/README.md +32 -0
  21. package/src/draco/draco_decoder.js +34 -0
  22. package/src/draco/draco_decoder.wasm +0 -0
  23. package/src/draco/draco_encoder.js +33 -0
  24. package/src/draco/draco_wasm_wrapper.js +117 -0
  25. package/src/draco/gltf/draco_decoder.js +33 -0
  26. package/src/draco/gltf/draco_decoder.wasm +0 -0
  27. package/src/draco/gltf/draco_encoder.js +33 -0
  28. package/src/draco/gltf/draco_wasm_wrapper.js +116 -0
  29. package/src/tileRenderer/base/Tile.d.ts +50 -0
  30. package/src/tileRenderer/base/TileBase.d.ts +76 -0
  31. package/src/tileRenderer/base/TileInternal.d.ts +36 -0
  32. package/src/tileRenderer/base/TilesRendererBase.d.ts +35 -0
  33. package/src/tileRenderer/base/TilesRendererBase.js +847 -0
  34. package/src/tileRenderer/base/Tileset.d.ts +66 -0
  35. package/src/tileRenderer/base/constants.d.ts +6 -0
  36. package/src/tileRenderer/base/constants.js +16 -0
  37. package/src/tileRenderer/base/loaders/B3DMLoaderBase.d.ts +18 -0
  38. package/src/tileRenderer/base/loaders/B3DMLoaderBase.js +85 -0
  39. package/src/tileRenderer/base/loaders/CMPTLoaderBase.d.ts +22 -0
  40. package/src/tileRenderer/base/loaders/CMPTLoaderBase.js +61 -0
  41. package/src/tileRenderer/base/loaders/I3DMLoaderBase.d.ts +21 -0
  42. package/src/tileRenderer/base/loaders/I3DMLoaderBase.js +130 -0
  43. package/src/tileRenderer/base/loaders/LoaderBase.d.ts +10 -0
  44. package/src/tileRenderer/base/loaders/LoaderBase.js +73 -0
  45. package/src/tileRenderer/base/loaders/PNTSLoaderBase.d.ts +17 -0
  46. package/src/tileRenderer/base/loaders/PNTSLoaderBase.js +82 -0
  47. package/src/tileRenderer/base/plugins/ImplicitTilingPlugin.js +12 -0
  48. package/src/tileRenderer/base/traverseFunctions.js +468 -0
  49. package/src/tileRenderer/gltf.js +144 -0
  50. package/src/tileRenderer/index.d.ts +41 -0
  51. package/src/tileRenderer/index.js +44 -0
  52. package/src/tileRenderer/plugins/README.md +578 -0
  53. package/src/tileRenderer/plugins/base/ImplicitTilingPlugin.d.ts +2 -0
  54. package/src/tileRenderer/plugins/base/ImplicitTilingPlugin.js +84 -0
  55. package/src/tileRenderer/plugins/base/SUBTREELoader.js +876 -0
  56. package/src/tileRenderer/plugins/index.d.ts +17 -0
  57. package/src/tileRenderer/plugins/index.js +17 -0
  58. package/src/tileRenderer/plugins/three/CesiumIonAuthPlugin.d.ts +9 -0
  59. package/src/tileRenderer/plugins/three/CesiumIonAuthPlugin.js +175 -0
  60. package/src/tileRenderer/plugins/three/DebugTilesPlugin.d.ts +29 -0
  61. package/src/tileRenderer/plugins/three/DebugTilesPlugin.js +677 -0
  62. package/src/tileRenderer/plugins/three/GLTFExtensionsPlugin.d.ts +18 -0
  63. package/src/tileRenderer/plugins/three/GLTFExtensionsPlugin.js +86 -0
  64. package/src/tileRenderer/plugins/three/GoogleAttributionsManager.js +62 -0
  65. package/src/tileRenderer/plugins/three/GoogleCloudAuthPlugin.d.ts +5 -0
  66. package/src/tileRenderer/plugins/three/GoogleCloudAuthPlugin.js +200 -0
  67. package/src/tileRenderer/plugins/three/ReorientationPlugin.d.ts +12 -0
  68. package/src/tileRenderer/plugins/three/ReorientationPlugin.js +136 -0
  69. package/src/tileRenderer/plugins/three/TileCompressionPlugin.d.ts +18 -0
  70. package/src/tileRenderer/plugins/three/TileCompressionPlugin.js +223 -0
  71. package/src/tileRenderer/plugins/three/UpdateOnChangePlugin.d.ts +5 -0
  72. package/src/tileRenderer/plugins/three/UpdateOnChangePlugin.js +87 -0
  73. package/src/tileRenderer/plugins/three/fade/FadeManager.js +370 -0
  74. package/src/tileRenderer/plugins/three/fade/TilesFadePlugin.d.ts +9 -0
  75. package/src/tileRenderer/plugins/three/fade/TilesFadePlugin.js +318 -0
  76. package/src/tileRenderer/plugins/three/gltf/GLTFCesiumRTCExtension.d.ts +5 -0
  77. package/src/tileRenderer/plugins/three/gltf/GLTFCesiumRTCExtension.js +27 -0
  78. package/src/tileRenderer/plugins/three/gltf/GLTFMeshFeaturesExtension.d.ts +30 -0
  79. package/src/tileRenderer/plugins/three/gltf/GLTFMeshFeaturesExtension.js +76 -0
  80. package/src/tileRenderer/plugins/three/gltf/GLTFStructuralMetadataExtension.d.ts +49 -0
  81. package/src/tileRenderer/plugins/three/gltf/GLTFStructuralMetadataExtension.js +147 -0
  82. package/src/tileRenderer/plugins/three/gltf/metadata/classes/ClassProperty.js +149 -0
  83. package/src/tileRenderer/plugins/three/gltf/metadata/classes/MeshFeatures.js +215 -0
  84. package/src/tileRenderer/plugins/three/gltf/metadata/classes/PropertyAttributeAccessor.js +107 -0
  85. package/src/tileRenderer/plugins/three/gltf/metadata/classes/PropertySetAccessor.js +45 -0
  86. package/src/tileRenderer/plugins/three/gltf/metadata/classes/PropertyTableAccessor.js +209 -0
  87. package/src/tileRenderer/plugins/three/gltf/metadata/classes/PropertyTextureAccessor.js +244 -0
  88. package/src/tileRenderer/plugins/three/gltf/metadata/classes/StructuralMetadata.js +202 -0
  89. package/src/tileRenderer/plugins/three/gltf/metadata/math/Matrix2.js +55 -0
  90. package/src/tileRenderer/plugins/three/gltf/metadata/utilities/ClassPropertyHelpers.js +495 -0
  91. package/src/tileRenderer/plugins/three/gltf/metadata/utilities/TexCoordUtilities.js +72 -0
  92. package/src/tileRenderer/plugins/three/gltf/metadata/utilities/TextureReadUtility.js +154 -0
  93. package/src/tileRenderer/plugins/three/objects/EllipsoidRegionHelper.js +186 -0
  94. package/src/tileRenderer/plugins/three/objects/SphereHelper.js +55 -0
  95. package/src/tileRenderer/r3f/README.md +238 -0
  96. package/src/tileRenderer/r3f/components/CameraControls.jsx +132 -0
  97. package/src/tileRenderer/r3f/components/CameraTransition.jsx +177 -0
  98. package/src/tileRenderer/r3f/components/CanvasDOMOverlay.jsx +54 -0
  99. package/src/tileRenderer/r3f/components/CompassGizmo.jsx +260 -0
  100. package/src/tileRenderer/r3f/components/TilesAttributionOverlay.jsx +110 -0
  101. package/src/tileRenderer/r3f/components/TilesRenderer.jsx +239 -0
  102. package/src/tileRenderer/r3f/index.jsx +6 -0
  103. package/src/tileRenderer/r3f/utilities/useForceUpdate.jsx +8 -0
  104. package/src/tileRenderer/r3f/utilities/useObjectDep.jsx +59 -0
  105. package/src/tileRenderer/r3f/utilities/useOptions.jsx +143 -0
  106. package/src/tileRenderer/three/DebugTilesRenderer.d.ts +28 -0
  107. package/src/tileRenderer/three/DebugTilesRenderer.js +58 -0
  108. package/src/tileRenderer/three/TilesGroup.d.ts +9 -0
  109. package/src/tileRenderer/three/TilesGroup.js +91 -0
  110. package/src/tileRenderer/three/TilesRenderer.d.ts +37 -0
  111. package/src/tileRenderer/three/TilesRenderer.js +1049 -0
  112. package/src/tileRenderer/three/controls/CameraTransitionManager.js +305 -0
  113. package/src/tileRenderer/three/controls/EnvironmentControls.js +1295 -0
  114. package/src/tileRenderer/three/controls/GlobeControls.js +684 -0
  115. package/src/tileRenderer/three/controls/PivotPointMesh.js +104 -0
  116. package/src/tileRenderer/three/controls/PointerTracker.js +257 -0
  117. package/src/tileRenderer/three/controls/utils.js +113 -0
  118. package/src/tileRenderer/three/loaders/B3DMLoader.d.ts +26 -0
  119. package/src/tileRenderer/three/loaders/B3DMLoader.js +85 -0
  120. package/src/tileRenderer/three/loaders/CMPTLoader.d.ts +19 -0
  121. package/src/tileRenderer/three/loaders/CMPTLoader.js +97 -0
  122. package/src/tileRenderer/three/loaders/GLTFExtensionLoader.d.ts +11 -0
  123. package/src/tileRenderer/three/loaders/GLTFExtensionLoader.js +68 -0
  124. package/src/tileRenderer/three/loaders/I3DMLoader.d.ts +26 -0
  125. package/src/tileRenderer/three/loaders/I3DMLoader.js +256 -0
  126. package/src/tileRenderer/three/loaders/PNTSLoader.d.ts +25 -0
  127. package/src/tileRenderer/three/loaders/PNTSLoader.js +202 -0
  128. package/src/tileRenderer/three/loaders/gltf/GLTFCesiumRTCExtension.js +12 -0
  129. package/src/tileRenderer/three/loaders/gltf/GLTFMeshFeaturesExtension.js +12 -0
  130. package/src/tileRenderer/three/loaders/gltf/GLTFStructuralMetadataExtension.js +12 -0
  131. package/src/tileRenderer/three/math/Ellipsoid.d.ts +31 -0
  132. package/src/tileRenderer/three/math/Ellipsoid.js +337 -0
  133. package/src/tileRenderer/three/math/EllipsoidRegion.d.ts +23 -0
  134. package/src/tileRenderer/three/math/EllipsoidRegion.js +178 -0
  135. package/src/tileRenderer/three/math/ExtendedFrustum.js +65 -0
  136. package/src/tileRenderer/three/math/GeoConstants.d.ts +4 -0
  137. package/src/tileRenderer/three/math/GeoConstants.js +5 -0
  138. package/src/tileRenderer/three/math/GeoUtils.d.ts +9 -0
  139. package/src/tileRenderer/three/math/GeoUtils.js +106 -0
  140. package/src/tileRenderer/three/math/OBB.js +179 -0
  141. package/src/tileRenderer/three/math/TileBoundingVolume.js +272 -0
  142. package/src/tileRenderer/three/plugins/CesiumIonAuthPlugin.js +12 -0
  143. package/src/tileRenderer/three/plugins/DebugTilesPlugin.js +26 -0
  144. package/src/tileRenderer/three/plugins/GoogleCloudAuthPlugin.js +12 -0
  145. package/src/tileRenderer/three/raycastTraverse.js +178 -0
  146. package/src/tileRenderer/three/renderers/CesiumIonTilesRenderer.d.ts +14 -0
  147. package/src/tileRenderer/three/renderers/CesiumIonTilesRenderer.js +21 -0
  148. package/src/tileRenderer/three/renderers/GoogleTilesRenderer.d.ts +43 -0
  149. package/src/tileRenderer/three/renderers/GoogleTilesRenderer.js +48 -0
  150. package/src/tileRenderer/three/utilities.js +54 -0
  151. package/src/tileRenderer/utilities/BatchTable.d.ts +24 -0
  152. package/src/tileRenderer/utilities/BatchTable.js +82 -0
  153. package/src/tileRenderer/utilities/BatchTableHierarchyExtension.js +127 -0
  154. package/src/tileRenderer/utilities/FeatureTable.d.ts +30 -0
  155. package/src/tileRenderer/utilities/FeatureTable.js +159 -0
  156. package/src/tileRenderer/utilities/LRUCache.d.ts +8 -0
  157. package/src/tileRenderer/utilities/LRUCache.js +385 -0
  158. package/src/tileRenderer/utilities/PriorityQueue.d.ts +16 -0
  159. package/src/tileRenderer/utilities/PriorityQueue.js +137 -0
  160. package/src/tileRenderer/utilities/arrayToString.js +7 -0
  161. package/src/tileRenderer/utilities/readMagicBytes.js +29 -0
  162. package/src/tileRenderer/utilities/rgb565torgb.js +22 -0
  163. package/src/tileRenderer/utilities/urlExtension.js +34 -0
  164. package/tsconfig.json +42 -0
  165. package/tsconfig.node.json +11 -0
  166. package/typings/three.d.ts +27 -0
@@ -0,0 +1,876 @@
1
+ /**
2
+ * Structure almost identical to Cesium, also the comments and the names are kept
3
+ * https://github.com/CesiumGS/cesium/blob/0a69f67b393ba194eefb7254600811c4b712ddc0/packages/engine/Source/Scene/Implicit3DTileContent.js
4
+ */
5
+ import { LoaderBase } from '../../base/loaders/LoaderBase.js';
6
+ import { readMagicBytes } from '../../utilities/readMagicBytes.js';
7
+ import { arrayToString } from '../../utilities/arrayToString.js';
8
+
9
+
10
+
11
+ function isOctreeSubdivision( tile ) {
12
+
13
+ return tile.__implicitRoot.implicitTiling.subdivisionScheme === 'OCTREE';
14
+
15
+ }
16
+
17
+ function getBoundsDivider( tile ) {
18
+
19
+ return isOctreeSubdivision( tile ) ? 8 : 4;
20
+
21
+ }
22
+
23
+
24
+ function getSubtreeCoordinates( tile, parentTile ) {
25
+
26
+ if ( ! parentTile ) {
27
+
28
+ return [ 0, 0, 0 ];
29
+
30
+ }
31
+
32
+ const x = 2 * parentTile.__x + ( tile.__subtreeIdx % 2 );
33
+ const y = 2 * parentTile.__y + ( Math.floor( tile.__subtreeIdx / 2 ) % 2 );
34
+ const z = isOctreeSubdivision( tile ) ?
35
+ 2 * parentTile.__z + ( Math.floor( tile.__subtreeIdx / 4 ) % 2 ) : 0;
36
+
37
+ return [ x, y, z ];
38
+
39
+ }
40
+
41
+ class SubtreeTile {
42
+
43
+ constructor( parentTile, childMortonIndex ) {
44
+
45
+ this.parent = parentTile;
46
+ this.children = [];
47
+ this.__level = parentTile.__level + 1;
48
+ this.__implicitRoot = parentTile.__implicitRoot;
49
+
50
+ // Index inside the tree
51
+ this.__subtreeIdx = childMortonIndex;
52
+ [ this.__x, this.__y, this.__z ] = getSubtreeCoordinates( this, parentTile );
53
+
54
+ }
55
+
56
+ static copy( tile ) {
57
+
58
+ const copyTile = {};
59
+ copyTile.children = [];
60
+ copyTile.__level = tile.__level;
61
+ copyTile.__implicitRoot = tile.__implicitRoot;
62
+
63
+ // Index inside the tree
64
+ copyTile.__subtreeIdx = tile.__subtreeIdx;
65
+ [ copyTile.__x, copyTile.__y, copyTile.__z ] = [ tile.__x, tile.__y, tile.__z ];
66
+
67
+ copyTile.boundingVolume = tile.boundingVolume;
68
+ copyTile.geometricError = tile.geometricError;
69
+ return copyTile;
70
+
71
+ }
72
+
73
+ }
74
+
75
+ export class SUBTREELoader extends LoaderBase {
76
+
77
+ constructor( tile ) {
78
+
79
+ super();
80
+ this.tile = tile;
81
+ this.rootTile = tile.__implicitRoot; // The implicit root tile
82
+
83
+ }
84
+
85
+ /**
86
+ * A helper object for storing the two parts of the subtree binary
87
+ *
88
+ * @typedef {object} Subtree
89
+ * @property {number} version
90
+ * @property {JSON} subtreeJson
91
+ * @property {ArrayBuffer} subtreeByte
92
+ * @private
93
+ */
94
+
95
+ /**
96
+ *
97
+ * @param buffer
98
+ * @return {Subtree}
99
+ */
100
+
101
+ parseBuffer( buffer ) {
102
+
103
+ const dataView = new DataView( buffer );
104
+ let offset = 0;
105
+
106
+ // 16-byte header
107
+
108
+ // 4 bytes
109
+ const magic = readMagicBytes( dataView );
110
+ console.assert( magic === 'subt', 'SUBTREELoader: The magic bytes equal "subt".' );
111
+ offset += 4;
112
+
113
+ // 4 bytes
114
+ const version = dataView.getUint32( offset, true );
115
+ console.assert( version === 1, 'SUBTREELoader: The version listed in the header is "1".' );
116
+ offset += 4;
117
+
118
+ // From Cesium
119
+ // Read the bottom 32 bits of the 64-bit byte length.
120
+ // This is ok for now because:
121
+ // 1) not all browsers have native 64-bit operations
122
+ // 2) the data is well under 4GB
123
+
124
+ // 8 bytes
125
+ const jsonLength = dataView.getUint32( offset, true );
126
+ offset += 8;
127
+
128
+ // 8 bytes
129
+ const byteLength = dataView.getUint32( offset, true );
130
+ offset += 8;
131
+
132
+ const subtreeJson = JSON.parse( arrayToString( new Uint8Array( buffer, offset, jsonLength ) ) );
133
+ offset += jsonLength;
134
+
135
+ const subtreeByte = buffer.slice( offset, offset + byteLength );
136
+
137
+ return {
138
+ version,
139
+ subtreeJson,
140
+ subtreeByte
141
+ };
142
+
143
+ }
144
+
145
+
146
+ parse( buffer ) {
147
+
148
+ // todo here : handle json
149
+ const subtree = this.parseBuffer( buffer );
150
+ const subtreeJson = subtree.subtreeJson;
151
+
152
+ // TODO Handle metadata
153
+ /*
154
+ const subtreeMetadata = subtreeJson.subtreeMetadata;
155
+ subtree._metadata = subtreeMetadata;
156
+ */
157
+
158
+
159
+ /*
160
+ Tile availability indicates which tiles exist within the subtree
161
+
162
+ Content availability indicates which tiles have associated content resources
163
+
164
+ Child subtree availability indicates what subtrees are reachable from this subtree
165
+
166
+ */
167
+
168
+
169
+ // After identifying how availability is stored, put the results in this new array for consistent processing later
170
+ subtreeJson.contentAvailabilityHeaders = [].concat( subtreeJson.contentAvailability );
171
+
172
+ const bufferHeaders = this.preprocessBuffers( subtreeJson.buffers );
173
+ const bufferViewHeaders = this.preprocessBufferViews(
174
+ subtreeJson.bufferViews,
175
+ bufferHeaders
176
+ );
177
+
178
+ // Buffers and buffer views are inactive until explicitly marked active.
179
+ // This way we can avoid fetching buffers that will not be used.
180
+ this.markActiveBufferViews( subtreeJson, bufferViewHeaders );
181
+
182
+ const buffersU8 = this.requestActiveBuffers(
183
+ bufferHeaders,
184
+ subtree.subtreeByte
185
+ );
186
+
187
+ const bufferViewsU8 = this.parseActiveBufferViews( bufferViewHeaders, buffersU8 );
188
+ this.parseAvailability( subtree, subtreeJson, bufferViewsU8 );
189
+ this.expandSubtree( this.tile, subtree );
190
+
191
+ }
192
+
193
+
194
+ /**
195
+ * Determine which buffer views need to be loaded into memory. This includes:
196
+ *
197
+ * <ul>
198
+ * <li>The tile availability bitstream (if a bitstream is defined)</li>
199
+ * <li>The content availability bitstream(s) (if a bitstream is defined)</li>
200
+ * <li>The child subtree availability bitstream (if a bitstream is defined)</li>
201
+ * </ul>
202
+ *
203
+ * <p>
204
+ * This function modifies the buffer view headers' isActive flags in place.
205
+ * </p>
206
+ *
207
+ * @param {JSON} subtreeJson The JSON chunk from the subtree
208
+ * @param {BufferViewHeader[]} bufferViewHeaders The preprocessed buffer view headers
209
+ * @private
210
+ */
211
+ markActiveBufferViews( subtreeJson, bufferViewHeaders ) {
212
+
213
+ let header;
214
+ const tileAvailabilityHeader = subtreeJson.tileAvailability;
215
+
216
+ // Check for bitstream first, which is part of the current schema.
217
+ // bufferView is the name of the bitstream from an older schema.
218
+ if ( ! isNaN( tileAvailabilityHeader.bitstream ) ) {
219
+
220
+ header = bufferViewHeaders[ tileAvailabilityHeader.bitstream ];
221
+
222
+ } else if ( ! isNaN( tileAvailabilityHeader.bufferView ) ) {
223
+
224
+ header = bufferViewHeaders[ tileAvailabilityHeader.bufferView ];
225
+
226
+ }
227
+
228
+ if ( header ) {
229
+
230
+ header.isActive = true;
231
+ header.bufferHeader.isActive = true;
232
+
233
+ }
234
+
235
+ const contentAvailabilityHeaders = subtreeJson.contentAvailabilityHeaders;
236
+ for ( let i = 0; i < contentAvailabilityHeaders.length; i ++ ) {
237
+
238
+ header = undefined;
239
+ if ( ! isNaN( contentAvailabilityHeaders[ i ].bitstream ) ) {
240
+
241
+ header = bufferViewHeaders[ contentAvailabilityHeaders[ i ].bitstream ];
242
+
243
+ } else if ( ! isNaN( contentAvailabilityHeaders[ i ].bufferView ) ) {
244
+
245
+ header = bufferViewHeaders[ contentAvailabilityHeaders[ i ].bufferView ];
246
+
247
+ }
248
+ if ( header ) {
249
+
250
+ header.isActive = true;
251
+ header.bufferHeader.isActive = true;
252
+
253
+ }
254
+
255
+ }
256
+ header = undefined;
257
+ const childSubtreeAvailabilityHeader = subtreeJson.childSubtreeAvailability;
258
+ if ( ! isNaN( childSubtreeAvailabilityHeader.bitstream ) ) {
259
+
260
+ header = bufferViewHeaders[ childSubtreeAvailabilityHeader.bitstream ];
261
+
262
+ } else if ( ! isNaN( childSubtreeAvailabilityHeader.bufferView ) ) {
263
+
264
+ header = bufferViewHeaders[ childSubtreeAvailabilityHeader.bufferView ];
265
+
266
+ }
267
+ if ( header ) {
268
+
269
+ header.isActive = true;
270
+ header.bufferHeader.isActive = true;
271
+
272
+ }
273
+
274
+ }
275
+
276
+
277
+ /**
278
+ * Go through the list of buffers and gather all the active ones into
279
+ * a dictionary.
280
+ * <p>
281
+ * The results are put into a dictionary object. The keys are indices of
282
+ * buffers, and the values are Uint8Arrays of the contents. Only buffers
283
+ * marked with the isActive flag are fetched.
284
+ * </p>
285
+ * <p>
286
+ * The internal buffer (the subtree's binary chunk) is also stored in this
287
+ * dictionary if it is marked active.
288
+ * </p>
289
+ * @param {BufferHeader[]} bufferHeaders The preprocessed buffer headers
290
+ * @param {ArrayBuffer} internalBuffer The binary chunk of the subtree file
291
+ * @returns {object} buffersU8 A dictionary of buffer index to a Uint8Array of its contents.
292
+ * @private
293
+ */
294
+ requestActiveBuffers( bufferHeaders, internalBuffer ) {
295
+
296
+ const bufferResults = [];
297
+ for ( let i = 0; i < bufferHeaders.length; i ++ ) {
298
+
299
+ const bufferHeader = bufferHeaders[ i ];
300
+ if ( bufferHeader.isActive ) {
301
+
302
+ bufferResults.push( internalBuffer );
303
+
304
+ } else {
305
+
306
+ bufferResults.push( undefined );
307
+
308
+ }
309
+
310
+ }
311
+
312
+ const buffersU8 = {};
313
+ for ( let i = 0; i < bufferResults.length; i ++ ) {
314
+
315
+ const result = bufferResults[ i ];
316
+ if ( result ) {
317
+
318
+ buffersU8[ i ] = result;
319
+
320
+ }
321
+
322
+ }
323
+ return buffersU8;
324
+
325
+ }
326
+
327
+ /**
328
+ * Go through the list of buffer views, and if they are marked as active,
329
+ * extract a subarray from one of the active buffers.
330
+ *
331
+ * @param {BufferViewHeader[]} bufferViewHeaders
332
+ * @param {object} buffersU8 A dictionary of buffer index to a Uint8Array of its contents.
333
+ * @returns {object} A dictionary of buffer view index to a Uint8Array of its contents.
334
+ * @private
335
+ */
336
+ parseActiveBufferViews( bufferViewHeaders, buffersU8 ) {
337
+
338
+ const bufferViewsU8 = {};
339
+ for ( let i = 0; i < bufferViewHeaders.length; i ++ ) {
340
+
341
+ const bufferViewHeader = bufferViewHeaders[ i ];
342
+ if ( ! bufferViewHeader.isActive ) {
343
+
344
+ continue;
345
+
346
+ }
347
+ const start = bufferViewHeader.byteOffset;
348
+ const end = start + bufferViewHeader.byteLength;
349
+ const buffer = buffersU8[ bufferViewHeader.buffer ];
350
+ bufferViewsU8[ i ] = buffer.slice( start, end );
351
+
352
+ }
353
+ return bufferViewsU8;
354
+
355
+ }
356
+
357
+ /**
358
+ * A buffer header is the JSON header from the subtree JSON chunk plus
359
+ * a couple extra boolean flags for easy reference.
360
+ *
361
+ * Buffers are assumed inactive until explicitly marked active. This is used
362
+ * to avoid fetching unneeded buffers.
363
+ *
364
+ * @typedef {object} BufferHeader
365
+ * @property {boolean} isActive Whether this buffer is currently used.
366
+ * @property {string} [uri] The URI of the buffer (external buffers only)
367
+ * @property {number} byteLength The byte length of the buffer, including any padding contained within.
368
+ * @private
369
+ */
370
+
371
+ /**
372
+ * Iterate over the list of buffers from the subtree JSON and add the isActive field for easier parsing later.
373
+ * This modifies the objects in place.
374
+ * @param {Object[]} [bufferHeaders=[]] The JSON from subtreeJson.buffers.
375
+ * @returns {BufferHeader[]} The same array of headers with additional fields.
376
+ * @private
377
+ */
378
+ preprocessBuffers( bufferHeaders = [] ) {
379
+
380
+ for ( let i = 0; i < bufferHeaders.length; i ++ ) {
381
+
382
+ const bufferHeader = bufferHeaders[ i ];
383
+ bufferHeader.isActive = false;
384
+
385
+ }
386
+ return bufferHeaders;
387
+
388
+ }
389
+
390
+
391
+ /**
392
+ * A buffer header is the JSON header from the subtree JSON chunk plus
393
+ * the isActive flag and a reference to the header for the underlying buffer
394
+ *
395
+ * @typedef {object} BufferViewHeader
396
+ * @property {BufferHeader} bufferHeader A reference to the header for the underlying buffer
397
+ * @property {boolean} isActive Whether this bufferView is currently used.
398
+ * @property {number} buffer The index of the underlying buffer.
399
+ * @property {number} byteOffset The start byte of the bufferView within the buffer.
400
+ * @property {number} byteLength The length of the bufferView. No padding is included in this length.
401
+ * @private
402
+ */
403
+
404
+ /**
405
+ * Iterate the list of buffer views from the subtree JSON and add the
406
+ * isActive flag. Also save a reference to the bufferHeader
407
+ *
408
+ * @param {Object[]} [bufferViewHeaders=[]] The JSON from subtree.bufferViews
409
+ * @param {BufferHeader[]} bufferHeaders The preprocessed buffer headers
410
+ * @returns {BufferViewHeader[]} The same array of bufferView headers with additional fields
411
+ * @private
412
+ */
413
+ preprocessBufferViews( bufferViewHeaders = [], bufferHeaders ) {
414
+
415
+ for ( let i = 0; i < bufferViewHeaders.length; i ++ ) {
416
+
417
+ const bufferViewHeader = bufferViewHeaders[ i ];
418
+ bufferViewHeader.bufferHeader = bufferHeaders[ bufferViewHeader.buffer ];
419
+ bufferViewHeader.isActive = false;
420
+
421
+ }
422
+ return bufferViewHeaders;
423
+
424
+ }
425
+
426
+
427
+ /**
428
+ * Parse the three availability bitstreams and store them in the subtree
429
+ *
430
+ * @param {Subtree} subtree The subtree to modify
431
+ * @param {Object} subtreeJson The subtree JSON
432
+ * @param {Object} bufferViewsU8 A dictionary of buffer view index to a Uint8Array of its contents.
433
+ * @private
434
+ */
435
+ parseAvailability(
436
+ subtree,
437
+ subtreeJson,
438
+ bufferViewsU8
439
+ ) {
440
+
441
+ const branchingFactor = getBoundsDivider( this.rootTile );
442
+ const subtreeLevels = this.rootTile.implicitTiling.subtreeLevels;
443
+ const tileAvailabilityBits =
444
+ ( Math.pow( branchingFactor, subtreeLevels ) - 1 ) / ( branchingFactor - 1 );
445
+ const childSubtreeBits = Math.pow( branchingFactor, subtreeLevels );
446
+
447
+ subtree._tileAvailability = this.parseAvailabilityBitstream(
448
+ subtreeJson.tileAvailability,
449
+ bufferViewsU8,
450
+ tileAvailabilityBits
451
+ );
452
+
453
+ subtree._contentAvailabilityBitstreams = [];
454
+ for ( let i = 0; i < subtreeJson.contentAvailabilityHeaders.length; i ++ ) {
455
+
456
+ const bitstream = this.parseAvailabilityBitstream(
457
+ subtreeJson.contentAvailabilityHeaders[ i ],
458
+ bufferViewsU8,
459
+ // content availability has the same length as tile availability.
460
+ tileAvailabilityBits
461
+ );
462
+ subtree._contentAvailabilityBitstreams.push( bitstream );
463
+
464
+ }
465
+
466
+ subtree._childSubtreeAvailability = this.parseAvailabilityBitstream(
467
+ subtreeJson.childSubtreeAvailability,
468
+ bufferViewsU8,
469
+ childSubtreeBits
470
+ );
471
+
472
+ }
473
+
474
+ /**
475
+ * A helper object for storing the two parts of the subtree binary
476
+ *
477
+ * @typedef {object} ParsedBitstream
478
+ * @property {Boolean} constant
479
+ * @property {ArrayBuffer} bitstream
480
+ * @property {number} lengthBits The length of the availability bitstream in bits
481
+ * @private
482
+ */
483
+
484
+
485
+ /**
486
+ * Given the JSON describing an availability bitstream, turn it into an
487
+ * in-memory representation using an object. This handles bitstreams from a bufferView.
488
+ *
489
+ * @param {Object} availabilityJson A JSON object representing the availability
490
+ * @param {Object} bufferViewsU8 A dictionary of bufferView index to its Uint8Array contents.
491
+ * @param {number} lengthBits The length of the availability bitstream in bits
492
+ * @returns {ParsedBitstream}
493
+ * @private
494
+ */
495
+ parseAvailabilityBitstream(
496
+ availabilityJson,
497
+ bufferViewsU8,
498
+ lengthBits,
499
+ ) {
500
+
501
+ if ( ! isNaN( availabilityJson.constant ) ) {
502
+
503
+ return {
504
+ constant: Boolean( availabilityJson.constant ),
505
+ lengthBits: lengthBits,
506
+ };
507
+
508
+ }
509
+ let bufferView;
510
+ // Check for bitstream first, which is part of the current schema.
511
+ // bufferView is the name of the bitstream from an older schema.
512
+
513
+ if ( ! isNaN( availabilityJson.bitstream ) ) {
514
+
515
+ bufferView = bufferViewsU8[ availabilityJson.bitstream ];
516
+
517
+ } else if ( ! isNaN( availabilityJson.bufferView ) ) {
518
+
519
+ bufferView = bufferViewsU8[ availabilityJson.bufferView ];
520
+
521
+ }
522
+ return {
523
+ bitstream: bufferView,
524
+ lengthBits: lengthBits
525
+ };
526
+
527
+ }
528
+
529
+
530
+ /**
531
+ * Expand a single subtree tile. This transcodes the subtree into
532
+ * a tree of {@link SubtreeTile}. The root of this tree is stored in
533
+ * the placeholder tile's children array. This method also creates
534
+ * tiles for the child subtrees to be lazily expanded as needed.
535
+ *
536
+ * @param {Object | SubtreeTile} subtreeRoot The first node of the subtree
537
+ * @param {Subtree} subtree The parsed subtree
538
+ * @private
539
+ */
540
+ expandSubtree( subtreeRoot, subtree ) {
541
+
542
+ // TODO If multiple contents were supported then this tile could contain both renderable and un renderable content.
543
+ const contentTile = SubtreeTile.copy( subtreeRoot );
544
+
545
+ // If the subtree root tile has content, then create a placeholder child with cloned parameters
546
+ // Todo Multiple contents not handled, keep the first content found
547
+ for ( let i = 0; subtree && i < subtree._contentAvailabilityBitstreams.length; i ++ ) {
548
+
549
+ if ( subtree && this.getBit( subtree._contentAvailabilityBitstreams[ i ], 0 ) ) {
550
+
551
+ // Create a child holding the content uri, this child is similar to its parent and doesn't have any children
552
+ contentTile.content = { uri: this.parseImplicitURI( subtreeRoot, this.rootTile.content.uri ) };
553
+ break;
554
+
555
+ }
556
+
557
+ }
558
+
559
+ subtreeRoot.children.push( contentTile );
560
+
561
+ // Creating each leaf inside the current subtree
562
+ const bottomRow = this.transcodeSubtreeTiles(
563
+ contentTile,
564
+ subtree
565
+ );
566
+
567
+ // For each child subtree, create a tile containing the uri of the next subtree to fetch
568
+ const childSubtrees = this.listChildSubtrees( subtree, bottomRow );
569
+ for ( let i = 0; i < childSubtrees.length; i ++ ) {
570
+
571
+ const subtreeLocator = childSubtrees[ i ];
572
+ const leafTile = subtreeLocator.tile;
573
+ const subtreeTile = this.deriveChildTile(
574
+ null,
575
+ leafTile,
576
+ null,
577
+ subtreeLocator.childMortonIndex
578
+ );
579
+ // Assign subtree uri as content
580
+ subtreeTile.content = { uri: this.parseImplicitURI( subtreeTile, this.rootTile.implicitTiling.subtrees.uri ) };
581
+ leafTile.children.push( subtreeTile );
582
+
583
+ }
584
+
585
+ }
586
+
587
+ /**
588
+ * Transcode the implicitly defined tiles within this subtree and generate
589
+ * explicit {@link SubtreeTile} objects. This function only transcode tiles,
590
+ * child subtrees are handled separately.
591
+ *
592
+ * @param {Object | SubtreeTile} subtreeRoot The root of the current subtree
593
+ * @param {Subtree} subtree The subtree to get availability information
594
+ * @returns {Array} The bottom row of transcoded tiles. This is helpful for processing child subtrees
595
+ * @private
596
+ */
597
+ transcodeSubtreeTiles( subtreeRoot, subtree ) {
598
+
599
+ // Sliding window over the levels of the tree.
600
+ // Each row is branchingFactor * length of previous row
601
+ // Tiles within a row are ordered by Morton index.
602
+ let parentRow = [ subtreeRoot ];
603
+ let currentRow = [];
604
+
605
+ for ( let level = 1; level < this.rootTile.implicitTiling.subtreeLevels; level ++ ) {
606
+
607
+ const branchingFactor = getBoundsDivider( this.rootTile );
608
+ const levelOffset = ( Math.pow( branchingFactor, level ) - 1 ) / ( branchingFactor - 1 );
609
+ const numberOfChildren = branchingFactor * parentRow.length;
610
+ for (
611
+ let childMortonIndex = 0;
612
+ childMortonIndex < numberOfChildren;
613
+ childMortonIndex ++
614
+ ) {
615
+
616
+ const childBitIndex = levelOffset + childMortonIndex;
617
+ const parentMortonIndex = childMortonIndex >> Math.log2( branchingFactor );
618
+ const parentTile = parentRow[ parentMortonIndex ];
619
+
620
+ // Check if tile is available
621
+ if ( ! this.getBit( subtree._tileAvailability, childBitIndex ) ) {
622
+
623
+ currentRow.push( undefined );
624
+ continue;
625
+
626
+ }
627
+
628
+ // Create a tile and add it as a child
629
+ const childTile = this.deriveChildTile(
630
+ subtree,
631
+ parentTile,
632
+ childBitIndex,
633
+ childMortonIndex
634
+ );
635
+ parentTile.children.push( childTile );
636
+ currentRow.push( childTile );
637
+
638
+ }
639
+ parentRow = currentRow;
640
+ currentRow = [];
641
+
642
+ }
643
+ return parentRow;
644
+
645
+ }
646
+
647
+ /**
648
+ * Given a parent tile and information about which child to create, derive
649
+ * the properties of the child tile implicitly.
650
+ * <p>
651
+ * This creates a real tile for rendering.
652
+ * </p>
653
+ *
654
+ * @param {Subtree} subtree The subtree the child tile belongs to
655
+ * @param {Object | SubtreeTile} parentTile The parent of the new child tile
656
+ * @param {number} childBitIndex The index of the child tile within the tile's availability information.
657
+ * @param {number} childMortonIndex The morton index of the child tile relative to its parent
658
+ * @returns {SubtreeTile} The new child tile.
659
+ * @private
660
+ */
661
+ deriveChildTile(
662
+ subtree,
663
+ parentTile,
664
+ childBitIndex,
665
+ childMortonIndex
666
+ ) {
667
+
668
+ const subtreeTile = new SubtreeTile( parentTile, childMortonIndex );
669
+ subtreeTile.boundingVolume = this.getTileBoundingVolume( subtreeTile );
670
+ subtreeTile.geometricError = this.getGeometricError( subtreeTile );
671
+
672
+ // Todo Multiple contents not handled, keep the first found content
673
+ for ( let i = 0; subtree && i < subtree._contentAvailabilityBitstreams.length; i ++ ) {
674
+
675
+ if ( subtree && this.getBit( subtree._contentAvailabilityBitstreams[ i ], childBitIndex ) ) {
676
+
677
+ subtreeTile.content = { uri: this.parseImplicitURI( subtreeTile, this.rootTile.content.uri ) };
678
+ break;
679
+
680
+ }
681
+
682
+ }
683
+ return subtreeTile;
684
+
685
+ }
686
+
687
+
688
+ /**
689
+ * Get a bit from the bitstream as a Boolean. If the bitstream
690
+ * is a constant, the constant value is returned instead.
691
+ *
692
+ * @param {ParsedBitstream} object
693
+ * @param {number} index The integer index of the bit.
694
+ * @returns {boolean} The value of the bit
695
+ * @private
696
+ */
697
+ getBit( object, index ) {
698
+
699
+ if ( index < 0 || index >= object.lengthBits ) {
700
+
701
+ throw new Error( 'Bit index out of bounds.' );
702
+
703
+ }
704
+ if ( object.constant !== undefined ) {
705
+
706
+ return object.constant;
707
+
708
+ }
709
+ // byteIndex is floor(index / 8)
710
+ const byteIndex = index >> 3;
711
+ const bitIndex = index % 8;
712
+ return ( ( new Uint8Array( object.bitstream )[ byteIndex ] >> bitIndex ) & 1 ) === 1;
713
+
714
+ }
715
+
716
+ /**
717
+ * //TODO Adapt for Sphere
718
+ * To maintain numerical stability during this subdivision process,
719
+ * the actual bounding volumes should not be computed progressively by subdividing a non-root tile volume.
720
+ * Instead, the exact bounding volumes are computed directly for a given level.
721
+ * @param {Object | SubtreeTile} tile
722
+ * @return {Object} object containing the bounding volume
723
+ */
724
+ getTileBoundingVolume( tile ) {
725
+
726
+ const boundingVolume = {};
727
+ if ( this.rootTile.boundingVolume.region ) {
728
+
729
+ const region = [ ...this.rootTile.boundingVolume.region ];
730
+ const minX = region[ 0 ];
731
+ const maxX = region[ 2 ];
732
+ const minY = region[ 1 ];
733
+ const maxY = region[ 3 ];
734
+ const sizeX = ( maxX - minX ) / Math.pow( 2, tile.__level );
735
+ const sizeY = ( maxY - minY ) / Math.pow( 2, tile.__level );
736
+ region[ 0 ] = minX + sizeX * tile.__x; //west
737
+ region[ 2 ] = minX + sizeX * ( tile.__x + 1 ); //east
738
+ region[ 1 ] = minY + sizeY * tile.__y; //south
739
+ region[ 3 ] = minY + sizeY * ( tile.__y + 1 ); //north
740
+
741
+ for ( let k = 0; k < 4; k ++ ) {
742
+
743
+ const coord = region[ k ];
744
+ if ( coord < - Math.PI ) {
745
+
746
+ region[ k ] += 2 * Math.PI;
747
+
748
+ } else if ( coord > Math.PI ) {
749
+
750
+ region[ k ] -= 2 * Math.PI;
751
+
752
+ }
753
+
754
+ }
755
+
756
+ //Also divide the height in the case of octree.
757
+ if ( isOctreeSubdivision( tile ) ) {
758
+
759
+ const minZ = region[ 4 ];
760
+ const maxZ = region[ 5 ];
761
+
762
+ const sizeZ = ( maxZ - minZ ) / Math.pow( 2, tile.__level );
763
+
764
+ region[ 4 ] = minZ + sizeZ * tile.__z; //minimum height
765
+ region[ 5 ] = minZ + sizeZ * ( tile.__z + 1 ); // maximum height
766
+
767
+ }
768
+
769
+ boundingVolume.region = region;
770
+
771
+ }
772
+
773
+ if ( this.rootTile.boundingVolume.box ) {
774
+
775
+ // 0-2: center of the box
776
+ // 3-5: x axis direction and half length
777
+ // 6-8: y axis direction and half length
778
+ // 9-11: z axis direction and half length
779
+
780
+ const box = [ ...this.rootTile.boundingVolume.box ];
781
+ const cellSteps = 2 ** tile.__level - 1;
782
+ const scale = Math.pow( 2, - tile.__level );
783
+ const axisNumber = isOctreeSubdivision( tile ) ? 3 : 2;
784
+
785
+
786
+ for ( let i = 0; i < axisNumber; i ++ ) {
787
+
788
+ // scale the bounds axes
789
+ box[ 3 + i * 3 + 0 ] *= scale;
790
+ box[ 3 + i * 3 + 1 ] *= scale;
791
+ box[ 3 + i * 3 + 2 ] *= scale;
792
+
793
+ // axis vector
794
+ const x = box[ 3 + i * 3 + 0 ];
795
+ const y = box[ 3 + i * 3 + 1 ];
796
+ const z = box[ 3 + i * 3 + 2 ];
797
+
798
+ // adjust the center by the x, y and z axes
799
+ const axisOffset = i === 0 ? tile.__x : ( i === 1 ? tile.__y : tile.__z );
800
+ box[ 0 ] += 2 * x * ( - 0.5 * cellSteps + axisOffset );
801
+ box[ 1 ] += 2 * y * ( - 0.5 * cellSteps + axisOffset );
802
+ box[ 2 ] += 2 * z * ( - 0.5 * cellSteps + axisOffset );
803
+
804
+ }
805
+
806
+ boundingVolume.box = box;
807
+
808
+ }
809
+
810
+ return boundingVolume;
811
+
812
+ }
813
+
814
+ /**
815
+ * Each child’s geometricError is half of its parent’s geometricError
816
+ * @param {Object | SubtreeTile} tile
817
+ * @return {number}
818
+ */
819
+ getGeometricError( tile ) {
820
+
821
+ return this.rootTile.geometricError / Math.pow( 2, tile.__level );
822
+
823
+ }
824
+
825
+
826
+ /**
827
+ * Determine what child subtrees exist and return a list of information
828
+ *
829
+ * @param {Object} subtree The subtree for looking up availability
830
+ * @param {Array} bottomRow The bottom row of tiles in a transcoded subtree
831
+ * @returns {[]} A list of identifiers for the child subtrees.
832
+ * @private
833
+ */
834
+ listChildSubtrees( subtree, bottomRow ) {
835
+
836
+ const results = [];
837
+ const branchingFactor = getBoundsDivider( this.rootTile );
838
+ for ( let i = 0; i < bottomRow.length; i ++ ) {
839
+
840
+ const leafTile = bottomRow[ i ];
841
+ if ( leafTile === undefined ) {
842
+
843
+ continue;
844
+
845
+ }
846
+ for ( let j = 0; j < branchingFactor; j ++ ) {
847
+
848
+ const index = i * branchingFactor + j;
849
+ if ( this.getBit( subtree._childSubtreeAvailability, index ) ) {
850
+
851
+ results.push( {
852
+ tile: leafTile,
853
+ childMortonIndex: index
854
+ } );
855
+
856
+ }
857
+
858
+ }
859
+
860
+ }
861
+ return results;
862
+
863
+ }
864
+
865
+
866
+ parseImplicitURI( tile, uri ) {
867
+
868
+ uri = uri.replace( '{level}', tile.__level );
869
+ uri = uri.replace( '{x}', tile.__x );
870
+ uri = uri.replace( '{y}', tile.__y );
871
+ uri = uri.replace( '{z}', tile.__z );
872
+ return uri;
873
+
874
+ }
875
+
876
+ }