Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

ObjLoader2 async worker code breaks under uglify #31

Closed
unphased opened this issue Dec 29, 2017 · 17 comments
Closed

ObjLoader2 async worker code breaks under uglify #31

unphased opened this issue Dec 29, 2017 · 17 comments

Comments

@unphased
Copy link

unphased commented Dec 29, 2017

The code that gets generated for the blob for the worker ends up mangled. Here is an excerpt

Validator = { isValid: function (e){return null!==e&&void 0!==e}, verifyInput: function (e,t){return null===e||void 0===e?t:e}, }

ConsolConsoleLoggerLogger = (function () {

function e(e,t){this.enabled=e!==!1,this.debug=t===!0}

ConsoleLogger.prototype.setDebug = function (e){this.debug=e===!0};

ConsoleLogger.prototype.isDebug = function (){return this.isEnabled()&&this.debug};

ConsoleLogger.prototype.setEnabled = function (e){this.enabled=e===!0};

ConsoleLogger.prototype.isEnabled = function (){return this.enabled};

ConsoleLogger.prototype.logDebug = function (e){this.enabled&&this.debug&&console.info(e)};

ConsoleLogger.prototype.logInfo = function (e){this.enabled&&console.info(e)};

ConsoleLogger.prototype.logWarn = function (e){console.warn(e)};

ConsoleLogger.prototype.logError = function (e){console.error(e)};

ConsoleLogger.prototype.logTimeStart = function (e){this.enabled&&console.time(e)};

ConsoleLogger.prototype.logTimeEnd = function (e){this.enabled&&console.timeEnd(e)};

return ConsoleLogger;

})();

/**

  • This code was constructed by OBJLoader2 buildCode.
    */

LoadLoaderBaserBase = (function () {

function e(e,o){this.manager=t.verifyInput(e,THREE.DefaultLoadingManager),this.logger=t.verifyInput(o,new n),this.modelName="",this.instanceNo=0,this.path="",this.useIndices=!1,this.disregardNormals=!1,this.loaderRootNode=new THREE.Group,this.builder=new THREE.LoaderSupport.Builder(this.logger),this._createDefaultMaterials(),this.callbacks=new THREE.LoaderSupport.Callbacks}

LoaderBase.prototype._createDefaultMaterials = function (){var e=new THREE.MeshStandardMaterial({color:14479871});e.name="defaultMaterial";var t=new THREE.MeshStandardMaterial({color:14479871});t.name="vertexColorMaterial",t.vertexColors=THREE.VertexColors;var n={};n[e.name]=e,n[t.name]=t,this.builder.updateMaterials({cmd:"materialData",materials:{materialCloneInstructions:null,serializedMaterials:null,runtimeMaterials:n}})};

LoaderBase.prototype._applyPrepData = function (e){t.isValid(e)&&(this.setModelName(e.modelName),this.setStreamMeshesTo(e.streamMeshesTo),this.builder.setMaterials(e.materials),this.setUseIndices(e.useIndices),this.setDisregardNormals(e.disregardNormals),this._setCallbacks(e.getCallbacks()))};

LoaderBase.prototype._setCallbacks = function (e){t.isValid(e.onProgress)&&this.callbacks.setCallbackOnProgress(e.onProgress),t.isValid(e.onMeshAlter)&&this.callbacks.setCallbackOnMeshAlter(e.onMeshAlter),t.isValid(e.onLoad)&&this.callbacks.setCallbackOnLoad(e.onLoad),t.isValid(e.onLoadMaterials)&&this.callbacks.setCallbackOnLoadMaterials(e.onLoadMaterials),this.builder._setCallbacks(this.callbacks)};

LoaderBase.prototype.getLogger = function (){return this.logger};

LoaderBase.prototype.setModelName = function (e){this.modelName=t.verifyInput(e,this.modelName)};

LoaderBase.prototype.setPath = function (e){this.path=t.verifyInput(e,this.path)};

LoaderBase.prototype.setStreamMeshesTo = function (e){this.loaderRootNode=t.verifyInput(e,this.loaderRootNode)};

LoaderBase.prototype.setMaterials = function (e){this.builder.setMaterials(e)};

LoaderBase.prototype.setUseIndices = function (e){this.useIndices=e===!0};

LoaderBase.prototype.setDisregardNormals = function (e){this.disregardNormals=e===!0};

LoaderBase.prototype.onProgress = function (e,n,o){var a=t.isValid(n)?n:"",i={detail:{type:e,modelName:this.modelName,instanceNo:this.instanceNo,text:a,numericalValue:o}};t.isValid(this.callbacks.onProgress)&&this.callbacks.onProgress(i),this.logger.logDebug(a)};

return LoaderBase;

})();

Consts = {
CODE_LF: 10,
CODE_CR: 13,
CODE_SPACE: 32,
CODE_SLASH: 47,
STRING_LF: "\n",
STRING_CR: "\r",
STRING_SPACE: " ",
STRING_SLASH: "/",
LINE_F: "f",
LINE_G: "g",
LINE_L: "l",
LINE_O: "o",
LINE_S: "s",
LINE_V: "v",
LINE_VT: "vt",
LINE_VN: "vn",
LINE_MTLLIB: "mtllib",
LINE_USEMTL: "usemtl",
}

ParsParserr = (function () {

function e(e){this.callbackProgress=null,this.callbackBuilder=null,this.materials={},this.rawMesh=null,this.useAsync=!1,this.materialPerSmoothingGroup=!1,this.useIndices=!1,this.disregardNormals=!1,this.inputObjectCount=1,this.outputObjectCount=1,this.counts={vertices:0,faces:0,doubleIndicesCount:0},this.logger=e,this.totalBytes=0,this.reachedFaces=!1}

Parser.prototype.setUseAsync = function (e){this.useAsync=e};

Parser.prototype.setMaterialPerSmoothingGroup = function (e){this.materialPerSmoothingGroup=e};

Parser.prototype.setUseIndices = function (e){this.useIndices=e};

Parser.prototype.setDisregardNormals = function (e){this.disregardNormals=e};

Parser.prototype.setMaterials = function (e){this.materials=o.verifyInput(e,this.materials),this.materials=o.verifyInput(this.materials,{})};

Parser.prototype.setCallbackBuilder = function (e){if(this.callbackBuilder=e,!o.isValid(this.callbackBuilder))throw'Unable to run as no "builder" callback is set.'};

Parser.prototype.setCallbackProgress = function (e){this.callbackProgress=e};

Parser.prototype.configure = function (){if(this.rawMesh=new r(this.materialPerSmoothingGroup,this.useIndices,this.disregardNormals),this.logger.isEnabled()){var e=Object.keys(this.materials),t=e.length>0?"\n\tmaterialNames:\n\t\t- "+e.join("\n\t\t- "):"\n\tmaterialNames: None",n="OBJLoader2.Parser configuration:"+t+"\n\tuseAsync: "+this.useAsync+"\n\tmaterialPerSmoothingGroup: "+this.materialPerSmoothingGroup+"\n\tuseIndices: "+this.useIndices+"\n\tdisregardNormals: "+this.disregardNormals+"\n\tcallbackBuilderName: "+this.callbackBuilder.name+"\n\tcallbackProgressName: "+this.callbackProgress.name;this.logger.logInfo(n)}};

Parser.prototype.parse = function (e){this.logger.logTimeStart("OBJLoader2.Parser.parse"),this.configure();var t=new Uint8Array(e),n=t.byteLength;this.totalBytes=n;for(var o,i=new Array(128),r=0,s=new Array(16),l=0,c="",d=0;d<n;d++)switch(o=t[d]){case a.CODE_SPACE:c.length>0&&(i[r++]=c),s[l++]=0,c="";break;case a.CODE_SLASH:c.length>0&&(i[r++]=c),s[l++]=1,c="";break;case a.CODE_LF:c.length>0&&(i[r++]=c),c="",this.processLine(i,r,s,l,d),r=0,l=0;break;case a.CODE_CR:break;default:c+=String.fromCharCode(o)}this.finalize(d),this.logger.logTimeEnd("OBJLoader2.Parser.parse")};

Parser.prototype.parseText = function (e){this.logger.logTimeStart("OBJLoader2.Parser.parseText"),this.configure();var t=e.length;this.totalBytes=t;for(var n,o=new Array(128),i=0,r=new Array(16),s=0,l="",c=0;c<t;c++)switch(n=e[c]){case a.STRING_SPACE:l.length>0&&(o[i++]=l),r[s++]=0,l="";break;case a.STRING_SLASH:l.length>0&&(o[i++]=l),r[s++]=1,l="";break;case a.STRING_LF:l.length>0&&(o[i++]=l),l="",this.processLine(o,i,r,s,c),i=0,s=0;break;case a.STRING_CR:break;default:l+=n}this.finalize(c),this.logger.logTimeEnd("OBJLoader2.Parser.parseText")};

Parser.prototype.processLine = function (e,t,n,o,i){if(!(t<1)){var r=function(e,t){for(var n=0,o=0;o<t;o++)n+=e[o];return n},s=function(e,t,n){var o="";if(2===t)o=e[1];else{for(var a=t-1,i=1;i<a;i++)o+=e[i]+(0===n[i]?" ":"/");o+=e[a]}return o},l=function(e,t){for(var n=0;n<t;n++)e[n]=""};switch(e[0]){case a.LINE_V:if(this.reachedFaces){if(this.rawMesh.colors.length>0&&this.rawMesh.colors.length!==this.rawMesh.vertices.length)throw"Vertex Colors were detected, but vertex count and color count do not match!";this.processCompletedMesh(this.rawMesh.objectName,this.rawMesh.groupName,i,!0),this.reachedFaces=!1}4===t?this.rawMesh.pushVertex(e):this.rawMesh.pushVertexAndVertextColors(e);break;case a.LINE_VT:this.rawMesh.pushUv(e);break;case a.LINE_VN:this.rawMesh.pushNormal(e);break;case a.LINE_F:this.reachedFaces=!0,this.rawMesh.processFaces(e,t,r(n,o));break;case a.LINE_L:this.rawMesh.processLines(e,t,r(n,o));break;case a.LINE_S:this.rawMesh.pushSmoothingGroup(e[1]),l(e,t);break;case a.LINE_G:this.processCompletedMesh(this.rawMesh.objectName,s(e,t,n),i,!1),l(e,t);break;case a.LINE_O:this.processCompletedMesh(s(e,t,n),this.rawMesh.groupName,i,!1),l(e,t);break;case a.LINE_MTLLIB:this.rawMesh.pushMtllib(s(e,t,n)),l(e,t);break;case a.LINE_USEMTL:this.rawMesh.pushUsemtl(s(e,t,n)),l(e,t)}}};

Parser.prototype.createRawMeshReport = function (e,t){var n=e.createReport(t);return"Input Object number: "+t+"\n\tObject name: "+n.objectName+"\n\tGroup name: "+n.groupName+"\n\tMtllib name: "+n.mtllibName+"\n\tVertex count: "+n.vertexCount+"\n\tNormal count: "+n.normalCount+"\n\tUV count: "+n.uvCount+"\n\tSmoothingGroup count: "+n.smoothingGroupCount+"\n\tMaterial count: "+n.mtlCount+"\n\tReal RawMeshSubGroup count: "+n.subGroups};

Parser.prototype.processCompletedMesh = function (e,t,n,a){var i=this.rawMesh.finalize();if(o.isValid(i)){this.inputObjectCount++,this.logger.isDebug()&&this.logger.logDebug(this.createRawMeshReport(this.rawMesh,this.inputObjectCount)),this.buildMesh(i,n);var r=n/this.totalBytes;this.callbackProgress("Completed [o: "+this.rawMesh.objectName+" g:"+this.rawMesh.groupName+"] Total progress: "+(100*r).toFixed(2)+"%",r),this.rawMesh=a?this.rawMesh.newInstanceResetOffsets():this.rawMesh.newInstanceKeepOffsets()}this.rawMesh.objectName!==e&&o.isValid(e)&&this.rawMesh.pushObject(e),this.rawMesh.groupName!==t&&o.isValid(t)&&this.rawMesh.pushGroup(t)};

Parser.prototype.finalize = function (e){this.logger.logInfo("Global output object count: "+this.outputObjectCount);var t=o.isValid(this.rawMesh)?this.rawMesh.finalize():null;if(o.isValid(t)){if(this.inputObjectCount++,this.logger.isDebug()&&this.logger.logDebug(this.createRawMeshReport(this.rawMesh,this.inputObjectCount)),this.buildMesh(t,e),this.logger.isEnabled()){var n="Overall counts: \n\tVertices: "+this.counts.vertices+"\n\tFaces: "+this.counts.faces+"\n\tMultiple definitions: "+this.counts.doubleIndicesCount;this.logger.logInfo(n)}var a=e/this.totalBytes;this.callbackProgress("Completed Parsing: 100.00%",a)}};

Parser.prototype.buildMesh = function (e,t){var n=e.subGroups,a=new Float32Array(e.absoluteVertexCount);this.counts.vertices+=e.absoluteVertexCount/3,this.counts.faces+=e.faceCount,this.counts.doubleIndicesCount+=e.doubleIndicesCount;var i,r,s,l,c,d,u,h=e.absoluteIndexCount>0?new Uint32Array(e.absoluteIndexCount):null,p=e.absoluteColorCount>0?new Float32Array(e.absoluteColorCount):null,m=e.absoluteNormalCount>0?new Float32Array(e.absoluteNormalCount):null,f=e.absoluteUvCount>0?new Float32Array(e.absoluteUvCount):null,g=o.isValid(p),v=[],E=n.length>1,b=0,y=[],w=[],T=0,M=0,R=0,H=0,x=0,k=0,L=0;for(var S in n)if(n.hasOwnProperty(S)){if(i=n[S],u=i.materialName,d=u+(g?"_vertexColor":"")+(0===i.smoothingGroup?"_flat":""),l=this.materials[u],c=this.materials[d],!o.isValid(l)&&!o.isValid(c)){var I=g?"vertexColorMaterial":"defaultMaterial";l=this.materials[I],this.logger.logWarn('object_group "'+i.objectName+"_"+i.groupName+'" was defined with unresolvable material "'+u+'"! Assigning "'+I+'".'),u=I,u===d&&(c=l,d=I)}if(!o.isValid(c)){var P={materialNameOrg:u,materialName:d,materialProperties:{vertexColors:g?2:0,flatShading:0===i.smoothingGroup}},C={cmd:"materialData",materials:{materialCloneInstructions:P}};this.callbackBuilder(C),this.useAsync&&(this.materials[d]=P)}if(E?(r=y[d],r||(r=b,y[d]=b,v.push(d),b++),L=this.useIndices?i.indices.length:i.vertices.length/3,s={start:k,count:L,index:r},w.push(s),k+=L):v.push(d),a.set(i.vertices,T),T+=i.vertices.length,h&&(h.set(i.indices,M),M+=i.indices.length),p&&(p.set(i.colors,R),R+=i.colors.length),m&&(m.set(i.normals,H),H+=i.normals.length),f&&(f.set(i.uvs,x),x+=i.uvs.length),this.logger.isDebug()){var A=o.isValid(r)?"\n\t\tmaterialIndex: "+r:"",B="Output Object no.: "+this.outputObjectCount+"\n\t\tobjectName: "+i.objectName+"\n\t\tgroupName: "+i.groupName+"\n\t\tmaterialName: "+i.materialName+A+"\n\t\tsmoothingGroup: "+i.smoothingGroup+"\n\t\t#vertices: "+i.vertices.length/3+"\n\t\t#indices: "+i.indices.length+"\n\t\t#colors: "+i.colors.length/3+"\n\t\t#uvs: "+i.uvs.length/2+"\n\t\t#normals: "+i.normals.length/3;this.logger.logDebug(B)}}this.outputObjectCount++,this.callbackBuilder({cmd:"meshData",progress:{numericalValue:t/this.totalBytes},params:{meshName:e.name},materials:{multiMaterial:E,materialNames:v,materialGroups:w},buffers:{vertices:a,indices:h,colors:p,normals:m,uvs:f}},[a.buffer],o.isValid(h)?[h.buffer]:null,o.isValid(p)?[p.buffer]:null,o.isValid(m)?[m.buffer]:null,o.isValid(f)?[f.buffer]:null)};

return Parser;

})();

