{"version":3,"file":"MTLLoader.cjs","sources":["../../src/loaders/MTLLoader.js"],"sourcesContent":["import {\n Color,\n DefaultLoadingManager,\n FileLoader,\n FrontSide,\n Loader,\n LoaderUtils,\n MeshPhongMaterial,\n RepeatWrapping,\n TextureLoader,\n Vector2,\n} from 'three'\n\n/**\n * Loads a Wavefront .mtl file specifying materials\n */\n\nclass MTLLoader extends Loader {\n constructor(manager) {\n super(manager)\n }\n\n /**\n * Loads and parses a MTL asset from a URL.\n *\n * @param {String} url - URL to the MTL file.\n * @param {Function} [onLoad] - Callback invoked with the loaded object.\n * @param {Function} [onProgress] - Callback for download progress.\n * @param {Function} [onError] - Callback for download errors.\n *\n * @see setPath setResourcePath\n *\n * @note In order for relative texture references to resolve correctly\n * you must call setResourcePath() explicitly prior to load.\n */\n load(url, onLoad, onProgress, onError) {\n const scope = this\n\n const path = this.path === '' ? LoaderUtils.extractUrlBase(url) : this.path\n\n const loader = new FileLoader(this.manager)\n loader.setPath(this.path)\n loader.setRequestHeader(this.requestHeader)\n loader.setWithCredentials(this.withCredentials)\n loader.load(\n url,\n function (text) {\n try {\n onLoad(scope.parse(text, path))\n } catch (e) {\n if (onError) {\n onError(e)\n } else {\n console.error(e)\n }\n\n scope.manager.itemError(url)\n }\n },\n onProgress,\n onError,\n )\n }\n\n setMaterialOptions(value) {\n this.materialOptions = value\n return this\n }\n\n /**\n * Parses a MTL file.\n *\n * @param {String} text - Content of MTL file\n * @return {MaterialCreator}\n *\n * @see setPath setResourcePath\n *\n * @note In order for relative texture references to resolve correctly\n * you must call setResourcePath() explicitly prior to parse.\n */\n parse(text, path) {\n const lines = text.split('\\n')\n let info = {}\n const delimiter_pattern = /\\s+/\n const materialsInfo = {}\n\n for (let i = 0; i < lines.length; i++) {\n let line = lines[i]\n line = line.trim()\n\n if (line.length === 0 || line.charAt(0) === '#') {\n // Blank line or comment ignore\n continue\n }\n\n const pos = line.indexOf(' ')\n\n let key = pos >= 0 ? line.substring(0, pos) : line\n key = key.toLowerCase()\n\n let value = pos >= 0 ? line.substring(pos + 1) : ''\n value = value.trim()\n\n if (key === 'newmtl') {\n // New material\n\n info = { name: value }\n materialsInfo[value] = info\n } else {\n if (key === 'ka' || key === 'kd' || key === 'ks' || key === 'ke') {\n const ss = value.split(delimiter_pattern, 3)\n info[key] = [parseFloat(ss[0]), parseFloat(ss[1]), parseFloat(ss[2])]\n } else {\n info[key] = value\n }\n }\n }\n\n const materialCreator = new MaterialCreator(this.resourcePath || path, this.materialOptions)\n materialCreator.setCrossOrigin(this.crossOrigin)\n materialCreator.setManager(this.manager)\n materialCreator.setMaterials(materialsInfo)\n return materialCreator\n }\n}\n\n/**\n * Create a new MTLLoader.MaterialCreator\n * @param baseUrl - Url relative to which textures are loaded\n * @param options - Set of options on how to construct the materials\n * side: Which side to apply the material\n * FrontSide (default), THREE.BackSide, THREE.DoubleSide\n * wrap: What type of wrapping to apply for textures\n * RepeatWrapping (default), THREE.ClampToEdgeWrapping, THREE.MirroredRepeatWrapping\n * normalizeRGB: RGBs need to be normalized to 0-1 from 0-255\n * Default: false, assumed to be already normalized\n * ignoreZeroRGBs: Ignore values of RGBs (Ka,Kd,Ks) that are all 0's\n * Default: false\n * @constructor\n */\n\nclass MaterialCreator {\n constructor(baseUrl = '', options = {}) {\n this.baseUrl = baseUrl\n this.options = options\n this.materialsInfo = {}\n this.materials = {}\n this.materialsArray = []\n this.nameLookup = {}\n\n this.crossOrigin = 'anonymous'\n\n this.side = this.options.side !== undefined ? this.options.side : FrontSide\n this.wrap = this.options.wrap !== undefined ? this.options.wrap : RepeatWrapping\n }\n\n setCrossOrigin(value) {\n this.crossOrigin = value\n return this\n }\n\n setManager(value) {\n this.manager = value\n }\n\n setMaterials(materialsInfo) {\n this.materialsInfo = this.convert(materialsInfo)\n this.materials = {}\n this.materialsArray = []\n this.nameLookup = {}\n }\n\n convert(materialsInfo) {\n if (!this.options) return materialsInfo\n\n const converted = {}\n\n for (const mn in materialsInfo) {\n // Convert materials info into normalized form based on options\n\n const mat = materialsInfo[mn]\n\n const covmat = {}\n\n converted[mn] = covmat\n\n for (const prop in mat) {\n let save = true\n let value = mat[prop]\n const lprop = prop.toLowerCase()\n\n switch (lprop) {\n case 'kd':\n case 'ka':\n case 'ks':\n // Diffuse color (color under white light) using RGB values\n\n if (this.options && this.options.normalizeRGB) {\n value = [value[0] / 255, value[1] / 255, value[2] / 255]\n }\n\n if (this.options && this.options.ignoreZeroRGBs) {\n if (value[0] === 0 && value[1] === 0 && value[2] === 0) {\n // ignore\n\n save = false\n }\n }\n\n break\n\n default:\n break\n }\n\n if (save) {\n covmat[lprop] = value\n }\n }\n }\n\n return converted\n }\n\n preload() {\n for (const mn in this.materialsInfo) {\n this.create(mn)\n }\n }\n\n getIndex(materialName) {\n return this.nameLookup[materialName]\n }\n\n getAsArray() {\n let index = 0\n\n for (const mn in this.materialsInfo) {\n this.materialsArray[index] = this.create(mn)\n this.nameLookup[mn] = index\n index++\n }\n\n return this.materialsArray\n }\n\n create(materialName) {\n if (this.materials[materialName] === undefined) {\n this.createMaterial_(materialName)\n }\n\n return this.materials[materialName]\n }\n\n createMaterial_(materialName) {\n // Create material\n\n const scope = this\n const mat = this.materialsInfo[materialName]\n const params = {\n name: materialName,\n side: this.side,\n }\n\n function resolveURL(baseUrl, url) {\n if (typeof url !== 'string' || url === '') return ''\n\n // Absolute URL\n if (/^https?:\\/\\//i.test(url)) return url\n\n return baseUrl + url\n }\n\n function setMapForType(mapType, value) {\n if (params[mapType]) return // Keep the first encountered texture\n\n const texParams = scope.getTextureParams(value, params)\n const map = scope.loadTexture(resolveURL(scope.baseUrl, texParams.url))\n\n map.repeat.copy(texParams.scale)\n map.offset.copy(texParams.offset)\n\n map.wrapS = scope.wrap\n map.wrapT = scope.wrap\n\n params[mapType] = map\n }\n\n for (const prop in mat) {\n const value = mat[prop]\n let n\n\n if (value === '') continue\n\n switch (prop.toLowerCase()) {\n // Ns is material specular exponent\n\n case 'kd':\n // Diffuse color (color under white light) using RGB values\n\n params.color = new Color().fromArray(value)\n\n break\n\n case 'ks':\n // Specular color (color when light is reflected from shiny surface) using RGB values\n params.specular = new Color().fromArray(value)\n\n break\n\n case 'ke':\n // Emissive using RGB values\n params.emissive = new Color().fromArray(value)\n\n break\n\n case 'map_kd':\n // Diffuse texture map\n\n setMapForType('map', value)\n\n break\n\n case 'map_ks':\n // Specular map\n\n setMapForType('specularMap', value)\n\n break\n\n case 'map_ke':\n // Emissive map\n\n setMapForType('emissiveMap', value)\n\n break\n\n case 'norm':\n setMapForType('normalMap', value)\n\n break\n\n case 'map_bump':\n case 'bump':\n // Bump texture map\n\n setMapForType('bumpMap', value)\n\n break\n\n case 'map_d':\n // Alpha map\n\n setMapForType('alphaMap', value)\n params.transparent = true\n\n break\n\n case 'ns':\n // The specular exponent (defines the focus of the specular highlight)\n // A high exponent results in a tight, concentrated highlight. Ns values normally range from 0 to 1000.\n\n params.shininess = parseFloat(value)\n\n break\n\n case 'd':\n n = parseFloat(value)\n\n if (n < 1) {\n params.opacity = n\n params.transparent = true\n }\n\n break\n\n case 'tr':\n n = parseFloat(value)\n\n if (this.options && this.options.invertTrProperty) n = 1 - n\n\n if (n > 0) {\n params.opacity = 1 - n\n params.transparent = true\n }\n\n break\n\n default:\n break\n }\n }\n\n this.materials[materialName] = new MeshPhongMaterial(params)\n return this.materials[materialName]\n }\n\n getTextureParams(value, matParams) {\n const texParams = {\n scale: new Vector2(1, 1),\n offset: new Vector2(0, 0),\n }\n\n const items = value.split(/\\s+/)\n let pos\n\n pos = items.indexOf('-bm')\n\n if (pos >= 0) {\n matParams.bumpScale = parseFloat(items[pos + 1])\n items.splice(pos, 2)\n }\n\n pos = items.indexOf('-s')\n\n if (pos >= 0) {\n texParams.scale.set(parseFloat(items[pos + 1]), parseFloat(items[pos + 2]))\n items.splice(pos, 4) // we expect 3 parameters here!\n }\n\n pos = items.indexOf('-o')\n\n if (pos >= 0) {\n texParams.offset.set(parseFloat(items[pos + 1]), parseFloat(items[pos + 2]))\n items.splice(pos, 4) // we expect 3 parameters here!\n }\n\n texParams.url = items.join(' ').trim()\n return texParams\n }\n\n loadTexture(url, mapping, onLoad, onProgress, onError) {\n const manager = this.manager !== undefined ? this.manager : DefaultLoadingManager\n let loader = manager.getHandler(url)\n\n if (loader === null) {\n loader = new TextureLoader(manager)\n }\n\n if (loader.setCrossOrigin) loader.setCrossOrigin(this.crossOrigin)\n\n const texture = loader.load(url, onLoad, onProgress, onError)\n\n if (mapping !== undefined) texture.mapping = mapping\n\n return texture\n }\n}\n\nexport { MTLLoader }\n"],"names":["Loader","LoaderUtils","FileLoader","FrontSide","RepeatWrapping","Color","MeshPhongMaterial","Vector2","DefaultLoadingManager","TextureLoader"],"mappings":"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"}