ソースを参照

Merge pull request #12200 from kaisalmen/OBJLoader_V2_Update

OBJLoader2 Version 2.0.0: Documentation and additional enhancements
Mr.doob 7 年 前
コミット
d9d2999d51

+ 260 - 0
docs/examples/loaders/LoaderSupport.html

@@ -0,0 +1,260 @@
+<!DOCTYPE html>
+<html lang="en">
+	<head>
+		<meta charset="utf-8" />
+		<base href="../../" />
+		<script src="list.js"></script>
+		<script src="page.js"></script>
+		<link type="text/css" rel="stylesheet" href="page.css" />
+	</head>
+	<body>
+
+		<h1>[name]</h1>
+
+		<div class="desc">Supporting classes for file loaders.</div>
+
+		<h2>Sub-Classes</h2>
+		[page:LoaderSupport.Builder]<br>
+		[page:LoaderSupport.LoadedMeshUserOverride]<br>
+		[page:LoaderSupport.Commons]<br>
+		[page:LoaderSupport.PrepData]<br>
+		[page:LoaderSupport.Callbacks]<br>
+		[page:LoaderSupport.WorkerDirector]<br>
+		[page:LoaderSupport.WorkerSupport]
+
+		<h2>Example</h2>
+
+		[example:webgl_loader_obj2_meshspray] - Example using [page:LoaderSupport.LoaderWorkerDirector] and [page:LoaderSupport.LoaderWorkerSupport].<br>
+
+		<h2>Classes</h2>
+		<br>
+
+		<a name="Builder"></a><h1>Builder</h1>
+		<h2>Constructor</h2>
+
+		<h3>Builder()</h3>
+		<div>
+			Builds one or many THREE.Mesh from one raw set of Arraybuffers, materialGroup descriptions and further parameters.
+			Supports vertex, vertexColor, normal, uv and index buffers.
+		</div>
+
+		<h2>Methods</h2>
+		TODO
+		<br>
+		<br>
+
+
+		<a name="LoadedMeshUserOverride"></a><h1>LoadedMeshUserOverride</h1>
+		<h2>Constructor</h2>
+
+		<h3>LoadedMeshUserOverride( [page:Boolean disregardMesh], [page:THREE.BufferGeometry bufferGeometry], [page:THREE.Material material] )</h3>
+		<div>
+			[page:Boolean disregardMesh] - Tell implementation to completely disregard this mesh<br>
+			[page:Boolean alteredMesh] - Tell implementation that mesh(es) have been altered or added
+		</div>
+		<div>
+			Object to return by callback onMeshAlter. Used to disregard a certain mesh or to return one to many meshes.
+		</div>
+
+		<h2>Methods</h2>
+		TODO
+		<br>
+		<br>
+
+
+		<h3>Commons()</h3>
+		<div>
+			Base class to be used by loaders.
+		</div>
+
+		<h2>Methods</h2>
+		TODO
+		<br>
+		<br>
+
+
+		<a name="PrepData"></a><h1>PrepData</h1>
+		<h2>Constructor</h2>
+
+		<h3>PrepData( [page:String modelName] )</h3>
+		<div>
+			[page:String modelName] - Overall name of the model
+		</div>
+		<div>
+			Configuration instructions to be used by run method.
+		</div>
+
+		<h2>Methods</h2>
+
+		<h3>[method:null setStreamMeshesTo] ( [page:Object3D streamMeshesTo] )</h3>
+		<div>
+			[page:Object3D streamMeshesTo] - Object already attached to scenegraph where new meshes will be attached to
+		</div>
+		<div>
+			Set the node where the loaded objects will be attached directly.
+		</div>
+
+
+		<h3>[method:null setMaterialPerSmoothingGroup] ( [page:boolean materialPerSmoothingGroup] )</h3>
+		<div>
+			[page:boolean materialPerSmoothingGroup]
+		</div>
+		<div>
+			Tells whether a material shall be created per smoothing group.
+		</div>
+
+
+		<h3>[method:null setUseIndices]( [page:Boolean useIndices] )</h3>
+		<div>
+			[page:Boolean useIndices] - Default is false
+		</div>
+		<div>
+			Instructs loaders to create indexed [page:BufferGeometry].
+		</div>
+
+
+		<h3>[method:null setDisregardNormals]( [page:Boolean disregardNormals] )</h3>
+		<div>
+			[page:Boolean disregardNormals]
+		</div>
+		<div>
+			Tells whether normals should be completely disregarded and regenerated.
+		</div>
+
+
+		<h3>[method:Callbacks getCallbacks]()</h3>
+		<div>
+			Returns all callbacks as [page:LoaderSupport.Callbacks].
+		</div>
+
+
+		<h3>[method:null setCrossOrigin]( [page:String crossOrigin] )</h3>
+		<div>
+			[page:String crossOrigin] - CORS value
+		</div>
+		<div>
+			Sets the CORS string to be used.
+		</div>
+
+
+		<h3>[method:null addResource]( [page:LoaderSupport.ResourceDescriptor resource] )</h3>
+		<div>
+			[page:LoaderSupport.ResourceDescriptor resource]
+		</div>
+		<div>
+			Add a resource description.
+		</div>
+
+
+		<h3>[method:null setUseAsync]( [page:Boolean useAsync] )</h3>
+		<div>
+			[page:Boolean useAsync]
+		</div>
+		<div>
+			If true uses async loading with worker, if false loads data synchronously.
+		</div>
+		<br>
+		<br>
+
+
+		<a name="Callbacks"></a><h1>Callbacks</h1>
+		<h2>Constructor</h2>
+
+		<h3>Callbacks()</h3>
+		<div>
+			Callbacks utilized by loaders and builder.
+		</div>
+
+		<h2>Methods</h2>
+		TODO
+		<br>
+		<br>
+
+
+		<a name="WorkerDirector"></a><h1>WorkerDirector</h1>
+		<h2>Constructor</h2>
+
+		<h3>WorkerDirector( [page:String classDef], [page:LoaderSupport.ConsoleLogger logger] )</h3>
+		<div>
+			[page:String classDef] - Class definition to be used for construction<br>
+			[page:LoaderSupport.ConsoleLogger logger] - logger to be used
+		</div>
+		<div>
+			Orchestrate loading of multiple OBJ files/data from an instruction queue with a configurable amount of workers (1-16).<br>
+			- Workflow:<br>
+			- prepareWorkers<br>
+			- enqueueForRun<br>
+			- processQueue<br>
+			- deregister
+		</div>
+
+
+		<h3>[method:null prepareWorkers]( [page:WWOBJLoader2.Callbacks globalCallbacks], [page:Number maxQueueSize], [page:Number maxWebWorkers] )</h3>
+		<div>
+			[page:LoaderSupport.Callbacks globalCallbacks] - Register global callbacks used by all web workers<br>
+			[page:Number maxQueueSize] - Set the maximum size of the instruction queue (1-1024)<br>
+			[page:Number maxWebWorkers] - Set the maximum amount of workers (1-16)
+		</div>
+		<div>
+			Create or destroy workers according limits. Set the name and register callbacks for dynamically created web workers.
+		</div>
+
+
+		<h3>[method:null enqueueForRun]( [page:LoaderSupport.PrepData runParams] )</h3>
+		<div>
+			[page:LoaderSupport.PrepData runParams]
+		</div>
+		<div>
+			Store run instructions in internal instructionQueue.
+		</div>
+
+
+		<h3>[method:null processQueue]()</h3>
+		<div>
+			Process the instructionQueue until it is depleted.
+		</div>
+
+
+		<h3>[method:null deregister]()</h3>
+		<div>
+			Terminate all workers.
+		</div>
+
+
+		<h3>[method:null getMaxQueueSize]()</h3>
+		<div>
+			Returns the maximum length of the instruction queue.
+		</div>
+
+
+		<h3>[method:null getMaxWebWorkers]()</h3>
+		<div>
+			Returns the maximum number of workers.
+		</div>
+
+
+		<h3>[method:null setCrossOrigin]( [page:String crossOrigin] )</h3>
+		<div>
+			[page:String crossOrigin] - CORS value
+		</div>
+		<div>
+			Sets the CORS string to be used.
+		</div>
+
+
+		<h3>WorkerSupport()</h3>
+		<div>
+			WorkerSupport
+		</div>
+
+		<h2>Methods</h2>
+		TODO
+		<br>
+
+
+		<h2>Source</h2>
+
+		[link:https://github.com/mrdoob/three.js/blob/master/examples/js/loaders/LoaderSupport.js examples/js/loaders/LoaderSupport.js]
+
+	</body>
+</html>

+ 86 - 34
docs/examples/loaders/OBJLoader2.html

@@ -13,98 +13,150 @@
 
 		<div class="desc">A loader for loading an <em>.obj</em> resource.</div>
 
-		<h2>Example</h2>
+		<h2>Examples</h2>
 
 		<code>
 		// instantiate the loader
 		var loader = new THREE.OBJLoader2();
 
 		// function called on successful load
-		var intergrateIntoScene = function ( object ) {
-			scene.add( object );
+		var callbackOnLoad = function ( event ) {
+			scene.add( event.detail.loaderRootNode );
 		};
 
-		// load a resource from provided URL
-		loader.load( 'obj/female02/female02.obj', intergrateIntoScene );
+		// load a resource from provided URL synchronously
+		loader.load( 'obj/female02/female02.obj', callbackOnLoad, null, null, null, false );
 		</code>
 
-		[example:webgl_loader_obj2]
+		[example:webgl_loader_obj2] - Simple example <br>
+		[example:webgl_loader_obj2_options] - Example for multiple use-cases (parse, load and run with instructions (sync and async)<br>
+		[example:webgl_loader_obj2_run_director] - Advanced example using [page:LoaderSupport.LoaderWorkerDirector] for orchestration of multiple workers.
 
 
 		<h2>Constructor</h2>
 
 		<h3>[name]( [page:LoadingManager manager] )</h3>
 		<div>
-		[page:LoadingManager manager] — The [page:LoadingManager loadingManager] for the loader to use. Default is [page:LoadingManager THREE.DefaultLoadingManager].
+			[page:LoadingManager manager] - The [page:LoadingManager loadingManager] for the loader to use. Default is [page:LoadingManager THREE.DefaultLoadingManager].
 		</div>
 		<div>
 			Use [name] to load OBJ data from files or to parse OBJ data from arraybuffer or text.
 		</div>
 
-		<h2>Properties</h2>
-
 
 		<h2>Methods</h2>
 
-		<h3>[method:null load]( [page:String url], [page:Function onLoad], [page:Function onProgress], [page:Function onError], [page:Boolean useArrayBuffer] )</h3>
+		<h3>[method:Object3D parse]( {[page:arraybuffer content]|[page:String content]] )</h3>
 		<div>
-			[page:String url] — URL of the file to load<br />
-			[page:Function onLoad] — Called after loading was successfully completed. The argument will be the loaded [page:Object3D].<br />
-			[page:Function onProgress] — Called to report progress of loading. The argument will be the XMLHttpRequest instance, which contains .[page:Integer total] and .[page:Integer loaded] bytes.<br />
-			[page:Function onError]  Called after an error occurred during loading.<br />
-			[page:boolean useArrayBuffer] — Set this to false to force string based parsing<br />
+			[[page:arraybuffer content]|[page:String content]] OBJ data as Uint8Array or String
 		</div>
 		<div>
-			Use this convenient method to load an OBJ file at the given URL. Per default the fileLoader uses an arraybuffer
+			Parses OBJ data synchronously from arraybuffer or string and returns the [page:Object3D loaderRoorNode].
 		</div>
 
-		<h3>[method:Object3D parse]( [page:ArrayBuffer arrayBuffer] )</h3>
+
+		<h3>[method:Object3D parseAsync]( [page:arraybuffer content], [page:Function onLoad] )</h3>
 		<div>
-			[page:ArrayBuffer arrayBuffer] — OBJ data as Uint8Array
+			[page:arraybuffer content] - OBJ data as Uint8Array<br>
+			[page:Function onLoad] - Called after worker successfully completed loading<br>
 		</div>
 		<div>
-			Default parse function: Parses OBJ file content stored in arrayBuffer and returns the [page:Object3D sceneGraphBaseNode].
+			Parses OBJ content asynchronously from arraybuffer.
 		</div>
 
-		<h3>[method:Object3D parseText]( [page:String test] )</h3>
+
+		<h3>[method:null load]( [page:String url], [page:Function onLoad], [page:Function onProgress], [page:Function onError], [page:Function onMeshAlter], [page:boolean useAsync] )</h3>
 		<div>
-			[page:String text] — OBJ data as string
+			[page:String url] - URL of the file to load<br>
+			[page:Function onLoad] - Called after loading was successfully completed<br>
+			[page:Function onProgress] - Called to report progress of loading. The argument will be the XMLHttpRequest instance, which contains .[page:Integer total] and .[page:Integer loaded] bytes.<br>
+			[page:Function onError] - Called after an error occurred during loading.<br>
+			[page:Function onMeshAlter] - Called after a new mesh raw data becomes available to allow alteration<br>
+			[page:boolean useAsync] - If true uses async loading with worker, if false loads data synchronously
 		</div>
 		<div>
-			Legacy parse function: Parses OBJ file content stored in string and returns the [page:Object3D sceneGraphBaseNode].
+			Use this convenient method to load an OBJ file at the given URL. Per default the fileLoader uses an arraybuffer.
 		</div>
 
-		<h3>[method:null setMaterials] ( Array of [page:Material materials] )</h3>
+
+		<h3>[method:null run]( [page:LoaderSupport.PrepData params], [page:LoaderSupport.WorkerSupport workerSupportExternal] )</h3>
 		<div>
-			Array of [page:Material materials] — Array of [page:Material Materials] from MTLLoader
+			[page:LoaderSupport.PrepData params] - prepData All parameters and resources required for execution<br>
+			[page:LoaderSupport.WorkerSupport workerSupportExternal] - Use pre-existing WorkerSupport
 		</div>
 		<div>
-			Set materials loaded by MTLLoader or any other supplier of an Array of [page:Material Materials].
+			Run the loader according the provided instructions.
+		</div>
+
+
+		<h3>[method:null setMaterialPerSmoothingGroup] ( [page:boolean materialPerSmoothingGroup] )</h3>
+		<div>
+			[page:boolean materialPerSmoothingGroup]
+		</div>
+		<div>
+			Tells whether a material shall be created per smoothing group.
+		</div>
+
+
+		<h2>The following methods are inherited from [page:LoaderSupport.Commons]</h2>
+
+		<h3>[method:ConsoleLogger getLogger] ()</h3>
+		<div>
+			Returns [page:LoaderSupport.ConsoleLogger].
+		</div>
+
+
+		<h3>[method:null setModelName] ( [page:String modelName] )</h3>
+		<div>
+			[page:String modelName]
+		</div>
+		<div>
+			Set the name of the model.
 		</div>
 
+
 		<h3>[method:null setPath] ( [page:String path] )</h3>
 		<div>
-			[page:String path] — The basePath
+			[page:String path] - URL
+		</div>
+		<div>
+			The URL of the base path.
+		</div>
+
+
+		<h3>[method:null setStreamMeshesTo] ( [page:Object3D streamMeshesTo] )</h3>
+		<div>
+			[page:Object3D streamMeshesTo] - Object already attached to scenegraph where new meshes will be attached to
 		</div>
 		<div>
-			Base path to use.
+			Set the node where the loaded objects will be attached directly.
 		</div>
 
-		<h3>[method:null setSceneGraphBaseNode] ( [page:Object3D sceneGraphBaseNode] )</h3>
+
+		<h3>[method:null setMaterials] ( Array of [page:Material materials] )</h3>
+		<div>
+			Array of [page:Material materials] - Array of [page:Material Materials]
+		</div>
+		<div>
+			Set materials loaded by MTLLoader or any other supplier of an Array of [page:Material Materials].
+		</div>
+
+
+		<h3>[method:null setUseIndices]( [page:Boolean useIndices] )</h3>
 		<div>
-			[page:Object3D sceneGraphBaseNode] — Scenegraph object where meshes will be attached
+			[page:Boolean useIndices]
 		</div>
 		<div>
-			Set the node where the loaded objects will be attached.
+			Instructs loaders to create indexed [page:BufferGeometry].
 		</div>
 
-		<h3>[method:null setDebug]( [page:Boolean parserDebug], [page:Boolean meshCreatorDebug] )</h3>
+
+		<h3>[method:null setDisregardNormals]( [page:Boolean disregardNormals] )</h3>
 		<div>
-			[page:Boolean parserDebug] — Internal Parser will produce debug output<br>
-			[page:Boolean meshCreatorDebug] — Internal MeshCreator will produce debug output
+			[page:Boolean disregardNormals]
 		</div>
 		<div>
-			Allows to set debug mode for the parser and the meshCreator.
+			Tells whether normals should be completely disregarded and regenerated.
 		</div>
 
 		<h2>Source</h2>

+ 0 - 404
docs/examples/loaders/WWOBJLoader2.html

@@ -1,404 +0,0 @@
-<!DOCTYPE html>
-<html lang="en">
-	<head>
-		<meta charset="utf-8" />
-		<base href="../../" />
-		<script src="list.js"></script>
-		<script src="page.js"></script>
-		<link type="text/css" rel="stylesheet" href="page.css" />
-	</head>
-	<body>
-
-		<h1>[name]</h1>
-
-		<div class="desc">A loader for loading an <em>.obj</em> resource within a web worker.</div>
-
-		<h2>Sub-Classes</h2>
-		[page:WWOBJLoader2.PrepDataArrayBuffer]<br>
-		[page:WWOBJLoader2.PrepDataFile]<br>
-		[page:WWOBJLoader2.PrepDataCallbacks]<br>
-		[page:WWOBJLoader2.LoadedMeshUserOverride]<br>
-		[page:WWOBJLoader2.WWOBJLoader2Director]
-
-		<h2>Example</h2>
-
-		<code>
-			// instantiate the loader
-			var loader = new THREE.OBJLoader2.WWOBJLoader2();
-
-			// load an OBJ file by providing a name, the path and the file name
-			var prepData = new THREE.OBJLoader2.WWOBJLoader2.PrepDataFile(
-				'female02',
-				'obj/female02/',
-				'female02.obj'
-			);
-
-			// set where to add the loaded data in the scene graph.
-			prepData.setSceneGraphBaseNode( scene );
-
-			// provide the preparation data to the loader and let it run.
-			loader.prepareRun( prepData );
-			loader.run();
-		</code>
-
-		[example:webgl_loader_obj2_ww] — Simple example that allows to load own models via file selection.<br>
-		[example:webgl_loader_obj2_ww_parallels] — Advanced example using [page:WWOBJLoader2.WWOBJLoader2Director] for orchestration of multiple workers.
-
-
-		<h2>Constructor</h2>
-
-		<h3>[name]()</h3>
-		<div>
-			OBJ data will be loaded by dynamically created web worker.<br>
-			First feed instructions with: [page:WWOBJLoader2.prepareRun prepareRun]<br>
-			Then execute with: [page:WWOBJLoader2.run run]
-		</div>
-
-		<h2>Properties</h2>
-
-
-		<h2>Methods</h2>
-
-		<h3>[method:null prepareRun]( [page:Object params] )</h3>
-		<div>
-			[page:Object params] — Either [page:WWOBJLoader2.PrepDataArrayBuffer] or [page:WWOBJLoader2.PrepDataFile]
-		</div>
-		<div>
-			Set all parameters for required for execution of [page:WWOBJLoader2.run run].
-		</div>
-
-
-		<h3>[method:null run]()</h3>
-		<div>
-			Run the loader according the preparation instruction provided in [page:WWOBJLoader2.prepareRun prepareRun].
-		</div>
-
-
-		<h3>[method:null setCrossOrigin]( [page:String crossOrigin] )</h3>
-		<div>
-			[page:String crossOrigin] — CORS value
-		</div>
-		<div>
-			Sets the CORS string to be used.
-		</div>
-
-
-		<h3>[method:null setDebug]( [page:Boolean enabled] )</h3>
-		<div>
-			[page:Boolean enabled] — True or false
-		</div>
-		<div>
-			Enable or disable debug logging.
-		</div>
-
-
-		<h3>[method:null setRequestTerminate]( [page:Boolean requestTerminate] )</h3>
-		<div>
-			[page:Boolean requestTerminate] — True or false
-		</div>
-		<div>
-			Call requestTerminate to terminate the web worker and free local resource after execution.
-		</div>
-
-
-		<h3>[method:null registerCallbackCompletedLoading]( [page:Function callbackCompletedLoading] )</h3>
-		<div>
-			[page:Function callbackCompletedLoading] — 	Callback function for described functionality
-		</div>
-		<div>
-			Register callback function that is called once loading of the complete model is completed.
-		</div>
-
-
-		<h3>[method:null registerCallbackProgress]( [page:Function callbackProgress] )</h3>
-		<div>
-			[page:Function callbackProgress] — 	Callback function for described functionality
-		</div>
-		<div>
-			Register callback function that is invoked by internal function "_announceProgress" to print feedback.
-		</div>
-
-
-		<h3>[method:null registerCallbackMaterialsLoaded]( [page:Function callbackMaterialsLoaded] )</h3>
-		<div>
-			[page:Function callbackMaterialsLoaded] — 	Callback function for described functionality
-		</div>
-		<div>
-			Register callback function that is called once materials have been loaded. It allows to alter and return materials.
-		</div>
-
-
-		<h3>[method:null registerCallbackMeshLoaded]( [page:Function callbackMeshLoaded] )</h3>
-		<div>
-			[page:Function callbackMeshLoaded] — 	Callback function for described functionality
-		</div>
-		<div>
-			Register callback function that is called every time a mesh was loaded. Use [page:WWOBJLoader2.LoadedMeshUserOverride] for alteration instructions (geometry, material or disregard mesh).
-		</div>
-
-		<h3>[method:null registerCallbackErrorWhileLoading]( [page:Function callbackErrorWhileLoading] )</h3>
-		<div>
-			[page:Function callbackErrorWhileLoading] — 	Callback function for described functionality
-		</div>
-		<div>
-			Register callback function that is called to report an error that prevented loading.
-		</div>
-
-
-		<h3>[method:null clearAllCallbacks]()</h3>
-		<div>
-			Clears all registered callbacks.
-		</div>
-
-
-		<h2>Sub-Classes</h2>
-		<br>
-		<a name="PrepDataArrayBuffer"></a><h1>PrepDataArrayBuffer</h1>
-		<h2>Constructor</h2>
-
-		<h3>PrepDataArrayBuffer( [page:String modelName], [page:Uint8Array objAsArrayBuffer], [page:String pathTexture], [page:String mtlAsString] )</h3>
-		<div>
-			[page:String modelName] — Overall name of the model<br>
-			[page:Uint8Array objAsArrayBuffer] — OBJ file content as ArrayBuffer<br>
-			[page:String pathTexture] — Path to texture files<br>
-			[page:String mtlAsString] — MTL file content as string
-		</div>
-		<div>
-			Instruction to configure [page:WWOBJLoader2.prepareRun] to load OBJ from given ArrayBuffer and MTL from given String.
-		</div>
-
-		<h2>Methods</h2>
-
-		<h3>[method:PrepDataCallbacks getCallbacks]()</h3>
-		<div>
-			Returns all callbacks as [page:WWOBJLoader2.PrepDataCallbacks].
-		</div>
-
-
-		<h3>[method:null setRequestTerminate]( [page:Boolean requestTerminate] )</h3>
-		<div>
-			[page:Boolean requestTerminate] — Default is false
-		</div>
-		<div>
-			Request termination of web worker and free local resources after execution.
-		</div>
-
-
-		<h3>[method:null setSceneGraphBaseNode]( [page:THREE.Object3D sceneGraphBaseNode] )</h3>
-		<div>
-			[page:Object3D sceneGraphBaseNode] — Scene graph object
-		</div>
-		<div>
-			[page:Object3D] where meshes will be attached.
-		</div>
-
-
-		<h3>[method:null setStreamMeshes]( [page:Boolean streamMeshes] )</h3>
-		<div>
-			[page:Boolean streamMeshes] — Default is true
-		</div>
-		<div>
-			Singles meshes are directly integrated into scene when loaded or later.
-		</div>
-		<br>
-		<br>
-
-
-		<a name="PrepDataFile"></a><h1>PrepDataFile</h1>
-		<h2>Constructor</h2>
-
-		<h3>PrepDataFile( [page:String modelName], [page:String pathObj], [page:String fileObj], [page:String pathTexture], [page:String fileMtl] )</h3>
-		<div>
-			[page:String modelName] — Overall name of the model<br>
-			[page:String pathObj] — Path to OBJ file<br>
-			[page:String fileObj] — OBJ file name<br>
-			[page:String pathTexture] — Path to texture files<br>
-			[page:String fileMtl] — MTL file name
-		</div>
-		<div>
-			Instruction to configure [page:WWOBJLoader2.prepareRun] to load OBJ and MTL from files.
-		</div>
-
-		<h2>Methods</h2>
-
-		<h3>[method:PrepDataCallbacks getCallbacks]()</h3>
-		<div>
-			Returns all callbacks as [page:WWOBJLoader2.PrepDataCallbacks].
-		</div>
-
-
-		<h3>[method:null setRequestTerminate]( [page:Boolean requestTerminate] )</h3>
-		<div>
-			[page:Boolean requestTerminate] — Default is false
-		</div>
-		<div>
-			Request termination of web worker and free local resources after execution.
-		</div>
-
-
-		<h3>[method:null setSceneGraphBaseNode]( [page:THREE.Object3D sceneGraphBaseNode] )</h3>
-		<div>
-			[page:Object3D sceneGraphBaseNode] — Scene graph object
-		</div>
-		<div>
-			[page:Object3D] where meshes will be attached.
-		</div>
-
-
-		<h3>[method:null setStreamMeshes]( [page:Boolean streamMeshes] )</h3>
-		<div>
-			[page:Boolean streamMeshes] — Default is true
-		</div>
-		<div>
-			Singles meshes are directly integrated into scene when loaded or later.
-		</div>
-		<br>
-		<br>
-
-
-		<a name="PrepDataCallbacks"></a><h1>PrepDataCallbacks</h1>
-		<h2>Constructor</h2>
-
-		<h3>PrepDataCallbacks()</h3>
-		<div>
-			Callbacks utilized by functions working with [page:WWOBJLoader2.PrepDataArrayBuffer] or [page:WWOBJLoader2.PrepDataFile].
-		</div>
-
-		<h2>Methods</h2>
-
-		<h3>[method:null registerCallbackCompletedLoading]( [page:Function callbackCompletedLoading] )</h3>
-		<div>
-			[page:Function callbackCompletedLoading] — Callback function for described functionality
-		</div>
-		<div>
-			Register callback function that is called once loading of the complete model is completed.
-		</div>
-
-
-		<h3>[method:null registerCallbackProgress]( [page:Function callbackProgress] )</h3>
-		<div>
-			[page:Function callbackProgress] — Callback function for described functionality
-		</div>
-		<div>
-			Register callback function that is invoked by internal function "_announceProgress" to print feedback.
-		</div>
-
-
-		<h3>[method:null registerCallbackErrorWhileLoading]( [page:Function callbackErrorWhileLoading] )</h3>
-		<div>
-			[page:Function callbackErrorWhileLoading] — Callback function for described functionality
-		</div>
-		<div>
-			Report if an error prevented loading.
-		</div>
-
-
-		<h3>[method:null registerCallbackMaterialsLoaded]( [page:Function callbackMaterialsLoaded] )</h3>
-		<div>
-			[page:Function callbackMaterialsLoaded] — Callback function for described functionality
-		</div>
-		<div>
-			Register callback function that is called once materials have been loaded. It allows to alter and return materials.
-		</div>
-
-
-		<h3>[method:null registerCallbackMeshLoaded]( [page:Function callbackMeshLoaded] )</h3>
-		<div>
-			[page:Function callbackMeshLoaded] — Callback function for described functionality
-		</div>
-		<div>
-			Register callback function that is called every time a mesh was loaded. Use [page:WWOBJLoader2.LoadedMeshUserOverride] for alteration instructions (geometry, material or disregard mesh).
-		</div>
-		<br>
-		<br>
-
-
-		<a name="LoadedMeshUserOverride"></a><h1>LoadedMeshUserOverride</h1>
-		<h2>Constructor</h2>
-
-		<h3>LoadedMeshUserOverride( [page:Boolean disregardMesh], [page:THREE.BufferGeometry bufferGeometry], [page:THREE.Material material] )</h3>
-		<div>
-			[page:Boolean disregardMesh] — Tell [page:WWOBJLoader2] to completely disregard this mesh<br>
-			[page:BufferGeometry bufferGeometry] — The [page:BufferGeometry] to be used<br>
-			[page:Material material] — The [page:Material] to be used
-		</div>
-		<div>
-			Object to return by THREE.OBJLoader2.WWOBJLoader2.callbacks.meshLoaded. Used to adjust bufferGeometry or material or prevent complete loading of mesh.
-		</div>
-		<br>
-		<br>
-
-
-		<a name="WWOBJLoader2Director"></a><h1>WWOBJLoader2Director</h1>
-		<h2>Constructor</h2>
-
-		<h3>WWOBJLoader2Director()</h3>
-		<div>
-			Orchestrate loading of multiple OBJ files/data from an instruction queue with a configurable amount of workers (1-16).<br>
-			Workflow:<br>
-				prepareWorkers<br>
-				enqueueForRun<br>
-				processQueue<br>
-				deregister
-		</div>
-
-		<h3>[method:null prepareWorkers]( [page:WWOBJLoader2.PrepDataCallbacks globalCallbacks], [page:Number maxQueueSize], [page:Number maxWebWorkers] )</h3>
-		<div>
-			[page:WWOBJLoader2.PrepDataCallbacks globalCallbacks] — Register global callbacks used by all web workers<br>
-			[page:Number maxQueueSize] — Set the maximum size of the instruction queue (1-1024)<br>
-			[page:Number maxWebWorkers] — Set the maximum amount of workers (1-16)
-		</div>
-		<div>
-			Create or destroy workers according limits. Set the name and register callbacks for dynamically created web workers.
-		</div>
-
-
-		<h3>[method:null enqueueForRun]( [page:Object runParams] )</h3>
-		<div>
-			[page:Object runParams] — Either [page:WWOBJLoader2.PrepDataArrayBuffer] or [page:WWOBJLoader2.PrepDataFile]
-		</div>
-		<div>
-			Store run instructions in internal instructionQueue.
-		</div>
-
-
-		<h3>[method:null processQueue]()</h3>
-		<div>
-			Process the instructionQueue until it is depleted.
-		</div>
-
-
-		<h3>[method:null deregister]()</h3>
-		<div>
-			Terminate all workers
-		</div>
-
-
-		<h3>[method:null getMaxQueueSize]()</h3>
-		<div>
-			Returns the maximum length of the instruction queue.
-		</div>
-
-
-		<h3>[method:null getMaxWebWorkers]()</h3>
-		<div>
-			Returns the maximum number of workers.
-		</div>
-
-
-		<h3>[method:null setCrossOrigin]( [page:String crossOrigin] )</h3>
-		<div>
-			[page:String crossOrigin] — CORS value
-		</div>
-		<div>
-			Sets the CORS string to be used.
-		</div>
-
-
-
-		<h2>Source</h2>
-
-		[link:https://github.com/mrdoob/three.js/blob/master/examples/js/loaders/OBJLoader2.js examples/js/loaders/OBJLoader2.js]
-
-	</body>
-</html>

+ 1 - 1
docs/list.js

@@ -352,7 +352,7 @@ var list = {
 			"MTLLoader": "examples/loaders/MTLLoader",
 			"OBJLoader": "examples/loaders/OBJLoader",
 			"OBJLoader2": "examples/loaders/OBJLoader2",
-			"WWOBJLoader2": "examples/loaders/WWOBJLoader2",
+			"LoaderSupport": "examples/loaders/LoaderSupport",
 			"PCDLoader": "examples/loaders/PCDLoader",
 			"PDBLoader": "examples/loaders/PDBLoader",
 			"SVGLoader": "examples/loaders/SVGLoader",

+ 251 - 113
examples/js/loaders/LoaderSupport.js

@@ -35,7 +35,121 @@ THREE.LoaderSupport.Validator = {
 
 
 /**
- * Callbacks utilized by functions working with WWLoader implementations
+ * Logging wrapper for console
+ * @class
+ */
+THREE.LoaderSupport.ConsoleLogger = (function () {
+
+	function ConsoleLogger( enabled, debug ) {
+		this.enabled = enabled !== false;
+		this.debug = debug === true;
+	}
+
+	/**
+	 * Enable or disable debug logging
+	 * @memberOf THREE.LoaderSupport.ConsoleLogger
+	 *
+	 * @param {boolean} debug True or False
+	 */
+	ConsoleLogger.prototype.setDebug = function ( debug ) {
+		this.debug = debug === true;
+	};
+
+	/**
+	 * Returns if is enabled and debug
+	 * @memberOf THREE.LoaderSupport.ConsoleLogger
+	 *
+	 * @returns {boolean}
+	 */
+	ConsoleLogger.prototype.isDebug = function () {
+		return this.isEnabled() && this.debug;
+	};
+
+	/**
+	 * Enable or disable info, debug and time logging
+	 * @memberOf THREE.LoaderSupport.ConsoleLogger
+	 *
+	 * @param {boolean} enabled True or False
+	 */
+	ConsoleLogger.prototype.setEnabled = function ( enabled ) {
+		this.enabled = enabled === true;
+	};
+
+	/**
+	 * Returns if is enabled.
+	 * @memberOf THREE.LoaderSupport.ConsoleLogger
+	 *
+	 * @returns {boolean}
+	 */
+	ConsoleLogger.prototype.isEnabled = function () {
+		return this.enabled;
+	};
+
+	/**
+	 * Log a debug message if enabled and debug is set.
+	 * @memberOf THREE.LoaderSupport.ConsoleLogger
+	 *
+	 * @param {string} message Message to log
+	 */
+	ConsoleLogger.prototype.logDebug = function ( message ) {
+		if ( this.enabled && this.debug ) console.info( message );
+	};
+
+	/**
+	 * Log an info message if enabled.
+	 * @memberOf THREE.LoaderSupport.ConsoleLogger
+	 *
+	 * @param {string} message Message to log
+	 */
+	ConsoleLogger.prototype.logInfo = function ( message ) {
+		if ( this.enabled ) console.info( message );
+	};
+
+	/**
+	 * Log a warn message (always).
+	 * @memberOf THREE.LoaderSupport.ConsoleLogger
+	 *
+	 * @param {string} message Message to log
+	 */
+	ConsoleLogger.prototype.logWarn = function ( message ) {
+		console.warn( message );
+	};
+
+	/**
+	 * Log an error message (always).
+	 * @memberOf THREE.LoaderSupport.ConsoleLogger
+	 *
+	 * @param {string} message Message to log
+	 */
+	ConsoleLogger.prototype.logError = function ( message ) {
+		console.error( message );
+	};
+
+	/**
+	 * Start time measurement with provided id.
+	 * @memberOf THREE.LoaderSupport.ConsoleLogger
+	 *
+	 * @param {string} id Time identification
+	 */
+	ConsoleLogger.prototype.logTimeStart = function ( id ) {
+		if ( this.enabled ) console.time( id );
+	};
+
+	/**
+	 * Start time measurement with provided id.
+	 * @memberOf THREE.LoaderSupport.ConsoleLogger
+	 *
+	 * @param {string} id Time identification
+	 */
+	ConsoleLogger.prototype.logTimeEnd = function ( id ) {
+		if ( this.enabled ) console.timeEnd( id );
+	};
+
+	return ConsoleLogger;
+})();
+
+/**
+ * Callbacks utilized by loaders and builder.
  * @class
  */
 THREE.LoaderSupport.Callbacks = (function () {
@@ -84,7 +198,8 @@ THREE.LoaderSupport.Callbacks = (function () {
 
 
 /**
- * Global callback definition
+ * Builds one or many THREE.Mesh from one raw set of Arraybuffers, materialGroup descriptions and further parameters.
+ * Supports vertex, vertexColor, normal, uv and index buffers.
  * @class
  */
 THREE.LoaderSupport.Builder = (function () {
@@ -148,6 +263,7 @@ THREE.LoaderSupport.Builder = (function () {
 
 	/**
 	 * Builds one or multiple meshes from the data described in the payload (buffers, params, material info,
+	 * @memberOf THREE.LoaderSupport.Builder
 	 *
 	 * @param {Object} payload buffers, params, materials
 	 * @returns {THREE.Mesh[]} mesh Array of {@link THREE.Mesh}
@@ -258,7 +374,15 @@ THREE.LoaderSupport.Builder = (function () {
 		var useOrgMesh = true;
 		if ( Validator.isValid( callbackOnMeshAlter ) ) {
 
-			callbackOnMeshAlterResult = callbackOnMeshAlter( meshName, bufferGeometry, material );
+			callbackOnMeshAlterResult = callbackOnMeshAlter(
+				{
+					detail: {
+						meshName: meshName,
+						bufferGeometry: bufferGeometry,
+						material: material
+					}
+				}
+			);
 			if ( Validator.isValid( callbackOnMeshAlterResult ) ) {
 
 				if ( ! callbackOnMeshAlterResult.isDisregardMesh() && callbackOnMeshAlterResult.providesAlteredMeshes() ) {
@@ -294,14 +418,28 @@ THREE.LoaderSupport.Builder = (function () {
 
 			}
 			progressMessage = 'Adding mesh(es) (' + meshNames.length + ': ' + meshNames + ') from input mesh: ' + meshName;
+			progressMessage += ' (' + ( payload.progress.numericalValue * 100 ).toFixed( 2 ) + '%)';
 
 		} else {
 
 			progressMessage = 'Not adding mesh: ' + meshName;
+			progressMessage += ' (' + ( payload.progress.numericalValue * 100 ).toFixed( 2 ) + '%)';
 
 		}
 		var callbackOnProgress = this.callbacks.onProgress;
-		if ( Validator.isValid( callbackOnProgress ) ) callbackOnProgress( progressMessage );
+		if ( Validator.isValid( callbackOnProgress ) ) {
+
+			var event = new CustomEvent( 'BuilderEvent', {
+				detail: {
+					type: 'progress',
+					modelName: payload.params.meshName,
+					text: progressMessage,
+					numericalValue: payload.progress.numericalValue
+				}
+			} );
+			callbackOnProgress( event );
+
+		}
 
 		return meshes;
 	};
@@ -311,20 +449,21 @@ THREE.LoaderSupport.Builder = (function () {
 
 
 /**
- * Global callback definition
+ * Base class to be used by loaders.
  * @class
  */
 THREE.LoaderSupport.Commons = (function () {
 
 	var Validator = THREE.LoaderSupport.Validator;
+	var ConsoleLogger = THREE.LoaderSupport.ConsoleLogger;
 
-	function Commons( manager ) {
+	function Commons( logger, manager ) {
+		this.logger = Validator.verifyInput( logger, new ConsoleLogger() );
 		this.manager = Validator.verifyInput( manager, THREE.DefaultLoadingManager );
 
 		this.modelName = '';
 		this.instanceNo = 0;
 		this.path = '';
-		this.debug = false;
 		this.useIndices = false;
 		this.disregardNormals = false;
 
@@ -354,33 +493,40 @@ THREE.LoaderSupport.Commons = (function () {
 		this.builder._setCallbacks( callbackOnProgress, callbackOnMeshAlter, callbackOnLoad );
 	};
 
-	Commons.prototype.setModelName = function ( modelName ) {
-		this.modelName = Validator.verifyInput( modelName, this.modelName );
+	/**
+	 * Provides access to console logging wrapper.
+	 *
+	 * @returns {THREE.LoaderSupport.ConsoleLogger}
+	 */
+	Commons.prototype.getLogger = function () {
+		return this.logger;
 	};
 
 	/**
-	 * The URL of the base path
-	 * @param {string} path
+	 * Set the name of the model.
+	 * @memberOf THREE.LoaderSupport.Commons
+	 *
+	 * @param {string} modelName
 	 */
-	Commons.prototype.setPath = function ( path ) {
-		this.path = Validator.verifyInput( path, this.path );
+	Commons.prototype.setModelName = function ( modelName ) {
+		this.modelName = Validator.verifyInput( modelName, this.modelName );
 	};
 
 	/**
-	 * Allows to set debug mode.
+	 * The URL of the base path.
 	 * @memberOf THREE.LoaderSupport.Commons
 	 *
-	 * @param {boolean} enabled
+	 * @param {string} path URL
 	 */
-	Commons.prototype.setDebug = function ( enabled ) {
-		this.debug = enabled;
+	Commons.prototype.setPath = function ( path ) {
+		this.path = Validator.verifyInput( path, this.path );
 	};
 
 	/**
 	 * Set the node where the loaded objects will be attached directly.
 	 * @memberOf THREE.LoaderSupport.Commons
 	 *
-	 * @param {THREE.Object3D} streamMeshesTo Attached scenegraph object where meshes will be attached live
+	 * @param {THREE.Object3D} streamMeshesTo Object already attached to scenegraph where new meshes will be attached to
 	 */
 	Commons.prototype.setStreamMeshesTo = function ( streamMeshesTo ) {
 		this.loaderRootNode = Validator.verifyInput( streamMeshesTo, this.loaderRootNode );
@@ -397,39 +543,49 @@ THREE.LoaderSupport.Commons = (function () {
 	};
 
 	/**
-	 * Tells whether indices should be used
+	 * Instructs loaders to create indexed {@link THREE.BufferGeometry}.
 	 * @memberOf THREE.LoaderSupport.Commons
 	 *
-	 * @param {boolean} useIndices=false Default is false
+	 * @param {boolean} useIndices=false
 	 */
 	Commons.prototype.setUseIndices = function ( useIndices ) {
 		this.useIndices = useIndices === true;
 	};
 
 	/**
-	 * Tells whether normals should be completely disregarded
+	 * Tells whether normals should be completely disregarded and regenerated.
 	 * @memberOf THREE.LoaderSupport.Commons
 	 *
-	 * @param {boolean} disregardNormals=false Default is false
+	 * @param {boolean} disregardNormals=false
 	 */
 	Commons.prototype.setDisregardNormals = function ( disregardNormals ) {
 		this.disregardNormals = disregardNormals === true;
 	};
 
 	/**
-	 * Announce feedback which is give to the registered callbacks and logged if debug is enabled
+	 * Announce feedback which is give to the registered callbacks
 	 * @memberOf THREE.LoaderSupport.Commons
+	 * @private
 	 *
-	 * @param baseText
-	 * @param text
+	 * @param {string} type
+	 * @param {string} text
+	 * @param {number} numericalValue
 	 */
-	Commons.prototype.onProgress = function ( baseText, text ) {
-		var content = Validator.isValid( baseText ) ? baseText: '';
-		content = Validator.isValid( text ) ? content + ' ' + text : content;
+	Commons.prototype.onProgress = function ( type, text, numericalValue ) {
+		var content = Validator.isValid( text ) ? text: '';
+		var event = {
+			detail: {
+				type: type,
+				modelName: this.modelName,
+				instanceNo: this.instanceNo,
+				text: content,
+				numericalValue: numericalValue
+			}
+		};
 
-		if ( Validator.isValid( this.callbacks.onProgress ) ) this.callbacks.onProgress( content, this.modelName, this.instanceNo );
+		if ( Validator.isValid( this.callbacks.onProgress ) ) this.callbacks.onProgress( event );
 
-		if ( this.debug ) console.log( content );
+		this.logger.logDebug( content );
 	};
 
 	return Commons;
@@ -437,11 +593,11 @@ THREE.LoaderSupport.Commons = (function () {
 
 
 /**
- * Object to return by {@link THREE.LoaderSupport.Commons}.callbacks.meshLoaded.
- * Used to disregard a certain mesh or to return one to many created meshes.
+ * Object to return by callback onMeshAlter. Used to disregard a certain mesh or to return one to many meshes.
  * @class
  *
  * @param {boolean} disregardMesh=false Tell implementation to completely disregard this mesh
+ * @param {boolean} disregardMesh=false Tell implementation that mesh(es) have been altered or added
  */
 THREE.LoaderSupport.LoadedMeshUserOverride = (function () {
 
@@ -531,7 +687,7 @@ THREE.LoaderSupport.ResourceDescriptor = (function () {
 
 
 /**
- * Base class for configuration of prepareRun when using {@link THREE.LoaderSupport.WorkerSupport}.
+ * Configuration instructions to be used by run method.
  * @class
  */
 THREE.LoaderSupport.PrepData = (function () {
@@ -551,41 +707,40 @@ THREE.LoaderSupport.PrepData = (function () {
 	}
 
 	/**
-	 * {@link THREE.Object3D} where meshes will be attached.
+	 * Set the node where the loaded objects will be attached directly.
 	 * @memberOf THREE.LoaderSupport.PrepData
 	 *
-	 * @param {THREE.Object3D} streamMeshesTo Scene graph object
+	 * @param {THREE.Object3D} streamMeshesTo Object already attached to scenegraph where new meshes will be attached to
 	 */
 	PrepData.prototype.setStreamMeshesTo = function ( streamMeshesTo ) {
 		this.streamMeshesTo = Validator.verifyInput( streamMeshesTo, null );
 	};
 
 	/**
-	 * Tells whether a material shall be created per smoothing group
+	 * Tells whether a material shall be created per smoothing group.
 	 * @memberOf THREE.LoaderSupport.PrepData
 	 *
-	 * @param {boolean} materialPerSmoothingGroup
+	 * @param {boolean} materialPerSmoothingGroup=false
 	 */
 	PrepData.prototype.setMaterialPerSmoothingGroup = function ( materialPerSmoothingGroup ) {
-		this.materialPerSmoothingGroup = materialPerSmoothingGroup;
+		this.materialPerSmoothingGroup = materialPerSmoothingGroup === true;
 	};
 
 	/**
 	 * Tells whether indices should be used
 	 * @memberOf THREE.LoaderSupport.PrepData
 	 *
-	 * @param {boolean} useIndices=false Default is false
+	 * @param {boolean} useIndices=false
 	 */
 	PrepData.prototype.setUseIndices = function ( useIndices ) {
 		this.useIndices = useIndices === true;
 	};
 
-
 	/**
-	 * Tells whether normals should be completely disregarded
+	 * Tells whether normals should be completely disregarded and regenerated.
 	 * @memberOf THREE.LoaderSupport.PrepData
 	 *
-	 * @param {boolean} disregardNormals=false Default is false
+	 * @param {boolean} disregardNormals=false
 	 */
 	PrepData.prototype.setDisregardNormals = function ( disregardNormals ) {
 		this.disregardNormals = disregardNormals === true;
@@ -612,16 +767,18 @@ THREE.LoaderSupport.PrepData = (function () {
 	};
 
 	/**
-	 * Add a resource description
+	 * Add a resource description.
 	 * @memberOf THREE.LoaderSupport.PrepData
 	 *
-	 * @param {THREE.LoaderSupport.ResourceDescriptor} The resource description
+	 * @param {THREE.LoaderSupport.ResourceDescriptor}
 	 */
 	PrepData.prototype.addResource = function ( resource ) {
 		this.resources.push( resource );
 	};
 
 	/**
+	 * If true uses async loading with worker, if false loads data synchronously.
+	 * @memberOf THREE.LoaderSupport.PrepData
 	 *
 	 * @param {boolean} useAsync
 	 */
@@ -631,6 +788,7 @@ THREE.LoaderSupport.PrepData = (function () {
 
 	/**
 	 * Clones this object and returns it afterwards.
+	 * @memberOf THREE.LoaderSupport.PrepData
 	 *
 	 * @returns {@link THREE.LoaderSupport.PrepData}
 	 */
@@ -665,43 +823,43 @@ THREE.LoaderSupport.WorkerRunnerRefImpl = (function () {
 		for ( property in params ) {
 			funcName = 'set' + property.substring( 0, 1 ).toLocaleUpperCase() + property.substring( 1 );
 			values = params[ property ];
-			if ( parser.hasOwnProperty( property ) ) {
 
-				if ( typeof parser[ funcName ] === 'function' ) {
+			if ( typeof parser[ funcName ] === 'function' ) {
 
-					parser[ funcName ]( values );
+				parser[ funcName ]( values );
 
-				} else {
+			} else if ( parser.hasOwnProperty( property ) ) {
 
-					parser[ property ] = values;
+				parser[ property ] = values;
 
-				}
 			}
 		}
 	};
 
 	WorkerRunnerRefImpl.prototype.run = function ( payload ) {
+		var logger = new ConsoleLogger( payload.logger.enabled, payload.logger.debug );
+
 		if ( payload.cmd === 'run' ) {
 
-			console.log( 'WorkerRunner: Starting Run...' );
+			logger.logInfo( 'WorkerRunner: Starting Run...' );
 
 			var callbacks = {
 				callbackBuilder: function ( payload ) {
 					self.postMessage( payload );
 				},
-				callbackProgress: function ( message ) {
-					console.log( 'WorkerRunner: progress: ' + message );
+				callbackProgress: function ( text ) {
+					logger.logDebug( 'WorkerRunner: progress: ' + text );
 				}
 			};
 
 			// Parser is expected to be named as such
-			var parser = new Parser();
+			var parser = new Parser( logger );
 			this.applyProperties( parser, payload.params );
 			this.applyProperties( parser, payload.materials );
 			this.applyProperties( parser, callbacks );
 			parser.parse( payload.buffers.input );
 
-			console.log( 'WorkerRunner: Run complete!' );
+			logger.logInfo( 'WorkerRunner: Run complete!' );
 
 			callbacks.callbackBuilder( {
 				cmd: 'complete',
@@ -710,7 +868,7 @@ THREE.LoaderSupport.WorkerRunnerRefImpl = (function () {
 
 		} else {
 
-			console.error( 'WorkerRunner: Received unknown command: ' + payload.cmd );
+			logger.logError( 'WorkerRunner: Received unknown command: ' + payload.cmd );
 
 		}
 	};
@@ -720,12 +878,13 @@ THREE.LoaderSupport.WorkerRunnerRefImpl = (function () {
 
 THREE.LoaderSupport.WorkerSupport = (function () {
 
-	var WORKER_SUPPORT_VERSION = '1.0.0-dev';
+	var WORKER_SUPPORT_VERSION = '1.0.0';
 
 	var Validator = THREE.LoaderSupport.Validator;
 
-	function WorkerSupport() {
-		console.log( "Using THREE.LoaderSupport.WorkerSupport version: " + WORKER_SUPPORT_VERSION );
+	function WorkerSupport( logger ) {
+		this.logger = Validator.verifyInput( logger, new THREE.LoaderSupport.ConsoleLogger() );
+		this.logger.logInfo( 'Using THREE.LoaderSupport.WorkerSupport version: ' + WORKER_SUPPORT_VERSION );
 
 		// check worker support first
 		if ( window.Worker === undefined ) throw "This browser does not support web workers!";
@@ -756,18 +915,18 @@ THREE.LoaderSupport.WorkerSupport = (function () {
 
 		if ( ! Validator.isValid( this.worker ) ) {
 
-			console.log( 'WorkerSupport: Building worker code...' );
-			console.time( 'buildWebWorkerCode' );
+			this.logger.logInfo( 'WorkerSupport: Building worker code...' );
+			this.logger.logTimeStart( 'buildWebWorkerCode' );
 
 			var workerRunner;
 			if ( Validator.isValid( runnerImpl ) ) {
 
-				console.log( 'WorkerSupport: Using "' + runnerImpl.name + '" as Runncer class for worker.');
+				this.logger.logInfo( 'WorkerSupport: Using "' + runnerImpl.name + '" as Runncer class for worker.' );
 				workerRunner = runnerImpl;
 
 			} else {
 
-				console.log( 'WorkerSupport: Using DEFAULT "THREE.LoaderSupport.WorkerRunnerRefImpl" as Runncer class for worker.');
+				this.logger.logInfo( 'WorkerSupport: Using DEFAULT "THREE.LoaderSupport.WorkerRunnerRefImpl" as Runncer class for worker.' );
 				workerRunner = THREE.LoaderSupport.WorkerRunnerRefImpl;
 
 			}
@@ -777,7 +936,7 @@ THREE.LoaderSupport.WorkerSupport = (function () {
 
 			var blob = new Blob( [ this.workerCode ], { type: 'text/plain' } );
 			this.worker = new Worker( window.URL.createObjectURL( blob ) );
-			console.timeEnd( 'buildWebWorkerCode' );
+			this.logger.logTimeEnd( 'buildWebWorkerCode' );
 
 			var scope = this;
 			var receiveWorkerMessage = function ( e ) {
@@ -794,14 +953,14 @@ THREE.LoaderSupport.WorkerSupport = (function () {
 
 						if ( scope.terminateRequested ) {
 
-							console.log( 'WorkerSupport: Run is complete. Terminating application on request!' );
+							scope.logger.logInfo( 'WorkerSupport: Run is complete. Terminating application on request!' );
 							scope.terminateWorker();
 
 						}
 						break;
 
 					default:
-						console.error( 'WorkerSupport: Received unknown command: ' + payload.cmd );
+						scope.logger.logError( 'WorkerSupport: Received unknown command: ' + payload.cmd );
 						break;
 
 				}
@@ -906,18 +1065,22 @@ THREE.LoaderSupport.WorkerSupport = (function () {
  *   deregister
  *
  * @class
+ *
+ * @param {string} classDef Class definition to be used for construction
+ * @param {THREE.LoaderSupport.ConsoleLogger} logger logger to be used
  */
 THREE.LoaderSupport.WorkerDirector = (function () {
 
-	var LOADER_WORKER_DIRECTOR_VERSION = '1.0.0-dev';
+	var LOADER_WORKER_DIRECTOR_VERSION = '2.0.0';
 
 	var Validator = THREE.LoaderSupport.Validator;
 
 	var MAX_WEB_WORKER = 16;
 	var MAX_QUEUE_SIZE = 8192;
 
-	function WorkerDirector( classDef ) {
-		console.log( "Using THREE.LoaderSupport.WorkerDirector version: " + LOADER_WORKER_DIRECTOR_VERSION );
+	function WorkerDirector( classDef, logger ) {
+		this.logger = Validator.verifyInput( logger, new THREE.LoaderSupport.ConsoleLogger() );
+		this.logger.logInfo( 'Using THREE.LoaderSupport.WorkerDirector version: ' + LOADER_WORKER_DIRECTOR_VERSION );
 
 		this.maxQueueSize = MAX_QUEUE_SIZE ;
 		this.maxWebWorkers = MAX_WEB_WORKER;
@@ -986,7 +1149,7 @@ THREE.LoaderSupport.WorkerDirector = (function () {
 			for ( i = start; i < this.maxWebWorkers; i++ ) {
 
 				this.workerDescription.workerSupports[ i ] = {
-					workerSupport: new THREE.LoaderSupport.WorkerSupport(),
+					workerSupport: new THREE.LoaderSupport.WorkerSupport( this.logger ),
 					loader: null
 				};
 
@@ -1007,7 +1170,7 @@ THREE.LoaderSupport.WorkerDirector = (function () {
 	 * Store run instructions in internal instructionQueue.
 	 * @memberOf THREE.LoaderSupport.WorkerDirector
 	 *
-	 * @param {Object} prepData Either {@link THREE.LoaderSupport.PrepData}
+	 * @param {THREE.LoaderSupport.PrepData} prepData
 	 */
 	WorkerDirector.prototype.enqueueForRun = function ( prepData ) {
 		if ( this.instructionQueue.length < this.maxQueueSize ) {
@@ -1033,15 +1196,15 @@ THREE.LoaderSupport.WorkerDirector = (function () {
 
 	WorkerDirector.prototype._kickWorkerRun = function( prepData, workerInstanceNo ) {
 		var scope = this;
-		var directorOnLoad = function ( sceneGraphBaseNode, modelName, instanceNo ) {
+		var directorOnLoad = function ( event ) {
 			scope.objectsCompleted++;
 
 			var nextPrepData = scope.instructionQueue[ 0 ];
 			if ( Validator.isValid( nextPrepData ) ) {
 
 				scope.instructionQueue.shift();
-				console.log( '\nAssigning next item from queue to worker (queue length: ' + scope.instructionQueue.length + ')\n\n' );
-				scope._kickWorkerRun( nextPrepData, instanceNo );
+				scope.logger.logInfo( '\nAssigning next item from queue to worker (queue length: ' + scope.instructionQueue.length + ')\n\n' );
+				scope._kickWorkerRun( nextPrepData, event.detail.instanceNo );
 
 			} else if ( scope.instructionQueue.length === 0 ) {
 
@@ -1052,45 +1215,20 @@ THREE.LoaderSupport.WorkerDirector = (function () {
 
 		var prepDataCallbacks = prepData.getCallbacks();
 		var globalCallbacks = this.workerDescription.globalCallbacks;
-		var wrapperOnLoad = function ( sceneGraphBaseNode, modelName, instanceNo ) {
-			if ( Validator.isValid( globalCallbacks.onLoad ) ) {
-
-				globalCallbacks.onLoad( sceneGraphBaseNode, modelName, instanceNo );
-
-			}
-
-			if ( Validator.isValid( prepDataCallbacks.onLoad ) ) {
-
-				prepDataCallbacks.onLoad( sceneGraphBaseNode, modelName, instanceNo );
-
-			}
-			directorOnLoad( sceneGraphBaseNode, modelName, instanceNo );
+		var wrapperOnLoad = function ( event ) {
+			if ( Validator.isValid( globalCallbacks.onLoad ) ) globalCallbacks.onLoad( event );
+			if ( Validator.isValid( prepDataCallbacks.onLoad ) ) prepDataCallbacks.onLoad( event );
+			directorOnLoad( event );
 		};
 
-		var wrapperOnProgress = function ( content, modelName, instanceNo ) {
-			if ( Validator.isValid( globalCallbacks.onProgress ) ) {
-
-				globalCallbacks.onProgress( content, modelName, instanceNo );
-			}
-
-			if ( Validator.isValid( prepDataCallbacks.onProgress ) ) {
-
-				prepDataCallbacks.onProgress( content, modelName, instanceNo );
-
-			}
+		var wrapperOnProgress = function ( event ) {
+			if ( Validator.isValid( globalCallbacks.onProgress ) ) globalCallbacks.onProgress( event );
+			if ( Validator.isValid( prepDataCallbacks.onProgress ) ) prepDataCallbacks.onProgress( event );
 		};
 
-		var wrapperOnMeshAlter = function ( meshName, bufferGeometry, material ) {
-			if ( Validator.isValid( globalCallbacks.onMeshAlter ) ) {
-
-				globalCallbacks.onMeshAlter( meshName, bufferGeometry, material );
-			}
-
-			if ( Validator.isValid( prepDataCallbacks.onMeshAlter ) ) {
-
-				prepDataCallbacks.onMeshAlter( meshName, bufferGeometry, material );
-
-			}
+		var wrapperOnMeshAlter = function ( event ) {
+			if ( Validator.isValid( globalCallbacks.onMeshAlter ) ) globalCallbacks.onMeshAlter( event );
+			if ( Validator.isValid( prepDataCallbacks.onMeshAlter ) ) prepDataCallbacks.onMeshAlter( event );
 		};
 
 		var supportTuple = this.workerDescription.workerSupports[ workerInstanceNo ];
@@ -1108,7 +1246,7 @@ THREE.LoaderSupport.WorkerDirector = (function () {
 	WorkerDirector.prototype._buildLoader = function ( instanceNo ) {
 		var classDef = this.workerDescription.classDef;
 		var loader = Object.create( classDef.prototype );
-		this.workerDescription.classDef.call( loader );
+		this.workerDescription.classDef.call( loader, this.logger );
 
 		// verify that all required functions are implemented
 		if ( ! loader.hasOwnProperty( 'instanceNo' ) ) throw classDef.name + ' has no property "instanceNo".';
@@ -1133,16 +1271,16 @@ THREE.LoaderSupport.WorkerDirector = (function () {
 	 * @memberOf THREE.LoaderSupport.WorkerDirector
 	 */
 	WorkerDirector.prototype.deregister = function () {
-		console.log( 'WorkerDirector received the deregister call. Terminating all workers!' );
+		this.logger.logInfo( 'WorkerDirector received the deregister call. Terminating all workers!' );
 
 		for ( var i = 0, length = this.workerDescription.workerSupports.length; i < length; i++ ) {
 
 			var supportTuple = this.workerDescription.workerSupports[ i ];
 			supportTuple.workerSupport.setTerminateRequested( true );
-			console.log( 'Requested termination of worker.' );
+			this.logger.logInfo( 'Requested termination of worker.' );
 
 			var loaderCallbacks = supportTuple.loader.callbacks;
-			if ( Validator.isValid( loaderCallbacks.onProgress ) ) loaderCallbacks.onProgress( '' );
+			if ( Validator.isValid( loaderCallbacks.onProgress ) ) loaderCallbacks.onProgress( { detail: { text: '' } } );
 
 		}
 

+ 177 - 155
examples/js/loaders/OBJLoader2.js

@@ -15,16 +15,17 @@ if ( THREE.OBJLoader2 === undefined ) { THREE.OBJLoader2 = {} }
  */
 THREE.OBJLoader2 = (function () {
 
-	var OBJLOADER2_VERSION = '2.0.0-dev';
-	var Validator = THREE.LoaderSupport.Validator;
+	var OBJLOADER2_VERSION = '2.0.0';
 	var Commons = THREE.LoaderSupport.Commons;
+	var Validator = THREE.LoaderSupport.Validator;
+	var ConsoleLogger = THREE.LoaderSupport.ConsoleLogger;
 
 	OBJLoader2.prototype = Object.create( THREE.LoaderSupport.Commons.prototype );
 	OBJLoader2.prototype.constructor = OBJLoader2;
 
-	function OBJLoader2( manager ) {
-		THREE.LoaderSupport.Commons.call( this, manager );
-		console.log( "Using THREE.OBJLoader2 version: " + OBJLOADER2_VERSION );
+	function OBJLoader2( logger, manager ) {
+		THREE.LoaderSupport.Commons.call( this, logger, manager );
+		this.logger.logInfo( 'Using THREE.OBJLoader2 version: ' + OBJLOADER2_VERSION );
 
 		this.materialPerSmoothingGroup = false;
 		this.fileLoader = Validator.verifyInput( this.fileLoader, new THREE.FileLoader( this.manager ) );
@@ -34,51 +35,40 @@ THREE.OBJLoader2 = (function () {
 	};
 
 	/**
-	 * Tells whether a material shall be created per smoothing group
+	 * Tells whether a material shall be created per smoothing group.
 	 * @memberOf THREE.OBJLoader2
 	 *
-	 * @param {boolean} materialPerSmoothingGroup=false Default is false
+	 * @param {boolean} materialPerSmoothingGroup=false
 	 */
 	OBJLoader2.prototype.setMaterialPerSmoothingGroup = function ( materialPerSmoothingGroup ) {
 		this.materialPerSmoothingGroup = materialPerSmoothingGroup === true;
 	};
 
 	/**
-	 * Sets debug mode for the parser
-	 * @memberOf THREE.OBJLoader2
-	 *
-	 * @param {boolean} enabled
-	 */
-	OBJLoader2.prototype.setDebug = function ( enabled ) {
-		THREE.LoaderSupport.Commons.prototype.setDebug.call( this, enabled );
-	};
-
-	/**
-	 * Use this convenient method to load an OBJ file at the given URL. Per default the fileLoader uses an arraybuffer
+	 * 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. The argument will be the XMLHttpRequest instance, which contains {integer total} and {integer loaded} bytes.
 	 * @param {callback} onError Called after an error occurred during loading
-	 * @param {callback} onMeshAlter Called after a new mesh raw data becomes available
-	 * @param {boolean} useAsync Set this to use async loading
+	 * @param {callback} onMeshAlter Called after a new mesh raw data becomes available to allow alteration
+	 * @param {boolean} useAsync If true uses async loading with worker, if false loads data synchronously
 	 */
 	OBJLoader2.prototype.load = function ( url, onLoad, onProgress, onError, onMeshAlter, useAsync ) {
 		var scope = this;
 		if ( ! Validator.isValid( onProgress ) ) {
-			var refPercentComplete = 0;
-			var percentComplete = 0;
+			var numericalValueRef = 0;
+			var numericalValue = 0;
 			onProgress = function ( event ) {
 				if ( ! event.lengthComputable ) return;
 
-				percentComplete = Math.round( event.loaded / event.total * 100 );
-				if ( percentComplete > refPercentComplete ) {
+				numericalValue = event.loaded / event.total;
+				if ( numericalValue > numericalValueRef ) {
 
-					refPercentComplete = percentComplete;
-					var output = 'Download of "' + url + '": ' + percentComplete + '%';
-					console.log( output );
-					scope.onProgress( output );
+					numericalValueRef = numericalValue;
+					var output = 'Download of "' + url + '": ' + ( numericalValue * 100 ).toFixed( 2 ) + '%';
+					scope.onProgress( 'progressLoad', output, numericalValue );
 
 				}
 			};
@@ -87,8 +77,8 @@ THREE.OBJLoader2 = (function () {
 		if ( ! Validator.isValid( onError ) ) {
 			onError = function ( event ) {
 				var output = 'Error occurred while downloading "' + url + '"';
-				console.error( output + ': ' + event );
-				scope.onProgress( output );
+				scope.logger.logError( output + ': ' + event );
+				scope.onProgress( 'error', output, -1 );
 			};
 		}
 
@@ -102,7 +92,15 @@ THREE.OBJLoader2 = (function () {
 			} else {
 
 				scope._setCallbacks( null, onMeshAlter, null );
-				onLoad( scope.parse( content ), scope.modelName, scope.instanceNo );
+				onLoad(
+					{
+						detail: {
+							loaderRootNode: scope.parse( content ),
+							modelName: scope.modelName,
+							instanceNo: scope.instanceNo
+						}
+					}
+				);
 
 			}
 
@@ -124,6 +122,7 @@ THREE.OBJLoader2 = (function () {
 
 			this.terminateWorkerOnLoad = false;
 			this.workerSupport = workerSupportExternal;
+			this.logger = workerSupportExternal.logger;
 
 		} else {
 
@@ -167,20 +166,19 @@ THREE.OBJLoader2 = (function () {
 	};
 
 	/**
-	 * Parses OBJ content synchronously.
+	 * Parses OBJ data synchronously from arraybuffer or string.
 	 * @memberOf THREE.OBJLoader2
 	 *
-	 * @param content
+	 * @param {arraybuffer|string} content OBJ data as Uint8Array or String
 	 */
 	OBJLoader2.prototype.parse = function ( content ) {
-		console.time( 'OBJLoader2 parse: ' + this.modelName );
+		this.logger.logTimeStart( 'OBJLoader2 parse: ' + this.modelName );
 
-		var parser = new Parser();
+		var parser = new Parser( this.logger );
 		parser.setMaterialPerSmoothingGroup( this.materialPerSmoothingGroup );
 		parser.setUseIndices( this.useIndices );
 		parser.setDisregardNormals( this.disregardNormals );
 		parser.setMaterialNames( this.builder.materialNames );
-		parser.setDebug( this.debug );
 
 		var scope = this;
 		var onMeshLoaded = function ( payload ) {
@@ -192,19 +190,19 @@ THREE.OBJLoader2 = (function () {
 			}
 		};
 		parser.setCallbackBuilder( onMeshLoaded );
-		var onProgressScoped = function ( message ) {
-			scope.onProgress( message );
+		var onProgressScoped = function ( text, numericalValue ) {
+			scope.onProgress( 'progressParse', text, numericalValue );
 		};
 		parser.setCallbackProgress( onProgressScoped );
 
 		if ( content instanceof ArrayBuffer || content instanceof Uint8Array ) {
 
-			console.log( 'Parsing arrayBuffer...' );
+			this.logger.logInfo( 'Parsing arrayBuffer...' );
 			parser.parse( content );
 
 		} else if ( typeof( content ) === 'string' || content instanceof String ) {
 
-			console.log( 'Parsing text...' );
+			this.logger.logInfo( 'Parsing text...' );
 			parser.parseText( content );
 
 		} else {
@@ -212,26 +210,34 @@ THREE.OBJLoader2 = (function () {
 			throw 'Provided content was neither of type String nor Uint8Array! Aborting...';
 
 		}
-		console.timeEnd( 'OBJLoader2 parse: ' + this.modelName );
+		this.logger.logTimeEnd( 'OBJLoader2 parse: ' + this.modelName );
 
 		return this.loaderRootNode;
 	};
 
 	/**
-	 * Parses OBJ content asynchronously.
+	 * Parses OBJ content asynchronously from arraybuffer.
 	 * @memberOf THREE.OBJLoader2
 	 *
-	 * @param {arraybuffer} content
-	 * @param {callback} onLoad
+	 * @param {arraybuffer} content OBJ data as Uint8Array
+	 * @param {callback} onLoad Called after worker successfully completed loading
 	 */
 	OBJLoader2.prototype.parseAsync = function ( content, onLoad ) {
-		console.time( 'OBJLoader2 parseAsync: ' + this.modelName);
+		this.logger.logTimeStart( 'OBJLoader2 parseAsync: ' + this.modelName );
 
 		var scope = this;
-		var scopedOnLoad = function ( message ) {
-			onLoad( scope.loaderRootNode, scope.modelName, scope.instanceNo, message );
+		var scopedOnLoad = function () {
+			onLoad(
+				{
+					detail: {
+						loaderRootNode: scope.loaderRootNode,
+						modelName: scope.modelName,
+						instanceNo: scope.instanceNo
+					}
+				}
+			);
 			if ( scope.terminateWorkerOnLoad ) scope.workerSupport.terminateWorker();
-			console.timeEnd( 'OBJLoader2 parseAsync: ' + scope.modelName );
+			scope.logger.logTimeEnd( 'OBJLoader2 parseAsync: ' + scope.modelName );
 		};
 		var scopedOnMeshLoaded = function ( payload ) {
 			var meshes = scope.builder.buildMeshes( payload );
@@ -242,7 +248,7 @@ THREE.OBJLoader2 = (function () {
 			}
 		};
 
-		this.workerSupport = Validator.verifyInput( this.workerSupport, new THREE.LoaderSupport.WorkerSupport() );
+		this.workerSupport = Validator.verifyInput( this.workerSupport, new THREE.LoaderSupport.WorkerSupport( this.logger ) );
 		var buildCode = function ( funcBuildObject, funcBuildSingelton ) {
 			var workerCode = '';
 			workerCode += '/**\n';
@@ -251,6 +257,7 @@ THREE.OBJLoader2 = (function () {
 			workerCode += funcBuildSingelton( 'Commons', 'Commons', Commons );
 			workerCode += funcBuildObject( 'Consts', Consts );
 			workerCode += funcBuildObject( 'Validator', Validator );
+			workerCode += funcBuildSingelton( 'ConsoleLogger', 'ConsoleLogger', ConsoleLogger );
 			workerCode += funcBuildSingelton( 'Parser', 'Parser', Parser );
 			workerCode += funcBuildSingelton( 'RawMesh', 'RawMesh', RawMesh );
 			workerCode += funcBuildSingelton( 'RawMeshSubGroup', 'RawMeshSubGroup', RawMeshSubGroup );
@@ -263,11 +270,14 @@ THREE.OBJLoader2 = (function () {
 			{
 				cmd: 'run',
 				params: {
-					debug: this.debug,
 					materialPerSmoothingGroup: this.materialPerSmoothingGroup,
 					useIndices: this.useIndices,
 					disregardNormals: this.disregardNormals
 				},
+				logger: {
+					debug: this.logger.debug,
+					enabled: this.logger.enabled
+				},
 				materials: {
 					materialNames: this.builder.materialNames
 				},
@@ -309,12 +319,11 @@ THREE.OBJLoader2 = (function () {
 	 */
 	var Parser = (function () {
 
-		function Parser() {
+		function Parser( logger ) {
 			this.callbackProgress = null;
 			this.callbackBuilder = null;
 
 			this.materialNames = [];
-			this.debug = false;
 			this.rawMesh = null;
 			this.materialPerSmoothingGroup = false;
 			this.useIndices = false;
@@ -327,23 +336,8 @@ THREE.OBJLoader2 = (function () {
 				faces: 0,
 				doubleIndicesCount: 0
 			};
-		};
-
-		Parser.prototype.setDebug = function ( debug ) {
-			if ( debug === true || debug === false ) this.debug = debug;
-		};
-
-		Parser.prototype.configure = function () {
-			this.rawMesh = new RawMesh( this.materialPerSmoothingGroup, this.useIndices, this.disregardNormals );
-
-			var matNames = ( this.materialNames.length > 0 ) ? '\n\tmaterialNames:\n\t\t- ' + this.materialNames.join( '\n\t\t- ' ) : '\n\tmaterialNames: None';
-			var printConfig = 'OBJLoader2.Parser configuration:'
-				+ '\n\tdebug: ' + this.debug
-				+ matNames
-				+ '\n\tmaterialPerSmoothingGroup: ' + this.materialPerSmoothingGroup
-				+ '\n\tuseIndices: ' + this.useIndices
-				+ '\n\tdisregardNormals: ' +this.disregardNormals;
-			console.log( printConfig );
+			this.logger = logger;
+			this.totalBytes = 0;
 		};
 
 		Parser.prototype.setMaterialPerSmoothingGroup = function ( materialPerSmoothingGroup ) {
@@ -372,6 +366,23 @@ THREE.OBJLoader2 = (function () {
 			this.callbackProgress = callbackProgress;
 		};
 
+		Parser.prototype.configure = function () {
+			this.rawMesh = new RawMesh( this.materialPerSmoothingGroup, this.useIndices, this.disregardNormals );
+
+			if ( this.logger.isEnabled() ) {
+
+				var matNames = ( this.materialNames.length > 0 ) ? '\n\tmaterialNames:\n\t\t- ' + this.materialNames.join( '\n\t\t- ' ) : '\n\tmaterialNames: None';
+				var printedConfig = 'OBJLoader2.Parser configuration:'
+						+ matNames
+						+ '\n\tmaterialPerSmoothingGroup: ' + this.materialPerSmoothingGroup
+						+ '\n\tuseIndices: ' + this.useIndices
+						+ '\n\tdisregardNormals: ' + this.disregardNormals
+						+ '\n\tcallbackBuilderName: ' + this.callbackBuilder.name
+						+ '\n\tcallbackProgressName: ' + this.callbackProgress.name;
+				this.logger.logInfo( printedConfig );
+			}
+		};
+
 		/**
 		 * Parse the provided arraybuffer
 		 * @memberOf Parser
@@ -379,36 +390,38 @@ THREE.OBJLoader2 = (function () {
 		 * @param {Uint8Array} arrayBuffer OBJ data as Uint8Array
 		 */
 		Parser.prototype.parse = function ( arrayBuffer ) {
-			console.time( 'OBJLoader2.Parser.parse' );
+			this.logger.logTimeStart( 'OBJLoader2.Parser.parse' );
 			this.configure();
 
 			var arrayBufferView = new Uint8Array( arrayBuffer );
 			var length = arrayBufferView.byteLength;
+			this.totalBytes = length;
 			var buffer = new Array( 128 );
 			var bufferPointer = 0;
 			var slashesCount = 0;
 			var reachedFaces = false;
 			var code;
 			var word = '';
-			for ( var i = 0; i < length; i++ ) {
+			var i = 0;
+			for ( ; i < length; i ++ ) {
 
 				code = arrayBufferView[ i ];
 				switch ( code ) {
 					case Consts.CODE_SPACE:
-						if ( word.length > 0 ) buffer[ bufferPointer++ ] = word;
+						if ( word.length > 0 ) buffer[ bufferPointer ++ ] = word;
 						word = '';
 						break;
 
 					case Consts.CODE_SLASH:
-						slashesCount++;
-						if ( word.length > 0 ) buffer[ bufferPointer++ ] = word;
+						slashesCount ++;
+						if ( word.length > 0 ) buffer[ bufferPointer ++ ] = word;
 						word = '';
 						break;
 
 					case Consts.CODE_LF:
-						if ( word.length > 0 ) buffer[ bufferPointer++ ] = word;
+						if ( word.length > 0 ) buffer[ bufferPointer ++ ] = word;
 						word = '';
-						reachedFaces = this.processLine( buffer, bufferPointer, slashesCount, reachedFaces );
+						reachedFaces = this.processLine( buffer, bufferPointer, slashesCount, reachedFaces, i );
 						bufferPointer = 0;
 						slashesCount = 0;
 						break;
@@ -421,8 +434,8 @@ THREE.OBJLoader2 = (function () {
 						break;
 				}
 			}
-			this.finalize();
-			console.timeEnd( 'OBJLoader2.Parser.parse' );
+			this.finalize( i );
+			this.logger.logTimeEnd( 'OBJLoader2.Parser.parse' );
 		};
 
 		/**
@@ -432,35 +445,37 @@ THREE.OBJLoader2 = (function () {
 		 * @param {string} text OBJ data as string
 		 */
 		Parser.prototype.parseText = function ( text ) {
-			console.time( 'OBJLoader2.Parser.parseText' );
+			this.logger.logTimeStart( 'OBJLoader2.Parser.parseText' );
 			this.configure();
 
 			var length = text.length;
+			this.totalBytes = length;
 			var buffer = new Array( 128 );
 			var bufferPointer = 0;
 			var slashesCount = 0;
 			var reachedFaces = false;
 			var char;
 			var word = '';
-			for ( var i = 0; i < length; i++ ) {
+			var i = 0;
+			for ( ; i < length; i ++ ) {
 
 				char = text[ i ];
 				switch ( char ) {
 					case Consts.STRING_SPACE:
-						if ( word.length > 0 ) buffer[ bufferPointer++ ] = word;
+						if ( word.length > 0 ) buffer[ bufferPointer ++ ] = word;
 						word = '';
 						break;
 
 					case Consts.STRING_SLASH:
-						slashesCount++;
-						if ( word.length > 0 ) buffer[ bufferPointer++ ] = word;
+						slashesCount ++;
+						if ( word.length > 0 ) buffer[ bufferPointer ++ ] = word;
 						word = '';
 						break;
 
 					case Consts.STRING_LF:
-						if ( word.length > 0 ) buffer[ bufferPointer++ ] = word;
+						if ( word.length > 0 ) buffer[ bufferPointer ++ ] = word;
 						word = '';
-						reachedFaces = this.processLine( buffer, bufferPointer, slashesCount, reachedFaces );
+						reachedFaces = this.processLine( buffer, bufferPointer, slashesCount, reachedFaces, i );
 						bufferPointer = 0;
 						slashesCount = 0;
 						break;
@@ -472,11 +487,11 @@ THREE.OBJLoader2 = (function () {
 						word += char;
 				}
 			}
-			this.finalize();
-			console.timeEnd( 'OBJLoader2.Parser.parseText' );
+			this.finalize( i );
+			this.logger.logTimeEnd( 'OBJLoader2.Parser.parseText' );
 		};
 
-		Parser.prototype.processLine = function ( buffer, bufferPointer, slashesCount, reachedFaces ) {
+		Parser.prototype.processLine = function ( buffer, bufferPointer, slashesCount, reachedFaces, currentByte ) {
 			if ( bufferPointer < 1 ) return reachedFaces;
 
 			var bufferLength = bufferPointer - 1;
@@ -492,7 +507,7 @@ THREE.OBJLoader2 = (function () {
 							throw 'Vertex Colors were detected, but vertex count and color count do not match!';
 
 						}
-						this.processCompletedObject( null, this.rawMesh.groupName );
+						this.processCompletedObject( null, this.rawMesh.groupName, currentByte );
 						reachedFaces = false;
 
 					}
@@ -539,7 +554,7 @@ THREE.OBJLoader2 = (function () {
 
 				case Consts.LINE_G:
 					concatBuffer = bufferLength > 1 ? buffer.slice( 1, bufferPointer ).join( ' ' ) : buffer[ 1 ];
-					this.processCompletedGroup( concatBuffer );
+					this.processCompletedGroup( concatBuffer, currentByte );
 					this.flushStringBuffer( buffer, bufferPointer );
 					break;
 
@@ -547,7 +562,7 @@ THREE.OBJLoader2 = (function () {
 					concatBuffer = bufferLength > 1 ? buffer.slice( 1, bufferPointer ).join( ' ' ) : buffer[ 1 ];
 					if ( this.rawMesh.vertices.length > 0 ) {
 
-						this.processCompletedObject( concatBuffer, null );
+						this.processCompletedObject( concatBuffer, null, currentByte );
 						reachedFaces = false;
 
 					} else {
@@ -577,32 +592,48 @@ THREE.OBJLoader2 = (function () {
 		};
 
 		Parser.prototype.flushStringBuffer = function ( buffer, bufferLength ) {
-			for ( var i = 0; i < bufferLength; i++ ) {
+			for ( var i = 0; i < bufferLength; i ++ ) {
 				buffer[ i ] = '';
 			}
 		};
 
-		Parser.prototype.processCompletedObject = function ( objectName, groupName ) {
-			var result = this.rawMesh.finalize( this.debug );
+		Parser.prototype.createRawMeshReport = function ( rawMesh , inputObjectCount ) {
+			var report = rawMesh.createReport( inputObjectCount );
+			return 'Input Object number: ' + inputObjectCount +
+				'\n\tObject name: ' + report.objectName +
+				'\n\tGroup name: ' + report.groupName +
+				'\n\tMtllib name: ' + report.mtllibName +
+				'\n\tVertex count: ' + report.vertexCount +
+				'\n\tNormal count: ' + report.normalCount +
+				'\n\tUV count: ' + report.uvCount +
+				'\n\tSmoothingGroup count: ' + report.smoothingGroupCount +
+				'\n\tMaterial count: ' + report.mtlCount +
+				'\n\tReal RawMeshSubGroup count: ' + report.subGroups;
+		};
+
+		Parser.prototype.processCompletedObject = function ( objectName, groupName, currentByte ) {
+			var result = this.rawMesh.finalize();
 			if ( Validator.isValid( result ) ) {
 
 				this.inputObjectCount++;
-				if ( this.debug ) this.rawMesh.createReport( this.inputObjectCount, true );
-				var message = this.buildMesh( result, this.inputObjectCount );
-				this.onProgress( message );
+				if ( this.logger.isDebug() ) this.logger.logDebug( this.createRawMeshReport( this.rawMesh, this.inputObjectCount ) );
+				this.buildMesh( result, currentByte );
+				var progressBytesPercent = currentByte / this.totalBytes;
+				this.callbackProgress( 'Completed object: ' + objectName + ' Total progress: ' + ( progressBytesPercent * 100 ).toFixed( 2 ) + '%', progressBytesPercent );
 
 			}
 			this.rawMesh = this.rawMesh.newInstanceFromObject( objectName, groupName );
 		};
 
-		Parser.prototype.processCompletedGroup = function ( groupName ) {
+		Parser.prototype.processCompletedGroup = function ( groupName, currentByte ) {
 			var result = this.rawMesh.finalize();
 			if ( Validator.isValid( result ) ) {
 
 				this.inputObjectCount++;
-				if ( this.debug ) this.rawMesh.createReport( this.inputObjectCount, true );
-				var message = this.buildMesh( result, this.inputObjectCount );
-				this.onProgress( message );
+				if ( this.logger.isDebug() ) this.logger.logDebug( this.createRawMeshReport( this.rawMesh, this.inputObjectCount ) );
+				this.buildMesh( result, currentByte );
+				var progressBytesPercent = currentByte / this.totalBytes;
+				this.callbackProgress( 'Completed group: ' + groupName + ' Total progress: ' + ( progressBytesPercent * 100 ).toFixed( 2 ) + '%', progressBytesPercent );
 				this.rawMesh = this.rawMesh.newInstanceFromGroup( groupName );
 
 			} else {
@@ -613,28 +644,28 @@ THREE.OBJLoader2 = (function () {
 			}
 		};
 
-		Parser.prototype.finalize = function () {
-			console.log( 'Global output object count: ' + this.outputObjectCount );
+		Parser.prototype.finalize = function ( currentByte ) {
+			this.logger.logInfo( 'Global output object count: ' + this.outputObjectCount );
 			var result = Validator.isValid( this.rawMesh ) ? this.rawMesh.finalize() : null;
 			if ( Validator.isValid( result ) ) {
 
 				this.inputObjectCount++;
-				if ( this.debug ) this.rawMesh.createReport( this.inputObjectCount, true );
-				var message = this.buildMesh( result, this.inputObjectCount );
-
-				console.log(
-					'Overall counts: '  +
-					'\n\tVertices: ' + this.counts.vertices,
-					'\n\tFaces: ' + this.counts.faces,
-					'\n\tMultiple definitions: ' + this.counts.doubleIndicesCount
-				);
-				this.onProgress( message );
+				if ( this.logger.isDebug() ) this.logger.logDebug( this.createRawMeshReport( this.rawMesh, this.inputObjectCount ) );
+				this.buildMesh( result, currentByte );
 
-			}
-		};
+				if ( this.logger.isEnabled() ) {
+
+					var parserFinalReport = 'Overall counts: ' +
+						'\n\tVertices: ' + this.counts.vertices +
+						'\n\tFaces: ' + this.counts.faces +
+						'\n\tMultiple definitions: ' + this.counts.doubleIndicesCount;
+					this.logger.logInfo( parserFinalReport );
+
+				}
+				var progressBytesPercent = currentByte / this.totalBytes;
+				this.callbackProgress( 'Completed Parsing: 100.00%', progressBytesPercent );
 
-		Parser.prototype.onProgress = function ( text ) {
-			if ( Validator.isValid( text ) && Validator.isValid( this.callbackProgress) ) this.callbackProgress( text );
+			}
 		};
 
 		/**
@@ -643,7 +674,7 @@ THREE.OBJLoader2 = (function () {
 		 *
 		 * @param result
 		 */
-		Parser.prototype.buildMesh = function ( result ) {
+		Parser.prototype.buildMesh = function ( result, currentByte ) {
 			var rawObjectDescriptions = result.subGroups;
 
 			var vertexFA = new Float32Array( result.absoluteVertexCount );
@@ -686,7 +717,9 @@ THREE.OBJLoader2 = (function () {
 				if ( this.materialNames[ materialDescription.name ] === null ) {
 
 					materialDescription.default = true;
-					console.warn( 'object_group "' + rawObjectDescription.objectName + '_' + rawObjectDescription.groupName + '" was defined without material! Assigning "defaultMaterial".' );
+					this.logger.logWarn( '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
@@ -749,7 +782,23 @@ THREE.OBJLoader2 = (function () {
 					uvFAOffset += rawObjectDescription.uvs.length;
 
 				}
-				if ( this.debug ) this.printReport( rawObjectDescription, selectedMaterialIndex );
+
+				if ( this.logger.isDebug() ) {
+					var materialIndexLine = Validator.isValid( selectedMaterialIndex ) ? '\n\t\tmaterialIndex: ' + selectedMaterialIndex : '';
+					var createdReport = 'Output Object no.: ' + this.outputObjectCount +
+						'\n\t\tobjectName: ' + rawObjectDescription.objectName +
+						'\n\t\tgroupName: ' + rawObjectDescription.groupName +
+						'\n\t\tmaterialName: ' + rawObjectDescription.materialName +
+						materialIndexLine +
+						'\n\t\tsmoothingGroup: ' + rawObjectDescription.smoothingGroup +
+						'\n\t\t#vertices: ' + rawObjectDescription.vertices.length / 3 +
+						'\n\t\t#indices: ' + rawObjectDescription.indices.length +
+						'\n\t\t#colors: ' + rawObjectDescription.colors.length / 3 +
+						'\n\t\t#uvs: ' + rawObjectDescription.uvs.length / 2 +
+						'\n\t\t#normals: ' + rawObjectDescription.normals.length / 3;
+					this.logger.logDebug( createdReport );
+				}
+
 
 			}
 
@@ -757,6 +806,9 @@ THREE.OBJLoader2 = (function () {
 			this.callbackBuilder(
 				{
 					cmd: 'meshData',
+					progress: {
+						numericalValue: currentByte / this.totalBytes
+					},
 					params: {
 						meshName: result.name
 					},
@@ -781,23 +833,6 @@ THREE.OBJLoader2 = (function () {
 			);
 		};
 
-		Parser.prototype.printReport = function ( rawObjectDescription, selectedMaterialIndex ) {
-			var materialIndexLine = Validator.isValid( selectedMaterialIndex ) ? '\n\tmaterialIndex: ' + selectedMaterialIndex : '';
-			console.log(
-				'\tOutput Object no.: ' + this.outputObjectCount +
-				'\n\tobjectName: ' + rawObjectDescription.objectName +
-				'\n\tgroupName: ' + rawObjectDescription.groupName +
-				'\n\tmaterialName: ' + rawObjectDescription.materialName +
-				materialIndexLine +
-				'\n\tsmoothingGroup: ' + rawObjectDescription.smoothingGroup +
-				'\n\t#vertices: ' + rawObjectDescription.vertices.length / 3 +
-				'\n\t#indices: ' + rawObjectDescription.indices.length +
-				'\n\t#colors: ' + rawObjectDescription.colors.length / 3 +
-				'\n\t#uvs: ' + rawObjectDescription.uvs.length / 2 +
-				'\n\t#normals: ' + rawObjectDescription.normals.length / 3
-			);
-		};
-
 		return Parser;
 	})();
 
@@ -1140,7 +1175,7 @@ THREE.OBJLoader2 = (function () {
 			return result;
 		};
 
-		RawMesh.prototype.createReport = function ( inputObjectCount, printDirectly ) {
+		RawMesh.prototype.createReport = function () {
 			var report = {
 				objectName: this.objectName,
 				groupName: this.groupName,
@@ -1153,20 +1188,6 @@ THREE.OBJLoader2 = (function () {
 				subGroups: this.subGroups.length
 			};
 
-			if ( printDirectly ) {
-				console.log( 'Input Object number: ' + inputObjectCount +
-					'\n\tObject name: ' + report.objectName +
-					'\n\tGroup name: ' + report.groupName +
-					'\n\tMtllib name: ' + report.mtllibName +
-					'\n\tVertex count: ' + report.vertexCount +
-					'\n\tNormal count: ' + report.normalCount +
-					'\n\tUV count: ' + report.uvCount +
-					'\n\tSmoothingGroup count: ' + report.smoothingGroupCount +
-					'\n\tMaterial count: ' + report.mtlCount +
-					'\n\tReal RawMeshSubGroup count: ' + report.subGroups
-				);
-			}
-
 			return report;
 		};
 
@@ -1284,9 +1305,10 @@ THREE.OBJLoader2 = (function () {
 	 * @param {string} [crossOrigin] CORS value
 	 */
 	OBJLoader2.prototype._loadMtl = function ( resource, callbackOnLoad, crossOrigin ) {
-		if ( Validator.isValid( resource ) ) console.time( 'Loading MTL: ' + resource.name );
+		if ( Validator.isValid( resource ) ) this.logger.logTimeStart( 'Loading MTL: ' + resource.name );
 
 		var materials = [];
+		var scope = this;
 		var processMaterials = function ( materialCreator ) {
 			var materialCreatorMaterials = [];
 			if ( Validator.isValid( materialCreator ) ) {
@@ -1303,7 +1325,7 @@ THREE.OBJLoader2 = (function () {
 				}
 			}
 
-			if ( Validator.isValid( resource ) ) console.timeEnd( 'Loading MTL: ' + resource.name );
+			if ( Validator.isValid( resource ) ) scope.logger.logTimeEnd( 'Loading MTL: ' + resource.name );
 			callbackOnLoad( materials );
 		};
 
@@ -1327,7 +1349,7 @@ THREE.OBJLoader2 = (function () {
 
 				var onError = function ( event ) {
 					var output = 'Error occurred while downloading "' + resource.url + '"';
-					console.error( output + ': ' + event );
+					this.logger.logError( output + ': ' + event );
 					throw output;
 				};
 

+ 4 - 4
examples/webgl_loader_obj2.html

@@ -143,9 +143,9 @@
 
 					var scope = this;
 					var objLoader = new THREE.OBJLoader2();
-					var callbackOnLoad = function ( loaderRootNode, modelName, instanceNo ) {
-						scope.scene.add( loaderRootNode );
-						console.log( 'Loading complete: ' + modelName );
+					var callbackOnLoad = function ( event ) {
+						scope.scene.add( event.detail.loaderRootNode );
+						console.log( 'Loading complete: ' + event.detail.modelName );
 						scope._reportProgress( '' );
 					};
 
@@ -154,7 +154,7 @@
 						objLoader.setMaterials( materials );
 						objLoader.setUseIndices( true );
 						objLoader.setDisregardNormals( false );
-						objLoader.setDebug( false );
+						objLoader.getLogger().setDebug( true );
 						objLoader.load( 'obj/female02/female02.obj', callbackOnLoad, null, null, null, false );
 					};
 					objLoader.loadMtl( 'obj/female02/female02.mtl', 'female02.mtl', null, onLoadMtl );

+ 50 - 26
examples/webgl_loader_obj2_meshspray.html

@@ -75,21 +75,18 @@
 		<script src="js/Detector.js"></script>
 		<script src="../build/three.js"></script>
 		<script src="js/controls/TrackballControls.js"></script>
-		<script src="js/loaders/MTLLoader.js"></script>
 		<script src="js/libs/dat.gui.min.js"></script>
 
 		<script src="js/loaders/LoaderSupport.js"></script>
 
 		<script>
-			/**
-			 * @author Kai Salmen / www.kaisalmen.de
-			 */
 
 			'use strict';
 
 			var MeshSpray = (function () {
 
 				var Validator = THREE.LoaderSupport.Validator;
+				var ConsoleLogger = THREE.LoaderSupport.ConsoleLogger;
 
 				MeshSpray.prototype = Object.create( THREE.LoaderSupport.Commons.prototype );
 				MeshSpray.prototype.constructor = MeshSpray;
@@ -97,10 +94,23 @@
 				function MeshSpray( manager ) {
 					THREE.LoaderSupport.Commons.call( this, manager );
 					this.workerSupport = null;
+					this.logger = new ConsoleLogger();
 				};
 
 				MeshSpray.prototype.run = function ( prepData, workerSupportExternal ) {
-					console.time( 'MeshSpray' );
+
+					if ( Validator.isValid( workerSupportExternal ) ) {
+
+						this.workerSupport = workerSupportExternal;
+						this.logger = workerSupportExternal.logger;
+
+					} else {
+
+						this.workerSupport = Validator.verifyInput( this.workerSupport, new THREE.LoaderSupport.WorkerSupport() );
+
+					}
+
+					this.logger.logTimeStart( 'MeshSpray' );
 
 					this._applyPrepData( prepData );
 
@@ -115,18 +125,25 @@
 					};
 					var scopeFuncComplete = function ( message ) {
 						var callback = scope.callbacks.onLoad;
-						if ( Validator.isValid( callback ) ) callback( scope.loaderRootNode, scope.modelName, scope.instanceNo, message );
-						console.timeEnd( 'MeshSpray' );
+						if ( Validator.isValid( callback ) ) callback(
+							{
+								detail: {
+									loaderRootNode: scope.loaderRootNode,
+									modelName: scope.modelName,
+									instanceNo: scope.instanceNo
+								}
+							}
+						);
+						scope.logger.logTimeEnd( 'MeshSpray' );
 					};
 
-			        this.workerSupport = Validator.verifyInput( workerSupportExternal, this.workerSupport );
-					this.workerSupport = Validator.verifyInput( this.workerSupport, new THREE.LoaderSupport.WorkerSupport() );
 					var buildCode = function ( funcBuildObject, funcBuildSingelton ) {
 						var workerCode = '';
 						workerCode += '/**\n';
 						workerCode += '  * This code was constructed by MeshSpray buildWorkerCode.\n';
 						workerCode += '  */\n\n';
 						workerCode += funcBuildObject( 'Validator', Validator );
+						workerCode += funcBuildSingelton( 'ConsoleLogger', 'ConsoleLogger', ConsoleLogger );
 						workerCode += funcBuildSingelton( 'Parser', 'Parser', Parser );
 
 						return workerCode;
@@ -138,10 +155,15 @@
 							cmd: 'run',
 							params: {
 								debug: this.debug,
+								enableLogging: this.logger.enabled,
 								dimension: prepData.dimension,
 								quantity: prepData.quantity,
 								globalObjectCount: prepData.globalObjectCount
 							},
+							logger: {
+								debug: this.logger.debug,
+								enabled: this.logger.enabled
+							},
 							materials: {
 								materialNames: this.builder.materialNames
 							},
@@ -154,7 +176,7 @@
 
 				var Parser  = ( function () {
 
-					function Parser() {
+					function Parser( logger ) {
 						this.sizeFactor = 0.5;
 						this.localOffsetFactor = 1.0;
 						this.globalObjectCount = 0;
@@ -162,6 +184,7 @@
 						this.dimension = 200;
 						this.quantity = 1;
 						this.callbackBuilder = null;
+						this.logger = logger;
 					};
 
 					Parser.prototype.parse = function () {
@@ -244,6 +267,9 @@
 						this.callbackBuilder(
 							{
 								cmd: 'meshData',
+								progress: {
+									numericalValue: 1.0
+								},
 								params: {
 									meshName: 'Gen' + this.globalObjectCount
 								},
@@ -265,7 +291,7 @@
 							uvFA !== null ? [ uvFA.buffer ] : null
 						);
 
-						console.log( 'Global output object count: ' + this.globalObjectCount );
+						this.logger.logInfo( 'Global output object count: ' + this.globalObjectCount );
 					};
 
 					return Parser;
@@ -277,6 +303,8 @@
 
 			var MeshSprayApp = (function () {
 
+				var Validator = THREE.LoaderSupport.Validator;
+
 				function MeshSprayApp( elementToBindTo ) {
 					this.renderer = null;
 					this.canvas = elementToBindTo;
@@ -343,28 +371,24 @@
 					var maxQueueSize = 1024;
 					var maxWebWorkers = 4;
 					var radius = 640;
-					this.workerDirector = new THREE.LoaderSupport.WorkerDirector( MeshSpray );
+					var logger = new THREE.LoaderSupport.ConsoleLogger( false );
+					this.workerDirector = new THREE.LoaderSupport.WorkerDirector( MeshSpray, logger );
 					this.workerDirector.setCrossOrigin( 'anonymous' );
 
 					var scope = this;
-					var callbackOnLoad = function ( sceneGraphBaseNode, modelName, instanceNo ) {
-						var msg = 'Worker #' + instanceNo + ': Completed loading. (#' + scope.workerDirector.objectsCompleted + ')';
-						console.log( msg );
+					var callbackOnLoad = function ( event ) {
+						logger.logInfo( 'Worker #' + event.detail.instanceNo + ': Completed loading. (#' + scope.workerDirector.objectsCompleted + ')' );
 					};
-					var reportProgress = function( content, modelName, instanceNo ) {
-						if ( THREE.LoaderSupport.Validator.isValid( content ) && content.length > 0 ) {
-
-							document.getElementById( 'feedback' ).innerHTML = content;
-							console.log( content );
-
-						}
+					var reportProgress = function( event ) {
+						document.getElementById( 'feedback' ).innerHTML = event.detail.text;
+						logger.logInfo( event.detail.text );
 					};
-					var callbackMeshAlter = function ( name, bufferGeometry, material ) {
+					var callbackMeshAlter = function ( event ) {
 						var override = new THREE.LoaderSupport.LoadedMeshUserOverride( false, true );
 
-						var mesh = new THREE.Mesh( bufferGeometry, material );
-						material.side = THREE.DoubleSide;
-						mesh.name = name;
+						event.detail.side = THREE.DoubleSide;
+						var mesh = new THREE.Mesh( event.detail.bufferGeometry, event.detail.material );
+						mesh.name = event.detail.meshName;
 						override.addMesh( mesh );
 
 						return override;

+ 29 - 27
examples/webgl_loader_obj2_options.html

@@ -155,7 +155,7 @@
 
 				WWOBJLoader2Example.prototype.useParseSync = function () {
 					var modelName = 'female02';
-					this._reportProgress( 'Loading: ' + modelName );
+					this._reportProgress( { detail: { text: 'Loading: ' + modelName } } );
 
 					var scope = this;
 					var objLoader = new THREE.OBJLoader2();
@@ -174,7 +174,7 @@
 								scope.pivot.add( local );
 								local.add( objLoader.parse( content ) );
 
-								scope._reportProgress( 'Loading complete: ' + modelName );
+								scope._reportProgress( { detail: { text: 'Loading complete: ' + modelName } } );
 							}
 						);
 					};
@@ -184,16 +184,16 @@
 
 				WWOBJLoader2Example.prototype.useParseAsync = function () {
 					var modelName = 'female02_vertex' ;
-					this._reportProgress( 'Loading: ' + modelName );
+					this._reportProgress( { detail: { text: 'Loading: ' + modelName } } );
 
-					var callbackOnLoad = function ( loaderRootNode, modelName, instanceNo ) {
+					var callbackOnLoad = function ( event ) {
 						var local = new THREE.Object3D();
 						local.name = 'Pivot_female02_vertex';
 						local.position.set( -75, 0, 0 );
 						scope.pivot.add( local );
-						local.add( loaderRootNode );
+						local.add( event.detail.loaderRootNode );
 
-						scope._reportProgress( 'Loading complete: ' + modelName );
+						scope._reportProgress( { detail: { text: 'Loading complete: ' + event.detail.modelName } } );
 					};
 
 					var scope = this;
@@ -203,28 +203,29 @@
 					var fileLoader = new THREE.FileLoader();
 					fileLoader.setPath( '' );
 					fileLoader.setResponseType( 'arraybuffer' );
-					fileLoader.load( 'obj/female02/female02_vertex_colors.obj',
+					var filename = 'obj/female02/female02_vertex_colors.obj';
+					fileLoader.load( filename,
 						function ( content ) {
 							objLoader.parseAsync( content, callbackOnLoad );
-							scope._reportProgress( 'Loading complete: ' + modelName );
+							scope._reportProgress( { detail: { text: 'File loading complete: ' + filename } } );
 						}
 					);
 				};
 
 				WWOBJLoader2Example.prototype.useLoadSync = function () {
 					var modelName = 'male02';
-					this._reportProgress( 'Loading: ' + modelName );
+					this._reportProgress( { detail: { text: 'Loading: ' + modelName } } );
 
 					var scope = this;
 					var objLoader = new THREE.OBJLoader2();
-					var callbackOnLoad = function ( loaderRootNode, modelName, instanceNo ) {
+					var callbackOnLoad = function ( event ) {
 						var local = new THREE.Object3D();
 						local.name = 'Pivot_male02';
 						local.position.set( 0, 0, -75 );
 						scope.pivot.add( local );
-						local.add( loaderRootNode );
+						local.add( event.detail.loaderRootNode );
 
-						scope._reportProgress( 'Loading complete: ' + modelName );
+						scope._reportProgress( { detail: { text: 'Loading complete: ' + event.detail.modelName } } );
 					};
 
 					var onLoadMtl = function ( materials ) {
@@ -237,20 +238,20 @@
 
 				WWOBJLoader2Example.prototype.useLoadAsync = function () {
 					var modelName = 'WaltHead';
-					this._reportProgress( 'Loading: ' + modelName );
+					this._reportProgress( { detail: { text: 'Loading: ' + modelName } } );
 
 					var scope = this;
 					var objLoader = new THREE.OBJLoader2();
-					var callbackOnLoad = function ( loaderRootNode, modelName, instanceNo ) {
+					var callbackOnLoad = function ( event ) {
 						var local = new THREE.Object3D();
 						local.name = 'Pivot_WaltHead';
 						local.position.set( -125, 50, 0 );
 						var scale = 0.5;
 						local.scale.set( scale, scale, scale );
 						scope.pivot.add( local );
-						local.add( loaderRootNode );
+						local.add( event.detail.loaderRootNode );
 
-						scope._reportProgress( 'Loading complete: ' + modelName );
+						scope._reportProgress( { detail: { text: 'Loading complete: ' + event.detail.modelName } } );
 					};
 
 					var onLoadMtl = function ( materials ) {
@@ -263,8 +264,8 @@
 
 				WWOBJLoader2Example.prototype.useRunSync = function () {
 					var scope = this;
-					var callbackOnLoad = function ( loaderRootNode, modelName, instanceNo ) {
-						scope._reportProgress( 'Loading complete: ' + modelName );
+					var callbackOnLoad = function ( event ) {
+						scope._reportProgress( { detail: { text: 'Loading complete: ' + event.detail.modelName } } );
 					};
 
 					var prepData = new THREE.LoaderSupport.PrepData( 'cerberus' );
@@ -284,8 +285,8 @@
 
 				WWOBJLoader2Example.prototype.useRunAsyncMeshAlter = function () {
 					var scope = this;
-					var callbackOnLoad = function ( loaderRootNode, modelName, instanceNo ) {
-						scope._reportProgress( 'Loading complete: ' + modelName );
+					var callbackOnLoad = function ( event ) {
+						scope._reportProgress( { detail: { text: 'Loading complete: ' + event.detail.modelName } } );
 					};
 
 					var prepData = new THREE.LoaderSupport.PrepData( 'vive-controller' );
@@ -297,13 +298,13 @@
 					prepData.addResource( new THREE.LoaderSupport.ResourceDescriptor( 'models/obj/vive-controller/vr_controller_vive_1_5.obj', 'OBJ' ) );
 					prepData.setUseAsync( true );
 					var callbacks = prepData.getCallbacks();
-					var callbackMeshAlter = function ( name, bufferGeometry, material ) {
+					var callbackMeshAlter = function ( event ) {
 						var override = new THREE.LoaderSupport.LoadedMeshUserOverride( false, true );
 
-						var mesh = new THREE.Mesh( bufferGeometry, material );
+						var mesh = new THREE.Mesh( event.detail.bufferGeometry, event.detail.material );
 						var scale = 200.0;
 						mesh.scale.set( scale, scale, scale );
-						mesh.name = name;
+						mesh.name = event.detail.meshName;
 						var helper = new THREE.VertexNormalsHelper( mesh, 2, 0x00ff00, 1 );
 						helper.name = 'VertexNormalsHelper';
 
@@ -321,12 +322,13 @@
 				};
 
 				WWOBJLoader2Example.prototype.finalize = function () {
-					this._reportProgress( '' );
+					this._reportProgress( { detail: { text: '' } } );
 				};
 
-				WWOBJLoader2Example.prototype._reportProgress = function( content, modelName, instanceNo ) {
-					console.log( 'Progress: ' + content );
-					document.getElementById( 'feedback' ).innerHTML = Validator.isValid( content ) ? content : '';
+				WWOBJLoader2Example.prototype._reportProgress = function( event ) {
+					var output = Validator.verifyInput( event.detail.text, '' );
+					console.log( 'Progress: ' + output );
+					document.getElementById( 'feedback' ).innerHTML = output;
 				};
 
 				WWOBJLoader2Example.prototype.resizeDisplayGL = function () {

+ 29 - 15
examples/webgl_loader_obj2_run_director.html

@@ -111,7 +111,9 @@
 					this.camera = null;
 					this.cameraTarget = this.cameraDefaults.posCameraTarget;
 
-					this.workerDirector = new THREE.LoaderSupport.WorkerDirector( THREE.OBJLoader2 );
+					var logger = new THREE.LoaderSupport.ConsoleLogger();
+					logger.setEnabled( false );
+					this.workerDirector = new THREE.LoaderSupport.WorkerDirector( THREE.OBJLoader2, logger  );
 					this.workerDirector.setCrossOrigin( 'anonymous' );
 
 					this.controls = null;
@@ -191,8 +193,14 @@
 
 					this.renderer.render( this.scene, this.camera );
 				};
-				WWParallels.prototype.reportProgress = function( text ) {
-					document.getElementById( 'feedback' ).innerHTML = text;
+
+				WWParallels.prototype._reportProgress = function( content ) {
+					var output = content;
+					if ( Validator.isValid( content ) && Validator.isValid( content.detail ) ) output = content.detail.text;
+
+					output = Validator.verifyInput( output, '' );
+					console.log( 'Progress:\n\t' + output.replace(/\<br\>/g, '\n\t' ) );
+					document.getElementById( 'feedback' ).innerHTML = output;
 				};
 
 				WWParallels.prototype.enqueueAllAssests = function ( maxQueueSize, maxWebWorkers, streamMeshes ) {
@@ -218,39 +226,45 @@
 						scope.reportDonwload[ i ] = true;
 
 					}
-					scope.reportProgress( scope.feedbackArray.join( '\<br\>' ) );
+					scope._reportProgress( scope.feedbackArray.join( '\<br\>' ) );
 
-					var callbackOnLoad = function ( loaderRootNode, modelName, instanceNo ) {
+					var callbackOnLoad = function ( event ) {
+						var instanceNo = event.detail.instanceNo;
 						scope.reportDonwload[ instanceNo ] = false;
-						scope.allAssets.push( loaderRootNode );
+						scope.allAssets.push( event.detail.loaderRootNode );
 
-						var msg = 'Worker #' + instanceNo + ': Completed loading: ' + modelName + ' (#' + scope.workerDirector.objectsCompleted + ')';
+						var msg = 'Worker #' + instanceNo + ': Completed loading: ' + event.detail.modelName + ' (#' + scope.workerDirector.objectsCompleted + ')';
 						console.log( msg );
 						scope.feedbackArray[ instanceNo ] = msg;
-						scope.reportProgress( scope.feedbackArray.join( '\<br\>' ) );
+						scope._reportProgress( scope.feedbackArray.join( '\<br\>' ) );
 
 						if ( scope.workerDirector.objectsCompleted + 1 === maxQueueSize ) scope.running = false;
 					};
 
-					var callbackReportProgress = function ( content, modelName, instanceNo ) {
+					var callbackReportProgress = function ( event ) {
+						var	instanceNo = event.detail.instanceNo;
+						var text = event.detail.text;
+
 						if ( scope.reportDonwload[ instanceNo ] ) {
-							var msg = 'Worker #' + instanceNo + ': ' + content;
+							var msg = 'Worker #' + instanceNo + ': ' + text;
 							console.log( msg );
 
 							scope.feedbackArray[ instanceNo ] = msg;
-							scope.reportProgress( scope.feedbackArray.join( '\<br\>' ) );
+							scope._reportProgress( scope.feedbackArray.join( '\<br\>' ) );
 						}
 					};
 
-					var callbackMeshAlter = function ( name, bufferGeometry, material ) {
+					var callbackMeshAlter = function ( event ) {
 						var override = new THREE.LoaderSupport.LoadedMeshUserOverride( false, false );
 
-						if ( Validator.isValid( material ) && material.name === 'defaultMaterial' || name === 'Mesh_Mesh_head_geo.001_lambert2SG.001' ) {
+						var material = event.detail.material;
+						var meshName = event.detail.meshName;
+						if ( Validator.isValid( material ) && material.name === 'defaultMaterial' || meshName === 'Mesh_Mesh_head_geo.001_lambert2SG.001' ) {
 
 							var materialOverride = material;
 							materialOverride.color = new THREE.Color( Math.random(), Math.random(), Math.random() );
-							var mesh = new THREE.Mesh( bufferGeometry, material );
-							mesh.name = name;
+							var mesh = new THREE.Mesh( event.detail.bufferGeometry, material );
+							mesh.name = meshName;
 
 							override.addMesh( mesh );
 							override.alteredMesh = true;