RawMRawMeshsh = (function () {

function e(e,t,n,a){this.globalVertexOffset=1,this.globalUvOffset=1,this.globalNormalOffset=1,this.vertices=[],this.colors=[],this.normals=[],this.uvs=[],this.activeMtlName=o.verifyInput(a,""),this.objectName="",this.groupName="",this.mtllibName="",this.smoothingGroup={splitMaterials:e===!0,normalized:-1,real:-1},this.useIndices=t===!0,this.disregardNormals=n===!0,this.mtlCount=0,this.smoothingGroupCount=0,this.subGroups=[],this.subGroupInUse=null,this.pushSmoothingGroup(1),this.doubleIndicesCount=0,this.faceCount=0}

RawMesh.prototype.newInstanceResetOffsets = function (){var t=new e(this.smoothingGroup.splitMaterials,this.useIndices,this.disregardNormals,this.activeMtlName);return t.globalVertexOffset=this.globalVertexOffset+this.vertices.length/3,t.globalUvOffset=this.globalUvOffset+this.uvs.length/2,t.globalNormalOffset=this.globalNormalOffset+this.normals.length/3,t};

RawMesh.prototype.newInstanceKeepOffsets = function (){var t=new e(this.smoothingGroup.splitMaterials,this.useIndices,this.disregardNormals,this.activeMtlName);return t.pushObject(this.objectName),t.vertices=this.vertices,t.colors=this.colors,t.uvs=this.uvs,t.normals=this.normals,t.globalVertexOffset=this.globalVertexOffset,t.globalUvOffset=this.globalUvOffset,t.globalNormalOffset=this.globalNormalOffset,t};

RawMesh.prototype.pushVertex = function (e){this.vertices.push(parseFloat(e[1])),this.vertices.push(parseFloat(e[2])),this.vertices.push(parseFloat(e[3]))};

RawMesh.prototype.pushVertexAndVertextColors = function (e){this.vertices.push(parseFloat(e[1])),this.vertices.push(parseFloat(e[2])),this.vertices.push(parseFloat(e[3])),this.colors.push(parseFloat(e[4])),this.colors.push(parseFloat(e[5])),this.colors.push(parseFloat(e[6]))};

RawMesh.prototype.pushUv = function (e){this.uvs.push(parseFloat(e[1])),this.uvs.push(parseFloat(e[2]))};

RawMesh.prototype.pushNormal = function (e){this.normals.push(parseFloat(e[1])),this.normals.push(parseFloat(e[2])),this.normals.push(parseFloat(e[3]))};

RawMesh.prototype.pushObject = function (e){this.objectName=o.verifyInput(e,"")};

RawMesh.prototype.pushMtllib = function (e){this.mtllibName=o.verifyInput(e,"")};

RawMesh.prototype.pushGroup = function (e){this.groupName=o.verifyInput(e,"")};

RawMesh.prototype.pushUsemtl = function (e){this.activeMtlName!==e&&o.isValid(e)&&(this.activeMtlName=e,this.mtlCount++,this.verifyIndex())};

RawMesh.prototype.pushSmoothingGroup = function (e){var t=parseInt(e);isNaN(t)&&(t="off"===e?0:1);var n=this.smoothingGroup.normalized;this.smoothingGroup.normalized=this.smoothingGroup.splitMaterials?t:0===t?0:1,this.smoothingGroup.real=t,n!==t&&(this.smoothingGroupCount++,this.verifyIndex())};

RawMesh.prototype.verifyIndex = function (){var e=this.activeMtlName+"|"+this.smoothingGroup.normalized;this.subGroupInUse=this.subGroups[e],o.isValid(this.subGroupInUse)||(this.subGroupInUse=new s(this.objectName,this.groupName,this.activeMtlName,this.smoothingGroup.normalized),this.subGroups[e]=this.subGroupInUse)};

RawMesh.prototype.processFaces = function (e,t,n){var o,a,i=t-1;if(0===n)for(o=2,a=i-1;o<a;o++)this.buildFace(e[1]),this.buildFace(e[o]),this.buildFace(e[o+1]);else if(i===2*n)for(o=3,a=i-2;o<a;o+=2)this.buildFace(e[1],e[2]),this.buildFace(e[o],e[o+1]),this.buildFace(e[o+2],e[o+3]);else if(2*i===3*n)for(o=4,a=i-3;o<a;o+=3)this.buildFace(e[1],e[2],e[3]),this.buildFace(e[o],e[o+1],e[o+2]),this.buildFace(e[o+3],e[o+4],e[o+5]);else for(o=3,a=i-2;o<a;o+=2)this.buildFace(e[1],void 0,e[2]),this.buildFace(e[o],void 0,e[o+1]),this.buildFace(e[o+2],void 0,e[o+3])};

RawMesh.prototype.buildFace = function (e,t,n){var a=this.subGroupInUse;this.disregardNormals&&(n=void 0);var i=this,r=function(){var o=3*(parseInt(e)-i.globalVertexOffset),r=i.colors.length>0?o:null,s=a.vertices;if(s.push(i.vertices[o++]),s.push(i.vertices[o++]),s.push(i.vertices[o]),null!==r){var l=a.colors;l.push(i.colors[r++]),l.push(i.colors[r++]),l.push(i.colors[r])}if(t){var c=2*(parseInt(t)-i.globalUvOffset),d=a.uvs;d.push(i.uvs[c++]),d.push(i.uvs[c])}if(n){var u=3*(parseInt(n)-i.globalNormalOffset),h=a.normals;h.push(i.normals[u++]),h.push(i.normals[u++]),h.push(i.normals[u])}};if(this.useIndices){var s=e+(t?"_"+t:"_n")+(n?"_"+n:"_n"),l=a.indexMappings[s];o.isValid(l)?this.doubleIndicesCount++:(l=a.vertices.length/3,r(),a.indexMappings[s]=l,a.indexMappingsCount++),a.indices.push(l)}else r();this.faceCount++};

RawMesh.prototype.processLines = function (e,t,n){var o,a=1,i=t-1;if(i===2*n)for(o=i-2;a<o;a+=2)this.vertices.push(parseInt(e[a])),this.uvs.push(parseInt(e[a+1]));else for(o=i-1;a<o;a++)this.vertices.push(parseInt(e[a]))};

RawMesh.prototype.finalize = function (){var e,t,n=[],o=0,a=0,i=0,r=0,s=0,l=0;for(var c in this.subGroups)if(e=this.subGroups[c],e.vertices.length>0){if(t=e.indices,t.length>0&&a>0)for(var d in t)t[d]=t[d]+a;n.push(e),o+=e.vertices.length,a+=e.indexMappingsCount,i+=e.indices.length,r+=e.colors.length,l+=e.uvs.length,s+=e.normals.length}var u=null;return n.length>0&&(u={name:""!==this.groupName?this.groupName:this.objectName,subGroups:n,absoluteVertexCount:o,absoluteIndexCount:i,absoluteColorCount:r,absoluteNormalCount:s,absoluteUvCount:l,faceCount:this.faceCount,doubleIndicesCount:this.doubleIndicesCount}),u};

RawMesh.prototype.createReport = function (){var e={objectName:this.objectName,groupName:this.groupName,mtllibName:this.mtllibName,vertexCount:this.vertices.length/3,normalCount:this.normals.length/3,uvCount:this.uvs.length/2,smoothingGroupCount:this.smoothingGroupCount,mtlCount:this.mtlCount,subGroups:this.subGroups.length};return e};

return RawMesh;

})();

RawMRawMeshSubGroupshSubGroup = (function () {

function e(e,t,n,o){this.objectName=e,this.groupName=t,this.materialName=n,this.smoothingGroup=o,this._init()}

RawMeshSubGroup.prototype._init = function (){this.vertices=[],this.indexMappingsCount=0,this.indexMappings=[],this.indices=[],this.colors=[],this.uvs=[],this.normals=[]};

return RawMeshSubGroup;

})();

e = (function () {

function e(){var e=this,t=function(t){e.processMessage(t.data)};self.addEventListener("message",t,!1)}

e.prototype.applyProperties = function (e,t){var n,o,a;for(n in t)o="set"+n.substring(0,1).toLocaleUpperCase()+n.substring(1),a=t[n],"function"==typeof e[o]?e[o](a):e.hasOwnProperty(n)&&(e[n]=a)};

e.prototype.processMessage = function (e){var t=new ConsoleLogger;if(Validator.isValid(e.logger)&&(t.setEnabled(e.logger.enabled),t.setDebug(e.logger.debug)),"run"===e.cmd){var n={callbackBuilder:function(e){self.postMessage(e)},callbackProgress:function(e){t.logDebug("WorkerRunner: progress: "+e)}},o=new Parser(t);this.applyProperties(o,e.params),this.applyProperties(o,e.materials),this.applyProperties(o,n),o.workerScope=self,o.parse(e.data.input,e.data.options),t.logInfo("WorkerRunner: Run complete!"),n.callbackBuilder({cmd:"complete",msg:"WorkerRunner completed run."})}else t.logError("WorkerRunner: Received unknown command: "+e.cmd)};

return e;

})();

new e();



This is what the same exfiltration from non minified code looks like

Validator = {
isValid: function ( input ) {
return ( input !== null && input !== undefined );
},
verifyInput: function ( input, defaultValue ) {
return ( input === null || input === undefined ) ? defaultValue : input;
},
}

ConsoleLogger = (function () {

function ConsoleLogger( enabled, debug ) {
	this.enabled = enabled !== false;
	this.debug = debug === true;
}

ConsoleLogger.prototype.setDebug = function ( debug ) {
	this.debug = debug === true;
};

ConsoleLogger.prototype.isDebug = function () {
	return this.isEnabled() && this.debug;
};

ConsoleLogger.prototype.setEnabled = function ( enabled ) {
	this.enabled = enabled === true;
};

ConsoleLogger.prototype.isEnabled = function () {
	return this.enabled;
};

ConsoleLogger.prototype.logDebug = function ( message ) {
	if ( this.enabled && this.debug ) console.info( message );
};

ConsoleLogger.prototype.logInfo = function ( message ) {
	if ( this.enabled ) console.info( message );
};

ConsoleLogger.prototype.logWarn = function ( message ) {
	console.warn( message );
};

ConsoleLogger.prototype.logError = function ( message ) {
	console.error( message );
};

ConsoleLogger.prototype.logTimeStart = function ( id ) {
	if ( this.enabled ) console.time( id );
};

ConsoleLogger.prototype.logTimeEnd = function ( id ) {
	if ( this.enabled ) console.timeEnd( id );
};

return ConsoleLogger;

})();

/**

  • This code was constructed by OBJLoader2 buildCode.
    */

LoaderBase = (function () {

function LoaderBase( manager, logger ) {
	this.manager = Validator.verifyInput( manager, THREE.DefaultLoadingManager );
	this.logger = Validator.verifyInput( logger, new ConsoleLogger() );

	this.modelName = '';
	this.instanceNo = 0;
	this.path = '';
	this.useIndices = false;
	this.disregardNormals = false;

	this.loaderRootNode = new THREE.Group();
	this.builder = new THREE.LoaderSupport.Builder( this.logger );
	this._createDefaultMaterials();
	this.callbacks = new THREE.LoaderSupport.Callbacks();
}

LoaderBase.prototype._createDefaultMaterials = function () {
	var defaultMaterial = new THREE.MeshStandardMaterial( { color: 0xDCF1FF } );
	defaultMaterial.name = 'defaultMaterial';

	var vertexColorMaterial = new THREE.MeshStandardMaterial( { color: 0xDCF1FF } );
	vertexColorMaterial.name = 'vertexColorMaterial';
	vertexColorMaterial.vertexColors = THREE.VertexColors;

	var runtimeMaterials = {};
	runtimeMaterials[ defaultMaterial.name ] = defaultMaterial;
	runtimeMaterials[ vertexColorMaterial.name ] = vertexColorMaterial;

	this.builder.updateMaterials(
		{
			cmd: 'materialData',
			materials: {
				materialCloneInstructions: null,
				serializedMaterials: null,
				runtimeMaterials: runtimeMaterials
			}
		}
	);
};

LoaderBase.prototype._applyPrepData = function ( prepData ) {
	if ( Validator.isValid( prepData ) ) {

		this.setModelName( prepData.modelName );
		this.setStreamMeshesTo( prepData.streamMeshesTo );
		this.builder.setMaterials( prepData.materials );
		this.setUseIndices( prepData.useIndices );
		this.setDisregardNormals( prepData.disregardNormals );

		this._setCallbacks( prepData.getCallbacks() );
	}
};

LoaderBase.prototype._setCallbacks = function ( callbacks ) {
	if ( Validator.isValid( callbacks.onProgress ) ) this.callbacks.setCallbackOnProgress( callbacks.onProgress );
	if ( Validator.isValid( callbacks.onMeshAlter ) ) this.callbacks.setCallbackOnMeshAlter( callbacks.onMeshAlter );
	if ( Validator.isValid( callbacks.onLoad ) ) this.callbacks.setCallbackOnLoad( callbacks.onLoad );
	if ( Validator.isValid( callbacks.onLoadMaterials ) ) this.callbacks.setCallbackOnLoadMaterials( callbacks.onLoadMaterials );

	this.builder._setCallbacks( this.callbacks );
};

LoaderBase.prototype.getLogger = function () {
	return this.logger;
};

LoaderBase.prototype.setModelName = function ( modelName ) {
	this.modelName = Validator.verifyInput( modelName, this.modelName );
};

LoaderBase.prototype.setPath = function ( path ) {
	this.path = Validator.verifyInput( path, this.path );
};

LoaderBase.prototype.setStreamMeshesTo = function ( streamMeshesTo ) {
	this.loaderRootNode = Validator.verifyInput( streamMeshesTo, this.loaderRootNode );
};

LoaderBase.prototype.setMaterials = function ( materials ) {
	this.builder.setMaterials( materials );
};

LoaderBase.prototype.setUseIndices = function ( useIndices ) {
	this.useIndices = useIndices === true;
};

LoaderBase.prototype.setDisregardNormals = function ( disregardNormals ) {
	this.disregardNormals = disregardNormals === true;
};

LoaderBase.prototype.onProgress = function ( type, text, numericalValue ) {
	var content = Validator.isValid( text ) ? text: '';
	var event = {
		detail: {
			type: type,
			modelName: this.modelName,
			instanceNo: this.instanceNo,
			text: content,
			numericalValue: numericalValue
		}
	};

	if ( Validator.isValid( this.callbacks.onProgress ) ) this.callbacks.onProgress( event );

	this.logger.logDebug( content );
};

return LoaderBase;

})();

