@loaders.gl/gltf 4.3.0-alpha.7 → 4.3.0-beta.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 (38) hide show
  1. package/dist/dist.dev.js +383 -66
  2. package/dist/dist.min.js +1 -1
  3. package/dist/glb-loader.d.ts.map +1 -1
  4. package/dist/glb-writer.js +1 -1
  5. package/dist/gltf-loader.d.ts.map +1 -1
  6. package/dist/gltf-writer.d.ts.map +1 -1
  7. package/dist/gltf-writer.js +4 -2
  8. package/dist/index.cjs +266 -16
  9. package/dist/index.cjs.map +3 -3
  10. package/dist/index.d.ts +2 -0
  11. package/dist/index.d.ts.map +1 -1
  12. package/dist/index.js +2 -0
  13. package/dist/lib/api/gltf-extensions.d.ts +4 -1
  14. package/dist/lib/api/gltf-extensions.d.ts.map +1 -1
  15. package/dist/lib/api/gltf-extensions.js +11 -0
  16. package/dist/lib/api/gltf-scenegraph.d.ts.map +1 -1
  17. package/dist/lib/api/gltf-scenegraph.js +1 -2
  18. package/dist/lib/encoders/encode-gltf.d.ts +3 -1
  19. package/dist/lib/encoders/encode-gltf.d.ts.map +1 -1
  20. package/dist/lib/encoders/encode-gltf.js +3 -3
  21. package/dist/lib/extensions/EXT_mesh_features.d.ts +17 -1
  22. package/dist/lib/extensions/EXT_mesh_features.d.ts.map +1 -1
  23. package/dist/lib/extensions/EXT_mesh_features.js +109 -0
  24. package/dist/lib/extensions/EXT_structural_metadata.d.ts +19 -0
  25. package/dist/lib/extensions/EXT_structural_metadata.d.ts.map +1 -1
  26. package/dist/lib/extensions/EXT_structural_metadata.js +168 -0
  27. package/dist/lib/extensions/KHR_draco_mesh_compression.d.ts.map +1 -1
  28. package/dist/lib/utils/version.js +1 -1
  29. package/package.json +8 -8
  30. package/src/glb-writer.ts +1 -1
  31. package/src/gltf-writer.ts +8 -4
  32. package/src/index.ts +6 -0
  33. package/src/lib/api/gltf-extensions.ts +15 -1
  34. package/src/lib/api/gltf-scenegraph.ts +1 -3
  35. package/src/lib/encoders/encode-gltf.ts +11 -4
  36. package/src/lib/extensions/EXT_mesh_features.ts +130 -0
  37. package/src/lib/extensions/EXT_structural_metadata.ts +232 -1
  38. package/src/lib/extensions/KHR_draco_mesh_compression.ts +1 -2
@@ -1,6 +1,7 @@
1
1
  /* eslint-disable camelcase */
2
2
  import {GLTF} from '../types/gltf-json-schema';
3
3
  import type {GLTFLoaderOptions} from '../../gltf-loader';
4
+ import {GLTFWriterOptions} from '../../gltf-writer';
4
5
 
5
6
  // GLTF 1.0 extensions (decode only)
6
7
  // import * as KHR_binary_gltf from './KHR_draco_mesh_compression';
@@ -33,7 +34,7 @@ type GLTFExtensionPlugin = {
33
34
  options: GLTFLoaderOptions,
34
35
  context
35
36
  ) => Promise<void>;
36
- encode?: (gltfData: {json: GLTF}, options: GLTFLoaderOptions) => void;
37
+ encode?: (gltfData: {json: GLTF}, options: GLTFWriterOptions) => void;
37
38
  };
38
39
 
39
40
  /**
@@ -61,6 +62,11 @@ export const EXTENSIONS: GLTFExtensionPlugin[] = [
61
62
  EXT_feature_metadata
62
63
  ];
63
64
 
65
+ /**
66
+ * List of extensions processed by the GLTFWriter
67
+ */
68
+ const EXTENSIONS_ENCODING: GLTFExtensionPlugin[] = [EXT_structural_metadata, EXT_mesh_features];
69
+
64
70
  /** Call before any resource loading starts */
65
71
  export function preprocessExtensions(gltf, options: GLTFLoaderOptions = {}, context?) {
66
72
  const extensions = EXTENSIONS.filter((extension) => useExtension(extension.name, options));
@@ -79,6 +85,14 @@ export async function decodeExtensions(gltf, options: GLTFLoaderOptions = {}, co
79
85
  }
80
86
  }
