@loaders.gl/draco 4.2.0-alpha.4 → 4.2.0-alpha.6

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 (56) hide show
  1. package/dist/dist.dev.js +268 -79
  2. package/dist/dist.min.js +11 -0
  3. package/dist/draco-loader.d.ts +2 -2
  4. package/dist/draco-loader.d.ts.map +1 -1
  5. package/dist/draco-loader.js +23 -17
  6. package/dist/draco-worker-node.js +186 -127
  7. package/dist/draco-worker-node.js.map +3 -3
  8. package/dist/draco-worker.js +5 -3
  9. package/dist/draco-worker.js.map +2 -2
  10. package/dist/draco-writer-worker-node.js +188 -127
  11. package/dist/draco-writer-worker-node.js.map +3 -3
  12. package/dist/draco-writer-worker.js +5 -3
  13. package/dist/draco-writer-worker.js.map +2 -2
  14. package/dist/draco-writer.d.ts +2 -2
  15. package/dist/draco-writer.d.ts.map +1 -1
  16. package/dist/draco-writer.js +30 -23
  17. package/dist/draco3d/draco3d-types.js +48 -41
  18. package/dist/index.cjs +34 -71
  19. package/dist/index.cjs.map +7 -0
  20. package/dist/index.d.ts +6 -6
  21. package/dist/index.d.ts.map +1 -1
  22. package/dist/index.js +27 -21
  23. package/dist/lib/draco-builder.d.ts +2 -2
  24. package/dist/lib/draco-builder.d.ts.map +1 -1
  25. package/dist/lib/draco-builder.js +314 -243
  26. package/dist/lib/draco-module-loader.js +78 -62
  27. package/dist/lib/draco-parser.d.ts +2 -2
  28. package/dist/lib/draco-parser.d.ts.map +1 -1
  29. package/dist/lib/draco-parser.js +437 -323
  30. package/dist/lib/draco-types.js +1 -1
  31. package/dist/lib/utils/get-draco-schema.d.ts +1 -1
  32. package/dist/lib/utils/get-draco-schema.d.ts.map +1 -1
  33. package/dist/lib/utils/get-draco-schema.js +29 -32
  34. package/dist/lib/utils/version.js +4 -2
  35. package/dist/workers/draco-worker-node.js +1 -1
  36. package/dist/workers/draco-worker.js +0 -1
  37. package/dist/workers/draco-writer-worker-node.js +20 -25
  38. package/dist/workers/draco-writer-worker.js +19 -25
  39. package/package.json +10 -10
  40. package/dist/draco-loader.js.map +0 -1
  41. package/dist/draco-writer.js.map +0 -1
  42. package/dist/draco3d/draco3d-types.js.map +0 -1
  43. package/dist/index.js.map +0 -1
  44. package/dist/lib/draco-builder.js.map +0 -1
  45. package/dist/lib/draco-module-loader.js.map +0 -1
  46. package/dist/lib/draco-parser.js.map +0 -1
  47. package/dist/lib/draco-types.js.map +0 -1
  48. package/dist/lib/utils/get-draco-schema.js.map +0 -1
  49. package/dist/lib/utils/version.js.map +0 -1
  50. package/dist/libs/libs/draco_decoder.wasm +0 -0
  51. package/dist/libs/libs/draco_encoder.js +0 -52
  52. package/dist/libs/libs/draco_wasm_wrapper.js +0 -117
  53. package/dist/workers/draco-worker-node.js.map +0 -1
  54. package/dist/workers/draco-worker.js.map +0 -1
  55. package/dist/workers/draco-writer-worker-node.js.map +0 -1
  56. package/dist/workers/draco-writer-worker.js.map +0 -1
@@ -1,362 +1,476 @@
1
+ /* eslint-disable camelcase */
1
2
  import { getMeshBoundingBox } from '@loaders.gl/schema';
2
3
  import { getDracoSchema } from "./utils/get-draco-schema.js";
4
+ // @ts-ignore
5
+ // eslint-disable-next-line @typescript-eslint/no-unused-vars
3
6
  const GEOMETRY_TYPE = {
4
- TRIANGULAR_MESH: 0,
5
- POINT_CLOUD: 1
7
+ TRIANGULAR_MESH: 0,
8
+ POINT_CLOUD: 1
6
9
  };
10
+ // Native Draco attribute names to GLTF attribute names.
7
11
  const DRACO_TO_GLTF_ATTRIBUTE_NAME_MAP = {
8
- POSITION: 'POSITION',
9
- NORMAL: 'NORMAL',
10
- COLOR: 'COLOR_0',
11
- TEX_COORD: 'TEXCOORD_0'
12
+ POSITION: 'POSITION',
13
+ NORMAL: 'NORMAL',
14
+ COLOR: 'COLOR_0',
15
+ TEX_COORD: 'TEXCOORD_0'
12
16
  };
