UNPKG

itowns

Version:

A JS/WebGL framework for 3D geospatial data visualization

497 lines (415 loc) 16.1 kB
"use strict"; var _interopRequireWildcard = require("@babel/runtime/helpers/interopRequireWildcard"); var _interopRequireDefault = require("@babel/runtime/helpers/interopRequireDefault"); Object.defineProperty(exports, "__esModule", { value: true }); exports["default"] = void 0; var _typeof2 = _interopRequireDefault(require("@babel/runtime/helpers/typeof")); var THREE = _interopRequireWildcard(require("three")); // This file has been added and patched after installing the NPM modules (via NPM script 'prepare') var threeExamples = {}; /** * @author Don McCurdy / https://www.donmccurdy.com */ threeExamples.DRACOLoader = function (manager) { THREE.Loader.call(this, 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' }; }; threeExamples.DRACOLoader.prototype = Object.assign(Object.create(THREE.Loader.prototype), { constructor: threeExamples.DRACOLoader, setDecoderPath: function setDecoderPath(path) { this.decoderPath = path; return this; }, setDecoderConfig: function setDecoderConfig(config) { this.decoderConfig = config; return this; }, setWorkerLimit: function setWorkerLimit(workerLimit) { this.workerLimit = workerLimit; return this; }, /** @deprecated */ setVerbosity: function setVerbosity() { console.warn('threeExamples.DRACOLoader: The .setVerbosity() method has been removed.'); }, /** @deprecated */ setDrawMode: function setDrawMode() { console.warn('threeExamples.DRACOLoader: The .setDrawMode() method has been removed.'); }, /** @deprecated */ setSkipDequantization: function setSkipDequantization() { console.warn('threeExamples.DRACOLoader: The .setSkipDequantization() method has been removed.'); }, load: function load(url, onLoad, onProgress, onError) { var _this = this; var loader = new THREE.FileLoader(this.manager); loader.setPath(this.path); loader.setResponseType('arraybuffer'); if (this.crossOrigin === 'use-credentials') { loader.setWithCredentials(true); } loader.load(url, function (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 decodeDracoFile(buffer, callback, attributeIDs, attributeTypes) { var taskConfig = { attributeIDs: attributeIDs || this.defaultAttributeIDs, attributeTypes: attributeTypes || this.defaultAttributeTypes, useUniqueIDs: !!attributeIDs }; this.decodeGeometry(buffer, taskConfig).then(callback); }, decodeGeometry: function decodeGeometry(buffer, taskConfig) { var _this2 = this; var worker; var taskID = this.workerNextTaskID++; var taskCost = buffer.byteLength; // 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; } } // Obtain a worker and assign a task, and construct a geometry instance // when the task completes. var geometryPending = this._getWorker(taskID, taskCost).then(function (_worker) { worker = _worker; return new Promise(function (resolve, reject) { worker._callbacks[taskID] = { resolve: resolve, reject: reject }; worker.postMessage({ type: 'decode', id: taskID, taskConfig: taskConfig, buffer: buffer }, [buffer]); // this.debug(); }); }).then(function (message) { return _this2._createGeometry(message.geometry); }); // Remove task from the task list. geometryPending["finally"](function () { if (worker && taskID) { _this2._releaseTask(worker, taskID); // this.debug(); } }); return geometryPending; }, _createGeometry: function _createGeometry(geometryData) { var geometry = new THREE.BufferGeometry(); if (geometryData.index) { geometry.setIndex(new THREE.BufferAttribute(geometryData.index.array, 1)); } for (var i = 0; i < geometryData.attributes.length; i++) { var attribute = geometryData.attributes[i]; var name = attribute.name; var array = attribute.array; var itemSize = attribute.itemSize; geometry.addAttribute(name, new THREE.BufferAttribute(array, itemSize)); } return geometry; }, _loadLibrary: function _loadLibrary(url, responseType) { var loader = new THREE.FileLoader(this.manager); loader.setPath(this.decoderPath); loader.setResponseType(responseType); return new Promise(function (resolve, reject) { loader.load(url, resolve, undefined, reject); }); }, _initDecoder: function _initDecoder() { var _this3 = this; if (this.decoderPending) return this.decoderPending; var useJS = (typeof WebAssembly === "undefined" ? "undefined" : (0, _typeof2["default"])(WebAssembly)) !== 'object' || 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(function (libraries) { var jsContent = libraries[0]; if (!useJS) { _this3.decoderConfig.wasmBinary = libraries[1]; } var fn = threeExamples.DRACOLoader.DRACOWorker.toString(); var body = ['/* draco decoder */', jsContent, '', '/* worker */', fn.substring(fn.indexOf('{') + 1, fn.lastIndexOf('}'))].join('\n'); _this3.workerSourceURL = URL.createObjectURL(new Blob([body])); }); return this.decoderPending; }, _getWorker: function _getWorker(taskID, taskCost) { var _this4 = this; return this._initDecoder().then(function () { if (_this4.workerPool.length < _this4.workerLimit) { var worker = new Worker(_this4.workerSourceURL); worker._callbacks = {}; worker._taskCosts = {}; worker._taskLoad = 0; worker.postMessage({ type: 'init', decoderConfig: _this4.decoderConfig }); worker.onmessage = function (e) { var message = e.data; switch (message.type) { case 'decode': worker._callbacks[message.id].resolve(message); break; case 'error': worker._callbacks[message.id].reject(message); break; default: console.error('threeExamples.DRACOLoader: Unexpected message, "' + message.type + '"'); } }; _this4.workerPool.push(worker); } else { _this4.workerPool.sort(function (a, b) { return a._taskLoad > b._taskLoad ? -1 : 1; }); } var worker = _this4.workerPool[_this4.workerPool.length - 1]; worker._taskCosts[taskID] = taskCost; worker._taskLoad += taskCost; return worker; }); }, _releaseTask: function _releaseTask(worker, taskID) { worker._taskLoad -= worker._taskCosts[taskID]; delete worker._callbacks[taskID]; delete worker._taskCosts[taskID]; }, debug: function debug() { console.log('Task load: ', this.workerPool.map(function (worker) { return worker._taskLoad; })); }, dispose: function dispose() { for (var i = 0; i < this.workerPool.length; ++i) { this.workerPool[i].terminate(); } this.workerPool.length = 0; return this; } }); /* WEB WORKER */ threeExamples.DRACOLoader.DRACOWorker = function () { var decoderConfig; var decoderPending; onmessage = function onmessage(e) { var message = e.data; switch (message.type) { case 'init': decoderConfig = message.decoderConfig; decoderPending = new Promise(function (resolve /*, reject*/ ) { decoderConfig.onModuleLoaded = function (draco) { // Module is Promise-like. Wrap before resolving to avoid loop. resolve({ draco: draco }); }; DracoDecoderModule(decoderConfig); }); break; case 'decode': var buffer = message.buffer; var taskConfig = message.taskConfig; decoderPending.then(function (module) { var draco = module.draco; var decoder = new draco.Decoder(); var decoderBuffer = new draco.DecoderBuffer(); decoderBuffer.Init(new Int8Array(buffer), buffer.byteLength); try { var geometry = decodeGeometry(draco, decoder, decoderBuffer, taskConfig); var buffers = geometry.attributes.map(function (attr) { return attr.array.buffer; }); if (geometry.index) buffers.push(geometry.index.array.buffer); self.postMessage({ type: 'decode', id: message.id, geometry: 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) { var attributeIDs = taskConfig.attributeIDs; var attributeTypes = taskConfig.attributeTypes; var dracoGeometry; var decodingStatus; 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('threeExamples.DRACOLoader: Unexpected geometry type.'); } if (!decodingStatus.ok() || dracoGeometry.ptr === 0) { throw new Error('threeExamples.DRACOLoader: Decoding failed: ' + decodingStatus.error_msg()); } var geometry = { index: null, attributes: [] }; // Gather all vertex attributes. for (var attributeName in attributeIDs) { var attributeType = self[attributeTypes[attributeName]]; var attribute; var attributeID; // A Draco file may be created with default vertex attributes, whose attribute IDs // are mapped 1:1 from their semantic name (POSITION, NORMAL, ...). Alternatively, // 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 index = new Uint32Array(numFaces * 3); 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 }; 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; var dracoArray; var array; switch (attributeType) { case Float32Array: dracoArray = new draco.DracoFloat32Array(); decoder.GetAttributeFloatForAllPoints(dracoGeometry, attribute, dracoArray); array = new Float32Array(numValues); break; case Int8Array: dracoArray = new draco.DracoInt8Array(); decoder.GetAttributeInt8ForAllPoints(dracoGeometry, attribute, dracoArray); array = new Int8Array(numValues); break; case Int16Array: dracoArray = new draco.DracoInt16Array(); decoder.GetAttributeInt16ForAllPoints(dracoGeometry, attribute, dracoArray); array = new Int16Array(numValues); break; case Int32Array: dracoArray = new draco.DracoInt32Array(); decoder.GetAttributeInt32ForAllPoints(dracoGeometry, attribute, dracoArray); array = new Int32Array(numValues); break; case Uint8Array: dracoArray = new draco.DracoUInt8Array(); decoder.GetAttributeUInt8ForAllPoints(dracoGeometry, attribute, dracoArray); array = new Uint8Array(numValues); break; case Uint16Array: dracoArray = new draco.DracoUInt16Array(); decoder.GetAttributeUInt16ForAllPoints(dracoGeometry, attribute, dracoArray); array = new Uint16Array(numValues); break; case Uint32Array: dracoArray = new draco.DracoUInt32Array(); decoder.GetAttributeUInt32ForAllPoints(dracoGeometry, attribute, dracoArray); array = new Uint32Array(numValues); break; default: throw new Error('threeExamples.DRACOLoader: Unexpected attribute type.'); } for (var i = 0; i < numValues; i++) { array[i] = dracoArray.GetValue(i); } draco.destroy(dracoArray); return { name: attributeName, array: array, itemSize: numComponents }; } }; /** Deprecated static methods */ /** @deprecated */ threeExamples.DRACOLoader.setDecoderPath = function () { console.warn('threeExamples.DRACOLoader: The .setDecoderPath() method has been removed. Use instance methods.'); }; /** @deprecated */ threeExamples.DRACOLoader.setDecoderConfig = function () { console.warn('threeExamples.DRACOLoader: The .setDecoderConfig() method has been removed. Use instance methods.'); }; /** @deprecated */ threeExamples.DRACOLoader.releaseDecoderModule = function () { console.warn('threeExamples.DRACOLoader: The .releaseDecoderModule() method has been removed. Use instance methods.'); }; /** @deprecated */ threeExamples.DRACOLoader.getDecoderModule = function () { console.warn('threeExamples.DRACOLoader: The .getDecoderModule() method has been removed. Use instance methods.'); }; var _default = threeExamples.DRACOLoader; exports["default"] = _default;