Consts = {
CODE_LF: 10,
CODE_CR: 13,
CODE_SPACE: 32,
CODE_SLASH: 47,
STRING_LF: "\n",
STRING_CR: "\r",
STRING_SPACE: " ",
STRING_SLASH: "/",
LINE_F: "f",
LINE_G: "g",
LINE_L: "l",
LINE_O: "o",
LINE_S: "s",
LINE_V: "v",
LINE_VT: "vt",
LINE_VN: "vn",
LINE_MTLLIB: "mtllib",
LINE_USEMTL: "usemtl",
}

Parser = (function () {

function Parser( logger ) {
		this.callbackProgress = null;
		this.callbackBuilder = null;

		this.materials = {};
		this.rawMesh = null;
		this.useAsync = false;
		this.materialPerSmoothingGroup = false;
		this.useIndices = false;
		this.disregardNormals = false;

		this.inputObjectCount = 1;
		this.outputObjectCount = 1;
		this.counts = {
			vertices: 0,
			faces: 0,
			doubleIndicesCount: 0
		};
		this.logger = logger;
		this.totalBytes = 0;
		this.reachedFaces = false;
	}

Parser.prototype.setUseAsync = function ( useAsync ) {
		this.useAsync = useAsync;
	};

Parser.prototype.setMaterialPerSmoothingGroup = function ( materialPerSmoothingGroup ) {
		this.materialPerSmoothingGroup = materialPerSmoothingGroup;
	};

Parser.prototype.setUseIndices = function ( useIndices ) {
		this.useIndices = useIndices;
	};

Parser.prototype.setDisregardNormals = function ( disregardNormals ) {
		this.disregardNormals = disregardNormals;
	};

Parser.prototype.setMaterials = function ( materials ) {
		this.materials = Validator.verifyInput( materials, this.materials );
		this.materials = Validator.verifyInput( this.materials, {} );
	};

Parser.prototype.setCallbackBuilder = function ( callbackBuilder ) {
		this.callbackBuilder = callbackBuilder;
		if ( ! Validator.isValid( this.callbackBuilder ) ) throw 'Unable to run as no "builder" callback is set.';
	};

Parser.prototype.setCallbackProgress = function ( callbackProgress ) {
		this.callbackProgress = callbackProgress;
	};

Parser.prototype.configure = function () {
		this.rawMesh = new RawMesh( this.materialPerSmoothingGroup, this.useIndices, this.disregardNormals );

		if ( this.logger.isEnabled() ) {

			var matKeys = Object.keys( this.materials );
			var matNames = ( matKeys.length > 0 ) ? '\n\tmaterialNames:\n\t\t- ' + matKeys.join( '\n\t\t- ' ) : '\n\tmaterialNames: None';
			var printedConfig = 'OBJLoader2.Parser configuration:'
					+ matNames
					+ '\n\tuseAsync: ' + this.useAsync
					+ '\n\tmaterialPerSmoothingGroup: ' + this.materialPerSmoothingGroup
					+ '\n\tuseIndices: ' + this.useIndices
					+ '\n\tdisregardNormals: ' + this.disregardNormals
					+ '\n\tcallbackBuilderName: ' + this.callbackBuilder.name
					+ '\n\tcallbackProgressName: ' + this.callbackProgress.name;
			this.logger.logInfo( printedConfig );
		}
	};

Parser.prototype.parse = function ( arrayBuffer ) {
		this.logger.logTimeStart( 'OBJLoader2.Parser.parse' );
		this.configure();

		var arrayBufferView = new Uint8Array( arrayBuffer );
		var length = arrayBufferView.byteLength;
		this.totalBytes = length;
		var buffer = new Array( 128 );
		var bufferPointer = 0;
		var slashSpacePattern = new Array( 16 );
		var slashSpacePatternPointer = 0;
		var code;
		var word = '';
		var i = 0;
		for ( ; i < length; i++ ) {

			code = arrayBufferView[ i ];
			switch ( code ) {
				case Consts.CODE_SPACE:
					if ( word.length > 0 ) buffer[ bufferPointer++ ] = word;
					slashSpacePattern[ slashSpacePatternPointer++ ] = 0;
					word = '';
					break;

				case Consts.CODE_SLASH:
					if ( word.length > 0 ) buffer[ bufferPointer++ ] = word;
					slashSpacePattern[ slashSpacePatternPointer++ ] = 1;
					word = '';
					break;

				case Consts.CODE_LF:
					if ( word.length > 0 ) buffer[ bufferPointer++ ] = word;
					word = '';
					this.processLine( buffer, bufferPointer, slashSpacePattern, slashSpacePatternPointer, i );
					bufferPointer = 0;
					slashSpacePatternPointer = 0;
					break;

				case Consts.CODE_CR:
					break;

				default:
					word += String.fromCharCode( code );
					break;
			}
		}
		this.finalize( i );
		this.logger.logTimeEnd( 'OBJLoader2.Parser.parse' );
	};

Parser.prototype.parseText = function ( text ) {
		this.logger.logTimeStart( 'OBJLoader2.Parser.parseText' );
		this.configure();

		var length = text.length;
		this.totalBytes = length;
		var buffer = new Array( 128 );
		var bufferPointer = 0;
		var slashSpacePattern = new Array( 16 );
		var slashSpacePatternPointer = 0;
		var char;
		var word = '';
		var i = 0;
		for ( ; i < length; i++ ) {

			char = text[ i ];
			switch ( char ) {
				case Consts.STRING_SPACE:
					if ( word.length > 0 ) buffer[ bufferPointer++ ] = word;
					slashSpacePattern[ slashSpacePatternPointer++ ] = 0;
					word = '';
					break;

				case Consts.STRING_SLASH:
					if ( word.length > 0 ) buffer[ bufferPointer++ ] = word;
					slashSpacePattern[ slashSpacePatternPointer++ ] = 1;
					word = '';
					break;

				case Consts.STRING_LF:
					if ( word.length > 0 ) buffer[ bufferPointer++ ] = word;
					word = '';
					this.processLine( buffer, bufferPointer, slashSpacePattern, slashSpacePatternPointer, i );
					bufferPointer = 0;
					slashSpacePatternPointer = 0;
					break;

				case Consts.STRING_CR:
					break;

				default:
					word += char;
			}
		}
		this.finalize( i );
		this.logger.logTimeEnd( 'OBJLoader2.Parser.parseText' );
	};

Parser.prototype.processLine = function ( buffer, bufferPointer, slashSpacePattern, slashSpacePatternPointer, currentByte ) {
		if ( bufferPointer < 1 ) return;

		var countSlashes = function ( slashSpacePattern, slashSpacePatternPointer ) {
			var slashesCount = 0;
			for ( var i = 0; i < slashSpacePatternPointer; i++ ) {
				slashesCount += slashSpacePattern[ i ];
			}
			return slashesCount;
		};

		var concatStringBuffer = function ( buffer, bufferPointer, slashSpacePattern ) {
			var concatBuffer = '';
			if ( bufferPointer === 2 ) {

				concatBuffer = buffer[ 1 ];

			} else {

				var bufferLength = bufferPointer - 1;
				for ( var i = 1; i < bufferLength; i++ ) {

					concatBuffer += buffer[ i ] + ( slashSpacePattern[ i ] === 0 ? ' ' : '/' );

				}
				concatBuffer += buffer[ bufferLength ];

			}
			return concatBuffer;
		};

		var flushStringBuffer = function ( buffer, bufferPointer ) {
			for ( var i = 0; i < bufferPointer; i++ ) {
				buffer[ i ] = '';
			}
		};

		switch ( buffer[ 0 ] ) {
			case Consts.LINE_V:
				// object complete instance required if reached faces already (= reached next block of v)
				if ( this.reachedFaces ) {

					if ( this.rawMesh.colors.length > 0 && this.rawMesh.colors.length !== this.rawMesh.vertices.length ) {

						throw 'Vertex Colors were detected, but vertex count and color count do not match!';

					}
					// only when new vertices after faces are detected complete new mesh is prepared (reset offsets, etc)
					this.processCompletedMesh( this.rawMesh.objectName, this.rawMesh.groupName, currentByte, true );
					this.reachedFaces = false;

				}
				if ( bufferPointer === 4 ) {

					this.rawMesh.pushVertex( buffer )

				} else {

					this.rawMesh.pushVertexAndVertextColors( buffer );

				}
				break;

			case Consts.LINE_VT:
				this.rawMesh.pushUv( buffer );
				break;

			case Consts.LINE_VN:
				this.rawMesh.pushNormal( buffer );
				break;

			case Consts.LINE_F:
				this.reachedFaces = true;
				this.rawMesh.processFaces( buffer, bufferPointer, countSlashes( slashSpacePattern, slashSpacePatternPointer ) );
				break;

			case Consts.LINE_L:
				this.rawMesh.processLines( buffer, bufferPointer, countSlashes( slashSpacePattern, slashSpacePatternPointer ) );
				break;

			case Consts.LINE_S:
				this.rawMesh.pushSmoothingGroup( buffer[ 1 ] );
				flushStringBuffer( buffer, bufferPointer );
				break;

			case Consts.LINE_G:
				this.processCompletedMesh( this.rawMesh.objectName, concatStringBuffer( buffer, bufferPointer, slashSpacePattern ), currentByte, false );
				flushStringBuffer( buffer, bufferPointer );
				break;

			case Consts.LINE_O:
				this.processCompletedMesh( concatStringBuffer( buffer, bufferPointer, slashSpacePattern ), this.rawMesh.groupName, currentByte, false );
				flushStringBuffer( buffer, bufferPointer );
				break;

			case Consts.LINE_MTLLIB:
				this.rawMesh.pushMtllib( concatStringBuffer( buffer, bufferPointer, slashSpacePattern ) );
				flushStringBuffer( buffer, bufferPointer );
				break;

			case Consts.LINE_USEMTL:
				this.rawMesh.pushUsemtl( concatStringBuffer( buffer, bufferPointer, slashSpacePattern ) );
				flushStringBuffer( buffer, bufferPointer );
				break;

			default:
				break;
		}
	};

Parser.prototype.createRawMeshReport = function ( rawMesh , inputObjectCount ) {
		var report = rawMesh.createReport( inputObjectCount );
		return 'Input Object number: ' + inputObjectCount +
			'\n\tObject name: ' + report.objectName +
			'\n\tGroup name: ' + report.groupName +
			'\n\tMtllib name: ' + report.mtllibName +
			'\n\tVertex count: ' + report.vertexCount +
			'\n\tNormal count: ' + report.normalCount +
			'\n\tUV count: ' + report.uvCount +
			'\n\tSmoothingGroup count: ' + report.smoothingGroupCount +
			'\n\tMaterial count: ' + report.mtlCount +
			'\n\tReal RawMeshSubGroup count: ' + report.subGroups;
	};

Parser.prototype.processCompletedMesh = function ( objectName, groupName, currentByte, beginNewObject ) {
		var result = this.rawMesh.finalize();
		if ( Validator.isValid( result ) ) {

			this.inputObjectCount++;
			if ( this.logger.isDebug() ) this.logger.logDebug( this.createRawMeshReport( this.rawMesh, this.inputObjectCount ) );
			this.buildMesh( result, currentByte );
			var progressBytesPercent = currentByte / this.totalBytes;
			this.callbackProgress( 'Completed [o: ' + this.rawMesh.objectName + ' g:' + this.rawMesh.groupName + '] Total progress: ' + ( progressBytesPercent * 100 ).toFixed( 2 ) + '%', progressBytesPercent );
			this.rawMesh = beginNewObject ? this.rawMesh.newInstanceResetOffsets() : this.rawMesh.newInstanceKeepOffsets();

		}
		// Always update group an object name in case they have changed and are valid
		if ( this.rawMesh.objectName !== objectName && Validator.isValid( objectName ) ) this.rawMesh.pushObject( objectName );
		if ( this.rawMesh.groupName !== groupName && Validator.isValid( groupName ) ) this.rawMesh.pushGroup( groupName );
	};

Parser.prototype.finalize = function ( currentByte ) {
		this.logger.logInfo( 'Global output object count: ' + this.outputObjectCount );
		var result = Validator.isValid( this.rawMesh ) ? this.rawMesh.finalize() : null;
		if ( Validator.isValid( result ) ) {

			this.inputObjectCount++;
			if ( this.logger.isDebug() ) this.logger.logDebug( this.createRawMeshReport( this.rawMesh, this.inputObjectCount ) );
			this.buildMesh( result, currentByte );

			if ( this.logger.isEnabled() ) {

				var parserFinalReport = 'Overall counts: ' +
					'\n\tVertices: ' + this.counts.vertices +
					'\n\tFaces: ' + this.counts.faces +
					'\n\tMultiple definitions: ' + this.counts.doubleIndicesCount;
				this.logger.logInfo( parserFinalReport );

			}
			var progressBytesPercent = currentByte / this.totalBytes;
			this.callbackProgress( 'Completed Parsing: 100.00%', progressBytesPercent );

		}
	};

Parser.prototype.buildMesh = function ( result, currentByte ) {
		var rawObjectDescriptions = result.subGroups;

		var vertexFA = new Float32Array( result.absoluteVertexCount );
		this.counts.vertices += result.absoluteVertexCount / 3;
		this.counts.faces += result.faceCount;
		this.counts.doubleIndicesCount += result.doubleIndicesCount;
		var indexUA = ( result.absoluteIndexCount > 0 ) ? new Uint32Array( result.absoluteIndexCount ) : null;
		var colorFA = ( result.absoluteColorCount > 0 ) ? new Float32Array( result.absoluteColorCount ) : null;
		var normalFA = ( result.absoluteNormalCount > 0 ) ? new Float32Array( result.absoluteNormalCount ) : null;
		var uvFA = ( result.absoluteUvCount > 0 ) ? new Float32Array( result.absoluteUvCount ) : null;
		var haveVertexColors = Validator.isValid( colorFA );

		var rawObjectDescription;
		var materialNames = [];

		var createMultiMaterial = ( rawObjectDescriptions.length > 1 );
		var materialIndex = 0;
		var materialIndexMapping = [];
		var selectedMaterialIndex;
		var materialGroup;
		var materialGroups = [];

		var vertexFAOffset = 0;
		var indexUAOffset = 0;
		var colorFAOffset = 0;
		var normalFAOffset = 0;
		var uvFAOffset = 0;
		var materialGroupOffset = 0;
		var materialGroupLength = 0;

		var materialOrg, material, materialName, materialNameOrg;
		for ( var oodIndex in rawObjectDescriptions ) {

			if ( ! rawObjectDescriptions.hasOwnProperty( oodIndex ) ) continue;
			rawObjectDescription = rawObjectDescriptions[ oodIndex ];

			materialNameOrg = rawObjectDescription.materialName;
			materialName = materialNameOrg + ( haveVertexColors ? '_vertexColor' : '' ) + ( rawObjectDescription.smoothingGroup === 0 ? '_flat' : '' );
			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 ( ! Validator.isValid( materialOrg ) && ! Validator.isValid( material ) ) {

				var defaultMaterialName = haveVertexColors ? 'vertexColorMaterial' : 'defaultMaterial';
				materialOrg = this.materials[ defaultMaterialName ];
				this.logger.logWarn( 'object_group "' + rawObjectDescription.objectName + '_' +
					rawObjectDescription.groupName + '" was defined with unresolvable material "' +
					materialNameOrg + '"! Assigning "' + defaultMaterialName + '".' );
				materialNameOrg = defaultMaterialName;

				// if names are identical then there is no need for later manipulation
				if ( materialNameOrg === materialName ) {

					material = materialOrg;
					materialName = defaultMaterialName;

				}

			}
			if ( ! Validator.isValid( material ) ) {

				var materialCloneInstructions = {
					materialNameOrg: materialNameOrg,
					materialName: materialName,
					materialProperties: {
						vertexColors: haveVertexColors ? 2 : 0,
						flatShading: rawObjectDescription.smoothingGroup === 0
					}
				};
				var payload = {
					cmd: 'materialData',
					materials: {
						materialCloneInstructions: materialCloneInstructions
					}
				};
				this.callbackBuilder( payload );

				// fake entry for async; sync Parser always works on material references (Builder update directly visible here)
				if ( this.useAsync ) this.materials[ materialName ] = materialCloneInstructions;

			}

			if ( createMultiMaterial ) {

				// re-use material if already used before. Reduces materials array size and eliminates duplicates
				selectedMaterialIndex = materialIndexMapping[ materialName ];
				if ( ! selectedMaterialIndex ) {

					selectedMaterialIndex = materialIndex;
					materialIndexMapping[ materialName ] = materialIndex;
					materialNames.push( materialName );
					materialIndex++;

				}
				materialGroupLength = this.useIndices ? rawObjectDescription.indices.length : rawObjectDescription.vertices.length / 3;
				materialGroup = {
					start: materialGroupOffset,
					count: materialGroupLength,
					index: selectedMaterialIndex
				};
				materialGroups.push( materialGroup );
				materialGroupOffset += materialGroupLength;

			} else {

				materialNames.push( materialName );

			}

			vertexFA.set( rawObjectDescription.vertices, vertexFAOffset );
			vertexFAOffset += rawObjectDescription.vertices.length;

			if ( indexUA ) {

				indexUA.set( rawObjectDescription.indices, indexUAOffset );
				indexUAOffset += rawObjectDescription.indices.length;

			}

			if ( colorFA ) {

				colorFA.set( rawObjectDescription.colors, colorFAOffset );
				colorFAOffset += rawObjectDescription.colors.length;

			}

			if ( normalFA ) {

				normalFA.set( rawObjectDescription.normals, normalFAOffset );
				normalFAOffset += rawObjectDescription.normals.length;

			}
			if ( uvFA ) {

				uvFA.set( rawObjectDescription.uvs, uvFAOffset );
				uvFAOffset += rawObjectDescription.uvs.length;

			}

			if ( this.logger.isDebug() ) {
				var materialIndexLine = Validator.isValid( selectedMaterialIndex ) ? '\n\t\tmaterialIndex: ' + selectedMaterialIndex : '';
				var createdReport = 'Output Object no.: ' + this.outputObjectCount +
					'\n\t\tobjectName: ' + rawObjectDescription.objectName +
					'\n\t\tgroupName: ' + rawObjectDescription.groupName +
					'\n\t\tmaterialName: ' + rawObjectDescription.materialName +
					materialIndexLine +
					'\n\t\tsmoothingGroup: ' + rawObjectDescription.smoothingGroup +
					'\n\t\t#vertices: ' + rawObjectDescription.vertices.length / 3 +
					'\n\t\t#indices: ' + rawObjectDescription.indices.length +
					'\n\t\t#colors: ' + rawObjectDescription.colors.length / 3 +
					'\n\t\t#uvs: ' + rawObjectDescription.uvs.length / 2 +
					'\n\t\t#normals: ' + rawObjectDescription.normals.length / 3;
				this.logger.logDebug( createdReport );
			}

		}

		this.outputObjectCount++;
		this.callbackBuilder(
			{
				cmd: 'meshData',
				progress: {
					numericalValue: currentByte / this.totalBytes
				},
				params: {
					meshName: result.name
				},
				materials: {
					multiMaterial: createMultiMaterial,
					materialNames: materialNames,
					materialGroups: materialGroups
				},
				buffers: {
					vertices: vertexFA,
					indices: indexUA,
					colors: colorFA,
					normals: normalFA,
					uvs: uvFA
				}
			},
			[ vertexFA.buffer ],
			Validator.isValid( indexUA ) ? [ indexUA.buffer ] : null,
			Validator.isValid( colorFA ) ? [ colorFA.buffer ] : null,
			Validator.isValid( normalFA ) ? [ normalFA.buffer ] : null,
			Validator.isValid( uvFA ) ? [ uvFA.buffer ] : null
		);
	};

return Parser;

})();