81
87
 
88
+ /** Call before resource writing */
89
+ export function encodeExtensions(gltf, options: GLTFWriterOptions = {}) {
90
+ for (const extension of EXTENSIONS_ENCODING) {
91
+ gltf = extension.encode?.(gltf, options) ?? gltf;
92
+ }
93
+ return gltf;
94
+ }
95
+
82
96
  function useExtension(extensionName: string, options: GLTFLoaderOptions) {
83
97
  const excludes = options?.gltf?.excludeExtensions || {};
84
98
  const exclude = extensionName in excludes && !excludes[extensionName];
@@ -557,9 +557,6 @@ export class GLTFScenegraph {
557
557
 
558
558
  /** Pack the binary chunk */
559
559
  createBinaryChunk(): void {
560
- // Encoder expects this array undefined or empty
561
- this.gltf.buffers = [];
562
-
563
560
  // Allocate total array
564
561
  const totalByteLength = this.byteLength;
565
562
  const arrayBuffer = new ArrayBuffer(totalByteLength);
@@ -583,6 +580,7 @@ export class GLTFScenegraph {
583
580
 
584
581
  // Put arrayBuffer to sourceBuffers for possible additional writing data in the chunk
585
582
  this.sourceBuffers = [arrayBuffer];
583
+ this.gltf.buffers = [{arrayBuffer, byteOffset: 0, byteLength: arrayBuffer.byteLength}];
586
584
  }
587
585
 
588
586
  // PRIVATE
@@ -1,4 +1,6 @@
1
1
  import {encodeGLBSync} from './encode-glb';
2
+ import {GLTFWriterOptions} from '../../gltf-writer';
3
+ import {GLTFWithBuffers} from '@loaders.gl/gltf';
2
4
 
3
5
  export type GLTFEncodeOptions = Record<string, any>;
4
6
 
@@ -19,16 +21,21 @@ export type GLTFEncodeOptions = Record<string, any>;
19
21
  * @param options
20
22
  * @returns
21
23
  */
22
- export function encodeGLTFSync(gltf, arrayBuffer, byteOffset, options) {
23
- convertBuffersToBase64(gltf);
24
+ export function encodeGLTFSync(
25
+ gltf: GLTFWithBuffers,
26
+ arrayBuffer: DataView | null,
27
+ byteOffset: number,
28
+ options: GLTFWriterOptions
29
+ ) {
30
+ validateGltf(gltf);
24
31
 
25
32
  // TODO: Copy buffers to binary
26
33
 
27
34
  return encodeGLBSync(gltf, arrayBuffer, byteOffset, options);
28
35
  }
29
36
 
30
- function convertBuffersToBase64(gltf, {firstBuffer = 0} = {}) {
31
- if (gltf.buffers && gltf.buffers.length > firstBuffer) {
37
+ function validateGltf(gltf) {
38
+ if (gltf.buffers && gltf.buffers.length > 1) {
32
39
  throw new Error('encodeGLTF: multiple buffers not yet implemented');
33
40
  }
34
41
  }
@@ -4,6 +4,7 @@
4
4
  import type {NumericArray} from '@loaders.gl/loader-utils';
5
5
  import type {GLTF, GLTFMeshPrimitive} from '../types/gltf-json-schema';
6
6
  import {GLTFLoaderOptions} from '../../gltf-loader';
7
+ import {GLTFWriterOptions} from '../../gltf-writer';
7
8
  import type {
8
9
  GLTF_EXT_mesh_features,
9
10
  GLTF_EXT_mesh_features_featureId
@@ -11,6 +12,7 @@ import type {
11
12
 
12
13
  import {GLTFScenegraph} from '../api/gltf-scenegraph';
13
14
  import {getPrimitiveTextureData} from './utils/3d-tiles-utils';
15
+ import {getComponentTypeFromArray} from '../gltf-utils/gltf-utils';
14
16
 
15
17
  const EXT_MESH_FEATURES_NAME = 'EXT_mesh_features';
16
18
  export const name = EXT_MESH_FEATURES_NAME;
@@ -20,6 +22,13 @@ export async function decode(gltfData: {json: GLTF}, options: GLTFLoaderOptions)
20
22
  decodeExtMeshFeatures(scenegraph, options);
21
23
  }
22
24
 
25
+ export function encode(gltfData: {json: GLTF}, options: GLTFWriterOptions): {json: GLTF} {
26
+ const scenegraph = new GLTFScenegraph(gltfData);
27
+ encodeExtMeshFeatures(scenegraph, options);
28
+ scenegraph.createBinaryChunk();
29
+ return scenegraph.gltf;
30
+ }
31
+
23
32
  /**
24
33
  * Decodes feature metadata from extension.
25
34
  * @param {GLTFScenegraph} scenegraph - Instance of the class for structured access to GLTF data.
@@ -91,3 +100,124 @@ function processMeshPrimitiveFeatures(
91
100
  featureId.data = featureIdData;
92
101
  }
93
102
  }
103
+
104
+ /*
105
+ Encoding data
106
+ */
107
+
108
+ function encodeExtMeshFeatures(scenegraph: GLTFScenegraph, options: GLTFWriterOptions) {
109
+ const meshes = scenegraph.gltf.json.meshes;
110
+ if (!meshes) {
111
+ return;
112
+ }
113
+
114
+ // Iterate through all meshes/primitives.
115
+ for (const mesh of meshes) {
116
+ for (const primitive of mesh.primitives) {
117
+ encodeExtMeshFeaturesForPrimitive(scenegraph, primitive);
118
+ }
119
+ }
120
+ }
121
+
122
+ /**
123
+ * Creates ExtMeshFeatures, creates a featureId containing feature ids provided.
124
+ * @param scenegraph - Instance of the class for structured access to GLTF data.
125
+ * @param primitive - target primitive instance that will contain the extension
126
+ * @param featureIdArray - Array of feature id
127
+ * @param propertyTableIndex - index of the property table created by the ExtStructuralMetadata (optional).
128
+ */
129
+ export function createExtMeshFeatures(
130
+ scenegraph: GLTFScenegraph,
131
+ primitive: GLTFMeshPrimitive,
132
+ featureIdArray: NumericArray,
133
+ propertyTableIndex?: number
134
+ ) {
135
+ if (!primitive.extensions) {
136
+ primitive.extensions = {};
137
+ }
138
+ let extension = primitive.extensions[EXT_MESH_FEATURES_NAME] as GLTF_EXT_mesh_features;
139
+ if (!extension) {
140
+ extension = {featureIds: []};
141
+ primitive.extensions[EXT_MESH_FEATURES_NAME] = extension;
142
+ }
143
+
144
+ const {featureIds} = extension;
145
+ const featureId: GLTF_EXT_mesh_features_featureId = {
146
+ featureCount: featureIdArray.length,
147
+ propertyTable: propertyTableIndex,
148
+ data: featureIdArray
149
+ };
150
+ featureIds.push(featureId);
151
+
152
+ scenegraph.addObjectExtension(primitive, EXT_MESH_FEATURES_NAME, extension);
153
+ }
154
+
155
+ /**
156
+ * Encodes a feature ID set to extension.
157
+ * @param scenegraph - Instance of the class for structured access to GLTF data.
158
+ * @param primitive - Primitive that the data encoded belongs to.
159
+ * @see https://github.com/CesiumGS/glTF/tree/3d-tiles-next/extensions/2.0/Vendor/EXT_mesh_features
160
+ */
161
+ function encodeExtMeshFeaturesForPrimitive(
162
+ scenegraph: GLTFScenegraph,
163
+ primitive: GLTFMeshPrimitive
164
+ ) {
165
+ const extension = primitive.extensions?.[EXT_MESH_FEATURES_NAME] as GLTF_EXT_mesh_features;
166
+ if (!extension) {
167
+ return;
168
+ }
169
+ const featureIds: GLTF_EXT_mesh_features_featureId[] = extension.featureIds;
170
+ featureIds.forEach((featureId, elementIndex) => {
171
+ if (featureId.data) {
172
+ const {accessorKey, index} = createAccessorKey(primitive.attributes);
173
+ const typedArray = new Uint32Array(featureId.data as NumericArray);
174
+
175
+ // Clean up featureId object.
176
+ // Everything that could come from the original extension in case of round-trip decode/encode operations should be deleted.
177
+ // We need make sure the featureId object is clean.
178
+ featureIds[elementIndex] = {
179
+ featureCount: typedArray.length,
180
+ propertyTable: featureId.propertyTable,
181
+ attribute: index
182
+ };
183
+
184
+ scenegraph.gltf.buffers.push({
185
+ arrayBuffer: typedArray.buffer,
186
+ byteOffset: typedArray.byteOffset,
187
+ byteLength: typedArray.byteLength
188
+ });
189
+
190
+ const bufferViewIndex = scenegraph.addBufferView(typedArray);
191
+ const accessorIndex = scenegraph.addAccessor(bufferViewIndex, {
192
+ size: 1,
193
+ componentType: getComponentTypeFromArray(typedArray),
194
+ count: typedArray.length
195
+ });
196
+ primitive.attributes[accessorKey] = accessorIndex;
197
+ }
198
+ });
199
+ }
200
+
201
+ /**
202
+ * Creates an accessor key for the attribute array provided.
203
+ * The generated key has a suffix (number) that is the next consequtive in the list of existing accessors.
204
+ * @param attributes - attribute array
205
+ * @returns accessor key and the key suffix (number) used in the key.
206
+ */
207
+ function createAccessorKey(attributes: {[k: string]: number}) {
208
+ const prefix = '_FEATURE_ID_';
209
+ // Search for all "_FEATURE_ID_n" attribures in the primitive provided if any.
210
+ // If there are some, e.g. "_FEATURE_ID_0", "_FEATURE_ID_1",
211
+ // we will add a new one with the name "_FEATURE_ID_2"
212
+ const attrs = Object.keys(attributes).filter((item) => item.indexOf(prefix) === 0);
213
+ let max = -1;
214
+ for (const a of attrs) {
215
+ const n = Number(a.substring(prefix.length));
216
+ if (n > max) {
217
+ max = n;
218
+ }
219
+ }
220
+ max++;
221
+ const accessorKey = `${prefix}${max}`;
222
+ return {accessorKey, index: max};
223
+ }
@@ -12,9 +12,11 @@ import type {
12
12
  GLTF_EXT_structural_metadata_GLTF,
13
13
  GLTF_EXT_structural_metadata_PropertyTexture,
14
14
  GLTF_EXT_structural_metadata_PropertyTable_Property,
15
- GLTF_EXT_structural_metadata_Primitive
15
+ GLTF_EXT_structural_metadata_Primitive,
16
+ GLTF_EXT_structural_metadata_Class
16
17
  } from '../types/gltf-ext-structural-metadata-schema';
17
18
  import type {GLTFLoaderOptions} from '../../gltf-loader';
19
+ import {GLTFWriterOptions} from '../../gltf-writer';
18
20
 
19
21
  import {GLTFScenegraph} from '../api/gltf-scenegraph';
20
22
  import {
@@ -37,6 +39,13 @@ export async function decode(gltfData: {json: GLTF}, options: GLTFLoaderOptions)
37
39
  decodeExtStructuralMetadata(scenegraph, options);
38
40
  }
39
41
 
42
+ export function encode(gltfData: {json: GLTF}, options: GLTFWriterOptions) {
43
+ const scenegraph = new GLTFScenegraph(gltfData);
44
+ encodeExtStructuralMetadata(scenegraph, options);
45
+ scenegraph.createBinaryChunk();
46
+ return scenegraph.gltf;
47
+ }
48
+
40
49
  /*
41
50
  // Example of the extension.
42
51
  // See more info at https://github.com/CesiumGS/glTF/tree/3d-tiles-next/extensions/2.0/Vendor/EXT_structural_metadata
@@ -701,3 +710,225 @@ function getEnumByValue(
701
710
 
702
711
  return null;
703
712
  }
713
+
714
+ /*
715
+ Encoding data
716
+ */
717
+
718
+ export interface PropertyAttribute {
719
+ name: string;
720
+ elementType: string;
721
+ componentType?: string;
722
+ values: number[] | string[];
723
+ }
724
+
725
+ const SCHEMA_CLASS_ID_DEFAULT = 'schemaClassId';
726
+
727
+ function encodeExtStructuralMetadata(scenegraph: GLTFScenegraph, options: GLTFWriterOptions) {
728
+ const extension: GLTF_EXT_structural_metadata_GLTF | null = scenegraph.getExtension(
729
+ EXT_STRUCTURAL_METADATA_NAME
730
+ );
731
+ if (!extension) {
732
+ return;
733
+ }
734
+ if (extension.propertyTables) {
735
+ for (const table of extension.propertyTables) {
736
+ const classId = table.class;
737
+ const schemaClass = extension.schema?.classes?.[classId];
738
+ if (table.properties && schemaClass) {
739
+ encodeProperties(table, schemaClass, scenegraph);
740
+ }
741
+ }
742
+ }
743
+ }
744
+
745
+ function encodeProperties(
746
+ table: GLTF_EXT_structural_metadata_PropertyTable,
747
+ schemaClass: GLTF_EXT_structural_metadata_Class,
748
+ scenegraph: GLTFScenegraph
749
+ ) {
750
+ for (const propertyName in table.properties) {
751
+ const data = table.properties[propertyName].data;
752
+ if (data) {
753
+ const classProperty = schemaClass.properties[propertyName];
754
+ if (classProperty) {
755
+ const tableProperty = createPropertyTableProperty(
756
+ data as number[] | string[],
757
+ classProperty,
758
+ scenegraph
759
+ );
760
+ // Override table property that came with "data"
761
+ table.properties[propertyName] = tableProperty;
762
+ }
763
+ }
764
+ }
765
+ }
766
+
767
+ /**
768
+ * Creates ExtStructuralMetadata, creates the schema and creates a property table containing feature data provided.
769
+ * @param scenegraph - Instance of the class for structured access to GLTF data.
770
+ * @param propertyAttributes - property attributes
771
+ * @param classId - classId to use for encoding metadata.
772
+ * @returns Index of the table created.
773
+ */
774
+ export function createExtStructuralMetadata(
775
+ scenegraph: GLTFScenegraph,
776
+ propertyAttributes: PropertyAttribute[],
777
+ classId: string = SCHEMA_CLASS_ID_DEFAULT
778
+ ): number {
779
+ let extension: GLTF_EXT_structural_metadata_GLTF | null = scenegraph.getExtension(
780
+ EXT_STRUCTURAL_METADATA_NAME
781
+ );
782
+ if (!extension) {
783
+ extension = scenegraph.addExtension(EXT_STRUCTURAL_METADATA_NAME);
784
+ }
785
+
786
+ extension.schema = createSchema(propertyAttributes, classId, extension.schema);
787
+ const table = createPropertyTable(propertyAttributes, classId, extension.schema);
788
+ if (!extension.propertyTables) {
789
+ extension.propertyTables = [];
790
+ }
791
+
792
+ return extension.propertyTables.push(table) - 1; // index of the table
793
+ }
794
+
795
+ function createSchema(
796
+ propertyAttributes: PropertyAttribute[],
797
+ classId: string,
798
+ schemaToUpdate?: GLTF_EXT_structural_metadata_Schema
799
+ ): GLTF_EXT_structural_metadata_Schema {
800
+ const schema: GLTF_EXT_structural_metadata_Schema = schemaToUpdate ?? {
801
+ id: 'schema_id'
802
+ };
803
+ const schemaClass: GLTF_EXT_structural_metadata_Class = {
804
+ properties: {}
805
+ };
806
+ for (const attribute of propertyAttributes) {
807
+ const classProperty: GLTF_EXT_structural_metadata_ClassProperty = {
808
+ type: attribute.elementType,
809
+ componentType: attribute.componentType
810
+ };
811
+ schemaClass.properties[attribute.name] = classProperty;
812
+ }
813
+
814
+ schema.classes = {};
815
+ schema.classes[classId] = schemaClass;
816
+ return schema;
817
+ }
818
+
819
+ function createPropertyTable(
820
+ propertyAttributes: PropertyAttribute[],
821
+ classId: string,
822
+ schema: GLTF_EXT_structural_metadata_Schema
823
+ ): GLTF_EXT_structural_metadata_PropertyTable {
824
+ const table: GLTF_EXT_structural_metadata_PropertyTable = {
825
+ class: classId,
826
+ count: 0
827
+ };
828
+ // count is a number of rows in the table
829
+ let count = 0;
830
+ const schemaClass = schema.classes?.[classId];
831
+
832
+ for (const attribute of propertyAttributes) {
833
+ if (count === 0) {
834
+ count = attribute.values.length;
835
+ }
836
+
837
+ // The number of elements in all propertyAttributes must be the same
838
+ if (count !== attribute.values.length && attribute.values.length) {
839
+ throw new Error('Illegal values in attributes');
840
+ }
841
+
842
+ const classProperty = schemaClass?.properties[attribute.name];
843
+ if (classProperty) {
844
+ // const tableProperty = createPropertyTableProperty(attribute, classProperty, scenegraph);
845
+ if (!table.properties) {
846
+ table.properties = {};
847
+ }
848
+ // values is a required field. Its real value will be set while encoding data
849
+ table.properties[attribute.name] = {values: 0, data: attribute.values};
850
+ }
851
+ }
852
+
853
+ table.count = count;
854
+ return table;
855
+ }
856
+
857
+ function createPropertyTableProperty(
858
+ // attribute: PropertyAttribute,
859
+ values: number[] | string[],
860
+ classProperty: GLTF_EXT_structural_metadata_ClassProperty,
861
+ scenegraph: GLTFScenegraph
862
+ ): GLTF_EXT_structural_metadata_PropertyTable_Property {
863
+ const prop: GLTF_EXT_structural_metadata_PropertyTable_Property = {values: 0};
864
+
865
+ if (classProperty.type === 'STRING') {
866
+ const {stringData, stringOffsets} = createPropertyDataString(values as string[]);
867
+ prop.stringOffsets = createBufferView(stringOffsets, scenegraph);
868
+ prop.values = createBufferView(stringData, scenegraph);
869
+ } else if (classProperty.type === 'SCALAR' && classProperty.componentType) {
870
+ const data = createPropertyDataScalar(values as number[], classProperty.componentType);
871
+ prop.values = createBufferView(data, scenegraph);
872
+ }
873
+
874
+ return prop;
875
+ }
876
+
877
+ const COMPONENT_TYPE_TO_ARRAY_CONSTRUCTOR = {
878
+ INT8: Int8Array,
879
+ UINT8: Uint8Array,
880
+ INT16: Int16Array,
881
+ UINT16: Uint16Array,
882
+ INT32: Int32Array,
883
+ UINT32: Uint32Array,
884
+ INT64: Int32Array,
885
+ UINT64: Uint32Array,
886
+ FLOAT32: Float32Array,
887
+ FLOAT64: Float64Array
888
+ };
889
+
890
+ function createPropertyDataScalar(array: number[], componentType: string): TypedArray {
891
+ const numberArray: number[] = [];
892
+ for (const value of array) {
893
+ numberArray.push(Number(value));
894
+ }
895
+ const Construct = COMPONENT_TYPE_TO_ARRAY_CONSTRUCTOR[componentType];
896
+ if (!Construct) {
897
+ throw new Error('Illegal component type');
898
+ }
899
+ return new Construct(numberArray);
900
+ }
901
+
902
+ function createPropertyDataString(strings: string[]): {
903
+ stringData: TypedArray;
904
+ stringOffsets: TypedArray;
905
+ } {
906
+ const utf8Encode = new TextEncoder();
907
+ const arr: Uint8Array[] = [];
908
+ let len = 0;
909
+ for (const str of strings) {
910
+ const uint8Array = utf8Encode.encode(str);
911
+ len += uint8Array.length;
912
+ arr.push(uint8Array);
913
+ }
914
+ const strArray = new Uint8Array(len);
915
+ const strOffsets: number[] = [];
916
+ let offset = 0;
917
+ for (const str of arr) {
918
+ strArray.set(str, offset);
919
+ strOffsets.push(offset);
920
+ offset += str.length;
921
+ }
922
+ strOffsets.push(offset); // The last offset represents the byte offset after the last string.
923
+ const stringOffsetsTypedArray = new Uint32Array(strOffsets); // Its length = len+1
924
+ return {stringData: strArray, stringOffsets: stringOffsetsTypedArray};
925
+ }
926
+
927
+ function createBufferView(typedArray: TypedArray, scenegraph: GLTFScenegraph): number {
928
+ scenegraph.gltf.buffers.push({
929
+ arrayBuffer: typedArray.buffer,
930
+ byteOffset: typedArray.byteOffset,
931
+ byteLength: typedArray.byteLength
932
+ });
933
+ return scenegraph.addBufferView(typedArray);
934
+ }
@@ -5,8 +5,7 @@
5
5
  import type {LoaderContext} from '@loaders.gl/loader-utils';
6
6
  import {sliceArrayBuffer, parseFromContext} from '@loaders.gl/loader-utils';
7
7
 
8
- import {DracoLoader} from '@loaders.gl/draco';
9
- import {DracoLoaderOptions} from '@loaders.gl/draco';
8
+ import {DracoLoader, DracoLoaderOptions} from '@loaders.gl/draco';
10
9
 
11
10
  import type {
12
11
  GLTF,