Cesium-Examples/libs/wwobjloader2/4.0.0/wwobjloader2.js
2025-03-11 17:51:04 +08:00

1669 lines
57 KiB
JavaScript

(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<void>}
* @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;
}
}
/***/ })
/******/ ]);
});