13
17
  const DRACO_DATA_TYPE_TO_TYPED_ARRAY_MAP = {
14
- 1: Int8Array,
15
- 2: Uint8Array,
16
- 3: Int16Array,
17
- 4: Uint16Array,
18
- 5: Int32Array,
19
- 6: Uint32Array,
20
- 9: Float32Array
18
+ 1: Int8Array,
19
+ 2: Uint8Array,
20
+ 3: Int16Array,
21
+ 4: Uint16Array,
22
+ 5: Int32Array,
23
+ 6: Uint32Array,
24
+ 9: Float32Array
21
25
  };
22
26
  const INDEX_ITEM_SIZE = 4;
23
27
  export default class DracoParser {
24
- constructor(draco) {
25
- this.draco = void 0;
26
- this.decoder = void 0;
27
- this.metadataQuerier = void 0;
28
- this.draco = draco;
29
- this.decoder = new this.draco.Decoder();
30
- this.metadataQuerier = new this.draco.MetadataQuerier();
31
- }
32
- destroy() {
33
- this.draco.destroy(this.decoder);
34
- this.draco.destroy(this.metadataQuerier);
35
- }
36
- parseSync(arrayBuffer) {
37
- let options = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : {};
38
- const buffer = new this.draco.DecoderBuffer();
39
- buffer.Init(new Int8Array(arrayBuffer), arrayBuffer.byteLength);
40
- this._disableAttributeTransforms(options);
41
- const geometry_type = this.decoder.GetEncodedGeometryType(buffer);
42
- const dracoGeometry = geometry_type === this.draco.TRIANGULAR_MESH ? new this.draco.Mesh() : new this.draco.PointCloud();
43
- try {
44
- let dracoStatus;
45
- switch (geometry_type) {
46
- case this.draco.TRIANGULAR_MESH:
47
- dracoStatus = this.decoder.DecodeBufferToMesh(buffer, dracoGeometry);
48
- break;
49
- case this.draco.POINT_CLOUD:
50
- dracoStatus = this.decoder.DecodeBufferToPointCloud(buffer, dracoGeometry);
51
- break;
52
- default:
53
- throw new Error('DRACO: Unknown geometry type.');
54
- }
55
- if (!dracoStatus.ok() || !dracoGeometry.ptr) {
56
- const message = `DRACO decompression failed: ${dracoStatus.error_msg()}`;
57
- throw new Error(message);
58
- }
59
- const loaderData = this._getDracoLoaderData(dracoGeometry, geometry_type, options);
60
- const geometry = this._getMeshData(dracoGeometry, loaderData, options);
61
- const boundingBox = getMeshBoundingBox(geometry.attributes);
62
- const schema = getDracoSchema(geometry.attributes, loaderData, geometry.indices);
63
- const data = {
64
- loader: 'draco',
65
- loaderData,
66
- header: {
67
- vertexCount: dracoGeometry.num_points(),
68
- boundingBox
69
- },
70
- ...geometry,
71
- schema
72
- };
73
- return data;
74
- } finally {
75
- this.draco.destroy(buffer);
76
- if (dracoGeometry) {
77
- this.draco.destroy(dracoGeometry);
78
- }
28
+ draco;
29
+ decoder;
30
+ metadataQuerier;
31
+ // draco - the draco decoder, either import `draco3d` or load dynamically
32
+ constructor(draco) {
33
+ this.draco = draco;
34
+ this.decoder = new this.draco.Decoder();
35
+ this.metadataQuerier = new this.draco.MetadataQuerier();
79
36
  }
80
- }
81
- _getDracoLoaderData(dracoGeometry, geometry_type, options) {
82
- const metadata = this._getTopLevelMetadata(dracoGeometry);
83
- const attributes = this._getDracoAttributes(dracoGeometry, options);
84
- return {
85
- geometry_type,
86
- num_attributes: dracoGeometry.num_attributes(),
87
- num_points: dracoGeometry.num_points(),
88
- num_faces: dracoGeometry instanceof this.draco.Mesh ? dracoGeometry.num_faces() : 0,
89
- metadata,
90
- attributes
91
- };
92
- }
93
- _getDracoAttributes(dracoGeometry, options) {
94
- const dracoAttributes = {};
95
- for (let attributeId = 0; attributeId < dracoGeometry.num_attributes(); attributeId++) {
96
- const dracoAttribute = this.decoder.GetAttribute(dracoGeometry, attributeId);
97
- const metadata = this._getAttributeMetadata(dracoGeometry, attributeId);
98
- dracoAttributes[dracoAttribute.unique_id()] = {
99
- unique_id: dracoAttribute.unique_id(),
100
- attribute_type: dracoAttribute.attribute_type(),
101
- data_type: dracoAttribute.data_type(),
102
- num_components: dracoAttribute.num_components(),
103
- byte_offset: dracoAttribute.byte_offset(),
104
- byte_stride: dracoAttribute.byte_stride(),
105
- normalized: dracoAttribute.normalized(),
106
- attribute_index: attributeId,
107
- metadata
108
- };
109
- const quantization = this._getQuantizationTransform(dracoAttribute, options);
110
- if (quantization) {
111
- dracoAttributes[dracoAttribute.unique_id()].quantization_transform = quantization;
112
- }
113
- const octahedron = this._getOctahedronTransform(dracoAttribute, options);
114
- if (octahedron) {
115
- dracoAttributes[dracoAttribute.unique_id()].octahedron_transform = octahedron;
116
- }
37
+ /**
38
+ * Destroy draco resources
39
+ */
40
+ destroy() {
41
+ this.draco.destroy(this.decoder);
42
+ this.draco.destroy(this.metadataQuerier);
43
+ }
44
+ /**
45
+ * NOTE: caller must call `destroyGeometry` on the return value after using it
46
+ * @param arrayBuffer
47
+ * @param options
48
+ */
49
+ parseSync(arrayBuffer, options = {}) {
50
+ const buffer = new this.draco.DecoderBuffer();
51
+ buffer.Init(new Int8Array(arrayBuffer), arrayBuffer.byteLength);
52
+ this._disableAttributeTransforms(options);
53
+ const geometry_type = this.decoder.GetEncodedGeometryType(buffer);
54
+ const dracoGeometry = geometry_type === this.draco.TRIANGULAR_MESH
55
+ ? new this.draco.Mesh()
56
+ : new this.draco.PointCloud();
57
+ try {
58
+ let dracoStatus;
59
+ switch (geometry_type) {
60
+ case this.draco.TRIANGULAR_MESH:
61
+ dracoStatus = this.decoder.DecodeBufferToMesh(buffer, dracoGeometry);
62
+ break;
63
+ case this.draco.POINT_CLOUD:
64
+ dracoStatus = this.decoder.DecodeBufferToPointCloud(buffer, dracoGeometry);
65
+ break;
66
+ default:
67
+ throw new Error('DRACO: Unknown geometry type.');
68
+ }
69
+ if (!dracoStatus.ok() || !dracoGeometry.ptr) {
70
+ const message = `DRACO decompression failed: ${dracoStatus.error_msg()}`;
71
+ // console.error(message);
72
+ throw new Error(message);
73
+ }
74
+ const loaderData = this._getDracoLoaderData(dracoGeometry, geometry_type, options);
75
+ const geometry = this._getMeshData(dracoGeometry, loaderData, options);
76
+ const boundingBox = getMeshBoundingBox(geometry.attributes);
77
+ const schema = getDracoSchema(geometry.attributes, loaderData, geometry.indices);
78
+ const data = {
79
+ loader: 'draco',
80
+ loaderData,
81
+ header: {
82
+ vertexCount: dracoGeometry.num_points(),
83
+ boundingBox
84
+ },
85
+ ...geometry,
86
+ schema
87
+ };
88
+ return data;
89
+ }
90
+ finally {
91
+ this.draco.destroy(buffer);
92
+ if (dracoGeometry) {
93
+ this.draco.destroy(dracoGeometry);
94
+ }
95
+ }
117
96
  }
118
- return dracoAttributes;
119
- }
120
- _getMeshData(dracoGeometry, loaderData, options) {
121
- const attributes = this._getMeshAttributes(loaderData, dracoGeometry, options);
122
- const positionAttribute = attributes.POSITION;
123
- if (!positionAttribute) {
124
- throw new Error('DRACO: No position attribute found.');
97
+ // Draco specific "loader data"
98
+ /**
99
+ * Extract
100
+ * @param dracoGeometry
101
+ * @param geometry_type
102
+ * @param options
103
+ * @returns
104
+ */
105
+ _getDracoLoaderData(dracoGeometry, geometry_type, options) {
106
+ const metadata = this._getTopLevelMetadata(dracoGeometry);
107
+ const attributes = this._getDracoAttributes(dracoGeometry, options);
108
+ return {
109
+ geometry_type,
110
+ num_attributes: dracoGeometry.num_attributes(),
111
+ num_points: dracoGeometry.num_points(),
112
+ num_faces: dracoGeometry instanceof this.draco.Mesh ? dracoGeometry.num_faces() : 0,
113
+ metadata,
114
+ attributes
115
+ };
125
116
  }
126
- if (dracoGeometry instanceof this.draco.Mesh) {
127
- switch (options.topology) {
128
- case 'triangle-strip':
129
- return {
130
- topology: 'triangle-strip',
131
- mode: 4,
132
- attributes,
133
- indices: {
134
- value: this._getTriangleStripIndices(dracoGeometry),
135
- size: 1
117
+ /**
118
+ * Extract all draco provided information and metadata for each attribute
119
+ * @param dracoGeometry
120
+ * @param options
121
+ * @returns
122
+ */
123
+ _getDracoAttributes(dracoGeometry, options) {
124
+ const dracoAttributes = {};
125
+ for (let attributeId = 0; attributeId < dracoGeometry.num_attributes(); attributeId++) {
126
+ // Note: Draco docs do not seem clear on `GetAttribute` ids just being a zero-based index,
127
+ // but it does seems to work this way
128
+ const dracoAttribute = this.decoder.GetAttribute(dracoGeometry, attributeId);
129
+ const metadata = this._getAttributeMetadata(dracoGeometry, attributeId);
130
+ dracoAttributes[dracoAttribute.unique_id()] = {
131
+ unique_id: dracoAttribute.unique_id(),
132
+ attribute_type: dracoAttribute.attribute_type(),
133
+ data_type: dracoAttribute.data_type(),
134
+ num_components: dracoAttribute.num_components(),
135
+ byte_offset: dracoAttribute.byte_offset(),
136
+ byte_stride: dracoAttribute.byte_stride(),
137
+ normalized: dracoAttribute.normalized(),
138
+ attribute_index: attributeId,
139
+ metadata
140
+ };
141
+ // Add transformation parameters for any attributes app wants untransformed
142
+ const quantization = this._getQuantizationTransform(dracoAttribute, options);
143
+ if (quantization) {
144
+ dracoAttributes[dracoAttribute.unique_id()].quantization_transform = quantization;
136
145
  }
137
- };
138
- case 'triangle-list':
139
- default:
140
- return {
141
- topology: 'triangle-list',
142
- mode: 5,
143
- attributes,
144
- indices: {
145
- value: this._getTriangleListIndices(dracoGeometry),
146
- size: 1
146
+ const octahedron = this._getOctahedronTransform(dracoAttribute, options);
147
+ if (octahedron) {
148
+ dracoAttributes[dracoAttribute.unique_id()].octahedron_transform = octahedron;
147
149
  }
148
- };
149
- }
150
+ }
151
+ return dracoAttributes;
150
152
  }
151
- return {
152
- topology: 'point-list',
153
- mode: 0,
154
- attributes
155
- };
156
- }
157
- _getMeshAttributes(loaderData, dracoGeometry, options) {
158
- const attributes = {};
159
- for (const loaderAttribute of Object.values(loaderData.attributes)) {
160
- const attributeName = this._deduceAttributeName(loaderAttribute, options);
161
- loaderAttribute.name = attributeName;
162
- const {
163
- value,
164
- size
165
- } = this._getAttributeValues(dracoGeometry, loaderAttribute);
166
- attributes[attributeName] = {
167
- value,
168
- size,
169
- byteOffset: loaderAttribute.byte_offset,
170
- byteStride: loaderAttribute.byte_stride,
171
- normalized: loaderAttribute.normalized
172
- };
153
+ /**
154
+ * Get standard loaders.gl mesh category data
155
+ * Extracts the geometry from draco
156
+ * @param dracoGeometry
157
+ * @param options
158
+ */
159
+ _getMeshData(dracoGeometry, loaderData, options) {
160
+ const attributes = this._getMeshAttributes(loaderData, dracoGeometry, options);
161
+ const positionAttribute = attributes.POSITION;
162
+ if (!positionAttribute) {
163
+ throw new Error('DRACO: No position attribute found.');
164
+ }
165
+ // For meshes, we need indices to define the faces.
166
+ if (dracoGeometry instanceof this.draco.Mesh) {
167
+ switch (options.topology) {
168
+ case 'triangle-strip':
169
+ return {
170
+ topology: 'triangle-strip',
171
+ mode: 4, // GL.TRIANGLES
172
+ attributes,
173
+ indices: {
174
+ value: this._getTriangleStripIndices(dracoGeometry),
175
+ size: 1
176
+ }
177
+ };
178
+ case 'triangle-list':
179
+ default:
180
+ return {
181
+ topology: 'triangle-list',
182
+ mode: 5, // GL.TRIANGLE_STRIP
183
+ attributes,
184
+ indices: {
185
+ value: this._getTriangleListIndices(dracoGeometry),
186
+ size: 1
187
+ }
188
+ };
189
+ }
190
+ }
191
+ // PointCloud - must come last as Mesh inherits from PointCloud
192
+ return {
193
+ topology: 'point-list',
194
+ mode: 0, // GL.POINTS
195
+ attributes
196
+ };
173
197
  }
174
- return attributes;
175
- }
176
- _getTriangleListIndices(dracoGeometry) {
177
- const numFaces = dracoGeometry.num_faces();
178
- const numIndices = numFaces * 3;
179
- const byteLength = numIndices * INDEX_ITEM_SIZE;
180
- const ptr = this.draco._malloc(byteLength);
181
- try {
182
- this.decoder.GetTrianglesUInt32Array(dracoGeometry, byteLength, ptr);
183
- return new Uint32Array(this.draco.HEAPF32.buffer, ptr, numIndices).slice();
184
- } finally {
185
- this.draco._free(ptr);
198
+ _getMeshAttributes(loaderData, dracoGeometry, options) {
199
+ const attributes = {};
200
+ for (const loaderAttribute of Object.values(loaderData.attributes)) {
201
+ const attributeName = this._deduceAttributeName(loaderAttribute, options);
202
+ loaderAttribute.name = attributeName;
203
+ const { value, size } = this._getAttributeValues(dracoGeometry, loaderAttribute);
204
+ attributes[attributeName] = {
205
+ value,
206
+ size,
207
+ byteOffset: loaderAttribute.byte_offset,
208
+ byteStride: loaderAttribute.byte_stride,
209
+ normalized: loaderAttribute.normalized
210
+ };
211
+ }
212
+ return attributes;
186
213
  }
187
- }
188
- _getTriangleStripIndices(dracoGeometry) {
189
- const dracoArray = new this.draco.DracoInt32Array();
190
- try {
191
- this.decoder.GetTriangleStripsFromMesh(dracoGeometry, dracoArray);
192
- return getUint32Array(dracoArray);
193
- } finally {
194
- this.draco.destroy(dracoArray);
214
+ // MESH INDICES EXTRACTION
215
+ /**
216
+ * For meshes, we need indices to define the faces.
217
+ * @param dracoGeometry
218
+ */
219
+ _getTriangleListIndices(dracoGeometry) {
220
+ // Example on how to retrieve mesh and attributes.
221
+ const numFaces = dracoGeometry.num_faces();
222
+ const numIndices = numFaces * 3;
223
+ const byteLength = numIndices * INDEX_ITEM_SIZE;
224
+ const ptr = this.draco._malloc(byteLength);
225
+ try {
226
+ this.decoder.GetTrianglesUInt32Array(dracoGeometry, byteLength, ptr);
227
+ return new Uint32Array(this.draco.HEAPF32.buffer, ptr, numIndices).slice();
228
+ }
229
+ finally {
230
+ this.draco._free(ptr);
231
+ }
195
232
  }
196
- }
197
- _getAttributeValues(dracoGeometry, attribute) {
198
- const TypedArrayCtor = DRACO_DATA_TYPE_TO_TYPED_ARRAY_MAP[attribute.data_type];
199
- const numComponents = attribute.num_components;
200
- const numPoints = dracoGeometry.num_points();
201
- const numValues = numPoints * numComponents;
202
- const byteLength = numValues * TypedArrayCtor.BYTES_PER_ELEMENT;
203
- const dataType = getDracoDataType(this.draco, TypedArrayCtor);
204
- let value;
205
- const ptr = this.draco._malloc(byteLength);
206
- try {
207
- const dracoAttribute = this.decoder.GetAttribute(dracoGeometry, attribute.attribute_index);
208
- this.decoder.GetAttributeDataArrayForAllPoints(dracoGeometry, dracoAttribute, dataType, byteLength, ptr);
209
- value = new TypedArrayCtor(this.draco.HEAPF32.buffer, ptr, numValues).slice();
210
- } finally {
211
- this.draco._free(ptr);
233
+ /**
234
+ * For meshes, we need indices to define the faces.
235
+ * @param dracoGeometry
236
+ */
237
+ _getTriangleStripIndices(dracoGeometry) {
238
+ const dracoArray = new this.draco.DracoInt32Array();
239
+ try {
240
+ /* const numStrips = */ this.decoder.GetTriangleStripsFromMesh(dracoGeometry, dracoArray);
241
+ return getUint32Array(dracoArray);
242
+ }
243
+ finally {
244
+ this.draco.destroy(dracoArray);
245
+ }
212
246
  }
213
- return {
214
- value,
215
- size: numComponents
216
- };
217
- }
218
- _deduceAttributeName(attribute, options) {
219
- const uniqueId = attribute.unique_id;
220
- for (const [attributeName, attributeUniqueId] of Object.entries(options.extraAttributes || {})) {
221
- if (attributeUniqueId === uniqueId) {
222
- return attributeName;
223
- }
247
+ /**
248
+ *
249
+ * @param dracoGeometry
250
+ * @param dracoAttribute
251
+ * @param attributeName
252
+ */
253
+ _getAttributeValues(dracoGeometry, attribute) {
254
+ const TypedArrayCtor = DRACO_DATA_TYPE_TO_TYPED_ARRAY_MAP[attribute.data_type];
255
+ const numComponents = attribute.num_components;
256
+ const numPoints = dracoGeometry.num_points();
257
+ const numValues = numPoints * numComponents;
258
+ const byteLength = numValues * TypedArrayCtor.BYTES_PER_ELEMENT;
259
+ const dataType = getDracoDataType(this.draco, TypedArrayCtor);
260
+ let value;
261
+ const ptr = this.draco._malloc(byteLength);
262
+ try {
263
+ const dracoAttribute = this.decoder.GetAttribute(dracoGeometry, attribute.attribute_index);
264
+ this.decoder.GetAttributeDataArrayForAllPoints(dracoGeometry, dracoAttribute, dataType, byteLength, ptr);
265
+ value = new TypedArrayCtor(this.draco.HEAPF32.buffer, ptr, numValues).slice();
266
+ }
267
+ finally {
268
+ this.draco._free(ptr);
269
+ }
270
+ return { value, size: numComponents };
224
271
  }
225
- const thisAttributeType = attribute.attribute_type;
226
- for (const dracoAttributeConstant in DRACO_TO_GLTF_ATTRIBUTE_NAME_MAP) {
227
- const attributeType = this.draco[dracoAttributeConstant];
228
- if (attributeType === thisAttributeType) {
229
- return DRACO_TO_GLTF_ATTRIBUTE_NAME_MAP[dracoAttributeConstant];
272
+ // Attribute names
273
+ /**
274
+ * DRACO does not store attribute names - We need to deduce an attribute name
275
+ * for each attribute
276
+ _getAttributeNames(
277
+ dracoGeometry: Mesh | PointCloud,
278
+ options: DracoParseOptions
279
+ ): {[unique_id: number]: string} {
280
+ const attributeNames: {[unique_id: number]: string} = {};
281
+ for (let attributeId = 0; attributeId < dracoGeometry.num_attributes(); attributeId++) {
282
+ const dracoAttribute = this.decoder.GetAttribute(dracoGeometry, attributeId);
283
+ const attributeName = this._deduceAttributeName(dracoAttribute, options);
284
+ attributeNames[attributeName] = attributeName;
230
285
  }
286
+ return attributeNames;
231
287
  }
232
- const entryName = options.attributeNameEntry || 'name';
233
- if (attribute.metadata[entryName]) {
234
- return attribute.metadata[entryName].string;
288
+ */
289
+ /**
290
+ * Deduce an attribute name.
291
+ * @note DRACO does not save attribute names, just general type (POSITION, COLOR)
292
+ * to help optimize compression. We generate GLTF compatible names for the Draco-recognized
293
+ * types
294
+ * @param attributeData
295
+ */
296
+ _deduceAttributeName(attribute, options) {
297
+ // Deduce name based on application provided map
298
+ const uniqueId = attribute.unique_id;
299
+ for (const [attributeName, attributeUniqueId] of Object.entries(options.extraAttributes || {})) {
300
+ if (attributeUniqueId === uniqueId) {
301
+ return attributeName;
302
+ }
303
+ }
304
+ // Deduce name based on attribute type
305
+ const thisAttributeType = attribute.attribute_type;
306
+ for (const dracoAttributeConstant in DRACO_TO_GLTF_ATTRIBUTE_NAME_MAP) {
307
+ const attributeType = this.draco[dracoAttributeConstant];
308
+ if (attributeType === thisAttributeType) {
309
+ // TODO - Return unique names if there multiple attributes per type
310
+ // (e.g. multiple TEX_COORDS or COLORS)
311
+ return DRACO_TO_GLTF_ATTRIBUTE_NAME_MAP[dracoAttributeConstant];
312
+ }
313
+ }
314
+ // Look up in metadata
315
+ // TODO - shouldn't this have priority?
316
+ const entryName = options.attributeNameEntry || 'name';
317
+ if (attribute.metadata[entryName]) {
318
+ return attribute.metadata[entryName].string;
319
+ }
320
+ // Attribute of "GENERIC" type, we need to assign some name
321
+ return `CUSTOM_ATTRIBUTE_${uniqueId}`;
235
322
  }
236
- return `CUSTOM_ATTRIBUTE_${uniqueId}`;
237
- }
238
- _getTopLevelMetadata(dracoGeometry) {
239
- const dracoMetadata = this.decoder.GetMetadata(dracoGeometry);
240
- return this._getDracoMetadata(dracoMetadata);
241
- }
242
- _getAttributeMetadata(dracoGeometry, attributeId) {
243
- const dracoMetadata = this.decoder.GetAttributeMetadata(dracoGeometry, attributeId);
244
- return this._getDracoMetadata(dracoMetadata);
245
- }
246
- _getDracoMetadata(dracoMetadata) {
247
- if (!dracoMetadata || !dracoMetadata.ptr) {
248
- return {};
323
+ // METADATA EXTRACTION
324
+ /** Get top level metadata */
325
+ _getTopLevelMetadata(dracoGeometry) {
326
+ const dracoMetadata = this.decoder.GetMetadata(dracoGeometry);
327
+ return this._getDracoMetadata(dracoMetadata);
249
328
  }
250
- const result = {};
251
- const numEntries = this.metadataQuerier.NumEntries(dracoMetadata);
252
- for (let entryIndex = 0; entryIndex < numEntries; entryIndex++) {
253
- const entryName = this.metadataQuerier.GetEntryName(dracoMetadata, entryIndex);
254
- result[entryName] = this._getDracoMetadataField(dracoMetadata, entryName);
329
+ /** Get per attribute metadata */
330
+ _getAttributeMetadata(dracoGeometry, attributeId) {
331
+ const dracoMetadata = this.decoder.GetAttributeMetadata(dracoGeometry, attributeId);
332
+ return this._getDracoMetadata(dracoMetadata);
255
333
  }
256
- return result;
257
- }
258
- _getDracoMetadataField(dracoMetadata, entryName) {
259
- const dracoArray = new this.draco.DracoInt32Array();
260
- try {
261
- this.metadataQuerier.GetIntEntryArray(dracoMetadata, entryName, dracoArray);
262
- const intArray = getInt32Array(dracoArray);
263
- return {
264
- int: this.metadataQuerier.GetIntEntry(dracoMetadata, entryName),
265
- string: this.metadataQuerier.GetStringEntry(dracoMetadata, entryName),
266
- double: this.metadataQuerier.GetDoubleEntry(dracoMetadata, entryName),
267
- intArray
268
- };
269
- } finally {
270
- this.draco.destroy(dracoArray);
334
+ /**
335
+ * Extract metadata field values
336
+ * @param dracoMetadata
337
+ * @returns
338
+ */
339
+ _getDracoMetadata(dracoMetadata) {
340
+ // The not so wonderful world of undocumented Draco APIs :(
341
+ if (!dracoMetadata || !dracoMetadata.ptr) {
342
+ return {};
343
+ }
344
+ const result = {};
345
+ const numEntries = this.metadataQuerier.NumEntries(dracoMetadata);
346
+ for (let entryIndex = 0; entryIndex < numEntries; entryIndex++) {
347
+ const entryName = this.metadataQuerier.GetEntryName(dracoMetadata, entryIndex);
348
+ result[entryName] = this._getDracoMetadataField(dracoMetadata, entryName);
349
+ }
350
+ return result;
271
351
  }
272
- }
273
- _disableAttributeTransforms(options) {
274
- const {
275
- quantizedAttributes = [],
276
- octahedronAttributes = []
277
- } = options;
278
- const skipAttributes = [...quantizedAttributes, ...octahedronAttributes];
279
- for (const dracoAttributeName of skipAttributes) {
280
- this.decoder.SkipAttributeTransform(this.draco[dracoAttributeName]);
352
+ /**
353
+ * Extracts possible values for one metadata entry by name
354
+ * @param dracoMetadata
355
+ * @param entryName
356
+ */
357
+ _getDracoMetadataField(dracoMetadata, entryName) {
358
+ const dracoArray = new this.draco.DracoInt32Array();
359
+ try {
360
+ // Draco metadata fields can hold int32 arrays
361
+ this.metadataQuerier.GetIntEntryArray(dracoMetadata, entryName, dracoArray);
362
+ const intArray = getInt32Array(dracoArray);
363
+ return {
364
+ int: this.metadataQuerier.GetIntEntry(dracoMetadata, entryName),
365
+ string: this.metadataQuerier.GetStringEntry(dracoMetadata, entryName),
366
+ double: this.metadataQuerier.GetDoubleEntry(dracoMetadata, entryName),
367
+ intArray
368
+ };
369
+ }
370
+ finally {
371
+ this.draco.destroy(dracoArray);
372
+ }
281
373
  }
282
- }
283
- _getQuantizationTransform(dracoAttribute, options) {
284
- const {
285
- quantizedAttributes = []
286
- } = options;
287
- const attribute_type = dracoAttribute.attribute_type();
288
- const skip = quantizedAttributes.map(type => this.decoder[type]).includes(attribute_type);
289
- if (skip) {
290
- const transform = new this.draco.AttributeQuantizationTransform();
291
- try {
292
- if (transform.InitFromAttribute(dracoAttribute)) {
293
- return {
294
- quantization_bits: transform.quantization_bits(),
295
- range: transform.range(),
296
- min_values: new Float32Array([1, 2, 3]).map(i => transform.min_value(i))
297
- };
374
+ // QUANTIZED ATTRIBUTE SUPPORT (NO DECOMPRESSION)
375
+ /** Skip transforms for specific attribute types */
376
+ _disableAttributeTransforms(options) {
377
+ const { quantizedAttributes = [], octahedronAttributes = [] } = options;
378
+ const skipAttributes = [...quantizedAttributes, ...octahedronAttributes];
379
+ for (const dracoAttributeName of skipAttributes) {
380
+ this.decoder.SkipAttributeTransform(this.draco[dracoAttributeName]);
298
381
  }
299
- } finally {
300
- this.draco.destroy(transform);
301
- }
302
382
  }
303
- return null;
304
- }
305
- _getOctahedronTransform(dracoAttribute, options) {
306
- const {
307
- octahedronAttributes = []
308
- } = options;
309
- const attribute_type = dracoAttribute.attribute_type();
310
- const octahedron = octahedronAttributes.map(type => this.decoder[type]).includes(attribute_type);
311
- if (octahedron) {
312
- const transform = new this.draco.AttributeQuantizationTransform();
313
- try {
314
- if (transform.InitFromAttribute(dracoAttribute)) {
315
- return {
316
- quantization_bits: transform.quantization_bits()
317
- };
383
+ /**
384
+ * Extract (and apply?) Position Transform
385
+ * @todo not used
386
+ */
387
+ _getQuantizationTransform(dracoAttribute, options) {
388
+ const { quantizedAttributes = [] } = options;
389
+ const attribute_type = dracoAttribute.attribute_type();
390
+ const skip = quantizedAttributes.map((type) => this.decoder[type]).includes(attribute_type);
391
+ if (skip) {
392
+ const transform = new this.draco.AttributeQuantizationTransform();
393
+ try {
394
+ if (transform.InitFromAttribute(dracoAttribute)) {
395
+ return {
396
+ quantization_bits: transform.quantization_bits(),
397
+ range: transform.range(),
398
+ min_values: new Float32Array([1, 2, 3]).map((i) => transform.min_value(i))
399
+ };
400
+ }
401
+ }
402
+ finally {
403
+ this.draco.destroy(transform);
404
+ }
318
405
  }
319
- } finally {
320
- this.draco.destroy(transform);
321
- }
406
+ return null;
407
+ }
408
+ _getOctahedronTransform(dracoAttribute, options) {
409
+ const { octahedronAttributes = [] } = options;
410
+ const attribute_type = dracoAttribute.attribute_type();
411
+ const octahedron = octahedronAttributes
412
+ .map((type) => this.decoder[type])
413
+ .includes(attribute_type);
414
+ if (octahedron) {
415
+ const transform = new this.draco.AttributeQuantizationTransform();
416
+ try {
417
+ if (transform.InitFromAttribute(dracoAttribute)) {
418
+ return {
419
+ quantization_bits: transform.quantization_bits()
420
+ };
421
+ }
422
+ }
423
+ finally {
424
+ this.draco.destroy(transform);
425
+ }
426
+ }
427
+ return null;
322
428
  }
323
- return null;
324
- }
325
429
  }
430
+ /**
431
+ * Get draco specific data type by TypedArray constructor type
432
+ * @param attributeType
433
+ * @returns draco specific data type
434
+ */
326
435
  function getDracoDataType(draco, attributeType) {
327
- switch (attributeType) {
328
- case Float32Array:
329
- return draco.DT_FLOAT32;
330
- case Int8Array:
331
- return draco.DT_INT8;
332
- case Int16Array:
333
- return draco.DT_INT16;
334
- case Int32Array:
335
- return draco.DT_INT32;
336
- case Uint8Array:
337
- return draco.DT_UINT8;
338
- case Uint16Array:
339
- return draco.DT_UINT16;
340
- case Uint32Array:
341
- return draco.DT_UINT32;
342
- default:
343
- return draco.DT_INVALID;
344
- }
436
+ switch (attributeType) {
437
+ case Float32Array:
438
+ return draco.DT_FLOAT32;
439
+ case Int8Array:
440
+ return draco.DT_INT8;
441
+ case Int16Array:
442
+ return draco.DT_INT16;
443
+ case Int32Array:
444
+ return draco.DT_INT32;
445
+ case Uint8Array:
446
+ return draco.DT_UINT8;
447
+ case Uint16Array:
448
+ return draco.DT_UINT16;
449
+ case Uint32Array:
450
+ return draco.DT_UINT32;
451
+ default:
452
+ return draco.DT_INVALID;
453
+ }
345
454
  }
455
+ /**
456
+ * Copy a Draco int32 array into a JS typed array
457
+ */
346
458
  function getInt32Array(dracoArray) {
347
- const numValues = dracoArray.size();
348
- const intArray = new Int32Array(numValues);
349
- for (let i = 0; i < numValues; i++) {
350
- intArray[i] = dracoArray.GetValue(i);
351
- }
352
- return intArray;
459
+ const numValues = dracoArray.size();
460
+ const intArray = new Int32Array(numValues);
461
+ for (let i = 0; i < numValues; i++) {
462
+ intArray[i] = dracoArray.GetValue(i);
463
+ }
464
+ return intArray;
353
465
  }
466
+ /**
467
+ * Copy a Draco int32 array into a JS typed array
468
+ */
354
469
  function getUint32Array(dracoArray) {
355
- const numValues = dracoArray.size();
356
- const intArray = new Int32Array(numValues);
357
- for (let i = 0; i < numValues; i++) {
358
- intArray[i] = dracoArray.GetValue(i);
359
- }
360
- return intArray;
470
+ const numValues = dracoArray.size();
471
+ const intArray = new Int32Array(numValues);
472
+ for (let i = 0; i < numValues; i++) {
473
+ intArray[i] = dracoArray.GetValue(i);
474
+ }
475
+ return intArray;
361
476
  }
362
- //# sourceMappingURL=draco-parser.js.map