diff --git a/tools/demo/canvas-three/custom/DRACOLoader.js b/tools/demo/canvas-three/custom/DRACOLoader.js index 20b7d7e1..7c909c12 100644 --- a/tools/demo/canvas-three/custom/DRACOLoader.js +++ b/tools/demo/canvas-three/custom/DRACOLoader.js @@ -1,12 +1,6 @@ -import { - BufferAttribute, - BufferGeometry, - FileLoader, - Loader -} from "three"; +import { BufferAttribute, BufferGeometry, FileLoader, Loader } from 'three'; var DRACOLoader = function (manager) { - Loader.call(this, manager); this.decoderPath = ''; @@ -23,68 +17,53 @@ var DRACOLoader = function (manager) { position: 'POSITION', normal: 'NORMAL', color: 'COLOR', - uv: 'TEX_COORD' + uv: 'TEX_COORD', }; this.defaultAttributeTypes = { position: 'Float32Array', normal: 'Float32Array', color: 'Float32Array', - uv: 'Float32Array' + uv: 'Float32Array', }; - }; DRACOLoader.prototype = Object.assign(Object.create(Loader.prototype), { - constructor: DRACOLoader, setDecoderPath: function (path) { - this.decoderPath = path; return this; - }, setDecoderConfig: function (config) { - this.decoderConfig = config; return this; - }, setWorkerLimit: function (workerLimit) { - this.workerLimit = workerLimit; return this; - }, /** @deprecated */ setVerbosity: function () { - console.warn('THREE.DRACOLoader: The .setVerbosity() method has been removed.'); - }, /** @deprecated */ setDrawMode: function () { - console.warn('THREE.DRACOLoader: The .setDrawMode() method has been removed.'); - }, /** @deprecated */ setSkipDequantization: function () { - console.warn('THREE.DRACOLoader: The .setSkipDequantization() method has been removed.'); - }, load: function (url, onLoad, onProgress, onError) { - var loader = new FileLoader(this.manager); loader.setPath(this.path); @@ -92,54 +71,46 @@ DRACOLoader.prototype = Object.assign(Object.create(Loader.prototype), { loader.setRequestHeader(this.requestHeader); if (this.crossOrigin === 'use-credentials') { - loader.setWithCredentials(true); - } - loader.load(url, (buffer) => { - - var taskConfig = { - attributeIDs: this.defaultAttributeIDs, - attributeTypes: this.defaultAttributeTypes, - useUniqueIDs: false - }; - - this.decodeGeometry(buffer, taskConfig) - .then(onLoad) - .catch(onError); - }, onProgress, onError); + loader.load( + url, + (buffer) => { + var 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: function (buffer, callback, attributeIDs, attributeTypes) { - var taskConfig = { attributeIDs: attributeIDs || this.defaultAttributeIDs, attributeTypes: attributeTypes || this.defaultAttributeTypes, - useUniqueIDs: !!attributeIDs + useUniqueIDs: !!attributeIDs, }; this.decodeGeometry(buffer, taskConfig).then(callback); - }, decodeGeometry: function (buffer, taskConfig) { - // TODO: For backward-compatibility, support 'attributeTypes' objects containing // references (rather than names) to typed array constructors. These must be // serialized before sending them to the worker. for (var attribute in taskConfig.attributeTypes) { - var type = taskConfig.attributeTypes[attribute]; if (type.BYTES_PER_ELEMENT !== undefined) { - taskConfig.attributeTypes[attribute] = type.name; - } - } // @@ -149,26 +120,17 @@ DRACOLoader.prototype = Object.assign(Object.create(Loader.prototype), { // Check for an existing task using this buffer. A transferred buffer cannot be transferred // again from this thread. if (DRACOLoader.taskCache.has(buffer)) { - var cachedTask = DRACOLoader.taskCache.get(buffer); if (cachedTask.key === taskKey) { - return cachedTask.promise; - } else if (buffer.byteLength === 0) { - // Technically, it would be possible to wait for the previous task to complete, // transfer the buffer back, and decode again with the second configuration. That // is complex, and I don't know of any reason to decode a Draco buffer twice in // different ways, so this is left unimplemented. - throw new Error( - 'THREE.DRACOLoader: Unable to re-decode a buffer with different ' + - 'settings. Buffer has already been transferred.' - ); - + throw new Error('THREE.DRACOLoader: Unable to re-decode a buffer with different ' + 'settings. Buffer has already been transferred.'); } - } // @@ -180,31 +142,27 @@ DRACOLoader.prototype = Object.assign(Object.create(Loader.prototype), { // Obtain a worker and assign a task, and construct a geometry instance // when the task completes. var geometryPending = this._getWorker(taskID, taskCost) - .catch(e => { + .catch((e) => { console.log('geometryPending', e); }) .then((_worker) => { - worker = _worker; return new Promise((resolve, reject) => { - try { - worker._callbacks[taskID] = {resolve, reject}; + worker._callbacks[taskID] = { resolve, reject }; worker.postMessage({ type: 'decode', id: taskID, taskConfig, - buffer: JSON.stringify(Array.from(new Uint8Array(buffer))) + buffer: JSON.stringify(Array.from(new Uint8Array(buffer))), }); } catch (e) { console.log('geometryPending postMessage', e); } // this.debug(); - }); - }) .then((message) => { const data = message.geometry; @@ -217,30 +175,24 @@ DRACOLoader.prototype = Object.assign(Object.create(Loader.prototype), { // Note: replaced '.finally()' with '.catch().then()' block - iOS 11 support (#19416) geometryPending .catch((e) => { - console.log('geometryPending', e) + console.log('geometryPending', e); return true; }) .then(() => { if (worker && taskID) { - this._releaseTask(worker, taskID); // this.debug(); - } }); - // Cache the task result. DRACOLoader.taskCache.set(buffer, { - key: taskKey, - promise: geometryPending - + promise: geometryPending, }); return geometryPending; - }, _createGeometry: function (geometryData) { @@ -264,159 +216,120 @@ DRACOLoader.prototype = Object.assign(Object.create(Loader.prototype), { } else { return buf; } - } + }; if (geometryData.index) { geometry.setIndex(new BufferAttribute(getBuffer(geometryData.index.array, geometryData.indexType), 1)); } for (var i = 0; i < geometryData.attributes.length; i++) { - var attribute = geometryData.attributes[i]; var name = attribute.name; var array = getBuffer(attribute.array, geometryData.attributeTypes[i]); var itemSize = attribute.itemSize; geometry.setAttribute(name, new BufferAttribute(array, itemSize)); - } } catch (e) { console.log('_createGeometry', e); } return geometry; - }, _loadLibrary: function (url, responseType) { - var loader = new FileLoader(this.manager); loader.setPath(this.decoderPath); loader.setResponseType(responseType); return new Promise((resolve, reject) => { - loader.load(url, resolve, undefined, reject); - }); - }, preload: function () { - this._initDecoder(); return this; - }, _initDecoder: function () { - if (this.decoderPending) return this.decoderPending; var useJS = this.decoderConfig.type === 'js'; var 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) => { - - var jsContent = libraries[0]; - - if (!useJS) { + this.decoderPending = Promise.all(librariesPending).then((libraries) => { + var jsContent = libraries[0]; - this.decoderConfig.wasmBinary = libraries[1]; - - } + if (!useJS) { + this.decoderConfig.wasmBinary = libraries[1]; + } - var fn = DRACOLoader.DRACOWorker.toString(); + var fn = DRACOLoader.DRACOWorker.toString(); - var body = [ - '/* draco decoder */', - jsContent, - '', - '/* worker */', - fn.substring(fn.indexOf('{') + 1, fn.lastIndexOf('}')) - ].join('\n'); + var body = ['/* draco decoder */', jsContent, '', '/* worker */', fn.substring(fn.indexOf('{') + 1, fn.lastIndexOf('}'))].join('\n'); - try { - this.workerSourceURL = URL.createObjectURL(new Blob([body])); - require(this.workerSourceURL); - } catch (e) { - } - }); + try { + this.workerSourceURL = URL.createObjectURL(new Blob([body], { type: 'text/javascript' })); + //require(this.workerSourceURL); + } catch (e) { + console.log('require fail', e); + } + }); return this.decoderPending; - }, _getWorker: function (taskID, taskCost) { - return this._initDecoder().then(() => { - if (this.workerPool.length < this.workerLimit) { + try { + var worker = new Worker(this.workerSourceURL); - try { - var worker = new Worker(this.workerSourceURL); - - worker._callbacks = {}; - worker._taskCosts = {}; - worker._taskLoad = 0; - - worker.postMessage({type: 'init', decoderConfig: this.decoderConfig}); - worker.onmessage = function (e) { - var message = JSON.parse(e.data); - - switch (message.type) { - - case 'decode': - worker._callbacks[message.id].resolve(message); - break; - - case 'error': - worker._callbacks[message.id].reject(message); - break; + worker._callbacks = {}; + worker._taskCosts = {}; + worker._taskLoad = 0; - default: - console.error('THREE.DRACOLoader: Unexpected message, "' + message.type + '"'); + worker.postMessage({ type: 'init', decoderConfig: this.decoderConfig }); + worker.onmessage = function (e) { + var message = JSON.parse(e.data); - } + switch (message.type) { + case 'decode': + worker._callbacks[message.id].resolve(message); + break; - }; - - this.workerPool.push(worker); - }catch (e) { - console.log('creating worker', e); - } + case 'error': + worker._callbacks[message.id].reject(message); + break; + default: + console.error('THREE.DRACOLoader: Unexpected message, "' + message.type + '"'); + } + }; + this.workerPool.push(worker); + } catch (e) { + console.log('creating worker', e); + } } else { - this.workerPool.sort(function (a, b) { - return a._taskLoad > b._taskLoad ? -1 : 1; - }); - } - var worker = this.workerPool[this.workerPool.length - 1]; worker._taskCosts[taskID] = taskCost; worker._taskLoad += taskCost; return worker; - }); - }, _releaseTask: function (worker, taskID) { @@ -430,51 +343,41 @@ DRACOLoader.prototype = Object.assign(Object.create(Loader.prototype), { }, debug: function () { - - console.log('Task load: ', this.workerPool.map((worker) => worker._taskLoad)); - + console.log( + 'Task load: ', + this.workerPool.map((worker) => worker._taskLoad) + ); }, dispose: function () { - for (var i = 0; i < this.workerPool.length; ++i) { - this.workerPool[i].terminate(); - } this.workerPool.length = 0; return this; - - } - + }, }); /* WEB WORKER */ DRACOLoader.DRACOWorker = function () { - var decoderConfig; var decoderPending; onmessage = function (e) { - var message = e.data; switch (message.type) { - case 'init': decoderConfig = message.decoderConfig; - decoderPending = new Promise(function (resolve/*, reject*/) { - + decoderPending = new Promise(function (resolve /*, reject*/) { decoderConfig.onModuleLoaded = function (draco) { // Module is Promise-like. Wrap before resolving to avoid loop. - resolve({draco: draco}); - + resolve({ draco: draco }); }; DracoDecoderModule(decoderConfig); // eslint-disable-line no-undef - }); break; @@ -489,7 +392,6 @@ DRACOLoader.DRACOWorker = function () { var decoderBuffer = new draco.DecoderBuffer(); decoderBuffer.Init(new Int8Array(buffer), buffer.byteLength); - var geometry = decodeGeometry(draco, decoder, decoderBuffer, taskConfig); var bufferType = function (buf) { let type = 'Unknown'; @@ -509,36 +411,32 @@ DRACOLoader.DRACOWorker = function () { type = 'Float32Array'; } return type; - } + }; var attributeTypes = []; geometry.attributes = geometry.attributes.map((attr) => { var type = bufferType(attr.array); attr.array = Array.from(attr.array); attributeTypes.push(type); - return attr + return attr; }); var indexType; if (geometry.index) { indexType = bufferType(geometry.index.array); geometry.index.array = Array.from(geometry.index.array); } - self.postMessage(JSON.stringify({type: 'decode', id: message.id, geometry, indexType, attributeTypes})); + self.postMessage(JSON.stringify({ type: 'decode', id: message.id, geometry, indexType, attributeTypes })); } catch (error) { - self.postMessage(JSON.stringify({type: 'error', id: message.id, error: error.message})); + self.postMessage(JSON.stringify({ type: 'error', id: message.id, error: error.message })); } finally { draco.destroy(decoderBuffer); draco.destroy(decoder); } - }); break; - } - }; function decodeGeometry(draco, decoder, decoderBuffer, taskConfig) { - var attributeIDs = taskConfig.attributeIDs; var attributeTypes = taskConfig.attributeTypes; @@ -548,32 +446,23 @@ DRACOLoader.DRACOWorker = function () { var 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()); - } - var geometry = {index: null, attributes: []}; + var geometry = { index: null, attributes: [] }; // Gather all vertex attributes. for (var attributeName in attributeIDs) { - var attributeType = self[attributeTypes[attributeName]]; var attribute; @@ -584,27 +473,21 @@ DRACOLoader.DRACOWorker = function () { // a Draco file may contain a custom set of attributes, identified by known unique // IDs. glTF files always do the latter, and `.drc` files typically do the former. 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)); - } // Add index. if (geometryType === draco.TRIANGULAR_MESH) { - // Generate mesh faces. var numFaces = dracoGeometry.num_faces(); var numIndices = numFaces * 3; @@ -612,31 +495,24 @@ DRACOLoader.DRACOWorker = function () { var indexArray = new draco.DracoInt32Array(); for (var i = 0; i < numFaces; ++i) { - decoder.GetFaceFromMesh(dracoGeometry, i, indexArray); for (var j = 0; j < 3; ++j) { - index[i * 3 + j] = indexArray.GetValue(j); - } - } - geometry.index = {array: index, itemSize: 1}; + geometry.index = { array: index, itemSize: 1 }; draco.destroy(indexArray); - } draco.destroy(dracoGeometry); return geometry; - } function decodeAttribute(draco, decoder, dracoGeometry, attributeName, attributeType, attribute) { - var numComponents = attribute.num_components(); var numPoints = dracoGeometry.num_points(); var numValues = numPoints * numComponents; @@ -645,7 +521,6 @@ DRACOLoader.DRACOWorker = function () { var array; switch (attributeType) { - case Float32Array: dracoArray = new draco.DracoFloat32Array(); decoder.GetAttributeFloatForAllPoints(dracoGeometry, attribute, dracoArray); @@ -690,13 +565,10 @@ DRACOLoader.DRACOWorker = function () { default: throw new Error('THREE.DRACOLoader: Unexpected attribute type.'); - } for (var i = 0; i < numValues; i++) { - array[i] = dracoArray.GetValue(i); - } draco.destroy(dracoArray); @@ -704,11 +576,9 @@ DRACOLoader.DRACOWorker = function () { return { name: attributeName, array: array, - itemSize: numComponents + itemSize: numComponents, }; - } - }; DRACOLoader.taskCache = new WeakMap(); @@ -717,30 +587,22 @@ DRACOLoader.taskCache = new WeakMap(); /** @deprecated */ DRACOLoader.setDecoderPath = function () { - console.warn('THREE.DRACOLoader: The .setDecoderPath() method has been removed. Use instance methods.'); - }; /** @deprecated */ DRACOLoader.setDecoderConfig = function () { - console.warn('THREE.DRACOLoader: The .setDecoderConfig() method has been removed. Use instance methods.'); - }; /** @deprecated */ DRACOLoader.releaseDecoderModule = function () { - console.warn('THREE.DRACOLoader: The .releaseDecoderModule() method has been removed. Use instance methods.'); - }; /** @deprecated */ DRACOLoader.getDecoderModule = function () { - console.warn('THREE.DRACOLoader: The .getDecoderModule() method has been removed. Use instance methods.'); - }; -export {DRACOLoader}; +export { DRACOLoader };