RawMesh = (function () {

function RawMesh( materialPerSmoothingGroup, useIndices, disregardNormals, activeMtlName ) {
		this.globalVertexOffset = 1;
		this.globalUvOffset = 1;
		this.globalNormalOffset = 1;

		this.vertices = [];
		this.colors = [];
		this.normals = [];
		this.uvs = [];

		// faces are stored according combined index of group, material and smoothingGroup (0 or not)
		this.activeMtlName = Validator.verifyInput( activeMtlName, '' );
		this.objectName = '';
		this.groupName = '';
		this.mtllibName = '';
		this.smoothingGroup = {
			splitMaterials: materialPerSmoothingGroup === true,
			normalized: -1,
			real: -1
		};
		this.useIndices = useIndices === true;
		this.disregardNormals = disregardNormals === true;

		this.mtlCount = 0;
		this.smoothingGroupCount = 0;

		this.subGroups = [];
		this.subGroupInUse = null;
		// this default index is required as it is possible to define faces without 'g' or 'usemtl'
		this.pushSmoothingGroup( 1 );

		this.doubleIndicesCount = 0;
		this.faceCount = 0;
	}

RawMesh.prototype.newInstanceResetOffsets = function () {
		var newRawObject = new RawMesh( this.smoothingGroup.splitMaterials, this.useIndices, this.disregardNormals, this.activeMtlName );

		// move indices forward
		newRawObject.globalVertexOffset = this.globalVertexOffset + this.vertices.length / 3;
		newRawObject.globalUvOffset = this.globalUvOffset + this.uvs.length / 2;
		newRawObject.globalNormalOffset = this.globalNormalOffset + this.normals.length / 3;

		return newRawObject;
	};

RawMesh.prototype.newInstanceKeepOffsets = function () {
		var newRawObject = new RawMesh( this.smoothingGroup.splitMaterials, this.useIndices, this.disregardNormals, this.activeMtlName );
		// keep objectName
		newRawObject.pushObject( this.objectName );

		// keep current buffers and indices forward
		newRawObject.vertices = this.vertices;
		newRawObject.colors = this.colors;
		newRawObject.uvs = this.uvs;
		newRawObject.normals = this.normals;
		newRawObject.globalVertexOffset = this.globalVertexOffset;
		newRawObject.globalUvOffset = this.globalUvOffset;
		newRawObject.globalNormalOffset = this.globalNormalOffset;

		return newRawObject;
	};

RawMesh.prototype.pushVertex = function ( buffer ) {
		this.vertices.push( parseFloat( buffer[ 1 ] ) );
		this.vertices.push( parseFloat( buffer[ 2 ] ) );
		this.vertices.push( parseFloat( buffer[ 3 ] ) );
	};

RawMesh.prototype.pushVertexAndVertextColors = function ( buffer ) {
		this.vertices.push( parseFloat( buffer[ 1 ] ) );
		this.vertices.push( parseFloat( buffer[ 2 ] ) );
		this.vertices.push( parseFloat( buffer[ 3 ] ) );
		this.colors.push( parseFloat( buffer[ 4 ] ) );
		this.colors.push( parseFloat( buffer[ 5 ] ) );
		this.colors.push( parseFloat( buffer[ 6 ] ) );
	};

RawMesh.prototype.pushUv = function ( buffer ) {
		this.uvs.push( parseFloat( buffer[ 1 ] ) );
		this.uvs.push( parseFloat( buffer[ 2 ] ) );
	};

RawMesh.prototype.pushNormal = function ( buffer ) {
		this.normals.push( parseFloat( buffer[ 1 ] ) );
		this.normals.push( parseFloat( buffer[ 2 ] ) );
		this.normals.push( parseFloat( buffer[ 3 ] ) );
	};

RawMesh.prototype.pushObject = function ( objectName ) {
		this.objectName = Validator.verifyInput( objectName, '' );
	};

RawMesh.prototype.pushMtllib = function ( mtllibName ) {
		this.mtllibName = Validator.verifyInput( mtllibName, '' );
	};

RawMesh.prototype.pushGroup = function ( groupName ) {
		this.groupName = Validator.verifyInput( groupName, '' );
	};

RawMesh.prototype.pushUsemtl = function ( mtlName ) {
		if ( this.activeMtlName === mtlName || ! Validator.isValid( mtlName ) ) return;
		this.activeMtlName = mtlName;
		this.mtlCount++;

		this.verifyIndex();
	};

RawMesh.prototype.pushSmoothingGroup = function ( smoothingGroup ) {
		var smoothingGroupInt = parseInt( smoothingGroup );
		if ( isNaN( smoothingGroupInt ) ) {
			smoothingGroupInt = smoothingGroup === "off" ? 0 : 1;
		}

		var smoothCheck = this.smoothingGroup.normalized;
		this.smoothingGroup.normalized = this.smoothingGroup.splitMaterials ? smoothingGroupInt : ( smoothingGroupInt === 0 ) ? 0 : 1;
		this.smoothingGroup.real = smoothingGroupInt;

		if ( smoothCheck !== smoothingGroupInt ) {

			this.smoothingGroupCount++;
			this.verifyIndex();

		}
	};

RawMesh.prototype.verifyIndex = function () {
		var index = this.activeMtlName + '|' + this.smoothingGroup.normalized;
		this.subGroupInUse = this.subGroups[ index ];
		if ( ! Validator.isValid( this.subGroupInUse ) ) {

			this.subGroupInUse = new RawMeshSubGroup( this.objectName, this.groupName, this.activeMtlName, this.smoothingGroup.normalized );
			this.subGroups[ index ] = this.subGroupInUse;

		}
	};

RawMesh.prototype.processFaces = function ( buffer, bufferPointer, slashesCount ) {
		var bufferLength = bufferPointer - 1;
		var i, length;

		// "f vertex ..."
		if ( slashesCount === 0 ) {

			for ( i = 2, length = bufferLength - 1; i < length; i ++ ) {

				this.buildFace( buffer[ 1 ] );
				this.buildFace( buffer[ i ] );
				this.buildFace( buffer[ i + 1 ] );

			}

			// "f vertex/uv ..."
		} else if  ( bufferLength === slashesCount * 2 ) {

			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 ) {

			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 {

			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 ] );

			}

		}
	};

RawMesh.prototype.buildFace = function ( faceIndexV, faceIndexU, faceIndexN ) {
		var sgiu = this.subGroupInUse;
		if ( this.disregardNormals ) faceIndexN = undefined;
		var scope = this;
		var updateRawObjectDescriptionInUse = function () {

			var indexPointerV = ( parseInt( faceIndexV ) - scope.globalVertexOffset ) * 3;
			var indexPointerC = scope.colors.length > 0 ? indexPointerV : null;

			var vertices = sgiu.vertices;
			vertices.push( scope.vertices[ indexPointerV++ ] );
			vertices.push( scope.vertices[ indexPointerV++ ] );
			vertices.push( scope.vertices[ indexPointerV ] );

			if ( indexPointerC !== null ) {

				var colors = sgiu.colors;
				colors.push( scope.colors[ indexPointerC++ ] );
				colors.push( scope.colors[ indexPointerC++ ] );
				colors.push( scope.colors[ indexPointerC ] );

			}

			if ( faceIndexU ) {

				var indexPointerU = ( parseInt( faceIndexU ) - scope.globalUvOffset ) * 2;
				var uvs = sgiu.uvs;
				uvs.push( scope.uvs[ indexPointerU++ ] );
				uvs.push( scope.uvs[ indexPointerU ] );

			}
			if ( faceIndexN ) {

				var indexPointerN = ( parseInt( faceIndexN ) - scope.globalNormalOffset ) * 3;
				var normals = sgiu.normals;
				normals.push( scope.normals[ indexPointerN++ ] );
				normals.push( scope.normals[ indexPointerN++ ] );
				normals.push( scope.normals[ indexPointerN ] );

			}
		};

		if ( this.useIndices ) {

			var mappingName = faceIndexV + ( faceIndexU ? '_' + faceIndexU : '_n' ) + ( faceIndexN ? '_' + faceIndexN : '_n' );
			var indicesPointer = sgiu.indexMappings[ mappingName ];
			if ( Validator.isValid( indicesPointer ) ) {

				this.doubleIndicesCount++;

			} else {

				indicesPointer = sgiu.vertices.length / 3;
				updateRawObjectDescriptionInUse();
				sgiu.indexMappings[ mappingName ] = indicesPointer;
				sgiu.indexMappingsCount++;

			}
			sgiu.indices.push( indicesPointer );

		} else {

			updateRawObjectDescriptionInUse();

		}
		this.faceCount++;
	};

RawMesh.prototype.processLines = function ( buffer, bufferPointer, slashCount ) {
		var i = 1;
		var length;
		var bufferLength = bufferPointer - 1;

		if ( bufferLength === slashCount * 2 ) {

			for ( length = bufferLength - 2; i < length; i += 2 ) {

				this.vertices.push( parseInt( buffer[ i ] ) );
				this.uvs.push( parseInt( buffer[ i + 1 ] ) );

			}

		} else {

			for ( length = bufferLength - 1; i < length; i ++ ) {

				this.vertices.push( parseInt( buffer[ i ] ) );

			}

		}
	};

