"use strict"; Object.defineProperty(exports, Symbol.toStringTag, { value: "Module" }); const THREE = require("three"); const _taskCache = /* @__PURE__ */ new WeakMap(); class DRACOLoader extends THREE.Loader { constructor(manager) { super(manager); this.decoderPath = ""; this.decoderConfig = {}; this.decoderBinary = null; this.decoderPending = null; this.workerLimit = 4; this.workerPool = []; this.workerNextTaskID = 1; this.workerSourceURL = ""; this.defaultAttributeIDs = { position: "POSITION", normal: "NORMAL", color: "COLOR", uv: "TEX_COORD" }; this.defaultAttributeTypes = { position: "Float32Array", normal: "Float32Array", color: "Float32Array", uv: "Float32Array" }; } setDecoderPath(path) { this.decoderPath = path; return this; } setDecoderConfig(config) { this.decoderConfig = config; return this; } setWorkerLimit(workerLimit) { this.workerLimit = workerLimit; return this; } load(url, onLoad, onProgress, onError) { const loader = new THREE.FileLoader(this.manager); loader.setPath(this.path); loader.setResponseType("arraybuffer"); loader.setRequestHeader(this.requestHeader); loader.setWithCredentials(this.withCredentials); loader.load( url, (buffer) => { const taskConfig = { attributeIDs: this.defaultAttributeIDs, attributeTypes: this.defaultAttributeTypes, useUniqueIDs: false }; this.decodeGeometry(buffer, taskConfig).then(onLoad).catch(onError); }, onProgress, onError ); } /** @deprecated Kept for backward-compatibility with previous DRACOLoader versions. */ decodeDracoFile(buffer, callback, attributeIDs, attributeTypes) { const taskConfig = { attributeIDs: attributeIDs || this.defaultAttributeIDs, attributeTypes: attributeTypes || this.defaultAttributeTypes, useUniqueIDs: !!attributeIDs }; this.decodeGeometry(buffer, taskConfig).then(callback); } decodeGeometry(buffer, taskConfig) { for (const attribute in taskConfig.attributeTypes) { const type = taskConfig.attributeTypes[attribute]; if (type.BYTES_PER_ELEMENT !== void 0) { taskConfig.attributeTypes[attribute] = type.name; } } const taskKey = JSON.stringify(taskConfig); if (_taskCache.has(buffer)) { const cachedTask = _taskCache.get(buffer); if (cachedTask.key === taskKey) { return cachedTask.promise; } else if (buffer.byteLength === 0) { throw new Error( "THREE.DRACOLoader: Unable to re-decode a buffer with different settings. Buffer has already been transferred." ); } } let worker; const taskID = this.workerNextTaskID++; const taskCost = buffer.byteLength; const geometryPending = this._getWorker(taskID, taskCost).then((_worker) => { worker = _worker; return new Promise((resolve, reject) => { worker._callbacks[taskID] = { resolve, reject }; worker.postMessage({ type: "decode", id: taskID, taskConfig, buffer }, [buffer]); }); }).then((message) => this._createGeometry(message.geometry)); geometryPending.catch(() => true).then(() => { if (worker && taskID) { this._releaseTask(worker, taskID); } }); _taskCache.set(buffer, { key: taskKey, promise: geometryPending }); return geometryPending; } _createGeometry(geometryData) { const geometry = new THREE.BufferGeometry(); if (geometryData.index) { geometry.setIndex(new THREE.BufferAttribute(geometryData.index.array, 1)); } for (let i = 0; i < geometryData.attributes.length; i++) { const attribute = geometryData.attributes[i]; const name = attribute.name; const array = attribute.array; const itemSize = attribute.itemSize; geometry.setAttribute(name, new THREE.BufferAttribute(array, itemSize)); } return geometry; } _loadLibrary(url, responseType) { const loader = new THREE.FileLoader(this.manager); loader.setPath(this.decoderPath); loader.setResponseType(responseType); loader.setWithCredentials(this.withCredentials); return new Promise((resolve, reject) => { loader.load(url, resolve, void 0, reject); }); } preload() { this._initDecoder(); return this; } _initDecoder() { if (this.decoderPending) return this.decoderPending; const useJS = typeof WebAssembly !== "object" || this.decoderConfig.type === "js"; const librariesPending = []; if (useJS) { librariesPending.push(this._loadLibrary("draco_decoder.js", "text")); } else { librariesPending.push(this._loadLibrary("draco_wasm_wrapper.js", "text")); librariesPending.push(this._loadLibrary("draco_decoder.wasm", "arraybuffer")); } this.decoderPending = Promise.all(librariesPending).then((libraries) => { const jsContent = libraries[0]; if (!useJS) { this.decoderConfig.wasmBinary = libraries[1]; } const fn = DRACOWorker.toString(); const body = [ "/* draco decoder */", jsContent, "", "/* worker */", fn.substring(fn.indexOf("{") + 1, fn.lastIndexOf("}")) ].join("\n"); this.workerSourceURL = URL.createObjectURL(new Blob([body])); }); return this.decoderPending; } _getWorker(taskID, taskCost) { return this._initDecoder().then(() => { if (this.workerPool.length < this.workerLimit) { const worker2 = new Worker(this.workerSourceURL); worker2._callbacks = {}; worker2._taskCosts = {}; worker2._taskLoad = 0; worker2.postMessage({ type: "init", decoderConfig: this.decoderConfig }); worker2.onmessage = function(e) { const message = e.data; switch (message.type) { case "decode": worker2._callbacks[message.id].resolve(message); break; case "error": worker2._callbacks[message.id].reject(message); break; default: console.error('THREE.DRACOLoader: Unexpected message, "' + message.type + '"'); } }; this.workerPool.push(worker2); } else { this.workerPool.sort(function(a, b) { return a._taskLoad > b._taskLoad ? -1 : 1; }); } const worker = this.workerPool[this.workerPool.length - 1]; worker._taskCosts[taskID] = taskCost; worker._taskLoad += taskCost; return worker; }); } _releaseTask(worker, taskID) { worker._taskLoad -= worker._taskCosts[taskID]; delete worker._callbacks[taskID]; delete worker._taskCosts[taskID]; } debug() { console.log( "Task load: ", this.workerPool.map((worker) => worker._taskLoad) ); } dispose() { for (let i = 0; i < this.workerPool.length; ++i) { this.workerPool[i].terminate(); } this.workerPool.length = 0; return this; } } function DRACOWorker() { let decoderConfig; let decoderPending; onmessage = function(e) { const message = e.data; switch (message.type) { case "init": decoderConfig = message.decoderConfig; decoderPending = new Promise(function(resolve) { decoderConfig.onModuleLoaded = function(draco) { resolve({ draco }); }; DracoDecoderModule(decoderConfig); }); break; case "decode": const buffer = message.buffer; const taskConfig = message.taskConfig; decoderPending.then((module2) => { const draco = module2.draco; const decoder = new draco.Decoder(); const decoderBuffer = new draco.DecoderBuffer(); decoderBuffer.Init(new Int8Array(buffer), buffer.byteLength); try { const geometry = decodeGeometry(draco, decoder, decoderBuffer, taskConfig); const buffers = geometry.attributes.map((attr) => attr.array.buffer); if (geometry.index) buffers.push(geometry.index.array.buffer); self.postMessage({ type: "decode", id: message.id, geometry }, buffers); } catch (error) { console.error(error); self.postMessage({ type: "error", id: message.id, error: error.message }); } finally { draco.destroy(decoderBuffer); draco.destroy(decoder); } }); break; } }; function decodeGeometry(draco, decoder, decoderBuffer, taskConfig) { const attributeIDs = taskConfig.attributeIDs; const attributeTypes = taskConfig.attributeTypes; let dracoGeometry; let decodingStatus; const geometryType = decoder.GetEncodedGeometryType(decoderBuffer); if (geometryType === draco.TRIANGULAR_MESH) { dracoGeometry = new draco.Mesh(); decodingStatus = decoder.DecodeBufferToMesh(decoderBuffer, dracoGeometry); } else if (geometryType === draco.POINT_CLOUD) { dracoGeometry = new draco.PointCloud(); decodingStatus = decoder.DecodeBufferToPointCloud(decoderBuffer, dracoGeometry); } else { throw new Error("THREE.DRACOLoader: Unexpected geometry type."); } if (!decodingStatus.ok() || dracoGeometry.ptr === 0) { throw new Error("THREE.DRACOLoader: Decoding failed: " + decodingStatus.error_msg()); } const geometry = { index: null, attributes: [] }; for (const attributeName in attributeIDs) { const attributeType = self[attributeTypes[attributeName]]; let attribute; let attributeID; if (taskConfig.useUniqueIDs) { attributeID = attributeIDs[attributeName]; attribute = decoder.GetAttributeByUniqueId(dracoGeometry, attributeID); } else { attributeID = decoder.GetAttributeId(dracoGeometry, draco[attributeIDs[attributeName]]); if (attributeID === -1) continue; attribute = decoder.GetAttribute(dracoGeometry, attributeID); } geometry.attributes.push(decodeAttribute(draco, decoder, dracoGeometry, attributeName, attributeType, attribute)); } if (geometryType === draco.TRIANGULAR_MESH) { geometry.index = decodeIndex(draco, decoder, dracoGeometry); } draco.destroy(dracoGeometry); return geometry; } function decodeIndex(draco, decoder, dracoGeometry) { const numFaces = dracoGeometry.num_faces(); const numIndices = numFaces * 3; const byteLength = numIndices * 4; const ptr = draco._malloc(byteLength); decoder.GetTrianglesUInt32Array(dracoGeometry, byteLength, ptr); const index = new Uint32Array(draco.HEAPF32.buffer, ptr, numIndices).slice(); draco._free(ptr); return { array: index, itemSize: 1 }; } function decodeAttribute(draco, decoder, dracoGeometry, attributeName, attributeType, attribute) { const numComponents = attribute.num_components(); const numPoints = dracoGeometry.num_points(); const numValues = numPoints * numComponents; const byteLength = numValues * attributeType.BYTES_PER_ELEMENT; const dataType = getDracoDataType(draco, attributeType); const ptr = draco._malloc(byteLength); decoder.GetAttributeDataArrayForAllPoints(dracoGeometry, attribute, dataType, byteLength, ptr); const array = new attributeType(draco.HEAPF32.buffer, ptr, numValues).slice(); draco._free(ptr); return { name: attributeName, array, itemSize: numComponents }; } function getDracoDataType(draco, attributeType) { switch (attributeType) { case Float32Array: return draco.DT_FLOAT32; case Int8Array: return draco.DT_INT8; case Int16Array: return draco.DT_INT16; case Int32Array: return draco.DT_INT32; case Uint8Array: return draco.DT_UINT8; case Uint16Array: return draco.DT_UINT16; case Uint32Array: return draco.DT_UINT32; } } } exports.DRACOLoader = DRACOLoader; //# sourceMappingURL=DRACOLoader.cjs.map