(function (global, factory) { if (typeof define === "function" && define.amd) { define(["exports", "three"], factory); } else if (typeof exports !== "undefined") { factory(exports, require("three")); } else { var mod = { exports: {} }; factory(mod.exports, global.three); global.MTLLoader = mod.exports; } })(typeof globalThis !== "undefined" ? globalThis : typeof self !== "undefined" ? self : this, function (_exports, _three) { "use strict"; Object.defineProperty(_exports, "__esModule", { value: true }); _exports.MTLLoader = void 0; function _classCallCheck(instance, Constructor) { if (!(instance instanceof Constructor)) { throw new TypeError("Cannot call a class as a function"); } } function _defineProperties(target, props) { for (var i = 0; i < props.length; i++) { var descriptor = props[i]; descriptor.enumerable = descriptor.enumerable || false; descriptor.configurable = true; if ("value" in descriptor) descriptor.writable = true; Object.defineProperty(target, descriptor.key, descriptor); } } function _createClass(Constructor, protoProps, staticProps) { if (protoProps) _defineProperties(Constructor.prototype, protoProps); if (staticProps) _defineProperties(Constructor, staticProps); Object.defineProperty(Constructor, "prototype", { writable: false }); return Constructor; } function _inherits(subClass, superClass) { if (typeof superClass !== "function" && superClass !== null) { throw new TypeError("Super expression must either be null or a function"); } Object.defineProperty(subClass, "prototype", { value: Object.create(superClass && superClass.prototype, { constructor: { value: subClass, writable: true, configurable: true } }), writable: false }); if (superClass) _setPrototypeOf(subClass, superClass); } function _setPrototypeOf(o, p) { _setPrototypeOf = Object.setPrototypeOf || function _setPrototypeOf(o, p) { o.__proto__ = p; return o; }; return _setPrototypeOf(o, p); } function _createSuper(Derived) { var hasNativeReflectConstruct = _isNativeReflectConstruct(); return function _createSuperInternal() { var Super = _getPrototypeOf(Derived), result; if (hasNativeReflectConstruct) { var NewTarget = _getPrototypeOf(this).constructor; result = Reflect.construct(Super, arguments, NewTarget); } else { result = Super.apply(this, arguments); } return _possibleConstructorReturn(this, result); }; } function _possibleConstructorReturn(self, call) { if (call && (typeof call === "object" || typeof call === "function")) { return call; } else if (call !== void 0) { throw new TypeError("Derived constructors may only return object or undefined"); } return _assertThisInitialized(self); } function _assertThisInitialized(self) { if (self === void 0) { throw new ReferenceError("this hasn't been initialised - super() hasn't been called"); } return self; } function _isNativeReflectConstruct() { if (typeof Reflect === "undefined" || !Reflect.construct) return false; if (Reflect.construct.sham) return false; if (typeof Proxy === "function") return true; try { Boolean.prototype.valueOf.call(Reflect.construct(Boolean, [], function () {})); return true; } catch (e) { return false; } } function _getPrototypeOf(o) { _getPrototypeOf = Object.setPrototypeOf ? Object.getPrototypeOf : function _getPrototypeOf(o) { return o.__proto__ || Object.getPrototypeOf(o); }; return _getPrototypeOf(o); } /** * Loads a Wavefront .mtl file specifying materials */ var MTLLoader = /*#__PURE__*/function (_Loader) { _inherits(MTLLoader, _Loader); var _super = _createSuper(MTLLoader); function MTLLoader(manager) { _classCallCheck(this, MTLLoader); return _super.call(this, manager); } /** * Loads and parses a MTL asset from a URL. * * @param {String} url - URL to the MTL file. * @param {Function} [onLoad] - Callback invoked with the loaded object. * @param {Function} [onProgress] - Callback for download progress. * @param {Function} [onError] - Callback for download errors. * * @see setPath setResourcePath * * @note In order for relative texture references to resolve correctly * you must call setResourcePath() explicitly prior to load. */ _createClass(MTLLoader, [{ key: "load", value: function load(url, onLoad, onProgress, onError) { var scope = this; var path = this.path === '' ? _three.LoaderUtils.extractUrlBase(url) : this.path; var loader = new _three.FileLoader(this.manager); loader.setPath(this.path); loader.setRequestHeader(this.requestHeader); loader.setWithCredentials(this.withCredentials); loader.load(url, function (text) { try { onLoad(scope.parse(text, path)); } catch (e) { if (onError) { onError(e); } else { console.error(e); } scope.manager.itemError(url); } }, onProgress, onError); } }, { key: "setMaterialOptions", value: function setMaterialOptions(value) { this.materialOptions = value; return this; } /** * Parses a MTL file. * * @param {String} text - Content of MTL file * @return {MaterialCreator} * * @see setPath setResourcePath * * @note In order for relative texture references to resolve correctly * you must call setResourcePath() explicitly prior to parse. */ }, { key: "parse", value: function parse(text, path) { var lines = text.split('\n'); var info = {}; var delimiter_pattern = /\s+/; var materialsInfo = {}; for (var i = 0; i < lines.length; i++) { var line = lines[i]; line = line.trim(); if (line.length === 0 || line.charAt(0) === '#') { // Blank line or comment ignore continue; } var pos = line.indexOf(' '); var key = pos >= 0 ? line.substring(0, pos) : line; key = key.toLowerCase(); var value = pos >= 0 ? line.substring(pos + 1) : ''; value = value.trim(); if (key === 'newmtl') { // New material info = { name: value }; materialsInfo[value] = info; } else { if (key === 'ka' || key === 'kd' || key === 'ks' || key === 'ke') { var ss = value.split(delimiter_pattern, 3); info[key] = [parseFloat(ss[0]), parseFloat(ss[1]), parseFloat(ss[2])]; } else { info[key] = value; } } } var materialCreator = new MaterialCreator(this.resourcePath || path, this.materialOptions); materialCreator.setCrossOrigin(this.crossOrigin); materialCreator.setManager(this.manager); materialCreator.setMaterials(materialsInfo); return materialCreator; } }]); return MTLLoader; }(_three.Loader); /** * Create a new MTLLoader.MaterialCreator * @param baseUrl - Url relative to which textures are loaded * @param options - Set of options on how to construct the materials * side: Which side to apply the material * FrontSide (default), THREE.BackSide, THREE.DoubleSide * wrap: What type of wrapping to apply for textures * RepeatWrapping (default), THREE.ClampToEdgeWrapping, THREE.MirroredRepeatWrapping * normalizeRGB: RGBs need to be normalized to 0-1 from 0-255 * Default: false, assumed to be already normalized * ignoreZeroRGBs: Ignore values of RGBs (Ka,Kd,Ks) that are all 0's * Default: false * @constructor */ _exports.MTLLoader = MTLLoader; var MaterialCreator = /*#__PURE__*/function () { function MaterialCreator() { var baseUrl = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : ''; var options = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : {}; _classCallCheck(this, MaterialCreator); this.baseUrl = baseUrl; this.options = options; this.materialsInfo = {}; this.materials = {}; this.materialsArray = []; this.nameLookup = {}; this.crossOrigin = 'anonymous'; this.side = this.options.side !== undefined ? this.options.side : _three.FrontSide; this.wrap = this.options.wrap !== undefined ? this.options.wrap : _three.RepeatWrapping; } _createClass(MaterialCreator, [{ key: "setCrossOrigin", value: function setCrossOrigin(value) { this.crossOrigin = value; return this; } }, { key: "setManager", value: function setManager(value) { this.manager = value; } }, { key: "setMaterials", value: function setMaterials(materialsInfo) { this.materialsInfo = this.convert(materialsInfo); this.materials = {}; this.materialsArray = []; this.nameLookup = {}; } }, { key: "convert", value: function convert(materialsInfo) { if (!this.options) return materialsInfo; var converted = {}; for (var mn in materialsInfo) { // Convert materials info into normalized form based on options var mat = materialsInfo[mn]; var covmat = {}; converted[mn] = covmat; for (var prop in mat) { var save = true; var value = mat[prop]; var lprop = prop.toLowerCase(); switch (lprop) { case 'kd': case 'ka': case 'ks': // Diffuse color (color under white light) using RGB values if (this.options && this.options.normalizeRGB) { value = [value[0] / 255, value[1] / 255, value[2] / 255]; } if (this.options && this.options.ignoreZeroRGBs) { if (value[0] === 0 && value[1] === 0 && value[2] === 0) { // ignore save = false; } } break; default: break; } if (save) { covmat[lprop] = value; } } } return converted; } }, { key: "preload", value: function preload() { for (var mn in this.materialsInfo) { this.create(mn); } } }, { key: "getIndex", value: function getIndex(materialName) { return this.nameLookup[materialName]; } }, { key: "getAsArray", value: function getAsArray() { var index = 0; for (var mn in this.materialsInfo) { this.materialsArray[index] = this.create(mn); this.nameLookup[mn] = index; index++; } return this.materialsArray; } }, { key: "create", value: function create(materialName) { if (this.materials[materialName] === undefined) { this.createMaterial_(materialName); } return this.materials[materialName]; } }, { key: "createMaterial_", value: function createMaterial_(materialName) { // Create material var scope = this; var mat = this.materialsInfo[materialName]; var params = { name: materialName, side: this.side }; function resolveURL(baseUrl, url) { if (typeof url !== 'string' || url === '') return ''; // Absolute URL if (/^https?:\/\//i.test(url)) return url; return baseUrl + url; } function setMapForType(mapType, value) { if (params[mapType]) return; // Keep the first encountered texture var texParams = scope.getTextureParams(value, params); var map = scope.loadTexture(resolveURL(scope.baseUrl, texParams.url)); map.repeat.copy(texParams.scale); map.offset.copy(texParams.offset); map.wrapS = scope.wrap; map.wrapT = scope.wrap; params[mapType] = map; } for (var prop in mat) { var value = mat[prop]; var n = void 0; if (value === '') continue; switch (prop.toLowerCase()) { // Ns is material specular exponent case 'kd': // Diffuse color (color under white light) using RGB values params.color = new _three.Color().fromArray(value); break; case 'ks': // Specular color (color when light is reflected from shiny surface) using RGB values params.specular = new _three.Color().fromArray(value); break; case 'ke': // Emissive using RGB values params.emissive = new _three.Color().fromArray(value); break; case 'map_kd': // Diffuse texture map setMapForType('map', value); break; case 'map_ks': // Specular map setMapForType('specularMap', value); break; case 'map_ke': // Emissive map setMapForType('emissiveMap', value); break; case 'norm': setMapForType('normalMap', value); break; case 'map_bump': case 'bump': // Bump texture map setMapForType('bumpMap', value); break; case 'map_d': // Alpha map setMapForType('alphaMap', value); params.transparent = true; break; case 'ns': // The specular exponent (defines the focus of the specular highlight) // A high exponent results in a tight, concentrated highlight. Ns values normally range from 0 to 1000. params.shininess = parseFloat(value); break; case 'd': n = parseFloat(value); if (n < 1) { params.opacity = n; params.transparent = true; } break; case 'tr': n = parseFloat(value); if (this.options && this.options.invertTrProperty) n = 1 - n; if (n > 0) { params.opacity = 1 - n; params.transparent = true; } break; default: break; } } this.materials[materialName] = new _three.MeshPhongMaterial(params); return this.materials[materialName]; } }, { key: "getTextureParams", value: function getTextureParams(value, matParams) { var texParams = { scale: new _three.Vector2(1, 1), offset: new _three.Vector2(0, 0) }; var items = value.split(/\s+/); var pos; pos = items.indexOf('-bm'); if (pos >= 0) { matParams.bumpScale = parseFloat(items[pos + 1]); items.splice(pos, 2); } pos = items.indexOf('-s'); if (pos >= 0) { texParams.scale.set(parseFloat(items[pos + 1]), parseFloat(items[pos + 2])); items.splice(pos, 4); // we expect 3 parameters here! } pos = items.indexOf('-o'); if (pos >= 0) { texParams.offset.set(parseFloat(items[pos + 1]), parseFloat(items[pos + 2])); items.splice(pos, 4); // we expect 3 parameters here! } texParams.url = items.join(' ').trim(); return texParams; } }, { key: "loadTexture", value: function loadTexture(url, mapping, onLoad, onProgress, onError) { var manager = this.manager !== undefined ? this.manager : _three.DefaultLoadingManager; var loader = manager.getHandler(url); if (loader === null) { loader = new _three.TextureLoader(manager); } if (loader.setCrossOrigin) loader.setCrossOrigin(this.crossOrigin); var texture = loader.load(url, onLoad, onProgress, onError); if (mapping !== undefined) texture.mapping = mapping; return texture; } }]); return MaterialCreator; }(); });