RawMesh.prototype.finalize = function () {
		var rawObjectDescriptionsTemp = [];
		var rawObjectDescription;
		var absoluteVertexCount = 0;
		var absoluteIndexMappingsCount = 0;
		var absoluteIndexCount = 0;
		var absoluteColorCount = 0;
		var absoluteNormalCount = 0;
		var absoluteUvCount = 0;
		var indices;
		for ( var name in this.subGroups ) {

			rawObjectDescription = this.subGroups[ name ];
			if ( rawObjectDescription.vertices.length > 0 ) {

				indices = rawObjectDescription.indices;
				if ( indices.length > 0 && absoluteIndexMappingsCount > 0 ) {

					for ( var i in indices ) indices[ i ] = indices[ i ] + absoluteIndexMappingsCount;

				}
				rawObjectDescriptionsTemp.push( rawObjectDescription );
				absoluteVertexCount += rawObjectDescription.vertices.length;
				absoluteIndexMappingsCount += rawObjectDescription.indexMappingsCount;
				absoluteIndexCount += rawObjectDescription.indices.length;
				absoluteColorCount += rawObjectDescription.colors.length;
				absoluteUvCount += rawObjectDescription.uvs.length;
				absoluteNormalCount += rawObjectDescription.normals.length;

			}
		}

		// do not continue if no result
		var result = null;
		if ( rawObjectDescriptionsTemp.length > 0 ) {

			result = {
				name: this.groupName !== '' ? this.groupName : this.objectName,
				subGroups: rawObjectDescriptionsTemp,
				absoluteVertexCount: absoluteVertexCount,
				absoluteIndexCount: absoluteIndexCount,
				absoluteColorCount: absoluteColorCount,
				absoluteNormalCount: absoluteNormalCount,
				absoluteUvCount: absoluteUvCount,
				faceCount: this.faceCount,
				doubleIndicesCount: this.doubleIndicesCount
			};

		}
		return result;
	};

RawMesh.prototype.createReport = function () {
		var report = {
			objectName: this.objectName,
			groupName: this.groupName,
			mtllibName: this.mtllibName,
			vertexCount: this.vertices.length / 3,
			normalCount: this.normals.length / 3,
			uvCount: this.uvs.length / 2,
			smoothingGroupCount: this.smoothingGroupCount,
			mtlCount: this.mtlCount,
			subGroups: this.subGroups.length
		};

		return report;
	};

return RawMesh;

})();

RawMeshSubGroup = (function () {

function RawMeshSubGroup( objectName, groupName, materialName, smoothingGroup ) {
		this.objectName = objectName;
		this.groupName = groupName;
		this.materialName = materialName;
		this.smoothingGroup = smoothingGroup;
		this._init();
	}

RawMeshSubGroup.prototype._init = function () {
		this.vertices = [];
		this.indexMappingsCount = 0;
		this.indexMappings = [];
		this.indices = [];
		this.colors = [];
		this.uvs = [];
		this.normals = [];
	};

return RawMeshSubGroup;

})();

WorkerRunnerRefImpl = (function () {

function WorkerRunnerRefImpl() {
	var scope = this;
	var scopedRunner = function( event ) {
		scope.processMessage( event.data );
	};
	self.addEventListener( 'message', scopedRunner, false );
}

WorkerRunnerRefImpl.prototype.applyProperties = function ( parser, params ) {
	var property, funcName, values;
	for ( property in params ) {
		funcName = 'set' + property.substring( 0, 1 ).toLocaleUpperCase() + property.substring( 1 );
		values = params[ property ];

		if ( typeof parser[ funcName ] === 'function' ) {

			parser[ funcName ]( values );

		} else if ( parser.hasOwnProperty( property ) ) {

			parser[ property ] = values;

		}
	}
};

WorkerRunnerRefImpl.prototype.processMessage = function ( payload ) {
	var logger = new ConsoleLogger();
	if ( Validator.isValid( payload.logger ) ) {

		logger.setEnabled( payload.logger.enabled );
		logger.setDebug( payload.logger.debug );

	}
	if ( payload.cmd === 'run' ) {

		var callbacks = {
			callbackBuilder: function ( payload ) {
				self.postMessage( payload );
			},
			callbackProgress: function ( text ) {
				logger.logDebug( 'WorkerRunner: progress: ' + text );
			}
		};

		// Parser is expected to be named as such
		var parser = new Parser( logger );
		this.applyProperties( parser, payload.params );
		this.applyProperties( parser, payload.materials );
		this.applyProperties( parser, callbacks );
		parser.workerScope = self;
		parser.parse( payload.data.input, payload.data.options );

		logger.logInfo( 'WorkerRunner: Run complete!' );

		callbacks.callbackBuilder( {
			cmd: 'complete',
			msg: 'WorkerRunner completed run.'
		} );

	} else {

		logger.logError( 'WorkerRunner: Received unknown command: ' + payload.cmd );

	}
};

return WorkerRunnerRefImpl;

})();

new WorkerRunnerRefImpl();


I'm going to be completely honest, I would never have expected this to work. After all there is some metaprogramming going on in there! 

But upon closer inspection, the logic appears to all be proper, some of the variables got renamed to minified variable names, but the right ones seem to be called. 

The ONLY strange stuff is that many of the toplevel names are mangled as though something went wrong with concurrent serialization somehow. `RawMRawMeshSubGroupshSubGroup` instead of `RawMeshSubGroup`, note the `e` got replaced with an entire instance of itself. Holy shit. I think that's the key to this. Something is causing the name to be injected into itself in place of its first `e` letter. 

OK so anyway. Somehow this all seems to ALMOST work under uglify so maybe with some slight robustification i can build a minified three.js that uses objloader2. 

Meanwhile, the good news is that i'm quite satisfied to be simply deploying unminified three.js to production. 
</details>
@unphased
Copy link
Author

To reiterate... I'm not posting this as a bug report per se.

I just wanted to illustrate a failure i encountered and it seems like there is some tantalizing room for robustifying the code a bit! But i need your help to make sense of it a little better.

@unphased unphased changed the title ObjLoader2 async worker code breaks under babel -> uglify ObjLoader2 async worker code breaks under uglify Dec 29, 2017
@kaisalmen
Copy link
Owner

Minification with Gulp used to work fine after release of V2.x.x. I fixed previous bugs and thought I did not break it again. I will investigate.

@unphased
Copy link
Author

i have to admit i do not currently use a gulp workflow. i run uglify directly, here is my command

./node_modules/.bin/uglifyjs map/index.es5.js --mangle toplevel --compress --reserve-domprops --reserved-file ~/.vim/uglify-reserved.json -p 1

where uglify-reserved.json contains

{
  "vars": [ "define", "require" ],
  "props": [ "length", "prototype", "transparent", "material" ]
}

@kaisalmen
Copy link
Owner

I use gulp-uglify 3.0.0 which uses UglifyJS2 3.1.5. The only option I set is:
mangle=false
which disables all mangling (does that words exist?)

When I set toplevel to true as you do on cmd-line it does not work. Constructors are broken.

Do you require mangle?

@unphased
Copy link
Author

unphased commented Dec 31, 2017

As I've explained, I do not require minifying/uglifying js, so as a corollary, mangling (yes, it is a word!) is not required by me.

I'm kind of curious though because it feels like it would be easy to fix it to work with mangling! Feel free to just put this issue on the back burner. I'm totally not blocked by it because I have changed my deployment to not minify any of my three.js dependencies anymore.

Thanks.

@kaisalmen
Copy link
Owner

The build object/singleton build function has problems creating a valid constructor from the existing mangled code. I will see whether I can make it work by adding some additional hints/arguments to the utility function.

There was a similar issue in the past. I want to make this work. Let's see...

@poacher2k
Copy link

poacher2k commented Jan 4, 2018

I'm encountering an error which seems likely to be caused by minification as well:
"Uncaught ReferenceError: _keys2 is not defined"

Parser.prototype.configure = function () {
	this.rawMesh = new RawMesh(this.materialPerSmoothingGroup, this.useIndices, this.disregardNormals);

	if (this.logger.isEnabled()) {
		var matKeys = (0, _keys2['default'])(this.materials);
		var matNames = matKeys.length > 0 ? '\n\tmaterialNames:\n\t\t- ' + matKeys.join('\n\t\t- ') : '\n\tmaterialNames: None';

		[...]
	}
};

Comparing the output with @unphased , it seems like the var matKeys-line should be var matKeys = Object.keys( this.materials ); instead ?

Edit: After looking through the blob, it seems like _keys2['default'] is the only occurrence of any mangling. So, yeah. 🤔

@kaisalmen
Copy link
Owner

kaisalmen commented Jan 4, 2018

@poacher2k on branch Issue31 mangling now works. It is not merged back, yet as tests are not complete. Could you please see if your problem is gone as well.

@poacher2k
Copy link

poacher2k commented Jan 4, 2018

@kaisalmen: seems like I'm still getting the same error.

This is the blob, error on :270
/**
  * This code was constructed by OBJLoader2 buildCode.
  */

THREE = { LoaderSupport: {} };

THREE.LoaderSupport.Validator = {
	isValid: function isValid(input) {
		return input !== null && input !== undefined;
	},
	verifyInput: function verifyInput(input, defaultValue) {
		return input === null || input === undefined ? defaultValue : input;
	},
}

THREE.LoaderSupport.ConsoleLogger = (function () {

	function ConsoleLogger(enabled, debug) {
		this.enabled = enabled !== false;
		this.debug = debug === true;
	}

	ConsoleLogger.prototype.setDebug = function (debug) {
		this.debug = debug === true;
	};

	ConsoleLogger.prototype.isDebug = function () {
		return this.isEnabled() && this.debug;
	};

	ConsoleLogger.prototype.setEnabled = function (enabled) {
		this.enabled = enabled === true;
	};

	ConsoleLogger.prototype.isEnabled = function () {
		return this.enabled;
	};

	ConsoleLogger.prototype.logDebug = function (message) {
		if (this.enabled && this.debug) console.info(message);
	};

	ConsoleLogger.prototype.logInfo = function (message) {
		if (this.enabled) console.info(message);
	};

	ConsoleLogger.prototype.logWarn = function (message) {
		console.warn(message);
	};

	ConsoleLogger.prototype.logError = function (message) {
		console.error(message);
	};

	ConsoleLogger.prototype.logTimeStart = function (id) {
		if (this.enabled) console.time(id);
	};

	ConsoleLogger.prototype.logTimeEnd = function (id) {
		if (this.enabled) console.timeEnd(id);
	};

	return ConsoleLogger;
})();

THREE.LoaderSupport.LoaderBase = (function () {

	function LoaderBase(manager, logger) {
		this.manager = Validator.verifyInput(manager, THREE.DefaultLoadingManager);
		this.logger = Validator.verifyInput(logger, new ConsoleLogger());

		this.modelName = '';
		this.instanceNo = 0;
		this.path = '';
		this.useIndices = false;
		this.disregardNormals = false;

		this.loaderRootNode = new THREE.Group();
		this.builder = new THREE.LoaderSupport.Builder(this.logger);
		this._createDefaultMaterials();
		this.callbacks = new THREE.LoaderSupport.Callbacks();
	}

	LoaderBase.prototype._createDefaultMaterials = function () {
		var defaultMaterial = new THREE.MeshStandardMaterial({ color: 0xdcf1ff });
		defaultMaterial.name = 'defaultMaterial';

		var vertexColorMaterial = new THREE.MeshStandardMaterial({
			color: 0xdcf1ff
		});
		vertexColorMaterial.name = 'vertexColorMaterial';
		vertexColorMaterial.vertexColors = THREE.VertexColors;

		var runtimeMaterials = {};
		runtimeMaterials[defaultMaterial.name] = defaultMaterial;
		runtimeMaterials[vertexColorMaterial.name] = vertexColorMaterial;

		this.builder.updateMaterials({
			cmd: 'materialData',
			materials: {
				materialCloneInstructions: null,
				serializedMaterials: null,
				runtimeMaterials: runtimeMaterials
			}
		});
	};

	LoaderBase.prototype._applyPrepData = function (prepData) {
		if (Validator.isValid(prepData)) {
			this.setModelName(prepData.modelName);
			this.setStreamMeshesTo(prepData.streamMeshesTo);
			this.builder.setMaterials(prepData.materials);
			this.setUseIndices(prepData.useIndices);
			this.setDisregardNormals(prepData.disregardNormals);

			this._setCallbacks(prepData.getCallbacks());
		}
	};

	LoaderBase.prototype._setCallbacks = function (callbacks) {
		if (Validator.isValid(callbacks.onProgress)) this.callbacks.setCallbackOnProgress(callbacks.onProgress);
		if (Validator.isValid(callbacks.onMeshAlter)) this.callbacks.setCallbackOnMeshAlter(callbacks.onMeshAlter);
		if (Validator.isValid(callbacks.onLoad)) this.callbacks.setCallbackOnLoad(callbacks.onLoad);
		if (Validator.isValid(callbacks.onLoadMaterials)) this.callbacks.setCallbackOnLoadMaterials(callbacks.onLoadMaterials);

		this.builder._setCallbacks(this.callbacks);
	};

	LoaderBase.prototype.getLogger = function () {
		return this.logger;
	};

	LoaderBase.prototype.setModelName = function (modelName) {
		this.modelName = Validator.verifyInput(modelName, this.modelName);
	};

	LoaderBase.prototype.setPath = function (path) {
		this.path = Validator.verifyInput(path, this.path);
	};

	LoaderBase.prototype.setStreamMeshesTo = function (streamMeshesTo) {
		this.loaderRootNode = Validator.verifyInput(streamMeshesTo, this.loaderRootNode);
	};

	LoaderBase.prototype.setMaterials = function (materials) {
		this.builder.setMaterials(materials);
	};

	LoaderBase.prototype.setUseIndices = function (useIndices) {
		this.useIndices = useIndices === true;
	};

	LoaderBase.prototype.setDisregardNormals = function (disregardNormals) {
		this.disregardNormals = disregardNormals === true;
	};

	LoaderBase.prototype.onProgress = function (type, text, numericalValue) {
		var content = Validator.isValid(text) ? text : '';
		var event = {
			detail: {
				type: type,
				modelName: this.modelName,
				instanceNo: this.instanceNo,
				text: content,
				numericalValue: numericalValue
			}
		};

		if (Validator.isValid(this.callbacks.onProgress)) this.callbacks.onProgress(event);

		this.logger.logDebug(content);
	};

	return LoaderBase;
})();

var Validator = THREE.LoaderSupport.Validator;
var ConsoleLogger = THREE.LoaderSupport.ConsoleLogger;
THREE.LoaderSupport.ObjParser = {
Consts: null,
Parser: null,
RawMesh: null,
RawMeshSubGroup: null
};
THREE.LoaderSupport.ObjParser.Consts = {
	CODE_LF: 10,
	CODE_CR: 13,
	CODE_SPACE: 32,
	CODE_SLASH: 47,
	STRING_LF: "\n",
	STRING_CR: "\r",
	STRING_SPACE: " ",
	STRING_SLASH: "/",
	LINE_F: "f",
	LINE_G: "g",
	LINE_L: "l",
	LINE_O: "o",
	LINE_S: "s",
	LINE_V: "v",
	LINE_VT: "vt",
	LINE_VN: "vn",
	LINE_MTLLIB: "mtllib",
	LINE_USEMTL: "usemtl",
}

