1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009101010111012101310141015101610171018101910201021102210231024102510261027102810291030103110321033103410351036103710381039104010411042104310441045104610471048104910501051105210531054105510561057105810591060106110621063106410651066106710681069107010711072107310741075107610771078107910801081108210831084108510861087108810891090109110921093109410951096109710981099110011011102110311041105110611071108110911101111111211131114111511161117111811191120112111221123112411251126112711281129113011311132113311341135113611371138113911401141114211431144114511461147114811491150115111521153115411551156115711581159116011611162116311641165116611671168116911701171 |
- /**
- * @author Kai Salmen / https://kaisalmen.de
- * Development repository: https://github.com/kaisalmen/WWOBJLoader
- */
- 'use strict';
- if ( THREE.OBJLoader2 === undefined ) { THREE.OBJLoader2 = {} }
- THREE.OBJLoader2.version = '1.0.6';
- /**
- * OBJ data will be loaded by dynamically created web worker.
- * First feed instructions with: prepareRun
- * Then: Execute with: run
- * @class
- */
- THREE.OBJLoader2.WWOBJLoader2 = (function () {
- function WWOBJLoader2() {
- this._init();
- }
- WWOBJLoader2.prototype._init = function () {
- // check worker support first
- if ( window.Worker === undefined ) throw "This browser does not support web workers!";
- if ( window.Blob === undefined ) throw "This browser does not support Blob!";
- if ( ! typeof window.URL.createObjectURL === 'function' ) throw "This browser does not support Object creation from URL!";
- this.instanceNo = 0;
- this.worker = null;
- this.workerCode = null;
- this.debug = false;
- this.sceneGraphBaseNode = null;
- this.streamMeshes = true;
- this.meshStore = null;
- this.modelName = 'none';
- this.validated = false;
- this.running = false;
- this.requestTerminate = false;
- this.callbacks = {
- progress: null,
- completedLoading: null,
- errorWhileLoading: null,
- materialsLoaded: null,
- meshLoaded: null,
- director: {
- completedLoading: null,
- errorWhileLoading: null
- }
- };
- this.manager = THREE.DefaultLoadingManager;
- this.fileLoader = new THREE.FileLoader( this.manager );
- this.mtlLoader = null;
- this.crossOrigin = null;
- this.dataAvailable = false;
- this.objAsArrayBuffer = null;
- this.fileObj = null;
- this.pathObj = null;
- this.fileMtl = null;
- this.mtlAsString = null;
- this.texturePath = null;
- this.materials = [];
- this.counter = 0;
- };
- /**
- * Set enable or disable debug logging
- * @memberOf THREE.OBJLoader2.WWOBJLoader2
- *
- * @param {boolean} enabled
- */
- WWOBJLoader2.prototype.setDebug = function ( enabled ) {
- this.debug = enabled;
- };
- /**
- * Sets the CORS string to be used.
- * @memberOf THREE.OBJLoader2.WWOBJLoader2
- *
- * @param {string} crossOrigin CORS value
- */
- WWOBJLoader2.prototype.setCrossOrigin = function ( crossOrigin ) {
- this.crossOrigin = crossOrigin;
- };
- /**
- * Register callback function that is invoked by internal function "_announceProgress" to print feedback
- * @memberOf THREE.OBJLoader2.WWOBJLoader2
- *
- * @param {callback} callbackProgress Callback function for described functionality
- */
- WWOBJLoader2.prototype.registerCallbackProgress = function ( callbackProgress ) {
- if ( callbackProgress != null ) this.callbacks.progress = callbackProgress;
- };
- /**
- * Register callback function that is called once loading of the complete model is completed
- * @memberOf THREE.OBJLoader2.WWOBJLoader2
- *
- * @param {callback} callbackCompletedLoading Callback function for described functionality
- */
- WWOBJLoader2.prototype.registerCallbackCompletedLoading = function ( callbackCompletedLoading ) {
- if ( callbackCompletedLoading != null ) this.callbacks.completedLoading = callbackCompletedLoading;
- };
- /**
- * Register callback function that is called once materials have been loaded. It allows to alter and return materials
- * @memberOf THREE.OBJLoader2.WWOBJLoader2
- *
- * @param {callback} callbackMaterialsLoaded Callback function for described functionality
- */
- WWOBJLoader2.prototype.registerCallbackMaterialsLoaded = function ( callbackMaterialsLoaded ) {
- if ( callbackMaterialsLoaded != null ) this.callbacks.materialsLoaded = callbackMaterialsLoaded;
- };
- /**
- * Register callback function that is called every time a mesh was loaded
- * @memberOf THREE.OBJLoader2.WWOBJLoader2
- *
- * @param {callback} callbackMeshLoaded Callback function for described functionality
- */
- WWOBJLoader2.prototype.registerCallbackMeshLoaded = function ( callbackMeshLoaded ) {
- if ( callbackMeshLoaded != null ) this.callbacks.meshLoaded = callbackMeshLoaded;
- };
- /**
- * Report if an error prevented loading
- * @memberOf THREE.OBJLoader2.WWOBJLoader2
- *
- * @param {callback} callbackErrorWhileLoading Callback function for described functionality
- */
- WWOBJLoader2.prototype.registerCallbackErrorWhileLoading = function ( callbackErrorWhileLoading ) {
- if ( callbackErrorWhileLoading != null ) this.callbacks.errorWhileLoading = callbackErrorWhileLoading;
- };
- /**
- * Call requestTerminate to terminate the web worker and free local resource after execution
- * @memberOf THREE.OBJLoader2.WWOBJLoader2
- *
- * @param {boolean} requestTerminate
- */
- WWOBJLoader2.prototype.setRequestTerminate = function ( requestTerminate ) {
- this.requestTerminate = ( requestTerminate != null && requestTerminate ) ? true : false;
- };
- WWOBJLoader2.prototype._validate = function () {
- if ( this.validated ) return;
- if ( this.worker == null ) {
- this._buildWebWorkerCode();
- var blob = new Blob( [ this.workerCode ], { type: 'text/plain' } );
- this.worker = new Worker( window.URL.createObjectURL( blob ) );
- var scope = this;
- var scopeFunction = function ( e ) {
- scope._receiveWorkerMessage( e );
- };
- this.worker.addEventListener( 'message', scopeFunction, false );
- }
- this.sceneGraphBaseNode = null;
- this.streamMeshes = true;
- this.meshStore = [];
- this.modelName = 'none';
- this.validated = true;
- this.running = true;
- this.requestTerminate = false;
- this.fileLoader = ( this.fileLoader == null ) ? new THREE.FileLoader( this.manager ) : this.fileLoader;
- this.mtlLoader = ( this.mtlLoader == null ) ? new THREE.MTLLoader() : this.mtlLoader;
- if ( this.crossOrigin != null ) this.mtlLoader.setCrossOrigin( this.crossOrigin );
- this.dataAvailable = false;
- this.fileObj = null;
- this.pathObj = null;
- this.fileMtl = null;
- this.texturePath = null;
- this.objAsArrayBuffer = null;
- this.mtlAsString = null;
- this.materials = [];
- var defaultMaterial = new THREE.MeshStandardMaterial( { color: 0xDCF1FF } );
- defaultMaterial.name = 'defaultMaterial';
- this.materials[ defaultMaterial.name ] = defaultMaterial;
- this.counter = 0;
- };
- /**
- * Set all parameters for required for execution of "run".
- * @memberOf THREE.OBJLoader2.WWOBJLoader2
- *
- * @param {Object} params Either {@link THREE.OBJLoader2.WWOBJLoader2.PrepDataArrayBuffer} or {@link THREE.OBJLoader2.WWOBJLoader2.PrepDataFile}
- */
- WWOBJLoader2.prototype.prepareRun = function ( params ) {
- this._validate();
- this.dataAvailable = params.dataAvailable;
- this.modelName = params.modelName;
- console.time( 'WWOBJLoader2' );
- if ( this.dataAvailable ) {
- // fast-fail on bad type
- if ( ! params.objAsArrayBuffer instanceof Uint8Array ) {
- throw 'Provided input is not of type arraybuffer! Aborting...';
- }
- this.worker.postMessage( {
- cmd: 'init',
- debug: this.debug
- } );
- this.objAsArrayBuffer = params.objAsArrayBuffer;
- this.mtlAsString = params.mtlAsString;
- } else {
- // fast-fail on bad type
- if ( ! ( typeof( params.fileObj ) === 'string' || params.fileObj instanceof String ) ) {
- throw 'Provided file is not properly defined! Aborting...';
- }
- this.worker.postMessage( {
- cmd: 'init',
- debug: this.debug
- } );
- this.fileObj = params.fileObj;
- this.pathObj = params.pathObj;
- this.fileMtl = params.fileMtl;
- }
- this.setRequestTerminate( params.requestTerminate );
- this.pathTexture = params.pathTexture;
- this.sceneGraphBaseNode = params.sceneGraphBaseNode;
- this.streamMeshes = params.streamMeshes;
- if ( ! this.streamMeshes ) this.meshStore = [];
- };
- /**
- * Run the loader according the preparation instruction provided in "prepareRun".
- * @memberOf THREE.OBJLoader2.WWOBJLoader2
- */
- WWOBJLoader2.prototype.run = function () {
- var scope = this;
- var processLoadedMaterials = function ( materialCreator ) {
- var materialCreatorMaterials = [];
- var materialNames = [];
- if ( materialCreator != null ) {
- materialCreator.preload();
- materialCreatorMaterials = materialCreator.materials;
- for ( var materialName in materialCreatorMaterials ) {
- if ( materialCreatorMaterials.hasOwnProperty( materialName ) ) {
- materialNames.push( materialName );
- scope.materials[ materialName ] = materialCreatorMaterials[ materialName ];
- }
- }
- }
- scope.worker.postMessage( {
- cmd: 'setMaterials',
- materialNames: materialNames
- } );
- if ( scope.callbacks.materialsLoaded != null ) {
- var materialsCallback = scope.callbacks.materialsLoaded( scope.materials );
- if ( materialsCallback != null ) scope.materials = materialsCallback;
- }
- if ( scope.dataAvailable && scope.objAsArrayBuffer ) {
- scope.worker.postMessage({
- cmd: 'run',
- objAsArrayBuffer: scope.objAsArrayBuffer
- }, [ scope.objAsArrayBuffer.buffer ] );
- } else {
- var refPercentComplete = 0;
- var percentComplete = 0;
- var output;
- var onLoad = function ( objAsArrayBuffer ) {
- scope._announceProgress( 'Running web worker!' );
- scope.objAsArrayBuffer = new Uint8Array( objAsArrayBuffer );
- scope.worker.postMessage( {
- cmd: 'run',
- objAsArrayBuffer: scope.objAsArrayBuffer
- }, [ scope.objAsArrayBuffer.buffer ] );
- };
- var onProgress = function ( event ) {
- if ( ! event.lengthComputable ) return;
- percentComplete = Math.round( event.loaded / event.total * 100 );
- if ( percentComplete > refPercentComplete ) {
- refPercentComplete = percentComplete;
- output = 'Download of "' + scope.fileObj + '": ' + percentComplete + '%';
- console.log( output );
- scope._announceProgress( output );
- }
- };
- var onError = function ( event ) {
- output = 'Error occurred while downloading "' + scope.fileObj + '"';
- console.error( output + ': ' + event );
- scope._announceProgress( output );
- scope._finalize( 'error' );
- };
- scope.fileLoader.setPath( scope.pathObj );
- scope.fileLoader.setResponseType( 'arraybuffer' );
- scope.fileLoader.load( scope.fileObj, onLoad, onProgress, onError );
- }
- console.timeEnd( 'Loading MTL textures' );
- };
- this.mtlLoader.setPath( this.pathTexture );
- if ( this.dataAvailable ) {
- processLoadedMaterials( ( this.mtlAsString != null ) ? this.mtlLoader.parse( this.mtlAsString ) : null );
- } else {
- if ( this.fileMtl == null ) {
- processLoadedMaterials();
- } else {
- this.mtlLoader.load( this.fileMtl, processLoadedMaterials );
- }
- }
- };
- WWOBJLoader2.prototype._receiveWorkerMessage = function ( event ) {
- var payload = event.data;
- switch ( payload.cmd ) {
- case 'objData':
- this.counter ++;
- var bufferGeometry = new THREE.BufferGeometry();
- bufferGeometry.addAttribute( 'position', new THREE.BufferAttribute( new Float32Array( payload.vertices ), 3 ) );
- if ( payload.normals !== null ) {
- bufferGeometry.addAttribute( 'normal', new THREE.BufferAttribute( new Float32Array( payload.normals ), 3 ) );
- } else {
- bufferGeometry.computeVertexNormals();
- }
- if ( payload.uvs !== null ) {
- bufferGeometry.addAttribute( 'uv', new THREE.BufferAttribute( new Float32Array( payload.uvs ), 2 ) );
- }
- var materialDescriptions = payload.materialDescriptions;
- var materialDescription;
- var material;
- var materialName;
- var createMultiMaterial = payload.multiMaterial;
- var multiMaterials = [];
- for ( var key in materialDescriptions ) {
- materialDescription = materialDescriptions[ key ];
- material = this.materials[ materialDescription.name ];
- if ( materialDescription.default ) {
- material = this.materials[ 'defaultMaterial' ];
- } else if ( materialDescription.clone ) {
- materialName = material.name + '_flat';
- var materialClone = this.materials[ materialName ];
- if ( ! materialClone ) {
- materialClone = material.clone();
- materialClone.name = materialName;
- materialClone.shading = THREE.FlatShading;
- this.materials[ materialName ] = name;
- }
- } else if ( ! material ) {
- material = this.materials[ 'defaultMaterial' ];
- }
- if ( createMultiMaterial ) multiMaterials.push( material );
- }
- if ( createMultiMaterial ) {
- material = new THREE.MultiMaterial( multiMaterials );
- var materialGroups = payload.materialGroups;
- var materialGroup;
- for ( var key in materialGroups ) {
- materialGroup = materialGroups[ key ];
- bufferGeometry.addGroup( materialGroup.start, materialGroup.count, materialGroup.index );
- }
- }
- if ( this.callbacks.meshLoaded !== null ) {
- var materialOverride = this.callbacks.meshLoaded( payload.meshName, material );
- if ( materialOverride != null ) material = materialOverride;
- }
- var mesh = new THREE.Mesh( bufferGeometry, material );
- mesh.name = payload.meshName;
- if ( this.streamMeshes ) {
- this.sceneGraphBaseNode.add( mesh );
- } else {
- this.meshStore.push( mesh );
- }
- var output = '(' + this.counter + '): ' + payload.meshName;
- this._announceProgress( 'Adding mesh', output );
- break;
- case 'complete':
- if ( ! this.streamMeshes ) {
- for ( var key in this.meshStore ) {
- this.sceneGraphBaseNode.add( this.meshStore[ key ] );
- }
- }
- console.timeEnd( 'WWOBJLoader2' );
- if ( payload.msg != null ) {
- this._announceProgress( payload.msg );
- } else {
- this._announceProgress( '' );
- }
- this._finalize( 'complete' );
- break;
- case 'report_progress':
- this._announceProgress( '', payload.output );
- break;
- default:
- console.error( 'Received unknown command: ' + payload.cmd );
- break;
- }
- };
- WWOBJLoader2.prototype._terminate = function () {
- if ( this.worker != null ) {
- if ( this.running ) throw 'Unable to gracefully terminate worker as it is currently running!';
- this.worker.terminate();
- this.worker = null;
- this.workerCode = null;
- this._finalize( 'terminate' );
- }
- this.fileLoader = null;
- this.mtlLoader = null;
- };
- WWOBJLoader2.prototype._finalize = function ( reason, requestTerminate ) {
- this.running = false;
- if ( reason === 'complete' ) {
- if ( this.callbacks.completedLoading != null ) this.callbacks.completedLoading( this.modelName, this.instanceNo, this.requestTerminate );
- if ( this.callbacks.director.completedLoading != null ) this.callbacks.director.completedLoading( this.modelName, this.instanceNo, this.requestTerminate );
- } else if ( reason === 'error' ) {
- if ( this.callbacks.errorWhileLoading != null ) this.callbacks.errorWhileLoading( this.modelName, this.instanceNo, this.requestTerminate );
- if ( this.callbacks.director.errorWhileLoading != null ) this.callbacks.director.errorWhileLoading( this.modelName, this.instanceNo, this.requestTerminate );
- }
- this.validated = false;
- this.setRequestTerminate( requestTerminate );
- if ( this.requestTerminate ) {
- this._terminate();
- }
- };
- WWOBJLoader2.prototype._announceProgress = function ( baseText, text ) {
- var output = "";
- if ( baseText !== null && baseText !== undefined ) {
- output = baseText;
- }
- if ( text !== null && text !== undefined ) {
- output = output + " " + text;
- }
- if ( this.callbacks.progress !== null ) {
- this.callbacks.progress( output );
- }
- if ( this.debug ) {
- console.log( output );
- }
- };
- WWOBJLoader2.prototype._buildWebWorkerCode = function ( existingWorkerCode ) {
- if ( existingWorkerCode != null ) this.workerCode = existingWorkerCode;
- if ( this.workerCode == null ) {
- console.time( 'buildWebWorkerCode' );
- var wwDef = (function () {
- function OBJLoader() {
- this.meshCreator = new MeshCreator();
- this.parser = new Parser( this.meshCreator );
- this.validated = false;
- this.cmdState = 'created';
- this.debug = false;
- }
- /**
- * Allows to set debug mode for the parser and the meshCreatorDebug
- *
- * @param parserDebug
- * @param meshCreatorDebug
- */
- OBJLoader.prototype._setDebug = function ( parserDebug, meshCreatorDebug ) {
- this.parser._setDebug( parserDebug );
- this.meshCreator._setDebug( meshCreatorDebug );
- };
- /**
- * Validate status, then parse arrayBuffer, finalize and return objGroup
- *
- * @param arrayBuffer
- */
- OBJLoader.prototype.parse = function ( arrayBuffer ) {
- console.log( 'Parsing arrayBuffer...' );
- console.time( 'parseArrayBuffer' );
- this._validate();
- this.parser.parseArrayBuffer( arrayBuffer );
- var objGroup = this._finalize();
- console.timeEnd( 'parseArrayBuffer' );
- return objGroup;
- };
- OBJLoader.prototype._validate = function () {
- if ( this.validated ) return;
- this.parser._validate();
- this.meshCreator._validate();
- this.validated = true;
- };
- OBJLoader.prototype._finalize = function () {
- console.log( 'Global output object count: ' + this.meshCreator.globalObjectCount );
- this.parser._finalize();
- this.meshCreator._finalize();
- this.validated = false;
- };
- OBJLoader.prototype.init = function ( payload ) {
- this.cmdState = 'init';
- this._setDebug( payload.debug, payload.debug );
- };
- OBJLoader.prototype.setMaterials = function ( payload ) {
- this.cmdState = 'setMaterials';
- this.meshCreator._setMaterials( payload.materialNames );
- };
- OBJLoader.prototype.run = function ( payload ) {
- this.cmdState = 'run';
- this.parse( payload.objAsArrayBuffer );
- console.log( 'OBJ loading complete!' );
- this.cmdState = 'complete';
- self.postMessage( {
- cmd: this.cmdState,
- msg: null
- } );
- };
- return OBJLoader;
- })();
- var wwMeshCreatorDef = (function () {
- function MeshCreator() {
- this.materials = null;
- this.debug = false;
- this.globalObjectCount = 1;
- this.validated = false;
- }
- MeshCreator.prototype._setMaterials = function ( materials ) {
- this.materials = ( materials == null ) ? ( this.materials == null ? { materials: [] } : this.materials ) : materials;
- };
- MeshCreator.prototype._setDebug = function ( debug ) {
- this.debug = ( debug == null ) ? this.debug : debug;
- };
- MeshCreator.prototype._validate = function () {
- if ( this.validated ) return;
- this._setMaterials( null );
- this._setDebug( null );
- this.globalObjectCount = 1;
- };
- MeshCreator.prototype._finalize = function () {
- this.materials = null;
- this.validated = false;
- };
- /**
- * RawObjectDescriptions are transformed to THREE.Mesh.
- * It is ensured that rawObjectDescriptions only contain objects with vertices (no need to check).
- *
- * @param rawObjectDescriptions
- * @param inputObjectCount
- * @param absoluteVertexCount
- * @param absoluteNormalCount
- * @param absoluteUvCount
- */
- MeshCreator.prototype._buildMesh = function ( rawObjectDescriptions, inputObjectCount, absoluteVertexCount, absoluteNormalCount, absoluteUvCount ) {
- if ( this.debug ) console.log( 'OBJLoader.buildMesh:\nInput object no.: ' + inputObjectCount );
- var vertexFa = new Float32Array( absoluteVertexCount );
- var normalFA = ( absoluteNormalCount > 0 ) ? new Float32Array( absoluteNormalCount ) : null;
- var uvFA = ( absoluteUvCount > 0 ) ? new Float32Array( absoluteUvCount ) : null;
- var rawObjectDescription;
- var materialDescription;
- var materialDescriptions = [];
- var createMultiMaterial = ( rawObjectDescriptions.length > 1 );
- var materialIndex = 0;
- var materialIndexMapping = [];
- var selectedMaterialIndex;
- var materialGroup;
- var materialGroups = [];
- var vertexBAOffset = 0;
- var vertexGroupOffset = 0;
- var vertexLength;
- var normalOffset = 0;
- var uvOffset = 0;
- for ( var oodIndex in rawObjectDescriptions ) {
- rawObjectDescription = rawObjectDescriptions[ oodIndex ];
- materialDescription = { name: rawObjectDescription.materialName, flat: false, default: false };
- if ( this.materials[ materialDescription.name ] === null ) {
- materialDescription.default = true;
- console.warn( 'object_group "' + rawObjectDescription.objectName + '_' + rawObjectDescription.groupName + '" was defined without material! Assigning "defaultMaterial".' );
- }
- // Attach '_flat' to materialName in case flat shading is needed due to smoothingGroup 0
- if ( rawObjectDescription.smoothingGroup === 0 ) materialDescription.flat = true;
- vertexLength = rawObjectDescription.vertices.length;
- if ( createMultiMaterial ) {
- // re-use material if already used before. Reduces materials array size and eliminates duplicates
- selectedMaterialIndex = materialIndexMapping[ materialDescription.name ];
- if ( ! selectedMaterialIndex ) {
- selectedMaterialIndex = materialIndex;
- materialIndexMapping[ materialDescription.name ] = materialIndex;
- materialDescriptions.push( materialDescription );
- materialIndex++;
- }
- materialGroup = {
- start: vertexGroupOffset,
- count: vertexLength / 3,
- index: selectedMaterialIndex
- };
- materialGroups.push( materialGroup );
- vertexGroupOffset += vertexLength / 3;
- } else {
- materialDescriptions.push( materialDescription );
- }
- vertexFa.set( rawObjectDescription.vertices, vertexBAOffset );
- vertexBAOffset += vertexLength;
- if ( normalFA ) {
- normalFA.set( rawObjectDescription.normals, normalOffset );
- normalOffset += rawObjectDescription.normals.length;
- }
- if ( uvFA ) {
- uvFA.set( rawObjectDescription.uvs, uvOffset );
- uvOffset += rawObjectDescription.uvs.length;
- }
- if ( this.debug ) this.printReport( rawObjectDescription, selectedMaterialIndex );
- }
- self.postMessage( {
- cmd: 'objData',
- meshName: rawObjectDescription.objectName,
- multiMaterial: createMultiMaterial,
- materialDescriptions: materialDescriptions,
- materialGroups: materialGroups,
- vertices: vertexFa,
- normals: normalFA,
- uvs: uvFA
- }, [ vertexFa.buffer ], normalFA !== null ? [ normalFA.buffer ] : null, uvFA !== null ? [ uvFA.buffer ] : null );
- this.globalObjectCount++;
- };
- return MeshCreator;
- })();
- var wwLoaderRunnerDef = (function () {
- function OBJLoaderRunner() {
- self.addEventListener( 'message', this.runner, false );
- }
- OBJLoaderRunner.prototype.runner = function ( event ) {
- var payload = event.data;
- console.log( 'Command state before: ' + OBJLoaderRef.cmdState );
- switch ( payload.cmd ) {
- case 'init':
- OBJLoaderRef.init( payload );
- break;
- case 'setMaterials':
- OBJLoaderRef.setMaterials( payload );
- break;
- case 'run':
- OBJLoaderRef.run( payload );
- break;
- default:
- console.error( 'OBJLoader: Received unknown command: ' + payload.cmd );
- break;
- }
- console.log( 'Command state after: ' + OBJLoaderRef.cmdState );
- };
- return OBJLoaderRunner;
- })();
- var buildObject = function ( fullName, object ) {
- var objectString = fullName + ' = {\n';
- var part;
- for ( var name in object ) {
- part = object[ name ];
- if ( typeof( part ) === 'string' || part instanceof String ) {
- part = part.replace( '\n', '\\n' );
- part = part.replace( '\r', '\\r' );
- objectString += '\t' + name + ': "' + part + '",\n';
- } else if ( part instanceof Array ) {
- objectString += '\t' + name + ': [' + part + '],\n';
- } else if ( Number.isInteger( part ) ) {
- objectString += '\t' + name + ': ' + part + ',\n';
- } else if ( typeof part === 'function' ) {
- objectString += '\t' + name + ': ' + part + ',\n';
- }
- }
- objectString += '}\n\n';
- return objectString;
- };
- var buildSingelton = function ( fullName, internalName, object ) {
- var objectString = fullName + ' = (function () {\n\n';
- objectString += '\t' + object.prototype.constructor.toString() + '\n\n';
- var funcString;
- var objectPart;
- for ( var name in object.prototype ) {
- objectPart = object.prototype[ name ];
- if ( typeof objectPart === 'function' ) {
- funcString = objectPart.toString();
- objectString += '\t' + internalName + '.prototype.' + name + ' = ' + funcString + ';\n\n';
- }
- }
- objectString += '\treturn ' + internalName + ';\n';
- objectString += '})();\n\n';
- return objectString;
- };
- this.workerCode = '';
- this.workerCode += '/**\n';
- this.workerCode += ' * This code was constructed by WWOBJLoader2._buildWebWorkerCode\n';
- this.workerCode += ' */\n\n';
- // parser re-construction
- var objLoaderHelper = new THREE.OBJLoader2();
- this.workerCode += objLoaderHelper._buildWebWorkerCode( buildObject, buildSingelton );
- // web worker construction
- this.workerCode += buildSingelton( 'OBJLoader', 'OBJLoader', wwDef );
- this.workerCode += buildSingelton( 'MeshCreator', 'MeshCreator', wwMeshCreatorDef );
- this.workerCode += 'OBJLoaderRef = new OBJLoader();\n\n';
- this.workerCode += buildSingelton( 'OBJLoaderRunner', 'OBJLoaderRunner', wwLoaderRunnerDef );
- this.workerCode += 'new OBJLoaderRunner();\n\n';
- console.timeEnd( 'buildWebWorkerCode' );
- }
- return this.workerCode;
- };
- return WWOBJLoader2;
- })();
- /**
- * Instruction to configure {@link THREE.OBJLoader2.WWOBJLoader2}.prepareRun to load OBJ from given ArrayBuffer and MTL from given String
- *
- * @param {string} modelName Overall name of the model
- * @param {Uint8Array} objAsArrayBuffer OBJ file content as ArrayBuffer
- * @param {string} pathTexture Path to texture files
- * @param {string} mtlAsString MTL file content as string
- * @param {THREE.Object3D} sceneGraphBaseNode {@link THREE.Object3D} where meshes will be attached
- * @param {boolean} streamMeshes=true Singles meshes are directly integrated into scene when loaded or later
- * @param {boolean} [requestTerminate=false] Request termination of web worker and free local resources after execution
- *
- * @returns {{modelName: string, dataAvailable: boolean, objAsArrayBuffer: null, pathTexture: null, mtlAsString: null, sceneGraphBaseNode: null, streamMeshes: boolean, requestTerminate: boolean}}
- * @constructor
- */
- THREE.OBJLoader2.WWOBJLoader2.PrepDataArrayBuffer = function ( modelName, objAsArrayBuffer, pathTexture, mtlAsString, sceneGraphBaseNode, streamMeshes, requestTerminate ) {
- var data = {
- modelName: ( modelName == null ) ? 'none' : modelName,
- dataAvailable: true,
- objAsArrayBuffer: ( objAsArrayBuffer == null ) ? null : objAsArrayBuffer,
- pathTexture: ( pathTexture == null ) ? null : pathTexture,
- mtlAsString: ( mtlAsString == null ) ? null : mtlAsString,
- sceneGraphBaseNode: ( sceneGraphBaseNode == null ) ? null : sceneGraphBaseNode,
- streamMeshes: ( streamMeshes == null ) ? true : streamMeshes,
- requestTerminate: ( requestTerminate == null ) ? false : requestTerminate
- };
- return data;
- };
- /**
- * Instruction to configure {@link THREE.OBJLoader2.WWOBJLoader2}.prepareRun to load OBJ and MTL from files
- *
- * @param {string} modelName Overall name of the model
- * @param {string} pathObj Path to OBJ file
- * @param {string} fileObj OBJ file name
- * @param {string} pathTexture Path to texture files
- * @param {string} fileMtl MTL file name
- * @param {THREE.Object3D} sceneGraphBaseNode {@link THREE.Object3D} where meshes will be attached
- * @param {boolean} streamMeshes=true Singles meshes are directly integrated into scene when loaded or later
- * @param {boolean} [requestTerminate=false] Request termination of web worker and free local resources after execution
- *
- * @returns {{modelName: string, dataAvailable: boolean, pathObj: null, fileObj: null, pathTexture: null, fileMtl: null, sceneGraphBaseNode: null, streamMeshes: boolean, requestTerminate: boolean}}
- * @constructor
- */
- THREE.OBJLoader2.WWOBJLoader2.PrepDataFile = function ( modelName, pathObj, fileObj, pathTexture, fileMtl, sceneGraphBaseNode, streamMeshes, requestTerminate ) {
- var data = {
- modelName: ( modelName == null ) ? 'none' : modelName,
- dataAvailable: false,
- pathObj: ( pathObj == null ) ? null : pathObj,
- fileObj: ( fileObj == null ) ? null : fileObj,
- pathTexture: ( pathTexture == null ) ? null : pathTexture,
- fileMtl: ( fileMtl == null ) ? null : fileMtl,
- sceneGraphBaseNode: ( sceneGraphBaseNode == null ) ? null : sceneGraphBaseNode,
- streamMeshes: ( streamMeshes == null ) ? true : streamMeshes,
- requestTerminate: ( requestTerminate == null ) ? false : requestTerminate
- };
- return data;
- };
- /**
- * Orchestrate loading of multiple OBJ files/data from an instruction queue with a configurable amount of workers (1-16).
- * Use:
- * prepareWorkers
- * enqueueForRun
- * processQueue
- * deregister
- *
- * @class
- */
- THREE.OBJLoader2.WWOBJLoader2Director = (function () {
- var MAX_WEB_WORKER = 16;
- var MAX_QUEUE_SIZE = 1024;
- function WWOBJLoader2Director() {
- this.maxQueueSize = MAX_QUEUE_SIZE ;
- this.maxWebWorkers = MAX_WEB_WORKER;
- this.crossOrigin = null;
- this.workerDescription = {
- prototypeDef: THREE.OBJLoader2.WWOBJLoader2.prototype,
- callbacks: {},
- webWorkers: [],
- codeBuffer: null
- };
- this.objectsCompleted = 0;
- this.instructionQueue = [];
- }
- /**
- * Returns the maximum length of the instruction queue.
- * @memberOf THREE.OBJLoader2.WWOBJLoader2Director
- *
- * @returns {number}
- */
- WWOBJLoader2Director.prototype.getMaxQueueSize = function () {
- return this.maxQueueSize;
- };
- /**
- * Returns the maximum number of workers.
- * @memberOf THREE.OBJLoader2.WWOBJLoader2Director
- *
- * @returns {number}
- */
- WWOBJLoader2Director.prototype.getMaxWebWorkers = function () {
- return this.maxWebWorkers;
- };
- /**
- * Sets the CORS string to be used.
- * @memberOf THREE.OBJLoader2.WWOBJLoader2Director
- *
- * @param {string} crossOrigin CORS value
- */
- WWOBJLoader2Director.prototype.setCrossOrigin = function ( crossOrigin ) {
- this.crossOrigin = crossOrigin;
- };
- /**
- * Create or destroy workers according limits. Set the name and register callbacks for dynamically created web workers.
- * @memberOf THREE.OBJLoader2.WWOBJLoader2Director
- *
- * @param {callback[]} callbacks Register callbacks for all web workers:
- * { progress: null, completedLoading: null, errorWhileLoading: null, materialsLoaded: null, meshLoaded: null }
- * @param {number} maxQueueSize Set the maximum size of the instruction queue (1-1024)
- * @param {number} maxWebWorkers Set the maximum amount of workers (1-16)
- */
- WWOBJLoader2Director.prototype.prepareWorkers = function ( callbacks, maxQueueSize, maxWebWorkers ) {
- if ( callbacks != null ) {
- for ( var key in callbacks ) {
- if ( callbacks.hasOwnProperty( key ) ) this.workerDescription.callbacks[ key ] = callbacks[ key ];
- }
- }
- this.maxQueueSize = Math.min( maxQueueSize, MAX_QUEUE_SIZE );
- this.maxWebWorkers = Math.min( maxWebWorkers, MAX_WEB_WORKER );
- this.objectsCompleted = 0;
- this.instructionQueue = [];
- var start = this.workerDescription.webWorkers.length;
- if ( start < this.maxWebWorkers ) {
- for ( i = start; i < this.maxWebWorkers; i ++ ) {
- webWorker = this._buildWebWorker();
- this.workerDescription.webWorkers[ i ] = webWorker;
- }
- } else {
- for ( var webWorker, i = start - 1; i >= this.maxWebWorkers; i-- ) {
- webWorker = this.workerDescription.webWorkers[ i ];
- webWorker.setRequestTerminate( true );
- this.workerDescription.webWorkers.pop();
- }
- }
- };
- /**
- * Store run instructions in internal instructionQueue
- * @memberOf THREE.OBJLoader2.WWOBJLoader2Director
- *
- * @param {Object} params Either {@link THREE.OBJLoader2.WWOBJLoader2.PrepDataArrayBuffer} or {@link THREE.OBJLoader2.WWOBJLoader2.PrepDataFile}
- */
- WWOBJLoader2Director.prototype.enqueueForRun = function ( runParams ) {
- if ( this.instructionQueue.length < this.maxQueueSize ) {
- this.instructionQueue.push( runParams );
- }
- };
- /**
- * Process the instructionQueue until it is depleted
- * @memberOf THREE.OBJLoader2.WWOBJLoader2Director
- */
- WWOBJLoader2Director.prototype.processQueue = function () {
- if ( this.instructionQueue.length === 0 ) return;
- var webWorker;
- var runParams;
- var length = Math.min( this.maxWebWorkers, this.instructionQueue.length );
- for ( var i = 0; i < length; i++ ) {
- webWorker = this.workerDescription.webWorkers[ i ];
- runParams = this.instructionQueue[ 0 ];
- webWorker.prepareRun( runParams );
- webWorker.run();
- this.instructionQueue.shift();
- }
- };
- WWOBJLoader2Director.prototype._buildWebWorker = function () {
- var webWorker = Object.create( this.workerDescription.prototypeDef );
- webWorker._init();
- if ( this.crossOrigin != null ) webWorker.setCrossOrigin( this.crossOrigin );
- // Ensure code string is built once and then it is just passed on to every new instance
- if ( this.workerDescription.codeBuffer == null ) {
- this.workerDescription.codeBuffer = webWorker._buildWebWorkerCode();
- } else {
- webWorker._buildWebWorkerCode( this.workerDescription.codeBuffer );
- }
- for ( var key in this.workerDescription.callbacks ) {
- if ( webWorker.callbacks.hasOwnProperty( key ) && this.workerDescription.callbacks.hasOwnProperty( key ) ) {
- webWorker.callbacks[ key ] = this.workerDescription.callbacks[ key ];
- }
- }
- var scope = this;
- var managerCompletedLoading = function ( modelName, instanceNo, requestTerminate ) {
- scope.objectsCompleted++;
- if ( ! requestTerminate ) {
- var rekick = scope.workerDescription.webWorkers[ instanceNo ];
- var runParams = scope.instructionQueue[ 0 ];
- if ( runParams != null ) {
- rekick.prepareRun( runParams );
- rekick.run();
- scope.instructionQueue.shift();
- }
- }
- };
- webWorker.callbacks.director[ 'completedLoading' ] = managerCompletedLoading;
- webWorker.instanceNo = this.workerDescription.webWorkers.length;
- this.workerDescription.webWorkers.push( webWorker );
- return webWorker;
- };
- /**
- * Terminate all workers
- * @memberOf THREE.OBJLoader2.WWOBJLoader2Director
- */
- WWOBJLoader2Director.prototype.deregister = function () {
- console.log( 'WWOBJLoader2Director received the unregister call. Terminating all workers!' );
- for ( var i = 0, webWorker, length = this.workerDescription.webWorkers.length; i < length; i++ ) {
- webWorker = this.workerDescription.webWorkers[ i ];
- webWorker.setRequestTerminate( true );
- }
- this.workerDescription.callbacks = {};
- this.workerDescription.webWorkers = [];
- this.workerDescription.codeBuffer = null;
- };
- return WWOBJLoader2Director;
- })();
|