@loaders.gl/gltf 4.0.0-alpha.9 → 4.0.0-beta.2

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (152) hide show
  1. package/dist/dist.min.js +3777 -3105
  2. package/dist/es5/glb-loader.js +1 -3
  3. package/dist/es5/glb-loader.js.map +1 -1
  4. package/dist/es5/index.js +33 -0
  5. package/dist/es5/index.js.map +1 -1
  6. package/dist/es5/lib/api/gltf-extensions.js +3 -1
  7. package/dist/es5/lib/api/gltf-extensions.js.map +1 -1
  8. package/dist/es5/lib/extensions/EXT_mesh_features.js +99 -0
  9. package/dist/es5/lib/extensions/EXT_mesh_features.js.map +1 -0
  10. package/dist/es5/lib/extensions/EXT_meshopt_compression.js +2 -2
  11. package/dist/es5/lib/extensions/EXT_meshopt_compression.js.map +1 -1
  12. package/dist/es5/lib/extensions/EXT_structural_metadata.js +375 -0
  13. package/dist/es5/lib/extensions/EXT_structural_metadata.js.map +1 -0
  14. package/dist/es5/lib/extensions/KHR_draco_mesh_compression.js +6 -7
  15. package/dist/es5/lib/extensions/KHR_draco_mesh_compression.js.map +1 -1
  16. package/dist/es5/lib/extensions/KHR_texture_transform.js +2 -1
  17. package/dist/es5/lib/extensions/KHR_texture_transform.js.map +1 -1
  18. package/dist/es5/lib/extensions/deprecated/EXT_feature_metadata.js +162 -183
  19. package/dist/es5/lib/extensions/deprecated/EXT_feature_metadata.js.map +1 -1
  20. package/dist/es5/lib/extensions/utils/3d-tiles-utils.js +254 -0
  21. package/dist/es5/lib/extensions/utils/3d-tiles-utils.js.map +1 -0
  22. package/dist/es5/lib/gltf-utils/gltf-utils.js +29 -0
  23. package/dist/es5/lib/gltf-utils/gltf-utils.js.map +1 -1
  24. package/dist/es5/lib/parsers/parse-gltf.js +7 -4
  25. package/dist/es5/lib/parsers/parse-gltf.js.map +1 -1
  26. package/dist/es5/lib/types/gltf-ext-feature-metadata-schema.js +2 -0
  27. package/dist/es5/lib/types/gltf-ext-feature-metadata-schema.js.map +1 -0
  28. package/dist/es5/lib/types/gltf-ext-mesh-features-schema.js +2 -0
  29. package/dist/es5/lib/types/gltf-ext-mesh-features-schema.js.map +1 -0
  30. package/dist/es5/lib/types/gltf-ext-structural-metadata-schema.js +2 -0
  31. package/dist/es5/lib/types/gltf-ext-structural-metadata-schema.js.map +1 -0
  32. package/dist/es5/lib/types/gltf-json-schema.js.map +1 -1
  33. package/dist/es5/lib/types/gltf-types.js.map +1 -1
  34. package/dist/es5/lib/utils/version.js +1 -1
  35. package/dist/es5/lib/utils/version.js.map +1 -1
  36. package/dist/esm/glb-loader.js +0 -1
  37. package/dist/esm/glb-loader.js.map +1 -1
  38. package/dist/esm/index.js +5 -0
  39. package/dist/esm/index.js.map +1 -1
  40. package/dist/esm/lib/api/gltf-extensions.js +3 -1
  41. package/dist/esm/lib/api/gltf-extensions.js.map +1 -1
  42. package/dist/esm/lib/extensions/EXT_mesh_features.js +43 -0
  43. package/dist/esm/lib/extensions/EXT_mesh_features.js.map +1 -0
  44. package/dist/esm/lib/extensions/EXT_meshopt_compression.js +2 -2
  45. package/dist/esm/lib/extensions/EXT_meshopt_compression.js.map +1 -1
  46. package/dist/esm/lib/extensions/EXT_structural_metadata.js +302 -0
  47. package/dist/esm/lib/extensions/EXT_structural_metadata.js.map +1 -0
  48. package/dist/esm/lib/extensions/KHR_draco_mesh_compression.js +2 -5
  49. package/dist/esm/lib/extensions/KHR_draco_mesh_compression.js.map +1 -1
  50. package/dist/esm/lib/extensions/KHR_texture_transform.js +2 -1
  51. package/dist/esm/lib/extensions/KHR_texture_transform.js.map +1 -1
  52. package/dist/esm/lib/extensions/deprecated/EXT_feature_metadata.js +156 -167
  53. package/dist/esm/lib/extensions/deprecated/EXT_feature_metadata.js.map +1 -1
  54. package/dist/esm/lib/extensions/utils/3d-tiles-utils.js +215 -0
  55. package/dist/esm/lib/extensions/utils/3d-tiles-utils.js.map +1 -0
  56. package/dist/esm/lib/gltf-utils/gltf-utils.js +30 -0
  57. package/dist/esm/lib/gltf-utils/gltf-utils.js.map +1 -1
  58. package/dist/esm/lib/parsers/parse-gltf.js +6 -6
  59. package/dist/esm/lib/parsers/parse-gltf.js.map +1 -1
  60. package/dist/esm/lib/types/gltf-ext-feature-metadata-schema.js +2 -0
  61. package/dist/esm/lib/types/gltf-ext-feature-metadata-schema.js.map +1 -0
  62. package/dist/esm/lib/types/gltf-ext-mesh-features-schema.js +2 -0
  63. package/dist/esm/lib/types/gltf-ext-mesh-features-schema.js.map +1 -0
  64. package/dist/esm/lib/types/gltf-ext-structural-metadata-schema.js +2 -0
  65. package/dist/esm/lib/types/gltf-ext-structural-metadata-schema.js.map +1 -0
  66. package/dist/esm/lib/types/gltf-json-schema.js.map +1 -1
  67. package/dist/esm/lib/types/gltf-types.js.map +1 -1
  68. package/dist/esm/lib/utils/version.js +1 -1
  69. package/dist/esm/lib/utils/version.js.map +1 -1
  70. package/dist/glb-loader.d.ts +3 -1
  71. package/dist/glb-loader.d.ts.map +1 -1
  72. package/dist/index.d.ts +10 -2
  73. package/dist/index.d.ts.map +1 -1
  74. package/dist/lib/api/gltf-extensions.d.ts.map +1 -1
  75. package/dist/lib/extensions/EXT_mesh_features.d.ts +7 -0
  76. package/dist/lib/extensions/EXT_mesh_features.d.ts.map +1 -0
  77. package/dist/lib/extensions/EXT_structural_metadata.d.ts +16 -0
  78. package/dist/lib/extensions/EXT_structural_metadata.d.ts.map +1 -0
  79. package/dist/lib/extensions/KHR_draco_mesh_compression.d.ts +1 -1
  80. package/dist/lib/extensions/KHR_draco_mesh_compression.d.ts.map +1 -1
  81. package/dist/lib/extensions/deprecated/EXT_feature_metadata.d.ts +9 -0
  82. package/dist/lib/extensions/deprecated/EXT_feature_metadata.d.ts.map +1 -1
  83. package/dist/lib/extensions/utils/3d-tiles-utils.d.ts +82 -0
  84. package/dist/lib/extensions/utils/3d-tiles-utils.d.ts.map +1 -0
  85. package/dist/lib/gltf-utils/gltf-utils.d.ts +2 -0
  86. package/dist/lib/gltf-utils/gltf-utils.d.ts.map +1 -1
  87. package/dist/lib/parsers/parse-gltf.d.ts.map +1 -1
  88. package/dist/lib/types/gltf-ext-feature-metadata-schema.d.ts +421 -0
  89. package/dist/lib/types/gltf-ext-feature-metadata-schema.d.ts.map +1 -0
  90. package/dist/lib/types/gltf-ext-mesh-features-schema.d.ts +43 -0
  91. package/dist/lib/types/gltf-ext-mesh-features-schema.d.ts.map +1 -0
  92. package/dist/lib/types/gltf-ext-structural-metadata-schema.d.ts +329 -0
  93. package/dist/lib/types/gltf-ext-structural-metadata-schema.d.ts.map +1 -0
  94. package/dist/lib/types/gltf-json-schema.d.ts +12 -404
  95. package/dist/lib/types/gltf-json-schema.d.ts.map +1 -1
  96. package/dist/lib/types/gltf-types.d.ts +4 -1
  97. package/dist/lib/types/gltf-types.d.ts.map +1 -1
  98. package/package.json +6 -6
  99. package/src/glb-loader.ts +3 -3
  100. package/src/index.ts +37 -6
  101. package/src/lib/api/gltf-extensions.ts +6 -2
  102. package/src/lib/extensions/EXT_mesh_features.ts +91 -0
  103. package/src/lib/extensions/EXT_meshopt_compression.ts +1 -1
  104. package/src/lib/extensions/EXT_structural_metadata.ts +750 -0
  105. package/src/lib/extensions/KHR_draco_mesh_compression.ts +7 -7
  106. package/src/lib/extensions/KHR_texture_transform.ts +1 -1
  107. package/src/lib/extensions/deprecated/EXT_feature_metadata.ts +407 -281
  108. package/src/lib/extensions/utils/3d-tiles-utils.ts +430 -0
  109. package/src/lib/gltf-utils/gltf-utils.ts +38 -0
  110. package/src/lib/parsers/parse-gltf.ts +14 -6
  111. package/src/lib/types/gltf-ext-feature-metadata-schema.ts +470 -0
  112. package/src/lib/types/gltf-ext-mesh-features-schema.ts +46 -0
  113. package/src/lib/types/gltf-ext-structural-metadata-schema.ts +378 -0
  114. package/src/lib/types/gltf-json-schema.ts +26 -465
  115. package/src/lib/types/gltf-types.ts +5 -3
  116. package/dist/bundle.js +0 -5
  117. package/dist/glb-loader.js +0 -36
  118. package/dist/glb-writer.js +0 -35
  119. package/dist/gltf-loader.js +0 -50
  120. package/dist/gltf-writer.js +0 -32
  121. package/dist/index.js +0 -28
  122. package/dist/lib/api/gltf-extensions.js +0 -83
  123. package/dist/lib/api/gltf-scenegraph.js +0 -580
  124. package/dist/lib/api/normalize-gltf-v1.js +0 -299
  125. package/dist/lib/api/post-process-gltf.js +0 -433
  126. package/dist/lib/encoders/encode-glb.js +0 -72
  127. package/dist/lib/encoders/encode-gltf.js +0 -32
  128. package/dist/lib/extensions/EXT_meshopt_compression.js +0 -41
  129. package/dist/lib/extensions/EXT_texture_webp.js +0 -36
  130. package/dist/lib/extensions/KHR_binary_gltf.js +0 -39
  131. package/dist/lib/extensions/KHR_draco_mesh_compression.js +0 -138
  132. package/dist/lib/extensions/KHR_texture_basisu.js +0 -29
  133. package/dist/lib/extensions/KHR_texture_transform.js +0 -227
  134. package/dist/lib/extensions/deprecated/EXT_feature_metadata.js +0 -290
  135. package/dist/lib/extensions/deprecated/KHR_lights_punctual.js +0 -59
  136. package/dist/lib/extensions/deprecated/KHR_materials_unlit.js +0 -44
  137. package/dist/lib/extensions/deprecated/KHR_techniques_webgl.js +0 -79
  138. package/dist/lib/gltf-utils/get-typed-array.js +0 -41
  139. package/dist/lib/gltf-utils/gltf-attribute-utils.js +0 -73
  140. package/dist/lib/gltf-utils/gltf-constants.js +0 -43
  141. package/dist/lib/gltf-utils/gltf-utils.js +0 -90
  142. package/dist/lib/gltf-utils/resolve-url.js +0 -18
  143. package/dist/lib/parsers/parse-glb.js +0 -166
  144. package/dist/lib/parsers/parse-gltf.js +0 -179
  145. package/dist/lib/types/glb-types.js +0 -2
  146. package/dist/lib/types/gltf-json-schema.js +0 -4
  147. package/dist/lib/types/gltf-postprocessed-schema.js +0 -4
  148. package/dist/lib/types/gltf-types.js +0 -3
  149. package/dist/lib/utils/assert.js +0 -12
  150. package/dist/lib/utils/version.js +0 -7
  151. package/dist/meshopt/meshopt-decoder.js +0 -118
  152. package/dist/webp/webp.js +0 -38
