From fb79968d5a1d6f93c954ecd58d1f689b25f831ec Mon Sep 17 00:00:00 2001 From: Kai Salmen Date: Sat, 25 Mar 2017 13:07:42 +0100 Subject: [PATCH 1/3] #9756 WWOBJLoader2 V1.0.6 Improvements since initial external V1.0.0 release: OBJLoader2: - Removed need for making Parser public. OBJLoader2 has a build function for web worker code. - MeshCreator is now private to OBJLoader2 WWOBJLoader2: - Added checks for Blob and URL.createObjectURL - Worker code build: Removed need to adjust constructor and some new Object calls - Allow to properly set CORS to MTLLoader via WWOBJLoader2 and WWOBJLoader2Director - Now allows to enable/disable mesh streaming Example webgl_loader_obj - Added GridHelper - resources to load are now defined outside example classes Example webgl_loader_obj2_ww - Allow to clear all meshes in - Allows to load user OBJ/MTL files - Added GridHelper - resources to load are now defined outside example classes All Examples: - Created one page examples and tuned naming - All examples now use dat.gui - Removed namespace "THREE.examples" - Fixed comment typos - Fixed some code formatting issues - Fixed tabs in examples General: - Headers now carry references to development repository --- examples/files.js | 3 + examples/js/loaders/OBJLoader2.js | 1002 +++++++++++++++ examples/js/loaders/WWOBJLoader2.js | 1171 ++++++++++++++++++ examples/webgl_loader_obj2.html | 343 +++++ examples/webgl_loader_obj2_ww.html | 491 ++++++++ examples/webgl_loader_obj2_ww_parallels.html | 409 ++++++ 6 files changed, 3419 insertions(+) create mode 100644 examples/js/loaders/OBJLoader2.js create mode 100644 examples/js/loaders/WWOBJLoader2.js create mode 100644 examples/webgl_loader_obj2.html create mode 100644 examples/webgl_loader_obj2_ww.html create mode 100644 examples/webgl_loader_obj2_ww_parallels.html diff --git a/examples/files.js b/examples/files.js index 6c6267b2621c08..a7d570bdafbc0d 100644 --- a/examples/files.js +++ b/examples/files.js @@ -102,6 +102,9 @@ var files = { "webgl_loader_msgpack", "webgl_loader_obj", "webgl_loader_obj_mtl", + "webgl_loader_obj2", + "webgl_loader_obj2_ww", + "webgl_loader_obj2_ww_parallels", "webgl_loader_nrrd", "webgl_loader_pcd", "webgl_loader_pdb", diff --git a/examples/js/loaders/OBJLoader2.js b/examples/js/loaders/OBJLoader2.js new file mode 100644 index 00000000000000..9b39ad50ea6aa3 --- /dev/null +++ b/examples/js/loaders/OBJLoader2.js @@ -0,0 +1,1002 @@ +/** + * @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'; + +/** + * Use this class to load OBJ data from files or to parse OBJ data from arraybuffer or text + * @class + * + * @param {THREE.DefaultLoadingManager} [manager] Extension of {@link THREE.DefaultLoadingManager} + */ +THREE.OBJLoader2 = (function () { + + function OBJLoader2( manager ) { + this.manager = ( manager == null ) ? THREE.DefaultLoadingManager : manager; + + this.path = ''; + this.fileLoader = new THREE.FileLoader( this.manager ); + + this.meshCreator = new MeshCreator(); + this.parser = new Parser( this.meshCreator ); + + this.validated = false; + } + + /** + * Base path to use + * @memberOf THREE.OBJLoader2 + * + * @param {string} path The basepath + */ + OBJLoader2.prototype.setPath = function ( path ) { + this.path = ( path == null ) ? this.path : path; + }; + + /** + * Set the node where the loaded objects will be attached + * @memberOf THREE.OBJLoader2 + * + * @param {THREE.Object3D} sceneGraphBaseNode Scenegraph object where meshes will be attached + */ + OBJLoader2.prototype.setSceneGraphBaseNode = function ( sceneGraphBaseNode ) { + this.meshCreator._setSceneGraphBaseNode( sceneGraphBaseNode ); + }; + + /** + * Set materials loaded by MTLLoader + * @memberOf THREE.OBJLoader2 + * + * @param {THREE.MTLLoader.MaterialCreator.materials[]} materials {@link THREE.MTLLoader.MaterialCreator.materials} + */ + OBJLoader2.prototype.setMaterials = function ( materials ) { + this.meshCreator._setMaterials( materials ); + }; + + /** + * Allows to set debug mode for the parser and the meshCreator + * @memberOf THREE.OBJLoader2 + * + * @param {boolean} parserDebug {@link Parser} will produce debug output + * @param {boolean} meshCreatorDebug {@link THREE.OBJLoader2.MeshCreator} will produce debug output + */ + OBJLoader2.prototype.setDebug = function ( parserDebug, meshCreatorDebug ) { + this.parser._setDebug( parserDebug ); + this.meshCreator._setDebug( meshCreatorDebug ); + }; + + /** + * Use this convenient method to load an OBJ file at the given URL. Per default the fileLoader uses an arraybuffer + * @memberOf THREE.OBJLoader2 + * + * @param {string} url URL of the file to load + * @param {callback} onLoad Called after loading was successfully completed + * @param {callback} onProgress Called to report progress of loading + * @param {callback} onError Called after an error occurred during loading + * @param {boolean} [useArrayBuffer=true] Set this to false to force string based parsing + */ + OBJLoader2.prototype.load = function ( url, onLoad, onProgress, onError, useArrayBuffer ) { + this._validate(); + this.fileLoader.setPath( this.path ); + this.fileLoader.setResponseType( ( useArrayBuffer || useArrayBuffer == null ) ? 'arraybuffer' : 'text' ); + + var scope = this; + scope.fileLoader.load( url, function ( content ) { + + // only use parseText if useArrayBuffer is explicitly set to false + onLoad( ( useArrayBuffer || useArrayBuffer == null ) ? scope.parse( content ) : scope.parseText( content ) ); + + }, onProgress, onError ); + }; + + /** + * Default parse function: Parses OBJ file content stored in arrayBuffer and returns the sceneGraphBaseNode + * @memberOf THREE.OBJLoader2 + * + * @param {Uint8Array} arrayBuffer OBJ data as Uint8Array + */ + OBJLoader2.prototype.parse = function ( arrayBuffer ) { + // fast-fail on bad type + if ( ! ( arrayBuffer instanceof ArrayBuffer || arrayBuffer instanceof Uint8Array ) ) { + + throw 'Provided input is not of type arraybuffer! Aborting...'; + + } + console.log( 'Parsing arrayBuffer...' ); + console.time( 'parseArrayBuffer' ); + + this._validate(); + this.parser.parseArrayBuffer( arrayBuffer ); + var sceneGraphAttach = this._finalize(); + + console.timeEnd( 'parseArrayBuffer' ); + + return sceneGraphAttach; + }; + + /** + * Legacy parse function: Parses OBJ file content stored in string and returns the sceneGraphBaseNode + * @memberOf THREE.OBJLoader2 + * + * @param {string} text OBJ data as string + */ + OBJLoader2.prototype.parseText = function ( text ) { + // fast-fail on bad type + if ( ! ( typeof( text ) === 'string' || text instanceof String ) ) { + + throw 'Provided input is not of type String! Aborting...'; + + } + console.log( 'Parsing text...' ); + console.time( 'parseText' ); + + this._validate(); + this.parser.parseText( text ); + var sceneGraphBaseNode = this._finalize(); + + console.timeEnd( 'parseText' ); + + return sceneGraphBaseNode; + }; + + OBJLoader2.prototype._validate = function () { + if ( this.validated ) return; + + this.fileLoader = ( this.fileLoader == null ) ? new THREE.FileLoader( this.manager ) : this.fileLoader; + this.setPath(); + this.parser._validate(); + this.meshCreator._validate(); + + this.validated = true; + }; + + OBJLoader2.prototype._finalize = function () { + console.log( 'Global output object count: ' + this.meshCreator.globalObjectCount ); + + this.parser._finalize(); + this.fileLoader = null; + var sceneGraphBaseNode = this.meshCreator.sceneGraphBaseNode; + this.meshCreator._finalize(); + this.validated = false; + + return sceneGraphBaseNode; + }; + + /** + * Constants used by THREE.OBJLoader2 + */ + var 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', + /* + * Build Face/Quad: first element in indexArray is the line identification, therefore offset of one needs to be taken into account + * N-Gons are not supported + * Quad Faces: FaceA: 0, 1, 2 FaceB: 2, 3, 0 + * + * 0: "f vertex/uv/normal vertex/uv/normal vertex/uv/normal (vertex/uv/normal)" + * 1: "f vertex/uv vertex/uv vertex/uv (vertex/uv )" + * 2: "f vertex//normal vertex//normal vertex//normal (vertex//normal )" + * 3: "f vertex vertex vertex (vertex )" + * + * @param indexArray + * @param faceType + */ + QUAD_INDICES_1: [ 1, 2, 3, 3, 4, 1 ], + QUAD_INDICES_2: [ 1, 3, 5, 5, 7, 1 ], + QUAD_INDICES_3: [ 1, 4, 7, 7, 10, 1 ] + }; + + /** + * Parse OBJ data either from ArrayBuffer or string + * @class + */ + var Parser = (function () { + + function Parser( meshCreator ) { + this.meshCreator = meshCreator; + this.rawObject = null; + this.inputObjectCount = 1; + this.debug = false; + } + + Parser.prototype._setDebug = function ( debug ) { + this.debug = ( debug == null ) ? this.debug : debug; + }; + + Parser.prototype._validate = function () { + this.rawObject = new RawObject(); + this.inputObjectCount = 1; + }; + + /** + * Parse the provided arraybuffer + * @memberOf Parser + * + * @param {Uint8Array} arrayBuffer OBJ data as Uint8Array + */ + Parser.prototype.parseArrayBuffer = function ( arrayBuffer ) { + var arrayBufferView = new Uint8Array( arrayBuffer ); + var length = arrayBufferView.byteLength; + var buffer = new Array( 32 ); + var bufferPointer = 0; + var slashes = new Array( 32 ); + var slashesPointer = 0; + var reachedFaces = false; + var code; + var word = ''; + for ( var i = 0; i < length; i++ ) { + + code = arrayBufferView[ i ]; + switch ( code ) { + case Consts.CODE_SPACE: + if ( word.length > 0 ) buffer[ bufferPointer++ ] = word; + word = ''; + break; + + case Consts.CODE_SLASH: + slashes[ slashesPointer++ ] = i; + if ( word.length > 0 ) buffer[ bufferPointer++ ] = word; + word = ''; + break; + + case Consts.CODE_LF: + if ( word.length > 0 ) buffer[ bufferPointer++ ] = word; + word = ''; + reachedFaces = this._processLine( buffer, bufferPointer, slashes, slashesPointer, reachedFaces ); + slashesPointer = 0; + bufferPointer = 0; + break; + + case Consts.CODE_CR: + break; + + default: + word += String.fromCharCode( code ); + break; + } + } + }; + + /** + * Parse the provided text + * @memberOf Parser + * + * @param {string} text OBJ data as string + */ + Parser.prototype.parseText = function ( text ) { + var length = text.length; + var buffer = new Array( 32 ); + var bufferPointer = 0; + var slashes = new Array( 32 ); + var slashesPointer = 0; + var reachedFaces = false; + var char; + var word = ''; + for ( var i = 0; i < length; i++ ) { + + char = text[ i ]; + switch ( char ) { + case Consts.STRING_SPACE: + if ( word.length > 0 ) buffer[ bufferPointer++ ] = word; + word = ''; + break; + + case Consts.STRING_SLASH: + slashes[ slashesPointer++ ] = i; + if ( word.length > 0 ) buffer[ bufferPointer++ ] = word; + word = ''; + break; + + case Consts.STRING_LF: + if ( word.length > 0 ) buffer[ bufferPointer++ ] = word; + word = ''; + reachedFaces = this._processLine( buffer, bufferPointer, slashes, slashesPointer, reachedFaces ); + slashesPointer = 0; + bufferPointer = 0; + break; + + case Consts.STRING_CR: + break; + + default: + word += char; + } + } + }; + + Parser.prototype._processLine = function ( buffer, bufferPointer, slashes, slashesPointer, reachedFaces ) { + if ( bufferPointer < 1 ) return reachedFaces; + + var bufferLength = bufferPointer - 1; + switch ( buffer[ 0 ] ) { + case Consts.LINE_V: + + // object complete instance required if reached faces already (= reached next block of v) + if ( reachedFaces ) { + + this._processCompletedObject( null, this.rawObject.groupName ); + reachedFaces = false; + + } + this.rawObject._pushVertex( buffer ); + break; + + case Consts.LINE_VT: + this.rawObject._pushUv( buffer ); + break; + + case Consts.LINE_VN: + this.rawObject._pushNormal( buffer ); + break; + + case Consts.LINE_F: + reachedFaces = true; + /* + * 0: "f vertex/uv/normal ..." + * 1: "f vertex/uv ..." + * 2: "f vertex//normal ..." + * 3: "f vertex ..." + */ + var haveQuad = bufferLength % 4 === 0; + if ( slashesPointer > 1 && ( slashes[ 1 ] - slashes[ 0 ] ) === 1 ) { + + if ( haveQuad ) { + this.rawObject._buildQuadVVn( buffer ); + } else { + this.rawObject._buildFaceVVn( buffer ); + } + + } else if ( bufferLength === slashesPointer * 2 ) { + + if ( haveQuad ) { + this.rawObject._buildQuadVVt( buffer ); + } else { + this.rawObject._buildFaceVVt( buffer ); + } + + } else if ( bufferLength * 2 === slashesPointer * 3 ) { + + if ( haveQuad ) { + this.rawObject._buildQuadVVtVn( buffer ); + } else { + this.rawObject._buildFaceVVtVn( buffer ); + } + + } else { + + if ( haveQuad ) { + this.rawObject._buildQuadV( buffer ); + } else { + this.rawObject._buildFaceV( buffer ); + } + + } + break; + + case Consts.LINE_L: + if ( bufferLength === slashesPointer * 2 ) { + + this.rawObject._buildLineVvt( buffer ); + + } else { + + this.rawObject._buildLineV( buffer ); + + } + break; + + case Consts.LINE_S: + this.rawObject._pushSmoothingGroup( buffer[ 1 ] ); + break; + + case Consts.LINE_G: + this._processCompletedGroup( buffer[ 1 ] ); + break; + + case Consts.LINE_O: + if ( this.rawObject.vertices.length > 0 ) { + + this._processCompletedObject( buffer[ 1 ], null ); + reachedFaces = false; + + } else { + + this.rawObject._pushObject( buffer[ 1 ] ); + + } + break; + + case Consts.LINE_MTLLIB: + this.rawObject._pushMtllib( buffer[ 1 ] ); + break; + + case Consts.LINE_USEMTL: + this.rawObject._pushUsemtl( buffer[ 1 ] ); + break; + + default: + break; + } + return reachedFaces; + }; + + Parser.prototype._processCompletedObject = function ( objectName, groupName ) { + this.rawObject._finalize( this.meshCreator, this.inputObjectCount, this.debug ); + this.inputObjectCount++; + this.rawObject = this.rawObject._newInstanceFromObject( objectName, groupName ); + }; + + Parser.prototype._processCompletedGroup = function ( groupName ) { + var notEmpty = this.rawObject._finalize( this.meshCreator, this.inputObjectCount, this.debug ); + if ( notEmpty ) { + + this.inputObjectCount ++; + this.rawObject = this.rawObject._newInstanceFromGroup( groupName ); + + } else { + + // if a group was set that did not lead to object creation in finalize, then the group name has to be updated + this.rawObject._pushGroup( groupName ); + + } + }; + + Parser.prototype._finalize = function () { + this.rawObject._finalize( this.meshCreator, this.inputObjectCount, this.debug ); + this.inputObjectCount++; + }; + + return Parser; + })(); + + /** + * {@link RawObject} is only used by {@link Parser}. + * The user of OBJLoader2 does not need to care about this class. + * It is defined publicly for inclusion in web worker based OBJ loader ({@link THREE.OBJLoader2.WWOBJLoader2}) + */ + var RawObject = (function () { + + function RawObject( objectName, groupName, mtllibName ) { + this.globalVertexOffset = 1; + this.globalUvOffset = 1; + this.globalNormalOffset = 1; + + this.vertices = []; + this.normals = []; + this.uvs = []; + + // faces are stored according combined index of group, material and smoothingGroup (0 or not) + this.mtllibName = ( mtllibName != null ) ? mtllibName : 'none'; + this.objectName = ( objectName != null ) ? objectName : 'none'; + this.groupName = ( groupName != null ) ? groupName : 'none'; + this.activeMtlName = 'none'; + this.activeSmoothingGroup = 1; + + this.mtlCount = 0; + this.smoothingGroupCount = 0; + + this.rawObjectDescriptions = []; + // this default index is required as it is possible to define faces without 'g' or 'usemtl' + var index = this._buildIndex( this.activeMtlName, this.activeSmoothingGroup ); + this.rawObjectDescriptionInUse = new RawObjectDescription( this.objectName, this.groupName, this.activeMtlName, this.activeSmoothingGroup ); + this.rawObjectDescriptions[ index ] = this.rawObjectDescriptionInUse; + } + + RawObject.prototype._buildIndex = function ( materialName, smoothingGroup) { + return materialName + '|' + smoothingGroup; + }; + + RawObject.prototype._newInstanceFromObject = function ( objectName, groupName ) { + var newRawObject = new RawObject( objectName, groupName, this.mtllibName ); + + // 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; + }; + + RawObject.prototype._newInstanceFromGroup = function ( groupName ) { + var newRawObject = new RawObject( this.objectName, groupName, this.mtllibName ); + + // keep current buffers and indices forward + newRawObject.vertices = this.vertices; + newRawObject.uvs = this.uvs; + newRawObject.normals = this.normals; + newRawObject.globalVertexOffset = this.globalVertexOffset; + newRawObject.globalUvOffset = this.globalUvOffset; + newRawObject.globalNormalOffset = this.globalNormalOffset; + + return newRawObject; + }; + + RawObject.prototype._pushVertex = function ( buffer ) { + this.vertices.push( parseFloat( buffer[ 1 ] ) ); + this.vertices.push( parseFloat( buffer[ 2 ] ) ); + this.vertices.push( parseFloat( buffer[ 3 ] ) ); + }; + + RawObject.prototype._pushUv = function ( buffer ) { + this.uvs.push( parseFloat( buffer[ 1 ] ) ); + this.uvs.push( parseFloat( buffer[ 2 ] ) ); + }; + + RawObject.prototype._pushNormal = function ( buffer ) { + this.normals.push( parseFloat( buffer[ 1 ] ) ); + this.normals.push( parseFloat( buffer[ 2 ] ) ); + this.normals.push( parseFloat( buffer[ 3 ] ) ); + }; + + RawObject.prototype._pushObject = function ( objectName ) { + this.objectName = objectName; + }; + + RawObject.prototype._pushMtllib = function ( mtllibName ) { + this.mtllibName = mtllibName; + }; + + RawObject.prototype._pushGroup = function ( groupName ) { + this.groupName = groupName; + this._verifyIndex(); + }; + + RawObject.prototype._pushUsemtl = function ( mtlName ) { + if ( this.activeMtlName === mtlName || mtlName == null ) return; + this.activeMtlName = mtlName; + this.mtlCount++; + + this._verifyIndex(); + }; + + RawObject.prototype._pushSmoothingGroup = function ( activeSmoothingGroup ) { + var normalized = activeSmoothingGroup === 'off' ? 0 : activeSmoothingGroup; + if ( this.activeSmoothingGroup === normalized ) return; + this.activeSmoothingGroup = normalized; + this.smoothingGroupCount++; + + this._verifyIndex(); + }; + + RawObject.prototype._verifyIndex = function () { + var index = this._buildIndex( this.activeMtlName, ( this.activeSmoothingGroup === 0 ) ? 0 : 1 ); + if ( this.rawObjectDescriptions[ index ] == null ) { + + this.rawObjectDescriptionInUse = this.rawObjectDescriptions[ index ] = + new RawObjectDescription( + this.objectName, this.groupName, this.activeMtlName, this.activeSmoothingGroup + ); + + } else { + + this.rawObjectDescriptionInUse = this.rawObjectDescriptions[ index ]; + + } + }; + + RawObject.prototype._buildQuadVVtVn = function ( indexArray ) { + for ( var i = 0; i < 6; i ++ ) { + this._attachFaceV_( indexArray[ Consts.QUAD_INDICES_3[ i ] ] ); + this._attachFaceVt( indexArray[ Consts.QUAD_INDICES_3[ i ] + 1 ] ); + this._attachFaceVn( indexArray[ Consts.QUAD_INDICES_3[ i ] + 2 ] ); + } + }; + + RawObject.prototype._buildQuadVVt = function ( indexArray ) { + for ( var i = 0; i < 6; i ++ ) { + this._attachFaceV_( indexArray[ Consts.QUAD_INDICES_2[ i ] ] ); + this._attachFaceVt( indexArray[ Consts.QUAD_INDICES_2[ i ] + 1 ] ); + } + }; + + RawObject.prototype._buildQuadVVn = function ( indexArray ) { + for ( var i = 0; i < 6; i ++ ) { + this._attachFaceV_( indexArray[ Consts.QUAD_INDICES_2[ i ] ] ); + this._attachFaceVn( indexArray[ Consts.QUAD_INDICES_2[ i ] + 1 ] ); + } + }; + + RawObject.prototype._buildQuadV = function ( indexArray ) { + for ( var i = 0; i < 6; i ++ ) { + this._attachFaceV_( indexArray[ Consts.QUAD_INDICES_1[ i ] ] ); + } + }; + + RawObject.prototype._buildFaceVVtVn = function ( indexArray ) { + for ( var i = 1; i < 10; i += 3 ) { + this._attachFaceV_( indexArray[ i ] ); + this._attachFaceVt( indexArray[ i + 1 ] ); + this._attachFaceVn( indexArray[ i + 2 ] ); + } + }; + + RawObject.prototype._buildFaceVVt = function ( indexArray ) { + for ( var i = 1; i < 7; i += 2 ) { + this._attachFaceV_( indexArray[ i ] ); + this._attachFaceVt( indexArray[ i + 1 ] ); + } + }; + + RawObject.prototype._buildFaceVVn = function ( indexArray ) { + for ( var i = 1; i < 7; i += 2 ) { + this._attachFaceV_( indexArray[ i ] ); + this._attachFaceVn( indexArray[ i + 1 ] ); + } + }; + + RawObject.prototype._buildFaceV = function ( indexArray ) { + for ( var i = 1; i < 4; i ++ ) { + this._attachFaceV_( indexArray[ i ] ); + } + }; + + RawObject.prototype._attachFaceV_ = function ( faceIndex ) { + var faceIndexInt = parseInt( faceIndex ); + var index = ( faceIndexInt - this.globalVertexOffset ) * 3; + + var rodiu = this.rawObjectDescriptionInUse; + rodiu.vertices.push( this.vertices[ index++ ] ); + rodiu.vertices.push( this.vertices[ index++ ] ); + rodiu.vertices.push( this.vertices[ index ] ); + }; + + RawObject.prototype._attachFaceVt = function ( faceIndex ) { + var faceIndexInt = parseInt( faceIndex ); + var index = ( faceIndexInt - this.globalUvOffset ) * 2; + + var rodiu = this.rawObjectDescriptionInUse; + rodiu.uvs.push( this.uvs[ index++ ] ); + rodiu.uvs.push( this.uvs[ index ] ); + }; + + RawObject.prototype._attachFaceVn = function ( faceIndex ) { + var faceIndexInt = parseInt( faceIndex ); + var index = ( faceIndexInt - this.globalNormalOffset ) * 3; + + var rodiu = this.rawObjectDescriptionInUse; + rodiu.normals.push( this.normals[ index++ ] ); + rodiu.normals.push( this.normals[ index++ ] ); + rodiu.normals.push( this.normals[ index ] ); + }; + + /* + * Support for lines with or without texture. irst element in indexArray is the line identification + * 0: "f vertex/uv vertex/uv ..." + * 1: "f vertex vertex ..." + */ + RawObject.prototype._buildLineVvt = function ( lineArray ) { + var length = lineArray.length; + for ( var i = 1; i < length; i ++ ) { + this.vertices.push( parseInt( lineArray[ i ] ) ); + this.uvs.push( parseInt( lineArray[ i ] ) ); + } + }; + + RawObject.prototype._buildLineV = function ( lineArray ) { + var length = lineArray.length; + for ( var i = 1; i < length; i++ ) { + this.vertices.push( parseInt( lineArray[ i ] ) ); + } + }; + + /** + * Clear any empty rawObjectDescription and calculate absolute vertex, normal and uv counts + */ + RawObject.prototype._finalize = function ( meshCreator, inputObjectCount, debug ) { + var temp = this.rawObjectDescriptions; + this.rawObjectDescriptions = []; + var rawObjectDescription; + var index = 0; + var absoluteVertexCount = 0; + var absoluteNormalCount = 0; + var absoluteUvCount = 0; + + for ( var name in temp ) { + + rawObjectDescription = temp[ name ]; + if ( rawObjectDescription.vertices.length > 0 ) { + + if ( rawObjectDescription.objectName === 'none' ) rawObjectDescription.objectName = rawObjectDescription.groupName; + this.rawObjectDescriptions[ index++ ] = rawObjectDescription; + absoluteVertexCount += rawObjectDescription.vertices.length; + absoluteUvCount += rawObjectDescription.uvs.length; + absoluteNormalCount += rawObjectDescription.normals.length; + + } + } + + // don not continue if no result + var notEmpty = false; + if ( index > 0 ) { + + if ( debug ) this._createReport( inputObjectCount, true ); + meshCreator._buildMesh( + this.rawObjectDescriptions, + inputObjectCount, + absoluteVertexCount, + absoluteNormalCount, + absoluteUvCount + ); + notEmpty = true; + + } + return notEmpty; + }; + + RawObject.prototype._createReport = function ( inputObjectCount, printDirectly ) { + var report = { + name: this.objectName ? this.objectName : 'groups', + mtllibName: this.mtllibName, + vertexCount: this.vertices.length / 3, + normalCount: this.normals.length / 3, + uvCount: this.uvs.length / 2, + smoothingGroupCount: this.smoothingGroupCount, + mtlCount: this.mtlCount, + rawObjectDescriptions: this.rawObjectDescriptions.length + }; + + if ( printDirectly ) { + console.log( 'Input Object number: ' + inputObjectCount + ' Object name: ' + report.name ); + console.log( 'Mtllib name: ' + report.mtllibName ); + console.log( 'Vertex count: ' + report.vertexCount ); + console.log( 'Normal count: ' + report.normalCount ); + console.log( 'UV count: ' + report.uvCount ); + console.log( 'SmoothingGroup count: ' + report.smoothingGroupCount ); + console.log( 'Material count: ' + report.mtlCount ); + console.log( 'Real RawObjectDescription count: ' + report.rawObjectDescriptions ); + console.log( '' ); + } + + return report; + }; + + return RawObject; + })(); + + /** + * Descriptive information and data (vertices, normals, uvs) to passed on to mesh building function. + * @class + * + * @param {string} objectName Name of the mesh + * @param {string} groupName Name of the group + * @param {string} materialName Name of the material + * @param {number} smoothingGroup Normalized smoothingGroup (0: THREE.FlatShading, 1: THREE.SmoothShading) + */ + var RawObjectDescription = (function () { + + function RawObjectDescription( objectName, groupName, materialName, smoothingGroup ) { + this.objectName = objectName; + this.groupName = groupName; + this.materialName = materialName; + this.smoothingGroup = smoothingGroup; + this.vertices = []; + this.uvs = []; + this.normals = []; + } + + return RawObjectDescription; + })(); + + /** + * MeshCreator is used to transform RawObjectDescriptions to THREE.Mesh + * + * @class + */ + var MeshCreator = (function () { + + function MeshCreator() { + this.sceneGraphBaseNode = null; + this.materials = null; + this.debug = false; + this.globalObjectCount = 1; + + this.validated = false; + } + + MeshCreator.prototype._setSceneGraphBaseNode = function ( sceneGraphBaseNode ) { + this.sceneGraphBaseNode = ( sceneGraphBaseNode == null ) ? ( this.sceneGraphBaseNode == null ? new THREE.Group() : this.sceneGraphBaseNode ) : sceneGraphBaseNode; + }; + + 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._setSceneGraphBaseNode( null ); + this._setMaterials( null ); + this._setDebug( null ); + this.globalObjectCount = 1; + }; + + MeshCreator.prototype._finalize = function () { + this.sceneGraphBaseNode = null; + this.materials = null; + this.validated = false; + }; + + /** + * This is an internal function, but due to its importance to Parser it is documented. + * RawObjectDescriptions are transformed to THREE.Mesh. + * It is ensured that rawObjectDescriptions only contain objects with vertices (no need to check). + * This method shall be overridden by the web worker implementation + * + * @param {RawObjectDescription[]} rawObjectDescriptions Array of descriptive information and data (vertices, normals, uvs) about the parsed object(s) + * @param {number} inputObjectCount Number of objects already retrieved from OBJ + * @param {number} absoluteVertexCount Sum of all vertices of all rawObjectDescriptions + * @param {number} absoluteNormalCount Sum of all normals of all rawObjectDescriptions + * @param {number} absoluteUvCount Sum of all uvs of all rawObjectDescriptions + */ + MeshCreator.prototype._buildMesh = function ( rawObjectDescriptions, inputObjectCount, absoluteVertexCount, absoluteNormalCount, absoluteUvCount ) { + + if ( this.debug ) console.log( 'MeshCreator.buildRawMeshData:\nInput object no.: ' + inputObjectCount ); + + var bufferGeometry = new THREE.BufferGeometry(); + var vertexBA = new THREE.BufferAttribute( new Float32Array( absoluteVertexCount ), 3 ); + bufferGeometry.addAttribute( 'position', vertexBA ); + + var normalBA; + if ( absoluteNormalCount > 0 ) { + + normalBA = new THREE.BufferAttribute( new Float32Array( absoluteNormalCount ), 3 ); + bufferGeometry.addAttribute( 'normal', normalBA ); + + } + var uvBA; + if ( absoluteUvCount > 0 ) { + + uvBA = new THREE.BufferAttribute( new Float32Array( absoluteUvCount ), 2 ); + bufferGeometry.addAttribute( 'uv', uvBA ); + + } + + if ( this.debug ) console.log( 'Creating Multi-Material for object no.: ' + this.globalObjectCount ); + + var rawObjectDescription; + var material; + var materialName; + var createMultiMaterial = rawObjectDescriptions.length > 1; + var materials = []; + var materialIndex = 0; + var materialIndexMapping = []; + var selectedMaterialIndex; + + var vertexBAOffset = 0; + var vertexGroupOffset = 0; + var vertexLength; + var normalOffset = 0; + var uvOffset = 0; + + for ( var oodIndex in rawObjectDescriptions ) { + rawObjectDescription = rawObjectDescriptions[ oodIndex ]; + + materialName = rawObjectDescription.materialName; + material = this.materials[ materialName ]; + if ( ! material ) { + + material = this.materials[ 'defaultMaterial' ]; + if ( ! material ) { + + material = new THREE.MeshStandardMaterial( { color: 0xDCF1FF} ); + material.name = 'defaultMaterial'; + this.materials[ 'defaultMaterial' ] = material; + + } + console.warn( 'object_group "' + rawObjectDescription.objectName + '_' + rawObjectDescription.groupName + '" was defined without material! Assigning "defaultMaterial".' ); + + } + // clone material in case flat shading is needed due to smoothingGroup 0 + if ( rawObjectDescription.smoothingGroup === 0 ) { + + 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; + + } + + } + + vertexLength = rawObjectDescription.vertices.length; + 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; + materials.push( material ); + materialIndex++; + + } + + bufferGeometry.addGroup( vertexGroupOffset, vertexLength / 3, selectedMaterialIndex ); + vertexGroupOffset += vertexLength / 3; + } + + vertexBA.set( rawObjectDescription.vertices, vertexBAOffset ); + vertexBAOffset += vertexLength; + + if ( normalBA ) { + + normalBA.set( rawObjectDescription.normals, normalOffset ); + normalOffset += rawObjectDescription.normals.length; + + } + if ( uvBA ) { + + uvBA.set( rawObjectDescription.uvs, uvOffset ); + uvOffset += rawObjectDescription.uvs.length; + + } + if ( this.debug ) this._printReport( rawObjectDescription, selectedMaterialIndex ); + + } + if ( ! normalBA ) bufferGeometry.computeVertexNormals(); + + if ( createMultiMaterial ) material = new THREE.MultiMaterial( materials ); + var mesh = new THREE.Mesh( bufferGeometry, material ); + this.sceneGraphBaseNode.add( mesh ); + + this.globalObjectCount++; + }; + + MeshCreator.prototype._printReport = function ( rawObjectDescription, selectedMaterialIndex ) { + console.log( + ' Output Object no.: ' + this.globalObjectCount + + '\n objectName: ' + rawObjectDescription.objectName + + '\n groupName: ' + rawObjectDescription.groupName + + '\n materialName: ' + rawObjectDescription.materialName + + '\n materialIndex: ' + selectedMaterialIndex + + '\n smoothingGroup: ' + rawObjectDescription.smoothingGroup + + '\n #vertices: ' + rawObjectDescription.vertices.length / 3 + + '\n #uvs: ' + rawObjectDescription.uvs.length / 2 + + '\n #normals: ' + rawObjectDescription.normals.length / 3 + ); + }; + + return MeshCreator; + })(); + + OBJLoader2.prototype._buildWebWorkerCode = function ( funcBuildObject, funcBuildSingelton ) { + var workerCode = ''; + workerCode += funcBuildObject( 'Consts', Consts ); + workerCode += funcBuildSingelton( 'Parser', 'Parser', Parser ); + workerCode += funcBuildSingelton( 'RawObject', 'RawObject', RawObject ); + workerCode += funcBuildSingelton( 'RawObjectDescription', 'RawObjectDescription', RawObjectDescription ); + return workerCode; + }; + + return OBJLoader2; +})(); diff --git a/examples/js/loaders/WWOBJLoader2.js b/examples/js/loaders/WWOBJLoader2.js new file mode 100644 index 00000000000000..c85b0abd0dc37e --- /dev/null +++ b/examples/js/loaders/WWOBJLoader2.js @@ -0,0 +1,1171 @@ +/** + * @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; + +})(); diff --git a/examples/webgl_loader_obj2.html b/examples/webgl_loader_obj2.html new file mode 100644 index 00000000000000..8660cf4f100eab --- /dev/null +++ b/examples/webgl_loader_obj2.html @@ -0,0 +1,343 @@ + + + + three.js webgl - OBJLoader2 + + + + + + + + +
+ +
+
+ +
+
+ three.js - OBJLoader2 direct loader test +
+
+ + + + + + + + + + + diff --git a/examples/webgl_loader_obj2_ww.html b/examples/webgl_loader_obj2_ww.html new file mode 100644 index 00000000000000..1837331ffa4864 --- /dev/null +++ b/examples/webgl_loader_obj2_ww.html @@ -0,0 +1,491 @@ + + + + three.js webgl - WWOBJLoader2 + + + + + + + + +
+ +
+
+ +
+
+ three.js - OBJLoader2 direct loader test +
+
+ + + + + + + + + + + + + \ No newline at end of file diff --git a/examples/webgl_loader_obj2_ww_parallels.html b/examples/webgl_loader_obj2_ww_parallels.html new file mode 100644 index 00000000000000..3479c65f181524 --- /dev/null +++ b/examples/webgl_loader_obj2_ww_parallels.html @@ -0,0 +1,409 @@ + + + + three.js webgl - Web Worker Parallel Demo + + + + + + + +
+ +
+
+ +
+
+ three.js - WWOBJLoader2Director Parallels Demo +
+
+
+ + + + + + + + + + + + From 75de261d8a92ab6489ee9278d4e6997d4290272d Mon Sep 17 00:00:00 2001 From: Kai Salmen Date: Sat, 25 Mar 2017 13:10:43 +0100 Subject: [PATCH 2/3] #9756 OBJLoader2: - Removed underscores from functions of private classes WWOBJLoader2: - Adjusted naming of web worker classes --- examples/js/loaders/OBJLoader2.js | 206 ++++++++++++++-------------- examples/js/loaders/WWOBJLoader2.js | 88 ++++++------ 2 files changed, 147 insertions(+), 147 deletions(-) diff --git a/examples/js/loaders/OBJLoader2.js b/examples/js/loaders/OBJLoader2.js index 9b39ad50ea6aa3..1627793416c242 100644 --- a/examples/js/loaders/OBJLoader2.js +++ b/examples/js/loaders/OBJLoader2.js @@ -45,7 +45,7 @@ THREE.OBJLoader2 = (function () { * @param {THREE.Object3D} sceneGraphBaseNode Scenegraph object where meshes will be attached */ OBJLoader2.prototype.setSceneGraphBaseNode = function ( sceneGraphBaseNode ) { - this.meshCreator._setSceneGraphBaseNode( sceneGraphBaseNode ); + this.meshCreator.setSceneGraphBaseNode( sceneGraphBaseNode ); }; /** @@ -55,7 +55,7 @@ THREE.OBJLoader2 = (function () { * @param {THREE.MTLLoader.MaterialCreator.materials[]} materials {@link THREE.MTLLoader.MaterialCreator.materials} */ OBJLoader2.prototype.setMaterials = function ( materials ) { - this.meshCreator._setMaterials( materials ); + this.meshCreator.setMaterials( materials ); }; /** @@ -66,8 +66,8 @@ THREE.OBJLoader2 = (function () { * @param {boolean} meshCreatorDebug {@link THREE.OBJLoader2.MeshCreator} will produce debug output */ OBJLoader2.prototype.setDebug = function ( parserDebug, meshCreatorDebug ) { - this.parser._setDebug( parserDebug ); - this.meshCreator._setDebug( meshCreatorDebug ); + this.parser.setDebug( parserDebug ); + this.meshCreator.setDebug( meshCreatorDebug ); }; /** @@ -149,8 +149,8 @@ THREE.OBJLoader2 = (function () { this.fileLoader = ( this.fileLoader == null ) ? new THREE.FileLoader( this.manager ) : this.fileLoader; this.setPath(); - this.parser._validate(); - this.meshCreator._validate(); + this.parser.validate(); + this.meshCreator.validate(); this.validated = true; }; @@ -158,10 +158,10 @@ THREE.OBJLoader2 = (function () { OBJLoader2.prototype._finalize = function () { console.log( 'Global output object count: ' + this.meshCreator.globalObjectCount ); - this.parser._finalize(); + this.parser.finalize(); this.fileLoader = null; var sceneGraphBaseNode = this.meshCreator.sceneGraphBaseNode; - this.meshCreator._finalize(); + this.meshCreator.finalize(); this.validated = false; return sceneGraphBaseNode; @@ -220,11 +220,11 @@ THREE.OBJLoader2 = (function () { this.debug = false; } - Parser.prototype._setDebug = function ( debug ) { + Parser.prototype.setDebug = function ( debug ) { this.debug = ( debug == null ) ? this.debug : debug; }; - Parser.prototype._validate = function () { + Parser.prototype.validate = function () { this.rawObject = new RawObject(); this.inputObjectCount = 1; }; @@ -263,7 +263,7 @@ THREE.OBJLoader2 = (function () { case Consts.CODE_LF: if ( word.length > 0 ) buffer[ bufferPointer++ ] = word; word = ''; - reachedFaces = this._processLine( buffer, bufferPointer, slashes, slashesPointer, reachedFaces ); + reachedFaces = this.processLine( buffer, bufferPointer, slashes, slashesPointer, reachedFaces ); slashesPointer = 0; bufferPointer = 0; break; @@ -311,7 +311,7 @@ THREE.OBJLoader2 = (function () { case Consts.STRING_LF: if ( word.length > 0 ) buffer[ bufferPointer++ ] = word; word = ''; - reachedFaces = this._processLine( buffer, bufferPointer, slashes, slashesPointer, reachedFaces ); + reachedFaces = this.processLine( buffer, bufferPointer, slashes, slashesPointer, reachedFaces ); slashesPointer = 0; bufferPointer = 0; break; @@ -325,7 +325,7 @@ THREE.OBJLoader2 = (function () { } }; - Parser.prototype._processLine = function ( buffer, bufferPointer, slashes, slashesPointer, reachedFaces ) { + Parser.prototype.processLine = function ( buffer, bufferPointer, slashes, slashesPointer, reachedFaces ) { if ( bufferPointer < 1 ) return reachedFaces; var bufferLength = bufferPointer - 1; @@ -335,19 +335,19 @@ THREE.OBJLoader2 = (function () { // object complete instance required if reached faces already (= reached next block of v) if ( reachedFaces ) { - this._processCompletedObject( null, this.rawObject.groupName ); + this.processCompletedObject( null, this.rawObject.groupName ); reachedFaces = false; } - this.rawObject._pushVertex( buffer ); + this.rawObject.pushVertex( buffer ); break; case Consts.LINE_VT: - this.rawObject._pushUv( buffer ); + this.rawObject.pushUv( buffer ); break; case Consts.LINE_VN: - this.rawObject._pushNormal( buffer ); + this.rawObject.pushNormal( buffer ); break; case Consts.LINE_F: @@ -362,33 +362,33 @@ THREE.OBJLoader2 = (function () { if ( slashesPointer > 1 && ( slashes[ 1 ] - slashes[ 0 ] ) === 1 ) { if ( haveQuad ) { - this.rawObject._buildQuadVVn( buffer ); + this.rawObject.buildQuadVVn( buffer ); } else { - this.rawObject._buildFaceVVn( buffer ); + this.rawObject.buildFaceVVn( buffer ); } } else if ( bufferLength === slashesPointer * 2 ) { if ( haveQuad ) { - this.rawObject._buildQuadVVt( buffer ); + this.rawObject.buildQuadVVt( buffer ); } else { - this.rawObject._buildFaceVVt( buffer ); + this.rawObject.buildFaceVVt( buffer ); } } else if ( bufferLength * 2 === slashesPointer * 3 ) { if ( haveQuad ) { - this.rawObject._buildQuadVVtVn( buffer ); + this.rawObject.buildQuadVVtVn( buffer ); } else { - this.rawObject._buildFaceVVtVn( buffer ); + this.rawObject.buildFaceVVtVn( buffer ); } } else { if ( haveQuad ) { - this.rawObject._buildQuadV( buffer ); + this.rawObject.buildQuadV( buffer ); } else { - this.rawObject._buildFaceV( buffer ); + this.rawObject.buildFaceV( buffer ); } } @@ -397,42 +397,42 @@ THREE.OBJLoader2 = (function () { case Consts.LINE_L: if ( bufferLength === slashesPointer * 2 ) { - this.rawObject._buildLineVvt( buffer ); + this.rawObject.buildLineVvt( buffer ); } else { - this.rawObject._buildLineV( buffer ); + this.rawObject.buildLineV( buffer ); } break; case Consts.LINE_S: - this.rawObject._pushSmoothingGroup( buffer[ 1 ] ); + this.rawObject.pushSmoothingGroup( buffer[ 1 ] ); break; case Consts.LINE_G: - this._processCompletedGroup( buffer[ 1 ] ); + this.processCompletedGroup( buffer[ 1 ] ); break; case Consts.LINE_O: if ( this.rawObject.vertices.length > 0 ) { - this._processCompletedObject( buffer[ 1 ], null ); + this.processCompletedObject( buffer[ 1 ], null ); reachedFaces = false; } else { - this.rawObject._pushObject( buffer[ 1 ] ); + this.rawObject.pushObject( buffer[ 1 ] ); } break; case Consts.LINE_MTLLIB: - this.rawObject._pushMtllib( buffer[ 1 ] ); + this.rawObject.pushMtllib( buffer[ 1 ] ); break; case Consts.LINE_USEMTL: - this.rawObject._pushUsemtl( buffer[ 1 ] ); + this.rawObject.pushUsemtl( buffer[ 1 ] ); break; default: @@ -441,29 +441,29 @@ THREE.OBJLoader2 = (function () { return reachedFaces; }; - Parser.prototype._processCompletedObject = function ( objectName, groupName ) { - this.rawObject._finalize( this.meshCreator, this.inputObjectCount, this.debug ); + Parser.prototype.processCompletedObject = function ( objectName, groupName ) { + this.rawObject.finalize( this.meshCreator, this.inputObjectCount, this.debug ); this.inputObjectCount++; - this.rawObject = this.rawObject._newInstanceFromObject( objectName, groupName ); + this.rawObject = this.rawObject.newInstanceFromObject( objectName, groupName ); }; - Parser.prototype._processCompletedGroup = function ( groupName ) { - var notEmpty = this.rawObject._finalize( this.meshCreator, this.inputObjectCount, this.debug ); + Parser.prototype.processCompletedGroup = function ( groupName ) { + var notEmpty = this.rawObject.finalize( this.meshCreator, this.inputObjectCount, this.debug ); if ( notEmpty ) { this.inputObjectCount ++; - this.rawObject = this.rawObject._newInstanceFromGroup( groupName ); + this.rawObject = this.rawObject.newInstanceFromGroup( groupName ); } else { // if a group was set that did not lead to object creation in finalize, then the group name has to be updated - this.rawObject._pushGroup( groupName ); + this.rawObject.pushGroup( groupName ); } }; - Parser.prototype._finalize = function () { - this.rawObject._finalize( this.meshCreator, this.inputObjectCount, this.debug ); + Parser.prototype.finalize = function () { + this.rawObject.finalize( this.meshCreator, this.inputObjectCount, this.debug ); this.inputObjectCount++; }; @@ -498,16 +498,16 @@ THREE.OBJLoader2 = (function () { this.rawObjectDescriptions = []; // this default index is required as it is possible to define faces without 'g' or 'usemtl' - var index = this._buildIndex( this.activeMtlName, this.activeSmoothingGroup ); + var index = this.buildIndex( this.activeMtlName, this.activeSmoothingGroup ); this.rawObjectDescriptionInUse = new RawObjectDescription( this.objectName, this.groupName, this.activeMtlName, this.activeSmoothingGroup ); this.rawObjectDescriptions[ index ] = this.rawObjectDescriptionInUse; } - RawObject.prototype._buildIndex = function ( materialName, smoothingGroup) { + RawObject.prototype.buildIndex = function ( materialName, smoothingGroup) { return materialName + '|' + smoothingGroup; }; - RawObject.prototype._newInstanceFromObject = function ( objectName, groupName ) { + RawObject.prototype.newInstanceFromObject = function ( objectName, groupName ) { var newRawObject = new RawObject( objectName, groupName, this.mtllibName ); // move indices forward @@ -518,7 +518,7 @@ THREE.OBJLoader2 = (function () { return newRawObject; }; - RawObject.prototype._newInstanceFromGroup = function ( groupName ) { + RawObject.prototype.newInstanceFromGroup = function ( groupName ) { var newRawObject = new RawObject( this.objectName, groupName, this.mtllibName ); // keep current buffers and indices forward @@ -532,55 +532,55 @@ THREE.OBJLoader2 = (function () { return newRawObject; }; - RawObject.prototype._pushVertex = function ( buffer ) { + RawObject.prototype.pushVertex = function ( buffer ) { this.vertices.push( parseFloat( buffer[ 1 ] ) ); this.vertices.push( parseFloat( buffer[ 2 ] ) ); this.vertices.push( parseFloat( buffer[ 3 ] ) ); }; - RawObject.prototype._pushUv = function ( buffer ) { + RawObject.prototype.pushUv = function ( buffer ) { this.uvs.push( parseFloat( buffer[ 1 ] ) ); this.uvs.push( parseFloat( buffer[ 2 ] ) ); }; - RawObject.prototype._pushNormal = function ( buffer ) { + RawObject.prototype.pushNormal = function ( buffer ) { this.normals.push( parseFloat( buffer[ 1 ] ) ); this.normals.push( parseFloat( buffer[ 2 ] ) ); this.normals.push( parseFloat( buffer[ 3 ] ) ); }; - RawObject.prototype._pushObject = function ( objectName ) { + RawObject.prototype.pushObject = function ( objectName ) { this.objectName = objectName; }; - RawObject.prototype._pushMtllib = function ( mtllibName ) { + RawObject.prototype.pushMtllib = function ( mtllibName ) { this.mtllibName = mtllibName; }; - RawObject.prototype._pushGroup = function ( groupName ) { + RawObject.prototype.pushGroup = function ( groupName ) { this.groupName = groupName; - this._verifyIndex(); + this.verifyIndex(); }; - RawObject.prototype._pushUsemtl = function ( mtlName ) { + RawObject.prototype.pushUsemtl = function ( mtlName ) { if ( this.activeMtlName === mtlName || mtlName == null ) return; this.activeMtlName = mtlName; this.mtlCount++; - this._verifyIndex(); + this.verifyIndex(); }; - RawObject.prototype._pushSmoothingGroup = function ( activeSmoothingGroup ) { + RawObject.prototype.pushSmoothingGroup = function ( activeSmoothingGroup ) { var normalized = activeSmoothingGroup === 'off' ? 0 : activeSmoothingGroup; if ( this.activeSmoothingGroup === normalized ) return; this.activeSmoothingGroup = normalized; this.smoothingGroupCount++; - this._verifyIndex(); + this.verifyIndex(); }; - RawObject.prototype._verifyIndex = function () { - var index = this._buildIndex( this.activeMtlName, ( this.activeSmoothingGroup === 0 ) ? 0 : 1 ); + RawObject.prototype.verifyIndex = function () { + var index = this.buildIndex( this.activeMtlName, ( this.activeSmoothingGroup === 0 ) ? 0 : 1 ); if ( this.rawObjectDescriptions[ index ] == null ) { this.rawObjectDescriptionInUse = this.rawObjectDescriptions[ index ] = @@ -595,63 +595,63 @@ THREE.OBJLoader2 = (function () { } }; - RawObject.prototype._buildQuadVVtVn = function ( indexArray ) { + RawObject.prototype.buildQuadVVtVn = function ( indexArray ) { for ( var i = 0; i < 6; i ++ ) { - this._attachFaceV_( indexArray[ Consts.QUAD_INDICES_3[ i ] ] ); - this._attachFaceVt( indexArray[ Consts.QUAD_INDICES_3[ i ] + 1 ] ); - this._attachFaceVn( indexArray[ Consts.QUAD_INDICES_3[ i ] + 2 ] ); + this.attachFaceV_( indexArray[ Consts.QUAD_INDICES_3[ i ] ] ); + this.attachFaceVt( indexArray[ Consts.QUAD_INDICES_3[ i ] + 1 ] ); + this.attachFaceVn( indexArray[ Consts.QUAD_INDICES_3[ i ] + 2 ] ); } }; - RawObject.prototype._buildQuadVVt = function ( indexArray ) { + RawObject.prototype.buildQuadVVt = function ( indexArray ) { for ( var i = 0; i < 6; i ++ ) { - this._attachFaceV_( indexArray[ Consts.QUAD_INDICES_2[ i ] ] ); - this._attachFaceVt( indexArray[ Consts.QUAD_INDICES_2[ i ] + 1 ] ); + this.attachFaceV_( indexArray[ Consts.QUAD_INDICES_2[ i ] ] ); + this.attachFaceVt( indexArray[ Consts.QUAD_INDICES_2[ i ] + 1 ] ); } }; - RawObject.prototype._buildQuadVVn = function ( indexArray ) { + RawObject.prototype.buildQuadVVn = function ( indexArray ) { for ( var i = 0; i < 6; i ++ ) { - this._attachFaceV_( indexArray[ Consts.QUAD_INDICES_2[ i ] ] ); - this._attachFaceVn( indexArray[ Consts.QUAD_INDICES_2[ i ] + 1 ] ); + this.attachFaceV_( indexArray[ Consts.QUAD_INDICES_2[ i ] ] ); + this.attachFaceVn( indexArray[ Consts.QUAD_INDICES_2[ i ] + 1 ] ); } }; - RawObject.prototype._buildQuadV = function ( indexArray ) { + RawObject.prototype.buildQuadV = function ( indexArray ) { for ( var i = 0; i < 6; i ++ ) { - this._attachFaceV_( indexArray[ Consts.QUAD_INDICES_1[ i ] ] ); + this.attachFaceV_( indexArray[ Consts.QUAD_INDICES_1[ i ] ] ); } }; - RawObject.prototype._buildFaceVVtVn = function ( indexArray ) { + RawObject.prototype.buildFaceVVtVn = function ( indexArray ) { for ( var i = 1; i < 10; i += 3 ) { - this._attachFaceV_( indexArray[ i ] ); - this._attachFaceVt( indexArray[ i + 1 ] ); - this._attachFaceVn( indexArray[ i + 2 ] ); + this.attachFaceV_( indexArray[ i ] ); + this.attachFaceVt( indexArray[ i + 1 ] ); + this.attachFaceVn( indexArray[ i + 2 ] ); } }; - RawObject.prototype._buildFaceVVt = function ( indexArray ) { + RawObject.prototype.buildFaceVVt = function ( indexArray ) { for ( var i = 1; i < 7; i += 2 ) { - this._attachFaceV_( indexArray[ i ] ); - this._attachFaceVt( indexArray[ i + 1 ] ); + this.attachFaceV_( indexArray[ i ] ); + this.attachFaceVt( indexArray[ i + 1 ] ); } }; - RawObject.prototype._buildFaceVVn = function ( indexArray ) { + RawObject.prototype.buildFaceVVn = function ( indexArray ) { for ( var i = 1; i < 7; i += 2 ) { - this._attachFaceV_( indexArray[ i ] ); - this._attachFaceVn( indexArray[ i + 1 ] ); + this.attachFaceV_( indexArray[ i ] ); + this.attachFaceVn( indexArray[ i + 1 ] ); } }; - RawObject.prototype._buildFaceV = function ( indexArray ) { + RawObject.prototype.buildFaceV = function ( indexArray ) { for ( var i = 1; i < 4; i ++ ) { - this._attachFaceV_( indexArray[ i ] ); + this.attachFaceV_( indexArray[ i ] ); } }; - RawObject.prototype._attachFaceV_ = function ( faceIndex ) { + RawObject.prototype.attachFaceV_ = function ( faceIndex ) { var faceIndexInt = parseInt( faceIndex ); var index = ( faceIndexInt - this.globalVertexOffset ) * 3; @@ -661,7 +661,7 @@ THREE.OBJLoader2 = (function () { rodiu.vertices.push( this.vertices[ index ] ); }; - RawObject.prototype._attachFaceVt = function ( faceIndex ) { + RawObject.prototype.attachFaceVt = function ( faceIndex ) { var faceIndexInt = parseInt( faceIndex ); var index = ( faceIndexInt - this.globalUvOffset ) * 2; @@ -670,7 +670,7 @@ THREE.OBJLoader2 = (function () { rodiu.uvs.push( this.uvs[ index ] ); }; - RawObject.prototype._attachFaceVn = function ( faceIndex ) { + RawObject.prototype.attachFaceVn = function ( faceIndex ) { var faceIndexInt = parseInt( faceIndex ); var index = ( faceIndexInt - this.globalNormalOffset ) * 3; @@ -685,7 +685,7 @@ THREE.OBJLoader2 = (function () { * 0: "f vertex/uv vertex/uv ..." * 1: "f vertex vertex ..." */ - RawObject.prototype._buildLineVvt = function ( lineArray ) { + RawObject.prototype.buildLineVvt = function ( lineArray ) { var length = lineArray.length; for ( var i = 1; i < length; i ++ ) { this.vertices.push( parseInt( lineArray[ i ] ) ); @@ -693,7 +693,7 @@ THREE.OBJLoader2 = (function () { } }; - RawObject.prototype._buildLineV = function ( lineArray ) { + RawObject.prototype.buildLineV = function ( lineArray ) { var length = lineArray.length; for ( var i = 1; i < length; i++ ) { this.vertices.push( parseInt( lineArray[ i ] ) ); @@ -703,7 +703,7 @@ THREE.OBJLoader2 = (function () { /** * Clear any empty rawObjectDescription and calculate absolute vertex, normal and uv counts */ - RawObject.prototype._finalize = function ( meshCreator, inputObjectCount, debug ) { + RawObject.prototype.finalize = function ( meshCreator, inputObjectCount, debug ) { var temp = this.rawObjectDescriptions; this.rawObjectDescriptions = []; var rawObjectDescription; @@ -730,8 +730,8 @@ THREE.OBJLoader2 = (function () { var notEmpty = false; if ( index > 0 ) { - if ( debug ) this._createReport( inputObjectCount, true ); - meshCreator._buildMesh( + if ( debug ) this.createReport( inputObjectCount, true ); + meshCreator.buildMesh( this.rawObjectDescriptions, inputObjectCount, absoluteVertexCount, @@ -744,7 +744,7 @@ THREE.OBJLoader2 = (function () { return notEmpty; }; - RawObject.prototype._createReport = function ( inputObjectCount, printDirectly ) { + RawObject.prototype.createReport = function ( inputObjectCount, printDirectly ) { var report = { name: this.objectName ? this.objectName : 'groups', mtllibName: this.mtllibName, @@ -814,28 +814,28 @@ THREE.OBJLoader2 = (function () { this.validated = false; } - MeshCreator.prototype._setSceneGraphBaseNode = function ( sceneGraphBaseNode ) { + MeshCreator.prototype.setSceneGraphBaseNode = function ( sceneGraphBaseNode ) { this.sceneGraphBaseNode = ( sceneGraphBaseNode == null ) ? ( this.sceneGraphBaseNode == null ? new THREE.Group() : this.sceneGraphBaseNode ) : sceneGraphBaseNode; }; - MeshCreator.prototype._setMaterials = function ( materials ) { + MeshCreator.prototype.setMaterials = function ( materials ) { this.materials = ( materials == null ) ? ( this.materials == null ? { materials: [] } : this.materials ) : materials; }; - MeshCreator.prototype._setDebug = function ( debug ) { + MeshCreator.prototype.setDebug = function ( debug ) { this.debug = ( debug == null ) ? this.debug : debug; }; - MeshCreator.prototype._validate = function () { + MeshCreator.prototype.validate = function () { if ( this.validated ) return; - this._setSceneGraphBaseNode( null ); - this._setMaterials( null ); - this._setDebug( null ); + this.setSceneGraphBaseNode( null ); + this.setMaterials( null ); + this.setDebug( null ); this.globalObjectCount = 1; }; - MeshCreator.prototype._finalize = function () { + MeshCreator.prototype.finalize = function () { this.sceneGraphBaseNode = null; this.materials = null; this.validated = false; @@ -853,7 +853,7 @@ THREE.OBJLoader2 = (function () { * @param {number} absoluteNormalCount Sum of all normals of all rawObjectDescriptions * @param {number} absoluteUvCount Sum of all uvs of all rawObjectDescriptions */ - MeshCreator.prototype._buildMesh = function ( rawObjectDescriptions, inputObjectCount, absoluteVertexCount, absoluteNormalCount, absoluteUvCount ) { + MeshCreator.prototype.buildMesh = function ( rawObjectDescriptions, inputObjectCount, absoluteVertexCount, absoluteNormalCount, absoluteUvCount ) { if ( this.debug ) console.log( 'MeshCreator.buildRawMeshData:\nInput object no.: ' + inputObjectCount ); @@ -960,7 +960,7 @@ THREE.OBJLoader2 = (function () { uvOffset += rawObjectDescription.uvs.length; } - if ( this.debug ) this._printReport( rawObjectDescription, selectedMaterialIndex ); + if ( this.debug ) this.printReport( rawObjectDescription, selectedMaterialIndex ); } if ( ! normalBA ) bufferGeometry.computeVertexNormals(); @@ -972,7 +972,7 @@ THREE.OBJLoader2 = (function () { this.globalObjectCount++; }; - MeshCreator.prototype._printReport = function ( rawObjectDescription, selectedMaterialIndex ) { + MeshCreator.prototype.printReport = function ( rawObjectDescription, selectedMaterialIndex ) { console.log( ' Output Object no.: ' + this.globalObjectCount + '\n objectName: ' + rawObjectDescription.objectName + diff --git a/examples/js/loaders/WWOBJLoader2.js b/examples/js/loaders/WWOBJLoader2.js index c85b0abd0dc37e..121d086cafae58 100644 --- a/examples/js/loaders/WWOBJLoader2.js +++ b/examples/js/loaders/WWOBJLoader2.js @@ -556,9 +556,9 @@ THREE.OBJLoader2.WWOBJLoader2 = (function () { console.time( 'buildWebWorkerCode' ); var wwDef = (function () { - function OBJLoader() { - this.meshCreator = new MeshCreator(); - this.parser = new Parser( this.meshCreator ); + function WWOBJLoader() { + this.wwMeshCreator = new WWMeshCreator(); + this.parser = new Parser( this.wwMeshCreator ); this.validated = false; this.cmdState = 'created'; @@ -571,9 +571,9 @@ THREE.OBJLoader2.WWOBJLoader2 = (function () { * @param parserDebug * @param meshCreatorDebug */ - OBJLoader.prototype._setDebug = function ( parserDebug, meshCreatorDebug ) { - this.parser._setDebug( parserDebug ); - this.meshCreator._setDebug( meshCreatorDebug ); + WWOBJLoader.prototype.setDebug = function ( parserDebug, meshCreatorDebug ) { + this.parser.setDebug( parserDebug ); + this.wwMeshCreator.setDebug( meshCreatorDebug ); }; /** @@ -581,11 +581,11 @@ THREE.OBJLoader2.WWOBJLoader2 = (function () { * * @param arrayBuffer */ - OBJLoader.prototype.parse = function ( arrayBuffer ) { + WWOBJLoader.prototype.parse = function ( arrayBuffer ) { console.log( 'Parsing arrayBuffer...' ); console.time( 'parseArrayBuffer' ); - this._validate(); + this.validate(); this.parser.parseArrayBuffer( arrayBuffer ); var objGroup = this._finalize(); @@ -594,33 +594,33 @@ THREE.OBJLoader2.WWOBJLoader2 = (function () { return objGroup; }; - OBJLoader.prototype._validate = function () { + WWOBJLoader.prototype.validate = function () { if ( this.validated ) return; - this.parser._validate(); - this.meshCreator._validate(); + this.parser.validate(); + this.wwMeshCreator.validate(); this.validated = true; }; - OBJLoader.prototype._finalize = function () { - console.log( 'Global output object count: ' + this.meshCreator.globalObjectCount ); - this.parser._finalize(); - this.meshCreator._finalize(); + WWOBJLoader.prototype._finalize = function () { + console.log( 'Global output object count: ' + this.wwMeshCreator.globalObjectCount ); + this.parser.finalize(); + this.wwMeshCreator.finalize(); this.validated = false; }; - OBJLoader.prototype.init = function ( payload ) { + WWOBJLoader.prototype.init = function ( payload ) { this.cmdState = 'init'; - this._setDebug( payload.debug, payload.debug ); + this.setDebug( payload.debug, payload.debug ); }; - OBJLoader.prototype.setMaterials = function ( payload ) { + WWOBJLoader.prototype.setMaterials = function ( payload ) { this.cmdState = 'setMaterials'; - this.meshCreator._setMaterials( payload.materialNames ); + this.wwMeshCreator.setMaterials( payload.materialNames ); }; - OBJLoader.prototype.run = function ( payload ) { + WWOBJLoader.prototype.run = function ( payload ) { this.cmdState = 'run'; this.parse( payload.objAsArrayBuffer ); @@ -633,35 +633,35 @@ THREE.OBJLoader2.WWOBJLoader2 = (function () { } ); }; - return OBJLoader; + return WWOBJLoader; })(); var wwMeshCreatorDef = (function () { - function MeshCreator() { + function WWMeshCreator() { this.materials = null; this.debug = false; this.globalObjectCount = 1; this.validated = false; } - MeshCreator.prototype._setMaterials = function ( materials ) { + WWMeshCreator.prototype.setMaterials = function ( materials ) { this.materials = ( materials == null ) ? ( this.materials == null ? { materials: [] } : this.materials ) : materials; }; - MeshCreator.prototype._setDebug = function ( debug ) { + WWMeshCreator.prototype.setDebug = function ( debug ) { this.debug = ( debug == null ) ? this.debug : debug; }; - MeshCreator.prototype._validate = function () { + WWMeshCreator.prototype.validate = function () { if ( this.validated ) return; - this._setMaterials( null ); - this._setDebug( null ); + this.setMaterials( null ); + this.setDebug( null ); this.globalObjectCount = 1; }; - MeshCreator.prototype._finalize = function () { + WWMeshCreator.prototype.finalize = function () { this.materials = null; this.validated = false; }; @@ -676,7 +676,7 @@ THREE.OBJLoader2.WWOBJLoader2 = (function () { * @param absoluteNormalCount * @param absoluteUvCount */ - MeshCreator.prototype._buildMesh = function ( rawObjectDescriptions, inputObjectCount, absoluteVertexCount, absoluteNormalCount, absoluteUvCount ) { + WWMeshCreator.prototype.buildMesh = function ( rawObjectDescriptions, inputObjectCount, absoluteVertexCount, absoluteNormalCount, absoluteUvCount ) { if ( this.debug ) console.log( 'OBJLoader.buildMesh:\nInput object no.: ' + inputObjectCount ); var vertexFa = new Float32Array( absoluteVertexCount ); @@ -774,34 +774,34 @@ THREE.OBJLoader2.WWOBJLoader2 = (function () { this.globalObjectCount++; }; - return MeshCreator; + return WWMeshCreator; })(); - var wwLoaderRunnerDef = (function () { + var wwObjLoaderRunnerDef = (function () { - function OBJLoaderRunner() { + function WWOBJLoaderRunner() { self.addEventListener( 'message', this.runner, false ); } - OBJLoaderRunner.prototype.runner = function ( event ) { + WWOBJLoaderRunner.prototype.runner = function ( event ) { var payload = event.data; - console.log( 'Command state before: ' + OBJLoaderRef.cmdState ); + console.log( 'Command state before: ' + WWOBJLoaderRef.cmdState ); switch ( payload.cmd ) { case 'init': - OBJLoaderRef.init( payload ); + WWOBJLoaderRef.init( payload ); break; case 'setMaterials': - OBJLoaderRef.setMaterials( payload ); + WWOBJLoaderRef.setMaterials( payload ); break; case 'run': - OBJLoaderRef.run( payload ); + WWOBJLoaderRef.run( payload ); break; default: @@ -811,10 +811,10 @@ THREE.OBJLoader2.WWOBJLoader2 = (function () { } - console.log( 'Command state after: ' + OBJLoaderRef.cmdState ); + console.log( 'Command state after: ' + WWOBJLoaderRef.cmdState ); }; - return OBJLoaderRunner; + return WWOBJLoaderRunner; })(); var buildObject = function ( fullName, object ) { @@ -882,11 +882,11 @@ THREE.OBJLoader2.WWOBJLoader2 = (function () { 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'; + this.workerCode += buildSingelton( 'WWOBJLoader', 'WWOBJLoader', wwDef ); + this.workerCode += buildSingelton( 'WWMeshCreator', 'WWMeshCreator', wwMeshCreatorDef ); + this.workerCode += 'WWOBJLoaderRef = new WWOBJLoader();\n\n'; + this.workerCode += buildSingelton( 'WWOBJLoaderRunner', 'WWOBJLoaderRunner', wwObjLoaderRunnerDef ); + this.workerCode += 'new WWOBJLoaderRunner();\n\n'; console.timeEnd( 'buildWebWorkerCode' ); } From 0ff805ff84eac4a23beb792866a75dd1ab229633 Mon Sep 17 00:00:00 2001 From: Kai Salmen Date: Wed, 22 Mar 2017 08:16:54 +0100 Subject: [PATCH 3/3] #9756 Updated to WWOBJLoader2 V1.1.0: Adjusted to removal of MultiMaterial --- examples/js/loaders/OBJLoader.js | 3 +-- examples/js/loaders/OBJLoader2.js | 4 ++-- examples/js/loaders/WWOBJLoader2.js | 5 ++--- 3 files changed, 5 insertions(+), 7 deletions(-) diff --git a/examples/js/loaders/OBJLoader.js b/examples/js/loaders/OBJLoader.js index c11b68b657e194..6556a4d4f59bc8 100644 --- a/examples/js/loaders/OBJLoader.js +++ b/examples/js/loaders/OBJLoader.js @@ -720,8 +720,7 @@ THREE.OBJLoader.prototype = { } - var multiMaterial = new THREE.MultiMaterial( createdMaterials ); - mesh = ( ! isLine ? new THREE.Mesh( buffergeometry, multiMaterial ) : new THREE.LineSegments( buffergeometry, multiMaterial ) ); + mesh = ( ! isLine ? new THREE.Mesh( buffergeometry, createdMaterials ) : new THREE.LineSegments( buffergeometry, createdMaterials ) ); } else { diff --git a/examples/js/loaders/OBJLoader2.js b/examples/js/loaders/OBJLoader2.js index 1627793416c242..82d9d3bfdeb2f7 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.6'; +THREE.OBJLoader2.version = '1.1.0'; /** * Use this class to load OBJ data from files or to parse OBJ data from arraybuffer or text @@ -965,7 +965,7 @@ THREE.OBJLoader2 = (function () { } if ( ! normalBA ) bufferGeometry.computeVertexNormals(); - if ( createMultiMaterial ) material = new THREE.MultiMaterial( materials ); + if ( createMultiMaterial ) material = materials; var mesh = new THREE.Mesh( bufferGeometry, material ); this.sceneGraphBaseNode.add( mesh ); diff --git a/examples/js/loaders/WWOBJLoader2.js b/examples/js/loaders/WWOBJLoader2.js index 121d086cafae58..3ed4cd21b51029 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.6'; +THREE.OBJLoader2.version = '1.1.0'; /** * OBJ data will be loaded by dynamically created web worker. @@ -416,10 +416,9 @@ THREE.OBJLoader2.WWOBJLoader2 = (function () { if ( createMultiMaterial ) multiMaterials.push( material ); } - if ( createMultiMaterial ) { - material = new THREE.MultiMaterial( multiMaterials ); + material = multiMaterials; var materialGroups = payload.materialGroups; var materialGroup; for ( var key in materialGroups ) {