@loaders.gl/draco 4.3.2 → 4.4.0-alpha.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.
- package/dist/dist.dev.js +12966 -1012
- package/dist/dist.min.js +12 -3
- package/dist/draco-arrow-loader.d.ts +30 -0
- package/dist/draco-arrow-loader.d.ts.map +1 -0
- package/dist/draco-arrow-loader.js +19 -0
- package/dist/draco-format.d.ts +13 -0
- package/dist/draco-format.d.ts.map +1 -0
- package/dist/draco-format.js +15 -0
- package/dist/draco-loader.d.ts +28 -1
- package/dist/draco-loader.d.ts.map +1 -1
- package/dist/draco-loader.js +20 -1
- package/dist/draco-worker-node.js +253 -115
- package/dist/draco-worker-node.js.map +4 -4
- package/dist/draco-worker.js +111 -111
- package/dist/draco-worker.js.map +4 -4
- package/dist/draco-writer-worker-node.js +145 -6
- package/dist/draco-writer-worker-node.js.map +4 -4
- package/dist/draco-writer-worker.js +3 -2
- package/dist/draco-writer-worker.js.map +2 -2
- package/dist/draco-writer.d.ts +16 -0
- package/dist/draco-writer.d.ts.map +1 -1
- package/dist/draco-writer.js +19 -0
- package/dist/index.cjs +818 -802
- package/dist/index.cjs.map +4 -4
- package/dist/index.d.ts +5 -48
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +6 -38
- package/dist/lib/draco-builder.d.ts.map +1 -1
- package/dist/lib/draco-parser.d.ts.map +1 -1
- package/dist/lib/draco-parser.js +3 -1
- package/dist/lib/utils/get-draco-schema.d.ts.map +1 -1
- package/dist/lib/utils/get-draco-schema.js +1 -1
- package/dist/lib/utils/version.js +1 -1
- package/package.json +7 -6
- package/src/draco-arrow-loader.ts +25 -0
- package/src/draco-format.ts +18 -0
- package/src/draco-loader.ts +22 -2
- package/src/draco-writer.ts +21 -0
- package/src/index.ts +5 -45
- package/src/lib/draco-parser.ts +3 -1
- package/src/lib/utils/get-draco-schema.ts +2 -1
package/dist/index.cjs
CHANGED
|
@@ -22,975 +22,977 @@ var dist_exports = {};
|
|
|
22
22
|
__export(dist_exports, {
|
|
23
23
|
DRACO_EXTERNAL_LIBRARIES: () => DRACO_EXTERNAL_LIBRARIES,
|
|
24
24
|
DRACO_EXTERNAL_LIBRARY_URLS: () => DRACO_EXTERNAL_LIBRARY_URLS,
|
|
25
|
-
|
|
26
|
-
|
|
25
|
+
DracoArrowLoader: () => DracoArrowLoader,
|
|
26
|
+
DracoLoader: () => DracoLoader,
|
|
27
|
+
DracoWorkerLoader: () => DracoWorkerLoader,
|
|
27
28
|
DracoWriter: () => DracoWriter,
|
|
28
29
|
DracoWriterWorker: () => DracoWriterWorker
|
|
29
30
|
});
|
|
30
31
|
module.exports = __toCommonJS(dist_exports);
|
|
31
32
|
|
|
32
|
-
// dist/lib/
|
|
33
|
-
var
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
var
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
mimeTypes: ["application/octet-stream"],
|
|
47
|
-
binary: true,
|
|
48
|
-
tests: ["DRACO"],
|
|
49
|
-
options: {
|
|
50
|
-
draco: {
|
|
51
|
-
decoderType: typeof WebAssembly === "object" ? "wasm" : "js",
|
|
52
|
-
// 'js' for IE11
|
|
53
|
-
libraryPath: "libs/",
|
|
54
|
-
extraAttributes: {},
|
|
55
|
-
attributeNameEntry: void 0
|
|
56
|
-
}
|
|
57
|
-
}
|
|
33
|
+
// dist/lib/draco-module-loader.js
|
|
34
|
+
var import_worker_utils = require("@loaders.gl/worker-utils");
|
|
35
|
+
var DRACO_DECODER_VERSION = "1.5.6";
|
|
36
|
+
var DRACO_ENCODER_VERSION = "1.4.1";
|
|
37
|
+
var STATIC_DECODER_URL = `https://www.gstatic.com/draco/versioned/decoders/${DRACO_DECODER_VERSION}`;
|
|
38
|
+
var DRACO_EXTERNAL_LIBRARIES = {
|
|
39
|
+
/** The primary Draco3D encoder, javascript wrapper part */
|
|
40
|
+
DECODER: "draco_wasm_wrapper.js",
|
|
41
|
+
/** The primary draco decoder, compiled web assembly part */
|
|
42
|
+
DECODER_WASM: "draco_decoder.wasm",
|
|
43
|
+
/** Fallback decoder for non-webassebly environments. Very big bundle, lower performance */
|
|
44
|
+
FALLBACK_DECODER: "draco_decoder.js",
|
|
45
|
+
/** Draco encoder */
|
|
46
|
+
ENCODER: "draco_encoder.js"
|
|
58
47
|
};
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
const
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
}
|
|
74
|
-
|
|
75
|
-
const indicesField = getArrowFieldFromAttribute("indices", indices);
|
|
76
|
-
fields.push(indicesField);
|
|
48
|
+
var DRACO_EXTERNAL_LIBRARY_URLS = {
|
|
49
|
+
[DRACO_EXTERNAL_LIBRARIES.DECODER]: `${STATIC_DECODER_URL}/${DRACO_EXTERNAL_LIBRARIES.DECODER}`,
|
|
50
|
+
[DRACO_EXTERNAL_LIBRARIES.DECODER_WASM]: `${STATIC_DECODER_URL}/${DRACO_EXTERNAL_LIBRARIES.DECODER_WASM}`,
|
|
51
|
+
[DRACO_EXTERNAL_LIBRARIES.FALLBACK_DECODER]: `${STATIC_DECODER_URL}/${DRACO_EXTERNAL_LIBRARIES.FALLBACK_DECODER}`,
|
|
52
|
+
[DRACO_EXTERNAL_LIBRARIES.ENCODER]: `https://raw.githubusercontent.com/google/draco/${DRACO_ENCODER_VERSION}/javascript/${DRACO_EXTERNAL_LIBRARIES.ENCODER}`
|
|
53
|
+
};
|
|
54
|
+
var loadDecoderPromise;
|
|
55
|
+
var loadEncoderPromise;
|
|
56
|
+
async function loadDracoDecoderModule(options) {
|
|
57
|
+
const modules = options.modules || {};
|
|
58
|
+
if (modules.draco3d) {
|
|
59
|
+
loadDecoderPromise ||= modules.draco3d.createDecoderModule({}).then((draco) => {
|
|
60
|
+
return { draco };
|
|
61
|
+
});
|
|
62
|
+
} else {
|
|
63
|
+
loadDecoderPromise ||= loadDracoDecoder(options);
|
|
77
64
|
}
|
|
78
|
-
return
|
|
65
|
+
return await loadDecoderPromise;
|
|
79
66
|
}
|
|
80
|
-
function
|
|
81
|
-
const
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
67
|
+
async function loadDracoEncoderModule(options) {
|
|
68
|
+
const modules = options.modules || {};
|
|
69
|
+
if (modules.draco3d) {
|
|
70
|
+
loadEncoderPromise ||= modules.draco3d.createEncoderModule({}).then((draco) => {
|
|
71
|
+
return { draco };
|
|
72
|
+
});
|
|
73
|
+
} else {
|
|
74
|
+
loadEncoderPromise ||= loadDracoEncoder(options);
|
|
85
75
|
}
|
|
86
|
-
return
|
|
76
|
+
return await loadEncoderPromise;
|
|
87
77
|
}
|
|
88
|
-
function
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
78
|
+
async function loadDracoDecoder(options) {
|
|
79
|
+
let DracoDecoderModule;
|
|
80
|
+
let wasmBinary;
|
|
81
|
+
switch (options.draco && options.draco.decoderType) {
|
|
82
|
+
case "js":
|
|
83
|
+
DracoDecoderModule = await (0, import_worker_utils.loadLibrary)(DRACO_EXTERNAL_LIBRARY_URLS[DRACO_EXTERNAL_LIBRARIES.FALLBACK_DECODER], "draco", options, DRACO_EXTERNAL_LIBRARIES.FALLBACK_DECODER);
|
|
84
|
+
break;
|
|
85
|
+
case "wasm":
|
|
86
|
+
default:
|
|
87
|
+
[DracoDecoderModule, wasmBinary] = await Promise.all([
|
|
88
|
+
await (0, import_worker_utils.loadLibrary)(DRACO_EXTERNAL_LIBRARY_URLS[DRACO_EXTERNAL_LIBRARIES.DECODER], "draco", options, DRACO_EXTERNAL_LIBRARIES.DECODER),
|
|
89
|
+
await (0, import_worker_utils.loadLibrary)(DRACO_EXTERNAL_LIBRARY_URLS[DRACO_EXTERNAL_LIBRARIES.DECODER_WASM], "draco", options, DRACO_EXTERNAL_LIBRARIES.DECODER_WASM)
|
|
90
|
+
]);
|
|
91
|
+
}
|
|
92
|
+
DracoDecoderModule = DracoDecoderModule || globalThis.DracoDecoderModule;
|
|
93
|
+
return await initializeDracoDecoder(DracoDecoderModule, wasmBinary);
|
|
92
94
|
}
|
|
93
|
-
function
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
serializedMetadata[`${key}.string`] = JSON.stringify(metadata[key]);
|
|
95
|
+
function initializeDracoDecoder(DracoDecoderModule, wasmBinary) {
|
|
96
|
+
const options = {};
|
|
97
|
+
if (wasmBinary) {
|
|
98
|
+
options.wasmBinary = wasmBinary;
|
|
98
99
|
}
|
|
99
|
-
return
|
|
100
|
+
return new Promise((resolve) => {
|
|
101
|
+
DracoDecoderModule({
|
|
102
|
+
...options,
|
|
103
|
+
onModuleLoaded: (draco) => resolve({ draco })
|
|
104
|
+
// Module is Promise-like. Wrap in object to avoid loop.
|
|
105
|
+
});
|
|
106
|
+
});
|
|
107
|
+
}
|
|
108
|
+
async function loadDracoEncoder(options) {
|
|
109
|
+
let DracoEncoderModule = await (0, import_worker_utils.loadLibrary)(DRACO_EXTERNAL_LIBRARY_URLS[DRACO_EXTERNAL_LIBRARIES.ENCODER], "draco", options, DRACO_EXTERNAL_LIBRARIES.ENCODER);
|
|
110
|
+
DracoEncoderModule = DracoEncoderModule || globalThis.DracoEncoderModule;
|
|
111
|
+
return new Promise((resolve) => {
|
|
112
|
+
DracoEncoderModule({
|
|
113
|
+
onModuleLoaded: (draco) => resolve({ draco })
|
|
114
|
+
// Module is Promise-like. Wrap in object to avoid loop.
|
|
115
|
+
});
|
|
116
|
+
});
|
|
100
117
|
}
|
|
101
118
|
|
|
102
|
-
// dist/lib/draco-
|
|
103
|
-
var
|
|
119
|
+
// dist/lib/draco-builder.js
|
|
120
|
+
var GLTF_TO_DRACO_ATTRIBUTE_NAME_MAP = {
|
|
104
121
|
POSITION: "POSITION",
|
|
105
122
|
NORMAL: "NORMAL",
|
|
106
|
-
|
|
107
|
-
|
|
123
|
+
COLOR_0: "COLOR",
|
|
124
|
+
TEXCOORD_0: "TEX_COORD"
|
|
108
125
|
};
|
|
109
|
-
var
|
|
110
|
-
1: Int8Array,
|
|
111
|
-
2: Uint8Array,
|
|
112
|
-
3: Int16Array,
|
|
113
|
-
4: Uint16Array,
|
|
114
|
-
5: Int32Array,
|
|
115
|
-
6: Uint32Array,
|
|
116
|
-
// 7: BigInt64Array,
|
|
117
|
-
// 8: BigUint64Array,
|
|
118
|
-
9: Float32Array
|
|
119
|
-
// 10: Float64Array
|
|
120
|
-
// 11: BOOL - What array type do we use for this?
|
|
126
|
+
var noop = () => {
|
|
121
127
|
};
|
|
122
|
-
var
|
|
123
|
-
var DracoParser = class {
|
|
128
|
+
var DracoBuilder = class {
|
|
124
129
|
draco;
|
|
125
|
-
|
|
126
|
-
|
|
130
|
+
dracoEncoder;
|
|
131
|
+
dracoMeshBuilder;
|
|
132
|
+
dracoMetadataBuilder;
|
|
133
|
+
log;
|
|
127
134
|
// draco - the draco decoder, either import `draco3d` or load dynamically
|
|
128
135
|
constructor(draco) {
|
|
129
136
|
this.draco = draco;
|
|
130
|
-
this.
|
|
131
|
-
this.
|
|
137
|
+
this.dracoEncoder = new this.draco.Encoder();
|
|
138
|
+
this.dracoMeshBuilder = new this.draco.MeshBuilder();
|
|
139
|
+
this.dracoMetadataBuilder = new this.draco.MetadataBuilder();
|
|
132
140
|
}
|
|
133
|
-
/**
|
|
134
|
-
* Destroy draco resources
|
|
135
|
-
*/
|
|
136
141
|
destroy() {
|
|
137
|
-
this.
|
|
138
|
-
this.
|
|
142
|
+
this.destroyEncodedObject(this.dracoMeshBuilder);
|
|
143
|
+
this.destroyEncodedObject(this.dracoEncoder);
|
|
144
|
+
this.destroyEncodedObject(this.dracoMetadataBuilder);
|
|
145
|
+
this.dracoMeshBuilder = null;
|
|
146
|
+
this.dracoEncoder = null;
|
|
147
|
+
this.draco = null;
|
|
139
148
|
}
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
*/
|
|
145
|
-
parseSync(arrayBuffer, options = {}) {
|
|
146
|
-
const buffer = new this.draco.DecoderBuffer();
|
|
147
|
-
buffer.Init(new Int8Array(arrayBuffer), arrayBuffer.byteLength);
|
|
148
|
-
this._disableAttributeTransforms(options);
|
|
149
|
-
const geometry_type = this.decoder.GetEncodedGeometryType(buffer);
|
|
150
|
-
const dracoGeometry = geometry_type === this.draco.TRIANGULAR_MESH ? new this.draco.Mesh() : new this.draco.PointCloud();
|
|
151
|
-
try {
|
|
152
|
-
let dracoStatus;
|
|
153
|
-
switch (geometry_type) {
|
|
154
|
-
case this.draco.TRIANGULAR_MESH:
|
|
155
|
-
dracoStatus = this.decoder.DecodeBufferToMesh(buffer, dracoGeometry);
|
|
156
|
-
break;
|
|
157
|
-
case this.draco.POINT_CLOUD:
|
|
158
|
-
dracoStatus = this.decoder.DecodeBufferToPointCloud(buffer, dracoGeometry);
|
|
159
|
-
break;
|
|
160
|
-
default:
|
|
161
|
-
throw new Error("DRACO: Unknown geometry type.");
|
|
162
|
-
}
|
|
163
|
-
if (!dracoStatus.ok() || !dracoGeometry.ptr) {
|
|
164
|
-
const message = `DRACO decompression failed: ${dracoStatus.error_msg()}`;
|
|
165
|
-
throw new Error(message);
|
|
166
|
-
}
|
|
167
|
-
const loaderData = this._getDracoLoaderData(dracoGeometry, geometry_type, options);
|
|
168
|
-
const geometry = this._getMeshData(dracoGeometry, loaderData, options);
|
|
169
|
-
const boundingBox = (0, import_schema2.getMeshBoundingBox)(geometry.attributes);
|
|
170
|
-
const schema = getDracoSchema(geometry.attributes, loaderData, geometry.indices);
|
|
171
|
-
const data = {
|
|
172
|
-
loader: "draco",
|
|
173
|
-
loaderData,
|
|
174
|
-
header: {
|
|
175
|
-
vertexCount: dracoGeometry.num_points(),
|
|
176
|
-
boundingBox
|
|
177
|
-
},
|
|
178
|
-
...geometry,
|
|
179
|
-
schema
|
|
180
|
-
};
|
|
181
|
-
return data;
|
|
182
|
-
} finally {
|
|
183
|
-
this.draco.destroy(buffer);
|
|
184
|
-
if (dracoGeometry) {
|
|
185
|
-
this.draco.destroy(dracoGeometry);
|
|
186
|
-
}
|
|
149
|
+
// TBD - when does this need to be called?
|
|
150
|
+
destroyEncodedObject(object) {
|
|
151
|
+
if (object) {
|
|
152
|
+
this.draco.destroy(object);
|
|
187
153
|
}
|
|
188
154
|
}
|
|
189
|
-
// Draco specific "loader data"
|
|
190
155
|
/**
|
|
191
|
-
*
|
|
192
|
-
* @param
|
|
193
|
-
* @param geometry_type
|
|
156
|
+
* Encode mesh or point cloud
|
|
157
|
+
* @param mesh =({})
|
|
194
158
|
* @param options
|
|
195
|
-
* @returns
|
|
196
159
|
*/
|
|
197
|
-
|
|
198
|
-
|
|
199
|
-
|
|
200
|
-
return
|
|
201
|
-
geometry_type,
|
|
202
|
-
num_attributes: dracoGeometry.num_attributes(),
|
|
203
|
-
num_points: dracoGeometry.num_points(),
|
|
204
|
-
num_faces: dracoGeometry instanceof this.draco.Mesh ? dracoGeometry.num_faces() : 0,
|
|
205
|
-
metadata,
|
|
206
|
-
attributes
|
|
207
|
-
};
|
|
160
|
+
encodeSync(mesh, options = {}) {
|
|
161
|
+
this.log = noop;
|
|
162
|
+
this._setOptions(options);
|
|
163
|
+
return options.pointcloud ? this._encodePointCloud(mesh, options) : this._encodeMesh(mesh, options);
|
|
208
164
|
}
|
|
209
|
-
|
|
210
|
-
|
|
211
|
-
|
|
212
|
-
|
|
213
|
-
|
|
214
|
-
|
|
215
|
-
|
|
216
|
-
|
|
217
|
-
|
|
218
|
-
|
|
219
|
-
|
|
220
|
-
|
|
221
|
-
|
|
222
|
-
|
|
223
|
-
|
|
224
|
-
|
|
225
|
-
|
|
226
|
-
|
|
227
|
-
|
|
228
|
-
|
|
229
|
-
metadata
|
|
230
|
-
};
|
|
231
|
-
const quantization = this._getQuantizationTransform(dracoAttribute, options);
|
|
232
|
-
if (quantization) {
|
|
233
|
-
dracoAttributes[dracoAttribute.unique_id()].quantization_transform = quantization;
|
|
165
|
+
// PRIVATE
|
|
166
|
+
_getAttributesFromMesh(mesh) {
|
|
167
|
+
const attributes = { ...mesh, ...mesh.attributes };
|
|
168
|
+
if (mesh.indices) {
|
|
169
|
+
attributes.indices = mesh.indices;
|
|
170
|
+
}
|
|
171
|
+
return attributes;
|
|
172
|
+
}
|
|
173
|
+
_encodePointCloud(pointcloud, options) {
|
|
174
|
+
const dracoPointCloud = new this.draco.PointCloud();
|
|
175
|
+
if (options.metadata) {
|
|
176
|
+
this._addGeometryMetadata(dracoPointCloud, options.metadata);
|
|
177
|
+
}
|
|
178
|
+
const attributes = this._getAttributesFromMesh(pointcloud);
|
|
179
|
+
this._createDracoPointCloud(dracoPointCloud, attributes, options);
|
|
180
|
+
const dracoData = new this.draco.DracoInt8Array();
|
|
181
|
+
try {
|
|
182
|
+
const encodedLen = this.dracoEncoder.EncodePointCloudToDracoBuffer(dracoPointCloud, false, dracoData);
|
|
183
|
+
if (!(encodedLen > 0)) {
|
|
184
|
+
throw new Error("Draco encoding failed.");
|
|
234
185
|
}
|
|
235
|
-
|
|
236
|
-
|
|
237
|
-
|
|
186
|
+
this.log(`DRACO encoded ${dracoPointCloud.num_points()} points
|
|
187
|
+
with ${dracoPointCloud.num_attributes()} attributes into ${encodedLen} bytes`);
|
|
188
|
+
return dracoInt8ArrayToArrayBuffer(dracoData);
|
|
189
|
+
} finally {
|
|
190
|
+
this.destroyEncodedObject(dracoData);
|
|
191
|
+
this.destroyEncodedObject(dracoPointCloud);
|
|
192
|
+
}
|
|
193
|
+
}
|
|
194
|
+
_encodeMesh(mesh, options) {
|
|
195
|
+
const dracoMesh = new this.draco.Mesh();
|
|
196
|
+
if (options.metadata) {
|
|
197
|
+
this._addGeometryMetadata(dracoMesh, options.metadata);
|
|
198
|
+
}
|
|
199
|
+
const attributes = this._getAttributesFromMesh(mesh);
|
|
200
|
+
this._createDracoMesh(dracoMesh, attributes, options);
|
|
201
|
+
const dracoData = new this.draco.DracoInt8Array();
|
|
202
|
+
try {
|
|
203
|
+
const encodedLen = this.dracoEncoder.EncodeMeshToDracoBuffer(dracoMesh, dracoData);
|
|
204
|
+
if (encodedLen <= 0) {
|
|
205
|
+
throw new Error("Draco encoding failed.");
|
|
238
206
|
}
|
|
207
|
+
this.log(`DRACO encoded ${dracoMesh.num_points()} points
|
|
208
|
+
with ${dracoMesh.num_attributes()} attributes into ${encodedLen} bytes`);
|
|
209
|
+
return dracoInt8ArrayToArrayBuffer(dracoData);
|
|
210
|
+
} finally {
|
|
211
|
+
this.destroyEncodedObject(dracoData);
|
|
212
|
+
this.destroyEncodedObject(dracoMesh);
|
|
239
213
|
}
|
|
240
|
-
return dracoAttributes;
|
|
241
214
|
}
|
|
242
215
|
/**
|
|
243
|
-
*
|
|
244
|
-
*
|
|
245
|
-
* @param dracoGeometry
|
|
246
|
-
* @param options
|
|
216
|
+
* Set encoding options.
|
|
217
|
+
* @param {{speed?: any; method?: any; quantization?: any;}} options
|
|
247
218
|
*/
|
|
248
|
-
|
|
249
|
-
|
|
250
|
-
|
|
251
|
-
if (!positionAttribute) {
|
|
252
|
-
throw new Error("DRACO: No position attribute found.");
|
|
219
|
+
_setOptions(options) {
|
|
220
|
+
if ("speed" in options) {
|
|
221
|
+
this.dracoEncoder.SetSpeedOptions(...options.speed);
|
|
253
222
|
}
|
|
254
|
-
if (
|
|
255
|
-
|
|
256
|
-
|
|
257
|
-
return {
|
|
258
|
-
topology: "triangle-strip",
|
|
259
|
-
mode: 4,
|
|
260
|
-
// GL.TRIANGLES
|
|
261
|
-
attributes,
|
|
262
|
-
indices: {
|
|
263
|
-
value: this._getTriangleStripIndices(dracoGeometry),
|
|
264
|
-
size: 1
|
|
265
|
-
}
|
|
266
|
-
};
|
|
267
|
-
case "triangle-list":
|
|
268
|
-
default:
|
|
269
|
-
return {
|
|
270
|
-
topology: "triangle-list",
|
|
271
|
-
mode: 5,
|
|
272
|
-
// GL.TRIANGLE_STRIP
|
|
273
|
-
attributes,
|
|
274
|
-
indices: {
|
|
275
|
-
value: this._getTriangleListIndices(dracoGeometry),
|
|
276
|
-
size: 1
|
|
277
|
-
}
|
|
278
|
-
};
|
|
279
|
-
}
|
|
223
|
+
if ("method" in options) {
|
|
224
|
+
const dracoMethod = this.draco[options.method || "MESH_SEQUENTIAL_ENCODING"];
|
|
225
|
+
this.dracoEncoder.SetEncodingMethod(dracoMethod);
|
|
280
226
|
}
|
|
281
|
-
|
|
282
|
-
|
|
283
|
-
|
|
284
|
-
|
|
285
|
-
|
|
286
|
-
};
|
|
287
|
-
}
|
|
288
|
-
_getMeshAttributes(loaderData, dracoGeometry, options) {
|
|
289
|
-
const attributes = {};
|
|
290
|
-
for (const loaderAttribute of Object.values(loaderData.attributes)) {
|
|
291
|
-
const attributeName = this._deduceAttributeName(loaderAttribute, options);
|
|
292
|
-
loaderAttribute.name = attributeName;
|
|
293
|
-
const values = this._getAttributeValues(dracoGeometry, loaderAttribute);
|
|
294
|
-
if (values) {
|
|
295
|
-
const { value, size } = values;
|
|
296
|
-
attributes[attributeName] = {
|
|
297
|
-
value,
|
|
298
|
-
size,
|
|
299
|
-
byteOffset: loaderAttribute.byte_offset,
|
|
300
|
-
byteStride: loaderAttribute.byte_stride,
|
|
301
|
-
normalized: loaderAttribute.normalized
|
|
302
|
-
};
|
|
227
|
+
if ("quantization" in options) {
|
|
228
|
+
for (const attribute in options.quantization) {
|
|
229
|
+
const bits = options.quantization[attribute];
|
|
230
|
+
const dracoPosition = this.draco[attribute];
|
|
231
|
+
this.dracoEncoder.SetAttributeQuantization(dracoPosition, bits);
|
|
303
232
|
}
|
|
304
233
|
}
|
|
305
|
-
return attributes;
|
|
306
234
|
}
|
|
307
|
-
// MESH INDICES EXTRACTION
|
|
308
235
|
/**
|
|
309
|
-
*
|
|
310
|
-
* @param
|
|
236
|
+
* @param {Mesh} dracoMesh
|
|
237
|
+
* @param {object} attributes
|
|
238
|
+
* @returns {Mesh}
|
|
311
239
|
*/
|
|
312
|
-
|
|
313
|
-
const
|
|
314
|
-
const numIndices = numFaces * 3;
|
|
315
|
-
const byteLength = numIndices * INDEX_ITEM_SIZE;
|
|
316
|
-
const ptr = this.draco._malloc(byteLength);
|
|
240
|
+
_createDracoMesh(dracoMesh, attributes, options) {
|
|
241
|
+
const optionalMetadata = options.attributesMetadata || {};
|
|
317
242
|
try {
|
|
318
|
-
this.
|
|
319
|
-
|
|
320
|
-
|
|
321
|
-
|
|
243
|
+
const positions = this._getPositionAttribute(attributes);
|
|
244
|
+
if (!positions) {
|
|
245
|
+
throw new Error("positions");
|
|
246
|
+
}
|
|
247
|
+
const vertexCount = positions.length / 3;
|
|
248
|
+
for (let attributeName in attributes) {
|
|
249
|
+
const attribute = attributes[attributeName];
|
|
250
|
+
attributeName = GLTF_TO_DRACO_ATTRIBUTE_NAME_MAP[attributeName] || attributeName;
|
|
251
|
+
const uniqueId = this._addAttributeToMesh(dracoMesh, attributeName, attribute, vertexCount);
|
|
252
|
+
if (uniqueId !== -1) {
|
|
253
|
+
this._addAttributeMetadata(dracoMesh, uniqueId, {
|
|
254
|
+
name: attributeName,
|
|
255
|
+
...optionalMetadata[attributeName] || {}
|
|
256
|
+
});
|
|
257
|
+
}
|
|
258
|
+
}
|
|
259
|
+
} catch (error) {
|
|
260
|
+
this.destroyEncodedObject(dracoMesh);
|
|
261
|
+
throw error;
|
|
322
262
|
}
|
|
263
|
+
return dracoMesh;
|
|
323
264
|
}
|
|
324
265
|
/**
|
|
325
|
-
*
|
|
326
|
-
* @param
|
|
266
|
+
* @param {} dracoPointCloud
|
|
267
|
+
* @param {object} attributes
|
|
327
268
|
*/
|
|
328
|
-
|
|
329
|
-
const
|
|
269
|
+
_createDracoPointCloud(dracoPointCloud, attributes, options) {
|
|
270
|
+
const optionalMetadata = options.attributesMetadata || {};
|
|
330
271
|
try {
|
|
331
|
-
this.
|
|
332
|
-
|
|
333
|
-
|
|
334
|
-
|
|
272
|
+
const positions = this._getPositionAttribute(attributes);
|
|
273
|
+
if (!positions) {
|
|
274
|
+
throw new Error("positions");
|
|
275
|
+
}
|
|
276
|
+
const vertexCount = positions.length / 3;
|
|
277
|
+
for (let attributeName in attributes) {
|
|
278
|
+
const attribute = attributes[attributeName];
|
|
279
|
+
attributeName = GLTF_TO_DRACO_ATTRIBUTE_NAME_MAP[attributeName] || attributeName;
|
|
280
|
+
const uniqueId = this._addAttributeToMesh(dracoPointCloud, attributeName, attribute, vertexCount);
|
|
281
|
+
if (uniqueId !== -1) {
|
|
282
|
+
this._addAttributeMetadata(dracoPointCloud, uniqueId, {
|
|
283
|
+
name: attributeName,
|
|
284
|
+
...optionalMetadata[attributeName] || {}
|
|
285
|
+
});
|
|
286
|
+
}
|
|
287
|
+
}
|
|
288
|
+
} catch (error) {
|
|
289
|
+
this.destroyEncodedObject(dracoPointCloud);
|
|
290
|
+
throw error;
|
|
335
291
|
}
|
|
292
|
+
return dracoPointCloud;
|
|
336
293
|
}
|
|
337
294
|
/**
|
|
338
|
-
*
|
|
339
|
-
* @param dracoGeometry
|
|
340
|
-
* @param dracoAttribute
|
|
295
|
+
* @param mesh
|
|
341
296
|
* @param attributeName
|
|
297
|
+
* @param attribute
|
|
298
|
+
* @param vertexCount
|
|
342
299
|
*/
|
|
343
|
-
|
|
344
|
-
|
|
345
|
-
|
|
346
|
-
console.warn(`DRACO: Unsupported attribute type ${attribute.data_type}`);
|
|
347
|
-
return null;
|
|
300
|
+
_addAttributeToMesh(mesh, attributeName, attribute, vertexCount) {
|
|
301
|
+
if (!ArrayBuffer.isView(attribute)) {
|
|
302
|
+
return -1;
|
|
348
303
|
}
|
|
349
|
-
const
|
|
350
|
-
const
|
|
351
|
-
|
|
352
|
-
|
|
353
|
-
|
|
354
|
-
|
|
355
|
-
|
|
356
|
-
try {
|
|
357
|
-
const dracoAttribute = this.decoder.GetAttribute(dracoGeometry, attribute.attribute_index);
|
|
358
|
-
this.decoder.GetAttributeDataArrayForAllPoints(dracoGeometry, dracoAttribute, dataType, byteLength, ptr);
|
|
359
|
-
value = new TypedArrayCtor(this.draco.HEAPF32.buffer, ptr, numValues).slice();
|
|
360
|
-
} finally {
|
|
361
|
-
this.draco._free(ptr);
|
|
304
|
+
const type = this._getDracoAttributeType(attributeName);
|
|
305
|
+
const size = attribute.length / vertexCount;
|
|
306
|
+
if (type === "indices") {
|
|
307
|
+
const numFaces = attribute.length / 3;
|
|
308
|
+
this.log(`Adding attribute ${attributeName}, size ${numFaces}`);
|
|
309
|
+
this.dracoMeshBuilder.AddFacesToMesh(mesh, numFaces, attribute);
|
|
310
|
+
return -1;
|
|
362
311
|
}
|
|
363
|
-
|
|
364
|
-
|
|
365
|
-
|
|
366
|
-
|
|
367
|
-
|
|
368
|
-
|
|
369
|
-
|
|
370
|
-
|
|
371
|
-
|
|
372
|
-
|
|
373
|
-
|
|
374
|
-
|
|
375
|
-
|
|
376
|
-
|
|
377
|
-
|
|
312
|
+
this.log(`Adding attribute ${attributeName}, size ${size}`);
|
|
313
|
+
const builder = this.dracoMeshBuilder;
|
|
314
|
+
const { buffer } = attribute;
|
|
315
|
+
switch (attribute.constructor) {
|
|
316
|
+
case Int8Array:
|
|
317
|
+
return builder.AddInt8Attribute(mesh, type, vertexCount, size, new Int8Array(buffer));
|
|
318
|
+
case Int16Array:
|
|
319
|
+
return builder.AddInt16Attribute(mesh, type, vertexCount, size, new Int16Array(buffer));
|
|
320
|
+
case Int32Array:
|
|
321
|
+
return builder.AddInt32Attribute(mesh, type, vertexCount, size, new Int32Array(buffer));
|
|
322
|
+
case Uint8Array:
|
|
323
|
+
case Uint8ClampedArray:
|
|
324
|
+
return builder.AddUInt8Attribute(mesh, type, vertexCount, size, new Uint8Array(buffer));
|
|
325
|
+
case Uint16Array:
|
|
326
|
+
return builder.AddUInt16Attribute(mesh, type, vertexCount, size, new Uint16Array(buffer));
|
|
327
|
+
case Uint32Array:
|
|
328
|
+
return builder.AddUInt32Attribute(mesh, type, vertexCount, size, new Uint32Array(buffer));
|
|
329
|
+
case Float32Array:
|
|
330
|
+
return builder.AddFloatAttribute(mesh, type, vertexCount, size, new Float32Array(buffer));
|
|
331
|
+
default:
|
|
332
|
+
console.warn("Unsupported attribute type", attribute);
|
|
333
|
+
return -1;
|
|
378
334
|
}
|
|
379
|
-
return attributeNames;
|
|
380
335
|
}
|
|
381
|
-
*/
|
|
382
336
|
/**
|
|
383
|
-
*
|
|
384
|
-
*
|
|
385
|
-
*
|
|
386
|
-
* types
|
|
387
|
-
* @param attributeData
|
|
337
|
+
* DRACO can compress attributes of know type better
|
|
338
|
+
* TODO - expose an attribute type map?
|
|
339
|
+
* @param attributeName
|
|
388
340
|
*/
|
|
389
|
-
|
|
390
|
-
|
|
391
|
-
|
|
392
|
-
|
|
393
|
-
|
|
394
|
-
|
|
341
|
+
_getDracoAttributeType(attributeName) {
|
|
342
|
+
switch (attributeName.toLowerCase()) {
|
|
343
|
+
case "indices":
|
|
344
|
+
return "indices";
|
|
345
|
+
case "position":
|
|
346
|
+
case "positions":
|
|
347
|
+
case "vertices":
|
|
348
|
+
return this.draco.POSITION;
|
|
349
|
+
case "normal":
|
|
350
|
+
case "normals":
|
|
351
|
+
return this.draco.NORMAL;
|
|
352
|
+
case "color":
|
|
353
|
+
case "colors":
|
|
354
|
+
return this.draco.COLOR;
|
|
355
|
+
case "texcoord":
|
|
356
|
+
case "texcoords":
|
|
357
|
+
return this.draco.TEX_COORD;
|
|
358
|
+
default:
|
|
359
|
+
return this.draco.GENERIC;
|
|
395
360
|
}
|
|
396
|
-
|
|
397
|
-
|
|
398
|
-
|
|
399
|
-
|
|
400
|
-
|
|
361
|
+
}
|
|
362
|
+
_getPositionAttribute(attributes) {
|
|
363
|
+
for (const attributeName in attributes) {
|
|
364
|
+
const attribute = attributes[attributeName];
|
|
365
|
+
const dracoType = this._getDracoAttributeType(attributeName);
|
|
366
|
+
if (dracoType === this.draco.POSITION) {
|
|
367
|
+
return attribute;
|
|
401
368
|
}
|
|
402
369
|
}
|
|
403
|
-
|
|
404
|
-
if (attribute.metadata[entryName]) {
|
|
405
|
-
return attribute.metadata[entryName].string;
|
|
406
|
-
}
|
|
407
|
-
return `CUSTOM_ATTRIBUTE_${uniqueId}`;
|
|
408
|
-
}
|
|
409
|
-
// METADATA EXTRACTION
|
|
410
|
-
/** Get top level metadata */
|
|
411
|
-
_getTopLevelMetadata(dracoGeometry) {
|
|
412
|
-
const dracoMetadata = this.decoder.GetMetadata(dracoGeometry);
|
|
413
|
-
return this._getDracoMetadata(dracoMetadata);
|
|
414
|
-
}
|
|
415
|
-
/** Get per attribute metadata */
|
|
416
|
-
_getAttributeMetadata(dracoGeometry, attributeId) {
|
|
417
|
-
const dracoMetadata = this.decoder.GetAttributeMetadata(dracoGeometry, attributeId);
|
|
418
|
-
return this._getDracoMetadata(dracoMetadata);
|
|
370
|
+
return null;
|
|
419
371
|
}
|
|
420
372
|
/**
|
|
421
|
-
*
|
|
422
|
-
* @param
|
|
423
|
-
* @
|
|
373
|
+
* Add metadata for the geometry.
|
|
374
|
+
* @param dracoGeometry - WASM Draco Object
|
|
375
|
+
* @param metadata
|
|
424
376
|
*/
|
|
425
|
-
|
|
426
|
-
|
|
427
|
-
|
|
428
|
-
|
|
429
|
-
const result = {};
|
|
430
|
-
const numEntries = this.metadataQuerier.NumEntries(dracoMetadata);
|
|
431
|
-
for (let entryIndex = 0; entryIndex < numEntries; entryIndex++) {
|
|
432
|
-
const entryName = this.metadataQuerier.GetEntryName(dracoMetadata, entryIndex);
|
|
433
|
-
result[entryName] = this._getDracoMetadataField(dracoMetadata, entryName);
|
|
434
|
-
}
|
|
435
|
-
return result;
|
|
377
|
+
_addGeometryMetadata(dracoGeometry, metadata) {
|
|
378
|
+
const dracoMetadata = new this.draco.Metadata();
|
|
379
|
+
this._populateDracoMetadata(dracoMetadata, metadata);
|
|
380
|
+
this.dracoMeshBuilder.AddMetadata(dracoGeometry, dracoMetadata);
|
|
436
381
|
}
|
|
437
382
|
/**
|
|
438
|
-
*
|
|
439
|
-
* @param
|
|
440
|
-
* @param
|
|
383
|
+
* Add metadata for an attribute to geometry.
|
|
384
|
+
* @param dracoGeometry - WASM Draco Object
|
|
385
|
+
* @param uniqueAttributeId
|
|
386
|
+
* @param metadata
|
|
441
387
|
*/
|
|
442
|
-
|
|
443
|
-
const
|
|
444
|
-
|
|
445
|
-
|
|
446
|
-
const intArray = getInt32Array(dracoArray);
|
|
447
|
-
return {
|
|
448
|
-
int: this.metadataQuerier.GetIntEntry(dracoMetadata, entryName),
|
|
449
|
-
string: this.metadataQuerier.GetStringEntry(dracoMetadata, entryName),
|
|
450
|
-
double: this.metadataQuerier.GetDoubleEntry(dracoMetadata, entryName),
|
|
451
|
-
intArray
|
|
452
|
-
};
|
|
453
|
-
} finally {
|
|
454
|
-
this.draco.destroy(dracoArray);
|
|
455
|
-
}
|
|
456
|
-
}
|
|
457
|
-
// QUANTIZED ATTRIBUTE SUPPORT (NO DECOMPRESSION)
|
|
458
|
-
/** Skip transforms for specific attribute types */
|
|
459
|
-
_disableAttributeTransforms(options) {
|
|
460
|
-
const { quantizedAttributes = [], octahedronAttributes = [] } = options;
|
|
461
|
-
const skipAttributes = [...quantizedAttributes, ...octahedronAttributes];
|
|
462
|
-
for (const dracoAttributeName of skipAttributes) {
|
|
463
|
-
this.decoder.SkipAttributeTransform(this.draco[dracoAttributeName]);
|
|
464
|
-
}
|
|
388
|
+
_addAttributeMetadata(dracoGeometry, uniqueAttributeId, metadata) {
|
|
389
|
+
const dracoAttributeMetadata = new this.draco.Metadata();
|
|
390
|
+
this._populateDracoMetadata(dracoAttributeMetadata, metadata);
|
|
391
|
+
this.dracoMeshBuilder.SetMetadataForAttribute(dracoGeometry, uniqueAttributeId, dracoAttributeMetadata);
|
|
465
392
|
}
|
|
466
393
|
/**
|
|
467
|
-
*
|
|
468
|
-
* @
|
|
394
|
+
* Add contents of object or map to a WASM Draco Metadata Object
|
|
395
|
+
* @param dracoMetadata - WASM Draco Object
|
|
396
|
+
* @param metadata
|
|
469
397
|
*/
|
|
470
|
-
|
|
471
|
-
const
|
|
472
|
-
|
|
473
|
-
|
|
474
|
-
|
|
475
|
-
|
|
476
|
-
|
|
477
|
-
|
|
478
|
-
|
|
479
|
-
|
|
480
|
-
|
|
481
|
-
|
|
482
|
-
|
|
483
|
-
|
|
484
|
-
|
|
485
|
-
|
|
486
|
-
|
|
487
|
-
|
|
488
|
-
return null;
|
|
489
|
-
}
|
|
490
|
-
_getOctahedronTransform(dracoAttribute, options) {
|
|
491
|
-
const { octahedronAttributes = [] } = options;
|
|
492
|
-
const attribute_type = dracoAttribute.attribute_type();
|
|
493
|
-
const octahedron = octahedronAttributes.map((type) => this.decoder[type]).includes(attribute_type);
|
|
494
|
-
if (octahedron) {
|
|
495
|
-
const transform = new this.draco.AttributeQuantizationTransform();
|
|
496
|
-
try {
|
|
497
|
-
if (transform.InitFromAttribute(dracoAttribute)) {
|
|
498
|
-
return {
|
|
499
|
-
quantization_bits: transform.quantization_bits()
|
|
500
|
-
};
|
|
501
|
-
}
|
|
502
|
-
} finally {
|
|
503
|
-
this.draco.destroy(transform);
|
|
398
|
+
_populateDracoMetadata(dracoMetadata, metadata) {
|
|
399
|
+
for (const [key, value] of getEntries(metadata)) {
|
|
400
|
+
switch (typeof value) {
|
|
401
|
+
case "number":
|
|
402
|
+
if (Math.trunc(value) === value) {
|
|
403
|
+
this.dracoMetadataBuilder.AddIntEntry(dracoMetadata, key, value);
|
|
404
|
+
} else {
|
|
405
|
+
this.dracoMetadataBuilder.AddDoubleEntry(dracoMetadata, key, value);
|
|
406
|
+
}
|
|
407
|
+
break;
|
|
408
|
+
case "object":
|
|
409
|
+
if (value instanceof Int32Array) {
|
|
410
|
+
this.dracoMetadataBuilder.AddIntEntryArray(dracoMetadata, key, value, value.length);
|
|
411
|
+
}
|
|
412
|
+
break;
|
|
413
|
+
case "string":
|
|
414
|
+
default:
|
|
415
|
+
this.dracoMetadataBuilder.AddStringEntry(dracoMetadata, key, value);
|
|
504
416
|
}
|
|
505
417
|
}
|
|
506
|
-
return null;
|
|
507
418
|
}
|
|
508
419
|
};
|
|
509
|
-
function
|
|
510
|
-
|
|
511
|
-
|
|
512
|
-
|
|
513
|
-
|
|
514
|
-
|
|
515
|
-
case Int16Array:
|
|
516
|
-
return draco.DT_INT16;
|
|
517
|
-
case Int32Array:
|
|
518
|
-
return draco.DT_INT32;
|
|
519
|
-
case Uint8Array:
|
|
520
|
-
return draco.DT_UINT8;
|
|
521
|
-
case Uint16Array:
|
|
522
|
-
return draco.DT_UINT16;
|
|
523
|
-
case Uint32Array:
|
|
524
|
-
return draco.DT_UINT32;
|
|
525
|
-
default:
|
|
526
|
-
return draco.DT_INVALID;
|
|
527
|
-
}
|
|
528
|
-
}
|
|
529
|
-
function getInt32Array(dracoArray) {
|
|
530
|
-
const numValues = dracoArray.size();
|
|
531
|
-
const intArray = new Int32Array(numValues);
|
|
532
|
-
for (let i = 0; i < numValues; i++) {
|
|
533
|
-
intArray[i] = dracoArray.GetValue(i);
|
|
420
|
+
function dracoInt8ArrayToArrayBuffer(dracoData) {
|
|
421
|
+
const byteLength = dracoData.size();
|
|
422
|
+
const outputBuffer = new ArrayBuffer(byteLength);
|
|
423
|
+
const outputData = new Int8Array(outputBuffer);
|
|
424
|
+
for (let i = 0; i < byteLength; ++i) {
|
|
425
|
+
outputData[i] = dracoData.GetValue(i);
|
|
534
426
|
}
|
|
535
|
-
return
|
|
427
|
+
return outputBuffer;
|
|
536
428
|
}
|
|
537
|
-
function
|
|
538
|
-
const
|
|
539
|
-
|
|
540
|
-
for (let i = 0; i < numValues; i++) {
|
|
541
|
-
intArray[i] = dracoArray.GetValue(i);
|
|
542
|
-
}
|
|
543
|
-
return intArray;
|
|
429
|
+
function getEntries(container) {
|
|
430
|
+
const hasEntriesFunc = container.entries && !container.hasOwnProperty("entries");
|
|
431
|
+
return hasEntriesFunc ? container.entries() : Object.entries(container);
|
|
544
432
|
}
|
|
545
433
|
|
|
546
|
-
// dist/lib/
|
|
547
|
-
var
|
|
548
|
-
|
|
549
|
-
|
|
550
|
-
var
|
|
551
|
-
|
|
552
|
-
|
|
553
|
-
|
|
554
|
-
|
|
555
|
-
|
|
556
|
-
|
|
557
|
-
|
|
558
|
-
|
|
559
|
-
|
|
434
|
+
// dist/lib/utils/version.js
|
|
435
|
+
var VERSION = true ? "4.4.0-alpha.0" : "latest";
|
|
436
|
+
|
|
437
|
+
// dist/draco-writer.js
|
|
438
|
+
var DEFAULT_DRACO_WRITER_OPTIONS = {
|
|
439
|
+
pointcloud: false,
|
|
440
|
+
// Set to true if pointcloud (mode: 0, no indices)
|
|
441
|
+
attributeNameEntry: "name"
|
|
442
|
+
// Draco Compression Parameters
|
|
443
|
+
// method: 'MESH_EDGEBREAKER_ENCODING', // Use draco defaults
|
|
444
|
+
// speed: [5, 5], // Use draco defaults
|
|
445
|
+
// quantization: { // Use draco defaults
|
|
446
|
+
// POSITION: 10
|
|
447
|
+
// }
|
|
560
448
|
};
|
|
561
|
-
var
|
|
562
|
-
|
|
563
|
-
|
|
564
|
-
|
|
565
|
-
|
|
449
|
+
var DracoWriterWorker = {
|
|
450
|
+
id: "draco-writer",
|
|
451
|
+
name: "Draco compressed geometry writer",
|
|
452
|
+
module: "draco",
|
|
453
|
+
version: VERSION,
|
|
454
|
+
worker: true,
|
|
455
|
+
options: {
|
|
456
|
+
draco: {},
|
|
457
|
+
source: null
|
|
458
|
+
}
|
|
566
459
|
};
|
|
567
|
-
var
|
|
568
|
-
|
|
569
|
-
|
|
570
|
-
|
|
571
|
-
|
|
572
|
-
|
|
573
|
-
|
|
574
|
-
|
|
575
|
-
|
|
576
|
-
|
|
460
|
+
var DracoWriter = {
|
|
461
|
+
name: "DRACO",
|
|
462
|
+
id: "draco",
|
|
463
|
+
module: "draco",
|
|
464
|
+
version: VERSION,
|
|
465
|
+
extensions: ["drc"],
|
|
466
|
+
mimeTypes: ["application/octet-stream"],
|
|
467
|
+
options: {
|
|
468
|
+
draco: DEFAULT_DRACO_WRITER_OPTIONS
|
|
469
|
+
},
|
|
470
|
+
encode
|
|
471
|
+
};
|
|
472
|
+
async function encode(data, options = {}) {
|
|
473
|
+
const { draco } = await loadDracoEncoderModule(options);
|
|
474
|
+
const dracoBuilder = new DracoBuilder(draco);
|
|
475
|
+
try {
|
|
476
|
+
return dracoBuilder.encodeSync(data, options.draco);
|
|
477
|
+
} finally {
|
|
478
|
+
dracoBuilder.destroy();
|
|
577
479
|
}
|
|
578
|
-
return await loadDecoderPromise;
|
|
579
480
|
}
|
|
580
|
-
|
|
581
|
-
|
|
582
|
-
|
|
583
|
-
|
|
584
|
-
|
|
585
|
-
|
|
586
|
-
|
|
587
|
-
|
|
481
|
+
|
|
482
|
+
// dist/lib/draco-parser.js
|
|
483
|
+
var import_schema_utils2 = require("@loaders.gl/schema-utils");
|
|
484
|
+
|
|
485
|
+
// dist/lib/utils/get-draco-schema.js
|
|
486
|
+
var import_schema_utils = require("@loaders.gl/schema-utils");
|
|
487
|
+
function getDracoSchema(attributes, loaderData, indices) {
|
|
488
|
+
const metadata = makeMetadata(loaderData.metadata);
|
|
489
|
+
const fields = [];
|
|
490
|
+
const namedLoaderDataAttributes = transformAttributesLoaderData(loaderData.attributes);
|
|
491
|
+
for (const attributeName in attributes) {
|
|
492
|
+
const attribute = attributes[attributeName];
|
|
493
|
+
const field = getArrowFieldFromAttribute(attributeName, attribute, namedLoaderDataAttributes[attributeName]);
|
|
494
|
+
fields.push(field);
|
|
588
495
|
}
|
|
589
|
-
|
|
590
|
-
|
|
591
|
-
|
|
592
|
-
let DracoDecoderModule;
|
|
593
|
-
let wasmBinary;
|
|
594
|
-
switch (options.draco && options.draco.decoderType) {
|
|
595
|
-
case "js":
|
|
596
|
-
DracoDecoderModule = await (0, import_worker_utils.loadLibrary)(DRACO_EXTERNAL_LIBRARY_URLS[DRACO_EXTERNAL_LIBRARIES.FALLBACK_DECODER], "draco", options, DRACO_EXTERNAL_LIBRARIES.FALLBACK_DECODER);
|
|
597
|
-
break;
|
|
598
|
-
case "wasm":
|
|
599
|
-
default:
|
|
600
|
-
[DracoDecoderModule, wasmBinary] = await Promise.all([
|
|
601
|
-
await (0, import_worker_utils.loadLibrary)(DRACO_EXTERNAL_LIBRARY_URLS[DRACO_EXTERNAL_LIBRARIES.DECODER], "draco", options, DRACO_EXTERNAL_LIBRARIES.DECODER),
|
|
602
|
-
await (0, import_worker_utils.loadLibrary)(DRACO_EXTERNAL_LIBRARY_URLS[DRACO_EXTERNAL_LIBRARIES.DECODER_WASM], "draco", options, DRACO_EXTERNAL_LIBRARIES.DECODER_WASM)
|
|
603
|
-
]);
|
|
496
|
+
if (indices) {
|
|
497
|
+
const indicesField = getArrowFieldFromAttribute("indices", indices);
|
|
498
|
+
fields.push(indicesField);
|
|
604
499
|
}
|
|
605
|
-
|
|
606
|
-
return await initializeDracoDecoder(DracoDecoderModule, wasmBinary);
|
|
500
|
+
return { fields, metadata };
|
|
607
501
|
}
|
|
608
|
-
function
|
|
609
|
-
const
|
|
610
|
-
|
|
611
|
-
|
|
502
|
+
function transformAttributesLoaderData(loaderData) {
|
|
503
|
+
const result = {};
|
|
504
|
+
for (const key in loaderData) {
|
|
505
|
+
const dracoAttribute = loaderData[key];
|
|
506
|
+
result[dracoAttribute.name || "undefined"] = dracoAttribute;
|
|
612
507
|
}
|
|
613
|
-
return
|
|
614
|
-
DracoDecoderModule({
|
|
615
|
-
...options,
|
|
616
|
-
onModuleLoaded: (draco) => resolve({ draco })
|
|
617
|
-
// Module is Promise-like. Wrap in object to avoid loop.
|
|
618
|
-
});
|
|
619
|
-
});
|
|
508
|
+
return result;
|
|
620
509
|
}
|
|
621
|
-
|
|
622
|
-
|
|
623
|
-
|
|
624
|
-
return
|
|
625
|
-
|
|
626
|
-
|
|
627
|
-
|
|
628
|
-
|
|
629
|
-
|
|
510
|
+
function getArrowFieldFromAttribute(attributeName, attribute, loaderData) {
|
|
511
|
+
const metadataMap = loaderData ? makeMetadata(loaderData.metadata) : void 0;
|
|
512
|
+
const field = (0, import_schema_utils.deduceMeshField)(attributeName, attribute, metadataMap);
|
|
513
|
+
return field;
|
|
514
|
+
}
|
|
515
|
+
function makeMetadata(metadata) {
|
|
516
|
+
Object.entries(metadata);
|
|
517
|
+
const serializedMetadata = {};
|
|
518
|
+
for (const key in metadata) {
|
|
519
|
+
serializedMetadata[`${key}.string`] = JSON.stringify(metadata[key]);
|
|
520
|
+
}
|
|
521
|
+
return serializedMetadata;
|
|
630
522
|
}
|
|
631
523
|
|
|
632
|
-
// dist/lib/draco-
|
|
633
|
-
var
|
|
524
|
+
// dist/lib/draco-parser.js
|
|
525
|
+
var DRACO_TO_GLTF_ATTRIBUTE_NAME_MAP = {
|
|
634
526
|
POSITION: "POSITION",
|
|
635
527
|
NORMAL: "NORMAL",
|
|
636
|
-
|
|
637
|
-
|
|
528
|
+
COLOR: "COLOR_0",
|
|
529
|
+
TEX_COORD: "TEXCOORD_0"
|
|
638
530
|
};
|
|
639
|
-
var
|
|
531
|
+
var DRACO_DATA_TYPE_TO_TYPED_ARRAY_MAP = {
|
|
532
|
+
1: Int8Array,
|
|
533
|
+
2: Uint8Array,
|
|
534
|
+
3: Int16Array,
|
|
535
|
+
4: Uint16Array,
|
|
536
|
+
5: Int32Array,
|
|
537
|
+
6: Uint32Array,
|
|
538
|
+
// 7: BigInt64Array,
|
|
539
|
+
// 8: BigUint64Array,
|
|
540
|
+
9: Float32Array
|
|
541
|
+
// 10: Float64Array
|
|
542
|
+
// 11: BOOL - What array type do we use for this?
|
|
640
543
|
};
|
|
641
|
-
var
|
|
544
|
+
var INDEX_ITEM_SIZE = 4;
|
|
545
|
+
var DracoParser = class {
|
|
642
546
|
draco;
|
|
643
|
-
|
|
644
|
-
|
|
645
|
-
dracoMetadataBuilder;
|
|
646
|
-
log;
|
|
547
|
+
decoder;
|
|
548
|
+
metadataQuerier;
|
|
647
549
|
// draco - the draco decoder, either import `draco3d` or load dynamically
|
|
648
550
|
constructor(draco) {
|
|
649
551
|
this.draco = draco;
|
|
650
|
-
this.
|
|
651
|
-
this.
|
|
652
|
-
this.dracoMetadataBuilder = new this.draco.MetadataBuilder();
|
|
552
|
+
this.decoder = new this.draco.Decoder();
|
|
553
|
+
this.metadataQuerier = new this.draco.MetadataQuerier();
|
|
653
554
|
}
|
|
555
|
+
/**
|
|
556
|
+
* Destroy draco resources
|
|
557
|
+
*/
|
|
654
558
|
destroy() {
|
|
655
|
-
this.
|
|
656
|
-
this.
|
|
657
|
-
this.destroyEncodedObject(this.dracoMetadataBuilder);
|
|
658
|
-
this.dracoMeshBuilder = null;
|
|
659
|
-
this.dracoEncoder = null;
|
|
660
|
-
this.draco = null;
|
|
661
|
-
}
|
|
662
|
-
// TBD - when does this need to be called?
|
|
663
|
-
destroyEncodedObject(object) {
|
|
664
|
-
if (object) {
|
|
665
|
-
this.draco.destroy(object);
|
|
666
|
-
}
|
|
559
|
+
this.draco.destroy(this.decoder);
|
|
560
|
+
this.draco.destroy(this.metadataQuerier);
|
|
667
561
|
}
|
|
668
562
|
/**
|
|
669
|
-
*
|
|
670
|
-
* @param
|
|
563
|
+
* NOTE: caller must call `destroyGeometry` on the return value after using it
|
|
564
|
+
* @param arrayBuffer
|
|
671
565
|
* @param options
|
|
672
566
|
*/
|
|
673
|
-
|
|
674
|
-
|
|
675
|
-
|
|
676
|
-
|
|
677
|
-
|
|
678
|
-
|
|
679
|
-
_getAttributesFromMesh(mesh) {
|
|
680
|
-
const attributes = { ...mesh, ...mesh.attributes };
|
|
681
|
-
if (mesh.indices) {
|
|
682
|
-
attributes.indices = mesh.indices;
|
|
683
|
-
}
|
|
684
|
-
return attributes;
|
|
685
|
-
}
|
|
686
|
-
_encodePointCloud(pointcloud, options) {
|
|
687
|
-
const dracoPointCloud = new this.draco.PointCloud();
|
|
688
|
-
if (options.metadata) {
|
|
689
|
-
this._addGeometryMetadata(dracoPointCloud, options.metadata);
|
|
690
|
-
}
|
|
691
|
-
const attributes = this._getAttributesFromMesh(pointcloud);
|
|
692
|
-
this._createDracoPointCloud(dracoPointCloud, attributes, options);
|
|
693
|
-
const dracoData = new this.draco.DracoInt8Array();
|
|
567
|
+
parseSync(arrayBuffer, options = {}) {
|
|
568
|
+
const buffer = new this.draco.DecoderBuffer();
|
|
569
|
+
buffer.Init(new Int8Array(arrayBuffer), arrayBuffer.byteLength);
|
|
570
|
+
this._disableAttributeTransforms(options);
|
|
571
|
+
const geometry_type = this.decoder.GetEncodedGeometryType(buffer);
|
|
572
|
+
const dracoGeometry = geometry_type === this.draco.TRIANGULAR_MESH ? new this.draco.Mesh() : new this.draco.PointCloud();
|
|
694
573
|
try {
|
|
695
|
-
|
|
696
|
-
|
|
697
|
-
|
|
574
|
+
let dracoStatus;
|
|
575
|
+
switch (geometry_type) {
|
|
576
|
+
case this.draco.TRIANGULAR_MESH:
|
|
577
|
+
dracoStatus = this.decoder.DecodeBufferToMesh(buffer, dracoGeometry);
|
|
578
|
+
break;
|
|
579
|
+
case this.draco.POINT_CLOUD:
|
|
580
|
+
dracoStatus = this.decoder.DecodeBufferToPointCloud(buffer, dracoGeometry);
|
|
581
|
+
break;
|
|
582
|
+
default:
|
|
583
|
+
throw new Error("DRACO: Unknown geometry type.");
|
|
698
584
|
}
|
|
699
|
-
|
|
700
|
-
|
|
701
|
-
|
|
585
|
+
if (!dracoStatus.ok() || !dracoGeometry.ptr) {
|
|
586
|
+
const message = `DRACO decompression failed: ${dracoStatus.error_msg()}`;
|
|
587
|
+
throw new Error(message);
|
|
588
|
+
}
|
|
589
|
+
const loaderData = this._getDracoLoaderData(dracoGeometry, geometry_type, options);
|
|
590
|
+
const geometry = this._getMeshData(dracoGeometry, loaderData, options);
|
|
591
|
+
const boundingBox = (0, import_schema_utils2.getMeshBoundingBox)(geometry.attributes);
|
|
592
|
+
const schema = getDracoSchema(geometry.attributes, loaderData, geometry.indices);
|
|
593
|
+
const data = {
|
|
594
|
+
loader: "draco",
|
|
595
|
+
loaderData,
|
|
596
|
+
header: {
|
|
597
|
+
vertexCount: dracoGeometry.num_points(),
|
|
598
|
+
boundingBox
|
|
599
|
+
},
|
|
600
|
+
...geometry,
|
|
601
|
+
schema
|
|
602
|
+
};
|
|
603
|
+
return data;
|
|
702
604
|
} finally {
|
|
703
|
-
this.
|
|
704
|
-
|
|
605
|
+
this.draco.destroy(buffer);
|
|
606
|
+
if (dracoGeometry) {
|
|
607
|
+
this.draco.destroy(dracoGeometry);
|
|
608
|
+
}
|
|
705
609
|
}
|
|
706
610
|
}
|
|
707
|
-
|
|
708
|
-
|
|
709
|
-
|
|
710
|
-
|
|
711
|
-
|
|
712
|
-
|
|
713
|
-
|
|
714
|
-
|
|
715
|
-
|
|
716
|
-
|
|
717
|
-
|
|
718
|
-
|
|
611
|
+
// Draco specific "loader data"
|
|
612
|
+
/**
|
|
613
|
+
* Extract
|
|
614
|
+
* @param dracoGeometry
|
|
615
|
+
* @param geometry_type
|
|
616
|
+
* @param options
|
|
617
|
+
* @returns
|
|
618
|
+
*/
|
|
619
|
+
_getDracoLoaderData(dracoGeometry, geometry_type, options) {
|
|
620
|
+
const metadata = this._getTopLevelMetadata(dracoGeometry);
|
|
621
|
+
const attributes = this._getDracoAttributes(dracoGeometry, options);
|
|
622
|
+
return {
|
|
623
|
+
geometry_type,
|
|
624
|
+
num_attributes: dracoGeometry.num_attributes(),
|
|
625
|
+
num_points: dracoGeometry.num_points(),
|
|
626
|
+
num_faces: dracoGeometry instanceof this.draco.Mesh ? dracoGeometry.num_faces() : 0,
|
|
627
|
+
metadata,
|
|
628
|
+
attributes
|
|
629
|
+
};
|
|
630
|
+
}
|
|
631
|
+
/**
|
|
632
|
+
* Extract all draco provided information and metadata for each attribute
|
|
633
|
+
* @param dracoGeometry
|
|
634
|
+
* @param options
|
|
635
|
+
* @returns
|
|
636
|
+
*/
|
|
637
|
+
_getDracoAttributes(dracoGeometry, options) {
|
|
638
|
+
const dracoAttributes = {};
|
|
639
|
+
for (let attributeId = 0; attributeId < dracoGeometry.num_attributes(); attributeId++) {
|
|
640
|
+
const dracoAttribute = this.decoder.GetAttribute(dracoGeometry, attributeId);
|
|
641
|
+
const metadata = this._getAttributeMetadata(dracoGeometry, attributeId);
|
|
642
|
+
dracoAttributes[dracoAttribute.unique_id()] = {
|
|
643
|
+
unique_id: dracoAttribute.unique_id(),
|
|
644
|
+
attribute_type: dracoAttribute.attribute_type(),
|
|
645
|
+
data_type: dracoAttribute.data_type(),
|
|
646
|
+
num_components: dracoAttribute.num_components(),
|
|
647
|
+
byte_offset: dracoAttribute.byte_offset(),
|
|
648
|
+
byte_stride: dracoAttribute.byte_stride(),
|
|
649
|
+
normalized: dracoAttribute.normalized(),
|
|
650
|
+
attribute_index: attributeId,
|
|
651
|
+
metadata
|
|
652
|
+
};
|
|
653
|
+
const quantization = this._getQuantizationTransform(dracoAttribute, options);
|
|
654
|
+
if (quantization) {
|
|
655
|
+
dracoAttributes[dracoAttribute.unique_id()].quantization_transform = quantization;
|
|
656
|
+
}
|
|
657
|
+
const octahedron = this._getOctahedronTransform(dracoAttribute, options);
|
|
658
|
+
if (octahedron) {
|
|
659
|
+
dracoAttributes[dracoAttribute.unique_id()].octahedron_transform = octahedron;
|
|
719
660
|
}
|
|
720
|
-
this.log(`DRACO encoded ${dracoMesh.num_points()} points
|
|
721
|
-
with ${dracoMesh.num_attributes()} attributes into ${encodedLen} bytes`);
|
|
722
|
-
return dracoInt8ArrayToArrayBuffer(dracoData);
|
|
723
|
-
} finally {
|
|
724
|
-
this.destroyEncodedObject(dracoData);
|
|
725
|
-
this.destroyEncodedObject(dracoMesh);
|
|
726
661
|
}
|
|
662
|
+
return dracoAttributes;
|
|
727
663
|
}
|
|
728
664
|
/**
|
|
729
|
-
*
|
|
730
|
-
*
|
|
665
|
+
* Get standard loaders.gl mesh category data
|
|
666
|
+
* Extracts the geometry from draco
|
|
667
|
+
* @param dracoGeometry
|
|
668
|
+
* @param options
|
|
731
669
|
*/
|
|
732
|
-
|
|
733
|
-
|
|
734
|
-
|
|
670
|
+
_getMeshData(dracoGeometry, loaderData, options) {
|
|
671
|
+
const attributes = this._getMeshAttributes(loaderData, dracoGeometry, options);
|
|
672
|
+
const positionAttribute = attributes.POSITION;
|
|
673
|
+
if (!positionAttribute) {
|
|
674
|
+
throw new Error("DRACO: No position attribute found.");
|
|
735
675
|
}
|
|
736
|
-
if (
|
|
737
|
-
|
|
738
|
-
|
|
676
|
+
if (dracoGeometry instanceof this.draco.Mesh) {
|
|
677
|
+
switch (options.topology) {
|
|
678
|
+
case "triangle-strip":
|
|
679
|
+
return {
|
|
680
|
+
topology: "triangle-strip",
|
|
681
|
+
// TODO - mode is wrong?
|
|
682
|
+
mode: 4,
|
|
683
|
+
// GL.TRIANGLES
|
|
684
|
+
attributes,
|
|
685
|
+
indices: {
|
|
686
|
+
value: this._getTriangleStripIndices(dracoGeometry),
|
|
687
|
+
size: 1
|
|
688
|
+
}
|
|
689
|
+
};
|
|
690
|
+
case "triangle-list":
|
|
691
|
+
default:
|
|
692
|
+
return {
|
|
693
|
+
topology: "triangle-list",
|
|
694
|
+
// TODO - mode is wrong?
|
|
695
|
+
mode: 5,
|
|
696
|
+
// GL.TRIANGLE_STRIP
|
|
697
|
+
attributes,
|
|
698
|
+
indices: {
|
|
699
|
+
value: this._getTriangleListIndices(dracoGeometry),
|
|
700
|
+
size: 1
|
|
701
|
+
}
|
|
702
|
+
};
|
|
703
|
+
}
|
|
739
704
|
}
|
|
740
|
-
|
|
741
|
-
|
|
742
|
-
|
|
743
|
-
|
|
744
|
-
|
|
705
|
+
return {
|
|
706
|
+
topology: "point-list",
|
|
707
|
+
mode: 0,
|
|
708
|
+
// GL.POINTS
|
|
709
|
+
attributes
|
|
710
|
+
};
|
|
711
|
+
}
|
|
712
|
+
_getMeshAttributes(loaderData, dracoGeometry, options) {
|
|
713
|
+
const attributes = {};
|
|
714
|
+
for (const loaderAttribute of Object.values(loaderData.attributes)) {
|
|
715
|
+
const attributeName = this._deduceAttributeName(loaderAttribute, options);
|
|
716
|
+
loaderAttribute.name = attributeName;
|
|
717
|
+
const values = this._getAttributeValues(dracoGeometry, loaderAttribute);
|
|
718
|
+
if (values) {
|
|
719
|
+
const { value, size } = values;
|
|
720
|
+
attributes[attributeName] = {
|
|
721
|
+
value,
|
|
722
|
+
size,
|
|
723
|
+
byteOffset: loaderAttribute.byte_offset,
|
|
724
|
+
byteStride: loaderAttribute.byte_stride,
|
|
725
|
+
normalized: loaderAttribute.normalized
|
|
726
|
+
};
|
|
745
727
|
}
|
|
746
728
|
}
|
|
729
|
+
return attributes;
|
|
747
730
|
}
|
|
731
|
+
// MESH INDICES EXTRACTION
|
|
748
732
|
/**
|
|
749
|
-
*
|
|
750
|
-
* @param
|
|
751
|
-
* @returns {Mesh}
|
|
733
|
+
* For meshes, we need indices to define the faces.
|
|
734
|
+
* @param dracoGeometry
|
|
752
735
|
*/
|
|
753
|
-
|
|
754
|
-
const
|
|
736
|
+
_getTriangleListIndices(dracoGeometry) {
|
|
737
|
+
const numFaces = dracoGeometry.num_faces();
|
|
738
|
+
const numIndices = numFaces * 3;
|
|
739
|
+
const byteLength = numIndices * INDEX_ITEM_SIZE;
|
|
740
|
+
const ptr = this.draco._malloc(byteLength);
|
|
755
741
|
try {
|
|
756
|
-
|
|
757
|
-
|
|
758
|
-
|
|
759
|
-
|
|
760
|
-
const vertexCount = positions.length / 3;
|
|
761
|
-
for (let attributeName in attributes) {
|
|
762
|
-
const attribute = attributes[attributeName];
|
|
763
|
-
attributeName = GLTF_TO_DRACO_ATTRIBUTE_NAME_MAP[attributeName] || attributeName;
|
|
764
|
-
const uniqueId = this._addAttributeToMesh(dracoMesh, attributeName, attribute, vertexCount);
|
|
765
|
-
if (uniqueId !== -1) {
|
|
766
|
-
this._addAttributeMetadata(dracoMesh, uniqueId, {
|
|
767
|
-
name: attributeName,
|
|
768
|
-
...optionalMetadata[attributeName] || {}
|
|
769
|
-
});
|
|
770
|
-
}
|
|
771
|
-
}
|
|
772
|
-
} catch (error) {
|
|
773
|
-
this.destroyEncodedObject(dracoMesh);
|
|
774
|
-
throw error;
|
|
742
|
+
this.decoder.GetTrianglesUInt32Array(dracoGeometry, byteLength, ptr);
|
|
743
|
+
return new Uint32Array(this.draco.HEAPF32.buffer, ptr, numIndices).slice();
|
|
744
|
+
} finally {
|
|
745
|
+
this.draco._free(ptr);
|
|
775
746
|
}
|
|
776
|
-
return dracoMesh;
|
|
777
747
|
}
|
|
778
748
|
/**
|
|
779
|
-
*
|
|
780
|
-
* @param
|
|
749
|
+
* For meshes, we need indices to define the faces.
|
|
750
|
+
* @param dracoGeometry
|
|
781
751
|
*/
|
|
782
|
-
|
|
783
|
-
const
|
|
752
|
+
_getTriangleStripIndices(dracoGeometry) {
|
|
753
|
+
const dracoArray = new this.draco.DracoInt32Array();
|
|
784
754
|
try {
|
|
785
|
-
|
|
786
|
-
|
|
787
|
-
|
|
788
|
-
|
|
789
|
-
const vertexCount = positions.length / 3;
|
|
790
|
-
for (let attributeName in attributes) {
|
|
791
|
-
const attribute = attributes[attributeName];
|
|
792
|
-
attributeName = GLTF_TO_DRACO_ATTRIBUTE_NAME_MAP[attributeName] || attributeName;
|
|
793
|
-
const uniqueId = this._addAttributeToMesh(dracoPointCloud, attributeName, attribute, vertexCount);
|
|
794
|
-
if (uniqueId !== -1) {
|
|
795
|
-
this._addAttributeMetadata(dracoPointCloud, uniqueId, {
|
|
796
|
-
name: attributeName,
|
|
797
|
-
...optionalMetadata[attributeName] || {}
|
|
798
|
-
});
|
|
799
|
-
}
|
|
800
|
-
}
|
|
801
|
-
} catch (error) {
|
|
802
|
-
this.destroyEncodedObject(dracoPointCloud);
|
|
803
|
-
throw error;
|
|
755
|
+
this.decoder.GetTriangleStripsFromMesh(dracoGeometry, dracoArray);
|
|
756
|
+
return getUint32Array(dracoArray);
|
|
757
|
+
} finally {
|
|
758
|
+
this.draco.destroy(dracoArray);
|
|
804
759
|
}
|
|
805
|
-
return dracoPointCloud;
|
|
806
760
|
}
|
|
807
761
|
/**
|
|
808
|
-
*
|
|
762
|
+
*
|
|
763
|
+
* @param dracoGeometry
|
|
764
|
+
* @param dracoAttribute
|
|
809
765
|
* @param attributeName
|
|
810
|
-
* @param attribute
|
|
811
|
-
* @param vertexCount
|
|
812
766
|
*/
|
|
813
|
-
|
|
814
|
-
|
|
815
|
-
|
|
816
|
-
|
|
817
|
-
|
|
818
|
-
const size = attribute.length / vertexCount;
|
|
819
|
-
if (type === "indices") {
|
|
820
|
-
const numFaces = attribute.length / 3;
|
|
821
|
-
this.log(`Adding attribute ${attributeName}, size ${numFaces}`);
|
|
822
|
-
this.dracoMeshBuilder.AddFacesToMesh(mesh, numFaces, attribute);
|
|
823
|
-
return -1;
|
|
767
|
+
_getAttributeValues(dracoGeometry, attribute) {
|
|
768
|
+
const TypedArrayCtor = DRACO_DATA_TYPE_TO_TYPED_ARRAY_MAP[attribute.data_type];
|
|
769
|
+
if (!TypedArrayCtor) {
|
|
770
|
+
console.warn(`DRACO: Unsupported attribute type ${attribute.data_type}`);
|
|
771
|
+
return null;
|
|
824
772
|
}
|
|
825
|
-
|
|
826
|
-
const
|
|
827
|
-
const
|
|
828
|
-
|
|
829
|
-
|
|
830
|
-
|
|
831
|
-
|
|
832
|
-
|
|
833
|
-
|
|
834
|
-
|
|
835
|
-
|
|
836
|
-
|
|
837
|
-
|
|
838
|
-
case Uint16Array:
|
|
839
|
-
return builder.AddUInt16Attribute(mesh, type, vertexCount, size, new Uint16Array(buffer));
|
|
840
|
-
case Uint32Array:
|
|
841
|
-
return builder.AddUInt32Attribute(mesh, type, vertexCount, size, new Uint32Array(buffer));
|
|
842
|
-
case Float32Array:
|
|
843
|
-
return builder.AddFloatAttribute(mesh, type, vertexCount, size, new Float32Array(buffer));
|
|
844
|
-
default:
|
|
845
|
-
console.warn("Unsupported attribute type", attribute);
|
|
846
|
-
return -1;
|
|
773
|
+
const numComponents = attribute.num_components;
|
|
774
|
+
const numPoints = dracoGeometry.num_points();
|
|
775
|
+
const numValues = numPoints * numComponents;
|
|
776
|
+
const byteLength = numValues * TypedArrayCtor.BYTES_PER_ELEMENT;
|
|
777
|
+
const dataType = getDracoDataType(this.draco, TypedArrayCtor);
|
|
778
|
+
let value;
|
|
779
|
+
const ptr = this.draco._malloc(byteLength);
|
|
780
|
+
try {
|
|
781
|
+
const dracoAttribute = this.decoder.GetAttribute(dracoGeometry, attribute.attribute_index);
|
|
782
|
+
this.decoder.GetAttributeDataArrayForAllPoints(dracoGeometry, dracoAttribute, dataType, byteLength, ptr);
|
|
783
|
+
value = new TypedArrayCtor(this.draco.HEAPF32.buffer, ptr, numValues).slice();
|
|
784
|
+
} finally {
|
|
785
|
+
this.draco._free(ptr);
|
|
847
786
|
}
|
|
787
|
+
return { value, size: numComponents };
|
|
848
788
|
}
|
|
789
|
+
// Attribute names
|
|
849
790
|
/**
|
|
850
|
-
* DRACO
|
|
851
|
-
*
|
|
852
|
-
|
|
791
|
+
* DRACO does not store attribute names - We need to deduce an attribute name
|
|
792
|
+
* for each attribute
|
|
793
|
+
_getAttributeNames(
|
|
794
|
+
dracoGeometry: Mesh | PointCloud,
|
|
795
|
+
options: DracoParseOptions
|
|
796
|
+
): {[unique_id: number]: string} {
|
|
797
|
+
const attributeNames: {[unique_id: number]: string} = {};
|
|
798
|
+
for (let attributeId = 0; attributeId < dracoGeometry.num_attributes(); attributeId++) {
|
|
799
|
+
const dracoAttribute = this.decoder.GetAttribute(dracoGeometry, attributeId);
|
|
800
|
+
const attributeName = this._deduceAttributeName(dracoAttribute, options);
|
|
801
|
+
attributeNames[attributeName] = attributeName;
|
|
802
|
+
}
|
|
803
|
+
return attributeNames;
|
|
804
|
+
}
|
|
853
805
|
*/
|
|
854
|
-
|
|
855
|
-
|
|
856
|
-
|
|
857
|
-
|
|
858
|
-
|
|
859
|
-
|
|
860
|
-
|
|
861
|
-
|
|
862
|
-
|
|
863
|
-
|
|
864
|
-
|
|
865
|
-
|
|
866
|
-
|
|
867
|
-
return this.draco.COLOR;
|
|
868
|
-
case "texcoord":
|
|
869
|
-
case "texcoords":
|
|
870
|
-
return this.draco.TEX_COORD;
|
|
871
|
-
default:
|
|
872
|
-
return this.draco.GENERIC;
|
|
806
|
+
/**
|
|
807
|
+
* Deduce an attribute name.
|
|
808
|
+
* @note DRACO does not save attribute names, just general type (POSITION, COLOR)
|
|
809
|
+
* to help optimize compression. We generate GLTF compatible names for the Draco-recognized
|
|
810
|
+
* types
|
|
811
|
+
* @param attributeData
|
|
812
|
+
*/
|
|
813
|
+
_deduceAttributeName(attribute, options) {
|
|
814
|
+
const uniqueId = attribute.unique_id;
|
|
815
|
+
for (const [attributeName, attributeUniqueId] of Object.entries(options.extraAttributes || {})) {
|
|
816
|
+
if (attributeUniqueId === uniqueId) {
|
|
817
|
+
return attributeName;
|
|
818
|
+
}
|
|
873
819
|
}
|
|
874
|
-
|
|
875
|
-
|
|
876
|
-
|
|
877
|
-
|
|
878
|
-
|
|
879
|
-
if (dracoType === this.draco.POSITION) {
|
|
880
|
-
return attribute;
|
|
820
|
+
const thisAttributeType = attribute.attribute_type;
|
|
821
|
+
for (const dracoAttributeConstant in DRACO_TO_GLTF_ATTRIBUTE_NAME_MAP) {
|
|
822
|
+
const attributeType = this.draco[dracoAttributeConstant];
|
|
823
|
+
if (attributeType === thisAttributeType) {
|
|
824
|
+
return DRACO_TO_GLTF_ATTRIBUTE_NAME_MAP[dracoAttributeConstant];
|
|
881
825
|
}
|
|
882
826
|
}
|
|
883
|
-
|
|
827
|
+
const entryName = options.attributeNameEntry || "name";
|
|
828
|
+
if (attribute.metadata[entryName]) {
|
|
829
|
+
return attribute.metadata[entryName].string;
|
|
830
|
+
}
|
|
831
|
+
return `CUSTOM_ATTRIBUTE_${uniqueId}`;
|
|
832
|
+
}
|
|
833
|
+
// METADATA EXTRACTION
|
|
834
|
+
/** Get top level metadata */
|
|
835
|
+
_getTopLevelMetadata(dracoGeometry) {
|
|
836
|
+
const dracoMetadata = this.decoder.GetMetadata(dracoGeometry);
|
|
837
|
+
return this._getDracoMetadata(dracoMetadata);
|
|
838
|
+
}
|
|
839
|
+
/** Get per attribute metadata */
|
|
840
|
+
_getAttributeMetadata(dracoGeometry, attributeId) {
|
|
841
|
+
const dracoMetadata = this.decoder.GetAttributeMetadata(dracoGeometry, attributeId);
|
|
842
|
+
return this._getDracoMetadata(dracoMetadata);
|
|
884
843
|
}
|
|
885
844
|
/**
|
|
886
|
-
*
|
|
887
|
-
* @param
|
|
888
|
-
* @
|
|
845
|
+
* Extract metadata field values
|
|
846
|
+
* @param dracoMetadata
|
|
847
|
+
* @returns
|
|
889
848
|
*/
|
|
890
|
-
|
|
891
|
-
|
|
892
|
-
|
|
893
|
-
|
|
849
|
+
_getDracoMetadata(dracoMetadata) {
|
|
850
|
+
if (!dracoMetadata || !dracoMetadata.ptr) {
|
|
851
|
+
return {};
|
|
852
|
+
}
|
|
853
|
+
const result = {};
|
|
854
|
+
const numEntries = this.metadataQuerier.NumEntries(dracoMetadata);
|
|
855
|
+
for (let entryIndex = 0; entryIndex < numEntries; entryIndex++) {
|
|
856
|
+
const entryName = this.metadataQuerier.GetEntryName(dracoMetadata, entryIndex);
|
|
857
|
+
result[entryName] = this._getDracoMetadataField(dracoMetadata, entryName);
|
|
858
|
+
}
|
|
859
|
+
return result;
|
|
894
860
|
}
|
|
895
861
|
/**
|
|
896
|
-
*
|
|
897
|
-
* @param
|
|
898
|
-
* @param
|
|
899
|
-
* @param metadata
|
|
862
|
+
* Extracts possible values for one metadata entry by name
|
|
863
|
+
* @param dracoMetadata
|
|
864
|
+
* @param entryName
|
|
900
865
|
*/
|
|
901
|
-
|
|
902
|
-
const
|
|
903
|
-
|
|
904
|
-
|
|
866
|
+
_getDracoMetadataField(dracoMetadata, entryName) {
|
|
867
|
+
const dracoArray = new this.draco.DracoInt32Array();
|
|
868
|
+
try {
|
|
869
|
+
this.metadataQuerier.GetIntEntryArray(dracoMetadata, entryName, dracoArray);
|
|
870
|
+
const intArray = getInt32Array(dracoArray);
|
|
871
|
+
return {
|
|
872
|
+
int: this.metadataQuerier.GetIntEntry(dracoMetadata, entryName),
|
|
873
|
+
string: this.metadataQuerier.GetStringEntry(dracoMetadata, entryName),
|
|
874
|
+
double: this.metadataQuerier.GetDoubleEntry(dracoMetadata, entryName),
|
|
875
|
+
intArray
|
|
876
|
+
};
|
|
877
|
+
} finally {
|
|
878
|
+
this.draco.destroy(dracoArray);
|
|
879
|
+
}
|
|
880
|
+
}
|
|
881
|
+
// QUANTIZED ATTRIBUTE SUPPORT (NO DECOMPRESSION)
|
|
882
|
+
/** Skip transforms for specific attribute types */
|
|
883
|
+
_disableAttributeTransforms(options) {
|
|
884
|
+
const { quantizedAttributes = [], octahedronAttributes = [] } = options;
|
|
885
|
+
const skipAttributes = [...quantizedAttributes, ...octahedronAttributes];
|
|
886
|
+
for (const dracoAttributeName of skipAttributes) {
|
|
887
|
+
this.decoder.SkipAttributeTransform(this.draco[dracoAttributeName]);
|
|
888
|
+
}
|
|
905
889
|
}
|
|
906
890
|
/**
|
|
907
|
-
*
|
|
908
|
-
* @
|
|
909
|
-
* @param metadata
|
|
891
|
+
* Extract (and apply?) Position Transform
|
|
892
|
+
* @todo not used
|
|
910
893
|
*/
|
|
911
|
-
|
|
912
|
-
|
|
913
|
-
|
|
914
|
-
|
|
915
|
-
|
|
916
|
-
|
|
917
|
-
|
|
918
|
-
|
|
919
|
-
|
|
920
|
-
|
|
921
|
-
|
|
922
|
-
|
|
923
|
-
|
|
924
|
-
|
|
925
|
-
|
|
926
|
-
|
|
927
|
-
|
|
928
|
-
|
|
894
|
+
_getQuantizationTransform(dracoAttribute, options) {
|
|
895
|
+
const { quantizedAttributes = [] } = options;
|
|
896
|
+
const attribute_type = dracoAttribute.attribute_type();
|
|
897
|
+
const skip = quantizedAttributes.map((type) => this.decoder[type]).includes(attribute_type);
|
|
898
|
+
if (skip) {
|
|
899
|
+
const transform = new this.draco.AttributeQuantizationTransform();
|
|
900
|
+
try {
|
|
901
|
+
if (transform.InitFromAttribute(dracoAttribute)) {
|
|
902
|
+
return {
|
|
903
|
+
quantization_bits: transform.quantization_bits(),
|
|
904
|
+
range: transform.range(),
|
|
905
|
+
min_values: new Float32Array([1, 2, 3]).map((i) => transform.min_value(i))
|
|
906
|
+
};
|
|
907
|
+
}
|
|
908
|
+
} finally {
|
|
909
|
+
this.draco.destroy(transform);
|
|
910
|
+
}
|
|
911
|
+
}
|
|
912
|
+
return null;
|
|
913
|
+
}
|
|
914
|
+
_getOctahedronTransform(dracoAttribute, options) {
|
|
915
|
+
const { octahedronAttributes = [] } = options;
|
|
916
|
+
const attribute_type = dracoAttribute.attribute_type();
|
|
917
|
+
const octahedron = octahedronAttributes.map((type) => this.decoder[type]).includes(attribute_type);
|
|
918
|
+
if (octahedron) {
|
|
919
|
+
const transform = new this.draco.AttributeQuantizationTransform();
|
|
920
|
+
try {
|
|
921
|
+
if (transform.InitFromAttribute(dracoAttribute)) {
|
|
922
|
+
return {
|
|
923
|
+
quantization_bits: transform.quantization_bits()
|
|
924
|
+
};
|
|
925
|
+
}
|
|
926
|
+
} finally {
|
|
927
|
+
this.draco.destroy(transform);
|
|
929
928
|
}
|
|
930
929
|
}
|
|
930
|
+
return null;
|
|
931
931
|
}
|
|
932
932
|
};
|
|
933
|
-
function
|
|
934
|
-
|
|
935
|
-
|
|
936
|
-
|
|
937
|
-
|
|
938
|
-
|
|
933
|
+
function getDracoDataType(draco, attributeType) {
|
|
934
|
+
switch (attributeType) {
|
|
935
|
+
case Float32Array:
|
|
936
|
+
return draco.DT_FLOAT32;
|
|
937
|
+
case Int8Array:
|
|
938
|
+
return draco.DT_INT8;
|
|
939
|
+
case Int16Array:
|
|
940
|
+
return draco.DT_INT16;
|
|
941
|
+
case Int32Array:
|
|
942
|
+
return draco.DT_INT32;
|
|
943
|
+
case Uint8Array:
|
|
944
|
+
return draco.DT_UINT8;
|
|
945
|
+
case Uint16Array:
|
|
946
|
+
return draco.DT_UINT16;
|
|
947
|
+
case Uint32Array:
|
|
948
|
+
return draco.DT_UINT32;
|
|
949
|
+
default:
|
|
950
|
+
return draco.DT_INVALID;
|
|
939
951
|
}
|
|
940
|
-
return outputBuffer;
|
|
941
952
|
}
|
|
942
|
-
function
|
|
943
|
-
const
|
|
944
|
-
|
|
953
|
+
function getInt32Array(dracoArray) {
|
|
954
|
+
const numValues = dracoArray.size();
|
|
955
|
+
const intArray = new Int32Array(numValues);
|
|
956
|
+
for (let i = 0; i < numValues; i++) {
|
|
957
|
+
intArray[i] = dracoArray.GetValue(i);
|
|
958
|
+
}
|
|
959
|
+
return intArray;
|
|
945
960
|
}
|
|
946
|
-
|
|
947
|
-
|
|
948
|
-
|
|
949
|
-
|
|
950
|
-
|
|
951
|
-
attributeNameEntry: "name"
|
|
952
|
-
// Draco Compression Parameters
|
|
953
|
-
// method: 'MESH_EDGEBREAKER_ENCODING', // Use draco defaults
|
|
954
|
-
// speed: [5, 5], // Use draco defaults
|
|
955
|
-
// quantization: { // Use draco defaults
|
|
956
|
-
// POSITION: 10
|
|
957
|
-
// }
|
|
958
|
-
};
|
|
959
|
-
var DracoWriter = {
|
|
960
|
-
name: "DRACO",
|
|
961
|
-
id: "draco",
|
|
962
|
-
module: "draco",
|
|
963
|
-
version: VERSION,
|
|
964
|
-
extensions: ["drc"],
|
|
965
|
-
options: {
|
|
966
|
-
draco: DEFAULT_DRACO_WRITER_OPTIONS
|
|
967
|
-
},
|
|
968
|
-
encode
|
|
969
|
-
};
|
|
970
|
-
async function encode(data, options = {}) {
|
|
971
|
-
const { draco } = await loadDracoEncoderModule(options);
|
|
972
|
-
const dracoBuilder = new DracoBuilder(draco);
|
|
973
|
-
try {
|
|
974
|
-
return dracoBuilder.encodeSync(data, options.draco);
|
|
975
|
-
} finally {
|
|
976
|
-
dracoBuilder.destroy();
|
|
961
|
+
function getUint32Array(dracoArray) {
|
|
962
|
+
const numValues = dracoArray.size();
|
|
963
|
+
const intArray = new Int32Array(numValues);
|
|
964
|
+
for (let i = 0; i < numValues; i++) {
|
|
965
|
+
intArray[i] = dracoArray.GetValue(i);
|
|
977
966
|
}
|
|
967
|
+
return intArray;
|
|
978
968
|
}
|
|
979
969
|
|
|
980
|
-
// dist/
|
|
981
|
-
var
|
|
982
|
-
|
|
983
|
-
|
|
970
|
+
// dist/draco-loader.js
|
|
971
|
+
var DracoWorkerLoader = {
|
|
972
|
+
dataType: null,
|
|
973
|
+
batchType: null,
|
|
974
|
+
name: "Draco",
|
|
975
|
+
id: "draco",
|
|
984
976
|
module: "draco",
|
|
977
|
+
// shapes: ['mesh'],
|
|
985
978
|
version: VERSION,
|
|
986
979
|
worker: true,
|
|
980
|
+
extensions: ["drc"],
|
|
981
|
+
mimeTypes: ["application/octet-stream"],
|
|
982
|
+
binary: true,
|
|
983
|
+
tests: ["DRACO"],
|
|
987
984
|
options: {
|
|
988
|
-
draco: {
|
|
989
|
-
|
|
985
|
+
draco: {
|
|
986
|
+
decoderType: typeof WebAssembly === "object" ? "wasm" : "js",
|
|
987
|
+
// 'js' for IE11
|
|
988
|
+
libraryPath: "libs/",
|
|
989
|
+
extraAttributes: {},
|
|
990
|
+
attributeNameEntry: void 0
|
|
991
|
+
}
|
|
990
992
|
}
|
|
991
993
|
};
|
|
992
|
-
var
|
|
993
|
-
...
|
|
994
|
+
var DracoLoader = {
|
|
995
|
+
...DracoWorkerLoader,
|
|
994
996
|
parse
|
|
995
997
|
};
|
|
996
998
|
async function parse(arrayBuffer, options) {
|
|
@@ -1002,4 +1004,18 @@ async function parse(arrayBuffer, options) {
|
|
|
1002
1004
|
dracoParser.destroy();
|
|
1003
1005
|
}
|
|
1004
1006
|
}
|
|
1007
|
+
|
|
1008
|
+
// dist/draco-arrow-loader.js
|
|
1009
|
+
var import_schema_utils3 = require("@loaders.gl/schema-utils");
|
|
1010
|
+
var DracoArrowLoader = {
|
|
1011
|
+
...DracoLoader,
|
|
1012
|
+
dataType: null,
|
|
1013
|
+
worker: false,
|
|
1014
|
+
parse: parse2
|
|
1015
|
+
};
|
|
1016
|
+
async function parse2(arrayBuffer, options) {
|
|
1017
|
+
const mesh = await DracoLoader.parse(arrayBuffer, options);
|
|
1018
|
+
const arrowTable = (0, import_schema_utils3.convertMeshToTable)(mesh, "arrow-table");
|
|
1019
|
+
return arrowTable;
|
|
1020
|
+
}
|
|
1005
1021
|
//# sourceMappingURL=index.cjs.map
|