@@ -0,0 +1,430 @@
1
+ /**
2
+ * loaders.gl, MIT license
3
+ *
4
+ * Shared code for 3DTiles extensions:
5
+ * * EXT_feature_metadata
6
+ * * EXT_mesh_features
7
+ * * EXT_structural_metadata
8
+ */
9
+
10
+ import type {GLTFTextureInfoMetadata, GLTFMeshPrimitive} from '../../types/gltf-json-schema';
11
+ import type {BigTypedArray, TypedArray} from '@loaders.gl/schema';
12
+ import type {ImageType} from '@loaders.gl/images';
13
+
14
+ import {GLTFScenegraph} from '../../api/gltf-scenegraph';
15
+ import {getComponentTypeFromArray, getFloat32ArrayForAccessor} from '../../gltf-utils/gltf-utils';
16
+ import {getImageData} from '@loaders.gl/images';
17
+ import {emod} from '@loaders.gl/math';
18
+
19
+ export type NumericComponentType =
20
+ | 'INT8'
21
+ | 'UINT8'
22
+ | 'INT16'
23
+ | 'UINT16'
24
+ | 'INT32'
25
+ | 'UINT32'
26
+ | 'INT64'
27
+ | 'UINT64'
28
+ | 'FLOAT32'
29
+ | 'FLOAT64';
30
+
31
+ const ATTRIBUTE_TYPE_TO_COMPONENTS = {
32
+ SCALAR: 1,
33
+ VEC2: 2,
34
+ VEC3: 3,
35
+ VEC4: 4,
36
+ MAT2: 4,
37
+ MAT3: 9,
38
+ MAT4: 16,
39
+ BOOLEAN: 1,
40
+ STRING: 1,
41
+ ENUM: 1
42
+ };
43
+
44
+ const ATTRIBUTE_COMPONENT_TYPE_TO_ARRAY = {
45
+ INT8: Int8Array,
46
+ UINT8: Uint8Array,
47
+ INT16: Int16Array,
48
+ UINT16: Uint16Array,
49
+ INT32: Int32Array,
50
+ UINT32: Uint32Array,
51
+ INT64: BigInt64Array,
52
+ UINT64: BigUint64Array,
53
+ FLOAT32: Float32Array,
54
+ FLOAT64: Float64Array
55
+ };
56
+
57
+ const ATTRIBUTE_COMPONENT_TYPE_TO_BYTE_SIZE = {
58
+ INT8: 1,
59
+ UINT8: 1,
60
+ INT16: 2,
61
+ UINT16: 2,
62
+ INT32: 4,
63
+ UINT32: 4,
64
+ INT64: 8,
65
+ UINT64: 8,
66
+ FLOAT32: 4,
67
+ FLOAT64: 8
68
+ };
69
+
70
+ export function getArrayElementByteSize(attributeType, componentType): number {
71
+ return (
72
+ ATTRIBUTE_COMPONENT_TYPE_TO_BYTE_SIZE[componentType] *
73
+ ATTRIBUTE_TYPE_TO_COMPONENTS[attributeType]
74
+ );
75
+ }
76
+
77
+ /**
78
+ * Gets offset array from `arrayOffsets` or `stringOffsets`.
79
+ * @param scenegraph - Instance of the class for structured access to GLTF data.
80
+ * @param bufferViewIndex - Buffer view index
81
+ * @param offsetType - The type of values in `arrayOffsets` or `stringOffsets`.
82
+ * @param numberOfElements - The number of elements in each property array.
83
+ * @returns Array of values offsets. The number of offsets in the array is equal to `numberOfElements` plus one.
84
+ */
85
+ export function getOffsetsForProperty(
86
+ scenegraph: GLTFScenegraph,
87
+ bufferViewIndex: number,
88
+ offsetType: 'UINT8' | 'UINT16' | 'UINT32' | 'UINT64' | string,
89
+ numberOfElements: number
90
+ ): TypedArray | null {
91
+ if (
92
+ offsetType !== 'UINT8' &&
93
+ offsetType !== 'UINT16' &&
94
+ offsetType !== 'UINT32' &&
95
+ offsetType !== 'UINT64'
96
+ ) {
97
+ return null;
98
+ }
99
+ const arrayOffsetsBytes = scenegraph.getTypedArrayForBufferView(bufferViewIndex);
100
+ const arrayOffsets = convertRawBufferToMetadataArray(
101
+ arrayOffsetsBytes,
102
+ 'SCALAR', // offsets consist of ONE component
103
+ offsetType,
104
+ numberOfElements + 1 // The number of offsets is equal to the property table `count` plus one.
105
+ );
106
+
107
+ // We don't support BigInt offsets at the moment. It requires additional logic and potential issues in Safari
108
+ if (arrayOffsets instanceof BigInt64Array || arrayOffsets instanceof BigUint64Array) {
109
+ return null;
110
+ }
111
+ return arrayOffsets;
112
+ }
113
+
114
+ /**
115
+ * Converts raw bytes that are in the buffer to an array of the type defined by the schema.
116
+ * @param data - Raw bytes in the buffer.
117
+ * @param attributeType - SCALAR, VECN, MATN.
118
+ * @param componentType - Type of the component in elements, e.g. 'UINT8' or 'FLOAT32'.
119
+ * @param elementCount - Number of elements in the array. Default value is 1.
120
+ * @returns Data array
121
+ */
122
+ export function convertRawBufferToMetadataArray(
123
+ data: Uint8Array,
124
+ attributeType: string,
125
+ componentType: NumericComponentType,
126
+ elementCount: number = 1
127
+ ): BigTypedArray {
128
+ const numberOfComponents = ATTRIBUTE_TYPE_TO_COMPONENTS[attributeType];
129
+ const ArrayType = ATTRIBUTE_COMPONENT_TYPE_TO_ARRAY[componentType];
130
+ const size = ATTRIBUTE_COMPONENT_TYPE_TO_BYTE_SIZE[componentType];
131
+ const length = elementCount * numberOfComponents;
132
+ const byteLength = length * size;
133
+ let buffer = data.buffer;
134
+ let offset = data.byteOffset;
135
+ if (offset % size !== 0) {
136
+ const bufferArray = new Uint8Array(buffer);
137
+ buffer = bufferArray.slice(offset, offset + byteLength).buffer;
138
+ offset = 0;
139
+ }
140
+ return new ArrayType(buffer, offset, length);
141
+ }
142
+
143
+ /**
144
+ * Processes data encoded in the texture associated with the primitive.
145
+ * @param scenegraph - Instance of the class for structured access to GLTF data.
146
+ * @param textureInfo - Reference to the texture where extension data are stored.
147
+ * @param primitive - Primitive object in the mesh.
148
+ * @returns Array of data taken. Null if data can't be taken from the texture.
149
+ */
150
+ export function getPrimitiveTextureData(
151
+ scenegraph: GLTFScenegraph,
152
+ textureInfo: GLTFTextureInfoMetadata,
153
+ primitive: GLTFMeshPrimitive
154
+ ): number[] | null {
155
+ /*
156
+ texture.index is an index for the "textures" array.
157
+ The texture object referenced by this index looks like this:
158
+ {
159
+ "sampler": 0,
160
+ "source": 0
161
+ }
162
+ "sampler" is an index for the "samplers" array
163
+ "source" is an index for the "images" array that contains data. These data are stored in rgba channels of the image.
164
+
165
+ texture.texCoord is a number-suffix (like 1) for an attribute like "TEXCOORD_1" in meshes.primitives
166
+ The value of "TEXCOORD_1" is an accessor that is used to get coordinates. These coordinates are being used to get data from the image.
167
+ */
168
+ const json = scenegraph.gltf.json;
169
+
170
+ const texCoordAccessorKey = `TEXCOORD_${textureInfo.texCoord || 0}`;
171
+ const texCoordAccessorIndex = primitive.attributes[texCoordAccessorKey];
172
+
173
+ const textureCoordinates: Float32Array | null = getFloat32ArrayForAccessor(
174
+ scenegraph.gltf,
175
+ texCoordAccessorIndex
176
+ );
177
+ if (!textureCoordinates) {
178
+ return null;
179
+ }
180
+
181
+ const textureIndex: number = textureInfo.index;
182
+ const imageIndex = json.textures?.[textureIndex]?.source;
183
+ if (typeof imageIndex !== 'undefined') {
184
+ const mimeType = json.images?.[imageIndex]?.mimeType;
185
+ const parsedImage = scenegraph.gltf.images?.[imageIndex];
186
+ // Checking for width is to prevent handling Un-processed images (e.g. [analyze] stage, where loadImages option is set to false)
187
+ if (parsedImage && typeof parsedImage.width !== 'undefined') {
188
+ const textureData: number[] = [];
189
+ for (let index = 0; index < textureCoordinates.length; index += 2) {
190
+ const value = getImageValueByCoordinates(
191
+ parsedImage,
192
+ mimeType,
193
+ textureCoordinates,
194
+ index,
195
+ textureInfo.channels
196
+ );
197
+ textureData.push(value);
198
+ }
199
+ return textureData;
200
+ }
201
+ }
202
+ return null;
203
+ }
204
+
205
+ /**
206
+ * Puts property data to attributes.
207
+ * It creates corresponding buffer, bufferView and accessor
208
+ * so the data can be accessed like regular data stored in buffers.
209
+ * @param scenegraph - Scenegraph object.
210
+ * @param attributeName - Name of the attribute.
211
+ * @param propertyData - Property data to store.
212
+ * @param featureTable - Array where unique data from the property data are being stored.
213
+ * @param primitive - Primitive object.
214
+ */
215
+ export function primitivePropertyDataToAttributes(
216
+ scenegraph: GLTFScenegraph,
217
+ attributeName: string,
218
+ propertyData: number[],
219
+ featureTable: number[],
220
+ primitive: GLTFMeshPrimitive
221
+ ): void {
222
+ // No reason to create an empty buffer if there is no property data to store.
223
+ if (!propertyData?.length) {
224
+ return;
225
+ }
226
+ /*
227
+ featureTable will contain unique values, e.g.
228
+ propertyData = [24, 35, 28, 24]
229
+ featureTable = [24, 35, 28]
230
+ featureIndices will contain indices that refer featureTextureTable, e.g.
231
+ featureIndices = [0, 1, 2, 0]
232
+ */
233
+ const featureIndices: number[] = [];
234
+ for (const texelData of propertyData) {
235
+ let index = featureTable.findIndex((item) => item === texelData);
236
+ if (index === -1) {
237
+ index = featureTable.push(texelData) - 1;
238
+ }
239
+ featureIndices.push(index);
240
+ }
241
+ const typedArray = new Uint32Array(featureIndices);
242
+ const bufferIndex =
243
+ scenegraph.gltf.buffers.push({
244
+ arrayBuffer: typedArray.buffer,
245
+ byteOffset: typedArray.byteOffset,
246
+ byteLength: typedArray.byteLength
247
+ }) - 1;
248
+ const bufferViewIndex = scenegraph.addBufferView(typedArray, bufferIndex, 0);
249
+ const accessorIndex = scenegraph.addAccessor(bufferViewIndex, {
250
+ size: 1,
251
+ componentType: getComponentTypeFromArray(typedArray),
252
+ count: typedArray.length
253
+ });
254
+ primitive.attributes[attributeName] = accessorIndex;
255
+ }
256
+
257
+ /**
258
+ * Gets the value from the texture by coordinates provided.
259
+ * @param parsedImage - Image where the data are stored.
260
+ * @param mimeType - MIME type.
261
+ * @param textureCoordinates - uv coordinates to access data in the image.
262
+ * @param index - Index of uv coordinates in the array textureCoordinates.
263
+ * @param channels - Image channels where data are stored. Channels of an RGBA texture are numbered 0..3 respectively.
264
+ * @returns Value taken from the image.
265
+ */
266
+ function getImageValueByCoordinates(
267
+ parsedImage: ImageType,
268
+ mimeType: string | undefined,
269
+ textureCoordinates: Float32Array,
270
+ index: number,
271
+ channels: number[] | string = [0]
272
+ ) {
273
+ const CHANNELS_MAP = {
274
+ r: {offset: 0, shift: 0},
275
+ g: {offset: 1, shift: 8},
276
+ b: {offset: 2, shift: 16},
277
+ a: {offset: 3, shift: 24}
278
+ };
279
+
280
+ const u = textureCoordinates[index];
281
+ const v = textureCoordinates[index + 1];
282
+
283
+ let components = 1;
284
+ if (mimeType && (mimeType.indexOf('image/jpeg') !== -1 || mimeType.indexOf('image/png') !== -1))
285
+ components = 4;
286
+ const offset = coordinatesToOffset(u, v, parsedImage, components);
287
+ let value: number = 0;
288
+ for (const c of channels) {
289
+ /*
290
+ According to the EXT_feature_metadata extension specification:
291
+ Channels are labeled by rgba and are swizzled with a string of 1-4 characters.
292
+ According to the EXT_mesh_features extension specification:
293
+ The channels array contains non-negative integer values corresponding to channels of the source texture that the feature ID consists of.
294
+ Channels of an RGBA texture are numbered 0–3 respectively.
295
+ Function getImageValueByCoordinates is used to process both extensions.
296
+ So, there should be possible to get the element of CHANNELS_MAP by either index (0, 1, 2, 3) or key (r, g, b, a).
297
+ */
298
+ const map = typeof c === 'number' ? Object.values(CHANNELS_MAP)[c] : CHANNELS_MAP[c];
299
+ const imageOffset = offset + map.offset;
300
+ const imageData = getImageData(parsedImage);
301
+ if (imageData.data.length <= imageOffset) {
302
+ throw new Error(`${imageData.data.length} <= ${imageOffset}`);
303
+ }
304
+ const imageValue = imageData.data[imageOffset];
305
+ value |= imageValue << map.shift;
306
+ }
307
+ return value;
308
+ }
309
+
310
+ /**
311
+ * Retrieves the offset in the image where the data are stored.
312
+ * @param u - u-coordinate.
313
+ * @param v - v-coordinate.
314
+ * @param parsedImage - Image where the data are stored.
315
+ * @param componentsCount - Number of components the data consists of.
316
+ * @returns Offset in the image where the data are stored.
317
+ */
318
+ function coordinatesToOffset(
319
+ u: number,
320
+ v: number,
321
+ parsedImage: any,
322
+ componentsCount: number = 1
323
+ ): number {
324
+ const w = parsedImage.width;
325
+ const iX = emod(u) * (w - 1);
326
+ const indX = Math.round(iX);
327
+
328
+ const h = parsedImage.height;
329
+ const iY = emod(v) * (h - 1);
330
+ const indY = Math.round(iY);
331
+ const components = parsedImage.components ? parsedImage.components : componentsCount;
332
+ // components is a number of channels in the image
333
+ const offset = (indY * w + indX) * components;
334
+ return offset;
335
+ }
336
+
337
+ /**
338
+ * Parses variable-length array data.
339
+ * In this case every value of the property in the table will be an array
340
+ * of arbitrary length.
341
+ * @param valuesData - Values in a flat typed array.
342
+ * @param numberOfElements - Number of rows in the property table.
343
+ * @param arrayOffsets - Offsets of nested arrays in the flat values array.
344
+ * @param valuesDataBytesLength - Data byte length.
345
+ * @param valueSize - Value size in bytes.
346
+ * @returns Array of typed arrays.
347
+ */
348
+ export function parseVariableLengthArrayNumeric(
349
+ valuesData: BigTypedArray,
350
+ numberOfElements: number,
351
+ arrayOffsets: TypedArray,
352
+ valuesDataBytesLength: number,
353
+ valueSize: number
354
+ ): BigTypedArray[] {
355
+ const attributeValueArray: BigTypedArray[] = [];
356
+ for (let index = 0; index < numberOfElements; index++) {
357
+ const arrayOffset = arrayOffsets[index];
358
+ const arrayByteSize = arrayOffsets[index + 1] - arrayOffsets[index];
359
+ if (arrayByteSize + arrayOffset > valuesDataBytesLength) {
360
+ break;
361
+ }
362
+ const typedArrayOffset = arrayOffset / valueSize;
363
+ const elementCount = arrayByteSize / valueSize;
364
+ attributeValueArray.push(valuesData.slice(typedArrayOffset, typedArrayOffset + elementCount));
365
+ }
366
+ return attributeValueArray;
367
+ }
368
+
369
+ /**
370
+ * Parses fixed-length array data.
371
+ * In this case every value of the property in the table will be an array
372
+ * of constant length equal to `arrayCount`.
373
+ * @param valuesData - Values in a flat typed array.
374
+ * @param numberOfElements - Number of rows in the property table.
375
+ * @param arrayCount - Nested arrays length.
376
+ * @returns Array of typed arrays.
377
+ */
378
+ export function parseFixedLengthArrayNumeric(
379
+ valuesData: BigTypedArray,
380
+ numberOfElements: number,
381
+ arrayCount: number
382
+ ): BigTypedArray[] {
383
+ const attributeValueArray: BigTypedArray[] = [];
384
+ for (let index = 0; index < numberOfElements; index++) {
385
+ const elementOffset = index * arrayCount;
386
+ attributeValueArray.push(valuesData.slice(elementOffset, elementOffset + arrayCount));
387
+ }
388
+ return attributeValueArray;
389
+ }
390
+
391
+ /**
392
+ * Decodes properties of string type from binary source.
393
+ * @param numberOfElements - The number of elements in each property array that propertyTableProperty contains. It's a number of rows in the table.
394
+ * @param valuesDataBytes - Data taken from values property of the property table property.
395
+ * @param arrayOffsets - Offsets for variable-length arrays. It's null for fixed-length arrays or scalar types.
396
+ * @param stringOffsets - Index of the buffer view containing offsets for strings. It should be available for string type.
397
+ * @returns String property values
398
+ */
399
+ export function getPropertyDataString(
400
+ numberOfElements: number,
401
+ valuesDataBytes: Uint8Array,
402
+ arrayOffsets: TypedArray | null,
403
+ stringOffsets: TypedArray | null
404
+ ): string[] | string[][] {
405
+ if (arrayOffsets) {
406
+ // TODO: implement it as soon as we have the corresponding tileset
407
+ throw new Error('Not implemented - arrayOffsets for strings is specified');
408
+ }
409
+
410
+ if (stringOffsets) {
411
+ const stringsArray: string[] = [];
412
+ const textDecoder = new TextDecoder('utf8');
413
+
414
+ let stringOffset = 0;
415
+ for (let index = 0; index < numberOfElements; index++) {
416
+ const stringByteSize = stringOffsets[index + 1] - stringOffsets[index];
417
+
418
+ if (stringByteSize + stringOffset <= valuesDataBytes.length) {
419
+ const stringData = valuesDataBytes.subarray(stringOffset, stringByteSize + stringOffset);
420
+ const stringAttribute = textDecoder.decode(stringData);
421
+
422
+ stringsArray.push(stringAttribute);
423
+ stringOffset += stringByteSize;
424
+ }
425
+ }
426
+
427
+ return stringsArray;
428
+ }
429
+ return [];
430
+ }
@@ -1,5 +1,8 @@
1
1
  import {assert} from '../utils/assert';