THREE.LoaderSupport.ObjParser.Parser = (function () {

	function Parser() {
			this.callbackProgress = null;
			this.callbackBuilder = null;

			this.materials = {};
			this.rawMesh = null;
			this.useAsync = false;
			this.materialPerSmoothingGroup = false;
			this.useIndices = false;
			this.disregardNormals = false;

			this.inputObjectCount = 1;
			this.outputObjectCount = 1;
			this.counts = {
				vertices: 0,
				faces: 0,
				doubleIndicesCount: 0
			};

			this.logger = new THREE.LoaderSupport.ConsoleLogger();
			this.totalBytes = 0;
		}

	Parser.prototype.setUseAsync = function (useAsync) {
			this.useAsync = useAsync;
		};

	Parser.prototype.setMaterialPerSmoothingGroup = function (materialPerSmoothingGroup) {
			this.materialPerSmoothingGroup = materialPerSmoothingGroup;
		};

	Parser.prototype.setUseIndices = function (useIndices) {
			this.useIndices = useIndices;
		};

	Parser.prototype.setDisregardNormals = function (disregardNormals) {
			this.disregardNormals = disregardNormals;
		};

	Parser.prototype.setMaterials = function (materials) {
			this.materials = THREE.LoaderSupport.Validator.verifyInput(materials, this.materials);
			this.materials = THREE.LoaderSupport.Validator.verifyInput(this.materials, {});
		};

	Parser.prototype.setCallbackBuilder = function (callbackBuilder) {
			this.callbackBuilder = callbackBuilder;
			if (!THREE.LoaderSupport.Validator.isValid(this.callbackBuilder)) throw 'Unable to run as no "builder" callback is set.';
		};

	Parser.prototype.setCallbackProgress = function (callbackProgress) {
			this.callbackProgress = callbackProgress;
		};

	Parser.prototype.setLogConfig = function (enabled, debug) {
			this.logger.setEnabled(enabled);
			this.logger.setDebug(debug);
		};

	Parser.prototype.configure = function () {
			this.rawMesh = new THREE.LoaderSupport.ObjParser.RawMesh(this.materialPerSmoothingGroup, this.useIndices, this.disregardNormals);

			if (this.logger.isEnabled()) {
				var matKeys = (0, _keys2['default'])(this.materials);
				var matNames = matKeys.length > 0 ? '\n\tmaterialNames:\n\t\t- ' + matKeys.join('\n\t\t- ') : '\n\tmaterialNames: None';
				var printedConfig = 'OBJLoader2.Parser configuration:' + matNames + '\n\tuseAsync: ' + this.useAsync + '\n\tmaterialPerSmoothingGroup: ' + this.materialPerSmoothingGroup + '\n\tuseIndices: ' + this.useIndices + '\n\tdisregardNormals: ' + this.disregardNormals + '\n\tcallbackBuilderName: ' + this.callbackBuilder.name + '\n\tcallbackProgressName: ' + this.callbackProgress.name;
				this.logger.logInfo(printedConfig);
			}
		};

	Parser.prototype.parse = function (arrayBuffer) {
			this.logger.logTimeStart('OBJLoader2.Parser.parse');
			this.configure();

			var arrayBufferView = new Uint8Array(arrayBuffer);
			var length = arrayBufferView.byteLength;
			this.totalBytes = length;
			var buffer = new Array(128);
			var bufferPointer = 0;
			var slashSpacePattern = new Array(16);
			var slashSpacePatternPointer = 0;
			var code;
			var word = '';
			var i = 0;
			for (; i < length; i++) {
				code = arrayBufferView[i];
				switch (code) {
					case THREE.LoaderSupport.ObjParser.Consts.CODE_SPACE:
						if (word.length > 0) buffer[bufferPointer++] = word;
						slashSpacePattern[slashSpacePatternPointer++] = 0;
						word = '';
						break;

					case THREE.LoaderSupport.ObjParser.Consts.CODE_SLASH:
						if (word.length > 0) buffer[bufferPointer++] = word;
						slashSpacePattern[slashSpacePatternPointer++] = 1;
						word = '';
						break;

					case THREE.LoaderSupport.ObjParser.Consts.CODE_LF:
						if (word.length > 0) buffer[bufferPointer++] = word;
						word = '';
						this.processLine(buffer, bufferPointer, slashSpacePattern, slashSpacePatternPointer, i);
						bufferPointer = 0;
						slashSpacePatternPointer = 0;
						break;

					case THREE.LoaderSupport.ObjParser.Consts.CODE_CR:
						break;

					default:
						word += String.fromCharCode(code);
						break;
				}
			}
			this.finalize(i);
			this.logger.logTimeEnd('OBJLoader2.Parser.parse');
		};

	Parser.prototype.parseText = function (text) {
			this.logger.logTimeStart('OBJLoader2.Parser.parseText');
			this.configure();

			var length = text.length;
			this.totalBytes = length;
			var buffer = new Array(128);
			var bufferPointer = 0;
			var slashSpacePattern = new Array(16);
			var slashSpacePatternPointer = 0;
			var char;
			var word = '';
			var i = 0;
			for (; i < length; i++) {
				char = text[i];
				switch (char) {
					case THREE.LoaderSupport.ObjParser.Consts.STRING_SPACE:
						if (word.length > 0) buffer[bufferPointer++] = word;
						slashSpacePattern[slashSpacePatternPointer++] = 0;
						word = '';
						break;

					case THREE.LoaderSupport.ObjParser.Consts.STRING_SLASH:
						if (word.length > 0) buffer[bufferPointer++] = word;
						slashSpacePattern[slashSpacePatternPointer++] = 1;
						word = '';
						break;

					case THREE.LoaderSupport.ObjParser.Consts.STRING_LF:
						if (word.length > 0) buffer[bufferPointer++] = word;
						word = '';
						this.processLine(buffer, bufferPointer, slashSpacePattern, slashSpacePatternPointer, i);
						bufferPointer = 0;
						slashSpacePatternPointer = 0;
						break;

					case THREE.LoaderSupport.ObjParser.Consts.STRING_CR:
						break;

					default:
						word += char;
				}
			}
			this.finalize(i);
			this.logger.logTimeEnd('OBJLoader2.Parser.parseText');
		};

	Parser.prototype.processLine = function (buffer, bufferPointer, slashSpacePattern, slashSpacePatternPointer, currentByte) {
			if (bufferPointer < 1) return;

			var countSlashes = function countSlashes(slashSpacePattern, slashSpacePatternPointer) {
				var slashesCount = 0;
				for (var i = 0; i < slashSpacePatternPointer; i++) {
					slashesCount += slashSpacePattern[i];
				}
				return slashesCount;
			};

			var concatStringBuffer = function concatStringBuffer(buffer, bufferPointer, slashSpacePattern) {
				var concatBuffer = '';
				if (bufferPointer === 2) {
					concatBuffer = buffer[1];
				} else {
					var bufferLength = bufferPointer - 1;
					for (var i = 1; i < bufferLength; i++) {
						concatBuffer += buffer[i] + (slashSpacePattern[i] === 0 ? ' ' : '/');
					}
					concatBuffer += buffer[bufferLength];
				}
				return concatBuffer;
			};

			var flushStringBuffer = function flushStringBuffer(buffer, bufferPointer) {
				for (var i = 0; i < bufferPointer; i++) {
					buffer[i] = '';
				}
			};

			switch (buffer[0]) {
				case THREE.LoaderSupport.ObjParser.Consts.LINE_V:
					this.rawMesh.pushVertex(buffer, bufferPointer > 4);
					break;

				case THREE.LoaderSupport.ObjParser.Consts.LINE_VT:
					this.rawMesh.pushUv(buffer);
					break;

				case THREE.LoaderSupport.ObjParser.Consts.LINE_VN:
					this.rawMesh.pushNormal(buffer);
					break;

				case THREE.LoaderSupport.ObjParser.Consts.LINE_F:
					this.rawMesh.processFaces(buffer, bufferPointer, countSlashes(slashSpacePattern, slashSpacePatternPointer));
					break;

				case THREE.LoaderSupport.ObjParser.Consts.LINE_L:
					this.rawMesh.processLines(buffer, bufferPointer, countSlashes(slashSpacePattern, slashSpacePatternPointer));
					break;

				case THREE.LoaderSupport.ObjParser.Consts.LINE_S:
					this.rawMesh.pushSmoothingGroup(buffer[1]);
					flushStringBuffer(buffer, bufferPointer);
					break;

				case THREE.LoaderSupport.ObjParser.Consts.LINE_G:
					// 'g' leads to creation of mesh if valid data (faces declaration was done before), otherwise only groupName gets set
					this.processCompletedMesh(currentByte);
					this.rawMesh.pushGroup(concatStringBuffer(buffer, bufferPointer, slashSpacePattern));
					flushStringBuffer(buffer, bufferPointer);
					break;

				case THREE.LoaderSupport.ObjParser.Consts.LINE_O:
					// 'o' is pure meta-information and does not result in creation of new meshes
					this.rawMesh.pushObject(concatStringBuffer(buffer, bufferPointer, slashSpacePattern));
					flushStringBuffer(buffer, bufferPointer);
					break;

				case THREE.LoaderSupport.ObjParser.Consts.LINE_MTLLIB:
					this.rawMesh.pushMtllib(concatStringBuffer(buffer, bufferPointer, slashSpacePattern));
					flushStringBuffer(buffer, bufferPointer);
					break;

				case THREE.LoaderSupport.ObjParser.Consts.LINE_USEMTL:
					this.rawMesh.pushUsemtl(concatStringBuffer(buffer, bufferPointer, slashSpacePattern));
					flushStringBuffer(buffer, bufferPointer);
					break;

				default:
					break;
			}
		};

	Parser.prototype.createRawMeshReport = function (rawMesh, inputObjectCount) {
			var report = rawMesh.createReport(inputObjectCount);
			return 'Input Object number: ' + inputObjectCount + '\n\tObject name: ' + report.objectName + '\n\tGroup name: ' + report.groupName + '\n\tMtllib name: ' + report.mtllibName + '\n\tVertex count: ' + report.vertexCount + '\n\tNormal count: ' + report.normalCount + '\n\tUV count: ' + report.uvCount + '\n\tSmoothingGroup count: ' + report.smoothingGroupCount + '\n\tMaterial count: ' + report.mtlCount + '\n\tReal RawMeshSubGroup count: ' + report.subGroups;
		};

	Parser.prototype.processCompletedMesh = function (currentByte) {
			var result = this.rawMesh.finalize();
			if (THREE.LoaderSupport.Validator.isValid(result)) {
				if (this.rawMesh.colors.length > 0 && this.rawMesh.colors.length !== this.rawMesh.vertices.length) {
					throw 'Vertex Colors were detected, but vertex count and color count do not match!';
				}
				if (this.logger.isDebug()) this.logger.logDebug(this.createRawMeshReport(this.rawMesh, this.inputObjectCount));
				this.inputObjectCount++;

				this.buildMesh(result, currentByte);
				var progressBytesPercent = currentByte / this.totalBytes;
				this.callbackProgress('Completed [o: ' + this.rawMesh.objectName + ' g:' + this.rawMesh.groupName + '] Total progress: ' + (progressBytesPercent * 100).toFixed(2) + '%', progressBytesPercent);
				this.rawMesh.reset(this.rawMesh.smoothingGroup.splitMaterials);

				return true;
			} else {
				return false;
			}
		};

	Parser.prototype.finalize = function (currentByte) {
			this.logger.logInfo('Global output object count: ' + this.outputObjectCount);
			if (this.processCompletedMesh(currentByte) && this.logger.isEnabled()) {
				var parserFinalReport = 'Overall counts: ' + '\n\tVertices: ' + this.counts.vertices + '\n\tFaces: ' + this.counts.faces + '\n\tMultiple definitions: ' + this.counts.doubleIndicesCount;
				this.logger.logInfo(parserFinalReport);
			}
		};

	Parser.prototype.buildMesh = function (result, currentByte) {
			var rawObjectDescriptions = result.subGroups;

			var vertexFA = new Float32Array(result.absoluteVertexCount);
			this.counts.vertices += result.absoluteVertexCount / 3;
			this.counts.faces += result.faceCount;
			this.counts.doubleIndicesCount += result.doubleIndicesCount;
			var indexUA = result.absoluteIndexCount > 0 ? new Uint32Array(result.absoluteIndexCount) : null;
			var colorFA = result.absoluteColorCount > 0 ? new Float32Array(result.absoluteColorCount) : null;
			var normalFA = result.absoluteNormalCount > 0 ? new Float32Array(result.absoluteNormalCount) : null;
			var uvFA = result.absoluteUvCount > 0 ? new Float32Array(result.absoluteUvCount) : null;
			var haveVertexColors = THREE.LoaderSupport.Validator.isValid(colorFA);

			var rawObjectDescription;
			var materialNames = [];

			var createMultiMaterial = rawObjectDescriptions.length > 1;
			var materialIndex = 0;
			var materialIndexMapping = [];
			var selectedMaterialIndex;
			var materialGroup;
			var materialGroups = [];

			var vertexFAOffset = 0;
			var indexUAOffset = 0;
			var colorFAOffset = 0;
			var normalFAOffset = 0;
			var uvFAOffset = 0;
			var materialGroupOffset = 0;
			var materialGroupLength = 0;

			var materialOrg, material, materialName, materialNameOrg;
			for (var oodIndex in rawObjectDescriptions) {
				if (!rawObjectDescriptions.hasOwnProperty(oodIndex)) continue;
				rawObjectDescription = rawObjectDescriptions[oodIndex];

				materialNameOrg = rawObjectDescription.materialName;
				materialName = materialNameOrg + (haveVertexColors ? '_vertexColor' : '') + (rawObjectDescription.smoothingGroup === 0 ? '_flat' : '');
				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 (!THREE.LoaderSupport.Validator.isValid(materialOrg) && !THREE.LoaderSupport.Validator.isValid(material)) {
					var defaultMaterialName = haveVertexColors ? 'vertexColorMaterial' : 'defaultMaterial';
					materialOrg = this.materials[defaultMaterialName];
					this.logger.logWarn('object_group "' + rawObjectDescription.objectName + '_' + rawObjectDescription.groupName + '" was defined with unresolvable material "' + materialNameOrg + '"! Assigning "' + defaultMaterialName + '".');
					materialNameOrg = defaultMaterialName;

					// if names are identical then there is no need for later manipulation
					if (materialNameOrg === materialName) {
						material = materialOrg;
						materialName = defaultMaterialName;
					}
				}
				if (!THREE.LoaderSupport.Validator.isValid(material)) {
					var materialCloneInstructions = {
						materialNameOrg: materialNameOrg,
						materialName: materialName,
						materialProperties: {
							vertexColors: haveVertexColors ? 2 : 0,
							flatShading: rawObjectDescription.smoothingGroup === 0
						}
					};
					var payload = {
						cmd: 'materialData',
						materials: {
							materialCloneInstructions: materialCloneInstructions
						}
					};
					this.callbackBuilder(payload);

					// fake entry for async; sync Parser always works on material references (Builder update directly visible here)
					if (this.useAsync) this.materials[materialName] = materialCloneInstructions;
				}

				if (createMultiMaterial) {
					// re-use material if already used before. Reduces materials array size and eliminates duplicates
					selectedMaterialIndex = materialIndexMapping[materialName];
					if (!selectedMaterialIndex) {
						selectedMaterialIndex = materialIndex;
						materialIndexMapping[materialName] = materialIndex;
						materialNames.push(materialName);
						materialIndex++;
					}
					materialGroupLength = this.useIndices ? rawObjectDescription.indices.length : rawObjectDescription.vertices.length / 3;
					materialGroup = {
						start: materialGroupOffset,
						count: materialGroupLength,
						index: selectedMaterialIndex
					};
					materialGroups.push(materialGroup);
					materialGroupOffset += materialGroupLength;
				} else {
					materialNames.push(materialName);
				}

				vertexFA.set(rawObjectDescription.vertices, vertexFAOffset);
				vertexFAOffset += rawObjectDescription.vertices.length;

				if (indexUA) {
					indexUA.set(rawObjectDescription.indices, indexUAOffset);
					indexUAOffset += rawObjectDescription.indices.length;
				}

				if (colorFA) {
					colorFA.set(rawObjectDescription.colors, colorFAOffset);
					colorFAOffset += rawObjectDescription.colors.length;
				}

				if (normalFA) {
					normalFA.set(rawObjectDescription.normals, normalFAOffset);
					normalFAOffset += rawObjectDescription.normals.length;
				}
				if (uvFA) {
					uvFA.set(rawObjectDescription.uvs, uvFAOffset);
					uvFAOffset += rawObjectDescription.uvs.length;
				}

				if (this.logger.isDebug()) {
					var materialIndexLine = THREE.LoaderSupport.Validator.isValid(selectedMaterialIndex) ? '\n\t\tmaterialIndex: ' + selectedMaterialIndex : '';
					var createdReport = 'Output Object no.: ' + this.outputObjectCount + '\n\t\tgroupName: ' + rawObjectDescription.groupName + materialIndexLine + '\n\t\tmaterialName: ' + rawObjectDescription.materialName + '\n\t\tsmoothingGroup: ' + rawObjectDescription.smoothingGroup + '\n\t\tobjectName: ' + rawObjectDescription.objectName + '\n\t\t#vertices: ' + rawObjectDescription.vertices.length / 3 + '\n\t\t#indices: ' + rawObjectDescription.indices.length + '\n\t\t#colors: ' + rawObjectDescription.colors.length / 3 + '\n\t\t#uvs: ' + rawObjectDescription.uvs.length / 2 + '\n\t\t#normals: ' + rawObjectDescription.normals.length / 3;
					this.logger.logDebug(createdReport);
				}
			}

			this.outputObjectCount++;
			this.callbackBuilder({
				cmd: 'meshData',
				progress: {
					numericalValue: currentByte / this.totalBytes
				},
				params: {
					meshName: result.name
				},
				materials: {
					multiMaterial: createMultiMaterial,
					materialNames: materialNames,
					materialGroups: materialGroups
				},
				buffers: {
					vertices: vertexFA,
					indices: indexUA,
					colors: colorFA,
					normals: normalFA,
					uvs: uvFA
				}
			}, [vertexFA.buffer], THREE.LoaderSupport.Validator.isValid(indexUA) ? [indexUA.buffer] : null, THREE.LoaderSupport.Validator.isValid(colorFA) ? [colorFA.buffer] : null, THREE.LoaderSupport.Validator.isValid(normalFA) ? [normalFA.buffer] : null, THREE.LoaderSupport.Validator.isValid(uvFA) ? [uvFA.buffer] : null);
		};

	return Parser;
})();

