(function webpackUniversalModuleDefinition(root, factory) { if(typeof exports === 'object' && typeof module === 'object') module.exports = factory(require("three-wtm"), require("three")); else if(typeof define === 'function' && define.amd) define(["three-wtm", "three"], factory); else if(typeof exports === 'object') exports["wwobjloader2"] = factory(require("threeWtm"), require("three")); else root["wwobjloader2"] = factory(root["threeWtm"], root["THREE"]); })(window, function(__WEBPACK_EXTERNAL_MODULE__0__, __WEBPACK_EXTERNAL_MODULE__1__) { return /******/ (function(modules) { // webpackBootstrap /******/ // The module cache /******/ var installedModules = {}; /******/ /******/ // The require function /******/ function __webpack_require__(moduleId) { /******/ /******/ // Check if module is in cache /******/ if(installedModules[moduleId]) { /******/ return installedModules[moduleId].exports; /******/ } /******/ // Create a new module (and put it into the cache) /******/ var module = installedModules[moduleId] = { /******/ i: moduleId, /******/ l: false, /******/ exports: {} /******/ }; /******/ /******/ // Execute the module function /******/ modules[moduleId].call(module.exports, module, module.exports, __webpack_require__); /******/ /******/ // Flag the module as loaded /******/ module.l = true; /******/ /******/ // Return the exports of the module /******/ return module.exports; /******/ } /******/ /******/ /******/ // expose the modules object (__webpack_modules__) /******/ __webpack_require__.m = modules; /******/ /******/ // expose the module cache /******/ __webpack_require__.c = installedModules; /******/ /******/ // define getter function for harmony exports /******/ __webpack_require__.d = function(exports, name, getter) { /******/ if(!__webpack_require__.o(exports, name)) { /******/ Object.defineProperty(exports, name, { enumerable: true, get: getter }); /******/ } /******/ }; /******/ /******/ // define __esModule on exports /******/ __webpack_require__.r = function(exports) { /******/ if(typeof Symbol !== 'undefined' && Symbol.toStringTag) { /******/ Object.defineProperty(exports, Symbol.toStringTag, { value: 'Module' }); /******/ } /******/ Object.defineProperty(exports, '__esModule', { value: true }); /******/ }; /******/ /******/ // create a fake namespace object /******/ // mode & 1: value is a module id, require it /******/ // mode & 2: merge all properties of value into the ns /******/ // mode & 4: return value when already ns object /******/ // mode & 8|1: behave like require /******/ __webpack_require__.t = function(value, mode) { /******/ if(mode & 1) value = __webpack_require__(value); /******/ if(mode & 8) return value; /******/ if((mode & 4) && typeof value === 'object' && value && value.__esModule) return value; /******/ var ns = Object.create(null); /******/ __webpack_require__.r(ns); /******/ Object.defineProperty(ns, 'default', { enumerable: true, value: value }); /******/ if(mode & 2 && typeof value != 'string') for(var key in value) __webpack_require__.d(ns, key, function(key) { return value[key]; }.bind(null, key)); /******/ return ns; /******/ }; /******/ /******/ // getDefaultExport function for compatibility with non-harmony modules /******/ __webpack_require__.n = function(module) { /******/ var getter = module && module.__esModule ? /******/ function getDefault() { return module['default']; } : /******/ function getModuleExports() { return module; }; /******/ __webpack_require__.d(getter, 'a', getter); /******/ return getter; /******/ }; /******/ /******/ // Object.prototype.hasOwnProperty.call /******/ __webpack_require__.o = function(object, property) { return Object.prototype.hasOwnProperty.call(object, property); }; /******/ /******/ // __webpack_public_path__ /******/ __webpack_require__.p = ""; /******/ /******/ /******/ // Load entry module and return exports /******/ return __webpack_require__(__webpack_require__.s = 2); /******/ }) /************************************************************************/ /******/ ([ /* 0 */ /***/ (function(module, exports) { module.exports = __WEBPACK_EXTERNAL_MODULE__0__; /***/ }), /* 1 */ /***/ (function(module, exports) { module.exports = __WEBPACK_EXTERNAL_MODULE__1__; /***/ }), /* 2 */ /***/ (function(module, __webpack_exports__, __webpack_require__) { "use strict"; __webpack_require__.r(__webpack_exports__); /* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "MtlObjBridge", function() { return MtlObjBridge; }); /* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "OBJLoader2", function() { return OBJLoader2; }); /* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "OBJLoader2Parallel", function() { return OBJLoader2Parallel; }); /* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "OBJLoader2Parser", function() { return OBJLoader2Parser; }); /* harmony import */ var three__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(1); /* harmony import */ var three__WEBPACK_IMPORTED_MODULE_0___default = /*#__PURE__*/__webpack_require__.n(three__WEBPACK_IMPORTED_MODULE_0__); /* harmony import */ var three_wtm__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(0); /* harmony import */ var three_wtm__WEBPACK_IMPORTED_MODULE_1___default = /*#__PURE__*/__webpack_require__.n(three_wtm__WEBPACK_IMPORTED_MODULE_1__); function _defineProperty(obj, key, value) { if (key in obj) { Object.defineProperty(obj, key, { value: value, enumerable: true, configurable: true, writable: true }); } else { obj[key] = value; } return obj; } /** * Creates a new OBJLoader2. Use it to load OBJ data from files or to parse OBJ data from arraybuffer or text. * * @param {LoadingManager} [manager] The loadingManager for the loader to use. Default is {@link LoadingManager} * @constructor */ class OBJLoader2 extends three__WEBPACK_IMPORTED_MODULE_0__["Loader"] { /** * * @param {LoadingManager} [manager] */ constructor(manager) { super(manager); this.parser = new OBJLoader2Parser(); this.materialStore = new three_wtm__WEBPACK_IMPORTED_MODULE_1__["MaterialStore"](true); this.parser.materials = this.materialStore.getMaterials(); } /** * Enable or disable logging in general (except warn and error), plus enable or disable debug logging. * * @param {boolean} enabled True or false. * @param {boolean} debug True or false. * * @return {OBJLoader2} */ setLogging(enabled, debug) { this.parser.logging.enabled = enabled === true; this.parser.logging.debug = debug === true; return this; } /** * Tells whether a material shall be created per smoothing group. * * @param {boolean} materialPerSmoothingGroup=false * @return {OBJLoader2} */ setMaterialPerSmoothingGroup(materialPerSmoothingGroup) { this.parser.aterialPerSmoothingGroup = materialPerSmoothingGroup === true; return this; } /** * Usually 'o' is meta-information and does not result in creation of new meshes, but mesh creation on occurrence of "o" can be enforced. * * @param {boolean} useOAsMesh=false * @return {OBJLoader2} */ setUseOAsMesh(useOAsMesh) { this.parser.useOAsMesh = useOAsMesh === true; return this; } /** * Instructs loaders to create indexed {@link BufferGeometry}. * * @param {boolean} useIndices=false * @return {OBJLoader2} */ setUseIndices(useIndices) { this.parser.useIndices = useIndices === true; return this; } /** * Tells whether normals should be completely disregarded and regenerated. * * @param {boolean} disregardNormals=false * @return {OBJLoader2} */ setDisregardNormals(disregardNormals) { this.parser.disregardNormals = disregardNormals === true; return this; } /** * Set the name of the model. * * @param {string} modelName * @return {OBJLoader2} */ setModelName(modelName) { if (modelName) { this.parser.modelName = modelName; } return this; } /** * Returns the name of the models * @return {String} */ getModelName() { return this.parser.modelName; } /** * Set the node where the loaded objects will be attached directly. * * @param {Object3D} baseObject3d Object already attached to scenegraph where new meshes will be attached to * @return {OBJLoader2} */ setBaseObject3d(baseObject3d) { this.parser.baseObject3d = baseObject3d === undefined || baseObject3d === null ? this.parser.baseObject3d : baseObject3d; return this; } /** * Clears materials object and sets the new ones. * * @param {Object} materials Object with named materials * @return {OBJLoader2} */ setMaterials(materials) { this.materialStore.addMaterials(materials, false); this.parser.materials = this.materialStore.getMaterials(); return this; } /** * Register a function that is used to report overall processing progress. * * @param {Function} onProgress * @return {OBJLoader2} */ setCallbackOnProgress(onProgress) { if (onProgress !== null && onProgress !== undefined && onProgress instanceof Function) { this.parser.callbacks.onProgress = onProgress; } return this; } /** * Register an error handler function that is called if errors occur. It can decide to just log or to throw an exception. * * @param {Function} onError * @return {OBJLoader2} */ setCallbackOnError(onError) { if (onError !== null && onError !== undefined && onError instanceof Function) { this.parser.callbacks.onError = onError; } return this; } /** * Register a function that is called when parsing was completed. * * @param {Function} onLoad * @return {OBJLoader2} */ setCallbackOnLoad(onLoad) { if (onLoad !== null && onLoad !== undefined && onLoad instanceof Function) { this.parser.callbacks.onLoad = onLoad; } return this; } /** * Register a function that is called once a single mesh is available and it could be altered by the supplied function. * * @param {Function} [onMeshAlter] * @return {OBJLoader2} */ setCallbackOnMeshAlter(onMeshAlter) { if (onMeshAlter !== null && onMeshAlter !== undefined && onMeshAlter instanceof Function) { this.parser.callbacks.onMeshAlter = onMeshAlter; } return this; } /** * Use this convenient method to load a file at the given URL. By default the fileLoader uses an ArrayBuffer. * * @param {string} url A string containing the path/URL of the file to be loaded. * @param {Function} onLoad A function to be called after loading is successfully completed. The function receives loaded Object3D as an argument. * @param {Function} [onFileLoadProgress] A function to be called while the loading is in progress. The argument will be the XMLHttpRequest instance, which contains total and Integer bytes. * @param {Function} [onError] A function to be called if an error occurs during loading. The function receives the error as an argument. * @param {Function} [onMeshAlter] Called after every single mesh is made available by the parser */ load(url, onLoad, onFileLoadProgress, onError, onMeshAlter) { if (onLoad === null || onLoad === undefined || !(onLoad instanceof Function)) { const errorMessage = 'onLoad is not a function! Aborting...'; this.parser._onError(errorMessage); throw errorMessage; } else { this.setCallbackOnLoad(onLoad); } const scope = this; if (onError === null || onError === undefined || !(onError instanceof Function)) { onError = function (event) { let errorMessage = event; if (event.currentTarget && event.currentTarget.statusText !== null) { errorMessage = 'Error occurred while downloading!\nurl: ' + event.currentTarget.responseURL + '\nstatus: ' + event.currentTarget.statusText; } scope.parser._onError(errorMessage); }; } if (!url) { onError('An invalid url was provided. Unable to continue!'); } const urlFull = new URL(url, window.location.href).href; let filename = urlFull; const urlParts = urlFull.split('/'); if (urlParts.length > 2) { filename = urlParts[urlParts.length - 1]; let urlPartsPath = urlParts.slice(0, urlParts.length - 1).join('/') + '/'; if (urlPartsPath !== undefined) this.path = urlPartsPath; } if (onFileLoadProgress === null || onFileLoadProgress === undefined || !(onFileLoadProgress instanceof Function)) { let numericalValueRef = 0; let numericalValue = 0; onFileLoadProgress = function (event) { if (!event.lengthComputable) return; numericalValue = event.loaded / event.total; if (numericalValue > numericalValueRef) { numericalValueRef = numericalValue; const output = 'Download of "' + url + '": ' + (numericalValue * 100).toFixed(2) + '%'; scope.parser._onProgress('progressLoad', output, numericalValue); } }; } this.setCallbackOnMeshAlter(onMeshAlter); const fileLoaderOnLoad = function (content) { scope.parse(content); }; const fileLoader = new three__WEBPACK_IMPORTED_MODULE_0__["FileLoader"](this.manager); fileLoader.setPath(this.path || this.resourcePath); fileLoader.setResponseType('arraybuffer'); fileLoader.load(filename, fileLoaderOnLoad, onFileLoadProgress, onError); } /** * Parses OBJ data synchronously from arraybuffer or string and returns the {@link Object3D}. * * @param {arraybuffer|string} content OBJ data as Uint8Array or String * @return {Object3D} */ parse(content) { if (this.parser.logging.enabled) { console.info('Using OBJLoader2 version: ' + OBJLoader2.OBJLOADER2_VERSION); } // fast-fail in case of illegal data if (content === null || content === undefined) { throw 'Provided content is not a valid ArrayBuffer or String. Unable to continue parsing'; } if (this.parser.logging.enabled) { console.time('OBJLoader parse: ' + this.modelName); } if (content instanceof ArrayBuffer || content instanceof Uint8Array) { if (this.parser.logging.enabled) console.info('Parsing arrayBuffer...'); this.parser._execute(content); } else if (typeof content === 'string' || content instanceof String) { if (this.parser.logging.enabled) console.info('Parsing text...'); this.parser._executeLegacy(content); } else { this.parser._onError('Provided content was neither of type String nor Uint8Array! Aborting...'); } if (this.parser.logging.enabled) { console.timeEnd('OBJLoader parse: ' + this.modelName); } return this.parser.baseObject3d; } } _defineProperty(OBJLoader2, "OBJLOADER2_VERSION", '4.0.0-dev'); class OBJLoader2Parser { constructor() { this.logging = { enabled: false, debug: false }; this.usedBefore = false; this._init(); this.callbacks = { onLoad: null, onError: null, onProgress: null, onMeshAlter: null }; } _init() { this.contentRef = null; this.legacyMode = false; this.materials = {}; this.baseObject3d = new three__WEBPACK_IMPORTED_MODULE_0__["Object3D"](); this.modelName = 'noname'; this.materialPerSmoothingGroup = false; this.useOAsMesh = false; this.useIndices = false; this.disregardNormals = false; this.vertices = []; this.colors = []; this.normals = []; this.uvs = []; this.objectId = 0; this.rawMesh = { objectName: '', groupName: '', activeMtlName: '', mtllibName: '', // reset with new mesh faceType: -1, subGroups: [], subGroupInUse: null, smoothingGroup: { splitMaterials: false, normalized: -1, real: -1 }, counts: { doubleIndicesCount: 0, faceCount: 0, mtlCount: 0, smoothingGroupCount: 0 } }; this.inputObjectCount = 1; this.outputObjectCount = 1; this.globalCounts = { vertices: 0, faces: 0, doubleIndicesCount: 0, lineByte: 0, currentByte: 0, totalBytes: 0 }; } _resetRawMesh() { // faces are stored according combined index of group, material and smoothingGroup (0 or not) this.rawMesh.subGroups = []; this.rawMesh.subGroupInUse = null; this.rawMesh.smoothingGroup.normalized = -1; this.rawMesh.smoothingGroup.real = -1; // this default index is required as it is possible to define faces without 'g' or 'usemtl' this._pushSmoothingGroup(1); this.rawMesh.counts.doubleIndicesCount = 0; this.rawMesh.counts.faceCount = 0; this.rawMesh.counts.mtlCount = 0; this.rawMesh.counts.smoothingGroupCount = 0; } _configure() { this.usedBefore = true; this._pushSmoothingGroup(1); if (this.logging.enabled) { const matKeys = Object.keys(this.materials); const matNames = matKeys.length > 0 ? '\n\tmaterialNames:\n\t\t- ' + matKeys.join('\n\t\t- ') : '\n\tmaterialNames: None'; let printedConfig = 'OBJLoader2 Parser configuration:' + matNames + '\n\tmaterialPerSmoothingGroup: ' + this.materialPerSmoothingGroup + '\n\tuseOAsMesh: ' + this.useOAsMesh + '\n\tuseIndices: ' + this.useIndices + '\n\tdisregardNormals: ' + this.disregardNormals; if (this.callbacks.onProgress !== null) printedConfig += '\n\tcallbacks.onProgress: ' + this.callbacks.onProgress.name; if (this.callbacks.onError !== null) printedConfig += '\n\tcallbacks.onError: ' + this.callbacks.onError.name; if (this.callbacks.onMeshAlter !== null) printedConfig += '\n\tcallbacks.onMeshAlter: ' + this.callbacks.onMeshAlter.name; if (this.callbacks.onLoad !== null) printedConfig += '\n\tcallbacks.onLoad: ' + this.callbacks.onLoad.name; console.info(printedConfig); } } /** * Parse the provided arraybuffer * * @param {Uint8Array} arrayBuffer OBJ data as Uint8Array */ _execute(arrayBuffer) { if (this.logging.enabled) console.time('OBJLoader2Parser.execute'); this._configure(); const arrayBufferView = new Uint8Array(arrayBuffer); this.contentRef = arrayBufferView; const length = arrayBufferView.byteLength; this.globalCounts.totalBytes = length; const buffer = new Array(128); let bufferPointer = 0; let slashesCount = 0; let word = ''; let currentByte = 0; for (let code; currentByte < length; currentByte++) { code = arrayBufferView[currentByte]; switch (code) { // space case 32: if (word.length > 0) buffer[bufferPointer++] = word; word = ''; break; // slash case 47: if (word.length > 0) buffer[bufferPointer++] = word; slashesCount++; word = ''; break; // LF case 10: this._processLine(buffer, bufferPointer, slashesCount, word, currentByte); word = ''; bufferPointer = 0; slashesCount = 0; break; // CR case 13: break; default: word += String.fromCharCode(code); break; } } this._processLine(buffer, bufferPointer, slashesCount, word, currentByte); this._finalizeParsing(); if (this.logging.enabled) console.timeEnd('OBJLoader2Parser.execute'); } /** * Parse the provided text * * @param {string} text OBJ data as string */ _executeLegacy(text) { if (this.logging.enabled) console.time('OBJLoader2Parser.executeLegacy'); this._configure(); this.legacyMode = true; this.contentRef = text; const length = text.length; this.globalCounts.totalBytes = length; const buffer = new Array(128); let bufferPointer = 0; let slashesCount = 0; let word = ''; let currentByte = 0; for (let char; currentByte < length; currentByte++) { char = text[currentByte]; switch (char) { case ' ': if (word.length > 0) buffer[bufferPointer++] = word; word = ''; break; case '/': if (word.length > 0) buffer[bufferPointer++] = word; slashesCount++; word = ''; break; case '\n': this._processLine(buffer, bufferPointer, slashesCount, word, currentByte); word = ''; bufferPointer = 0; slashesCount = 0; break; case '\r': break; default: word += char; } } this._processLine(buffer, bufferPointer, word, slashesCount); this._finalizeParsing(); if (this.logging.enabled) console.timeEnd('OBJLoader2Parser.executeLegacy'); } _processLine(buffer, bufferPointer, slashesCount, word, currentByte) { this.globalCounts.lineByte = this.globalCounts.currentByte; this.globalCounts.currentByte = currentByte; if (bufferPointer < 1) return; if (word.length > 0) buffer[bufferPointer++] = word; const reconstructString = function (content, legacyMode, start, stop) { let line = ''; if (stop > start) { let i; if (legacyMode) { for (i = start; i < stop; i++) line += content[i]; } else { for (i = start; i < stop; i++) line += String.fromCharCode(content[i]); } line = line.trim(); } return line; }; let bufferLength, length, i; const lineDesignation = buffer[0]; switch (lineDesignation) { case 'v': this.vertices.push(parseFloat(buffer[1])); this.vertices.push(parseFloat(buffer[2])); this.vertices.push(parseFloat(buffer[3])); if (bufferPointer > 4) { this.colors.push(parseFloat(buffer[4])); this.colors.push(parseFloat(buffer[5])); this.colors.push(parseFloat(buffer[6])); } break; case 'vt': this.uvs.push(parseFloat(buffer[1])); this.uvs.push(parseFloat(buffer[2])); break; case 'vn': this.normals.push(parseFloat(buffer[1])); this.normals.push(parseFloat(buffer[2])); this.normals.push(parseFloat(buffer[3])); break; case 'f': bufferLength = bufferPointer - 1; // "f vertex ..." if (slashesCount === 0) { this._checkFaceType(0); for (i = 2, length = bufferLength; i < length; i++) { this._buildFace(buffer[1]); this._buildFace(buffer[i]); this._buildFace(buffer[i + 1]); } // "f vertex/uv ..." } else if (bufferLength === slashesCount * 2) { this._checkFaceType(1); for (i = 3, length = bufferLength - 2; i < length; i += 2) { this._buildFace(buffer[1], buffer[2]); this._buildFace(buffer[i], buffer[i + 1]); this._buildFace(buffer[i + 2], buffer[i + 3]); } // "f vertex/uv/normal ..." } else if (bufferLength * 2 === slashesCount * 3) { this._checkFaceType(2); for (i = 4, length = bufferLength - 3; i < length; i += 3) { this._buildFace(buffer[1], buffer[2], buffer[3]); this._buildFace(buffer[i], buffer[i + 1], buffer[i + 2]); this._buildFace(buffer[i + 3], buffer[i + 4], buffer[i + 5]); } // "f vertex//normal ..." } else { this._checkFaceType(3); for (i = 3, length = bufferLength - 2; i < length; i += 2) { this._buildFace(buffer[1], undefined, buffer[2]); this._buildFace(buffer[i], undefined, buffer[i + 1]); this._buildFace(buffer[i + 2], undefined, buffer[i + 3]); } } break; case 'l': case 'p': bufferLength = bufferPointer - 1; if (bufferLength === slashesCount * 2) { this._checkFaceType(4); for (i = 1, length = bufferLength + 1; i < length; i += 2) this._buildFace(buffer[i], buffer[i + 1]); } else { this._checkFaceType(lineDesignation === 'l' ? 5 : 6); for (i = 1, length = bufferLength + 1; i < length; i++) this._buildFace(buffer[i]); } break; case 's': this._pushSmoothingGroup(buffer[1]); break; case 'g': // 'g' leads to creation of mesh if valid data (faces declaration was done before), otherwise only groupName gets set this._processCompletedMesh(); this.rawMesh.groupName = reconstructString(this.contentRef, this.legacyMode, this.globalCounts.lineByte + 2, this.globalCounts.currentByte); break; case 'o': // 'o' is meta-information and usually does not result in creation of new meshes, but can be enforced with "useOAsMesh" if (this.useOAsMesh) this._processCompletedMesh(); this.rawMesh.objectName = reconstructString(this.contentRef, this.legacyMode, this.globalCounts.lineByte + 2, this.globalCounts.currentByte); break; case 'mtllib': this.rawMesh.mtllibName = reconstructString(this.contentRef, this.legacyMode, this.globalCounts.lineByte + 7, this.globalCounts.currentByte); break; case 'usemtl': const mtlName = reconstructString(this.contentRef, this.legacyMode, this.globalCounts.lineByte + 7, this.globalCounts.currentByte); if (mtlName !== '' && this.rawMesh.activeMtlName !== mtlName) { this.rawMesh.activeMtlName = mtlName; this.rawMesh.counts.mtlCount++; this._checkSubGroup(); } break; } } _pushSmoothingGroup(smoothingGroup) { let smoothingGroupInt = parseInt(smoothingGroup); if (isNaN(smoothingGroupInt)) { smoothingGroupInt = smoothingGroup === 'off' ? 0 : 1; } const smoothCheck = this.rawMesh.smoothingGroup.normalized; this.rawMesh.smoothingGroup.normalized = this.rawMesh.smoothingGroup.splitMaterials ? smoothingGroupInt : smoothingGroupInt === 0 ? 0 : 1; this.rawMesh.smoothingGroup.real = smoothingGroupInt; if (smoothCheck !== smoothingGroupInt) { this.rawMesh.counts.smoothingGroupCount++; this._checkSubGroup(); } } /** * Expanded faceTypes include all four face types, both line types and the point type * faceType = 0: "f vertex ..." * faceType = 1: "f vertex/uv ..." * faceType = 2: "f vertex/uv/normal ..." * faceType = 3: "f vertex//normal ..." * faceType = 4: "l vertex/uv ..." or "l vertex ..." * faceType = 5: "l vertex ..." * faceType = 6: "p vertex ..." */ _checkFaceType(faceType) { if (this.rawMesh.faceType !== faceType) { this._processCompletedMesh(); this.rawMesh.faceType = faceType; this._checkSubGroup(); } } _checkSubGroup() { const index = this.rawMesh.activeMtlName + '|' + this.rawMesh.smoothingGroup.normalized; this.rawMesh.subGroupInUse = this.rawMesh.subGroups[index]; if (this.rawMesh.subGroupInUse === undefined || this.rawMesh.subGroupInUse === null) { this.rawMesh.subGroupInUse = { index: index, objectName: this.rawMesh.objectName, groupName: this.rawMesh.groupName, materialName: this.rawMesh.activeMtlName, smoothingGroup: this.rawMesh.smoothingGroup.normalized, vertices: [], indexMappingsCount: 0, indexMappings: [], indices: [], colors: [], uvs: [], normals: [] }; this.rawMesh.subGroups[index] = this.rawMesh.subGroupInUse; } } _buildFace(faceIndexV, faceIndexU, faceIndexN) { const subGroupInUse = this.rawMesh.subGroupInUse; const scope = this; const updateSubGroupInUse = function () { const faceIndexVi = parseInt(faceIndexV); let indexPointerV = 3 * (faceIndexVi > 0 ? faceIndexVi - 1 : faceIndexVi + scope.vertices.length / 3); let indexPointerC = scope.colors.length > 0 ? indexPointerV : null; const vertices = subGroupInUse.vertices; vertices.push(scope.vertices[indexPointerV++]); vertices.push(scope.vertices[indexPointerV++]); vertices.push(scope.vertices[indexPointerV]); if (indexPointerC !== null) { const colors = subGroupInUse.colors; colors.push(scope.colors[indexPointerC++]); colors.push(scope.colors[indexPointerC++]); colors.push(scope.colors[indexPointerC]); } if (faceIndexU) { const faceIndexUi = parseInt(faceIndexU); let indexPointerU = 2 * (faceIndexUi > 0 ? faceIndexUi - 1 : faceIndexUi + scope.uvs.length / 2); const uvs = subGroupInUse.uvs; uvs.push(scope.uvs[indexPointerU++]); uvs.push(scope.uvs[indexPointerU]); } if (faceIndexN && !scope.disregardNormals) { const faceIndexNi = parseInt(faceIndexN); let indexPointerN = 3 * (faceIndexNi > 0 ? faceIndexNi - 1 : faceIndexNi + scope.normals.length / 3); const normals = subGroupInUse.normals; normals.push(scope.normals[indexPointerN++]); normals.push(scope.normals[indexPointerN++]); normals.push(scope.normals[indexPointerN]); } }; if (this.useIndices) { if (this.disregardNormals) faceIndexN = undefined; const mappingName = faceIndexV + (faceIndexU ? '_' + faceIndexU : '_n') + (faceIndexN ? '_' + faceIndexN : '_n'); let indicesPointer = subGroupInUse.indexMappings[mappingName]; if (indicesPointer === undefined || indicesPointer === null) { indicesPointer = this.rawMesh.subGroupInUse.vertices.length / 3; updateSubGroupInUse(); subGroupInUse.indexMappings[mappingName] = indicesPointer; subGroupInUse.indexMappingsCount++; } else { this.rawMesh.counts.doubleIndicesCount++; } subGroupInUse.indices.push(indicesPointer); } else { updateSubGroupInUse(); } this.rawMesh.counts.faceCount++; } _createRawMeshReport(inputObjectCount) { return 'Input Object number: ' + inputObjectCount + '\n\tObject name: ' + this.rawMesh.objectName + '\n\tGroup name: ' + this.rawMesh.groupName + '\n\tMtllib name: ' + this.rawMesh.mtllibName + '\n\tVertex count: ' + this.vertices.length / 3 + '\n\tNormal count: ' + this.normals.length / 3 + '\n\tUV count: ' + this.uvs.length / 2 + '\n\tSmoothingGroup count: ' + this.rawMesh.counts.smoothingGroupCount + '\n\tMaterial count: ' + this.rawMesh.counts.mtlCount + '\n\tReal MeshOutputGroup count: ' + this.rawMesh.subGroups.length; } /** * Clear any empty subGroup and calculate absolute vertex, normal and uv counts */ _finalizeRawMesh() { const meshOutputGroupTemp = []; let meshOutputGroup; let absoluteVertexCount = 0; let absoluteIndexMappingsCount = 0; let absoluteIndexCount = 0; let absoluteColorCount = 0; let absoluteNormalCount = 0; let absoluteUvCount = 0; let indices; for (const name in this.rawMesh.subGroups) { meshOutputGroup = this.rawMesh.subGroups[name]; if (meshOutputGroup.vertices.length > 0) { indices = meshOutputGroup.indices; if (indices.length > 0 && absoluteIndexMappingsCount > 0) { for (let i = 0; i < indices.length; i++) { indices[i] = indices[i] + absoluteIndexMappingsCount; } } meshOutputGroupTemp.push(meshOutputGroup); absoluteVertexCount += meshOutputGroup.vertices.length; absoluteIndexMappingsCount += meshOutputGroup.indexMappingsCount; absoluteIndexCount += meshOutputGroup.indices.length; absoluteColorCount += meshOutputGroup.colors.length; absoluteUvCount += meshOutputGroup.uvs.length; absoluteNormalCount += meshOutputGroup.normals.length; } } // do not continue if no result let result = null; if (meshOutputGroupTemp.length > 0) { result = { name: this.rawMesh.groupName !== '' ? this.rawMesh.groupName : this.rawMesh.objectName, subGroups: meshOutputGroupTemp, absoluteVertexCount: absoluteVertexCount, absoluteIndexCount: absoluteIndexCount, absoluteColorCount: absoluteColorCount, absoluteNormalCount: absoluteNormalCount, absoluteUvCount: absoluteUvCount, faceCount: this.rawMesh.counts.faceCount, doubleIndicesCount: this.rawMesh.counts.doubleIndicesCount }; } return result; } _processCompletedMesh() { const result = this._finalizeRawMesh(); const haveMesh = result !== null; if (haveMesh) { if (this.colors.length > 0 && this.colors.length !== this.vertices.length) { this._onError('Vertex Colors were detected, but vertex count and color count do not match!'); } if (this.logging.enabled && this.logging.debug) console.debug(this._createRawMeshReport(this.inputObjectCount)); this.inputObjectCount++; this._buildMesh(result); const progressBytesPercent = this.globalCounts.currentByte / this.globalCounts.totalBytes; this._onProgress('Completed [o: ' + this.rawMesh.objectName + ' g:' + this.rawMesh.groupName + '' + '] Total progress: ' + (progressBytesPercent * 100).toFixed(2) + '%'); this._resetRawMesh(); } return haveMesh; } /** * SubGroups are transformed to too intermediate format that is forwarded to the MeshReceiver. * It is ensured that SubGroups only contain objects with vertices (no need to check). * * @param result */ _buildMesh(result) { const meshOutputGroups = result.subGroups; this.globalCounts.vertices += result.absoluteVertexCount / 3; this.globalCounts.faces += result.faceCount; this.globalCounts.doubleIndicesCount += result.doubleIndicesCount; const geometry = new three__WEBPACK_IMPORTED_MODULE_0__["BufferGeometry"](); const vertexFA = new Float32Array(result.absoluteVertexCount); const indexUA = result.absoluteIndexCount > 0 ? new Uint32Array(result.absoluteIndexCount) : null; const colorFA = result.absoluteColorCount > 0 ? new Float32Array(result.absoluteColorCount) : null; const normalFA = result.absoluteNormalCount > 0 ? new Float32Array(result.absoluteNormalCount) : null; const uvFA = result.absoluteUvCount > 0 ? new Float32Array(result.absoluteUvCount) : null; geometry.setAttribute('position', new three__WEBPACK_IMPORTED_MODULE_0__["BufferAttribute"](vertexFA, 3, false)); if (normalFA != null) geometry.setAttribute('normal', new three__WEBPACK_IMPORTED_MODULE_0__["BufferAttribute"](normalFA, 3, false)); if (uvFA != null) geometry.setAttribute('uv', new three__WEBPACK_IMPORTED_MODULE_0__["BufferAttribute"](uvFA, 2, false)); if (colorFA != null) geometry.setAttribute('color', new three__WEBPACK_IMPORTED_MODULE_0__["BufferAttribute"](colorFA, 3, false)); if (indexUA !== null) geometry.setIndex(new three__WEBPACK_IMPORTED_MODULE_0__["BufferAttribute"](indexUA, 1, false)); let meshOutputGroup; let vertexFAOffset = 0; let indexUAOffset = 0; let colorFAOffset = 0; let normalFAOffset = 0; let uvFAOffset = 0; let materialGroupOffset = 0; let materialGroupLength = 0; const createMultiMaterial = meshOutputGroups.length > 1; const multiMaterial = []; const haveVertexColors = colorFA !== null; let flatShading; let materialIndex = 0; let materialOrg, material, materialName, materialNameOrg; const materialMetaInfo = { cloneInstructions: [], multiMaterialNames: {}, modelName: this.modelName, progress: this.globalCounts.currentByte / this.globalCounts.totalBytes, geometryType: this.rawMesh.faceType < 4 ? 0 : this.rawMesh.faceType === 6 ? 2 : 1, objectId: this.objectId }; for (const oodIndex in meshOutputGroups) { if (!meshOutputGroups.hasOwnProperty(oodIndex)) continue; meshOutputGroup = meshOutputGroups[oodIndex]; materialNameOrg = meshOutputGroup.materialName; flatShading = meshOutputGroup.smoothingGroup === 0; if (this.rawMesh.faceType < 4) { materialName = materialNameOrg; if (haveVertexColors) { materialName += '_vertexColor'; } if (flatShading) { materialName += '_flat'; } } else { materialName = this.rawMesh.faceType === 6 ? 'defaultPointMaterial' : 'defaultLineMaterial'; } materialOrg = this.materials[materialNameOrg]; material = this.materials[materialName]; // both original and derived names do not lead to an existing material => need to use a default material if ((materialOrg === undefined || materialOrg === null) && (material === undefined || material === null)) { materialName = haveVertexColors ? 'defaultVertexColorMaterial' : 'defaultMaterial'; material = this.materials[materialName]; if (this.logging.enabled) { console.info('object_group "' + meshOutputGroup.objectName + '_' + meshOutputGroup.groupName + '" was defined with unresolvable material "' + materialNameOrg + '"! Assigning "' + materialName + '".'); } } if (material === undefined || material === null) { const materialCloneInstruction = { materialNameOrg: materialNameOrg, materialProperties: { name: materialName, vertexColors: haveVertexColors ? 2 : 0, flatShading: flatShading } }; material = three_wtm__WEBPACK_IMPORTED_MODULE_1__["MaterialUtils"].cloneMaterial(this.materials, materialCloneInstruction, this.logging.enabled && this.logging.debug); materialMetaInfo.cloneInstructions.push(materialCloneInstruction); } if (createMultiMaterial) { materialGroupLength = this.useIndices ? meshOutputGroup.indices.length : meshOutputGroup.vertices.length / 3; geometry.addGroup(materialGroupOffset, materialGroupLength, materialIndex); material = this.materials[materialName]; multiMaterial[materialIndex] = material; materialMetaInfo.multiMaterialNames[materialIndex] = material.name; materialGroupOffset += materialGroupLength; materialIndex++; } vertexFA.set(meshOutputGroup.vertices, vertexFAOffset); vertexFAOffset += meshOutputGroup.vertices.length; if (indexUA !== null) { indexUA.set(meshOutputGroup.indices, indexUAOffset); indexUAOffset += meshOutputGroup.indices.length; } if (colorFA !== null) { colorFA.set(meshOutputGroup.colors, colorFAOffset); colorFAOffset += meshOutputGroup.colors.length; } if (normalFA !== null) { normalFA.set(meshOutputGroup.normals, normalFAOffset); normalFAOffset += meshOutputGroup.normals.length; } if (uvFA !== null) { uvFA.set(meshOutputGroup.uvs, uvFAOffset); uvFAOffset += meshOutputGroup.uvs.length; } if (this.logging.enabled && this.logging.debug) { let materialIndexLine = ''; if (materialIndex > 0) { materialIndexLine = '\n\t\tmaterialIndex: ' + materialIndex; } const createdReport = '\tOutput Object no.: ' + this.outputObjectCount + '\n\t\tgroupName: ' + meshOutputGroup.groupName + '\n\t\tIndex: ' + meshOutputGroup.index + '\n\t\tfaceType: ' + this.rawMesh.faceType + '\n\t\tmaterialName: ' + meshOutputGroup.materialName + '\n\t\tsmoothingGroup: ' + meshOutputGroup.smoothingGroup + materialIndexLine + '\n\t\tobjectName: ' + meshOutputGroup.objectName + '\n\t\t#vertices: ' + meshOutputGroup.vertices.length / 3 + '\n\t\t#indices: ' + meshOutputGroup.indices.length + '\n\t\t#colors: ' + meshOutputGroup.colors.length / 3 + '\n\t\t#uvs: ' + meshOutputGroup.uvs.length / 2 + '\n\t\t#normals: ' + meshOutputGroup.normals.length / 3; console.debug(createdReport); } } this.outputObjectCount++; let normalBA = geometry.getAttribute('normal'); if (normalBA === undefined || normalBA === null) geometry.computeVertexNormals(); let mesh; const appliedMaterial = createMultiMaterial ? multiMaterial : material; if (materialMetaInfo.geometryType === 0) { mesh = new three__WEBPACK_IMPORTED_MODULE_0__["Mesh"](geometry, appliedMaterial); } else if (materialMetaInfo.geometryType === 1) { mesh = new three__WEBPACK_IMPORTED_MODULE_0__["LineSegments"](geometry, appliedMaterial); } else { mesh = new three__WEBPACK_IMPORTED_MODULE_0__["Points"](geometry, appliedMaterial); } mesh.name = result.name; this._onAssetAvailable(mesh, materialMetaInfo); } _finalizeParsing() { if (this.logging.enabled) console.info('Global output object count: ' + this.outputObjectCount); if (this._processCompletedMesh() && this.logging.enabled) { const parserFinalReport = 'Overall counts: ' + '\n\tVertices: ' + this.globalCounts.vertices + '\n\tFaces: ' + this.globalCounts.faces + '\n\tMultiple definitions: ' + this.globalCounts.doubleIndicesCount; console.info(parserFinalReport); } this._onLoad(); } /** * Announce parse progress feedback which is logged to the console. * @private * * @param {string} text Textual description of the event */ _onProgress(text) { if (this.callbacks.onProgress !== null) { this.callbacks.onProgress(text); } else { const message = text ? text : ''; if (this.logging.enabled && this.logging.debug) console.log(message); } } /** * Announce error feedback which is logged as error message. * @private * * @param {String} errorMessage The event containing the error */ _onError(errorMessage) { if (this.callbacks.onError !== null) { this.callbacks.onError(errorMessage); } else { if (this.logging.enabled && this.logging.debug) console.error(errorMessage); } } /** * * @param {Mesh} mesh * @param {object} materialMetaInfo */ _onAssetAvailable(mesh, materialMetaInfo) { // hook for alteration or transfer to main when parser is run in worker this._onMeshAlter(mesh, materialMetaInfo); this.baseObject3d.add(mesh); } _onMeshAlter(mesh) { if (this.callbacks.onMeshAlter !== null) this.callbacks.onMeshAlter(mesh, this.baseObject3d); } _onLoad() { if (this.callbacks.onLoad !== null) this.callbacks.onLoad(this.baseObject3d, this.objectId); } static buildUglifiedMapping() { function _OBJLoader2Parser() { return OBJLoader2Parser; } return three_wtm__WEBPACK_IMPORTED_MODULE_1__["DeUglify"].buildUglifiedNameAssignment(_OBJLoader2Parser, 'OBJLoader2Parser', /_OBJLoader2Parser/, true); } } class OBJ2LoaderWorker { static buildStandardWorkerDependencies(threeJsLocation) { return [{ url: threeJsLocation }, { code: three_wtm__WEBPACK_IMPORTED_MODULE_1__["DeUglify"].buildThreeConst() }, { code: OBJ2LoaderWorker.buildThreeExtraConst() }, { code: '\n\n' }, { code: three_wtm__WEBPACK_IMPORTED_MODULE_1__["DeUglify"].buildUglifiedThreeMapping() }, { code: OBJ2LoaderWorker.buildUglifiedThreeExtraMapping() }, { code: '\n\n' }, { code: three_wtm__WEBPACK_IMPORTED_MODULE_1__["ObjectUtils"].serializeClass(three_wtm__WEBPACK_IMPORTED_MODULE_1__["DataTransport"]) }, { code: three_wtm__WEBPACK_IMPORTED_MODULE_1__["ObjectUtils"].serializeClass(three_wtm__WEBPACK_IMPORTED_MODULE_1__["GeometryTransport"]) }, { code: three_wtm__WEBPACK_IMPORTED_MODULE_1__["ObjectUtils"].serializeClass(three_wtm__WEBPACK_IMPORTED_MODULE_1__["MeshTransport"]) }, { code: three_wtm__WEBPACK_IMPORTED_MODULE_1__["ObjectUtils"].serializeClass(three_wtm__WEBPACK_IMPORTED_MODULE_1__["MaterialsTransport"]) }, { code: three_wtm__WEBPACK_IMPORTED_MODULE_1__["ObjectUtils"].serializeClass(three_wtm__WEBPACK_IMPORTED_MODULE_1__["MaterialUtils"]) }, { code: three_wtm__WEBPACK_IMPORTED_MODULE_1__["ObjectUtils"].serializeClass(OBJLoader2Parser) }, { code: three_wtm__WEBPACK_IMPORTED_MODULE_1__["ObjectUtils"].serializeClass(three_wtm__WEBPACK_IMPORTED_MODULE_1__["ObjectManipulator"]) }, { code: three_wtm__WEBPACK_IMPORTED_MODULE_1__["DeUglify"].buildUglifiedThreeWtmMapping() }, { code: '\n\n' }, { code: OBJLoader2Parser.buildUglifiedMapping() }, { code: '\n\n' }]; } static buildThreeExtraConst() { return 'const MathUtils = THREE.MathUtils;\n' + 'const Material = THREE.Material;\n' + 'const Object3D = THREE.Object3D;\n' + 'const Mesh = THREE.Mesh;\n'; } static buildUglifiedThreeExtraMapping() { function _MathUtils() { return three__WEBPACK_IMPORTED_MODULE_0__["MathUtils"]; } function _Material() { return three__WEBPACK_IMPORTED_MODULE_0__["Material"]; } function _Object3D() { return three__WEBPACK_IMPORTED_MODULE_0__["Object3D"]; } function _Mesh() { return three__WEBPACK_IMPORTED_MODULE_0__["Mesh"]; } return three_wtm__WEBPACK_IMPORTED_MODULE_1__["DeUglify"].buildUglifiedNameAssignment(_MathUtils, 'MathUtils', /_MathUtils/, false) + three_wtm__WEBPACK_IMPORTED_MODULE_1__["DeUglify"].buildUglifiedNameAssignment(_Material, 'Material', /_Material/, false) + three_wtm__WEBPACK_IMPORTED_MODULE_1__["DeUglify"].buildUglifiedNameAssignment(_Object3D, 'Object3D', /_Object3D/, false) + three_wtm__WEBPACK_IMPORTED_MODULE_1__["DeUglify"].buildUglifiedNameAssignment(_Mesh, 'Mesh', /_Mesh/, false); } static init(context, id, config) { const materialsTransport = new three_wtm__WEBPACK_IMPORTED_MODULE_1__["MaterialsTransport"]().loadData(config); context.obj2 = { parser: new OBJLoader2Parser(), buffer: null, materials: materialsTransport.getMaterials() }; context.obj2.parser._onMeshAlter = (mesh, materialMetaInfo) => { const materialsTransport = new three_wtm__WEBPACK_IMPORTED_MODULE_1__["MaterialsTransport"](); materialsTransport.main.multiMaterialNames = materialMetaInfo.multiMaterialNames; // only makes sense if materials are newly created, what they currently are not if (Object.keys(materialsTransport.main.multiMaterialNames).length === 0) { const material = mesh.material; three_wtm__WEBPACK_IMPORTED_MODULE_1__["MaterialUtils"].addMaterial(materialsTransport.main.materials, material, material.name, false, false); } materialsTransport.main.cloneInstructions = materialMetaInfo.cloneInstructions; materialsTransport.cleanMaterials(); const meshTransport = new three_wtm__WEBPACK_IMPORTED_MODULE_1__["MeshTransport"]('assetAvailable', materialMetaInfo.objectId).setProgress(materialMetaInfo.progress).setParams({ modelName: materialMetaInfo.modelName }).setMesh(mesh, materialMetaInfo.geometryType).setMaterialsTransport(materialsTransport); meshTransport.postMessage(context); }; context.obj2.parser.callbacks.onLoad = () => { const dataTransport = new three_wtm__WEBPACK_IMPORTED_MODULE_1__["DataTransport"]('execComplete', context.obj2.parser.objectId); dataTransport.postMessage(context); }; context.obj2.parser.callbacks.onProgress = text => { if (context.obj2.parser.logging.debug) console.debug('WorkerRunner: progress: ' + text); }; three_wtm__WEBPACK_IMPORTED_MODULE_1__["ObjectManipulator"].applyProperties(context.obj2.parser, materialsTransport.getParams(), false); const buffer = materialsTransport.getBuffer('modelData'); if (buffer !== undefined && buffer !== null) context.obj2.buffer = buffer; new three_wtm__WEBPACK_IMPORTED_MODULE_1__["DataTransport"]('init', id).postMessage(context); } static execute(context, id, config) { if (context.obj2.parser.usedBefore) { context.obj2.parser._init(); } context.obj2.parser.materials = context.obj2.materials; const dataTransport = new three_wtm__WEBPACK_IMPORTED_MODULE_1__["DataTransport"]().loadData(config); three_wtm__WEBPACK_IMPORTED_MODULE_1__["ObjectManipulator"].applyProperties(context.obj2.parser, dataTransport.getParams(), false); const buffer = dataTransport.getBuffer('modelData'); if (buffer !== undefined && buffer !== null) context.obj2.buffer = buffer; if (context.obj2.buffer) { context.obj2.parser.objectId = dataTransport.getId(); context.obj2.parser._execute(context.obj2.buffer); } } } /** * Creates a new OBJLoader2Parallel. Use it to load OBJ data from files or to parse OBJ data from arraybuffer. * It extends {@link OBJLoader2} with the capability to run the parser in a web worker. * * @param [LoadingManager] manager The loadingManager for the loader to use. Default is {@link LoadingManager} * @constructor */ class OBJLoader2Parallel extends OBJLoader2 { /** * * @param {LoadingManager} [manager] */ constructor(manager) { super(manager); this.preferJsmWorker = false; this.urls = { /** @type {URL} */ jsmWorker: new URL(OBJLoader2Parallel.DEFAULT_JSM_WORKER_PATH, window.location.href), /** @type {URL} */ threejs: new URL(OBJLoader2Parallel.DEFAULT_JSM_THREEJS_PATH, window.location.href) }; this.workerTaskManager = null; this.taskName = 'tmOBJLoader2'; } /** * @param {WorkerTaskManager} workerTaskManager The {@link WorkerTaskManager} * @param {string} [taskName] A specific taskName to allow distinction between legacy and module workers * * @return {OBJLoader2Parallel} */ setWorkerTaskManager(workerTaskManager, taskName) { this.workerTaskManager = workerTaskManager; if (taskName) this.taskName = taskName; return this; } /** * Set whether jsm modules in workers should be used. This requires browser support which is currently only experimental. * * @param {boolean} preferJsmWorker True or False * @param {URL} jsmWorkerUrl Provide complete jsm worker URL otherwise relative path to this module may not be correct * @return {OBJLoader2Parallel} */ setJsmWorker(preferJsmWorker, jsmWorkerUrl) { this.preferJsmWorker = preferJsmWorker === true; if (jsmWorkerUrl === undefined || jsmWorkerUrl === null || !(jsmWorkerUrl instanceof URL)) { throw 'The url to the jsm worker is not valid. Aborting...'; } else { this.urls.jsmWorker = jsmWorkerUrl; } return this; } /** * Override the default URL for three.js. This is only required when standard workers are build (preferJsmWorker=false). * * @param {URL} threejsUrl Provide complete three module URL otherwise relative path to this module may not be correct * @return {OBJLoader2Parallel} */ setThreejsLocation(threejsUrl) { if (threejsUrl === undefined || threejsUrl === null || !(threejsUrl instanceof URL)) { throw 'The url to the jsm worker is not valid. Aborting...'; } else { this.urls.threejs = threejsUrl; } return this; } /** * Request termination of worker once parser is finished. * * @param {boolean} terminateWorkerOnLoad True or false. * @return {OBJLoader2Parallel} */ setTerminateWorkerOnLoad(terminateWorkerOnLoad) { this.terminateWorkerOnLoad = terminateWorkerOnLoad === true; return this; } /** * Provide instructions on what is to be contained in the worker. * * @param {DataTransport} dataTransport Configuration object * @return {Promise} * @private */ async _buildWorkerCode(dataTransport) { if (this.workerTaskManager === null || !(this.workerTaskManager instanceof three_wtm__WEBPACK_IMPORTED_MODULE_1__["WorkerTaskManager"])) { if (this.parser.logging.debug) console.log('Needed to create new WorkerTaskManager'); this.workerTaskManager = new three_wtm__WEBPACK_IMPORTED_MODULE_1__["WorkerTaskManager"](1); this.workerTaskManager.setVerbose(this.parser.logging.enabled && this.parser.logging.debug); } if (!this.workerTaskManager.supportsTaskType(this.taskName)) { if (this.preferJsmWorker) { this.workerTaskManager.registerTaskTypeModule(this.taskName, this.urls.jsmWorker); } else { // build the standard worker from code imported here and don't reference three.js build with fixed path this.workerTaskManager.registerTaskType(this.taskName, OBJ2LoaderWorker.init, OBJ2LoaderWorker.execute, null, false, OBJ2LoaderWorker.buildStandardWorkerDependencies(this.urls.threejs)); } await this.workerTaskManager.initTaskType(this.taskName, dataTransport.getMain()); } } /** * See {@link OBJLoader2.load} */ load(content, onLoad, onFileLoadProgress, onError, onMeshAlter) { const scope = this; function interceptOnLoad(object3d, objectId) { if (object3d.name === 'OBJLoader2ParallelDummy') { if (scope.parser.logging.enabled && scope.parser.logging.debug) { console.debug('Received dummy answer from OBJLoader2Parallel#parse'); } } else { onLoad(object3d, objectId); } } OBJLoader2.prototype.load.call(this, content, interceptOnLoad, onFileLoadProgress, onError, onMeshAlter); } /** * See {@link OBJLoader2.parse} * The callback onLoad needs to be set to be able to receive the content if used in parallel mode. */ parse(content) { if (this.parser.logging.enabled) { console.info('Using OBJLoader2Parallel version: ' + OBJLoader2Parallel.OBJLOADER2_PARALLEL_VERSION); } const dataTransport = new three_wtm__WEBPACK_IMPORTED_MODULE_1__["DataTransport"]().setParams({ logging: { enabled: this.parser.logging.enabled, debug: this.parser.logging.debug } }); this._buildWorkerCode(dataTransport).then(() => { if (this.parser.logging.debug) console.log('OBJLoader2Parallel init was performed'); this._executeWorkerParse(content); }).catch(e => console.error(e)); let dummy = new three__WEBPACK_IMPORTED_MODULE_0__["Object3D"](); dummy.name = 'OBJLoader2ParallelDummy'; return dummy; } _executeWorkerParse(content) { const dataTransport = new three_wtm__WEBPACK_IMPORTED_MODULE_1__["DataTransport"]('execute', Math.floor(Math.random() * Math.floor(65536))); dataTransport.setParams({ modelName: this.parser.modelName, useIndices: this.parser.useIndices, disregardNormals: this.parser.disregardNormals, materialPerSmoothingGroup: this.parser.materialPerSmoothingGroup, useOAsMesh: this.parser.useOAsMesh, materials: three_wtm__WEBPACK_IMPORTED_MODULE_1__["MaterialUtils"].getMaterialsJSON(this.materialStore.getMaterials()) }).addBuffer('modelData', content).package(false); this.workerTaskManager.enqueueForExecution(this.taskName, dataTransport.getMain(), dataTransport => this._onLoad(dataTransport), dataTransport.getTransferables()).then(dataTransport => { this._onLoad(dataTransport); if (this.terminateWorkerOnLoad) this.workerTaskManager.dispose(); }).catch(e => console.error(e)); } /** * * @param {Mesh} mesh * @param {object} materialMetaInfo */ _onLoad(asset) { let cmd = asset.cmd; if (cmd === 'assetAvailable') { let meshTransport; if (asset.type === 'MeshTransport') { meshTransport = new three_wtm__WEBPACK_IMPORTED_MODULE_1__["MeshTransport"]().loadData(asset).reconstruct(false); } else { console.error('Received unknown asset.type: ' + asset.type); } if (meshTransport) { const materialsTransport = meshTransport.getMaterialsTransport(); let material = materialsTransport.processMaterialTransport(this.materialStore.getMaterials(), this.parser.logging.enabled); if (material === null) material = new three__WEBPACK_IMPORTED_MODULE_0__["MeshStandardMaterial"]({ color: 0xFF0000 }); let mesh; if (meshTransport.getGeometryType() === 0) { mesh = new three__WEBPACK_IMPORTED_MODULE_0__["Mesh"](meshTransport.getBufferGeometry(), material); } else if (meshTransport.getGeometryType() === 1) { mesh = new three__WEBPACK_IMPORTED_MODULE_0__["LineSegments"](meshTransport.getBufferGeometry(), material); } else { mesh = new three__WEBPACK_IMPORTED_MODULE_0__["Points"](meshTransport.getBufferGeometry(), material); } this.parser._onMeshAlter(mesh); this.parser.baseObject3d.add(mesh); } } else if (cmd === 'execComplete') { let dataTransport; if (asset.type === 'DataTransport') { dataTransport = new three_wtm__WEBPACK_IMPORTED_MODULE_1__["DataTransport"]().loadData(asset); if (dataTransport instanceof three_wtm__WEBPACK_IMPORTED_MODULE_1__["DataTransport"] && this.parser.callbacks.onLoad !== null) { this.parser.callbacks.onLoad(this.parser.baseObject3d, dataTransport.getId()); } } else { console.error('Received unknown asset.type: ' + asset.type); } } else { console.error('Received unknown command: ' + cmd); } } } _defineProperty(OBJLoader2Parallel, "OBJLOADER2_PARALLEL_VERSION", OBJLoader2.OBJLOADER2_VERSION); _defineProperty(OBJLoader2Parallel, "DEFAULT_JSM_WORKER_PATH", '/src/loaders/tmOBJLoader2.js'); _defineProperty(OBJLoader2Parallel, "DEFAULT_JSM_THREEJS_PATH", '/node_modules/three/build/three.min.js'); class MtlObjBridge { /** * * @param processResult * @param assetLoader */ static link(processResult, assetLoader) { if (typeof assetLoader.setMaterials === 'function') { assetLoader.setMaterials(MtlObjBridge.addMaterialsFromMtlLoader(processResult), true); } } /** * Returns the array instance of {@link Material}. * * @param materialCreator instance of MTLLoader */ static addMaterialsFromMtlLoader(materialCreator) { let newMaterials = {}; if (materialCreator['preload'] !== undefined && materialCreator['preload'] instanceof Function) { materialCreator['preload'](); newMaterials = materialCreator.materials; } return newMaterials; } } /***/ }) /******/ ]); });