diff --git a/examples/js/loaders/OBJLoader2.js b/examples/js/loaders/OBJLoader2.js index ee2ea9ccbc8beb..3a80389f82afb2 100644 --- a/examples/js/loaders/OBJLoader2.js +++ b/examples/js/loaders/OBJLoader2.js @@ -6,7 +6,7 @@ 'use strict'; if ( THREE.OBJLoader2 === undefined ) { THREE.OBJLoader2 = {} } -THREE.OBJLoader2.version = '1.0.4'; +THREE.OBJLoader2.version = '1.0.5'; /** * Use this class to load OBJ data from files or to parse OBJ data from arraybuffer or text @@ -505,7 +505,7 @@ THREE.OBJLoader2 = (function () { RawObject.prototype._buildIndex = function ( materialName, smoothingGroup) { return materialName + '|' + smoothingGroup; - } + }; RawObject.prototype._newInstanceFromObject = function ( objectName, groupName ) { var newRawObject = new RawObject( objectName, groupName, this.mtllibName ); diff --git a/examples/js/loaders/WWOBJLoader2.js b/examples/js/loaders/WWOBJLoader2.js index b5bfd269bf2741..bc5a0dcaa43c19 100644 --- a/examples/js/loaders/WWOBJLoader2.js +++ b/examples/js/loaders/WWOBJLoader2.js @@ -6,7 +6,7 @@ 'use strict'; if ( THREE.OBJLoader2 === undefined ) { THREE.OBJLoader2 = {} } -THREE.OBJLoader2.version = '1.0.4'; +THREE.OBJLoader2.version = '1.0.5'; /** * OBJ data will be loaded by dynamically created web worker. @@ -32,6 +32,8 @@ THREE.OBJLoader2.WWOBJLoader2 = (function () { this.debug = false; this.sceneGraphBaseNode = null; + this.streamMeshes = true; + this.meshStore = null; this.modelName = 'none'; this.validated = false; this.running = false; @@ -164,6 +166,8 @@ THREE.OBJLoader2.WWOBJLoader2 = (function () { } this.sceneGraphBaseNode = null; + this.streamMeshes = true; + this.meshStore = []; this.modelName = 'none'; this.validated = true; this.running = true; @@ -204,7 +208,7 @@ THREE.OBJLoader2.WWOBJLoader2 = (function () { if ( this.dataAvailable ) { // fast-fail on bad type - if ( ! ( params.objAsArrayBuffer instanceof ArrayBuffer || params.objAsArrayBuffer instanceof Uint8Array ) ) { + if ( ! params.objAsArrayBuffer instanceof Uint8Array ) { throw 'Provided input is not of type arraybuffer! Aborting...'; } @@ -236,6 +240,8 @@ THREE.OBJLoader2.WWOBJLoader2 = (function () { this.setRequestTerminate( params.requestTerminate ); this.pathTexture = params.pathTexture; this.sceneGraphBaseNode = params.sceneGraphBaseNode; + this.streamMeshes = params.streamMeshes; + if ( ! this.streamMeshes ) this.meshStore = []; }; /** @@ -327,6 +333,8 @@ THREE.OBJLoader2.WWOBJLoader2 = (function () { console.timeEnd( 'Loading MTL textures' ); }; + + this.mtlLoader.setPath( this.pathTexture ); if ( this.dataAvailable ) { processLoadedMaterials( ( this.mtlAsString != null ) ? this.mtlLoader.parse( this.mtlAsString ) : null ); @@ -339,7 +347,6 @@ THREE.OBJLoader2.WWOBJLoader2 = (function () { } else { - this.mtlLoader.setPath( this.pathTexture ); this.mtlLoader.load( this.fileMtl, processLoadedMaterials ); } @@ -431,14 +438,31 @@ THREE.OBJLoader2.WWOBJLoader2 = (function () { } var mesh = new THREE.Mesh( bufferGeometry, material ); mesh.name = payload.meshName; - this.sceneGraphBaseNode.add( mesh ); + 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 ) { @@ -663,7 +687,7 @@ THREE.OBJLoader2.WWOBJLoader2 = (function () { var materialDescription; var materialDescriptions = []; - var createMultiMaterial = ( rawObjectDescriptions.length > 1 ) ? true : false; + var createMultiMaterial = ( rawObjectDescriptions.length > 1 ); var materialIndex = 0; var materialIndexMapping = []; var selectedMaterialIndex; @@ -882,12 +906,13 @@ THREE.OBJLoader2.WWOBJLoader2 = (function () { * @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, requestTerminate: boolean}} + * @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, requestTerminate ) { +THREE.OBJLoader2.WWOBJLoader2.PrepDataArrayBuffer = function ( modelName, objAsArrayBuffer, pathTexture, mtlAsString, sceneGraphBaseNode, streamMeshes, requestTerminate ) { var data = { modelName: ( modelName == null ) ? 'none' : modelName, @@ -896,6 +921,7 @@ THREE.OBJLoader2.WWOBJLoader2.PrepDataArrayBuffer = function ( modelName, objAsA 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 }; @@ -911,12 +937,13 @@ THREE.OBJLoader2.WWOBJLoader2.PrepDataArrayBuffer = function ( modelName, objAsA * @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, requestTerminate: boolean}} + * @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, requestTerminate ) { +THREE.OBJLoader2.WWOBJLoader2.PrepDataFile = function ( modelName, pathObj, fileObj, pathTexture, fileMtl, sceneGraphBaseNode, streamMeshes, requestTerminate ) { var data = { modelName: ( modelName == null ) ? 'none' : modelName, @@ -926,6 +953,7 @@ THREE.OBJLoader2.WWOBJLoader2.PrepDataFile = function ( modelName, pathObj, file 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 }; diff --git a/examples/webgl_loader_obj2.html b/examples/webgl_loader_obj2.html index 6d1aedeaef43a3..fed6e5513d9448 100644 --- a/examples/webgl_loader_obj2.html +++ b/examples/webgl_loader_obj2.html @@ -7,85 +7,68 @@ + +
+ +
three.js - OBJLoader2 direct loader test
-
@@ -93,6 +76,7 @@ + - \ No newline at end of file + diff --git a/examples/webgl_loader_obj2_ww.html b/examples/webgl_loader_obj2_ww.html index a89f563dfdf29f..fc3dbb3522fc56 100644 --- a/examples/webgl_loader_obj2_ww.html +++ b/examples/webgl_loader_obj2_ww.html @@ -7,92 +7,80 @@ + +
+ +
three.js - OBJLoader2 direct loader test
-
+ + @@ -123,16 +111,34 @@ this.smoothShading = true; this.doubleSide = false; + this.streamMeshes = true; this.cube = null; this.pivot = null; - this.objDef = { + this.wwObjLoader2 = new THREE.OBJLoader2.WWOBJLoader2(); + this.wwObjLoader2.setCrossOrigin( 'anonymous' ); + + this.defaultObjDef = { + name: 'male02', path: 'obj/male02/', fileObj: 'male02.obj', - texturePath: 'obj/male02/', + pathTexture: 'obj/male02/', fileMtl: 'male02.mtl' }; + + // Check for the various File API support. + this.fileApiAvailable = true; + if ( window.File && window.FileReader && window.FileList && window.Blob ) { + + console.log( 'File API is supported! Enabling all features.' ); + + } else { + + this.fileApiAvailable = false; + console.warn( 'File API is not supported! Disabling file loading.' ); + + } } WWOBJLoader2Example.prototype.initGL = function () { @@ -147,7 +153,7 @@ this.camera = new THREE.PerspectiveCamera( this.cameraDefaults.fov, this.aspectRatio, this.cameraDefaults.near, this.cameraDefaults.far ); this.resetCamera(); - this.controls = new THREE.TrackballControls( this.camera ); + this.controls = new THREE.TrackballControls( this.camera, this.renderer.domElement ); var ambientLight = new THREE.AmbientLight( 0x404040 ); var directionalLight1 = new THREE.DirectionalLight( 0xC0C090 ); @@ -172,9 +178,6 @@ }; WWOBJLoader2Example.prototype.initPostGL = function () { - var wwObjLoader2 = new THREE.OBJLoader2.WWOBJLoader2(); - wwObjLoader2.setCrossOrigin( 'anonymous' ); - var reportProgress = function ( content ) { console.log( 'Progress: ' + content ); }; @@ -189,17 +192,83 @@ var completedLoading = function () { console.log( 'Loading complete!' ); }; - wwObjLoader2.registerCallbackProgress( reportProgress ); - wwObjLoader2.registerCallbackCompletedLoading( completedLoading ); - wwObjLoader2.registerCallbackMaterialsLoaded( materialsLoaded ); + this.wwObjLoader2.registerCallbackProgress( reportProgress ); + this.wwObjLoader2.registerCallbackCompletedLoading( completedLoading ); + this.wwObjLoader2.registerCallbackMaterialsLoaded( materialsLoaded ); + + this._loadFiles( this.defaultObjDef ); + return true; + }; + + WWOBJLoader2Example.prototype._loadFiles = function ( objDef ) { var prepData = new THREE.OBJLoader2.WWOBJLoader2.PrepDataFile( - 'male02', this.objDef.path, this.objDef.fileObj, this.objDef.texturePath, this.objDef.fileMtl, this.pivot + objDef.name, objDef.path, objDef.fileObj, objDef.pathTexture, objDef.fileMtl, this.pivot, this.streamMeshes ); - wwObjLoader2.prepareRun( prepData ); - wwObjLoader2.run(); + this.wwObjLoader2.prepareRun( prepData ); + this.wwObjLoader2.run(); + }; + + WWOBJLoader2Example.prototype._handleFileSelect = function ( event, pathTexture ) { + var fileObj = null; + var fileMtl = null; + var files = event.target.files; + + for ( var i = 0, file; file = files[ i ]; i++) { + + if ( file.name.indexOf( '\.obj' ) > 0 && fileObj === null ) { + fileObj = file; + } + + if ( file.name.indexOf( '\.mtl' ) > 0 && fileMtl === null ) { + fileMtl = file; + } + + } + + if ( fileObj == null ) { + alert( 'Unable to load OBJ file from given files: ' + files.toString() ); + } + + var fileReader = new FileReader(); + fileReader.onload = function( fileDataObj ) { + + var uint8Array = new Uint8Array( fileDataObj.target.result ); + if ( fileMtl === null ) { + + app.loadFilesUser({ + name: 'userObj', + objAsArrayBuffer: uint8Array, + pathTexture: pathTexture, + mtlAsString: null + }) + + } else { + + fileReader.onload = function( fileDataMtl ) { + + app.loadFilesUser({ + name: 'userObj', + objAsArrayBuffer: uint8Array, + pathTexture: pathTexture, + mtlAsString: fileDataMtl.target.result + }) + }; + fileReader.readAsText( fileMtl ); + + } + + }; + fileReader.readAsArrayBuffer( fileObj ); - return true; + }; + + WWOBJLoader2Example.prototype.loadFilesUser = function ( objDef ) { + var prepData = new THREE.OBJLoader2.WWOBJLoader2.PrepDataArrayBuffer( + objDef.name, objDef.objAsArrayBuffer, objDef.pathTexture, objDef.mtlAsString, this.pivot, this.streamMeshes + ); + this.wwObjLoader2.prepareRun( prepData ); + this.wwObjLoader2.run(); }; WWOBJLoader2Example.prototype.resizeDisplayGL = function () { @@ -243,13 +312,8 @@ var scope = this; scope.smoothShading = ! scope.smoothShading; - var side = document.getElementById( 'shading' ); - side.style.backgroundColor = scope.smoothShading ? 'darkgreen' : 'darkorange'; - side.style.borderColor = scope.smoothShading ? 'darkgreen' : 'darkorange'; - side.innerHTML = scope.smoothShading ? 'Smooth Shading' : 'Flat Shading'; console.log( scope.smoothShading ? 'Enabling SmoothShading' : 'Enabling FlatShading'); - scope.traversalFunction = function ( material ) { material.shading = scope.smoothShading ? THREE.SmoothShading : THREE.FlatShading; material.needsUpdate = true; @@ -264,13 +328,8 @@ var scope = this; scope.doubleSide = ! scope.doubleSide; - var side = document.getElementById( 'side' ); - side.style.backgroundColor = scope.doubleSide ? 'darkgreen' : 'darkorange'; - side.style.borderColor = scope.doubleSide ? 'darkgreen' : 'darkorange'; - side.innerHTML = scope.doubleSide ? 'Double Side' : 'Front Side'; console.log( scope.doubleSide ? 'Enabling DoubleSide materials' : 'Enabling FrontSide materials'); - scope.traversalFunction = function ( material ) { material.side = scope.doubleSide ? THREE.DoubleSide : THREE.FrontSide; }; @@ -303,15 +362,74 @@ })(); - var app = new WWOBJLoader2Example( document.getElementById( 'example' ) ); + // Init dat.gui and controls + var elemFileInput = document.getElementById( 'fileUploadInput' ); + var WWOBJLoader2Control = function() { + this.smoothShading = app.smoothShading; + this.doubleSide = app.doubleSide; + this.streamMeshes = app.streamMeshes; + }; + var wwObjLoader2Control = new WWOBJLoader2Control(); + + var gui = new dat.GUI( { + autoPlace: false, + width: 320 + } ); + + var menuDiv = document.getElementById( 'dat' ); + menuDiv.appendChild(gui.domElement); + var folderQueue = gui.addFolder( 'WWOBJLoader2 Options' ); + var controlSmooth = folderQueue.add( wwObjLoader2Control, 'smoothShading' ).name( 'Smooth Shading' ); + controlSmooth.onChange( function( value ) { + console.log( 'Setting smoothShading to: ' + value ); + app.alterSmoothShading(); + }); + + var controlDouble = folderQueue.add( wwObjLoader2Control, 'doubleSide' ).name( 'Double Side Materials' ); + controlDouble.onChange( function( value ) { + console.log( 'Setting doubleSide to: ' + value ); + app.alterDouble(); + }); + + var controlStreamMeshes = folderQueue.add( wwObjLoader2Control, 'streamMeshes' ).name( 'Stream Meshes' ); + controlStreamMeshes.onChange( function( value ) { + console.log( 'Setting streamMeshes to: ' + value ); + app.streamMeshes = value; + }); + + if ( app.fileApiAvailable ) { + + wwObjLoader2Control.pathTexture = 'obj/female02/'; + var controlPathTexture = folderQueue.add( wwObjLoader2Control, 'pathTexture' ).name( 'Relative path to textures' ); + controlPathTexture.onChange( function( value ) { + console.log( 'Setting pathTexture to: ' + value ); + app.pathTexture = value; + }); + + wwObjLoader2Control.loadObjFile = function () { + elemFileInput.click(); + }; + folderQueue.add( wwObjLoader2Control, 'loadObjFile' ).name( 'Load OBJ/MTL Files' ); + + var handleFileSelect = function ( object3d ) { + app._handleFileSelect( object3d, wwObjLoader2Control.pathTexture ); + }; + elemFileInput.addEventListener( 'change' , handleFileSelect, false ); + + } + folderQueue.open(); + + + + // init three.ks example application var resizeWindow = function () { app.resizeDisplayGL(); }; var render = function () { - requestAnimationFrame( render) ; + requestAnimationFrame( render ); app.render(); }; @@ -322,8 +440,9 @@ app.resizeDisplayGL(); app.initPostGL(); + // kick render loop render(); - + \ No newline at end of file diff --git a/examples/webgl_loader_obj2_ww_parallels.html b/examples/webgl_loader_obj2_ww_parallels.html index 74959013b511e2..8e7aa94bc42b5e 100644 --- a/examples/webgl_loader_obj2_ww_parallels.html +++ b/examples/webgl_loader_obj2_ww_parallels.html @@ -7,44 +7,44 @@ + @@ -192,7 +191,7 @@ document.getElementById( 'feedback' ).innerHTML = text; }; - WWParallels.prototype.enqueueAllAssests = function ( maxQueueSize, maxWebWorkers ) { + WWParallels.prototype.enqueueAllAssests = function ( maxQueueSize, maxWebWorkers, streamMeshes ) { var scope = this; scope.wwDirector.objectsCompleted = 0; scope.feedbackArray = new Array( maxWebWorkers ); @@ -295,7 +294,7 @@ model.sceneGraphBaseNode = pivot; runParams = new THREE.OBJLoader2.WWOBJLoader2.PrepDataFile( - model.modelName, model.pathObj, model.fileObj, model.pathTexture, model.fileMtl, model.sceneGraphBaseNode + model.modelName, model.pathObj, model.fileObj, model.pathTexture, model.fileMtl, model.sceneGraphBaseNode, streamMeshes ); this.wwDirector.enqueueForRun( runParams ); this.allAssets.push( runParams ); @@ -351,13 +350,15 @@ })(); - var app = new WWParallels( document.getElementById( 'example' ) ); - var WWControl = function() { + var WWParallelsControl = function() { this.queueLength = 128; this.workerCount = 4; - this.run = null; + this.streamMeshes = true; + this.run = function () { + app.enqueueAllAssests( this.queueLength, this.workerCount, this.streamMeshes ); + }; this.terminate = function () { app.terminateManager(); }; @@ -366,11 +367,7 @@ app.clearAllAssests(); }; }; - - var wwControl = new WWControl(); - wwControl.run = function () { - app.enqueueAllAssests( wwControl.queueLength, wwControl.workerCount ); - }; + var wwParallelsControl = new WWParallelsControl(); var gui = new dat.GUI( { autoPlace: false, @@ -380,14 +377,15 @@ var menuDiv = document.getElementById( 'dat' ); menuDiv.appendChild(gui.domElement); var folderQueue = gui.addFolder( 'Web Worker Director Queue Control' ); - folderQueue.add( wwControl, 'queueLength' ).min( 1 ).max( 1024 ).step( 1 ); - folderQueue.add( wwControl, 'workerCount' ).min( 1 ).max( 16 ).step( 1 ); - folderQueue.add( wwControl, 'run' ).name( 'Run Queue' ); + folderQueue.add( wwParallelsControl, 'queueLength' ).min( 1 ).max( 1024 ).step( 1 ); + folderQueue.add( wwParallelsControl, 'workerCount' ).min( 1 ).max( 16 ).step( 1 ); + folderQueue.add( wwParallelsControl, 'streamMeshes' ); + folderQueue.add( wwParallelsControl, 'run' ).name( 'Run Queue' ); folderQueue.open(); var folderWWControl = gui.addFolder( 'Resource Management' ); - folderWWControl.add( wwControl, 'terminate' ).name( 'Terminate WWManager' ); - folderWWControl.add( wwControl, 'clearAllAssests' ).name( 'Clear Scene' ); + folderWWControl.add( wwParallelsControl, 'terminate' ).name( 'Terminate WWManager' ); + folderWWControl.add( wwParallelsControl, 'clearAllAssests' ).name( 'Clear Scene' ); var resizeWindow = function () { app.resizeDisplayGL();