Browse Source

Updated examples builds

Mr.doob 3 years ago
parent
commit
38d0b96b4b

+ 25 - 14
examples/js/exporters/USDZExporter.js

@@ -228,25 +228,33 @@ def "Geometry"
 
 	function buildMeshVertexCount( geometry ) {
 
-		const count = geometry.index !== null ? geometry.index.array.length : geometry.attributes.position.count;
+		const count = geometry.index !== null ? geometry.index.count : geometry.attributes.position.count;
 		return Array( count / 3 ).fill( 3 ).join( ', ' );
 
 	}
 
 	function buildMeshVertexIndices( geometry ) {
 
-		if ( geometry.index !== null ) {
+		const index = geometry.index;
+		const array = [];
 
-			return geometry.index.array.join( ', ' );
+		if ( index !== null ) {
 
-		}
+			for ( let i = 0; i < index.count; i ++ ) {
 
-		const array = [];
-		const length = geometry.attributes.position.count;
+				array.push( index.getX( i ) );
+
+			}
 
-		for ( let i = 0; i < length; i ++ ) {
+		} else {
+
+			const length = geometry.attributes.position.count;
+
+			for ( let i = 0; i < length; i ++ ) {
 
-			array.push( i );
+				array.push( i );
+
+			}
 
 		}
 
@@ -264,11 +272,13 @@ def "Geometry"
 		}
 
 		const array = [];
-		const data = attribute.array;
 
-		for ( let i = 0; i < data.length; i += 3 ) {
+		for ( let i = 0; i < attribute.count; i ++ ) {
 
-			array.push( `(${data[ i + 0 ].toPrecision( PRECISION )}, ${data[ i + 1 ].toPrecision( PRECISION )}, ${data[ i + 2 ].toPrecision( PRECISION )})` );
+			const x = attribute.getX( i );
+			const y = attribute.getY( i );
+			const z = attribute.getZ( i );
+			array.push( `(${x.toPrecision( PRECISION )}, ${y.toPrecision( PRECISION )}, ${z.toPrecision( PRECISION )})` );
 
 		}
 
@@ -286,11 +296,12 @@ def "Geometry"
 		}
 
 		const array = [];
-		const data = attribute.array;
 
-		for ( let i = 0; i < data.length; i += 2 ) {
+		for ( let i = 0; i < attribute.count; i ++ ) {
 
-			array.push( `(${data[ i + 0 ].toPrecision( PRECISION )}, ${1 - data[ i + 1 ].toPrecision( PRECISION )})` );
+			const x = attribute.getX( i );
+			const y = attribute.getY( i );
+			array.push( `(${x.toPrecision( PRECISION )}, ${1 - y.toPrecision( PRECISION )})` );
 
 		}
 

+ 11 - 7
examples/js/loaders/ColladaLoader.js

@@ -1332,18 +1332,22 @@
 			}
 
 			function parseEffectExtraTechniqueBump( xml ) {
+
 				var data = {};
 
 				for ( var i = 0, l = xml.childNodes.length; i < l; i ++ ) {
 
 					var child = xml.childNodes[ i ];
-
 					if ( child.nodeType !== 1 ) continue;
 
 					switch ( child.nodeName ) {
 
 						case 'texture':
-							data[ child.nodeName ] = { id: child.getAttribute( 'texture' ), texcoord: child.getAttribute( 'texcoord' ), extra: parseEffectParameterTexture( child ) };
+							data[ child.nodeName ] = {
+								id: child.getAttribute( 'texture' ),
+								texcoord: child.getAttribute( 'texcoord' ),
+								extra: parseEffectParameterTexture( child )
+							};
 							break;
 
 					}
@@ -1607,16 +1611,16 @@
 
 				if ( technique.extra !== undefined && technique.extra.technique !== undefined ) {
 
-					let techniques = technique.extra.technique;
+					const techniques = technique.extra.technique;
 
-					for ( let k in techniques ) {
+					for ( const k in techniques ) {
 
-						let v = techniques[k];
+						const v = techniques[ k ];
 
-						switch (k) {
+						switch ( k ) {
 
 							case 'double_sided':
-								material.side = ( v === 1 ? THREE.DoubleSide : THREE.FrontSide );
+								material.side = v === 1 ? THREE.DoubleSide : THREE.FrontSide;
 								break;
 
 							case 'bump':

+ 12 - 0
examples/js/loaders/KTX2Loader.js

@@ -17,6 +17,8 @@
 
 	const _taskCache = new WeakMap();
 
+	let _activeLoaders = 0;
+
 	class KTX2Loader extends THREE.Loader {
 
 		constructor( manager ) {
@@ -109,6 +111,15 @@
 
 				} );
 
+				if ( _activeLoaders > 0 ) {
+
+					// Each instance loads a transcoder and allocates workers, increasing network and memory cost.
+					console.warn( 'THREE.KTX2Loader: Multiple active KTX2 loaders may cause performance issues.' + ' Use a single KTX2Loader instance, or call .dispose() on old instances.' );
+
+				}
+
+				_activeLoaders ++;
+
 			}
 
 			return this.transcoderPending;
@@ -207,6 +218,7 @@
 
 			URL.revokeObjectURL( this.workerSourceURL );
 			this.workerPool.dispose();
+			_activeLoaders --;
 			return this;
 
 		}

+ 237 - 271
examples/js/loaders/TDSLoader.js

@@ -16,7 +16,6 @@
 			super( manager );
 			this.debug = false;
 			this.group = null;
-			this.position = 0;
 			this.materials = [];
 			this.meshes = [];
 
@@ -79,7 +78,6 @@
 		parse( arraybuffer, path ) {
 
 			this.group = new THREE.Group();
-			this.position = 0;
 			this.materials = [];
 			this.meshes = [];
 			this.readFile( arraybuffer, path );
@@ -105,31 +103,30 @@
 		readFile( arraybuffer, path ) {
 
 			const data = new DataView( arraybuffer );
-			const chunk = this.readChunk( data );
+			const chunk = new Chunk( data, 0, this.debugMessage );
 
 			if ( chunk.id === MLIBMAGIC || chunk.id === CMAGIC || chunk.id === M3DMAGIC ) {
 
-				let next = this.nextChunk( data, chunk );
+				let next = chunk.readChunk();
 
-				while ( next !== 0 ) {
+				while ( next ) {
 
-					if ( next === M3D_VERSION ) {
+					if ( next.id === M3D_VERSION ) {
 
-						const version = this.readDWord( data );
+						const version = next.readDWord();
 						this.debugMessage( '3DS file version: ' + version );
 
-					} else if ( next === MDATA ) {
+					} else if ( next.id === MDATA ) {
 
-						this.resetPosition( data );
-						this.readMeshData( data, path );
+						this.readMeshData( next, path );
 
 					} else {
 
-						this.debugMessage( 'Unknown main chunk: ' + next.toString( 16 ) );
+						this.debugMessage( 'Unknown main chunk: ' + next.hexId );
 
 					}
 
-					next = this.nextChunk( data, chunk );
+					next = chunk.readChunk();
 
 				}
 
@@ -142,48 +139,45 @@
    * Read mesh data chunk.
    *
    * @method readMeshData
-   * @param {Dataview} data Dataview in use.
+   * @param {Chunk} chunk to read mesh from
    * @param {String} path Path for external resources.
    */
 
 
-		readMeshData( data, path ) {
+		readMeshData( chunk, path ) {
 
-			const chunk = this.readChunk( data );
-			let next = this.nextChunk( data, chunk );
+			let next = chunk.readChunk();
 
-			while ( next !== 0 ) {
+			while ( next ) {
 
-				if ( next === MESH_VERSION ) {
+				if ( next.id === MESH_VERSION ) {
 
-					const version = + this.readDWord( data );
+					const version = + next.readDWord();
 					this.debugMessage( 'Mesh Version: ' + version );
 
-				} else if ( next === MASTER_SCALE ) {
+				} else if ( next.id === MASTER_SCALE ) {
 
-					const scale = this.readFloat( data );
+					const scale = next.readFloat();
 					this.debugMessage( 'Master scale: ' + scale );
 					this.group.scale.set( scale, scale, scale );
 
-				} else if ( next === NAMED_OBJECT ) {
+				} else if ( next.id === NAMED_OBJECT ) {
 
 					this.debugMessage( 'Named Object' );
-					this.resetPosition( data );
-					this.readNamedObject( data );
+					this.readNamedObject( next );
 
-				} else if ( next === MAT_ENTRY ) {
+				} else if ( next.id === MAT_ENTRY ) {
 
 					this.debugMessage( 'Material' );
-					this.resetPosition( data );
-					this.readMaterialEntry( data, path );
+					this.readMaterialEntry( next, path );
 
 				} else {
 
-					this.debugMessage( 'Unknown MDATA chunk: ' + next.toString( 16 ) );
+					this.debugMessage( 'Unknown MDATA chunk: ' + next.hexId );
 
 				}
 
-				next = this.nextChunk( data, chunk );
+				next = chunk.readChunk();
 
 			}
 
@@ -192,145 +186,134 @@
    * Read named object chunk.
    *
    * @method readNamedObject
-   * @param {Dataview} data Dataview in use.
+   * @param {Chunk} chunk Chunk in use.
    */
 
 
-		readNamedObject( data ) {
+		readNamedObject( chunk ) {
 
-			const chunk = this.readChunk( data );
-			const name = this.readString( data, 64 );
-			chunk.cur = this.position;
-			let next = this.nextChunk( data, chunk );
+			const name = chunk.readString();
+			let next = chunk.readChunk();
 
-			while ( next !== 0 ) {
+			while ( next ) {
 
-				if ( next === N_TRI_OBJECT ) {
+				if ( next.id === N_TRI_OBJECT ) {
 
-					this.resetPosition( data );
-					const mesh = this.readMesh( data );
+					const mesh = this.readMesh( next );
 					mesh.name = name;
 					this.meshes.push( mesh );
 
 				} else {
 
-					this.debugMessage( 'Unknown named object chunk: ' + next.toString( 16 ) );
+					this.debugMessage( 'Unknown named object chunk: ' + next.hexId );
 
 				}
 
-				next = this.nextChunk( data, chunk );
+				next = chunk.readChunk();
 
 			}
 
-			this.endChunk( chunk );
-
 		}
 		/**
    * Read material data chunk and add it to the material list.
    *
    * @method readMaterialEntry
-   * @param {Dataview} data Dataview in use.
+   * @param {Chunk} chunk Chunk in use.
    * @param {String} path Path for external resources.
    */
 
 
-		readMaterialEntry( data, path ) {
+		readMaterialEntry( chunk, path ) {
 
-			const chunk = this.readChunk( data );
-			let next = this.nextChunk( data, chunk );
+			let next = chunk.readChunk();
 			const material = new THREE.MeshPhongMaterial();
 
-			while ( next !== 0 ) {
+			while ( next ) {
 
-				if ( next === MAT_NAME ) {
+				if ( next.id === MAT_NAME ) {
 
-					material.name = this.readString( data, 64 );
+					material.name = next.readString();
 					this.debugMessage( '   Name: ' + material.name );
 
-				} else if ( next === MAT_WIRE ) {
+				} else if ( next.id === MAT_WIRE ) {
 
 					this.debugMessage( '   Wireframe' );
 					material.wireframe = true;
 
-				} else if ( next === MAT_WIRE_SIZE ) {
+				} else if ( next.id === MAT_WIRE_SIZE ) {
 
-					const value = this.readByte( data );
+					const value = next.readByte();
 					material.wireframeLinewidth = value;
 					this.debugMessage( '   Wireframe Thickness: ' + value );
 
-				} else if ( next === MAT_TWO_SIDE ) {
+				} else if ( next.id === MAT_TWO_SIDE ) {
 
 					material.side = THREE.DoubleSide;
 					this.debugMessage( '   DoubleSided' );
 
-				} else if ( next === MAT_ADDITIVE ) {
+				} else if ( next.id === MAT_ADDITIVE ) {
 
 					this.debugMessage( '   Additive Blending' );
 					material.blending = THREE.AdditiveBlending;
 
-				} else if ( next === MAT_DIFFUSE ) {
+				} else if ( next.id === MAT_DIFFUSE ) {
 
 					this.debugMessage( '   Diffuse THREE.Color' );
-					material.color = this.readColor( data );
+					material.color = this.readColor( next );
 
-				} else if ( next === MAT_SPECULAR ) {
+				} else if ( next.id === MAT_SPECULAR ) {
 
 					this.debugMessage( '   Specular THREE.Color' );
-					material.specular = this.readColor( data );
+					material.specular = this.readColor( next );
 
-				} else if ( next === MAT_AMBIENT ) {
+				} else if ( next.id === MAT_AMBIENT ) {
 
 					this.debugMessage( '   Ambient color' );
-					material.color = this.readColor( data );
+					material.color = this.readColor( next );
 
-				} else if ( next === MAT_SHININESS ) {
+				} else if ( next.id === MAT_SHININESS ) {
 
-					const shininess = this.readPercentage( data );
+					const shininess = this.readPercentage( next );
 					material.shininess = shininess * 100;
 					this.debugMessage( '   Shininess : ' + shininess );
 
-				} else if ( next === MAT_TRANSPARENCY ) {
+				} else if ( next.id === MAT_TRANSPARENCY ) {
 
-					const transparency = this.readPercentage( data );
+					const transparency = this.readPercentage( next );
 					material.opacity = 1 - transparency;
 					this.debugMessage( '  Transparency : ' + transparency );
 					material.transparent = material.opacity < 1 ? true : false;
 
-				} else if ( next === MAT_TEXMAP ) {
+				} else if ( next.id === MAT_TEXMAP ) {
 
 					this.debugMessage( '   ColorMap' );
-					this.resetPosition( data );
-					material.map = this.readMap( data, path );
+					material.map = this.readMap( next, path );
 
-				} else if ( next === MAT_BUMPMAP ) {
+				} else if ( next.id === MAT_BUMPMAP ) {
 
 					this.debugMessage( '   BumpMap' );
-					this.resetPosition( data );
-					material.bumpMap = this.readMap( data, path );
+					material.bumpMap = this.readMap( next, path );
 
-				} else if ( next === MAT_OPACMAP ) {
+				} else if ( next.id === MAT_OPACMAP ) {
 
 					this.debugMessage( '   OpacityMap' );
-					this.resetPosition( data );
-					material.alphaMap = this.readMap( data, path );
+					material.alphaMap = this.readMap( next, path );
 
-				} else if ( next === MAT_SPECMAP ) {
+				} else if ( next.id === MAT_SPECMAP ) {
 
 					this.debugMessage( '   SpecularMap' );
-					this.resetPosition( data );
-					material.specularMap = this.readMap( data, path );
+					material.specularMap = this.readMap( next, path );
 
 				} else {
 
-					this.debugMessage( '   Unknown material chunk: ' + next.toString( 16 ) );
+					this.debugMessage( '   Unknown material chunk: ' + next.hexId );
 
 				}
 
-				next = this.nextChunk( data, chunk );
+				next = chunk.readChunk();
 
 			}
 
-			this.endChunk( chunk );
 			this.materials[ material.name ] = material;
 
 		}
@@ -338,68 +321,66 @@
    * Read mesh data chunk.
    *
    * @method readMesh
-   * @param {Dataview} data Dataview in use.
+   * @param {Chunk} chunk Chunk in use.
    * @return {Mesh} The parsed mesh.
    */
 
 
-		readMesh( data ) {
+		readMesh( chunk ) {
 
-			const chunk = this.readChunk( data );
-			let next = this.nextChunk( data, chunk );
+			let next = chunk.readChunk();
 			const geometry = new THREE.BufferGeometry();
 			const material = new THREE.MeshPhongMaterial();
 			const mesh = new THREE.Mesh( geometry, material );
 			mesh.name = 'mesh';
 
-			while ( next !== 0 ) {
+			while ( next ) {
 
-				if ( next === POINT_ARRAY ) {
+				if ( next.id === POINT_ARRAY ) {
 
-					const points = this.readWord( data );
+					const points = next.readWord();
 					this.debugMessage( '   Vertex: ' + points ); //BufferGeometry
 
 					const vertices = [];
 
 					for ( let i = 0; i < points; i ++ ) {
 
-						vertices.push( this.readFloat( data ) );
-						vertices.push( this.readFloat( data ) );
-						vertices.push( this.readFloat( data ) );
+						vertices.push( next.readFloat() );
+						vertices.push( next.readFloat() );
+						vertices.push( next.readFloat() );
 
 					}
 
 					geometry.setAttribute( 'position', new THREE.Float32BufferAttribute( vertices, 3 ) );
 
-				} else if ( next === FACE_ARRAY ) {
+				} else if ( next.id === FACE_ARRAY ) {
 
-					this.resetPosition( data );
-					this.readFaceArray( data, mesh );
+					this.readFaceArray( next, mesh );
 
-				} else if ( next === TEX_VERTS ) {
+				} else if ( next.id === TEX_VERTS ) {
 
-					const texels = this.readWord( data );
+					const texels = next.readWord();
 					this.debugMessage( '   UV: ' + texels ); //BufferGeometry
 
 					const uvs = [];
 
 					for ( let i = 0; i < texels; i ++ ) {
 
-						uvs.push( this.readFloat( data ) );
-						uvs.push( this.readFloat( data ) );
+						uvs.push( next.readFloat() );
+						uvs.push( next.readFloat() );
 
 					}
 
 					geometry.setAttribute( 'uv', new THREE.Float32BufferAttribute( uvs, 2 ) );
 
-				} else if ( next === MESH_MATRIX ) {
+				} else if ( next.id === MESH_MATRIX ) {
 
 					this.debugMessage( '   Tranformation Matrix (TODO)' );
 					const values = [];
 
 					for ( let i = 0; i < 12; i ++ ) {
 
-						values[ i ] = this.readFloat( data );
+						values[ i ] = next.readFloat();
 
 					}
 
@@ -432,15 +413,14 @@
 
 				} else {
 
-					this.debugMessage( '   Unknown mesh chunk: ' + next.toString( 16 ) );
+					this.debugMessage( '   Unknown mesh chunk: ' + next.hexId );
 
 				}
 
-				next = this.nextChunk( data, chunk );
+				next = chunk.readChunk();
 
 			}
 
-			this.endChunk( chunk );
 			geometry.computeVertexNormals();
 			return mesh;
 
@@ -449,22 +429,21 @@
    * Read face array data chunk.
    *
    * @method readFaceArray
-   * @param {Dataview} data Dataview in use.
+   * @param {Chunk} chunk Chunk in use.
    * @param {Mesh} mesh THREE.Mesh to be filled with the data read.
    */
 
 
-		readFaceArray( data, mesh ) {
+		readFaceArray( chunk, mesh ) {
 
-			const chunk = this.readChunk( data );
-			const faces = this.readWord( data );
+			const faces = chunk.readWord();
 			this.debugMessage( '   Faces: ' + faces );
 			const index = [];
 
 			for ( let i = 0; i < faces; ++ i ) {
 
-				index.push( this.readWord( data ), this.readWord( data ), this.readWord( data ) );
-				this.readWord( data ); // visibility
+				index.push( chunk.readWord(), chunk.readWord(), chunk.readWord() );
+				chunk.readWord(); // visibility
 
 			}
 
@@ -473,15 +452,14 @@
 			let materialIndex = 0;
 			let start = 0;
 
-			while ( this.position < chunk.end ) {
+			while ( ! chunk.endOfChunk ) {
 
-				const subchunk = this.readChunk( data );
+				const subchunk = chunk.readChunk();
 
 				if ( subchunk.id === MSH_MAT_GROUP ) {
 
 					this.debugMessage( '      Material THREE.Group' );
-					this.resetPosition( data );
-					const group = this.readMaterialGroup( data );
+					const group = this.readMaterialGroup( subchunk );
 					const count = group.index.length * 3; // assuming successive indices
 
 					mesh.geometry.addGroup( start, count, materialIndex );
@@ -498,76 +476,70 @@
 
 				} else {
 
-					this.debugMessage( '      Unknown face array chunk: ' + subchunk.toString( 16 ) );
+					this.debugMessage( '      Unknown face array chunk: ' + subchunk.hexId );
 
 				}
 
-				this.endChunk( subchunk );
-
 			}
 
 			if ( mesh.material.length === 1 ) mesh.material = mesh.material[ 0 ]; // for backwards compatibility
 
-			this.endChunk( chunk );
-
 		}
 		/**
    * Read texture map data chunk.
    *
    * @method readMap
-   * @param {Dataview} data Dataview in use.
+   * @param {Chunk} chunk Chunk in use.
    * @param {String} path Path for external resources.
    * @return {Texture} Texture read from this data chunk.
    */
 
 
-		readMap( data, path ) {
+		readMap( chunk, path ) {
 
-			const chunk = this.readChunk( data );
-			let next = this.nextChunk( data, chunk );
+			let next = chunk.readChunk();
 			let texture = {};
 			const loader = new THREE.TextureLoader( this.manager );
 			loader.setPath( this.resourcePath || path ).setCrossOrigin( this.crossOrigin );
 
-			while ( next !== 0 ) {
+			while ( next ) {
 
-				if ( next === MAT_MAPNAME ) {
+				if ( next.id === MAT_MAPNAME ) {
 
-					const name = this.readString( data, 128 );
+					const name = next.readString();
 					texture = loader.load( name );
 					this.debugMessage( '      File: ' + path + name );
 
-				} else if ( next === MAT_MAP_UOFFSET ) {
+				} else if ( next.id === MAT_MAP_UOFFSET ) {
 
-					texture.offset.x = this.readFloat( data );
+					texture.offset.x = next.readFloat();
 					this.debugMessage( '      OffsetX: ' + texture.offset.x );
 
-				} else if ( next === MAT_MAP_VOFFSET ) {
+				} else if ( next.id === MAT_MAP_VOFFSET ) {
 
-					texture.offset.y = this.readFloat( data );
+					texture.offset.y = next.readFloat();
 					this.debugMessage( '      OffsetY: ' + texture.offset.y );
 
-				} else if ( next === MAT_MAP_USCALE ) {
+				} else if ( next.id === MAT_MAP_USCALE ) {
 
-					texture.repeat.x = this.readFloat( data );
+					texture.repeat.x = next.readFloat();
 					this.debugMessage( '      RepeatX: ' + texture.repeat.x );
 
-				} else if ( next === MAT_MAP_VSCALE ) {
+				} else if ( next.id === MAT_MAP_VSCALE ) {
 
-					texture.repeat.y = this.readFloat( data );
+					texture.repeat.y = next.readFloat();
 					this.debugMessage( '      RepeatY: ' + texture.repeat.y );
 
 				} else {
 
-					this.debugMessage( '      Unknown map chunk: ' + next.toString( 16 ) );
+					this.debugMessage( '      Unknown map chunk: ' + next.hexId );
 
 				}
 
-				next = this.nextChunk( data, chunk );
+				next = chunk.readChunk();
 
 			}
 
-			this.endChunk( chunk );
 			return texture;
 
 		}
@@ -575,23 +547,22 @@
    * Read material group data chunk.
    *
    * @method readMaterialGroup
-   * @param {Dataview} data Dataview in use.
+   * @param {Chunk} chunk Chunk in use.
    * @return {Object} Object with name and index of the object.
    */
 
 
-		readMaterialGroup( data ) {
+		readMaterialGroup( chunk ) {
 
-			this.readChunk( data );
-			const name = this.readString( data, 64 );
-			const numFaces = this.readWord( data );
+			const name = chunk.readString();
+			const numFaces = chunk.readWord();
 			this.debugMessage( '         Name: ' + name );
 			this.debugMessage( '         Faces: ' + numFaces );
 			const index = [];
 
 			for ( let i = 0; i < numFaces; ++ i ) {
 
-				index.push( this.readWord( data ) );
+				index.push( chunk.readWord() );
 
 			}
 
@@ -605,132 +576,191 @@
    * Read a color value.
    *
    * @method readColor
-   * @param {DataView} data Dataview.
+   * @param {Chunk} chunk Chunk.
    * @return {Color} THREE.Color value read..
    */
 
 
-		readColor( data ) {
+		readColor( chunk ) {
 
-			const chunk = this.readChunk( data );
+			const subChunk = chunk.readChunk();
 			const color = new THREE.Color();
 
-			if ( chunk.id === COLOR_24 || chunk.id === LIN_COLOR_24 ) {
+			if ( subChunk.id === COLOR_24 || subChunk.id === LIN_COLOR_24 ) {
 
-				const r = this.readByte( data );
-				const g = this.readByte( data );
-				const b = this.readByte( data );
+				const r = subChunk.readByte();
+				const g = subChunk.readByte();
+				const b = subChunk.readByte();
 				color.setRGB( r / 255, g / 255, b / 255 );
 				this.debugMessage( '      THREE.Color: ' + color.r + ', ' + color.g + ', ' + color.b );
 
-			} else if ( chunk.id === COLOR_F || chunk.id === LIN_COLOR_F ) {
+			} else if ( subChunk.id === COLOR_F || subChunk.id === LIN_COLOR_F ) {
 
-				const r = this.readFloat( data );
-				const g = this.readFloat( data );
-				const b = this.readFloat( data );
+				const r = subChunk.readFloat();
+				const g = subChunk.readFloat();
+				const b = subChunk.readFloat();
 				color.setRGB( r, g, b );
 				this.debugMessage( '      THREE.Color: ' + color.r + ', ' + color.g + ', ' + color.b );
 
 			} else {
 
-				this.debugMessage( '      Unknown color chunk: ' + chunk.toString( 16 ) );
+				this.debugMessage( '      Unknown color chunk: ' + subChunk.hexId );
 
 			}
 
-			this.endChunk( chunk );
 			return color;
 
 		}
 		/**
-   * Read next chunk of data.
+   * Read percentage value.
    *
-   * @method readChunk
-   * @param {DataView} data Dataview.
-   * @return {Object} Chunk of data read.
+   * @method readPercentage
+   * @param {Chunk} chunk Chunk to read data from.
+   * @return {Number} Data read from the dataview.
    */
 
 
-		readChunk( data ) {
+		readPercentage( chunk ) {
 
-			const chunk = {};
-			chunk.cur = this.position;
-			chunk.id = this.readWord( data );
-			chunk.size = this.readDWord( data );
-			chunk.end = chunk.cur + chunk.size;
-			chunk.cur += 6;
-			return chunk;
+			const subChunk = chunk.readChunk();
+
+			switch ( subChunk.id ) {
+
+				case INT_PERCENTAGE:
+					return subChunk.readShort() / 100;
+					break;
+
+				case FLOAT_PERCENTAGE:
+					return subChunk.readFloat();
+					break;
+
+				default:
+					this.debugMessage( '      Unknown percentage chunk: ' + subChunk.hexId );
+					return 0;
+
+			}
 
 		}
 		/**
-   * Set position to the end of the current chunk of data.
+   * Print debug message to the console.
+   *
+   * Is controlled by a flag to show or hide debug messages.
    *
-   * @method endChunk
-   * @param {Object} chunk Data chunk.
+   * @method debugMessage
+   * @param {Object} message Debug message to print to the console.
    */
 
 
-		endChunk( chunk ) {
+		debugMessage( message ) {
+
+			if ( this.debug ) {
 
-			this.position = chunk.end;
+				console.log( message );
+
+			}
 
 		}
+
+	}
+	/** Read data/sub-chunks from chunk */
+
+
+	class Chunk {
+
 		/**
-   * Move to the next data chunk.
+   * Create a new chunk
    *
-   * @method nextChunk
-   * @param {DataView} data Dataview.
-   * @param {Object} chunk Data chunk.
+   * @class Chunk
+   * @param {DataView} data DataView to read from.
+   * @param {Number} position in data.
+   * @param {Function} debugMessage logging callback.
    */
+		constructor( data, position, debugMessage ) {
 
+			this.data = data; // the offset to the begin of this chunk
 
-		nextChunk( data, chunk ) {
+			this.offset = position; // the current reading position
 
-			if ( chunk.cur >= chunk.end ) {
+			this.position = position;
+			this.debugMessage = debugMessage;
 
-				return 0;
+			if ( this.debugMessage instanceof Function ) {
+
+				this.debugMessage = function () {};
+
+			}
+
+			this.id = this.readWord();
+			this.size = this.readDWord();
+			this.end = this.offset + this.size;
+
+			if ( this.end > data.byteLength ) {
+
+				this.debugMessage( 'Bad chunk size for chunk at ' + position );
 
 			}
 
-			this.position = chunk.cur;
+		}
+		/**
+   * read a sub cchunk.
+   *
+   * @method readChunk
+   * @return {Chunk | null} next sub chunk
+   */
+
+
+		readChunk() {
+
+			if ( this.endOfChunk ) {
+
+				return null;
+
+			}
 
 			try {
 
-				const next = this.readChunk( data );
-				chunk.cur += next.size;
-				return next.id;
+				const next = new Chunk( this.data, this.position, this.debugMessage );
+				this.position += next.size;
+				return next;
 
 			} catch ( e ) {
 
 				this.debugMessage( 'Unable to read chunk at ' + this.position );
-				return 0;
+				return null;
 
 			}
 
 		}
 		/**
-   * Reset dataview position.
+   * return the ID of this chunk as Hex
    *
-   * @method resetPosition
+   * @method idToString
+   * @return {String} hex-string of id
    */
 
 
-		resetPosition() {
+		get hexId() {
 
-			this.position -= 6;
+			return this.id.toString( 16 );
+
+		}
+
+		get endOfChunk() {
+
+			return this.position >= this.end;
 
 		}
 		/**
    * Read byte value.
    *
    * @method readByte
-   * @param {DataView} data Dataview to read data from.
    * @return {Number} Data read from the dataview.
    */
 
 
-		readByte( data ) {
+		readByte() {
 
-			const v = data.getUint8( this.position, true );
+			const v = this.data.getUint8( this.position, true );
 			this.position += 1;
 			return v;
 
@@ -739,22 +769,22 @@
    * Read 32 bit float value.
    *
    * @method readFloat
-   * @param {DataView} data Dataview to read data from.
    * @return {Number} Data read from the dataview.
    */
 
 
-		readFloat( data ) {
+		readFloat() {
 
 			try {
 
-				const v = data.getFloat32( this.position, true );
+				const v = this.data.getFloat32( this.position, true );
 				this.position += 4;
 				return v;
 
 			} catch ( e ) {
 
-				this.debugMessage( e + ' ' + this.position + ' ' + data.byteLength );
+				this.debugMessage( e + ' ' + this.position + ' ' + this.data.byteLength );
+				return 0;
 
 			}
 
@@ -763,14 +793,13 @@
    * Read 32 bit signed integer value.
    *
    * @method readInt
-   * @param {DataView} data Dataview to read data from.
    * @return {Number} Data read from the dataview.
    */
 
 
-		readInt( data ) {
+		readInt() {
 
-			const v = data.getInt32( this.position, true );
+			const v = this.data.getInt32( this.position, true );
 			this.position += 4;
 			return v;
 
@@ -779,14 +808,13 @@
    * Read 16 bit signed integer value.
    *
    * @method readShort
-   * @param {DataView} data Dataview to read data from.
    * @return {Number} Data read from the dataview.
    */
 
 
-		readShort( data ) {
+		readShort() {
 
-			const v = data.getInt16( this.position, true );
+			const v = this.data.getInt16( this.position, true );
 			this.position += 2;
 			return v;
 
@@ -795,14 +823,13 @@
    * Read 64 bit unsigned integer value.
    *
    * @method readDWord
-   * @param {DataView} data Dataview to read data from.
    * @return {Number} Data read from the dataview.
    */
 
 
-		readDWord( data ) {
+		readDWord() {
 
-			const v = data.getUint32( this.position, true );
+			const v = this.data.getUint32( this.position, true );
 			this.position += 4;
 			return v;
 
@@ -811,101 +838,40 @@
    * Read 32 bit unsigned integer value.
    *
    * @method readWord
-   * @param {DataView} data Dataview to read data from.
    * @return {Number} Data read from the dataview.
    */
 
 
-		readWord( data ) {
+		readWord() {
 
-			const v = data.getUint16( this.position, true );
+			const v = this.data.getUint16( this.position, true );
 			this.position += 2;
 			return v;
 
 		}
 		/**
-   * Read string value.
+   * Read NULL terminated ASCII string value from chunk-pos.
    *
    * @method readString
-   * @param {DataView} data Dataview to read data from.
-   * @param {Number} maxLength Max size of the string to be read.
    * @return {String} Data read from the dataview.
    */
 
 
-		readString( data, maxLength ) {
+		readString() {
 
 			let s = '';
+			let c = this.readByte();
 
-			for ( let i = 0; i < maxLength; i ++ ) {
-
-				const c = this.readByte( data );
-
-				if ( ! c ) {
-
-					break;
-
-				}
+			while ( c ) {
 
 				s += String.fromCharCode( c );
+				c = this.readByte();
 
 			}
 
 			return s;
 
 		}
-		/**
-   * Read percentage value.
-   *
-   * @method readPercentage
-   * @param {DataView} data Dataview to read data from.
-   * @return {Number} Data read from the dataview.
-   */
-
-
-		readPercentage( data ) {
-
-			const chunk = this.readChunk( data );
-			let value;
-
-			switch ( chunk.id ) {
-
-				case INT_PERCENTAGE:
-					value = this.readShort( data ) / 100;
-					break;
-
-				case FLOAT_PERCENTAGE:
-					value = this.readFloat( data );
-					break;
-
-				default:
-					this.debugMessage( '      Unknown percentage chunk: ' + chunk.toString( 16 ) );
-
-			}
-
-			this.endChunk( chunk );
-			return value;
-
-		}
-		/**
-   * Print debug message to the console.
-   *
-   * Is controlled by a flag to show or hide debug messages.
-   *
-   * @method debugMessage
-   * @param {Object} message Debug message to print to the console.
-   */
-
-
-		debugMessage( message ) {
-
-			if ( this.debug ) {
-
-				console.log( message );
-
-			}
-
-		}
 
 	} // const NULL_CHUNK = 0x0000;
 

+ 42 - 128
examples/js/objects/MarchingCubes.js

@@ -4,18 +4,19 @@
  * Port of http://webglsamples.org/blob/blob.html
  */
 
-	class MarchingCubes extends THREE.ImmediateRenderObject {
+	class MarchingCubes extends THREE.Mesh {
 
-		constructor( resolution, material, enableUvs, enableColors ) {
+		constructor( resolution, material, enableUvs = false, enableColors = false, maxPolyCount = 10000 ) {
 
-			super( material );
+			const geometry = new THREE.BufferGeometry();
+			super( geometry, material );
 			const scope = this; // temp buffers used in polygonize
 
 			const vlist = new Float32Array( 12 * 3 );
 			const nlist = new Float32Array( 12 * 3 );
 			const clist = new Float32Array( 12 * 3 );
-			this.enableUvs = enableUvs !== undefined ? enableUvs : false;
-			this.enableColors = enableColors !== undefined ? enableColors : false; // functions have to be object properties
+			this.enableUvs = enableUvs;
+			this.enableColors = enableColors; // functions have to be object properties
 			// prototype functions kill performance
 			// (tested and it was 4x slower !!!)
 
@@ -35,27 +36,34 @@
 				this.zd = this.size2;
 				this.field = new Float32Array( this.size3 );
 				this.normal_cache = new Float32Array( this.size3 * 3 );
-				this.palette = new Float32Array( this.size3 * 3 ); // immediate render mode simulator
-
-				this.maxCount = 4096; // TODO: find the fastest size for this buffer
+				this.palette = new Float32Array( this.size3 * 3 ); //
 
 				this.count = 0;
-				this.hasPositions = false;
-				this.hasNormals = false;
-				this.hasColors = false;
-				this.hasUvs = false;
-				this.positionArray = new Float32Array( this.maxCount * 3 );
-				this.normalArray = new Float32Array( this.maxCount * 3 );
+				const maxVertexCount = maxPolyCount * 3;
+				this.positionArray = new Float32Array( maxVertexCount * 3 );
+				const positionAttribute = new THREE.BufferAttribute( this.positionArray, 3 );
+				positionAttribute.setUsage( THREE.DynamicDrawUsage );
+				geometry.setAttribute( 'position', positionAttribute );
+				this.normalArray = new Float32Array( maxVertexCount * 3 );
+				const normalAttribute = new THREE.BufferAttribute( this.normalArray, 3 );
+				normalAttribute.setUsage( THREE.DynamicDrawUsage );
+				geometry.setAttribute( 'normal', normalAttribute );
 
 				if ( this.enableUvs ) {
 
-					this.uvArray = new Float32Array( this.maxCount * 2 );
+					this.uvArray = new Float32Array( maxVertexCount * 2 );
+					const uvAttribute = new THREE.BufferAttribute( this.uvArray, 2 );
+					uvAttribute.setUsage( THREE.DynamicDrawUsage );
+					geometry.setAttribute( 'uv', uvAttribute );
 
 				}
 
 				if ( this.enableColors ) {
 
-					this.colorArray = new Float32Array( this.maxCount * 3 );
+					this.colorArray = new Float32Array( maxVertexCount * 3 );
+					const colorAttribute = new THREE.BufferAttribute( this.colorArray, 3 );
+					colorAttribute.setUsage( THREE.DynamicDrawUsage );
+					geometry.setAttribute( 'color', colorAttribute );
 
 				}
 
@@ -136,7 +144,7 @@
 			// (this is where most of time is spent - it's inner work of O(n3) loop )
 
 
-			function polygonize( fx, fy, fz, q, isol, renderCallback ) {
+			function polygonize( fx, fy, fz, q, isol ) {
 
 				// cache indices
 				const q1 = q + 1,
@@ -282,7 +290,7 @@
 					o1 = cubeindex + i;
 					o2 = o1 + 1;
 					o3 = o1 + 2;
-					posnormtriv( vlist, nlist, clist, 3 * triTable[ o1 ], 3 * triTable[ o2 ], 3 * triTable[ o3 ], renderCallback );
+					posnormtriv( vlist, nlist, clist, 3 * triTable[ o1 ], 3 * triTable[ o2 ], 3 * triTable[ o3 ] );
 					i += 3;
 					numtris ++;
 
@@ -290,12 +298,9 @@
 
 				return numtris;
 
-			} /////////////////////////////////////
-			// Immediate render mode simulator
-			/////////////////////////////////////
-
+			}
 
-			function posnormtriv( pos, norm, colors, o1, o2, o3, renderCallback ) {
+			function posnormtriv( pos, norm, colors, o1, o2, o3 ) {
 
 				const c = scope.count * 3; // positions
 
@@ -368,67 +373,7 @@
 
 				scope.count += 3;
 
-				if ( scope.count >= scope.maxCount - 3 ) {
-
-					scope.hasPositions = true;
-					scope.hasNormals = true;
-
-					if ( scope.enableUvs ) {
-
-						scope.hasUvs = true;
-
-					}
-
-					if ( scope.enableColors ) {
-
-						scope.hasColors = true;
-
-					}
-
-					renderCallback( scope );
-
-				}
-
-			}
-
-			this.begin = function () {
-
-				this.count = 0;
-				this.hasPositions = false;
-				this.hasNormals = false;
-				this.hasUvs = false;
-				this.hasColors = false;
-
-			};
-
-			this.end = function ( renderCallback ) {
-
-				if ( this.count === 0 ) return;
-
-				for ( let i = this.count * 3; i < this.positionArray.length; i ++ ) {
-
-					this.positionArray[ i ] = 0.0;
-
-				}
-
-				this.hasPositions = true;
-				this.hasNormals = true;
-
-				if ( this.enableUvs && this.material.map ) {
-
-					this.hasUvs = true;
-
-				}
-
-				if ( this.enableColors && this.material.vertexColors !== THREE.NoColors ) {
-
-					this.hasColors = true;
-
-				}
-
-				renderCallback( this );
-
-			}; /////////////////////////////////////
+			} /////////////////////////////////////
 			// Metaballs
 			/////////////////////////////////////
 			// Adds a reciprocal ball (nice and blobby) that, to be fast, fades to zero after
@@ -729,9 +674,9 @@
 
 			};
 
-			this.render = function ( renderCallback ) {
+			this.onBeforeRender = function () {
 
-				this.begin(); // Triangulate. Yeah, this is slow.
+				this.count = 0; // Triangulate. Yeah, this is slow.
 
 				const smin2 = this.size - 2;
 
@@ -750,59 +695,28 @@
 							const fx = ( x - this.halfsize ) / this.halfsize; //+ 1
 
 							const q = y_offset + x;
-							polygonize( fx, fy, fz, q, this.isolation, renderCallback );
+							polygonize( fx, fy, fz, q, this.isolation );
 
 						}
 
 					}
 
-				}
-
-				this.end( renderCallback );
-
-			};
-
-			this.generateGeometry = function () {
-
-				console.warn( 'THREE.MarchingCubes: generateGeometry() now returns THREE.BufferGeometry' );
-				return this.generateBufferGeometry();
+				} // reset unneeded data
 
-			};
-
-			function concatenate( a, b, length ) {
 
-				const result = new Float32Array( a.length + length );
-				result.set( a, 0 );
-				result.set( b.slice( 0, length ), a.length );
-				return result;
-
-			}
-
-			this.generateBufferGeometry = function () {
+				for ( let i = this.count * 3; i < this.positionArray.length; i ++ ) {
 
-				const geo = new THREE.BufferGeometry();
-				let posArray = new Float32Array();
-				let normArray = new Float32Array();
-				let colorArray = new Float32Array();
-				let uvArray = new Float32Array();
-				const scope = this;
+					this.positionArray[ i ] = 0.0;
 
-				const geo_callback = function ( object ) {
+				} // update geometry data
 
-					if ( scope.hasPositions ) posArray = concatenate( posArray, object.positionArray, object.count * 3 );
-					if ( scope.hasNormals ) normArray = concatenate( normArray, object.normalArray, object.count * 3 );
-					if ( scope.hasColors ) colorArray = concatenate( colorArray, object.colorArray, object.count * 3 );
-					if ( scope.hasUvs ) uvArray = concatenate( uvArray, object.uvArray, object.count * 2 );
-					object.count = 0;
 
-				};
+				geometry.getAttribute( 'position' ).needsUpdate = true;
+				geometry.getAttribute( 'normal' ).needsUpdate = true;
+				if ( this.enableUvs ) geometry.getAttribute( 'uv' ).needsUpdate = true;
+				if ( this.enableColors ) geometry.getAttribute( 'color' ).needsUpdate = true; // safety check
 
-				this.render( geo_callback );
-				if ( this.hasPositions ) geo.setAttribute( 'position', new THREE.BufferAttribute( posArray, 3 ) );
-				if ( this.hasNormals ) geo.setAttribute( 'normal', new THREE.BufferAttribute( normArray, 3 ) );
-				if ( this.hasColors ) geo.setAttribute( 'color', new THREE.BufferAttribute( colorArray, 3 ) );
-				if ( this.hasUvs ) geo.setAttribute( 'uv', new THREE.BufferAttribute( uvArray, 2 ) );
-				return geo;
+				if ( this.count / 3 > maxPolyCount ) console.warn( 'THREE.MarchingCubes: Geometry buffers too small for rendering. Please create an instance with a higher poly count.' );
 
 			};
 
@@ -816,7 +730,7 @@
 	// Marching cubes lookup tables
 	/////////////////////////////////////
 	// These tables are straight from Paul Bourke's page:
-	// http://local.wasp.uwa.edu.au/~pbourke/geometry/polygonise/
+	// http://paulbourke.net/geometry/polygonise/
 	// who in turn got them from Cory Gene Bloyd.
 
 	const edgeTable = new Int32Array( [ 0x0, 0x109, 0x203, 0x30a, 0x406, 0x50f, 0x605, 0x70c, 0x80c, 0x905, 0xa0f, 0xb06, 0xc0a, 0xd03, 0xe09, 0xf00, 0x190, 0x99, 0x393, 0x29a, 0x596, 0x49f, 0x795, 0x69c, 0x99c, 0x895, 0xb9f, 0xa96, 0xd9a, 0xc93, 0xf99, 0xe90, 0x230, 0x339, 0x33, 0x13a, 0x636, 0x73f, 0x435, 0x53c, 0xa3c, 0xb35, 0x83f, 0x936, 0xe3a, 0xf33, 0xc39, 0xd30, 0x3a0, 0x2a9, 0x1a3, 0xaa, 0x7a6, 0x6af, 0x5a5, 0x4ac, 0xbac, 0xaa5, 0x9af, 0x8a6, 0xfaa, 0xea3, 0xda9, 0xca0, 0x460, 0x569, 0x663, 0x76a, 0x66, 0x16f, 0x265, 0x36c, 0xc6c, 0xd65, 0xe6f, 0xf66, 0x86a, 0x963, 0xa69, 0xb60, 0x5f0, 0x4f9, 0x7f3, 0x6fa, 0x1f6, 0xff, 0x3f5, 0x2fc, 0xdfc, 0xcf5, 0xfff, 0xef6, 0x9fa, 0x8f3, 0xbf9, 0xaf0, 0x650, 0x759, 0x453, 0x55a, 0x256, 0x35f, 0x55, 0x15c, 0xe5c, 0xf55, 0xc5f, 0xd56, 0xa5a, 0xb53, 0x859, 0x950, 0x7c0, 0x6c9, 0x5c3, 0x4ca, 0x3c6, 0x2cf, 0x1c5, 0xcc, 0xfcc, 0xec5, 0xdcf, 0xcc6, 0xbca, 0xac3, 0x9c9, 0x8c0, 0x8c0, 0x9c9, 0xac3, 0xbca, 0xcc6, 0xdcf, 0xec5, 0xfcc, 0xcc, 0x1c5, 0x2cf, 0x3c6, 0x4ca, 0x5c3, 0x6c9, 0x7c0, 0x950, 0x859, 0xb53, 0xa5a, 0xd56, 0xc5f, 0xf55, 0xe5c, 0x15c, 0x55, 0x35f, 0x256, 0x55a, 0x453, 0x759, 0x650, 0xaf0, 0xbf9, 0x8f3, 0x9fa, 0xef6, 0xfff, 0xcf5, 0xdfc, 0x2fc, 0x3f5, 0xff, 0x1f6, 0x6fa, 0x7f3, 0x4f9, 0x5f0, 0xb60, 0xa69, 0x963, 0x86a, 0xf66, 0xe6f, 0xd65, 0xc6c, 0x36c, 0x265, 0x16f, 0x66, 0x76a, 0x663, 0x569, 0x460, 0xca0, 0xda9, 0xea3, 0xfaa, 0x8a6, 0x9af, 0xaa5, 0xbac, 0x4ac, 0x5a5, 0x6af, 0x7a6, 0xaa, 0x1a3, 0x2a9, 0x3a0, 0xd30, 0xc39, 0xf33, 0xe3a, 0x936, 0x83f, 0xb35, 0xa3c, 0x53c, 0x435, 0x73f, 0x636, 0x13a, 0x33, 0x339, 0x230, 0xe90, 0xf99, 0xc93, 0xd9a, 0xa96, 0xb9f, 0x895, 0x99c, 0x69c, 0x795, 0x49f, 0x596, 0x29a, 0x393, 0x99, 0x190, 0xf00, 0xe09, 0xd03, 0xc0a, 0xb06, 0xa0f, 0x905, 0x80c, 0x70c, 0x605, 0x50f, 0x406, 0x30a, 0x203, 0x109, 0x0 ] );

+ 4 - 4
examples/js/renderers/CSS2DRenderer.js

@@ -2,10 +2,10 @@
 
 	class CSS2DObject extends THREE.Object3D {
 
-		constructor( element ) {
+		constructor( element = document.createElement( 'div' ) ) {
 
 			super();
-			this.element = element || document.createElement( 'div' );
+			this.element = element;
 			this.element.style.position = 'absolute';
 			this.element.style.userSelect = 'none';
 			this.element.setAttribute( 'draggable', false );
@@ -49,7 +49,7 @@
 
 	class CSS2DRenderer {
 
-		constructor() {
+		constructor( parameters = {} ) {
 
 			const _this = this;
 
@@ -60,7 +60,7 @@
 			const cache = {
 				objects: new WeakMap()
 			};
-			const domElement = document.createElement( 'div' );
+			const domElement = parameters.element !== undefined ? parameters.element : document.createElement( 'div' );
 			domElement.style.overflow = 'hidden';
 			this.domElement = domElement;
 

+ 4 - 4
examples/js/renderers/CSS3DRenderer.js

@@ -12,10 +12,10 @@
 
 	class CSS3DObject extends THREE.Object3D {
 
-		constructor( element ) {
+		constructor( element = document.createElement( 'div' ) ) {
 
 			super();
-			this.element = element || document.createElement( 'div' );
+			this.element = element;
 			this.element.style.position = 'absolute';
 			this.element.style.pointerEvents = 'auto';
 			this.element.style.userSelect = 'none';
@@ -75,7 +75,7 @@
 
 	class CSS3DRenderer {
 
-		constructor() {
+		constructor( parameters = {} ) {
 
 			const _this = this;
 
@@ -90,7 +90,7 @@
 				},
 				objects: new WeakMap()
 			};
-			const domElement = document.createElement( 'div' );
+			const domElement = parameters.element !== undefined ? parameters.element : document.createElement( 'div' );
 			domElement.style.overflow = 'hidden';
 			this.domElement = domElement;
 			const cameraElement = document.createElement( 'div' );