2
+
3
+ import type {GLTFWithBuffers} from '../types/gltf-types';
2
4
  import type {GLTFPostprocessed} from '../types/gltf-postprocessed-schema';
5
+ import {BYTES, COMPONENTS} from '../gltf-utils/gltf-constants';
3
6
 
4
7
  /**
5
8
  * Memory needed to store texture and all mipmap levels 1 + 1/4 + 1/16 + 1/64 + ...
@@ -85,6 +88,41 @@ export function getAccessorArrayTypeAndLength(accessor, bufferView) {
85
88
  return {ArrayType, length, byteLength};
86
89
  }
87
90
 
91
+ export function getFloat32ArrayForAccessor(
92
+ gltfData: GLTFWithBuffers,
93
+ texCoordAccessor: number
94
+ ): Float32Array | null {
95
+ const accessor = gltfData.json.accessors?.[texCoordAccessor];
96
+ if (accessor && typeof accessor.bufferView !== 'undefined') {
97
+ // Get `bufferView` of the `accessor`
98
+ const bufferView = gltfData.json.bufferViews?.[accessor.bufferView];
99
+ if (bufferView) {
100
+ // Get `arrayBuffer` the `bufferView` look at
101
+ const {arrayBuffer, byteOffset: bufferByteOffset} = gltfData.buffers[bufferView.buffer];
102
+ // Resulting byteOffset is sum of the buffer, accessor and bufferView byte offsets
103
+ const byteOffset =
104
+ (bufferByteOffset || 0) + (accessor.byteOffset || 0) + (bufferView.byteOffset || 0);
105
+ // Deduce TypedArray type and its length from `accessor` and `bufferView` data
106
+ const {ArrayType, length} = getAccessorArrayTypeAndLength(accessor, bufferView);
107
+ // Number of bytes each component occupies
108
+ const bytes = BYTES[accessor.componentType];
109
+ // Number of components. For the `TEXCOORD_0` with `VEC2` type, it must return 2
110
+ const components = COMPONENTS[accessor.type];
111
+ // Multiplier to calculate the address of the `TEXCOORD_0` element in the arrayBuffer
112
+ const elementAddressScale = bufferView.byteStride || bytes * components;
113
+ // Data transform to Float32Array
114
+ const result = new Float32Array(length);
115
+ for (let i = 0; i < accessor.count; i++) {
116
+ // Take [u, v] couple from the arrayBuffer
117
+ const uv = new ArrayType(arrayBuffer, byteOffset + i * elementAddressScale, 2);
118
+ result.set(uv, i * components);
119
+ }
120
+ return result;
121
+ }
122
+ }
123
+ return null;
124
+ }
125
+
88
126
  /**
89
127
  * Calculate the GPU memory used by a GLTF tile, for both buffer and texture memory
90
128
  * @param gltf - the gltf content of a GLTF tile
@@ -5,7 +5,8 @@ import type {GLTFWithBuffers} from '../types/gltf-types';
5
5
  import type {GLB} from '../types/glb-types';
6
6
  import type {ParseGLBOptions} from './parse-glb';
7
7
 
8
- import {parseJSON, sliceArrayBuffer} from '@loaders.gl/loader-utils';
8
+ import type {ImageType, TextureLevel} from '@loaders.gl/schema';
9
+ import {parseJSON, sliceArrayBuffer, parseFromContext} from '@loaders.gl/loader-utils';
9
10
  import {ImageLoader} from '@loaders.gl/images';
10
11
  import {BasisLoader, selectSupportedBasisFormat} from '@loaders.gl/textures';
11
12
 
@@ -198,13 +199,14 @@ async function loadImage(
198
199
  options,
199
200
  context: LoaderContext
200
201
  ) {
201
- const {fetch, parse} = context;
202
-
203
202
  let arrayBuffer;
204
203
 
205
204
  if (image.uri && !image.hasOwnProperty('bufferView')) {
206
205
  const uri = resolveUrl(image.uri, options);
206
+
207
+ const {fetch} = context;
207
208
  const response = await fetch(uri);
209
+
208
210
  arrayBuffer = await response.arrayBuffer();
209
211
  image.bufferView = {
210
212
  data: arrayBuffer
@@ -219,16 +221,21 @@ async function loadImage(
219
221
  assert(arrayBuffer, 'glTF image has no data');
220
222
 
221
223
  // Call `parse`
222
- let parsedImage = await parse(
224
+ let parsedImage = (await parseFromContext(
223
225
  arrayBuffer,
224
226
  [ImageLoader, BasisLoader],
225
- {mimeType: image.mimeType, basis: options.basis || {format: selectSupportedBasisFormat()}},
227
+ {
228
+ ...options,
229
+ mimeType: image.mimeType,
230
+ basis: options.basis || {format: selectSupportedBasisFormat()}
231
+ },
226
232
  context
227
- );
233
+ )) as ImageType | TextureLevel[][];
228
234
 
229
235
  if (parsedImage && parsedImage[0]) {
230
236
  parsedImage = {
231
237
  compressed: true,
238
+ // @ts-expect-error
232
239
  mipmaps: false,
233
240
  width: parsedImage[0].width,
234
241
  height: parsedImage[0].height,
@@ -240,5 +247,6 @@ async function loadImage(
240
247
 
241
248
  // Store the loaded image
242
249
  gltf.images = gltf.images || [];
250
+ // @ts-expect-error TODO - sort out image typing asap
243
251
  gltf.images[index] = parsedImage;
244
252
  }