THREE.LoaderSupport.ObjParser.RawMesh = (function () {

	function RawMesh(materialPerSmoothingGroup, useIndices, disregardNormals) {
			this.vertices = [];
			this.colors = [];
			this.normals = [];
			this.uvs = [];

			this.useIndices = useIndices === true;
			this.disregardNormals = disregardNormals === true;

			this.objectName = '';
			this.groupName = '';
			this.activeMtlName = '';
			this.mtllibName = '';
			this.reset(materialPerSmoothingGroup);
		}

	RawMesh.prototype.reset = function (materialPerSmoothingGroup) {
			// faces are stored according combined index of group, material and smoothingGroup (0 or not)
			this.subGroups = [];
			this.subGroupInUse = null;
			this.smoothingGroup = {
				splitMaterials: materialPerSmoothingGroup === true,
				normalized: -1,
				real: -1
			};
			// this default index is required as it is possible to define faces without 'g' or 'usemtl'
			this.pushSmoothingGroup(1);

			this.doubleIndicesCount = 0;
			this.faceCount = 0;
			this.mtlCount = 0;
			this.smoothingGroupCount = 0;
		};

	RawMesh.prototype.pushVertex = function (buffer, haveVertexColors) {
			this.vertices.push(parseFloat(buffer[1]));
			this.vertices.push(parseFloat(buffer[2]));
			this.vertices.push(parseFloat(buffer[3]));
			if (haveVertexColors) {
				this.colors.push(parseFloat(buffer[4]));
				this.colors.push(parseFloat(buffer[5]));
				this.colors.push(parseFloat(buffer[6]));
			}
		};

	RawMesh.prototype.pushUv = function (buffer) {
			this.uvs.push(parseFloat(buffer[1]));
			this.uvs.push(parseFloat(buffer[2]));
		};

	RawMesh.prototype.pushNormal = function (buffer) {
			this.normals.push(parseFloat(buffer[1]));
			this.normals.push(parseFloat(buffer[2]));
			this.normals.push(parseFloat(buffer[3]));
		};

	RawMesh.prototype.pushGroup = function (groupName) {
			this.groupName = THREE.LoaderSupport.Validator.verifyInput(groupName, '');
		};

	RawMesh.prototype.pushObject = function (objectName) {
			this.objectName = THREE.LoaderSupport.Validator.verifyInput(objectName, '');
		};

	RawMesh.prototype.pushMtllib = function (mtllibName) {
			this.mtllibName = THREE.LoaderSupport.Validator.verifyInput(mtllibName, '');
		};

	RawMesh.prototype.pushUsemtl = function (mtlName) {
			if (this.activeMtlName === mtlName || !THREE.LoaderSupport.Validator.isValid(mtlName)) return;
			this.activeMtlName = mtlName;
			this.mtlCount++;

			this.verifyIndex();
		};

	RawMesh.prototype.pushSmoothingGroup = function (smoothingGroup) {
			var smoothingGroupInt = parseInt(smoothingGroup);
			if (isNaN(smoothingGroupInt)) {
				smoothingGroupInt = smoothingGroup === 'off' ? 0 : 1;
			}

			var smoothCheck = this.smoothingGroup.normalized;
			this.smoothingGroup.normalized = this.smoothingGroup.splitMaterials ? smoothingGroupInt : smoothingGroupInt === 0 ? 0 : 1;
			this.smoothingGroup.real = smoothingGroupInt;

			if (smoothCheck !== smoothingGroupInt) {
				this.smoothingGroupCount++;
				this.verifyIndex();
			}
		};

	RawMesh.prototype.verifyIndex = function () {
			var index = this.activeMtlName + '|' + this.smoothingGroup.normalized;
			this.subGroupInUse = this.subGroups[index];
			if (!THREE.LoaderSupport.Validator.isValid(this.subGroupInUse)) {
				this.subGroupInUse = new THREE.LoaderSupport.ObjParser.RawMeshSubGroup(this.objectName, this.groupName, this.activeMtlName, this.smoothingGroup.normalized);
				this.subGroups[index] = this.subGroupInUse;
			}
		};

	RawMesh.prototype.processFaces = function (buffer, bufferPointer, slashesCount) {
			var bufferLength = bufferPointer - 1;
			var i, length;

			// "f vertex ..."
			if (slashesCount === 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) {
				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) {
				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 {
				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]);
				}
			}
		};

	RawMesh.prototype.buildFace = function (faceIndexV, faceIndexU, faceIndexN) {
			var sgiu = this.subGroupInUse;
			if (this.disregardNormals) faceIndexN = undefined;
			var scope = this;
			var updateRawObjectDescriptionInUse = function updateRawObjectDescriptionInUse() {
				var faceIndexVi = parseInt(faceIndexV);
				var indexPointerV = 3 * (faceIndexVi > 0 ? faceIndexVi - 1 : faceIndexVi + scope.vertices.length / 3);

				var vertices = sgiu.vertices;
				vertices.push(scope.vertices[indexPointerV++]);
				vertices.push(scope.vertices[indexPointerV++]);
				vertices.push(scope.vertices[indexPointerV]);

				var indexPointerC = scope.colors.length > 0 ? indexPointerV : null;
				if (indexPointerC !== null) {
					var colors = sgiu.colors;
					colors.push(scope.colors[indexPointerC++]);
					colors.push(scope.colors[indexPointerC++]);
					colors.push(scope.colors[indexPointerC]);
				}

				if (faceIndexU) {
					var faceIndexUi = parseInt(faceIndexU);
					var indexPointerU = 2 * (faceIndexUi > 0 ? faceIndexUi - 1 : faceIndexUi + scope.uvs.length / 2);
					var uvs = sgiu.uvs;
					uvs.push(scope.uvs[indexPointerU++]);
					uvs.push(scope.uvs[indexPointerU]);
				}
				if (faceIndexN) {
					var faceIndexNi = parseInt(faceIndexN);
					var indexPointerN = 3 * (faceIndexNi > 0 ? faceIndexNi - 1 : faceIndexNi + scope.normals.length / 3);
					var normals = sgiu.normals;
					normals.push(scope.normals[indexPointerN++]);
					normals.push(scope.normals[indexPointerN++]);
					normals.push(scope.normals[indexPointerN]);
				}
			};

			if (this.useIndices) {
				var mappingName = faceIndexV + (faceIndexU ? '_' + faceIndexU : '_n') + (faceIndexN ? '_' + faceIndexN : '_n');
				var indicesPointer = sgiu.indexMappings[mappingName];
				if (THREE.LoaderSupport.Validator.isValid(indicesPointer)) {
					this.doubleIndicesCount++;
				} else {
					indicesPointer = sgiu.vertices.length / 3;
					updateRawObjectDescriptionInUse();
					sgiu.indexMappings[mappingName] = indicesPointer;
					sgiu.indexMappingsCount++;
				}
				sgiu.indices.push(indicesPointer);
			} else {
				updateRawObjectDescriptionInUse();
			}
			this.faceCount++;
		};

	RawMesh.prototype.processLines = function (buffer, bufferPointer, slashCount) {
			var i = 1;
			var length;
			var bufferLength = bufferPointer - 1;

			if (bufferLength === slashCount * 2) {
				for (length = bufferLength - 2; i < length; i += 2) {
					this.vertices.push(parseInt(buffer[i]));
					this.uvs.push(parseInt(buffer[i + 1]));
				}
			} else {
				for (length = bufferLength - 1; i < length; i++) {
					this.vertices.push(parseInt(buffer[i]));
				}
			}
		};

	RawMesh.prototype.finalize = function () {
			var rawObjectDescriptionsTemp = [];
			var rawObjectDescription;
			var absoluteVertexCount = 0;
			var absoluteIndexMappingsCount = 0;
			var absoluteIndexCount = 0;
			var absoluteColorCount = 0;
			var absoluteNormalCount = 0;
			var absoluteUvCount = 0;
			var indices;
			for (var name in this.subGroups) {
				rawObjectDescription = this.subGroups[name];
				if (rawObjectDescription.vertices.length > 0) {
					indices = rawObjectDescription.indices;
					if (indices.length > 0 && absoluteIndexMappingsCount > 0) {
						for (var i in indices) {
							indices[i] = indices[i] + absoluteIndexMappingsCount;
						}
					}
					rawObjectDescriptionsTemp.push(rawObjectDescription);
					absoluteVertexCount += rawObjectDescription.vertices.length;
					absoluteIndexMappingsCount += rawObjectDescription.indexMappingsCount;
					absoluteIndexCount += rawObjectDescription.indices.length;
					absoluteColorCount += rawObjectDescription.colors.length;
					absoluteUvCount += rawObjectDescription.uvs.length;
					absoluteNormalCount += rawObjectDescription.normals.length;
				}
			}

			// do not continue if no result
			var result = null;
			if (rawObjectDescriptionsTemp.length > 0) {
				result = {
					name: this.groupName !== '' ? this.groupName : this.objectName,
					subGroups: rawObjectDescriptionsTemp,
					absoluteVertexCount: absoluteVertexCount,
					absoluteIndexCount: absoluteIndexCount,
					absoluteColorCount: absoluteColorCount,
					absoluteNormalCount: absoluteNormalCount,
					absoluteUvCount: absoluteUvCount,
					faceCount: this.faceCount,
					doubleIndicesCount: this.doubleIndicesCount
				};
			}
			return result;
		};

	RawMesh.prototype.createReport = function () {
			var report = {
				objectName: this.objectName,
				groupName: this.groupName,
				mtllibName: this.mtllibName,
				vertexCount: this.vertices.length / 3,
				normalCount: this.normals.length / 3,
				uvCount: this.uvs.length / 2,
				smoothingGroupCount: this.smoothingGroupCount,
				mtlCount: this.mtlCount,
				subGroups: this.subGroups.length
			};

			return report;
		};

	return RawMesh;
})();

THREE.LoaderSupport.ObjParser.RawMeshSubGroup = (function () {

	function RawMeshSubGroup(objectName, groupName, materialName, smoothingGroup) {
			this.objectName = objectName;
			this.groupName = groupName;
			this.materialName = materialName;
			this.smoothingGroup = smoothingGroup;
			this._init();
		}

	RawMeshSubGroup.prototype._init = function () {
			this.vertices = [];
			this.indexMappingsCount = 0;
			this.indexMappings = [];
			this.indices = [];
			this.colors = [];
			this.uvs = [];
			this.normals = [];
		};

	return RawMeshSubGroup;
})();

var Parser = THREE.LoaderSupport.ObjParser.Parser;

WorkerRunnerRefImpl = (function () {

	function WorkerRunnerRefImpl() {
		var scope = this;
		var scopedRunner = function scopedRunner(event) {
			scope.processMessage(event.data);
		};
		self.addEventListener('message', scopedRunner, false);
	}

	WorkerRunnerRefImpl.prototype.applyProperties = function (parser, params) {
		var property, funcName, values;
		for (property in params) {
			funcName = 'set' + property.substring(0, 1).toLocaleUpperCase() + property.substring(1);
			values = params[property];

			if (typeof parser[funcName] === 'function') {
				parser[funcName](values);
			} else if (parser.hasOwnProperty(property)) {
				parser[property] = values;
			}
		}
	};

	WorkerRunnerRefImpl.prototype.processMessage = function (payload) {
		var logEnabled = payload.logger.enabled;
		var logDebug = payload.logger.enabled;
		if (payload.cmd === 'run') {
			var callbacks = {
				callbackBuilder: function callbackBuilder(payload) {
					self.postMessage(payload);
				},
				callbackProgress: function callbackProgress(text) {
					if (logEnabled && logDebug) console.debug('WorkerRunner: progress: ' + text);
				}
			};

			// Parser is expected to be named as such
			var parser = new Parser();
			if (typeof parser['setLogConfig'] === 'function') parser.setLogConfig(logEnabled, logDebug);
			this.applyProperties(parser, payload.params);
			this.applyProperties(parser, payload.materials);
			this.applyProperties(parser, callbacks);
			parser.workerScope = self;
			parser.parse(payload.data.input, payload.data.options);

			if (logEnabled) console.log('WorkerRunner: Run complete!');

			callbacks.callbackBuilder({
				cmd: 'complete',
				msg: 'WorkerRunner completed run.'
			});
		} else {
			console.error('WorkerRunner: Received unknown command: ' + payload.cmd);
		}
	};

	return WorkerRunnerRefImpl;
})();

