@loaders.gl/gltf 4.0.0-alpha.23 → 4.0.0-alpha.25
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.
- package/dist/dist.min.js +378 -241
- package/dist/es5/index.js +12 -0
- package/dist/es5/index.js.map +1 -1
- package/dist/es5/lib/api/gltf-extensions.js +1 -1
- package/dist/es5/lib/api/gltf-extensions.js.map +1 -1
- package/dist/es5/lib/extensions/EXT_mesh_features.js +13 -25
- package/dist/es5/lib/extensions/EXT_mesh_features.js.map +1 -1
- package/dist/es5/lib/extensions/EXT_structural_metadata.js +152 -106
- package/dist/es5/lib/extensions/EXT_structural_metadata.js.map +1 -1
- package/dist/es5/lib/extensions/deprecated/EXT_feature_metadata.js +64 -16
- package/dist/es5/lib/extensions/deprecated/EXT_feature_metadata.js.map +1 -1
- package/dist/es5/lib/extensions/{data-processing.js → utils/3d-tiles-utils.js} +51 -24
- package/dist/es5/lib/extensions/utils/3d-tiles-utils.js.map +1 -0
- package/dist/es5/lib/gltf-utils/gltf-utils.js +29 -0
- package/dist/es5/lib/gltf-utils/gltf-utils.js.map +1 -1
- package/dist/es5/lib/types/gltf-ext-feature-metadata-schema.js +2 -0
- package/dist/es5/lib/types/gltf-ext-feature-metadata-schema.js.map +1 -0
- package/dist/es5/lib/types/gltf-ext-mesh-features-schema.js.map +1 -1
- package/dist/es5/lib/types/gltf-ext-structural-metadata-schema.js.map +1 -1
- package/dist/es5/lib/types/gltf-json-schema.js.map +1 -1
- package/dist/es5/lib/types/gltf-types.js.map +1 -1
- package/dist/es5/lib/utils/version.js +1 -1
- package/dist/esm/index.js +2 -0
- package/dist/esm/index.js.map +1 -1
- package/dist/esm/lib/api/gltf-extensions.js +1 -1
- package/dist/esm/lib/api/gltf-extensions.js.map +1 -1
- package/dist/esm/lib/extensions/EXT_mesh_features.js +13 -25
- package/dist/esm/lib/extensions/EXT_mesh_features.js.map +1 -1
- package/dist/esm/lib/extensions/EXT_structural_metadata.js +127 -89
- package/dist/esm/lib/extensions/EXT_structural_metadata.js.map +1 -1
- package/dist/esm/lib/extensions/deprecated/EXT_feature_metadata.js +64 -17
- package/dist/esm/lib/extensions/deprecated/EXT_feature_metadata.js.map +1 -1
- package/dist/esm/lib/extensions/{data-processing.js → utils/3d-tiles-utils.js} +50 -24
- package/dist/esm/lib/extensions/utils/3d-tiles-utils.js.map +1 -0
- package/dist/esm/lib/gltf-utils/gltf-utils.js +30 -0
- package/dist/esm/lib/gltf-utils/gltf-utils.js.map +1 -1
- package/dist/esm/lib/types/gltf-ext-feature-metadata-schema.js +2 -0
- package/dist/esm/lib/types/gltf-ext-feature-metadata-schema.js.map +1 -0
- package/dist/esm/lib/types/gltf-ext-mesh-features-schema.js.map +1 -1
- package/dist/esm/lib/types/gltf-ext-structural-metadata-schema.js.map +1 -1
- package/dist/esm/lib/types/gltf-json-schema.js.map +1 -1
- package/dist/esm/lib/types/gltf-types.js.map +1 -1
- package/dist/esm/lib/utils/version.js +1 -1
- package/dist/index.d.ts +6 -3
- package/dist/index.d.ts.map +1 -1
- package/dist/lib/extensions/EXT_mesh_features.d.ts.map +1 -1
- package/dist/lib/extensions/EXT_structural_metadata.d.ts +12 -4
- package/dist/lib/extensions/EXT_structural_metadata.d.ts.map +1 -1
- package/dist/lib/extensions/deprecated/EXT_feature_metadata.d.ts +9 -0
- package/dist/lib/extensions/deprecated/EXT_feature_metadata.d.ts.map +1 -1
- package/dist/lib/extensions/utils/3d-tiles-utils.d.ts +52 -0
- package/dist/lib/extensions/utils/3d-tiles-utils.d.ts.map +1 -0
- package/dist/lib/gltf-utils/gltf-utils.d.ts +2 -0
- package/dist/lib/gltf-utils/gltf-utils.d.ts.map +1 -1
- package/dist/lib/types/gltf-ext-feature-metadata-schema.d.ts +421 -0
- package/dist/lib/types/gltf-ext-feature-metadata-schema.d.ts.map +1 -0
- package/dist/lib/types/gltf-ext-mesh-features-schema.d.ts +4 -6
- package/dist/lib/types/gltf-ext-mesh-features-schema.d.ts.map +1 -1
- package/dist/lib/types/gltf-ext-structural-metadata-schema.d.ts +48 -29
- package/dist/lib/types/gltf-ext-structural-metadata-schema.d.ts.map +1 -1
- package/dist/lib/types/gltf-json-schema.d.ts +1 -420
- package/dist/lib/types/gltf-json-schema.d.ts.map +1 -1
- package/dist/lib/types/gltf-types.d.ts +3 -0
- package/dist/lib/types/gltf-types.d.ts.map +1 -1
- package/package.json +6 -6
- package/src/index.ts +10 -5
- package/src/lib/api/gltf-extensions.ts +1 -1
- package/src/lib/extensions/EXT_mesh_features.ts +18 -44
- package/src/lib/extensions/EXT_structural_metadata.ts +364 -217
- package/src/lib/extensions/deprecated/EXT_feature_metadata.ts +193 -30
- package/src/lib/extensions/{data-processing.ts → utils/3d-tiles-utils.ts} +128 -56
- package/src/lib/gltf-utils/gltf-utils.ts +38 -0
- package/src/lib/types/gltf-ext-feature-metadata-schema.ts +470 -0
- package/src/lib/types/gltf-ext-mesh-features-schema.ts +4 -6
- package/src/lib/types/gltf-ext-structural-metadata-schema.ts +52 -31
- package/src/lib/types/gltf-json-schema.ts +1 -468
- package/src/lib/types/gltf-types.ts +4 -0
- package/dist/bundle.js +0 -5
- package/dist/es5/lib/extensions/data-processing.js.map +0 -1
- package/dist/esm/lib/extensions/data-processing.js.map +0 -1
- package/dist/glb-loader.js +0 -34
- package/dist/glb-writer.js +0 -35
- package/dist/gltf-loader.js +0 -50
- package/dist/gltf-writer.js +0 -32
- package/dist/index.js +0 -34
- package/dist/lib/api/gltf-extensions.js +0 -88
- package/dist/lib/api/gltf-scenegraph.js +0 -580
- package/dist/lib/api/normalize-gltf-v1.js +0 -299
- package/dist/lib/api/post-process-gltf.js +0 -433
- package/dist/lib/encoders/encode-glb.js +0 -72
- package/dist/lib/encoders/encode-gltf.js +0 -32
- package/dist/lib/extensions/EXT_mesh_features.js +0 -89
- package/dist/lib/extensions/EXT_meshopt_compression.js +0 -41
- package/dist/lib/extensions/EXT_structural_metadata.js +0 -504
- package/dist/lib/extensions/EXT_texture_webp.js +0 -36
- package/dist/lib/extensions/KHR_binary_gltf.js +0 -39
- package/dist/lib/extensions/KHR_draco_mesh_compression.js +0 -137
- package/dist/lib/extensions/KHR_texture_basisu.js +0 -29
- package/dist/lib/extensions/KHR_texture_transform.js +0 -227
- package/dist/lib/extensions/data-processing.d.ts +0 -34
- package/dist/lib/extensions/data-processing.d.ts.map +0 -1
- package/dist/lib/extensions/data-processing.js +0 -212
- package/dist/lib/extensions/deprecated/EXT_feature_metadata.js +0 -282
- package/dist/lib/extensions/deprecated/KHR_lights_punctual.js +0 -59
- package/dist/lib/extensions/deprecated/KHR_materials_unlit.js +0 -44
- package/dist/lib/extensions/deprecated/KHR_techniques_webgl.js +0 -79
- package/dist/lib/gltf-utils/get-typed-array.js +0 -41
- package/dist/lib/gltf-utils/gltf-attribute-utils.js +0 -73
- package/dist/lib/gltf-utils/gltf-constants.js +0 -43
- package/dist/lib/gltf-utils/gltf-utils.js +0 -90
- package/dist/lib/gltf-utils/resolve-url.js +0 -18
- package/dist/lib/parsers/parse-glb.js +0 -166
- package/dist/lib/parsers/parse-gltf.js +0 -185
- package/dist/lib/types/glb-types.js +0 -2
- package/dist/lib/types/gltf-ext-mesh-features-schema.js +0 -2
- package/dist/lib/types/gltf-ext-structural-metadata-schema.js +0 -2
- package/dist/lib/types/gltf-json-schema.js +0 -4
- package/dist/lib/types/gltf-postprocessed-schema.js +0 -4
- package/dist/lib/types/gltf-types.js +0 -3
- package/dist/lib/utils/assert.js +0 -12
- package/dist/lib/utils/version.js +0 -7
- package/dist/meshopt/meshopt-decoder.js +0 -118
- package/dist/webp/webp.js +0 -38
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
/* eslint-disable camelcase */
|
|
2
|
+
import type {GLTF} from '../../types/gltf-json-schema';
|
|
2
3
|
import type {
|
|
3
|
-
GLTF,
|
|
4
4
|
GLTF_EXT_feature_metadata_Class,
|
|
5
5
|
GLTF_EXT_feature_metadata_ClassProperty,
|
|
6
6
|
GLTF_EXT_feature_metadata_FeatureTable,
|
|
@@ -8,13 +8,16 @@ import type {
|
|
|
8
8
|
GLTF_EXT_feature_metadata_FeatureTexture,
|
|
9
9
|
GLTF_EXT_feature_metadata_GLTF,
|
|
10
10
|
GLTF_EXT_feature_metadata_TextureAccessor
|
|
11
|
-
} from '../../types/gltf-
|
|
11
|
+
} from '../../types/gltf-ext-feature-metadata-schema';
|
|
12
|
+
import type {BigTypedArray, TypedArray} from '@loaders.gl/schema';
|
|
13
|
+
import type {FeatureTableJson} from '../../types/gltf-types';
|
|
12
14
|
import {GLTFScenegraph} from '../../api/gltf-scenegraph';
|
|
13
15
|
import {getImageData} from '@loaders.gl/images';
|
|
14
16
|
import {GLTFMeshPrimitive} from '../../types/gltf-json-schema';
|
|
15
|
-
import {getComponentTypeFromArray} from '../../gltf-utils/gltf-utils';
|
|
17
|
+
import {getComponentTypeFromArray, getFloat32ArrayForAccessor} from '../../gltf-utils/gltf-utils';
|
|
16
18
|
import {GLTFLoaderOptions} from '../../../gltf-loader';
|
|
17
19
|
import {emod} from '@loaders.gl/math';
|
|
20
|
+
import {convertRawBufferToMetadataArray, getOffsetsForProperty} from '../utils/3d-tiles-utils';
|
|
18
21
|
|
|
19
22
|
/** Extension name */
|
|
20
23
|
const EXT_FEATURE_METADATA_NAME = 'EXT_feature_metadata';
|
|
@@ -25,6 +28,65 @@ export async function decode(gltfData: {json: GLTF}, options: GLTFLoaderOptions)
|
|
|
25
28
|
decodeExtFeatureMetadata(scenegraph, options);
|
|
26
29
|
}
|
|
27
30
|
|
|
31
|
+
/**
|
|
32
|
+
* Handles EXT_feature_metadata to get property table.
|
|
33
|
+
* @param extension - Global level of EXT_FEATURE_METADATA extension.
|
|
34
|
+
* @param metadataClass - User selected feature metadata class name.
|
|
35
|
+
* @returns {FeatureTableJson | null} Property table or null if the extension can't be handled properly.
|
|
36
|
+
*/
|
|
37
|
+
export function getPropertyTableFromExtFeatureMetadata(
|
|
38
|
+
extension: GLTF_EXT_feature_metadata_GLTF,
|
|
39
|
+
metadataClass?: string
|
|
40
|
+
): FeatureTableJson | null {
|
|
41
|
+
if (extension.featureTables) {
|
|
42
|
+
/**
|
|
43
|
+
* Take only first feature table to generate attributes storage info object.
|
|
44
|
+
* TODO: Think about getting data from all feature tables?
|
|
45
|
+
* It can be tricky just because 3dTiles is able to have multiple featureId attributes and multiple feature tables.
|
|
46
|
+
* In I3S we should decide which featureIds attribute will be passed to geometry data.
|
|
47
|
+
*/
|
|
48
|
+
const firstFeatureTableName = Object.keys(extension.featureTables)?.[0];
|
|
49
|
+
|
|
50
|
+
if (firstFeatureTableName) {
|
|
51
|
+
const featureTable = extension.featureTables[firstFeatureTableName];
|
|
52
|
+
const propertyTable = {};
|
|
53
|
+
|
|
54
|
+
for (const propertyName in featureTable.properties) {
|
|
55
|
+
propertyTable[propertyName] = featureTable.properties[propertyName].data;
|
|
56
|
+
}
|
|
57
|
+
|
|
58
|
+
return propertyTable;
|
|
59
|
+
}
|
|
60
|
+
}
|
|
61
|
+
|
|
62
|
+
if (extension.featureTextures) {
|
|
63
|
+
let featureTexture: string | undefined;
|
|
64
|
+
for (const textureKey in extension.featureTextures) {
|
|
65
|
+
const texture = extension.featureTextures[textureKey];
|
|
66
|
+
if (texture.class === metadataClass) {
|
|
67
|
+
featureTexture = textureKey;
|
|
68
|
+
}
|
|
69
|
+
}
|
|
70
|
+
|
|
71
|
+
if (typeof featureTexture === 'string') {
|
|
72
|
+
const featureTable = extension.featureTextures[featureTexture];
|
|
73
|
+
const propertyTable = {};
|
|
74
|
+
|
|
75
|
+
for (const propertyName in featureTable.properties) {
|
|
76
|
+
propertyTable[propertyName] = featureTable.properties[propertyName].data;
|
|
77
|
+
}
|
|
78
|
+
|
|
79
|
+
return propertyTable;
|
|
80
|
+
}
|
|
81
|
+
}
|
|
82
|
+
|
|
83
|
+
// eslint-disable-next-line no-console
|
|
84
|
+
console.warn(
|
|
85
|
+
'Cannot get property table from EXT_feature_metadata extension. There is neither featureTables, nor featureTextures in the extension.'
|
|
86
|
+
);
|
|
87
|
+
return null;
|
|
88
|
+
}
|
|
89
|
+
|
|
28
90
|
/**
|
|
29
91
|
* Decodes feature metadata from extension
|
|
30
92
|
* @param scenegraph
|
|
@@ -125,24 +187,134 @@ function getPropertyDataFromBinarySource(
|
|
|
125
187
|
schemaProperty: GLTF_EXT_feature_metadata_ClassProperty,
|
|
126
188
|
numberOfFeatures: number,
|
|
127
189
|
featureTableProperty: GLTF_EXT_feature_metadata_FeatureTableProperty
|
|
128
|
-
):
|
|
190
|
+
): BigTypedArray | string[] {
|
|
129
191
|
const bufferView = featureTableProperty.bufferView;
|
|
130
|
-
// TODO think maybe we shouldn't get data only in Uint8Array format.
|
|
131
192
|
const dataArray: Uint8Array = scenegraph.getTypedArrayForBufferView(bufferView);
|
|
132
193
|
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
const offsetsData = scenegraph.getTypedArrayForBufferView(stringOffsetBufferView);
|
|
138
|
-
return getStringAttributes(dataArray, offsetsData, numberOfFeatures);
|
|
194
|
+
if (schemaProperty.type === 'STRING') {
|
|
195
|
+
const offsetsData = getStringOffsets(scenegraph, featureTableProperty, numberOfFeatures);
|
|
196
|
+
if (!offsetsData) {
|
|
197
|
+
return [];
|
|
139
198
|
}
|
|
140
|
-
|
|
199
|
+
return getStringAttributes(dataArray, offsetsData, numberOfFeatures);
|
|
200
|
+
} else if (isNumericProperty(schemaProperty.type)) {
|
|
201
|
+
return getNumericAttributes(
|
|
202
|
+
dataArray,
|
|
203
|
+
schemaProperty.type as
|
|
204
|
+
| 'INT8'
|
|
205
|
+
| 'UINT8'
|
|
206
|
+
| 'INT16'
|
|
207
|
+
| 'UINT16'
|
|
208
|
+
| 'INT32'
|
|
209
|
+
| 'UINT32'
|
|
210
|
+
| 'INT64'
|
|
211
|
+
| 'UINT64'
|
|
212
|
+
| 'FLOAT32'
|
|
213
|
+
| 'FLOAT64',
|
|
214
|
+
numberOfFeatures
|
|
215
|
+
);
|
|
141
216
|
}
|
|
142
217
|
|
|
143
218
|
return dataArray;
|
|
144
219
|
}
|
|
145
220
|
|
|
221
|
+
/**
|
|
222
|
+
* Check if the feature table property is of numeric type
|
|
223
|
+
* @param schemaPropertyType - feature table property
|
|
224
|
+
* @returns true if property is numeric, else - false
|
|
225
|
+
*/
|
|
226
|
+
function isNumericProperty(
|
|
227
|
+
schemaPropertyType:
|
|
228
|
+
| 'INT8'
|
|
229
|
+
| 'UINT8'
|
|
230
|
+
| 'INT16'
|
|
231
|
+
| 'UINT16'
|
|
232
|
+
| 'INT32'
|
|
233
|
+
| 'UINT32'
|
|
234
|
+
| 'INT64'
|
|
235
|
+
| 'UINT64'
|
|
236
|
+
| 'FLOAT32'
|
|
237
|
+
| 'FLOAT64'
|
|
238
|
+
| 'BOOLEAN'
|
|
239
|
+
| 'STRING'
|
|
240
|
+
| 'ENUM'
|
|
241
|
+
| 'ARRAY'
|
|
242
|
+
| string
|
|
243
|
+
): boolean {
|
|
244
|
+
return [
|
|
245
|
+
'UINT8',
|
|
246
|
+
'INT16',
|
|
247
|
+
'UINT16',
|
|
248
|
+
'INT32',
|
|
249
|
+
'UINT32',
|
|
250
|
+
'INT64',
|
|
251
|
+
'UINT64',
|
|
252
|
+
'FLOAT32',
|
|
253
|
+
'FLOAT64'
|
|
254
|
+
].includes(schemaPropertyType);
|
|
255
|
+
}
|
|
256
|
+
|
|
257
|
+
/**
|
|
258
|
+
* Parse featureTable.property.stringOffsetBufferView.
|
|
259
|
+
* String offsets is an array of offsets of strings in the united array of charactersz
|
|
260
|
+
* @param scenegraph - Instance of the class for structured access to GLTF data
|
|
261
|
+
* @param propertyTableProperty - propertyTable's property metadata
|
|
262
|
+
* @param numberOfElements - The number of elements in each property array that propertyTableProperty contains. It's a number of rows in the table
|
|
263
|
+
* @returns typed array with offset values
|
|
264
|
+
* @see https://github.com/CesiumGS/glTF/blob/c38f7f37e894004353c15cd0481bc5b7381ce841/extensions/2.0/Vendor/EXT_feature_metadata/schema/featureTable.property.schema.json#L50C10-L50C32
|
|
265
|
+
*/
|
|
266
|
+
function getStringOffsets(
|
|
267
|
+
scenegraph: GLTFScenegraph,
|
|
268
|
+
featureTableProperty: GLTF_EXT_feature_metadata_FeatureTableProperty,
|
|
269
|
+
numberOfElements: number
|
|
270
|
+
): TypedArray | null {
|
|
271
|
+
if (typeof featureTableProperty.stringOffsetBufferView !== 'undefined') {
|
|
272
|
+
// Data are in a FIXED-length array
|
|
273
|
+
return getOffsetsForProperty(
|
|
274
|
+
scenegraph,
|
|
275
|
+
featureTableProperty.stringOffsetBufferView,
|
|
276
|
+
featureTableProperty.offsetType || 'UINT32', // UINT32 is the default by the spec
|
|
277
|
+
numberOfElements
|
|
278
|
+
);
|
|
279
|
+
}
|
|
280
|
+
return null;
|
|
281
|
+
}
|
|
282
|
+
|
|
283
|
+
/**
|
|
284
|
+
* Parse numeric property values
|
|
285
|
+
* @param valuesDataBytes - values data array
|
|
286
|
+
* @param propertyType - type of the property
|
|
287
|
+
* @param elementCount - number of rows in the featureTable
|
|
288
|
+
* @returns Number data in a typed array
|
|
289
|
+
*/
|
|
290
|
+
function getNumericAttributes(
|
|
291
|
+
valuesDataBytes: Uint8Array,
|
|
292
|
+
propertyType:
|
|
293
|
+
| 'INT8'
|
|
294
|
+
| 'UINT8'
|
|
295
|
+
| 'INT16'
|
|
296
|
+
| 'UINT16'
|
|
297
|
+
| 'INT32'
|
|
298
|
+
| 'UINT32'
|
|
299
|
+
| 'INT64'
|
|
300
|
+
| 'UINT64'
|
|
301
|
+
| 'FLOAT32'
|
|
302
|
+
| 'FLOAT64',
|
|
303
|
+
elementCount: number
|
|
304
|
+
): BigTypedArray {
|
|
305
|
+
let valuesData = convertRawBufferToMetadataArray(
|
|
306
|
+
valuesDataBytes,
|
|
307
|
+
'SCALAR',
|
|
308
|
+
// The datatype of the element's components. Only applicable to `SCALAR`, `VECN`, and `MATN` types.
|
|
309
|
+
propertyType,
|
|
310
|
+
elementCount
|
|
311
|
+
);
|
|
312
|
+
if (!valuesData) {
|
|
313
|
+
valuesData = valuesDataBytes;
|
|
314
|
+
}
|
|
315
|
+
return valuesData;
|
|
316
|
+
}
|
|
317
|
+
|
|
146
318
|
/**
|
|
147
319
|
* Get properties from texture associated with all mesh primitives.
|
|
148
320
|
* @param scenegraph
|
|
@@ -208,16 +380,15 @@ function processPrimitiveTextures(
|
|
|
208
380
|
const textureData: number[] = [];
|
|
209
381
|
const texCoordAccessorKey = `TEXCOORD_${featureTextureProperty.texture.texCoord}`;
|
|
210
382
|
const texCoordAccessorIndex = primitive.attributes[texCoordAccessorKey];
|
|
211
|
-
const texCoordBufferView = scenegraph.getBufferView(texCoordAccessorIndex);
|
|
212
|
-
const texCoordArray: Uint8Array = scenegraph.getTypedArrayForBufferView(texCoordBufferView);
|
|
213
|
-
|
|
214
|
-
const textureCoordinates: Float32Array = new Float32Array(
|
|
215
|
-
texCoordArray.buffer,
|
|
216
|
-
texCoordArray.byteOffset,
|
|
217
|
-
texCoordArray.length / 4
|
|
218
|
-
);
|
|
219
383
|
// textureCoordinates contains UV coordinates of the actual data stored in the texture
|
|
220
384
|
// accessor.count is a number of UV pairs (they are stored as VEC2)
|
|
385
|
+
const textureCoordinates: Float32Array | null = getFloat32ArrayForAccessor(
|
|
386
|
+
scenegraph.gltf,
|
|
387
|
+
texCoordAccessorIndex
|
|
388
|
+
);
|
|
389
|
+
if (!textureCoordinates) {
|
|
390
|
+
return;
|
|
391
|
+
}
|
|
221
392
|
|
|
222
393
|
const textureIndex = featureTextureProperty.texture.index;
|
|
223
394
|
const texture = json.textures?.[textureIndex];
|
|
@@ -371,24 +542,16 @@ function findFeatureTextureByName(
|
|
|
371
542
|
*/
|
|
372
543
|
function getStringAttributes(
|
|
373
544
|
data: Uint8Array,
|
|
374
|
-
offsetsData:
|
|
545
|
+
offsetsData: TypedArray,
|
|
375
546
|
stringsCount: number
|
|
376
547
|
): string[] {
|
|
377
548
|
const stringsArray: string[] = [];
|
|
378
549
|
const textDecoder = new TextDecoder('utf8');
|
|
379
550
|
|
|
380
|
-
let stringOffset = 0;
|
|
381
|
-
const bytesPerStringSize = 4;
|
|
382
|
-
|
|
383
551
|
for (let index = 0; index < stringsCount; index++) {
|
|
384
|
-
|
|
385
|
-
const stringByteSize =
|
|
386
|
-
offsetsData[(index + 1) * bytesPerStringSize] - offsetsData[index * bytesPerStringSize];
|
|
387
|
-
const stringData = data.subarray(stringOffset, stringByteSize + stringOffset);
|
|
552
|
+
const stringData = data.slice(offsetsData[index], offsetsData[index + 1]);
|
|
388
553
|
const stringAttribute = textDecoder.decode(stringData);
|
|
389
|
-
|
|
390
554
|
stringsArray.push(stringAttribute);
|
|
391
|
-
stringOffset += stringByteSize;
|
|
392
555
|
}
|
|
393
556
|
|
|
394
557
|
return stringsArray;
|
|
@@ -1,12 +1,33 @@
|
|
|
1
|
-
|
|
2
|
-
|
|
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';
|
|
3
12
|
import type {ImageType} from '@loaders.gl/images';
|
|
4
13
|
|
|
5
|
-
import {GLTFScenegraph} from '
|
|
6
|
-
import {getComponentTypeFromArray} from '
|
|
14
|
+
import {GLTFScenegraph} from '../../api/gltf-scenegraph';
|
|
15
|
+
import {getComponentTypeFromArray, getFloat32ArrayForAccessor} from '../../gltf-utils/gltf-utils';
|
|
7
16
|
import {getImageData} from '@loaders.gl/images';
|
|
8
17
|
import {emod} from '@loaders.gl/math';
|
|
9
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
|
+
|
|
10
31
|
const ATTRIBUTE_TYPE_TO_COMPONENTS = {
|
|
11
32
|
SCALAR: 1,
|
|
12
33
|
VEC2: 2,
|
|
@@ -53,39 +74,79 @@ export function getArrayElementByteSize(attributeType, componentType): number {
|
|
|
53
74
|
);
|
|
54
75
|
}
|
|
55
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
|
+
|
|
56
114
|
/**
|
|
57
115
|
* Converts raw bytes that are in the buffer to an array of the type defined by the schema.
|
|
58
|
-
* @param
|
|
59
|
-
* @param
|
|
60
|
-
* @param
|
|
61
|
-
* @param
|
|
62
|
-
* @returns
|
|
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
|
|
63
121
|
*/
|
|
64
122
|
export function convertRawBufferToMetadataArray(
|
|
65
|
-
|
|
123
|
+
data: Uint8Array,
|
|
66
124
|
attributeType: string,
|
|
67
|
-
componentType:
|
|
125
|
+
componentType: NumericComponentType,
|
|
68
126
|
elementCount: number = 1
|
|
69
|
-
):
|
|
127
|
+
): BigTypedArray | null {
|
|
70
128
|
const numberOfComponents = ATTRIBUTE_TYPE_TO_COMPONENTS[attributeType];
|
|
71
129
|
const ArrayType = ATTRIBUTE_COMPONENT_TYPE_TO_ARRAY[componentType];
|
|
72
|
-
const length = elementCount * numberOfComponents;
|
|
73
130
|
const size = ATTRIBUTE_COMPONENT_TYPE_TO_BYTE_SIZE[componentType];
|
|
74
|
-
|
|
75
|
-
const
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
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);
|
|
80
141
|
}
|
|
81
142
|
|
|
82
143
|
/**
|
|
83
144
|
* Processes data encoded in the texture associated with the primitive.
|
|
84
145
|
* If Ext_mesh_featues is combined with the Ext_structural_metadata, propertyTable will also be processed.
|
|
85
|
-
* @param
|
|
86
|
-
* @param
|
|
87
|
-
* @param
|
|
88
|
-
* @returns
|
|
146
|
+
* @param scenegraph - Instance of the class for structured access to GLTF data.
|
|
147
|
+
* @param textureInfo - Reference to the texture where extension data are stored.
|
|
148
|
+
* @param primitive - Primitive object in the mesh.
|
|
149
|
+
* @returns Array of data taken. Null if data can't be taken from the texture.
|
|
89
150
|
*/
|
|
90
151
|
export function getPrimitiveTextureData(
|
|
91
152
|
scenegraph: GLTFScenegraph,
|
|
@@ -109,15 +170,14 @@ export function getPrimitiveTextureData(
|
|
|
109
170
|
|
|
110
171
|
const texCoordAccessorKey = `TEXCOORD_${textureInfo.texCoord || 0}`;
|
|
111
172
|
const texCoordAccessorIndex = primitive.attributes[texCoordAccessorKey];
|
|
112
|
-
const texCoordBufferView = scenegraph.getBufferView(texCoordAccessorIndex);
|
|
113
|
-
const texCoordArray: Uint8Array = scenegraph.getTypedArrayForBufferView(texCoordBufferView);
|
|
114
173
|
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
texCoordArray.byteOffset,
|
|
119
|
-
texCoordArray.length / 4
|
|
174
|
+
const textureCoordinates: Float32Array | null = getFloat32ArrayForAccessor(
|
|
175
|
+
scenegraph.gltf,
|
|
176
|
+
texCoordAccessorIndex
|
|
120
177
|
);
|
|
178
|
+
if (!textureCoordinates) {
|
|
179
|
+
return null;
|
|
180
|
+
}
|
|
121
181
|
|
|
122
182
|
const textureIndex: number = textureInfo.index;
|
|
123
183
|
const imageIndex = json.textures?.[textureIndex]?.source;
|
|
@@ -147,11 +207,11 @@ export function getPrimitiveTextureData(
|
|
|
147
207
|
* Puts property data to attributes.
|
|
148
208
|
* It creates corresponding buffer, bufferView and accessor
|
|
149
209
|
* so the data can be accessed like regular data stored in buffers.
|
|
150
|
-
* @param
|
|
151
|
-
* @param
|
|
152
|
-
* @param
|
|
153
|
-
* @param
|
|
154
|
-
* @param
|
|
210
|
+
* @param scenegraph - Scenegraph object.
|
|
211
|
+
* @param attributeName - Name of the attribute.
|
|
212
|
+
* @param propertyData - Property data to store.
|
|
213
|
+
* @param featureTable - Array where unique data from the property data are being stored.
|
|
214
|
+
* @param primitive - Primitive object.
|
|
155
215
|
*/
|
|
156
216
|
export function primitivePropertyDataToAttributes(
|
|
157
217
|
scenegraph: GLTFScenegraph,
|
|
@@ -160,7 +220,10 @@ export function primitivePropertyDataToAttributes(
|
|
|
160
220
|
featureTable: number[],
|
|
161
221
|
primitive: GLTFMeshPrimitive
|
|
162
222
|
): void {
|
|
163
|
-
if
|
|
223
|
+
// No reason to create an empty buffer if there is no property data to store.
|
|
224
|
+
if (!propertyData?.length) {
|
|
225
|
+
return;
|
|
226
|
+
}
|
|
164
227
|
/*
|
|
165
228
|
featureTable will contain unique values, e.g.
|
|
166
229
|
propertyData = [24, 35, 28, 24]
|
|
@@ -194,26 +257,26 @@ export function primitivePropertyDataToAttributes(
|
|
|
194
257
|
|
|
195
258
|
/**
|
|
196
259
|
* Gets the value from the texture by coordinates provided.
|
|
197
|
-
* @param
|
|
198
|
-
* @param
|
|
199
|
-
* @param
|
|
200
|
-
* @param
|
|
201
|
-
* @param
|
|
202
|
-
* @returns
|
|
260
|
+
* @param parsedImage - Image where the data are stored.
|
|
261
|
+
* @param mimeType - MIME type.
|
|
262
|
+
* @param textureCoordinates - uv coordinates to access data in the image.
|
|
263
|
+
* @param index - Index of uv coordinates in the array textureCoordinates.
|
|
264
|
+
* @param channels - Image channels where data are stored. Channels of an RGBA texture are numbered 0..3 respectively.
|
|
265
|
+
* @returns Value taken from the image.
|
|
203
266
|
*/
|
|
204
267
|
function getImageValueByCoordinates(
|
|
205
268
|
parsedImage: ImageType,
|
|
206
269
|
mimeType: string | undefined,
|
|
207
270
|
textureCoordinates: Float32Array,
|
|
208
271
|
index: number,
|
|
209
|
-
channels: number[] = [0]
|
|
272
|
+
channels: number[] | string = [0]
|
|
210
273
|
) {
|
|
211
|
-
const CHANNELS_MAP =
|
|
212
|
-
{offset: 0, shift: 0},
|
|
213
|
-
{offset: 1, shift: 8},
|
|
214
|
-
{offset: 2, shift: 16},
|
|
215
|
-
{offset: 3, shift: 24}
|
|
216
|
-
|
|
274
|
+
const CHANNELS_MAP = {
|
|
275
|
+
r: {offset: 0, shift: 0},
|
|
276
|
+
g: {offset: 1, shift: 8},
|
|
277
|
+
b: {offset: 2, shift: 16},
|
|
278
|
+
a: {offset: 3, shift: 24}
|
|
279
|
+
};
|
|
217
280
|
|
|
218
281
|
const u = textureCoordinates[index];
|
|
219
282
|
const v = textureCoordinates[index + 1];
|
|
@@ -224,7 +287,16 @@ function getImageValueByCoordinates(
|
|
|
224
287
|
const offset = coordinatesToOffset(u, v, parsedImage, components);
|
|
225
288
|
let value: number = 0;
|
|
226
289
|
for (const c of channels) {
|
|
227
|
-
|
|
290
|
+
/*
|
|
291
|
+
According to the EXT_feature_metadata extension specification:
|
|
292
|
+
Channels are labeled by rgba and are swizzled with a string of 1-4 characters.
|
|
293
|
+
According to the EXT_mesh_features extension specification:
|
|
294
|
+
The channels array contains non-negative integer values corresponding to channels of the source texture that the feature ID consists of.
|
|
295
|
+
Channels of an RGBA texture are numbered 0–3 respectively.
|
|
296
|
+
Function getImageValueByCoordinates is used to process both extensions.
|
|
297
|
+
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).
|
|
298
|
+
*/
|
|
299
|
+
const map = typeof c === 'number' ? Object.values(CHANNELS_MAP)[c] : CHANNELS_MAP[c];
|
|
228
300
|
const imageOffset = offset + map.offset;
|
|
229
301
|
const imageData = getImageData(parsedImage);
|
|
230
302
|
if (imageData.data.length <= imageOffset) {
|
|
@@ -237,12 +309,12 @@ function getImageValueByCoordinates(
|
|
|
237
309
|
}
|
|
238
310
|
|
|
239
311
|
/**
|
|
240
|
-
* Retrieves the offset in the image where the data are stored
|
|
241
|
-
* @param u - u-coordinate
|
|
242
|
-
* @param v - v-coordinate
|
|
243
|
-
* @param parsedImage -
|
|
244
|
-
* @param componentsCount -
|
|
245
|
-
* @returns
|
|
312
|
+
* Retrieves the offset in the image where the data are stored.
|
|
313
|
+
* @param u - u-coordinate.
|
|
314
|
+
* @param v - v-coordinate.
|
|
315
|
+
* @param parsedImage - Image where the data are stored.
|
|
316
|
+
* @param componentsCount - Number of components the data consists of.
|
|
317
|
+
* @returns Offset in the image where the data are stored.
|
|
246
318
|
*/
|
|
247
319
|
function coordinatesToOffset(
|
|
248
320
|
u: number,
|
|
@@ -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
|