new WorkerRunnerRefImpl();

@poacher2k
Copy link

I'm beginning to realize this might be caused by webpack and not the loader itself.

@kaisalmen
Copy link
Owner

kaisalmen commented Jan 4, 2018

For example the Parser Blob code generated by buildCode with OBJLoader2.min.js (via gulp build) looks like this:

THREE.LoaderSupport.ObjParser.Parser = (function () {

	function e(){this.callbackProgress=null,this.callbackBuilder=null,this.materials={},this.rawMesh=null,this.useAsync=!1,this.materialPerSmoothingGroup=!1,this.useIndices=!1,this.disregardNormals=!1,this.inputObjectCount=1,this.outputObjectCount=1,this.counts={vertices:0,faces:0,doubleIndicesCount:0},this.logger=new THREE.LoaderSupport.ConsoleLogger,this.totalBytes=0}

	e.prototype.setUseAsync = function (e){this.useAsync=e};

	e.prototype.setMaterialPerSmoothingGroup = function (e){this.materialPerSmoothingGroup=e};

	e.prototype.setUseIndices = function (e){this.useIndices=e};

	e.prototype.setDisregardNormals = function (e){this.disregardNormals=e};

	e.prototype.setMaterials = function (e){this.materials=THREE.LoaderSupport.Validator.verifyInput(e,this.materials),this.materials=THREE.LoaderSupport.Validator.verifyInput(this.materials,{})};

	e.prototype.setCallbackBuilder = function (e){if(this.callbackBuilder=e,!THREE.LoaderSupport.Validator.isValid(this.callbackBuilder))throw'Unable to run as no "builder" callback is set.'};

	e.prototype.setCallbackProgress = function (e){this.callbackProgress=e};

	e.prototype.setLogConfig = function (e,t){this.logger.setEnabled(e),this.logger.setDebug(t)};

	e.prototype.configure = function (){if(this.rawMesh=new THREE.LoaderSupport.ObjParser.RawMesh(this.materialPerSmoothingGroup,this.useIndices,this.disregardNormals),this.logger.isEnabled()){var e=Object.keys(this.materials),t="OBJLoader2.Parser configuration:"+(e.length>0?"\n\tmaterialNames:\n\t\t- "+e.join("\n\t\t- "):"\n\tmaterialNames: None")+"\n\tuseAsync: "+this.useAsync+"\n\tmaterialPerSmoothingGroup: "+this.materialPerSmoothingGroup+"\n\tuseIndices: "+this.useIndices+"\n\tdisregardNormals: "+this.disregardNormals+"\n\tcallbackBuilderName: "+this.callbackBuilder.name+"\n\tcallbackProgressName: "+this.callbackProgress.name;this.logger.logInfo(t)}};

	e.prototype.parse = function (e){this.logger.logTimeStart("OBJLoader2.Parser.parse"),this.configure();var t=new Uint8Array(e),r=t.byteLength;this.totalBytes=r;for(var o,s=new Array(128),a=0,i=new Array(16),n=0,l="",u=0;u<r;u++)switch(o=t[u]){case THREE.LoaderSupport.ObjParser.Consts.CODE_SPACE:l.length>0&&(s[a++]=l),i[n++]=0,l="";break;case THREE.LoaderSupport.ObjParser.Consts.CODE_SLASH:l.length>0&&(s[a++]=l),i[n++]=1,l="";break;case THREE.LoaderSupport.ObjParser.Consts.CODE_LF:l.length>0&&(s[a++]=l),l="",this.processLine(s,a,i,n,u),a=0,n=0;break;case THREE.LoaderSupport.ObjParser.Consts.CODE_CR:break;default:l+=String.fromCharCode(o)}this.finalize(u),this.logger.logTimeEnd("OBJLoader2.Parser.parse")};

	e.prototype.parseText = function (e){this.logger.logTimeStart("OBJLoader2.Parser.parseText"),this.configure();var t=e.length;this.totalBytes=t;for(var r,o=new Array(128),s=0,a=new Array(16),i=0,n="",l=0;l<t;l++)switch(r=e[l]){case THREE.LoaderSupport.ObjParser.Consts.STRING_SPACE:n.length>0&&(o[s++]=n),a[i++]=0,n="";break;case THREE.LoaderSupport.ObjParser.Consts.STRING_SLASH:n.length>0&&(o[s++]=n),a[i++]=1,n="";break;case THREE.LoaderSupport.ObjParser.Consts.STRING_LF:n.length>0&&(o[s++]=n),n="",this.processLine(o,s,a,i,l),s=0,i=0;break;case THREE.LoaderSupport.ObjParser.Consts.STRING_CR:break;default:n+=r}this.finalize(l),this.logger.logTimeEnd("OBJLoader2.Parser.parseText")};

	e.prototype.processLine = function (e,t,r,o,s){if(!(t<1)){var a=function(e,t){for(var r=0,o=0;o<t;o++)r+=e[o];return r},i=function(e,t,r){var o="";if(2===t)o=e[1];else{for(var s=t-1,a=1;a<s;a++)o+=e[a]+(0===r[a]?" ":"/");o+=e[s]}return o},n=function(e,t){for(var r=0;r<t;r++)e[r]=""};switch(e[0]){case THREE.LoaderSupport.ObjParser.Consts.LINE_V:this.rawMesh.pushVertex(e,t>4);break;case THREE.LoaderSupport.ObjParser.Consts.LINE_VT:this.rawMesh.pushUv(e);break;case THREE.LoaderSupport.ObjParser.Consts.LINE_VN:this.rawMesh.pushNormal(e);break;case THREE.LoaderSupport.ObjParser.Consts.LINE_F:this.rawMesh.processFaces(e,t,a(r,o));break;case THREE.LoaderSupport.ObjParser.Consts.LINE_L:this.rawMesh.processLines(e,t,a(r,o));break;case THREE.LoaderSupport.ObjParser.Consts.LINE_S:this.rawMesh.pushSmoothingGroup(e[1]),n(e,t);break;case THREE.LoaderSupport.ObjParser.Consts.LINE_G:this.processCompletedMesh(s),this.rawMesh.pushGroup(i(e,t,r)),n(e,t);break;case THREE.LoaderSupport.ObjParser.Consts.LINE_O:this.rawMesh.pushObject(i(e,t,r)),n(e,t);break;case THREE.LoaderSupport.ObjParser.Consts.LINE_MTLLIB:this.rawMesh.pushMtllib(i(e,t,r)),n(e,t);break;case THREE.LoaderSupport.ObjParser.Consts.LINE_USEMTL:this.rawMesh.pushUsemtl(i(e,t,r)),n(e,t)}}};

	e.prototype.createRawMeshReport = function (e,t){var r=e.createReport(t);return"Input Object number: "+t+"\n\tObject name: "+r.objectName+"\n\tGroup name: "+r.groupName+"\n\tMtllib name: "+r.mtllibName+"\n\tVertex count: "+r.vertexCount+"\n\tNormal count: "+r.normalCount+"\n\tUV count: "+r.uvCount+"\n\tSmoothingGroup count: "+r.smoothingGroupCount+"\n\tMaterial count: "+r.mtlCount+"\n\tReal RawMeshSubGroup count: "+r.subGroups};

	e.prototype.processCompletedMesh = function (e){var t=this.rawMesh.finalize();if(THREE.LoaderSupport.Validator.isValid(t)){if(this.rawMesh.colors.length>0&&this.rawMesh.colors.length!==this.rawMesh.vertices.length)throw"Vertex Colors were detected, but vertex count and color count do not match!";this.logger.isDebug()&&this.logger.logDebug(this.createRawMeshReport(this.rawMesh,this.inputObjectCount)),this.inputObjectCount++,this.buildMesh(t,e);var r=e/this.totalBytes;return this.callbackProgress("Completed [o: "+this.rawMesh.objectName+" g:"+this.rawMesh.groupName+"] Total progress: "+(100*r).toFixed(2)+"%",r),this.rawMesh.reset(this.rawMesh.smoothingGroup.splitMaterials),!0}return!1};

	e.prototype.finalize = function (e){if(this.logger.logInfo("Global output object count: "+this.outputObjectCount),this.processCompletedMesh(e)&&this.logger.isEnabled()){var t="Overall counts: \n\tVertices: "+this.counts.vertices+"\n\tFaces: "+this.counts.faces+"\n\tMultiple definitions: "+this.counts.doubleIndicesCount;this.logger.logInfo(t)}};

	e.prototype.buildMesh = function (e,t){var r=e.subGroups,o=new Float32Array(e.absoluteVertexCount);this.counts.vertices+=e.absoluteVertexCount/3,this.counts.faces+=e.faceCount,this.counts.doubleIndicesCount+=e.doubleIndicesCount;var s,a,i,n,l,u,p,h=e.absoluteIndexCount>0?new Uint32Array(e.absoluteIndexCount):null,d=e.absoluteColorCount>0?new Float32Array(e.absoluteColorCount):null,c=e.absoluteNormalCount>0?new Float32Array(e.absoluteNormalCount):null,g=e.absoluteUvCount>0?new Float32Array(e.absoluteUvCount):null,m=THREE.LoaderSupport.Validator.isValid(d),b=[],f=r.length>1,E=0,L=[],v=[],S=0,C=0,T=0,R=0,N=0,y=0,P=0;for(var M in r)if(r.hasOwnProperty(M)){if(s=r[M],p=s.materialName,u=p+(m?"_vertexColor":"")+(0===s.smoothingGroup?"_flat":""),n=this.materials[p],l=this.materials[u],!THREE.LoaderSupport.Validator.isValid(n)&&!THREE.LoaderSupport.Validator.isValid(l)){var I=m?"vertexColorMaterial":"defaultMaterial";n=this.materials[I],this.logger.logWarn('object_group "'+s.objectName+"_"+s.groupName+'" was defined with unresolvable material "'+p+'"! Assigning "'+I+'".'),(p=I)===u&&(l=n,u=I)}if(!THREE.LoaderSupport.Validator.isValid(l)){var O={materialNameOrg:p,materialName:u,materialProperties:{vertexColors:m?2:0,flatShading:0===s.smoothingGroup}},H={cmd:"materialData",materials:{materialCloneInstructions:O}};this.callbackBuilder(H),this.useAsync&&(this.materials[u]=O)}if(f?((a=L[u])||(a=E,L[u]=E,b.push(u),E++),i={start:y,count:P=this.useIndices?s.indices.length:s.vertices.length/3,index:a},v.push(i),y+=P):b.push(u),o.set(s.vertices,S),S+=s.vertices.length,h&&(h.set(s.indices,C),C+=s.indices.length),d&&(d.set(s.colors,T),T+=s.colors.length),c&&(c.set(s.normals,R),R+=s.normals.length),g&&(g.set(s.uvs,N),N+=s.uvs.length),this.logger.isDebug()){var w=THREE.LoaderSupport.Validator.isValid(a)?"\n\t\tmaterialIndex: "+a:"",G="Output Object no.: "+this.outputObjectCount+"\n\t\tgroupName: "+s.groupName+w+"\n\t\tmaterialName: "+s.materialName+"\n\t\tsmoothingGroup: "+s.smoothingGroup+"\n\t\tobjectName: "+s.objectName+"\n\t\t#vertices: "+s.vertices.length/3+"\n\t\t#indices: "+s.indices.length+"\n\t\t#colors: "+s.colors.length/3+"\n\t\t#uvs: "+s.uvs.length/2+"\n\t\t#normals: "+s.normals.length/3;this.logger.logDebug(G)}}this.outputObjectCount++,this.callbackBuilder({cmd:"meshData",progress:{numericalValue:t/this.totalBytes},params:{meshName:e.name},materials:{multiMaterial:f,materialNames:b,materialGroups:v},buffers:{vertices:o,indices:h,colors:d,normals:c,uvs:g}},[o.buffer],THREE.LoaderSupport.Validator.isValid(h)?[h.buffer]:null,THREE.LoaderSupport.Validator.isValid(d)?[d.buffer]:null,THREE.LoaderSupport.Validator.isValid(c)?[c.buffer]:null,THREE.LoaderSupport.Validator.isValid(g)?[g.buffer]:null)};

	return e;
})();

gulp now uses uglifyjs2 as follows: uglify( { mangle: { toplevel: true }

It looks like webpack does not properly minify/uglify things...

Did you also try the gulp build as described in the README?

@poacher2k
Copy link

Verified this was caused by webpack (I'm using ^3.5.5 atm).

Worked around it by adding var Object = window.Object; to the top of OBJLoader2.js

I did indeed build it according to the README. Thank you for trying to help @kaisalmen !

kaisalmen added a commit that referenced this issue Jan 4, 2018
@kaisalmen
Copy link
Owner

I tweaked the package naming a bit and removed unneeded local vars, but I think that's it. I did not see any problems with the new approach (all versions source, bundles (minified & not) work fine). I merged it back to master already. Any feedback is welcome.

@unphased Local vars/objects defined inside OBJLoader2 were destroyed by mangling. I now bound them to a global package. Then the names don't get corrupted. I think it is nicer. I defined the Parser in THREE.LoaderSupport.Parser.Obj. THREE.OBJLoader2 namespace is occupied by the singleton object and therefore I need to move it somewhere else. I don't want to enforce on all users OBJLoader2 a change of constructor. Additionally, THREE.LoaderSupport.Parser could become the home of other parser definitions to be used asynchronously , but that's another topic.

@kaisalmen
Copy link
Owner

I forgot to update MeshSpray. Will do later...

@kaisalmen
Copy link
Owner

Ok, MeshSpray is working again. This is done!

@4zuko
Copy link

4zuko commented Feb 26, 2018

Hi guys. The issue is still present in parser code generated in buildCode function after webpack minification. THREE is renamed to e so as a quick fix I did following:

workerCode += funcBuildSingleton('Parser', Parser).replace(/[a-z](?=\.LoaderSupport)/g, 'THREE');

I am using following versions including the latest version of OBJLoader2 and LoaderSupport:

package.json

{
    ...
    "devDependencies": {
        ...
        "webpack": "^2.7.0",
        "babel-loader": "^6.2.4",
        ...
    },
    scripts: {
        ...
        "dist": "npm run clean && npm run copy && webpack --progress --bail --env dist -p",
        ...
    }
    ...
}

Per documentation I can see that it is possible to override default behaviour using UglifyJsPlugin configuration:

module: {
    ...
    plugins: [new webpack.optimize.UglifyJsPlugin(config)],
    ...
}

Could you please provide me with valid UglifyJsPlugin configuration that should solve this issue?

Thanks!

@kaisalmen
Copy link
Owner

kaisalmen commented Feb 26, 2018

Hi @4zuko, this is the only thing gulp passes to uglify-js:

uglify( { mangle: { toplevel: true } } )

I just check that it still works and it does.
Please let me know what happens when you set:

module: {
    ...
    plugins: [new webpack.optimize.UglifyJsPlugin( { mangle: { toplevel: true } } )],
    ...
}

Thanks

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

4 participants