Browse Source

Merge remote-tracking branch 'origin/dev' into MarchingCubes

Gero3 6 years ago
parent
commit
1583b0948d
57 changed files with 5292 additions and 510 deletions
  1. 8 0
      docs/manual/en/introduction/Import-via-modules.html
  2. 11 7
      examples/js/loaders/AssimpLoader.js
  3. 3 81
      examples/js/loaders/GLTFLoader.js
  4. 63 127
      examples/js/loaders/HDRCubeTextureLoader.js
  5. 1 3
      examples/js/loaders/LDrawLoader.js
  6. 3 1
      examples/js/loaders/sea3d/SEA3DLoader.js
  7. 5 5
      examples/js/misc/GPUComputationRenderer.js
  8. 0 0
      examples/js/misc/Gyroscope.js
  9. 1 1
      examples/js/misc/MD2Character.js
  10. 9 9
      examples/js/misc/MD2CharacterComplex.js
  11. 0 0
      examples/js/misc/MorphBlendMesh.js
  12. 0 1
      examples/js/objects/MarchingCubes.js
  13. 105 0
      examples/jsm/geometries/LightningStrike.d.ts
  14. 1021 0
      examples/jsm/geometries/LightningStrike.js
  15. 17 0
      examples/jsm/libs/inflate.min.js
  16. 11 7
      examples/jsm/loaders/AssimpLoader.js
  17. 1 0
      examples/jsm/loaders/FBXLoader.js
  18. 47 111
      examples/jsm/loaders/GLTFLoader.js
  19. 3 1
      examples/jsm/loaders/HDRCubeTextureLoader.d.ts
  20. 63 127
      examples/jsm/loaders/HDRCubeTextureLoader.js
  21. 14 0
      examples/jsm/loaders/MD2Loader.d.ts
  22. 398 0
      examples/jsm/loaders/MD2Loader.js
  23. 1 0
      examples/jsm/loaders/VTKLoader.js
  24. 21 0
      examples/jsm/misc/CarControls.d.ts
  25. 1 1
      examples/jsm/misc/ConvexObjectBreaker.d.ts
  26. 41 0
      examples/jsm/misc/GPUComputationRenderer.d.ts
  27. 391 0
      examples/jsm/misc/GPUComputationRenderer.js
  28. 7 0
      examples/jsm/misc/Gyroscope.d.ts
  29. 73 0
      examples/jsm/misc/Gyroscope.js
  30. 24 0
      examples/jsm/misc/MD2Character.d.ts
  31. 274 0
      examples/jsm/misc/MD2Character.js
  32. 51 0
      examples/jsm/misc/MD2CharacterComplex.d.ts
  33. 575 0
      examples/jsm/misc/MD2CharacterComplex.js
  34. 26 0
      examples/jsm/misc/MorphBlendMesh.d.ts
  35. 326 0
      examples/jsm/misc/MorphBlendMesh.js
  36. 35 0
      examples/jsm/objects/LightningStorm.d.ts
  37. 249 0
      examples/jsm/objects/LightningStorm.js
  38. 73 0
      examples/jsm/objects/MarchingCubes.d.ts
  39. 1285 0
      examples/jsm/objects/MarchingCubes.js
  40. 1 1
      examples/webgl_gpgpu_birds.html
  41. 1 1
      examples/webgl_gpgpu_protoplanet.html
  42. 1 1
      examples/webgl_gpgpu_water.html
  43. 1 0
      examples/webgl_lightningstrike.html
  44. 1 1
      examples/webgl_loader_md2.html
  45. 3 3
      examples/webgl_loader_md2_control.html
  46. 1 1
      examples/webgl_marchingcubes.html
  47. 4 3
      examples/webgl_materials_envmaps_hdr.html
  48. 4 2
      examples/webgl_materials_reflectivity.html
  49. 3 2
      examples/webgl_materials_variations_physical.html
  50. 3 2
      examples/webgl_materials_variations_standard.html
  51. 2 2
      examples/webgl_raycast_sprite.html
  52. 4 2
      examples/webgl_tonemapping.html
  53. 2 2
      examples/webvr_sculpt.html
  54. 1 1
      examples/webvr_vive_sculpt.html
  55. 2 0
      src/core/Raycaster.js
  56. 10 1
      src/objects/Sprite.js
  57. 11 3
      utils/modularize.js

+ 8 - 0
docs/manual/en/introduction/Import-via-modules.html

@@ -178,6 +178,7 @@
 						<li>KMZLoader</li>
 						<li>KTXLoader</li>
 						<li>LWOLoader</li>
+						<li>MD2Loader</li>
 						<li>MTLLoader</li>
 						<li>OBJLoader</li>
 						<li>PCDLoader</li>
@@ -207,6 +208,13 @@
 				</li>
 				<li>misc
 					<ul>
+						<li>Car</li>
+						<li>ConvexObjectBreaker</li>
+						<li>GPUComputationRenderer</li>
+						<li>Gyroscope</li>
+						<li>MD2Character</li>
+						<li>MD2CharacterComplex</li>
+						<li>MorphBlendMesh</li>
 						<li>Ocean</li>
 					</ul>
 				</li>

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

@@ -538,8 +538,7 @@ THREE.AssimpLoader.prototype = {
 			for ( var i in root.children ) {
 
 				var child = cloneTreeToBones( root.children[ i ], scene );
-				if ( child )
-					rootBone.add( child );
+				rootBone.add( child );
 
 			}
 
@@ -1314,6 +1313,10 @@ THREE.AssimpLoader.prototype = {
 
 		function aiScene() {
 
+			this.versionMajor = 0;
+			this.versionMinor = 0;
+			this.versionRevision = 0;
+			this.compileFlags = 0;
 			this.mFlags = 0;
 			this.mNumMeshes = 0;
 			this.mNumMaterials = 0;
@@ -2232,13 +2235,13 @@ THREE.AssimpLoader.prototype = {
 			extendStream( stream );
 			stream.Seek( 44, aiOrigin_CUR ); // signature
 			/*unsigned int versionMajor =*/
-			var versionMajor = Read_unsigned_int( stream );
+			pScene.versionMajor = Read_unsigned_int( stream );
 			/*unsigned int versionMinor =*/
-			var versionMinor = Read_unsigned_int( stream );
+			pScene.versionMinor = Read_unsigned_int( stream );
 			/*unsigned int versionRevision =*/
-			var versionRevision = Read_unsigned_int( stream );
+			pScene.versionRevision = Read_unsigned_int( stream );
 			/*unsigned int compileFlags =*/
-			var compileFlags = Read_unsigned_int( stream );
+			pScene.compileFlags = Read_unsigned_int( stream );
 			shortened = Read_uint16_t( stream ) > 0;
 			compressed = Read_uint16_t( stream ) > 0;
 			if ( shortened )
@@ -2260,10 +2263,11 @@ THREE.AssimpLoader.prototype = {
 			} else {
 
 				ReadBinaryScene( stream, pScene );
-				return pScene.toTHREE();
 
 			}
 
+			return pScene.toTHREE();
+
 		}
 
 		return InternReadFile( buffer );

+ 3 - 81
examples/js/loaders/GLTFLoader.js

@@ -183,11 +183,11 @@ THREE.GLTFLoader = ( function () {
 							break;
 
 						case EXTENSIONS.KHR_MATERIALS_UNLIT:
-							extensions[ extensionName ] = new GLTFMaterialsUnlitExtension( json );
+							extensions[ extensionName ] = new GLTFMaterialsUnlitExtension();
 							break;
 
 						case EXTENSIONS.KHR_MATERIALS_PBR_SPECULAR_GLOSSINESS:
-							extensions[ extensionName ] = new GLTFMaterialsPbrSpecularGlossinessExtension( json );
+							extensions[ extensionName ] = new GLTFMaterialsPbrSpecularGlossinessExtension();
 							break;
 
 						case EXTENSIONS.KHR_DRACO_MESH_COMPRESSION:
@@ -199,7 +199,7 @@ THREE.GLTFLoader = ( function () {
 							break;
 
 						case EXTENSIONS.KHR_TEXTURE_TRANSFORM:
-							extensions[ EXTENSIONS.KHR_TEXTURE_TRANSFORM ] = new GLTFTextureTransformExtension( json );
+							extensions[ EXTENSIONS.KHR_TEXTURE_TRANSFORM ] = new GLTFTextureTransformExtension();
 							break;
 
 						default:
@@ -419,8 +419,6 @@ THREE.GLTFLoader = ( function () {
 	};
 
 	/* BINARY EXTENSION */
-
-	var BINARY_EXTENSION_BUFFER_NAME = 'binary_glTF';
 	var BINARY_EXTENSION_HEADER_MAGIC = 'glTF';
 	var BINARY_EXTENSION_HEADER_LENGTH = 12;
 	var BINARY_EXTENSION_CHUNK_TYPES = { JSON: 0x4E4F534A, BIN: 0x004E4942 };
@@ -1105,17 +1103,6 @@ THREE.GLTFLoader = ( function () {
 		UNSIGNED_SHORT: 5123
 	};
 
-	var WEBGL_TYPE = {
-		5126: Number,
-		//35674: THREE.Matrix2,
-		35675: THREE.Matrix3,
-		35676: THREE.Matrix4,
-		35664: THREE.Vector2,
-		35665: THREE.Vector3,
-		35666: THREE.Vector4,
-		35678: THREE.Texture
-	};
-
 	var WEBGL_COMPONENT_TYPES = {
 		5120: Int8Array,
 		5121: Uint8Array,
@@ -1140,48 +1127,6 @@ THREE.GLTFLoader = ( function () {
 		10497: THREE.RepeatWrapping
 	};
 
-	var WEBGL_SIDES = {
-		1028: THREE.BackSide, // Culling front
-		1029: THREE.FrontSide // Culling back
-		//1032: THREE.NoSide   // Culling front and back, what to do?
-	};
-
-	var WEBGL_DEPTH_FUNCS = {
-		512: THREE.NeverDepth,
-		513: THREE.LessDepth,
-		514: THREE.EqualDepth,
-		515: THREE.LessEqualDepth,
-		516: THREE.GreaterEqualDepth,
-		517: THREE.NotEqualDepth,
-		518: THREE.GreaterEqualDepth,
-		519: THREE.AlwaysDepth
-	};
-
-	var WEBGL_BLEND_EQUATIONS = {
-		32774: THREE.AddEquation,
-		32778: THREE.SubtractEquation,
-		32779: THREE.ReverseSubtractEquation
-	};
-
-	var WEBGL_BLEND_FUNCS = {
-		0: THREE.ZeroFactor,
-		1: THREE.OneFactor,
-		768: THREE.SrcColorFactor,
-		769: THREE.OneMinusSrcColorFactor,
-		770: THREE.SrcAlphaFactor,
-		771: THREE.OneMinusSrcAlphaFactor,
-		772: THREE.DstAlphaFactor,
-		773: THREE.OneMinusDstAlphaFactor,
-		774: THREE.DstColorFactor,
-		775: THREE.OneMinusDstColorFactor,
-		776: THREE.SrcAlphaSaturateFactor
-		// The followings are not supported by Three.js yet
-		//32769: CONSTANT_COLOR,
-		//32770: ONE_MINUS_CONSTANT_COLOR,
-		//32771: CONSTANT_ALPHA,
-		//32772: ONE_MINUS_CONSTANT_COLOR
-	};
-
 	var WEBGL_TYPE_SIZES = {
 		'SCALAR': 1,
 		'VEC2': 2,
@@ -1217,15 +1162,6 @@ THREE.GLTFLoader = ( function () {
 		STEP: THREE.InterpolateDiscrete
 	};
 
-	var STATES_ENABLES = {
-		2884: 'CULL_FACE',
-		2929: 'DEPTH_TEST',
-		3042: 'BLEND',
-		3089: 'SCISSOR_TEST',
-		32823: 'POLYGON_OFFSET_FILL',
-		32926: 'SAMPLE_ALPHA_TO_COVERAGE'
-	};
-
 	var ALPHA_MODES = {
 		OPAQUE: 'OPAQUE',
 		MASK: 'MASK',
@@ -1518,19 +1454,6 @@ THREE.GLTFLoader = ( function () {
 
 		}
 
-	}
-	function isObjectEqual( a, b ) {
-
-		if ( Object.keys( a ).length !== Object.keys( b ).length ) return false;
-
-		for ( var key in a ) {
-
-			if ( a[ key ] !== b[ key ] ) return false;
-
-		}
-
-		return true;
-
 	}
 
 	function createPrimitiveKey( primitiveDef ) {
@@ -2581,7 +2504,6 @@ THREE.GLTFLoader = ( function () {
 
 		var parser = this;
 		var json = this.json;
-		var extensions = this.extensions;
 
 		var meshDef = json.meshes[ meshIndex ];
 		var primitives = meshDef.primitives;

+ 63 - 127
examples/js/loaders/HDRCubeTextureLoader.js

@@ -6,101 +6,60 @@
 THREE.HDRCubeTextureLoader = function ( manager ) {
 
 	this.manager = ( manager !== undefined ) ? manager : THREE.DefaultLoadingManager;
-	// override in sub classes
 	this.hdrLoader = new THREE.RGBELoader();
+	this.type = THREE.UnsignedByteType;
 
 };
 
-THREE.HDRCubeTextureLoader.prototype.load = function ( type, urls, onLoad, onProgress, onError ) {
+THREE.HDRCubeTextureLoader.prototype.load = function ( urls, onLoad, onProgress, onError ) {
 
-	var RGBEByteToRGBFloat = function ( sourceArray, sourceOffset, destArray, destOffset ) {
+	if ( ! Array.isArray( urls ) ) {
 
-		var e = sourceArray[ sourceOffset + 3 ];
-		var scale = Math.pow( 2.0, e - 128.0 ) / 255.0;
+		console.warn( 'THREE.HDRCubeTextureLoader signature has changed. Use .setType() instead.' );
 
-		destArray[ destOffset + 0 ] = sourceArray[ sourceOffset + 0 ] * scale;
-		destArray[ destOffset + 1 ] = sourceArray[ sourceOffset + 1 ] * scale;
-		destArray[ destOffset + 2 ] = sourceArray[ sourceOffset + 2 ] * scale;
+		this.setType( urls );
 
-	};
+		urls = onLoad;
+		onLoad = onProgress;
+		onProgress = onError;
+		onError = arguments[ 4 ];
 
-	var RGBEByteToRGBHalf = ( function () {
-
-		// Source: http://gamedev.stackexchange.com/questions/17326/conversion-of-a-number-from-single-precision-floating-point-representation-to-a/17410#17410
-
-		var floatView = new Float32Array( 1 );
-		var int32View = new Int32Array( floatView.buffer );
-
-		/* This method is faster than the OpenEXR implementation (very often
-		 * used, eg. in Ogre), with the additional benefit of rounding, inspired
-		 * by James Tursa?s half-precision code. */
-		function toHalf( val ) {
-
-			floatView[ 0 ] = val;
-			var x = int32View[ 0 ];
-
-			var bits = ( x >> 16 ) & 0x8000; /* Get the sign */
-			var m = ( x >> 12 ) & 0x07ff; /* Keep one extra bit for rounding */
-			var e = ( x >> 23 ) & 0xff; /* Using int is faster here */
-
-			/* If zero, or denormal, or exponent underflows too much for a denormal
-			 * half, return signed zero. */
-			if ( e < 103 ) return bits;
-
-			/* If NaN, return NaN. If Inf or exponent overflow, return Inf. */
-			if ( e > 142 ) {
-
-				bits |= 0x7c00;
-				/* If exponent was 0xff and one mantissa bit was set, it means NaN,
-						 * not Inf, so make sure we set one mantissa bit too. */
-				bits |= ( ( e == 255 ) ? 0 : 1 ) && ( x & 0x007fffff );
-				return bits;
-
-			}
-
-			/* If exponent underflows but not too much, return a denormal */
-			if ( e < 113 ) {
-
-				m |= 0x0800;
-				/* Extra rounding may overflow and set mantissa to 0 and exponent
-				 * to 1, which is OK. */
-				bits |= ( m >> ( 114 - e ) ) + ( ( m >> ( 113 - e ) ) & 1 );
-				return bits;
+	}
 
-			}
+	var texture = new THREE.CubeTexture();
 
-			bits |= ( ( e - 112 ) << 10 ) | ( m >> 1 );
-			/* Extra rounding. An overflow will set mantissa to 0 and increment
-			 * the exponent, which is OK. */
-			bits += m & 1;
-			return bits;
+	texture.type = this.type;
 
-		}
+	switch ( texture.type ) {
 
-		return function ( sourceArray, sourceOffset, destArray, destOffset ) {
+		case THREE.UnsignedByteType:
 
-			var e = sourceArray[ sourceOffset + 3 ];
-			var scale = Math.pow( 2.0, e - 128.0 ) / 255.0;
+			texture.encoding = THREE.RGBEEncoding;
+			texture.format = THREE.RGBAFormat;
+			texture.minFilter = THREE.NearestFilter;
+			texture.magFilter = THREE.NearestFilter;
+			texture.generateMipmaps = false;
+			break;
 
-			destArray[ destOffset + 0 ] = toHalf( sourceArray[ sourceOffset + 0 ] * scale );
-			destArray[ destOffset + 1 ] = toHalf( sourceArray[ sourceOffset + 1 ] * scale );
-			destArray[ destOffset + 2 ] = toHalf( sourceArray[ sourceOffset + 2 ] * scale );
+		case THREE.FloatType:
 
-		};
+			texture.encoding = THREE.LinearEncoding;
+			texture.format = THREE.RGBFormat;
+			texture.minFilter = THREE.LinearFilter;
+			texture.magFilter = THREE.LinearFilter;
+			texture.generateMipmaps = false;
+			break;
 
-	} )();
+		case THREE.HalfFloatType:
 
-	//
+			texture.encoding = THREE.LinearEncoding;
+			texture.format = THREE.RGBFormat;
+			texture.minFilter = THREE.LinearFilter;
+			texture.magFilter = THREE.LinearFilter;
+			texture.generateMipmaps = false;
+			break;
 
-	var texture = new THREE.CubeTexture();
-
-	texture.type = type;
-	texture.encoding = ( type === THREE.UnsignedByteType ) ? THREE.RGBEEncoding : THREE.LinearEncoding;
-	texture.format = ( type === THREE.UnsignedByteType ) ? THREE.RGBAFormat : THREE.RGBFormat;
-	texture.minFilter = ( texture.encoding === THREE.RGBEEncoding ) ? THREE.NearestFilter : THREE.LinearFilter;
-	texture.magFilter = ( texture.encoding === THREE.RGBEEncoding ) ? THREE.NearestFilter : THREE.LinearFilter;
-	texture.generateMipmaps = ( texture.encoding !== THREE.RGBEEncoding );
-	texture.anisotropy = 0;
+	}
 
 	var scope = this;
 
@@ -108,71 +67,40 @@ THREE.HDRCubeTextureLoader.prototype.load = function ( type, urls, onLoad, onPro
 
 	function loadHDRData( i, onLoad, onProgress, onError ) {
 
-		var loader = new THREE.FileLoader( scope.manager );
-		loader.setPath( scope.path );
-		loader.setResponseType( 'arraybuffer' );
-		loader.load( urls[ i ], function ( buffer ) {
+		new THREE.FileLoader( scope.manager )
+			.setPath( scope.path )
+			.setResponseType( 'arraybuffer' )
+			.load( urls[ i ], function ( buffer ) {
 
-			loaded ++;
+				loaded ++;
 
-			var texData = scope.hdrLoader._parser( buffer );
+				var texData = scope.hdrLoader._parser( buffer );
 
-			if ( ! texData ) return;
+				if ( ! texData ) return;
 
-			if ( type === THREE.FloatType ) {
+				if ( texData.data !== undefined ) {
 
-				var numElements = ( texData.data.length / 4 ) * 3;
-				var floatdata = new Float32Array( numElements );
+					var dataTexture = new THREE.DataTexture( texData.data, texData.width, texData.height );
 
-				for ( var j = 0; j < numElements; j ++ ) {
+					dataTexture.type = texture.type;
+					dataTexture.encoding = texture.encoding;
+					dataTexture.format = texture.format;
+					dataTexture.minFilter = texture.minFilter;
+					dataTexture.magFilter = texture.magFilter;
+					dataTexture.generateMipmaps = texture.generateMipmaps;
 
-					RGBEByteToRGBFloat( texData.data, j * 4, floatdata, j * 3 );
+					texture.images[ i ] = dataTexture;
 
 				}
 
-				texData.data = floatdata;
-
-			} else if ( type === THREE.HalfFloatType ) {
-
-				var numElements = ( texData.data.length / 4 ) * 3;
-				var halfdata = new Uint16Array( numElements );
+				if ( loaded === 6 ) {
 
-				for ( var j = 0; j < numElements; j ++ ) {
-
-					RGBEByteToRGBHalf( texData.data, j * 4, halfdata, j * 3 );
+					texture.needsUpdate = true;
+					if ( onLoad ) onLoad( texture );
 
 				}
 
-				texData.data = halfdata;
-
-			}
-
-			if ( texData.image !== undefined ) {
-
-				texture[ i ].images = texData.image;
-
-			} else if ( texData.data !== undefined ) {
-
-				var dataTexture = new THREE.DataTexture( texData.data, texData.width, texData.height );
-				dataTexture.format = texture.format;
-				dataTexture.type = texture.type;
-				dataTexture.encoding = texture.encoding;
-				dataTexture.minFilter = texture.minFilter;
-				dataTexture.magFilter = texture.magFilter;
-				dataTexture.generateMipmaps = texture.generateMipmaps;
-
-				texture.images[ i ] = dataTexture;
-
-			}
-
-			if ( loaded === 6 ) {
-
-				texture.needsUpdate = true;
-				if ( onLoad ) onLoad( texture );
-
-			}
-
-		}, onProgress, onError );
+			}, onProgress, onError );
 
 	}
 
@@ -192,3 +120,11 @@ THREE.HDRCubeTextureLoader.prototype.setPath = function ( value ) {
 	return this;
 
 };
+
+THREE.HDRCubeTextureLoader.prototype.setType = function ( value ) {
+
+	this.type = value;
+	this.hdrLoader.setType( value );
+	return this;
+
+};

+ 1 - 3
examples/js/loaders/LDrawLoader.js

@@ -1045,8 +1045,6 @@ THREE.LDrawLoader = ( function () {
 			var mainColourCode = parentParseScope.mainColourCode;
 			var mainEdgeColourCode = parentParseScope.mainEdgeColourCode;
 
-			var url = parentParseScope.url;
-
 			var currentParseScope = this.getCurrentParseScope();
 
 			// Parse result variables
@@ -1356,7 +1354,7 @@ THREE.LDrawLoader = ( function () {
 							0, 0, 0, 1
 						);
 
-						var fileName = lp.getRemainingString().trim().replace( "\\", "/" );
+						var fileName = lp.getRemainingString().trim().replace( /\\/g, "/" );
 
 						if ( scope.fileMap[ fileName ] ) {
 

+ 3 - 1
examples/js/loaders/sea3d/SEA3DLoader.js

@@ -2470,7 +2470,9 @@ THREE.SEA3D.prototype.readCubeMapURL = function ( sea ) {
 
 		this.file.resume = ! usePMREM;
 
-		texture = new THREE.HDRCubeTextureLoader().load( THREE.UnsignedByteType, faces, function ( texture ) {
+		texture = new THREE.HDRCubeTextureLoader()
+			.setType( THREE.UnsignedByteType )
+			.load( faces, function ( texture ) {
 
 			if ( usePMREM ) {
 

+ 5 - 5
examples/js/misc/GPUComputationRenderer.js

@@ -28,7 +28,7 @@
  * // Initialization...
  *
  * // Create computation renderer
- * var gpuCompute = new GPUComputationRenderer( 1024, 1024, renderer );
+ * var gpuCompute = new THREE.GPUComputationRenderer( 1024, 1024, renderer );
  *
  * // Create initial state float textures
  * var pos0 = gpuCompute.createTexture();
@@ -89,7 +89,7 @@
  * // And compute each frame, before rendering to screen:
  * gpuCompute.doRenderTarget( myFilter1, myRenderTarget );
  * gpuCompute.doRenderTarget( myFilter2, outputRenderTarget );
- * 
+ *
  *
  *
  * @param {int} sizeX Computation problem size is always 2d: sizeX * sizeY elements.
@@ -97,7 +97,7 @@
  * @param {WebGLRenderer} renderer The renderer
   */
 
-function GPUComputationRenderer( sizeX, sizeY, renderer ) {
+THREE.GPUComputationRenderer = function( sizeX, sizeY, renderer ) {
 
 	this.variables = [];
 
@@ -137,7 +137,7 @@ function GPUComputationRenderer( sizeX, sizeY, renderer ) {
 		this.variables.push( variable );
 
 		return variable;
-		
+
 	};
 
 	this.setVariableDependencies = function( variable, dependencies ) {
@@ -371,4 +371,4 @@ function GPUComputationRenderer( sizeX, sizeY, renderer ) {
 
 	}
 
-}
+};

+ 0 - 0
examples/js/Gyroscope.js → examples/js/misc/Gyroscope.js


+ 1 - 1
examples/js/MD2Character.js → examples/js/misc/MD2Character.js

@@ -46,7 +46,7 @@ THREE.MD2Character = function () {
 
 			var boundingBox = new THREE.Box3();
 			boundingBox.setFromBufferAttribute( geo.attributes.position );
-			
+
 			scope.root.position.y = - scope.scale * boundingBox.min.y;
 
 			var mesh = createPart( geo, scope.skinsBody[ 0 ] );

+ 9 - 9
examples/js/MD2CharacterComplex.js → examples/js/misc/MD2CharacterComplex.js

@@ -154,7 +154,7 @@ THREE.MD2CharacterComplex = function () {
 
 		var loader = new THREE.MD2Loader();
 
-		loader.load( config.baseUrl + config.body, function( geo ) {
+		loader.load( config.baseUrl + config.body, function ( geo ) {
 
 			var boundingBox = new THREE.Box3();
 			boundingBox.setFromBufferAttribute( geo.attributes.position );
@@ -177,7 +177,7 @@ THREE.MD2CharacterComplex = function () {
 
 		var generateCallback = function ( index, name ) {
 
-			return function( geo ) {
+			return function ( geo ) {
 
 				var mesh = createPart( geo, scope.skinsWeapon[ index ] );
 				mesh.scale.set( scope.scale, scope.scale, scope.scale );
@@ -193,7 +193,7 @@ THREE.MD2CharacterComplex = function () {
 
 				checkLoadingComplete();
 
-			}
+			};
 
 		};
 
@@ -228,7 +228,7 @@ THREE.MD2CharacterComplex = function () {
 
 	};
 
-	this.setSkin = function( index ) {
+	this.setSkin = function ( index ) {
 
 		if ( this.meshBody && this.meshBody.material.wireframe === false ) {
 
@@ -293,7 +293,7 @@ THREE.MD2CharacterComplex = function () {
 
 		if ( this.animations ) {
 
-			this.updateBehaviors( delta );
+			this.updateBehaviors();
 			this.updateAnimations( delta );
 
 		}
@@ -316,7 +316,7 @@ THREE.MD2CharacterComplex = function () {
 			this.meshBody.update( delta );
 
 			this.meshBody.setAnimationWeight( this.activeAnimation, mix );
-			this.meshBody.setAnimationWeight( this.oldAnimation,  1 - mix );
+			this.meshBody.setAnimationWeight( this.oldAnimation, 1 - mix );
 
 		}
 
@@ -325,13 +325,13 @@ THREE.MD2CharacterComplex = function () {
 			this.meshWeapon.update( delta );
 
 			this.meshWeapon.setAnimationWeight( this.activeAnimation, mix );
-			this.meshWeapon.setAnimationWeight( this.oldAnimation,  1 - mix );
+			this.meshWeapon.setAnimationWeight( this.oldAnimation, 1 - mix );
 
 		}
 
 	};
 
-	this.updateBehaviors = function ( delta ) {
+	this.updateBehaviors = function () {
 
 		var controls = this.controls;
 		var animations = this.animations;
@@ -451,7 +451,7 @@ THREE.MD2CharacterComplex = function () {
 
 		this.maxReverseSpeed = - this.maxSpeed;
 
-		if ( controls.moveForward )  this.speed = THREE.Math.clamp( this.speed + delta * this.frontAcceleration, this.maxReverseSpeed, this.maxSpeed );
+		if ( controls.moveForward ) this.speed = THREE.Math.clamp( this.speed + delta * this.frontAcceleration, this.maxReverseSpeed, this.maxSpeed );
 		if ( controls.moveBackward ) this.speed = THREE.Math.clamp( this.speed - delta * this.backAcceleration, this.maxReverseSpeed, this.maxSpeed );
 
 		// orientation based on controls

+ 0 - 0
examples/js/MorphBlendMesh.js → examples/js/misc/MorphBlendMesh.js


+ 0 - 1
examples/js/MarchingCubes.js → examples/js/objects/MarchingCubes.js

@@ -973,7 +973,6 @@ THREE.MarchingCubes = function ( resolution, material, enableUvs, enableColors )
 THREE.MarchingCubes.prototype = Object.create( THREE.ImmediateRenderObject.prototype );
 THREE.MarchingCubes.prototype.constructor = THREE.MarchingCubes;
 
-
 /////////////////////////////////////
 // Marching cubes lookup tables
 /////////////////////////////////////

+ 105 - 0
examples/jsm/geometries/LightningStrike.d.ts

@@ -0,0 +1,105 @@
+import {
+  Vector3
+} from '../../../src/Three';
+
+export interface RandomGenerator {
+  random(): number;
+  getSeed(): number;
+  setSeed(seed: number): void;
+}
+
+export interface LightningSegment {
+  iteration: number;
+  pos0: Vector3;
+  pos1: Vector3;
+  linPos0: Vector3;
+  linPos1: Vector3;
+  up0: Vector3;
+  up1: Vector3;
+  radius0: number;
+  radius1: number;
+  fraction0: number;
+  fraction1: number;
+  positionVariationFactor: number;
+}
+
+export interface LightningSubray {
+  seed: number;
+  maxIterations: number;
+  recursion: number;
+  pos0: Vector3;
+  pos1: Vector3;
+  linPos0: Vector3;
+  linPos1: Vector3;
+  up0: Vector3;
+  up1: Vector3;
+  radius0: number;
+  radius1: number;
+  birthTime: number;
+  deathTime: number;
+  timeScale: number;
+  roughness: number;
+  straightness: number;
+  propagationTimeFactor: number;
+  vanishingTimeFactor: number;
+  endPropagationTime: number;
+  beginVanishingTime: number;
+}
+
+export interface RayParameters {
+  sourceOffset?: Vector3;
+  destOffset?: Vector3;
+
+  timeScale?: number;
+  roughness?: number;
+  straightness?: number;
+
+  up0?: Vector3;
+  up1?: Vector3;
+  radius0?: number;
+  radius1?: number;
+  radius0Factor? : number;
+  radius1Factor? : number;
+  minRadius? : number;
+
+  isEternal?: boolean;
+  birthTime?: number;
+  deathTime?: number;
+  propagationTimeFactor?: number;
+  vanishingTimeFactor?: number;
+  subrayPeriod?: number;
+  subrayDutyCycle?: number;
+
+  maxIterations?: number;
+  isStatic?: boolean;
+  ramification?: number;
+  maxSubrayRecursion?: number;
+  recursionProbability?: number;
+  generateUVs?: boolean;
+
+  randomGenerator?: RandomGenerator;
+  noiseSeed?: number;
+
+  onDecideSubrayCreation?: (segment: LightningSegment, lightningStrike: LightningStrike) => void;
+  onSubrayCreation?: (segment: LightningSegment, parentSubray: LightningSubray, childSubray: LightningSubray, lightningStrike: LightningStrike) => void;
+}
+
+export class LightningStrike {
+  constructor(rayParameters?: RayParameters);
+  copyParameters( dest?: RayParameters, source?: RayParameters): RayParameters;
+
+  // Ray states
+  static readonly RAY_INITIALIZED: number;
+  static readonly RAY_UNBORN: number;
+  static readonly RAY_PROPAGATING: number;
+  static readonly RAY_STEADY: number;
+  static readonly RAY_VANISHING: number;
+  static readonly RAY_EXTINGUISHED: number;
+
+  state: number;
+
+  update(time: number): void;
+
+  copy(source: LightningStrike): LightningStrike;
+  clone(): LightningStrike;
+}

+ 1021 - 0
examples/jsm/geometries/LightningStrike.js

@@ -0,0 +1,1021 @@
+/**
+ * @author yomboprime https://github.com/yomboprime
+ *
+ * @fileoverview LightningStrike object for creating lightning strikes and voltaic arcs.
+ *
+ *
+ * Usage
+ *
+ * var myRay = new LightningStrike( paramsObject );
+ * var myRayMesh = new Mesh( myRay, myMaterial );
+ * scene.add( myRayMesh );
+ * ...
+ * myRay.update( currentTime );
+ *
+ * The "currentTime" can vary its rate, go forwards, backwards or even jump, but it cannot be negative.
+ *
+ * You should normally leave the ray position to (0, 0, 0). You should control it by changing the sourceOffset and destOffset parameters.
+ *
+ *
+ * LightningStrike parameters
+ *
+ * The paramsObject can contain any of the following parameters.
+ *
+ * Legend:
+ * 'LightningStrike' (also called 'ray'): An independent voltaic arc with its ramifications and defined with a set of parameters.
+ * 'Subray': A ramification of the ray. It is not a LightningStrike object.
+ * 'Segment': A linear segment piece of a subray.
+ * 'Leaf segment': A ray segment which cannot be smaller.
+ *
+ *
+ * The following parameters can be changed any time and if they vary smoothly, the ray form will also change smoothly:
+ *
+ * @param {Vector3} sourceOffset The point where the ray starts.
+ *
+ * @param {Vector3} destOffset The point where the ray ends.
+ *
+ * @param {double} timeScale The rate at wich the ray form changes in time. Default: 1
+ *
+ * @param {double} roughness From 0 to 1. The higher the value, the more wrinkled is the ray. Default: 0.9
+ *
+ * @param {double} straightness From 0 to 1. The higher the value, the more straight will be a subray path. Default: 0.7
+ *
+ * @param {Vector3} up0 Ray 'up' direction at the ray starting point. Must be normalized. It should be perpendicular to the ray forward direction but it doesn't matter much.
+ *
+ * @param {Vector3} up1 Like the up0 parameter but at the end of the ray. Must be normalized.
+ *
+ * @param {double} radius0 Radius of the main ray trunk at the start point. Default: 1
+ *
+ * @param {double} radius1 Radius of the main ray trunk at the end point. Default: 1
+ *
+ * @param {double} radius0Factor The radius0 of a subray is this factor times the radius0 of its parent subray. Default: 0.5
+ *
+ * @param {double} radius1Factor The radius1 of a subray is this factor times the radius1 of its parent subray. Default: 0.2
+ *
+ * @param {minRadius} Minimum value a subray radius0 or radius1 can get. Default: 0.1
+ *
+ *
+ * The following parameters should not be changed after lightning creation. They can be changed but the ray will change its form abruptly:
+ *
+ * @param {boolean} isEternal If true the ray never extinguishes. Otherwise its life is controlled by the 'birthTime' and 'deathTime' parameters. Default: true if any of those two parameters is undefined.
+ *
+ * @param {double} birthTime The time at which the ray starts its life and begins propagating. Only if isEternal is false. Default: None.
+ *
+ * @param {double} deathTime The time at which the ray ends vanishing and its life. Only if isEternal is false. Default: None.
+ *
+ * @param {double} propagationTimeFactor From 0 to 1. Lifetime factor at which the ray ends propagating and enters the steady phase. For example, 0.1 means it is propagating 1/10 of its lifetime. Default: 0.1
+ *
+ * @param {double} vanishingTimeFactor From 0 to 1. Lifetime factor at which the ray ends the steady phase and begins vanishing. For example, 0.9 means it is vanishing 1/10 of its lifetime. Default: 0.9
+ *
+ * @param {double} subrayPeriod Subrays cycle periodically. This is their time period. Default: 4
+ *
+ * @param {double} subrayDutyCycle From 0 to 1. This is the fraction of time a subray is active. Default: 0.6
+ *
+ *
+ * These parameters cannot change after lightning creation:
+ *
+ * @param {integer} maxIterations: Greater than 0. The number of ray's leaf segments is 2**maxIterations. Default: 9
+ *
+ * @param {boolean} isStatic Set to true only for rays which won't change over time and are not attached to moving objects (Rare case). It is used to set the vertex buffers non-dynamic. You can omit calling update() for these rays.
+ *
+ * @param {integer} ramification Greater than 0. Maximum number of child subrays a subray can have. Default: 5
+ *
+ * @param {integer} maxSubrayRecursion Greater than 0. Maximum level of recursion (subray descendant generations). Default: 3
+ *
+ * @param {double} recursionProbability From 0 to 1. The lower the value, the less chance each new generation of subrays has to generate new subrays. Default: 0.6
+ *
+ * @param {boolean} generateUVs If true, the ray geometry will have uv coordinates generated. u runs along the ray, and v across its perimeter. Default: false.
+ *
+ * @param {Object} randomGenerator Set here your random number generator which will seed the SimplexNoise and other decisions during ray tree creation.
+ * It can be used to generate repeatable rays. For that, set also the noiseSeed parameter, and each ray created with that generator and seed pair will be identical in time.
+ * The randomGenerator parameter should be an object with a random() function similar to Math.random, but seedable.
+ * It must have also a getSeed() method, which returns the current seed, and a setSeed( seed ) method, which accepts as seed a fractional number from 0 to 1, as well as any other number.
+ * The default value is an internal generator for some uses and Math.random for others (It is non-repeatable even if noiseSeed is supplied)
+ *
+ * @param {double} noiseSeed Seed used to make repeatable rays (see the randomGenerator)
+ *
+ * @param {function} onDecideSubrayCreation Set this to change the callback which decides subray creation. You can look at the default callback in the code (createDefaultSubrayCreationCallbacks)for more info.
+ *
+ * @param {function} onSubrayCreation This is another callback, more simple than the previous one. It can be used to adapt the form of subrays or other parameters once a subray has been created and initialized. It is used in the examples to adapt subrays to a sphere or to a plane.
+ *
+ *
+*/
+
+import {
+	BufferGeometry,
+	Float32BufferAttribute,
+	Math as _Math,
+	Mesh,
+	Uint32BufferAttribute,
+	Vector3
+} from "../../../build/three.module.js";
+import { SimplexNoise } from "../math/SimplexNoise.js";
+
+var LightningStrike = function ( rayParameters ) {
+
+	BufferGeometry.call( this );
+
+	this.type = 'LightningStrike';
+
+	// Set parameters, and set undefined parameters to default values
+	rayParameters = rayParameters || {};
+	this.init( LightningStrike.copyParameters( rayParameters, rayParameters ) );
+
+	// Creates and populates the mesh
+	this.createMesh();
+
+};
+
+LightningStrike.prototype = Object.create( BufferGeometry.prototype );
+
+LightningStrike.prototype.constructor = LightningStrike;
+
+LightningStrike.prototype.isLightningStrike = true;
+
+// Ray states
+LightningStrike.RAY_INITIALIZED = 0;
+LightningStrike.RAY_UNBORN = 1;
+LightningStrike.RAY_PROPAGATING = 2;
+LightningStrike.RAY_STEADY = 3;
+LightningStrike.RAY_VANISHING = 4;
+LightningStrike.RAY_EXTINGUISHED = 5;
+
+LightningStrike.COS30DEG = Math.cos( 30 * Math.PI / 180 );
+LightningStrike.SIN30DEG = Math.sin( 30 * Math.PI / 180 );
+
+LightningStrike.createRandomGenerator = function () {
+
+	var numSeeds = 2053;
+	var seeds = [];
+
+	for ( var i = 0; i < numSeeds; i ++ ) {
+
+		seeds.push( Math.random() );
+
+	}
+
+	var generator = {
+
+		currentSeed: 0,
+
+		random: function () {
+
+			var value = seeds[ generator.currentSeed ];
+
+			generator.currentSeed = ( generator.currentSeed + 1 ) % numSeeds;
+
+			return value;
+
+		},
+
+		getSeed: function () {
+
+			return generator.currentSeed / numSeeds;
+
+		},
+
+		setSeed: function ( seed ) {
+
+			generator.currentSeed = Math.floor( seed * numSeeds ) % numSeeds;
+
+		}
+
+	};
+
+	return generator;
+
+};
+
+LightningStrike.copyParameters = function ( dest, source ) {
+
+	source = source || {};
+	dest = dest || {};
+
+	var vecCopy = function ( v ) {
+
+		if ( source === dest ) {
+
+			return v;
+
+		} else {
+
+			return v.clone();
+
+		}
+
+	};
+
+	dest.sourceOffset = source.sourceOffset !== undefined ? vecCopy( source.sourceOffset ) : new Vector3( 0, 100, 0 ),
+	dest.destOffset = source.destOffset !== undefined ? vecCopy( source.destOffset ) : new Vector3( 0, 0, 0 ),
+
+	dest.timeScale = source.timeScale !== undefined ? source.timeScale : 1,
+	dest.roughness = source.roughness !== undefined ? source.roughness : 0.9,
+	dest.straightness = source.straightness !== undefined ? source.straightness : 0.7,
+
+	dest.up0 = source.up0 !== undefined ? vecCopy( source.up0 ) : new Vector3( 0, 0, 1 );
+	dest.up1 = source.up1 !== undefined ? vecCopy( source.up1 ) : new Vector3( 0, 0, 1 ),
+	dest.radius0 = source.radius0 !== undefined ? source.radius0 : 1,
+	dest.radius1 = source.radius1 !== undefined ? source.radius1 : 1,
+	dest.radius0Factor = source.radius0Factor !== undefined ? source.radius0Factor : 0.5,
+	dest.radius1Factor = source.radius1Factor !== undefined ? source.radius1Factor : 0.2,
+	dest.minRadius = source.minRadius !== undefined ? source.minRadius : 0.2,
+
+	// These parameters should not be changed after lightning creation. They can be changed but the ray will change its form abruptly:
+
+	dest.isEternal = source.isEternal !== undefined ? source.isEternal : ( source.birthTime === undefined || source.deathTime === undefined ),
+	dest.birthTime = source.birthTime,
+	dest.deathTime = source.deathTime,
+	dest.propagationTimeFactor = source.propagationTimeFactor !== undefined ? source.propagationTimeFactor : 0.1,
+	dest.vanishingTimeFactor = source.vanishingTimeFactor !== undefined ? source.vanishingTimeFactor : 0.9,
+	dest.subrayPeriod = source.subrayPeriod !== undefined ? source.subrayPeriod : 4,
+	dest.subrayDutyCycle = source.subrayDutyCycle !== undefined ? source.subrayDutyCycle : 0.6;
+
+	// These parameters cannot change after lightning creation:
+
+	dest.maxIterations = source.maxIterations !== undefined ? source.maxIterations : 9;
+	dest.isStatic = source.isStatic !== undefined ? source.isStatic : false;
+	dest.ramification = source.ramification !== undefined ? source.ramification : 5;
+	dest.maxSubrayRecursion = source.maxSubrayRecursion !== undefined ? source.maxSubrayRecursion : 3;
+	dest.recursionProbability = source.recursionProbability !== undefined ? source.recursionProbability : 0.6;
+	dest.generateUVs = source.generateUVs !== undefined ? source.generateUVs : false;
+	dest.randomGenerator = source.randomGenerator,
+	dest.noiseSeed = source.noiseSeed,
+	dest.onDecideSubrayCreation = source.onDecideSubrayCreation,
+	dest.onSubrayCreation = source.onSubrayCreation;
+
+	return dest;
+
+};
+
+LightningStrike.prototype.update = function ( time ) {
+
+	if ( this.isStatic ) return;
+
+	if ( this.rayParameters.isEternal || ( this.rayParameters.birthTime <= time && time <= this.rayParameters.deathTime ) ) {
+
+		this.updateMesh( time );
+
+		if ( time < this.subrays[ 0 ].endPropagationTime ) {
+
+			this.state = LightningStrike.RAY_PROPAGATING;
+
+		} else if ( time > this.subrays[ 0 ].beginVanishingTime ) {
+
+			this.state = LightningStrike.RAY_VANISHING;
+
+		} else {
+
+			this.state = LightningStrike.RAY_STEADY;
+
+		}
+
+		this.visible = true;
+
+	} else {
+
+		this.visible = false;
+
+		if ( time < this.rayParameters.birthTime ) {
+
+			this.state = LightningStrike.RAY_UNBORN;
+
+		} else {
+
+			this.state = LightningStrike.RAY_EXTINGUISHED;
+
+		}
+
+	}
+
+};
+
+LightningStrike.prototype.init = function ( rayParameters ) {
+
+	// Init all the state from the parameters
+
+	this.rayParameters = rayParameters;
+
+	// These parameters cannot change after lightning creation:
+
+	this.maxIterations = rayParameters.maxIterations !== undefined ? Math.floor( rayParameters.maxIterations ) : 9;
+	rayParameters.maxIterations = this.maxIterations;
+	this.isStatic = rayParameters.isStatic !== undefined ? rayParameters.isStatic : false;
+	rayParameters.isStatic = this.isStatic;
+	this.ramification = rayParameters.ramification !== undefined ? Math.floor( rayParameters.ramification ) : 5;
+	rayParameters.ramification = this.ramification;
+	this.maxSubrayRecursion = rayParameters.maxSubrayRecursion !== undefined ? Math.floor( rayParameters.maxSubrayRecursion ) : 3;
+	rayParameters.maxSubrayRecursion = this.maxSubrayRecursion;
+	this.recursionProbability = rayParameters.recursionProbability !== undefined ? rayParameters.recursionProbability : 0.6;
+	rayParameters.recursionProbability = this.recursionProbability;
+	this.generateUVs = rayParameters.generateUVs !== undefined ? rayParameters.generateUVs : false;
+	rayParameters.generateUVs = this.generateUVs;
+
+	// Random generator
+	if ( rayParameters.randomGenerator !== undefined ) {
+
+		this.randomGenerator = rayParameters.randomGenerator;
+		this.seedGenerator = rayParameters.randomGenerator;
+
+		if ( rayParameters.noiseSeed !== undefined ) {
+
+			this.seedGenerator.setSeed( rayParameters.noiseSeed );
+
+		}
+
+	} else {
+
+		this.randomGenerator = LightningStrike.createRandomGenerator();
+		this.seedGenerator = Math;
+
+	}
+
+	// Ray creation callbacks
+	if ( rayParameters.onDecideSubrayCreation !== undefined ) {
+
+		this.onDecideSubrayCreation = rayParameters.onDecideSubrayCreation;
+
+	} else {
+
+		this.createDefaultSubrayCreationCallbacks();
+
+		if ( rayParameters.onSubrayCreation !== undefined ) {
+
+			this.onSubrayCreation = rayParameters.onSubrayCreation;
+
+		}
+
+	}
+
+	// Internal state
+
+	this.state = LightningStrike.RAY_INITIALIZED;
+
+	this.maxSubrays = Math.ceil( 1 + Math.pow( this.ramification, Math.max( 0, this.maxSubrayRecursion - 1 ) ) );
+	rayParameters.maxSubrays = this.maxSubrays;
+
+	this.maxRaySegments = 2 * ( 1 << this.maxIterations );
+
+	this.subrays = [];
+
+	for ( var i = 0; i < this.maxSubrays; i ++ ) {
+
+		this.subrays.push( this.createSubray() );
+
+	}
+
+	this.raySegments = [];
+
+	for ( var i = 0; i < this.maxRaySegments; i ++ ) {
+
+		this.raySegments.push( this.createSegment() );
+
+	}
+
+	this.time = 0;
+	this.timeFraction = 0;
+	this.currentSegmentCallback = null;
+	this.currentCreateTriangleVertices = this.generateUVs ? this.createTriangleVerticesWithUVs : this.createTriangleVerticesWithoutUVs;
+	this.numSubrays = 0;
+	this.currentSubray = null;
+	this.currentSegmentIndex = 0;
+	this.isInitialSegment = false;
+	this.subrayProbability = 0;
+
+	this.currentVertex = 0;
+	this.currentIndex = 0;
+	this.currentCoordinate = 0;
+	this.currentUVCoordinate = 0;
+	this.vertices = null;
+	this.uvs = null;
+	this.indices = null;
+	this.positionAttribute = null;
+	this.uvsAttribute = null;
+
+	this.simplexX = new SimplexNoise( this.seedGenerator );
+	this.simplexY = new SimplexNoise( this.seedGenerator );
+	this.simplexZ = new SimplexNoise( this.seedGenerator );
+
+	// Temp vectors
+	this.forwards = new Vector3();
+	this.forwardsFill = new Vector3();
+	this.side = new Vector3();
+	this.down = new Vector3();
+	this.middlePos = new Vector3();
+	this.middleLinPos = new Vector3();
+	this.newPos = new Vector3();
+	this.vPos = new Vector3();
+	this.cross1 = new Vector3();
+
+};
+
+LightningStrike.prototype.createMesh = function () {
+
+	var maxDrawableSegmentsPerSubRay = 1 << this.maxIterations;
+
+	var maxVerts = 3 * ( maxDrawableSegmentsPerSubRay + 1 ) * this.maxSubrays;
+	var maxIndices = 18 * maxDrawableSegmentsPerSubRay * this.maxSubrays;
+
+	this.vertices = new Float32Array( maxVerts * 3 );
+	this.indices = new Uint32Array( maxIndices );
+	if ( this.generateUVs ) {
+
+		this.uvs = new Float32Array( maxVerts * 2 );
+
+	}
+
+	// Populate the mesh
+	this.fillMesh( 0 );
+
+	this.setIndex( new Uint32BufferAttribute( this.indices, 1 ) );
+
+	this.positionAttribute = new Float32BufferAttribute( this.vertices, 3 );
+	this.addAttribute( 'position', this.positionAttribute );
+
+	if ( this.generateUVs ) {
+
+		this.uvsAttribute = new Float32BufferAttribute( new Float32Array( this.uvs ), 2 );
+		this.addAttribute( 'uv', this.uvsAttribute );
+
+	}
+
+	if ( ! this.isStatic ) {
+
+		this.index.dynamic = true;
+		this.positionAttribute.dynamic = true;
+		if ( this.generateUVs ) {
+
+			this.uvsAttribute.dynamic = true;
+
+		}
+
+	}
+
+	// Store buffers for later modification
+	this.vertices = this.positionAttribute.array;
+	this.indices = this.index.array;
+	if ( this.generateUVs ) {
+
+		this.uvs = this.uvsAttribute.array;
+
+	}
+
+};
+
+LightningStrike.prototype.updateMesh = function ( time ) {
+
+	this.fillMesh( time );
+
+	this.drawRange.count = this.currentIndex;
+
+	this.index.needsUpdate = true;
+
+	this.positionAttribute.needsUpdate = true;
+
+	if ( this.generateUVs ) {
+
+		this.uvsAttribute.needsUpdate = true;
+
+	}
+
+};
+
+LightningStrike.prototype.fillMesh = function ( time ) {
+
+	var scope = this;
+
+	this.currentVertex = 0;
+	this.currentIndex = 0;
+	this.currentCoordinate = 0;
+	this.currentUVCoordinate = 0;
+
+	this.fractalRay( time, function fillVertices( segment ) {
+
+		var subray = scope.currentSubray;
+
+		if ( time < subray.birthTime ) { //&& ( ! this.rayParameters.isEternal || scope.currentSubray.recursion > 0 ) ) {
+
+			return;
+
+		} else if ( this.rayParameters.isEternal && scope.currentSubray.recursion == 0 ) {
+
+			// Eternal rays don't propagate nor vanish, but its subrays do
+
+			scope.createPrism( segment );
+
+			scope.onDecideSubrayCreation( segment, scope );
+
+		} else if ( time < subray.endPropagationTime ) {
+
+			if ( scope.timeFraction >= segment.fraction0 * subray.propagationTimeFactor ) {
+
+				// Ray propagation has arrived to this segment
+
+				scope.createPrism( segment );
+
+				scope.onDecideSubrayCreation( segment, scope );
+
+			}
+
+		} else if ( time < subray.beginVanishingTime ) {
+
+			// Ray is steady (nor propagating nor vanishing)
+
+			scope.createPrism( segment );
+
+			scope.onDecideSubrayCreation( segment, scope );
+
+		} else {
+
+			if ( scope.timeFraction <= subray.vanishingTimeFactor + segment.fraction1 * ( 1 - subray.vanishingTimeFactor ) ) {
+
+				// Segment has not yet vanished
+
+				scope.createPrism( segment );
+
+			}
+
+			scope.onDecideSubrayCreation( segment, scope );
+
+		}
+
+	} );
+
+};
+
+LightningStrike.prototype.addNewSubray = function ( rayParameters ) {
+
+	return this.subrays[ this.numSubrays ++ ];
+
+};
+
+LightningStrike.prototype.initSubray = function ( subray, rayParameters ) {
+
+	subray.pos0.copy( rayParameters.sourceOffset );
+	subray.pos1.copy( rayParameters.destOffset );
+	subray.up0.copy( rayParameters.up0 );
+	subray.up1.copy( rayParameters.up1 );
+	subray.radius0 = rayParameters.radius0;
+	subray.radius1 = rayParameters.radius1;
+	subray.birthTime = rayParameters.birthTime;
+	subray.deathTime = rayParameters.deathTime;
+	subray.timeScale = rayParameters.timeScale;
+	subray.roughness = rayParameters.roughness;
+	subray.straightness = rayParameters.straightness;
+	subray.propagationTimeFactor = rayParameters.propagationTimeFactor;
+	subray.vanishingTimeFactor = rayParameters.vanishingTimeFactor;
+
+	subray.maxIterations = this.maxIterations;
+	subray.seed = rayParameters.noiseSeed !== undefined ? rayParameters.noiseSeed : 0;
+	subray.recursion = 0;
+
+};
+
+LightningStrike.prototype.fractalRay = function ( time, segmentCallback ) {
+
+	this.time = time;
+	this.currentSegmentCallback = segmentCallback;
+	this.numSubrays = 0;
+
+	// Add the top level subray
+	this.initSubray( this.addNewSubray(), this.rayParameters );
+
+	// Process all subrays that are being generated until consuming all of them
+	for ( var subrayIndex = 0; subrayIndex < this.numSubrays; subrayIndex ++ ) {
+
+		var subray = this.subrays[ subrayIndex ];
+		this.currentSubray = subray;
+
+		this.randomGenerator.setSeed( subray.seed );
+
+		subray.endPropagationTime = _Math.lerp( subray.birthTime, subray.deathTime, subray.propagationTimeFactor );
+		subray.beginVanishingTime = _Math.lerp( subray.deathTime, subray.birthTime, 1 - subray.vanishingTimeFactor );
+
+		var random1 = this.randomGenerator.random;
+		subray.linPos0.set( random1(), random1(), random1() ).multiplyScalar( 1000 );
+		subray.linPos1.set( random1(), random1(), random1() ).multiplyScalar( 1000 );
+
+		this.timeFraction = ( time - subray.birthTime ) / ( subray.deathTime - subray.birthTime );
+
+		this.currentSegmentIndex = 0;
+		this.isInitialSegment = true;
+
+		var segment = this.getNewSegment();
+		segment.iteration = 0;
+		segment.pos0.copy( subray.pos0 );
+		segment.pos1.copy( subray.pos1 );
+		segment.linPos0.copy( subray.linPos0 );
+		segment.linPos1.copy( subray.linPos1 );
+		segment.up0.copy( subray.up0 );
+		segment.up1.copy( subray.up1 );
+		segment.radius0 = subray.radius0;
+		segment.radius1 = subray.radius1;
+		segment.fraction0 = 0;
+		segment.fraction1 = 1;
+		segment.positionVariationFactor = 1 - subray.straightness;
+
+		this.subrayProbability = this.ramification * Math.pow( this.recursionProbability, subray.recursion ) / ( 1 << subray.maxIterations );
+
+		this.fractalRayRecursive( segment );
+
+	}
+
+	this.currentSegmentCallback = null;
+	this.currentSubray = null;
+
+};
+
+LightningStrike.prototype.fractalRayRecursive = function ( segment ) {
+
+	// Leave recursion condition
+	if ( segment.iteration >= this.currentSubray.maxIterations ) {
+
+		this.currentSegmentCallback( segment );
+
+		return;
+
+	}
+
+	// Interpolation
+	this.forwards.subVectors( segment.pos1, segment.pos0 );
+	var lForwards = this.forwards.length();
+
+	if ( lForwards < 0.000001 ) {
+
+		this.forwards.set( 0, 0, 0.01 );
+		lForwards = this.forwards.length();
+
+	}
+
+	var middleRadius = ( segment.radius0 + segment.radius1 ) * 0.5;
+	var middleFraction = ( segment.fraction0 + segment.fraction1 ) * 0.5;
+
+	var timeDimension = this.time * this.currentSubray.timeScale * Math.pow( 2, segment.iteration );
+
+	this.middlePos.lerpVectors( segment.pos0, segment.pos1, 0.5 );
+	this.middleLinPos.lerpVectors( segment.linPos0, segment.linPos1, 0.5 );
+	var p = this.middleLinPos;
+
+	// Noise
+	this.newPos.set( this.simplexX.noise4d( p.x, p.y, p.z, timeDimension ),
+		this.simplexY.noise4d( p.x, p.y, p.z, timeDimension ),
+		this.simplexZ.noise4d( p.x, p.y, p.z, timeDimension ) );
+
+	this.newPos.multiplyScalar( segment.positionVariationFactor * lForwards );
+	this.newPos.add( this.middlePos );
+
+	// Recursion
+
+	var newSegment1 = this.getNewSegment();
+	newSegment1.pos0.copy( segment.pos0 );
+	newSegment1.pos1.copy( this.newPos );
+	newSegment1.linPos0.copy( segment.linPos0 );
+	newSegment1.linPos1.copy( this.middleLinPos );
+	newSegment1.up0.copy( segment.up0 );
+	newSegment1.up1.copy( segment.up1 );
+	newSegment1.radius0 = segment.radius0;
+	newSegment1.radius1 = middleRadius;
+	newSegment1.fraction0 = segment.fraction0;
+	newSegment1.fraction1 = middleFraction;
+	newSegment1.positionVariationFactor = segment.positionVariationFactor * this.currentSubray.roughness;
+	newSegment1.iteration = segment.iteration + 1;
+
+	var newSegment2 = this.getNewSegment();
+	newSegment2.pos0.copy( this.newPos );
+	newSegment2.pos1.copy( segment.pos1 );
+	newSegment2.linPos0.copy( this.middleLinPos );
+	newSegment2.linPos1.copy( segment.linPos1 );
+	this.cross1.crossVectors( segment.up0, this.forwards.normalize() );
+	newSegment2.up0.crossVectors( this.forwards, this.cross1 ).normalize();
+	newSegment2.up1.copy( segment.up1 );
+	newSegment2.radius0 = middleRadius;
+	newSegment2.radius1 = segment.radius1;
+	newSegment2.fraction0 = middleFraction;
+	newSegment2.fraction1 = segment.fraction1;
+	newSegment2.positionVariationFactor = segment.positionVariationFactor * this.currentSubray.roughness;
+	newSegment2.iteration = segment.iteration + 1;
+
+	this.fractalRayRecursive( newSegment1 );
+
+	this.fractalRayRecursive( newSegment2 );
+
+};
+
+LightningStrike.prototype.createPrism = function ( segment ) {
+
+	// Creates one triangular prism and its vertices at the segment
+
+	this.forwardsFill.subVectors( segment.pos1, segment.pos0 ).normalize();
+
+	if ( this.isInitialSegment ) {
+
+		this.currentCreateTriangleVertices( segment.pos0, segment.up0, this.forwardsFill, segment.radius0, 0 );
+
+		this.isInitialSegment = false;
+
+	}
+
+	this.currentCreateTriangleVertices( segment.pos1, segment.up0, this.forwardsFill, segment.radius1, segment.fraction1 );
+
+	this.createPrismFaces();
+
+};
+
+LightningStrike.prototype.createTriangleVerticesWithoutUVs = function ( pos, up, forwards, radius ) {
+
+	// Create an equilateral triangle (only vertices)
+
+	this.side.crossVectors( up, forwards ).multiplyScalar( radius * LightningStrike.COS30DEG );
+	this.down.copy( up ).multiplyScalar( - radius * LightningStrike.SIN30DEG );
+
+	var p = this.vPos;
+	var v = this.vertices;
+
+	p.copy( pos ).sub( this.side ).add( this.down );
+
+	v[ this.currentCoordinate ++ ] = p.x;
+	v[ this.currentCoordinate ++ ] = p.y;
+	v[ this.currentCoordinate ++ ] = p.z;
+
+	p.copy( pos ).add( this.side ).add( this.down );
+
+	v[ this.currentCoordinate ++ ] = p.x;
+	v[ this.currentCoordinate ++ ] = p.y;
+	v[ this.currentCoordinate ++ ] = p.z;
+
+	p.copy( up ).multiplyScalar( radius ).add( pos );
+
+	v[ this.currentCoordinate ++ ] = p.x;
+	v[ this.currentCoordinate ++ ] = p.y;
+	v[ this.currentCoordinate ++ ] = p.z;
+
+	this.currentVertex += 3;
+
+};
+
+LightningStrike.prototype.createTriangleVerticesWithUVs = function ( pos, up, forwards, radius, u ) {
+
+	// Create an equilateral triangle (only vertices)
+
+	this.side.crossVectors( up, forwards ).multiplyScalar( radius * LightningStrike.COS30DEG );
+	this.down.copy( up ).multiplyScalar( - radius * LightningStrike.SIN30DEG );
+
+	var p = this.vPos;
+	var v = this.vertices;
+	var uv = this.uvs;
+
+	p.copy( pos ).sub( this.side ).add( this.down );
+
+	v[ this.currentCoordinate ++ ] = p.x;
+	v[ this.currentCoordinate ++ ] = p.y;
+	v[ this.currentCoordinate ++ ] = p.z;
+
+	uv[ this.currentUVCoordinate ++ ] = u;
+	uv[ this.currentUVCoordinate ++ ] = 0;
+
+	p.copy( pos ).add( this.side ).add( this.down );
+
+	v[ this.currentCoordinate ++ ] = p.x;
+	v[ this.currentCoordinate ++ ] = p.y;
+	v[ this.currentCoordinate ++ ] = p.z;
+
+	uv[ this.currentUVCoordinate ++ ] = u;
+	uv[ this.currentUVCoordinate ++ ] = 0.5;
+
+	p.copy( up ).multiplyScalar( radius ).add( pos );
+
+	v[ this.currentCoordinate ++ ] = p.x;
+	v[ this.currentCoordinate ++ ] = p.y;
+	v[ this.currentCoordinate ++ ] = p.z;
+
+	uv[ this.currentUVCoordinate ++ ] = u;
+	uv[ this.currentUVCoordinate ++ ] = 1;
+
+	this.currentVertex += 3;
+
+};
+
+LightningStrike.prototype.createPrismFaces = function ( vertex, index ) {
+
+	var indices = this.indices;
+	var vertex = this.currentVertex - 6;
+
+	indices[ this.currentIndex ++ ] = vertex + 1;
+	indices[ this.currentIndex ++ ] = vertex + 2;
+	indices[ this.currentIndex ++ ] = vertex + 5;
+	indices[ this.currentIndex ++ ] = vertex + 1;
+	indices[ this.currentIndex ++ ] = vertex + 5;
+	indices[ this.currentIndex ++ ] = vertex + 4;
+	indices[ this.currentIndex ++ ] = vertex + 0;
+	indices[ this.currentIndex ++ ] = vertex + 1;
+	indices[ this.currentIndex ++ ] = vertex + 4;
+	indices[ this.currentIndex ++ ] = vertex + 0;
+	indices[ this.currentIndex ++ ] = vertex + 4;
+	indices[ this.currentIndex ++ ] = vertex + 3;
+	indices[ this.currentIndex ++ ] = vertex + 2;
+	indices[ this.currentIndex ++ ] = vertex + 0;
+	indices[ this.currentIndex ++ ] = vertex + 3;
+	indices[ this.currentIndex ++ ] = vertex + 2;
+	indices[ this.currentIndex ++ ] = vertex + 3;
+	indices[ this.currentIndex ++ ] = vertex + 5;
+
+};
+
+LightningStrike.prototype.createDefaultSubrayCreationCallbacks = function () {
+
+	var random1 = this.randomGenerator.random;
+
+	this.onDecideSubrayCreation = function ( segment, lightningStrike ) {
+
+		// Decide subrays creation at parent (sub)ray segment
+
+		var subray = lightningStrike.currentSubray;
+
+		var period = lightningStrike.rayParameters.subrayPeriod;
+		var dutyCycle = lightningStrike.rayParameters.subrayDutyCycle;
+
+		var phase0 = ( lightningStrike.rayParameters.isEternal && subray.recursion == 0 ) ? - random1() * period : _Math.lerp( subray.birthTime, subray.endPropagationTime, segment.fraction0 ) - random1() * period;
+
+		var phase = lightningStrike.time - phase0;
+		var currentCycle = Math.floor( phase / period );
+
+		var childSubraySeed = random1() * ( currentCycle + 1 );
+
+		var isActive = phase % period <= dutyCycle * period;
+
+		probability = lightningStrike.subrayProbability;
+		var probability = 0;
+
+		if ( isActive ) {
+
+			probability = lightningStrike.subrayProbability;
+			// Distribution test: probability *= segment.fraction0 > 0.5 && segment.fraction0 < 0.9 ? 1 / 0.4 : 0;
+
+		}
+
+		if ( subray.recursion < lightningStrike.maxSubrayRecursion && lightningStrike.numSubrays < lightningStrike.maxSubrays && random1() < probability ) {
+
+			var childSubray = lightningStrike.addNewSubray();
+
+			var parentSeed = lightningStrike.randomGenerator.getSeed();
+			childSubray.seed = childSubraySeed;
+			lightningStrike.randomGenerator.setSeed( childSubraySeed );
+
+			childSubray.recursion = subray.recursion + 1;
+			childSubray.maxIterations = Math.max( 1, subray.maxIterations - 1 );
+
+			childSubray.linPos0.set( random1(), random1(), random1() ).multiplyScalar( 1000 );
+			childSubray.linPos1.set( random1(), random1(), random1() ).multiplyScalar( 1000 );
+			childSubray.up0.copy( subray.up0 );
+			childSubray.up1.copy( subray.up1 );
+			childSubray.radius0 = segment.radius0 * lightningStrike.rayParameters.radius0Factor;
+			childSubray.radius1 = Math.min( lightningStrike.rayParameters.minRadius, segment.radius1 * lightningStrike.rayParameters.radius1Factor );
+
+			childSubray.birthTime = phase0 + ( currentCycle ) * period;
+			childSubray.deathTime = childSubray.birthTime + period * dutyCycle;
+
+			if ( ! lightningStrike.rayParameters.isEternal && subray.recursion == 0 ) {
+
+				childSubray.birthTime = Math.max( childSubray.birthTime, subray.birthTime );
+				childSubray.deathTime = Math.min( childSubray.deathTime, subray.deathTime );
+
+			}
+
+			childSubray.timeScale = subray.timeScale * 2;
+			childSubray.roughness = subray.roughness;
+			childSubray.straightness = subray.straightness;
+			childSubray.propagationTimeFactor = subray.propagationTimeFactor;
+			childSubray.vanishingTimeFactor = subray.vanishingTimeFactor;
+
+			lightningStrike.onSubrayCreation( segment, subray, childSubray, lightningStrike );
+
+			lightningStrike.randomGenerator.setSeed( parentSeed );
+
+		}
+
+	};
+
+	var vec1Pos = new Vector3();
+	var vec2Forward = new Vector3();
+	var vec3Side = new Vector3();
+	var vec4Up = new Vector3();
+
+	this.onSubrayCreation = function ( segment, parentSubray, childSubray, lightningStrike ) {
+
+		// Decide childSubray origin and destination positions (pos0 and pos1) and possibly other properties of childSubray
+
+		// Just use the default cone position generator
+		lightningStrike.subrayCylinderPosition( segment, parentSubray, childSubray, 0.5, 0.6, 0.2 );
+
+	};
+
+	this.subrayConePosition = function ( segment, parentSubray, childSubray, heightFactor, sideWidthFactor, minSideWidthFactor ) {
+
+		// Sets childSubray pos0 and pos1 in a cone
+
+		childSubray.pos0.copy( segment.pos0 );
+
+		vec1Pos.subVectors( parentSubray.pos1, parentSubray.pos0 );
+		vec2Forward.copy( vec1Pos ).normalize();
+		vec1Pos.multiplyScalar( segment.fraction0 + ( 1 - segment.fraction0 ) * ( random1() * heightFactor ) );
+		var length = vec1Pos.length();
+		vec3Side.crossVectors( parentSubray.up0, vec2Forward );
+		var angle = 2 * Math.PI * random1();
+		vec3Side.multiplyScalar( Math.cos( angle ) );
+		vec4Up.copy( parentSubray.up0 ).multiplyScalar( Math.sin( angle ) );
+
+		childSubray.pos1.copy( vec3Side ).add( vec4Up ).multiplyScalar( length * sideWidthFactor * ( minSideWidthFactor + random1() * ( 1 - minSideWidthFactor ) ) ).add( vec1Pos ).add( parentSubray.pos0 );
+
+	};
+
+	this.subrayCylinderPosition = function ( segment, parentSubray, childSubray, heightFactor, sideWidthFactor, minSideWidthFactor ) {
+
+		// Sets childSubray pos0 and pos1 in a cylinder
+
+		childSubray.pos0.copy( segment.pos0 );
+
+		vec1Pos.subVectors( parentSubray.pos1, parentSubray.pos0 );
+		vec2Forward.copy( vec1Pos ).normalize();
+		vec1Pos.multiplyScalar( segment.fraction0 + ( 1 - segment.fraction0 ) * ( ( 2 * random1() - 1 ) * heightFactor ) );
+		var length = vec1Pos.length();
+		vec3Side.crossVectors( parentSubray.up0, vec2Forward );
+		var angle = 2 * Math.PI * random1();
+		vec3Side.multiplyScalar( Math.cos( angle ) );
+		vec4Up.copy( parentSubray.up0 ).multiplyScalar( Math.sin( angle ) );
+
+		childSubray.pos1.copy( vec3Side ).add( vec4Up ).multiplyScalar( length * sideWidthFactor * ( minSideWidthFactor + random1() * ( 1 - minSideWidthFactor ) ) ).add( vec1Pos ).add( parentSubray.pos0 );
+
+	};
+
+};
+
+LightningStrike.prototype.createSubray = function () {
+
+	return {
+
+		seed: 0,
+		maxIterations: 0,
+		recursion: 0,
+		pos0: new Vector3(),
+		pos1: new Vector3(),
+		linPos0: new Vector3(),
+		linPos1: new Vector3(),
+		up0: new Vector3(),
+		up1: new Vector3(),
+		radius0: 0,
+		radius1: 0,
+		birthTime: 0,
+		deathTime: 0,
+		timeScale: 0,
+		roughness: 0,
+		straightness: 0,
+		propagationTimeFactor: 0,
+		vanishingTimeFactor: 0,
+		endPropagationTime: 0,
+		beginVanishingTime: 0
+
+	};
+
+};
+
+LightningStrike.prototype.createSegment = function () {
+
+	return {
+		iteration: 0,
+		pos0: new Vector3(),
+		pos1: new Vector3(),
+		linPos0: new Vector3(),
+		linPos1: new Vector3(),
+		up0: new Vector3(),
+		up1: new Vector3(),
+		radius0: 0,
+		radius1: 0,
+		fraction0: 0,
+		fraction1: 0,
+		positionVariationFactor: 0
+	};
+
+};
+
+LightningStrike.prototype.getNewSegment = function () {
+
+	return this.raySegments[ this.currentSegmentIndex ++ ];
+
+};
+
+LightningStrike.prototype.copy = function ( source ) {
+
+	BufferGeometry.prototype.copy.call( this, source );
+
+	this.init( LightningStrike.copyParameters( {}, source.rayParameters ) );
+
+	return this;
+
+};
+
+LightningStrike.prototype.clone = function () {
+
+	return new this.constructor( LightningStrike.copyParameters( {}, this.rayParameters ) );
+
+};
+
+export { LightningStrike };

+ 17 - 0
examples/jsm/libs/inflate.min.js

@@ -0,0 +1,17 @@
+/** @license zlib.js 2012 - imaya [ https://github.com/imaya/zlib.js ] The MIT License */var mod={}, l=void 0,aa=mod;function r(c,d){var a=c.split("."),b=aa;!(a[0]in b)&&b.execScript&&b.execScript("var "+a[0]);for(var e;a.length&&(e=a.shift());)!a.length&&d!==l?b[e]=d:b=b[e]?b[e]:b[e]={}};var t="undefined"!==typeof Uint8Array&&"undefined"!==typeof Uint16Array&&"undefined"!==typeof Uint32Array&&"undefined"!==typeof DataView;function v(c){var d=c.length,a=0,b=Number.POSITIVE_INFINITY,e,f,g,h,k,m,n,p,s,x;for(p=0;p<d;++p)c[p]>a&&(a=c[p]),c[p]<b&&(b=c[p]);e=1<<a;f=new (t?Uint32Array:Array)(e);g=1;h=0;for(k=2;g<=a;){for(p=0;p<d;++p)if(c[p]===g){m=0;n=h;for(s=0;s<g;++s)m=m<<1|n&1,n>>=1;x=g<<16|p;for(s=m;s<e;s+=k)f[s]=x;++h}++g;h<<=1;k<<=1}return[f,a,b]};function w(c,d){this.g=[];this.h=32768;this.d=this.f=this.a=this.l=0;this.input=t?new Uint8Array(c):c;this.m=!1;this.i=y;this.r=!1;if(d||!(d={}))d.index&&(this.a=d.index),d.bufferSize&&(this.h=d.bufferSize),d.bufferType&&(this.i=d.bufferType),d.resize&&(this.r=d.resize);switch(this.i){case A:this.b=32768;this.c=new (t?Uint8Array:Array)(32768+this.h+258);break;case y:this.b=0;this.c=new (t?Uint8Array:Array)(this.h);this.e=this.z;this.n=this.v;this.j=this.w;break;default:throw Error("invalid inflate mode");
+}}var A=0,y=1,B={t:A,s:y};
+w.prototype.k=function(){for(;!this.m;){var c=C(this,3);c&1&&(this.m=!0);c>>>=1;switch(c){case 0:var d=this.input,a=this.a,b=this.c,e=this.b,f=d.length,g=l,h=l,k=b.length,m=l;this.d=this.f=0;if(a+1>=f)throw Error("invalid uncompressed block header: LEN");g=d[a++]|d[a++]<<8;if(a+1>=f)throw Error("invalid uncompressed block header: NLEN");h=d[a++]|d[a++]<<8;if(g===~h)throw Error("invalid uncompressed block header: length verify");if(a+g>d.length)throw Error("input buffer is broken");switch(this.i){case A:for(;e+
+g>b.length;){m=k-e;g-=m;if(t)b.set(d.subarray(a,a+m),e),e+=m,a+=m;else for(;m--;)b[e++]=d[a++];this.b=e;b=this.e();e=this.b}break;case y:for(;e+g>b.length;)b=this.e({p:2});break;default:throw Error("invalid inflate mode");}if(t)b.set(d.subarray(a,a+g),e),e+=g,a+=g;else for(;g--;)b[e++]=d[a++];this.a=a;this.b=e;this.c=b;break;case 1:this.j(ba,ca);break;case 2:for(var n=C(this,5)+257,p=C(this,5)+1,s=C(this,4)+4,x=new (t?Uint8Array:Array)(D.length),S=l,T=l,U=l,u=l,M=l,F=l,z=l,q=l,V=l,q=0;q<s;++q)x[D[q]]=
+C(this,3);if(!t){q=s;for(s=x.length;q<s;++q)x[D[q]]=0}S=v(x);u=new (t?Uint8Array:Array)(n+p);q=0;for(V=n+p;q<V;)switch(M=E(this,S),M){case 16:for(z=3+C(this,2);z--;)u[q++]=F;break;case 17:for(z=3+C(this,3);z--;)u[q++]=0;F=0;break;case 18:for(z=11+C(this,7);z--;)u[q++]=0;F=0;break;default:F=u[q++]=M}T=t?v(u.subarray(0,n)):v(u.slice(0,n));U=t?v(u.subarray(n)):v(u.slice(n));this.j(T,U);break;default:throw Error("unknown BTYPE: "+c);}}return this.n()};
+var G=[16,17,18,0,8,7,9,6,10,5,11,4,12,3,13,2,14,1,15],D=t?new Uint16Array(G):G,H=[3,4,5,6,7,8,9,10,11,13,15,17,19,23,27,31,35,43,51,59,67,83,99,115,131,163,195,227,258,258,258],I=t?new Uint16Array(H):H,J=[0,0,0,0,0,0,0,0,1,1,1,1,2,2,2,2,3,3,3,3,4,4,4,4,5,5,5,5,0,0,0],K=t?new Uint8Array(J):J,L=[1,2,3,4,5,7,9,13,17,25,33,49,65,97,129,193,257,385,513,769,1025,1537,2049,3073,4097,6145,8193,12289,16385,24577],da=t?new Uint16Array(L):L,ea=[0,0,0,0,1,1,2,2,3,3,4,4,5,5,6,6,7,7,8,8,9,9,10,10,11,11,12,12,
+13,13],N=t?new Uint8Array(ea):ea,O=new (t?Uint8Array:Array)(288),P,fa;P=0;for(fa=O.length;P<fa;++P)O[P]=143>=P?8:255>=P?9:279>=P?7:8;var ba=v(O),Q=new (t?Uint8Array:Array)(30),R,ga;R=0;for(ga=Q.length;R<ga;++R)Q[R]=5;var ca=v(Q);function C(c,d){for(var a=c.f,b=c.d,e=c.input,f=c.a,g=e.length,h;b<d;){if(f>=g)throw Error("input buffer is broken");a|=e[f++]<<b;b+=8}h=a&(1<<d)-1;c.f=a>>>d;c.d=b-d;c.a=f;return h}
+function E(c,d){for(var a=c.f,b=c.d,e=c.input,f=c.a,g=e.length,h=d[0],k=d[1],m,n;b<k&&!(f>=g);)a|=e[f++]<<b,b+=8;m=h[a&(1<<k)-1];n=m>>>16;if(n>b)throw Error("invalid code length: "+n);c.f=a>>n;c.d=b-n;c.a=f;return m&65535}
+w.prototype.j=function(c,d){var a=this.c,b=this.b;this.o=c;for(var e=a.length-258,f,g,h,k;256!==(f=E(this,c));)if(256>f)b>=e&&(this.b=b,a=this.e(),b=this.b),a[b++]=f;else{g=f-257;k=I[g];0<K[g]&&(k+=C(this,K[g]));f=E(this,d);h=da[f];0<N[f]&&(h+=C(this,N[f]));b>=e&&(this.b=b,a=this.e(),b=this.b);for(;k--;)a[b]=a[b++-h]}for(;8<=this.d;)this.d-=8,this.a--;this.b=b};
+w.prototype.w=function(c,d){var a=this.c,b=this.b;this.o=c;for(var e=a.length,f,g,h,k;256!==(f=E(this,c));)if(256>f)b>=e&&(a=this.e(),e=a.length),a[b++]=f;else{g=f-257;k=I[g];0<K[g]&&(k+=C(this,K[g]));f=E(this,d);h=da[f];0<N[f]&&(h+=C(this,N[f]));b+k>e&&(a=this.e(),e=a.length);for(;k--;)a[b]=a[b++-h]}for(;8<=this.d;)this.d-=8,this.a--;this.b=b};
+w.prototype.e=function(){var c=new (t?Uint8Array:Array)(this.b-32768),d=this.b-32768,a,b,e=this.c;if(t)c.set(e.subarray(32768,c.length));else{a=0;for(b=c.length;a<b;++a)c[a]=e[a+32768]}this.g.push(c);this.l+=c.length;if(t)e.set(e.subarray(d,d+32768));else for(a=0;32768>a;++a)e[a]=e[d+a];this.b=32768;return e};
+w.prototype.z=function(c){var d,a=this.input.length/this.a+1|0,b,e,f,g=this.input,h=this.c;c&&("number"===typeof c.p&&(a=c.p),"number"===typeof c.u&&(a+=c.u));2>a?(b=(g.length-this.a)/this.o[2],f=258*(b/2)|0,e=f<h.length?h.length+f:h.length<<1):e=h.length*a;t?(d=new Uint8Array(e),d.set(h)):d=h;return this.c=d};
+w.prototype.n=function(){var c=0,d=this.c,a=this.g,b,e=new (t?Uint8Array:Array)(this.l+(this.b-32768)),f,g,h,k;if(0===a.length)return t?this.c.subarray(32768,this.b):this.c.slice(32768,this.b);f=0;for(g=a.length;f<g;++f){b=a[f];h=0;for(k=b.length;h<k;++h)e[c++]=b[h]}f=32768;for(g=this.b;f<g;++f)e[c++]=d[f];this.g=[];return this.buffer=e};
+w.prototype.v=function(){var c,d=this.b;t?this.r?(c=new Uint8Array(d),c.set(this.c.subarray(0,d))):c=this.c.subarray(0,d):(this.c.length>d&&(this.c.length=d),c=this.c);return this.buffer=c};function W(c,d){var a,b;this.input=c;this.a=0;if(d||!(d={}))d.index&&(this.a=d.index),d.verify&&(this.A=d.verify);a=c[this.a++];b=c[this.a++];switch(a&15){case ha:this.method=ha;break;default:throw Error("unsupported compression method");}if(0!==((a<<8)+b)%31)throw Error("invalid fcheck flag:"+((a<<8)+b)%31);if(b&32)throw Error("fdict flag is not supported");this.q=new w(c,{index:this.a,bufferSize:d.bufferSize,bufferType:d.bufferType,resize:d.resize})}
+W.prototype.k=function(){var c=this.input,d,a;d=this.q.k();this.a=this.q.a;if(this.A){a=(c[this.a++]<<24|c[this.a++]<<16|c[this.a++]<<8|c[this.a++])>>>0;var b=d;if("string"===typeof b){var e=b.split(""),f,g;f=0;for(g=e.length;f<g;f++)e[f]=(e[f].charCodeAt(0)&255)>>>0;b=e}for(var h=1,k=0,m=b.length,n,p=0;0<m;){n=1024<m?1024:m;m-=n;do h+=b[p++],k+=h;while(--n);h%=65521;k%=65521}if(a!==(k<<16|h)>>>0)throw Error("invalid adler-32 checksum");}return d};var ha=8;r("Zlib.Inflate",W);r("Zlib.Inflate.prototype.decompress",W.prototype.k);var X={ADAPTIVE:B.s,BLOCK:B.t},Y,Z,$,ia;if(Object.keys)Y=Object.keys(X);else for(Z in Y=[],$=0,X)Y[$++]=Z;$=0;for(ia=Y.length;$<ia;++$)Z=Y[$],r("Zlib.Inflate.BufferType."+Z,X[Z]);
+var Zlib=mod.Zlib;
+export { Zlib }

+ 11 - 7
examples/jsm/loaders/AssimpLoader.js

@@ -558,8 +558,7 @@ AssimpLoader.prototype = {
 			for ( var i in root.children ) {
 
 				var child = cloneTreeToBones( root.children[ i ], scene );
-				if ( child )
-					rootBone.add( child );
+				rootBone.add( child );
 
 			}
 
@@ -1334,6 +1333,10 @@ AssimpLoader.prototype = {
 
 		function aiScene() {
 
+			this.versionMajor = 0;
+			this.versionMinor = 0;
+			this.versionRevision = 0;
+			this.compileFlags = 0;
 			this.mFlags = 0;
 			this.mNumMeshes = 0;
 			this.mNumMaterials = 0;
@@ -2252,13 +2255,13 @@ AssimpLoader.prototype = {
 			extendStream( stream );
 			stream.Seek( 44, aiOrigin_CUR ); // signature
 			/*unsigned int versionMajor =*/
-			var versionMajor = Read_unsigned_int( stream );
+			pScene.versionMajor = Read_unsigned_int( stream );
 			/*unsigned int versionMinor =*/
-			var versionMinor = Read_unsigned_int( stream );
+			pScene.versionMinor = Read_unsigned_int( stream );
 			/*unsigned int versionRevision =*/
-			var versionRevision = Read_unsigned_int( stream );
+			pScene.versionRevision = Read_unsigned_int( stream );
 			/*unsigned int compileFlags =*/
-			var compileFlags = Read_unsigned_int( stream );
+			pScene.compileFlags = Read_unsigned_int( stream );
 			shortened = Read_uint16_t( stream ) > 0;
 			compressed = Read_uint16_t( stream ) > 0;
 			if ( shortened )
@@ -2280,10 +2283,11 @@ AssimpLoader.prototype = {
 			} else {
 
 				ReadBinaryScene( stream, pScene );
-				return pScene.toTHREE();
 
 			}
 
+			return pScene.toTHREE();
+
 		}
 
 		return InternReadFile( buffer );

+ 1 - 0
examples/jsm/loaders/FBXLoader.js

@@ -63,6 +63,7 @@ import {
 	VectorKeyframeTrack,
 	VertexColors
 } from "../../../build/three.module.js";
+import { Zlib } from "../libs/inflate.min.js";
 import { TGALoader } from "../loaders/TGALoader.js";
 import { NURBSCurve } from "../curves/NURBSCurve.js";
 

+ 47 - 111
examples/jsm/loaders/GLTFLoader.js

@@ -7,33 +7,23 @@
  */
 
 import {
-	AddEquation,
-	AlwaysDepth,
 	AnimationClip,
-	BackSide,
 	Bone,
 	BufferAttribute,
 	BufferGeometry,
-	Camera,
 	ClampToEdgeWrapping,
 	Color,
 	DefaultLoadingManager,
 	DirectionalLight,
 	DoubleSide,
-	DstAlphaFactor,
-	DstColorFactor,
-	EqualDepth,
 	FileLoader,
 	FrontSide,
-	GreaterEqualDepth,
 	Group,
 	InterleavedBuffer,
 	InterleavedBufferAttribute,
 	Interpolant,
 	InterpolateDiscrete,
 	InterpolateLinear,
-	LessDepth,
-	LessEqualDepth,
 	Line,
 	LineBasicMaterial,
 	LineLoop,
@@ -45,7 +35,6 @@ import {
 	LoaderUtils,
 	Material,
 	Math as _Math,
-	Matrix3,
 	Matrix4,
 	Mesh,
 	MeshBasicMaterial,
@@ -54,15 +43,8 @@ import {
 	NearestFilter,
 	NearestMipMapLinearFilter,
 	NearestMipMapNearestFilter,
-	NeverDepth,
-	NotEqualDepth,
 	NumberKeyframeTrack,
 	Object3D,
-	OneFactor,
-	OneMinusDstAlphaFactor,
-	OneMinusDstColorFactor,
-	OneMinusSrcAlphaFactor,
-	OneMinusSrcColorFactor,
 	OrthographicCamera,
 	PerspectiveCamera,
 	PointLight,
@@ -73,28 +55,20 @@ import {
 	RGBAFormat,
 	RGBFormat,
 	RepeatWrapping,
-	ReverseSubtractEquation,
 	Scene,
 	ShaderLib,
 	ShaderMaterial,
 	Skeleton,
 	SkinnedMesh,
 	SpotLight,
-	SrcAlphaFactor,
-	SrcAlphaSaturateFactor,
-	SrcColorFactor,
-	SubtractEquation,
 	Texture,
 	TextureLoader,
 	TriangleFanDrawMode,
 	TriangleStripDrawMode,
 	UniformsUtils,
 	Vector2,
-	Vector3,
-	Vector4,
 	VectorKeyframeTrack,
 	VertexColors,
-	ZeroFactor,
 	sRGBEncoding
 } from "../../../build/three.module.js";
 
@@ -160,9 +134,9 @@ var GLTFLoader = ( function () {
 			loader.setPath( this.path );
 			loader.setResponseType( 'arraybuffer' );
 
-			if ( this.options.crossOrigin === 'use-credentials' ) {
+			if ( scope.crossOrigin === 'use-credentials' ) {
 
-				this.fileLoader.setWithCredentials( true );
+				loader.setWithCredentials( true );
 
 			}
 
@@ -275,11 +249,11 @@ var GLTFLoader = ( function () {
 							break;
 
 						case EXTENSIONS.KHR_MATERIALS_UNLIT:
-							extensions[ extensionName ] = new GLTFMaterialsUnlitExtension( json );
+							extensions[ extensionName ] = new GLTFMaterialsUnlitExtension();
 							break;
 
 						case EXTENSIONS.KHR_MATERIALS_PBR_SPECULAR_GLOSSINESS:
-							extensions[ extensionName ] = new GLTFMaterialsPbrSpecularGlossinessExtension( json );
+							extensions[ extensionName ] = new GLTFMaterialsPbrSpecularGlossinessExtension();
 							break;
 
 						case EXTENSIONS.KHR_DRACO_MESH_COMPRESSION:
@@ -291,7 +265,7 @@ var GLTFLoader = ( function () {
 							break;
 
 						case EXTENSIONS.KHR_TEXTURE_TRANSFORM:
-							extensions[ EXTENSIONS.KHR_TEXTURE_TRANSFORM ] = new GLTFTextureTransformExtension( json );
+							extensions[ EXTENSIONS.KHR_TEXTURE_TRANSFORM ] = new GLTFTextureTransformExtension();
 							break;
 
 						default:
@@ -511,8 +485,6 @@ var GLTFLoader = ( function () {
 	};
 
 	/* BINARY EXTENSION */
-
-	var BINARY_EXTENSION_BUFFER_NAME = 'binary_glTF';
 	var BINARY_EXTENSION_HEADER_MAGIC = 'glTF';
 	var BINARY_EXTENSION_HEADER_LENGTH = 12;
 	var BINARY_EXTENSION_CHUNK_TYPES = { JSON: 0x4E4F534A, BIN: 0x004E4942 };
@@ -1197,17 +1169,6 @@ var GLTFLoader = ( function () {
 		UNSIGNED_SHORT: 5123
 	};
 
-	var WEBGL_TYPE = {
-		5126: Number,
-		//35674: THREE.Matrix2,
-		35675: Matrix3,
-		35676: Matrix4,
-		35664: Vector2,
-		35665: Vector3,
-		35666: Vector4,
-		35678: Texture
-	};
-
 	var WEBGL_COMPONENT_TYPES = {
 		5120: Int8Array,
 		5121: Uint8Array,
@@ -1232,48 +1193,6 @@ var GLTFLoader = ( function () {
 		10497: RepeatWrapping
 	};
 
-	var WEBGL_SIDES = {
-		1028: BackSide, // Culling front
-		1029: FrontSide // Culling back
-		//1032: THREE.NoSide   // Culling front and back, what to do?
-	};
-
-	var WEBGL_DEPTH_FUNCS = {
-		512: NeverDepth,
-		513: LessDepth,
-		514: EqualDepth,
-		515: LessEqualDepth,
-		516: GreaterEqualDepth,
-		517: NotEqualDepth,
-		518: GreaterEqualDepth,
-		519: AlwaysDepth
-	};
-
-	var WEBGL_BLEND_EQUATIONS = {
-		32774: AddEquation,
-		32778: SubtractEquation,
-		32779: ReverseSubtractEquation
-	};
-
-	var WEBGL_BLEND_FUNCS = {
-		0: ZeroFactor,
-		1: OneFactor,
-		768: SrcColorFactor,
-		769: OneMinusSrcColorFactor,
-		770: SrcAlphaFactor,
-		771: OneMinusSrcAlphaFactor,
-		772: DstAlphaFactor,
-		773: OneMinusDstAlphaFactor,
-		774: DstColorFactor,
-		775: OneMinusDstColorFactor,
-		776: SrcAlphaSaturateFactor
-		// The followings are not supported by Three.js yet
-		//32769: CONSTANT_COLOR,
-		//32770: ONE_MINUS_CONSTANT_COLOR,
-		//32771: CONSTANT_ALPHA,
-		//32772: ONE_MINUS_CONSTANT_COLOR
-	};
-
 	var WEBGL_TYPE_SIZES = {
 		'SCALAR': 1,
 		'VEC2': 2,
@@ -1309,15 +1228,6 @@ var GLTFLoader = ( function () {
 		STEP: InterpolateDiscrete
 	};
 
-	var STATES_ENABLES = {
-		2884: 'CULL_FACE',
-		2929: 'DEPTH_TEST',
-		3042: 'BLEND',
-		3089: 'SCISSOR_TEST',
-		32823: 'POLYGON_OFFSET_FILL',
-		32926: 'SAMPLE_ALPHA_TO_COVERAGE'
-	};
-
 	var ALPHA_MODES = {
 		OPAQUE: 'OPAQUE',
 		MASK: 'MASK',
@@ -1610,19 +1520,6 @@ var GLTFLoader = ( function () {
 
 		}
 
-	}
-	function isObjectEqual( a, b ) {
-
-		if ( Object.keys( a ).length !== Object.keys( b ).length ) return false;
-
-		for ( var key in a ) {
-
-			if ( a[ key ] !== b[ key ] ) return false;
-
-		}
-
-		return true;
-
 	}
 
 	function createPrimitiveKey( primitiveDef ) {
@@ -2673,7 +2570,6 @@ var GLTFLoader = ( function () {
 
 		var parser = this;
 		var json = this.json;
-		var extensions = this.extensions;
 
 		var meshDef = json.meshes[ meshIndex ];
 		var primitives = meshDef.primitives;
@@ -2800,7 +2696,7 @@ var GLTFLoader = ( function () {
 	/**
 	 * Specification: https://github.com/KhronosGroup/glTF/tree/master/specification/2.0#cameras
 	 * @param {number} cameraIndex
-	 * @return {Promise<Camera>}
+	 * @return {Promise<THREE.Camera>}
 	 */
 	GLTFParser.prototype.loadCamera = function ( cameraIndex ) {
 
@@ -2973,12 +2869,52 @@ var GLTFLoader = ( function () {
 
 				}
 
+				var outputArray = outputAccessor.array;
+
+				if ( outputAccessor.normalized ) {
+
+					var scale;
+
+					if ( outputArray.constructor === Int8Array ) {
+
+						scale = 1 / 127;
+
+					} else if ( outputArray.constructor === Uint8Array ) {
+
+						scale = 1 / 255;
+
+					} else if ( outputArray.constructor == Int16Array ) {
+
+						scale = 1 / 32767;
+
+					} else if ( outputArray.constructor === Uint16Array ) {
+
+						scale = 1 / 65535;
+
+					} else {
+
+						throw new Error( 'THREE.GLTFLoader: Unsupported output accessor component type.' );
+
+					}
+
+					var scaled = new Float32Array( outputArray.length );
+
+					for ( var j = 0, jl = outputArray.length; j < jl; j ++ ) {
+
+						scaled[j] = outputArray[j] * scale;
+
+					}
+
+					outputArray = scaled;
+
+				}
+
 				for ( var j = 0, jl = targetNames.length; j < jl; j ++ ) {
 
 					var track = new TypedKeyframeTrack(
 						targetNames[ j ] + '.' + PATH_PROPERTIES[ target.path ],
 						inputAccessor.array,
-						outputAccessor.array,
+						outputArray,
 						interpolation
 					);
 

+ 3 - 1
examples/jsm/loaders/HDRCubeTextureLoader.d.ts

@@ -11,7 +11,9 @@ export class HDRCubeTextureLoader {
   manager: LoadingManager;
   hdrLoader: RGBELoader;
   path: string;
+  type: TextureDataType;
 
-  load(type: TextureDataType, url: string, onLoad: (texture: CubeTexture) => void, onProgress?: (event: ProgressEvent) => void, onError?: (event: ErrorEvent) => void): void;
+  load(url: string, onLoad: (texture: CubeTexture) => void, onProgress?: (event: ProgressEvent) => void, onError?: (event: ErrorEvent) => void): void;
   setPath(value: string): this;
+  setType(type: TextureDataType): this;
 }

+ 63 - 127
examples/jsm/loaders/HDRCubeTextureLoader.js

@@ -23,101 +23,60 @@ import { RGBELoader } from "../loaders/RGBELoader.js";
 var HDRCubeTextureLoader = function ( manager ) {
 
 	this.manager = ( manager !== undefined ) ? manager : DefaultLoadingManager;
-	// override in sub classes
 	this.hdrLoader = new RGBELoader();
+	this.type = UnsignedByteType;
 
 };
 
-HDRCubeTextureLoader.prototype.load = function ( type, urls, onLoad, onProgress, onError ) {
+HDRCubeTextureLoader.prototype.load = function ( urls, onLoad, onProgress, onError ) {
 
-	var RGBEByteToRGBFloat = function ( sourceArray, sourceOffset, destArray, destOffset ) {
+	if ( ! Array.isArray( urls ) ) {
 
-		var e = sourceArray[ sourceOffset + 3 ];
-		var scale = Math.pow( 2.0, e - 128.0 ) / 255.0;
+		console.warn( 'THREE.HDRCubeTextureLoader signature has changed. Use .setType() instead.' );
 
-		destArray[ destOffset + 0 ] = sourceArray[ sourceOffset + 0 ] * scale;
-		destArray[ destOffset + 1 ] = sourceArray[ sourceOffset + 1 ] * scale;
-		destArray[ destOffset + 2 ] = sourceArray[ sourceOffset + 2 ] * scale;
+		this.setType( urls );
 
-	};
+		urls = onLoad;
+		onLoad = onProgress;
+		onProgress = onError;
+		onError = arguments[ 4 ];
 
-	var RGBEByteToRGBHalf = ( function () {
-
-		// Source: http://gamedev.stackexchange.com/questions/17326/conversion-of-a-number-from-single-precision-floating-point-representation-to-a/17410#17410
-
-		var floatView = new Float32Array( 1 );
-		var int32View = new Int32Array( floatView.buffer );
-
-		/* This method is faster than the OpenEXR implementation (very often
-		 * used, eg. in Ogre), with the additional benefit of rounding, inspired
-		 * by James Tursa?s half-precision code. */
-		function toHalf( val ) {
-
-			floatView[ 0 ] = val;
-			var x = int32View[ 0 ];
-
-			var bits = ( x >> 16 ) & 0x8000; /* Get the sign */
-			var m = ( x >> 12 ) & 0x07ff; /* Keep one extra bit for rounding */
-			var e = ( x >> 23 ) & 0xff; /* Using int is faster here */
-
-			/* If zero, or denormal, or exponent underflows too much for a denormal
-			 * half, return signed zero. */
-			if ( e < 103 ) return bits;
-
-			/* If NaN, return NaN. If Inf or exponent overflow, return Inf. */
-			if ( e > 142 ) {
-
-				bits |= 0x7c00;
-				/* If exponent was 0xff and one mantissa bit was set, it means NaN,
-						 * not Inf, so make sure we set one mantissa bit too. */
-				bits |= ( ( e == 255 ) ? 0 : 1 ) && ( x & 0x007fffff );
-				return bits;
-
-			}
-
-			/* If exponent underflows but not too much, return a denormal */
-			if ( e < 113 ) {
-
-				m |= 0x0800;
-				/* Extra rounding may overflow and set mantissa to 0 and exponent
-				 * to 1, which is OK. */
-				bits |= ( m >> ( 114 - e ) ) + ( ( m >> ( 113 - e ) ) & 1 );
-				return bits;
+	}
 
-			}
+	var texture = new CubeTexture();
 
-			bits |= ( ( e - 112 ) << 10 ) | ( m >> 1 );
-			/* Extra rounding. An overflow will set mantissa to 0 and increment
-			 * the exponent, which is OK. */
-			bits += m & 1;
-			return bits;
+	texture.type = this.type;
 
-		}
+	switch ( texture.type ) {
 
-		return function ( sourceArray, sourceOffset, destArray, destOffset ) {
+		case UnsignedByteType:
 
-			var e = sourceArray[ sourceOffset + 3 ];
-			var scale = Math.pow( 2.0, e - 128.0 ) / 255.0;
+			texture.encoding = RGBEEncoding;
+			texture.format = RGBAFormat;
+			texture.minFilter = NearestFilter;
+			texture.magFilter = NearestFilter;
+			texture.generateMipmaps = false;
+			break;
 
-			destArray[ destOffset + 0 ] = toHalf( sourceArray[ sourceOffset + 0 ] * scale );
-			destArray[ destOffset + 1 ] = toHalf( sourceArray[ sourceOffset + 1 ] * scale );
-			destArray[ destOffset + 2 ] = toHalf( sourceArray[ sourceOffset + 2 ] * scale );
+		case FloatType:
 
-		};
+			texture.encoding = LinearEncoding;
+			texture.format = RGBFormat;
+			texture.minFilter = LinearFilter;
+			texture.magFilter = LinearFilter;
+			texture.generateMipmaps = false;
+			break;
 
-	} )();
+		case HalfFloatType:
 
-	//
+			texture.encoding = LinearEncoding;
+			texture.format = RGBFormat;
+			texture.minFilter = LinearFilter;
+			texture.magFilter = LinearFilter;
+			texture.generateMipmaps = false;
+			break;
 
-	var texture = new CubeTexture();
-
-	texture.type = type;
-	texture.encoding = ( type === UnsignedByteType ) ? RGBEEncoding : LinearEncoding;
-	texture.format = ( type === UnsignedByteType ) ? RGBAFormat : RGBFormat;
-	texture.minFilter = ( texture.encoding === RGBEEncoding ) ? NearestFilter : LinearFilter;
-	texture.magFilter = ( texture.encoding === RGBEEncoding ) ? NearestFilter : LinearFilter;
-	texture.generateMipmaps = ( texture.encoding !== RGBEEncoding );
-	texture.anisotropy = 0;
+	}
 
 	var scope = this;
 
@@ -125,71 +84,40 @@ HDRCubeTextureLoader.prototype.load = function ( type, urls, onLoad, onProgress,
 
 	function loadHDRData( i, onLoad, onProgress, onError ) {
 
-		var loader = new FileLoader( scope.manager );
-		loader.setPath( scope.path );
-		loader.setResponseType( 'arraybuffer' );
-		loader.load( urls[ i ], function ( buffer ) {
+		new FileLoader( scope.manager )
+			.setPath( scope.path )
+			.setResponseType( 'arraybuffer' )
+			.load( urls[ i ], function ( buffer ) {
 
-			loaded ++;
+				loaded ++;
 
-			var texData = scope.hdrLoader._parser( buffer );
+				var texData = scope.hdrLoader._parser( buffer );
 
-			if ( ! texData ) return;
+				if ( ! texData ) return;
 
-			if ( type === FloatType ) {
+				if ( texData.data !== undefined ) {
 
-				var numElements = ( texData.data.length / 4 ) * 3;
-				var floatdata = new Float32Array( numElements );
+					var dataTexture = new DataTexture( texData.data, texData.width, texData.height );
 
-				for ( var j = 0; j < numElements; j ++ ) {
+					dataTexture.type = texture.type;
+					dataTexture.encoding = texture.encoding;
+					dataTexture.format = texture.format;
+					dataTexture.minFilter = texture.minFilter;
+					dataTexture.magFilter = texture.magFilter;
+					dataTexture.generateMipmaps = texture.generateMipmaps;
 
-					RGBEByteToRGBFloat( texData.data, j * 4, floatdata, j * 3 );
+					texture.images[ i ] = dataTexture;
 
 				}
 
-				texData.data = floatdata;
-
-			} else if ( type === HalfFloatType ) {
-
-				var numElements = ( texData.data.length / 4 ) * 3;
-				var halfdata = new Uint16Array( numElements );
+				if ( loaded === 6 ) {
 
-				for ( var j = 0; j < numElements; j ++ ) {
-
-					RGBEByteToRGBHalf( texData.data, j * 4, halfdata, j * 3 );
+					texture.needsUpdate = true;
+					if ( onLoad ) onLoad( texture );
 
 				}
 
-				texData.data = halfdata;
-
-			}
-
-			if ( texData.image !== undefined ) {
-
-				texture[ i ].images = texData.image;
-
-			} else if ( texData.data !== undefined ) {
-
-				var dataTexture = new DataTexture( texData.data, texData.width, texData.height );
-				dataTexture.format = texture.format;
-				dataTexture.type = texture.type;
-				dataTexture.encoding = texture.encoding;
-				dataTexture.minFilter = texture.minFilter;
-				dataTexture.magFilter = texture.magFilter;
-				dataTexture.generateMipmaps = texture.generateMipmaps;
-
-				texture.images[ i ] = dataTexture;
-
-			}
-
-			if ( loaded === 6 ) {
-
-				texture.needsUpdate = true;
-				if ( onLoad ) onLoad( texture );
-
-			}
-
-		}, onProgress, onError );
+			}, onProgress, onError );
 
 	}
 
@@ -210,4 +138,12 @@ HDRCubeTextureLoader.prototype.setPath = function ( value ) {
 
 };
 
+HDRCubeTextureLoader.prototype.setType = function ( value ) {
+
+	this.type = value;
+	this.hdrLoader.setType( value );
+	return this;
+
+};
+
 export { HDRCubeTextureLoader };

+ 14 - 0
examples/jsm/loaders/MD2Loader.d.ts

@@ -0,0 +1,14 @@
+import {
+  BufferGeometry,
+  LoadingManager
+} from '../../../src/Three';
+
+export class MD2Loader {
+  constructor(manager?: LoadingManager);
+  manager: LoadingManager;
+  path: string;
+
+  load(url: string, onLoad: (geometry: BufferGeometry) => void, onProgress?: (event: ProgressEvent) => void, onError?: (event: ErrorEvent) => void): void;
+  setPath(path: string): this;
+  parse(data: ArrayBuffer): BufferGeometry;
+}

+ 398 - 0
examples/jsm/loaders/MD2Loader.js

@@ -0,0 +1,398 @@
+/**
+ * @author mrdoob / http://mrdoob.com/
+ */
+
+import {
+	AnimationClip,
+	BufferGeometry,
+	DefaultLoadingManager,
+	FileLoader,
+	Float32BufferAttribute,
+	Vector3
+} from "../../../build/three.module.js";
+
+var MD2Loader = function ( manager ) {
+
+	this.manager = ( manager !== undefined ) ? manager : DefaultLoadingManager;
+
+};
+
+MD2Loader.prototype = {
+
+	constructor: MD2Loader,
+
+	load: function ( url, onLoad, onProgress, onError ) {
+
+		var scope = this;
+
+		var loader = new FileLoader( scope.manager );
+		loader.setPath( scope.path );
+		loader.setResponseType( 'arraybuffer' );
+		loader.load( url, function ( buffer ) {
+
+			onLoad( scope.parse( buffer ) );
+
+		}, onProgress, onError );
+
+	},
+
+	setPath: function ( value ) {
+
+		this.path = value;
+		return this;
+
+	},
+
+	parse: ( function () {
+
+		var normalData = [
+			[ - 0.525731, 0.000000, 0.850651 ], [ - 0.442863, 0.238856, 0.864188 ],
+			[ - 0.295242, 0.000000, 0.955423 ], [ - 0.309017, 0.500000, 0.809017 ],
+			[ - 0.162460, 0.262866, 0.951056 ], [ 0.000000, 0.000000, 1.000000 ],
+			[ 0.000000, 0.850651, 0.525731 ], [ - 0.147621, 0.716567, 0.681718 ],
+			[ 0.147621, 0.716567, 0.681718 ], [ 0.000000, 0.525731, 0.850651 ],
+			[ 0.309017, 0.500000, 0.809017 ], [ 0.525731, 0.000000, 0.850651 ],
+			[ 0.295242, 0.000000, 0.955423 ], [ 0.442863, 0.238856, 0.864188 ],
+			[ 0.162460, 0.262866, 0.951056 ], [ - 0.681718, 0.147621, 0.716567 ],
+			[ - 0.809017, 0.309017, 0.500000 ], [ - 0.587785, 0.425325, 0.688191 ],
+			[ - 0.850651, 0.525731, 0.000000 ], [ - 0.864188, 0.442863, 0.238856 ],
+			[ - 0.716567, 0.681718, 0.147621 ], [ - 0.688191, 0.587785, 0.425325 ],
+			[ - 0.500000, 0.809017, 0.309017 ], [ - 0.238856, 0.864188, 0.442863 ],
+			[ - 0.425325, 0.688191, 0.587785 ], [ - 0.716567, 0.681718, - 0.147621 ],
+			[ - 0.500000, 0.809017, - 0.309017 ], [ - 0.525731, 0.850651, 0.000000 ],
+			[ 0.000000, 0.850651, - 0.525731 ], [ - 0.238856, 0.864188, - 0.442863 ],
+			[ 0.000000, 0.955423, - 0.295242 ], [ - 0.262866, 0.951056, - 0.162460 ],
+			[ 0.000000, 1.000000, 0.000000 ], [ 0.000000, 0.955423, 0.295242 ],
+			[ - 0.262866, 0.951056, 0.162460 ], [ 0.238856, 0.864188, 0.442863 ],
+			[ 0.262866, 0.951056, 0.162460 ], [ 0.500000, 0.809017, 0.309017 ],
+			[ 0.238856, 0.864188, - 0.442863 ], [ 0.262866, 0.951056, - 0.162460 ],
+			[ 0.500000, 0.809017, - 0.309017 ], [ 0.850651, 0.525731, 0.000000 ],
+			[ 0.716567, 0.681718, 0.147621 ], [ 0.716567, 0.681718, - 0.147621 ],
+			[ 0.525731, 0.850651, 0.000000 ], [ 0.425325, 0.688191, 0.587785 ],
+			[ 0.864188, 0.442863, 0.238856 ], [ 0.688191, 0.587785, 0.425325 ],
+			[ 0.809017, 0.309017, 0.500000 ], [ 0.681718, 0.147621, 0.716567 ],
+			[ 0.587785, 0.425325, 0.688191 ], [ 0.955423, 0.295242, 0.000000 ],
+			[ 1.000000, 0.000000, 0.000000 ], [ 0.951056, 0.162460, 0.262866 ],
+			[ 0.850651, - 0.525731, 0.000000 ], [ 0.955423, - 0.295242, 0.000000 ],
+			[ 0.864188, - 0.442863, 0.238856 ], [ 0.951056, - 0.162460, 0.262866 ],
+			[ 0.809017, - 0.309017, 0.500000 ], [ 0.681718, - 0.147621, 0.716567 ],
+			[ 0.850651, 0.000000, 0.525731 ], [ 0.864188, 0.442863, - 0.238856 ],
+			[ 0.809017, 0.309017, - 0.500000 ], [ 0.951056, 0.162460, - 0.262866 ],
+			[ 0.525731, 0.000000, - 0.850651 ], [ 0.681718, 0.147621, - 0.716567 ],
+			[ 0.681718, - 0.147621, - 0.716567 ], [ 0.850651, 0.000000, - 0.525731 ],
+			[ 0.809017, - 0.309017, - 0.500000 ], [ 0.864188, - 0.442863, - 0.238856 ],
+			[ 0.951056, - 0.162460, - 0.262866 ], [ 0.147621, 0.716567, - 0.681718 ],
+			[ 0.309017, 0.500000, - 0.809017 ], [ 0.425325, 0.688191, - 0.587785 ],
+			[ 0.442863, 0.238856, - 0.864188 ], [ 0.587785, 0.425325, - 0.688191 ],
+			[ 0.688191, 0.587785, - 0.425325 ], [ - 0.147621, 0.716567, - 0.681718 ],
+			[ - 0.309017, 0.500000, - 0.809017 ], [ 0.000000, 0.525731, - 0.850651 ],
+			[ - 0.525731, 0.000000, - 0.850651 ], [ - 0.442863, 0.238856, - 0.864188 ],
+			[ - 0.295242, 0.000000, - 0.955423 ], [ - 0.162460, 0.262866, - 0.951056 ],
+			[ 0.000000, 0.000000, - 1.000000 ], [ 0.295242, 0.000000, - 0.955423 ],
+			[ 0.162460, 0.262866, - 0.951056 ], [ - 0.442863, - 0.238856, - 0.864188 ],
+			[ - 0.309017, - 0.500000, - 0.809017 ], [ - 0.162460, - 0.262866, - 0.951056 ],
+			[ 0.000000, - 0.850651, - 0.525731 ], [ - 0.147621, - 0.716567, - 0.681718 ],
+			[ 0.147621, - 0.716567, - 0.681718 ], [ 0.000000, - 0.525731, - 0.850651 ],
+			[ 0.309017, - 0.500000, - 0.809017 ], [ 0.442863, - 0.238856, - 0.864188 ],
+			[ 0.162460, - 0.262866, - 0.951056 ], [ 0.238856, - 0.864188, - 0.442863 ],
+			[ 0.500000, - 0.809017, - 0.309017 ], [ 0.425325, - 0.688191, - 0.587785 ],
+			[ 0.716567, - 0.681718, - 0.147621 ], [ 0.688191, - 0.587785, - 0.425325 ],
+			[ 0.587785, - 0.425325, - 0.688191 ], [ 0.000000, - 0.955423, - 0.295242 ],
+			[ 0.000000, - 1.000000, 0.000000 ], [ 0.262866, - 0.951056, - 0.162460 ],
+			[ 0.000000, - 0.850651, 0.525731 ], [ 0.000000, - 0.955423, 0.295242 ],
+			[ 0.238856, - 0.864188, 0.442863 ], [ 0.262866, - 0.951056, 0.162460 ],
+			[ 0.500000, - 0.809017, 0.309017 ], [ 0.716567, - 0.681718, 0.147621 ],
+			[ 0.525731, - 0.850651, 0.000000 ], [ - 0.238856, - 0.864188, - 0.442863 ],
+			[ - 0.500000, - 0.809017, - 0.309017 ], [ - 0.262866, - 0.951056, - 0.162460 ],
+			[ - 0.850651, - 0.525731, 0.000000 ], [ - 0.716567, - 0.681718, - 0.147621 ],
+			[ - 0.716567, - 0.681718, 0.147621 ], [ - 0.525731, - 0.850651, 0.000000 ],
+			[ - 0.500000, - 0.809017, 0.309017 ], [ - 0.238856, - 0.864188, 0.442863 ],
+			[ - 0.262866, - 0.951056, 0.162460 ], [ - 0.864188, - 0.442863, 0.238856 ],
+			[ - 0.809017, - 0.309017, 0.500000 ], [ - 0.688191, - 0.587785, 0.425325 ],
+			[ - 0.681718, - 0.147621, 0.716567 ], [ - 0.442863, - 0.238856, 0.864188 ],
+			[ - 0.587785, - 0.425325, 0.688191 ], [ - 0.309017, - 0.500000, 0.809017 ],
+			[ - 0.147621, - 0.716567, 0.681718 ], [ - 0.425325, - 0.688191, 0.587785 ],
+			[ - 0.162460, - 0.262866, 0.951056 ], [ 0.442863, - 0.238856, 0.864188 ],
+			[ 0.162460, - 0.262866, 0.951056 ], [ 0.309017, - 0.500000, 0.809017 ],
+			[ 0.147621, - 0.716567, 0.681718 ], [ 0.000000, - 0.525731, 0.850651 ],
+			[ 0.425325, - 0.688191, 0.587785 ], [ 0.587785, - 0.425325, 0.688191 ],
+			[ 0.688191, - 0.587785, 0.425325 ], [ - 0.955423, 0.295242, 0.000000 ],
+			[ - 0.951056, 0.162460, 0.262866 ], [ - 1.000000, 0.000000, 0.000000 ],
+			[ - 0.850651, 0.000000, 0.525731 ], [ - 0.955423, - 0.295242, 0.000000 ],
+			[ - 0.951056, - 0.162460, 0.262866 ], [ - 0.864188, 0.442863, - 0.238856 ],
+			[ - 0.951056, 0.162460, - 0.262866 ], [ - 0.809017, 0.309017, - 0.500000 ],
+			[ - 0.864188, - 0.442863, - 0.238856 ], [ - 0.951056, - 0.162460, - 0.262866 ],
+			[ - 0.809017, - 0.309017, - 0.500000 ], [ - 0.681718, 0.147621, - 0.716567 ],
+			[ - 0.681718, - 0.147621, - 0.716567 ], [ - 0.850651, 0.000000, - 0.525731 ],
+			[ - 0.688191, 0.587785, - 0.425325 ], [ - 0.587785, 0.425325, - 0.688191 ],
+			[ - 0.425325, 0.688191, - 0.587785 ], [ - 0.425325, - 0.688191, - 0.587785 ],
+			[ - 0.587785, - 0.425325, - 0.688191 ], [ - 0.688191, - 0.587785, - 0.425325 ]
+		];
+
+		return function ( buffer ) {
+
+			console.time( 'MD2Loader' );
+
+			var data = new DataView( buffer );
+
+			// http://tfc.duke.free.fr/coding/md2-specs-en.html
+
+			var header = {};
+			var headerNames = [
+				'ident', 'version',
+				'skinwidth', 'skinheight',
+				'framesize',
+				'num_skins', 'num_vertices', 'num_st', 'num_tris', 'num_glcmds', 'num_frames',
+				'offset_skins', 'offset_st', 'offset_tris', 'offset_frames', 'offset_glcmds', 'offset_end'
+			];
+
+			for ( var i = 0; i < headerNames.length; i ++ ) {
+
+				header[ headerNames[ i ] ] = data.getInt32( i * 4, true );
+
+			}
+
+			if ( header.ident !== 844121161 || header.version !== 8 ) {
+
+				console.error( 'Not a valid MD2 file' );
+				return;
+
+			}
+
+			if ( header.offset_end !== data.byteLength ) {
+
+				console.error( 'Corrupted MD2 file' );
+				return;
+
+			}
+
+			//
+
+			var geometry = new BufferGeometry();
+
+			// uvs
+
+			var uvsTemp = [];
+			var offset = header.offset_st;
+
+			for ( var i = 0, l = header.num_st; i < l; i ++ ) {
+
+				var u = data.getInt16( offset + 0, true );
+				var v = data.getInt16( offset + 2, true );
+
+				uvsTemp.push( u / header.skinwidth, 1 - ( v / header.skinheight ) );
+
+				offset += 4;
+
+			}
+
+			// triangles
+
+			offset = header.offset_tris;
+
+			var vertexIndices = [];
+			var uvIndices = [];
+
+			for ( var i = 0, l = header.num_tris; i < l; i ++ ) {
+
+				vertexIndices.push(
+					data.getUint16( offset + 0, true ),
+					data.getUint16( offset + 2, true ),
+					data.getUint16( offset + 4, true )
+				);
+
+				uvIndices.push(
+					data.getUint16( offset + 6, true ),
+					data.getUint16( offset + 8, true ),
+					data.getUint16( offset + 10, true )
+				);
+
+				offset += 12;
+
+			}
+
+			// frames
+
+			var translation = new Vector3();
+			var scale = new Vector3();
+			var string = [];
+
+			var frames = [];
+
+			offset = header.offset_frames;
+
+			for ( var i = 0, l = header.num_frames; i < l; i ++ ) {
+
+				scale.set(
+					data.getFloat32( offset + 0, true ),
+					data.getFloat32( offset + 4, true ),
+					data.getFloat32( offset + 8, true )
+				);
+
+				translation.set(
+					data.getFloat32( offset + 12, true ),
+					data.getFloat32( offset + 16, true ),
+					data.getFloat32( offset + 20, true )
+				);
+
+				offset += 24;
+
+				for ( var j = 0; j < 16; j ++ ) {
+
+					var character = data.getUint8( offset + j, true );
+					if ( character === 0 ) break;
+
+					string[ j ] = character;
+
+				}
+
+				var frame = {
+					name: String.fromCharCode.apply( null, string ),
+					vertices: [],
+					normals: []
+				};
+
+				offset += 16;
+
+				for ( var j = 0; j < header.num_vertices; j ++ ) {
+
+					var x = data.getUint8( offset ++, true );
+					var y = data.getUint8( offset ++, true );
+					var z = data.getUint8( offset ++, true );
+					var n = normalData[ data.getUint8( offset ++, true ) ];
+
+					x = x * scale.x + translation.x;
+					y = y * scale.y + translation.y;
+					z = z * scale.z + translation.z;
+
+					frame.vertices.push( x, z, y ); // convert to Y-up
+					frame.normals.push( n[ 0 ], n[ 2 ], n[ 1 ] ); // convert to Y-up
+
+				}
+
+				frames.push( frame );
+
+			}
+
+			// static
+
+			var positions = [];
+			var normals = [];
+			var uvs = [];
+
+			var verticesTemp = frames[ 0 ].vertices;
+			var normalsTemp = frames[ 0 ].normals;
+
+			for ( var i = 0, l = vertexIndices.length; i < l; i ++ ) {
+
+				var vertexIndex = vertexIndices[ i ];
+				var stride = vertexIndex * 3;
+
+				//
+
+				var x = verticesTemp[ stride ];
+				var y = verticesTemp[ stride + 1 ];
+				var z = verticesTemp[ stride + 2 ];
+
+				positions.push( x, y, z );
+
+				//
+
+				var nx = normalsTemp[ stride ];
+				var ny = normalsTemp[ stride + 1 ];
+				var nz = normalsTemp[ stride + 2 ];
+
+				normals.push( nx, ny, nz );
+
+				//
+
+				var uvIndex = uvIndices[ i ];
+				stride = uvIndex * 2;
+
+				var u = uvsTemp[ stride ];
+				var v = uvsTemp[ stride + 1 ];
+
+				uvs.push( u, v );
+
+			}
+
+			geometry.addAttribute( 'position', new Float32BufferAttribute( positions, 3 ) );
+			geometry.addAttribute( 'normal', new Float32BufferAttribute( normals, 3 ) );
+			geometry.addAttribute( 'uv', new Float32BufferAttribute( uvs, 2 ) );
+
+			// animation
+
+			var morphPositions = [];
+			var morphNormals = [];
+
+			for ( var i = 0, l = frames.length; i < l; i ++ ) {
+
+				var frame = frames[ i ];
+				var attributeName = frame.name;
+
+				if ( frame.vertices.length > 0 ) {
+
+					var positions = [];
+
+					for ( var j = 0, jl = vertexIndices.length; j < jl; j ++ ) {
+
+						var vertexIndex = vertexIndices[ j ];
+						var stride = vertexIndex * 3;
+
+						var x = frame.vertices[ stride ];
+						var y = frame.vertices[ stride + 1 ];
+						var z = frame.vertices[ stride + 2 ];
+
+						positions.push( x, y, z );
+
+					}
+
+					var positionAttribute = new Float32BufferAttribute( positions, 3 );
+					positionAttribute.name = attributeName;
+
+					morphPositions.push( positionAttribute );
+
+				}
+
+				if ( frame.normals.length > 0 ) {
+
+					var normals = [];
+
+					for ( var j = 0, jl = vertexIndices.length; j < jl; j ++ ) {
+
+						var vertexIndex = vertexIndices[ j ];
+						var stride = vertexIndex * 3;
+
+						var nx = frame.normals[ stride ];
+						var ny = frame.normals[ stride + 1 ];
+						var nz = frame.normals[ stride + 2 ];
+
+						normals.push( nx, ny, nz );
+
+					}
+
+					var normalAttribute = new Float32BufferAttribute( normals, 3 );
+					normalAttribute.name = attributeName;
+
+					morphNormals.push( normalAttribute );
+
+				}
+
+			}
+
+			geometry.morphAttributes.position = morphPositions;
+			geometry.morphAttributes.normal = morphNormals;
+
+			geometry.animations = AnimationClip.CreateClipsFromMorphTargetSequences( frames, 10 );
+
+			console.timeEnd( 'MD2Loader' );
+
+			return geometry;
+
+		};
+
+	} )()
+
+};
+
+export { MD2Loader };

+ 1 - 0
examples/jsm/loaders/VTKLoader.js

@@ -18,6 +18,7 @@ import {
 	Float32BufferAttribute,
 	LoaderUtils
 } from "../../../build/three.module.js";
+import { Zlib } from "../libs/inflate.min.js";
 
 var VTKLoader = function ( manager ) {
 

+ 21 - 0
examples/jsm/misc/CarControls.d.ts

@@ -0,0 +1,21 @@
+import {
+  Object3D,
+} from '../../../src/Three';
+
+export class CarControls {
+  constructor( maxSpeed?: number, acceleration?: number, brakePower?: number, turningRadius?: number, keys?: object );
+
+  // API
+  enabled: boolean;
+  elemNames: object;
+  maxSpeed: number;
+  acceleration: number;
+  turningRadius: number;
+  brakePower: number;
+  speed: number;
+
+  dispose(): void;
+  update( delta: number ): void;
+  setModel ( model: Object3D, elemNames: object ): void;
+
+}

+ 1 - 1
examples/jsm/misc/ConvexObjectBreaker.d.ts

@@ -1,5 +1,5 @@
 import {
-  Object3D
+  Object3D,
   Plane,
   Vector3
 } from '../../../src/Three';

+ 41 - 0
examples/jsm/misc/GPUComputationRenderer.d.ts

@@ -0,0 +1,41 @@
+import {
+  WebGLRenderer,
+  RenderTarget,
+  Texture,
+  DataTexture,
+  Material,
+  ShaderMaterial,
+  Wrapping,
+  TextureFilter
+
+} from '../../../src/Three';
+
+export interface Variable {
+  name: string;
+  initialValueTexture: Texture;
+  material: Material;
+  dependencies: Variable[];
+  renderTargets: RenderTarget[];
+  wrapS: number;
+  wrapT: number;
+  minFilter: number;
+  magFilter: number;
+}
+
+export class GPUComputationRenderer {
+  constructor(sizeX: number, sizeY: number, renderer: WebGLRenderer);
+
+  addVariable(variableName: string, computeFragmentShader: string, initialValueTexture: Texture): Variable;
+  setVariableDependencies(variable: Variable, dependencies: Variable[] | null): void;
+
+  init(): string | null;
+  compute(): void;
+
+  getCurrentRenderTarget(variable: Variable): RenderTarget;
+  getAlternateRenderTarget(variable: Variable): RenderTarget;
+  addResolutionDefine(materialShader: ShaderMaterial): void;
+  createRenderTarget(sizeXTexture: number, sizeYTexture: number, wrapS: Wrapping, wrapT: number, minFilter: TextureFilter, magFilter: TextureFilter): RenderTarget;
+  createTexture(): DataTexture;
+  renderTexture(input: Texture, output: Texture): void;
+  doRenderTarget( material: Material, output: RenderTarget ): void;
+}

+ 391 - 0
examples/jsm/misc/GPUComputationRenderer.js

@@ -0,0 +1,391 @@
+/**
+ * @author yomboprime https://github.com/yomboprime
+ *
+ * GPUComputationRenderer, based on SimulationRenderer by zz85
+ *
+ * The GPUComputationRenderer uses the concept of variables. These variables are RGBA float textures that hold 4 floats
+ * for each compute element (texel)
+ *
+ * Each variable has a fragment shader that defines the computation made to obtain the variable in question.
+ * You can use as many variables you need, and make dependencies so you can use textures of other variables in the shader
+ * (the sampler uniforms are added automatically) Most of the variables will need themselves as dependency.
+ *
+ * The renderer has actually two render targets per variable, to make ping-pong. Textures from the current frame are used
+ * as inputs to render the textures of the next frame.
+ *
+ * The render targets of the variables can be used as input textures for your visualization shaders.
+ *
+ * Variable names should be valid identifiers and should not collide with THREE GLSL used identifiers.
+ * a common approach could be to use 'texture' prefixing the variable name; i.e texturePosition, textureVelocity...
+ *
+ * The size of the computation (sizeX * sizeY) is defined as 'resolution' automatically in the shader. For example:
+ * #DEFINE resolution vec2( 1024.0, 1024.0 )
+ *
+ * -------------
+ *
+ * Basic use:
+ *
+ * // Initialization...
+ *
+ * // Create computation renderer
+ * var gpuCompute = new GPUComputationRenderer( 1024, 1024, renderer );
+ *
+ * // Create initial state float textures
+ * var pos0 = gpuCompute.createTexture();
+ * var vel0 = gpuCompute.createTexture();
+ * // and fill in here the texture data...
+ *
+ * // Add texture variables
+ * var velVar = gpuCompute.addVariable( "textureVelocity", fragmentShaderVel, pos0 );
+ * var posVar = gpuCompute.addVariable( "texturePosition", fragmentShaderPos, vel0 );
+ *
+ * // Add variable dependencies
+ * gpuCompute.setVariableDependencies( velVar, [ velVar, posVar ] );
+ * gpuCompute.setVariableDependencies( posVar, [ velVar, posVar ] );
+ *
+ * // Add custom uniforms
+ * velVar.material.uniforms.time = { value: 0.0 };
+ *
+ * // Check for completeness
+ * var error = gpuCompute.init();
+ * if ( error !== null ) {
+ *		console.error( error );
+  * }
+ *
+ *
+ * // In each frame...
+ *
+ * // Compute!
+ * gpuCompute.compute();
+ *
+ * // Update texture uniforms in your visualization materials with the gpu renderer output
+ * myMaterial.uniforms.myTexture.value = gpuCompute.getCurrentRenderTarget( posVar ).texture;
+ *
+ * // Do your rendering
+ * renderer.render( myScene, myCamera );
+ *
+ * -------------
+ *
+ * Also, you can use utility functions to create ShaderMaterial and perform computations (rendering between textures)
+ * Note that the shaders can have multiple input textures.
+ *
+ * var myFilter1 = gpuCompute.createShaderMaterial( myFilterFragmentShader1, { theTexture: { value: null } } );
+ * var myFilter2 = gpuCompute.createShaderMaterial( myFilterFragmentShader2, { theTexture: { value: null } } );
+ *
+ * var inputTexture = gpuCompute.createTexture();
+ *
+ * // Fill in here inputTexture...
+ *
+ * myFilter1.uniforms.theTexture.value = inputTexture;
+ *
+ * var myRenderTarget = gpuCompute.createRenderTarget();
+ * myFilter2.uniforms.theTexture.value = myRenderTarget.texture;
+ *
+ * var outputRenderTarget = gpuCompute.createRenderTarget();
+ *
+ * // Now use the output texture where you want:
+ * myMaterial.uniforms.map.value = outputRenderTarget.texture;
+ *
+ * // And compute each frame, before rendering to screen:
+ * gpuCompute.doRenderTarget( myFilter1, myRenderTarget );
+ * gpuCompute.doRenderTarget( myFilter2, outputRenderTarget );
+ *
+ *
+ *
+ * @param {int} sizeX Computation problem size is always 2d: sizeX * sizeY elements.
+ * @param {int} sizeY Computation problem size is always 2d: sizeX * sizeY elements.
+ * @param {WebGLRenderer} renderer The renderer
+  */
+
+import {
+	Camera,
+	ClampToEdgeWrapping,
+	DataTexture,
+	FloatType,
+	HalfFloatType,
+	Mesh,
+	NearestFilter,
+	PlaneBufferGeometry,
+	RGBAFormat,
+	Scene,
+	ShaderMaterial,
+	WebGLRenderTarget
+} from "../../../build/three.module.js";
+
+var GPUComputationRenderer = function( sizeX, sizeY, renderer ) {
+
+	this.variables = [];
+
+	this.currentTextureIndex = 0;
+
+	var scene = new Scene();
+
+	var camera = new Camera();
+	camera.position.z = 1;
+
+	var passThruUniforms = {
+		texture: { value: null }
+	};
+
+	var passThruShader = createShaderMaterial( getPassThroughFragmentShader(), passThruUniforms );
+
+	var mesh = new Mesh( new PlaneBufferGeometry( 2, 2 ), passThruShader );
+	scene.add( mesh );
+
+
+	this.addVariable = function( variableName, computeFragmentShader, initialValueTexture ) {
+
+		var material = this.createShaderMaterial( computeFragmentShader );
+
+		var variable = {
+			name: variableName,
+			initialValueTexture: initialValueTexture,
+			material: material,
+			dependencies: null,
+			renderTargets: [],
+			wrapS: null,
+			wrapT: null,
+			minFilter: NearestFilter,
+			magFilter: NearestFilter
+		};
+
+		this.variables.push( variable );
+
+		return variable;
+
+	};
+
+	this.setVariableDependencies = function( variable, dependencies ) {
+
+		variable.dependencies = dependencies;
+
+	};
+
+	this.init = function() {
+
+		if ( ! renderer.extensions.get( "OES_texture_float" ) ) {
+
+			return "No OES_texture_float support for float textures.";
+
+		}
+
+		if ( renderer.capabilities.maxVertexTextures === 0 ) {
+
+			return "No support for vertex shader textures.";
+
+		}
+
+		for ( var i = 0; i < this.variables.length; i++ ) {
+
+			var variable = this.variables[ i ];
+
+			// Creates rendertargets and initialize them with input texture
+			variable.renderTargets[ 0 ] = this.createRenderTarget( sizeX, sizeY, variable.wrapS, variable.wrapT, variable.minFilter, variable.magFilter );
+			variable.renderTargets[ 1 ] = this.createRenderTarget( sizeX, sizeY, variable.wrapS, variable.wrapT, variable.minFilter, variable.magFilter );
+			this.renderTexture( variable.initialValueTexture, variable.renderTargets[ 0 ] );
+			this.renderTexture( variable.initialValueTexture, variable.renderTargets[ 1 ] );
+
+			// Adds dependencies uniforms to the ShaderMaterial
+			var material = variable.material;
+			var uniforms = material.uniforms;
+			if ( variable.dependencies !== null ) {
+
+				for ( var d = 0; d < variable.dependencies.length; d++ ) {
+
+					var depVar = variable.dependencies[ d ];
+
+					if ( depVar.name !== variable.name ) {
+
+						// Checks if variable exists
+						var found = false;
+						for ( var j = 0; j < this.variables.length; j++ ) {
+
+							if ( depVar.name === this.variables[ j ].name ) {
+								found = true;
+								break;
+							}
+
+						}
+						if ( ! found ) {
+							return "Variable dependency not found. Variable=" + variable.name + ", dependency=" + depVar.name;
+						}
+
+					}
+
+					uniforms[ depVar.name ] = { value: null };
+
+					material.fragmentShader = "\nuniform sampler2D " + depVar.name + ";\n" + material.fragmentShader;
+
+				}
+			}
+		}
+
+		this.currentTextureIndex = 0;
+
+		return null;
+
+	};
+
+	this.compute = function() {
+
+		var currentTextureIndex = this.currentTextureIndex;
+		var nextTextureIndex = this.currentTextureIndex === 0 ? 1 : 0;
+
+		for ( var i = 0, il = this.variables.length; i < il; i++ ) {
+
+			var variable = this.variables[ i ];
+
+			// Sets texture dependencies uniforms
+			if ( variable.dependencies !== null ) {
+
+				var uniforms = variable.material.uniforms;
+				for ( var d = 0, dl = variable.dependencies.length; d < dl; d++ ) {
+
+					var depVar = variable.dependencies[ d ];
+
+					uniforms[ depVar.name ].value = depVar.renderTargets[ currentTextureIndex ].texture;
+
+				}
+
+			}
+
+			// Performs the computation for this variable
+			this.doRenderTarget( variable.material, variable.renderTargets[ nextTextureIndex ] );
+
+		}
+
+		this.currentTextureIndex = nextTextureIndex;
+	};
+
+	this.getCurrentRenderTarget = function( variable ) {
+
+		return variable.renderTargets[ this.currentTextureIndex ];
+
+	};
+
+	this.getAlternateRenderTarget = function( variable ) {
+
+		return variable.renderTargets[ this.currentTextureIndex === 0 ? 1 : 0 ];
+
+	};
+
+	function addResolutionDefine( materialShader ) {
+
+		materialShader.defines.resolution = 'vec2( ' + sizeX.toFixed( 1 ) + ', ' + sizeY.toFixed( 1 ) + " )";
+
+	}
+	this.addResolutionDefine = addResolutionDefine;
+
+
+	// The following functions can be used to compute things manually
+
+	function createShaderMaterial( computeFragmentShader, uniforms ) {
+
+		uniforms = uniforms || {};
+
+		var material = new ShaderMaterial( {
+			uniforms: uniforms,
+			vertexShader: getPassThroughVertexShader(),
+			fragmentShader: computeFragmentShader
+		} );
+
+		addResolutionDefine( material );
+
+		return material;
+
+	}
+
+	this.createShaderMaterial = createShaderMaterial;
+
+	this.createRenderTarget = function( sizeXTexture, sizeYTexture, wrapS, wrapT, minFilter, magFilter ) {
+
+		sizeXTexture = sizeXTexture || sizeX;
+		sizeYTexture = sizeYTexture || sizeY;
+
+		wrapS = wrapS || ClampToEdgeWrapping;
+		wrapT = wrapT || ClampToEdgeWrapping;
+
+		minFilter = minFilter || NearestFilter;
+		magFilter = magFilter || NearestFilter;
+
+		var renderTarget = new WebGLRenderTarget( sizeXTexture, sizeYTexture, {
+			wrapS: wrapS,
+			wrapT: wrapT,
+			minFilter: minFilter,
+			magFilter: magFilter,
+			format: RGBAFormat,
+			type: ( /(iPad|iPhone|iPod)/g.test( navigator.userAgent ) ) ? HalfFloatType : FloatType,
+			stencilBuffer: false,
+			depthBuffer: false
+		} );
+
+		return renderTarget;
+
+	};
+
+	this.createTexture = function() {
+
+		var a = new Float32Array( sizeX * sizeY * 4 );
+		var texture = new DataTexture( a, sizeX, sizeY, RGBAFormat, FloatType );
+		texture.needsUpdate = true;
+
+		return texture;
+
+	};
+
+	this.renderTexture = function( input, output ) {
+
+		// Takes a texture, and render out in rendertarget
+		// input = Texture
+		// output = RenderTarget
+
+		passThruUniforms.texture.value = input;
+
+		this.doRenderTarget( passThruShader, output);
+
+		passThruUniforms.texture.value = null;
+
+	};
+
+	this.doRenderTarget = function( material, output ) {
+
+		var currentRenderTarget = renderer.getRenderTarget();
+
+		mesh.material = material;
+		renderer.setRenderTarget( output );
+		renderer.render( scene, camera );
+		mesh.material = passThruShader;
+
+		renderer.setRenderTarget( currentRenderTarget );
+
+	};
+
+	// Shaders
+
+	function getPassThroughVertexShader() {
+
+		return	"void main()	{\n" +
+				"\n" +
+				"	gl_Position = vec4( position, 1.0 );\n" +
+				"\n" +
+				"}\n";
+
+	}
+
+	function getPassThroughFragmentShader() {
+
+		return	"uniform sampler2D texture;\n" +
+				"\n" +
+				"void main() {\n" +
+				"\n" +
+				"	vec2 uv = gl_FragCoord.xy / resolution.xy;\n" +
+				"\n" +
+				"	gl_FragColor = texture2D( texture, uv );\n" +
+				"\n" +
+				"}\n";
+
+	}
+
+};
+
+export { GPUComputationRenderer };

+ 7 - 0
examples/jsm/misc/Gyroscope.d.ts

@@ -0,0 +1,7 @@
+import {
+  Object3D
+} from '../../../src/Three';
+
+export class Gyroscope extends Object3D {
+  constructor();
+}

+ 73 - 0
examples/jsm/misc/Gyroscope.js

@@ -0,0 +1,73 @@
+/**
+ * @author alteredq / http://alteredqualia.com/
+ */
+
+import {
+	Object3D,
+	Quaternion,
+	Vector3
+} from "../../../build/three.module.js";
+
+var Gyroscope = function () {
+
+	Object3D.call( this );
+
+};
+
+Gyroscope.prototype = Object.create( Object3D.prototype );
+Gyroscope.prototype.constructor = Gyroscope;
+
+Gyroscope.prototype.updateMatrixWorld = ( function () {
+
+	var translationObject = new Vector3();
+	var quaternionObject = new Quaternion();
+	var scaleObject = new Vector3();
+
+	var translationWorld = new Vector3();
+	var quaternionWorld = new Quaternion();
+	var scaleWorld = new Vector3();
+
+	return function updateMatrixWorld( force ) {
+
+		this.matrixAutoUpdate && this.updateMatrix();
+
+		// update matrixWorld
+
+		if ( this.matrixWorldNeedsUpdate || force ) {
+
+			if ( this.parent !== null ) {
+
+				this.matrixWorld.multiplyMatrices( this.parent.matrixWorld, this.matrix );
+
+				this.matrixWorld.decompose( translationWorld, quaternionWorld, scaleWorld );
+				this.matrix.decompose( translationObject, quaternionObject, scaleObject );
+
+				this.matrixWorld.compose( translationWorld, quaternionObject, scaleWorld );
+
+
+			} else {
+
+				this.matrixWorld.copy( this.matrix );
+
+			}
+
+
+			this.matrixWorldNeedsUpdate = false;
+
+			force = true;
+
+		}
+
+		// update children
+
+		for ( var i = 0, l = this.children.length; i < l; i ++ ) {
+
+			this.children[ i ].updateMatrixWorld( force );
+
+		}
+
+	};
+
+}() );
+
+export { Gyroscope };

+ 24 - 0
examples/jsm/misc/MD2Character.d.ts

@@ -0,0 +1,24 @@
+import {
+  Object3D,
+  Mesh,
+  Texture
+} from '../../../src/Three';
+
+export class MD2Character {
+  constructor();
+  scale: number;
+  animationFPS: number;
+  root: Object3D;
+  meshBody: Mesh | null;
+  meshWeapon: Mesh | null;
+  skinsBody: Texture[];
+  skinsWeapon: Texture[];
+
+  setPlaybackRate(rate: number): void;
+  setWireframe(wireframeEnabled: boolean): void;
+  setSkin(index: number): void;
+  setWeapon(index: number): void;
+  setAnimation(clipName: string): void;
+  syncWeaponAnimation(): void;
+  update(delta: number): void;
+}

+ 274 - 0
examples/jsm/misc/MD2Character.js

@@ -0,0 +1,274 @@
+/**
+ * @author alteredq / http://alteredqualia.com/
+ */
+
+import {
+	AnimationMixer,
+	Box3,
+	Mesh,
+	MeshLambertMaterial,
+	Object3D,
+	TextureLoader,
+	UVMapping
+} from "../../../build/three.module.js";
+import { MD2Loader } from "../loaders/MD2Loader.js";
+
+var MD2Character = function () {
+
+	var scope = this;
+
+	this.scale = 1;
+	this.animationFPS = 6;
+
+	this.root = new Object3D();
+
+	this.meshBody = null;
+	this.meshWeapon = null;
+
+	this.skinsBody = [];
+	this.skinsWeapon = [];
+
+	this.weapons = [];
+
+	this.activeAnimation = null;
+
+	this.mixer = null;
+
+	this.onLoadComplete = function () {};
+
+	this.loadCounter = 0;
+
+	this.loadParts = function ( config ) {
+
+		this.loadCounter = config.weapons.length * 2 + config.skins.length + 1;
+
+		var weaponsTextures = [];
+		for ( var i = 0; i < config.weapons.length; i ++ ) weaponsTextures[ i ] = config.weapons[ i ][ 1 ];
+		// SKINS
+
+		this.skinsBody = loadTextures( config.baseUrl + "skins/", config.skins );
+		this.skinsWeapon = loadTextures( config.baseUrl + "skins/", weaponsTextures );
+
+		// BODY
+
+		var loader = new MD2Loader();
+
+		loader.load( config.baseUrl + config.body, function ( geo ) {
+
+			var boundingBox = new Box3();
+			boundingBox.setFromBufferAttribute( geo.attributes.position );
+
+			scope.root.position.y = - scope.scale * boundingBox.min.y;
+
+			var mesh = createPart( geo, scope.skinsBody[ 0 ] );
+			mesh.scale.set( scope.scale, scope.scale, scope.scale );
+
+			scope.root.add( mesh );
+
+			scope.meshBody = mesh;
+
+			scope.meshBody.clipOffset = 0;
+			scope.activeAnimationClipName = mesh.geometry.animations[ 0 ].name;
+
+			scope.mixer = new AnimationMixer( mesh );
+
+			checkLoadingComplete();
+
+		} );
+
+		// WEAPONS
+
+		var generateCallback = function ( index, name ) {
+
+			return function ( geo ) {
+
+				var mesh = createPart( geo, scope.skinsWeapon[ index ] );
+				mesh.scale.set( scope.scale, scope.scale, scope.scale );
+				mesh.visible = false;
+
+				mesh.name = name;
+
+				scope.root.add( mesh );
+
+				scope.weapons[ index ] = mesh;
+				scope.meshWeapon = mesh;
+
+				checkLoadingComplete();
+
+			};
+
+		};
+
+		for ( var i = 0; i < config.weapons.length; i ++ ) {
+
+			loader.load( config.baseUrl + config.weapons[ i ][ 0 ], generateCallback( i, config.weapons[ i ][ 0 ] ) );
+
+		}
+
+	};
+
+	this.setPlaybackRate = function ( rate ) {
+
+		if ( rate !== 0 ) {
+
+			this.mixer.timeScale = 1 / rate;
+
+		} else {
+
+			this.mixer.timeScale = 0;
+
+		}
+
+	};
+
+	this.setWireframe = function ( wireframeEnabled ) {
+
+		if ( wireframeEnabled ) {
+
+			if ( this.meshBody ) this.meshBody.material = this.meshBody.materialWireframe;
+			if ( this.meshWeapon ) this.meshWeapon.material = this.meshWeapon.materialWireframe;
+
+		} else {
+
+			if ( this.meshBody ) this.meshBody.material = this.meshBody.materialTexture;
+			if ( this.meshWeapon ) this.meshWeapon.material = this.meshWeapon.materialTexture;
+
+		}
+
+	};
+
+	this.setSkin = function ( index ) {
+
+		if ( this.meshBody && this.meshBody.material.wireframe === false ) {
+
+			this.meshBody.material.map = this.skinsBody[ index ];
+
+		}
+
+	};
+
+	this.setWeapon = function ( index ) {
+
+		for ( var i = 0; i < this.weapons.length; i ++ ) this.weapons[ i ].visible = false;
+
+		var activeWeapon = this.weapons[ index ];
+
+		if ( activeWeapon ) {
+
+			activeWeapon.visible = true;
+			this.meshWeapon = activeWeapon;
+
+			scope.syncWeaponAnimation();
+
+		}
+
+	};
+
+	this.setAnimation = function ( clipName ) {
+
+		if ( this.meshBody ) {
+
+			if ( this.meshBody.activeAction ) {
+
+				this.meshBody.activeAction.stop();
+				this.meshBody.activeAction = null;
+
+			}
+
+			var action = this.mixer.clipAction( clipName, this.meshBody );
+
+			if ( action ) {
+
+				this.meshBody.activeAction = action.play();
+
+			}
+
+		}
+
+		scope.activeClipName = clipName;
+
+		scope.syncWeaponAnimation();
+
+	};
+
+	this.syncWeaponAnimation = function () {
+
+		var clipName = scope.activeClipName;
+
+		if ( scope.meshWeapon ) {
+
+			if ( this.meshWeapon.activeAction ) {
+
+				this.meshWeapon.activeAction.stop();
+				this.meshWeapon.activeAction = null;
+
+			}
+
+			var action = this.mixer.clipAction( clipName, this.meshWeapon );
+
+			if ( action ) {
+
+				this.meshWeapon.activeAction = action.syncWith( this.meshBody.activeAction ).play();
+
+			}
+
+		}
+
+	};
+
+	this.update = function ( delta ) {
+
+		if ( this.mixer ) this.mixer.update( delta );
+
+	};
+
+	function loadTextures( baseUrl, textureUrls ) {
+
+		var textureLoader = new TextureLoader();
+		var textures = [];
+
+		for ( var i = 0; i < textureUrls.length; i ++ ) {
+
+			textures[ i ] = textureLoader.load( baseUrl + textureUrls[ i ], checkLoadingComplete );
+			textures[ i ].mapping = UVMapping;
+			textures[ i ].name = textureUrls[ i ];
+
+		}
+
+		return textures;
+
+	}
+
+	function createPart( geometry, skinMap ) {
+
+		var materialWireframe = new MeshLambertMaterial( { color: 0xffaa00, wireframe: true, morphTargets: true, morphNormals: true } );
+		var materialTexture = new MeshLambertMaterial( { color: 0xffffff, wireframe: false, map: skinMap, morphTargets: true, morphNormals: true } );
+
+		//
+
+		var mesh = new Mesh( geometry, materialTexture );
+		mesh.rotation.y = - Math.PI / 2;
+
+		mesh.castShadow = true;
+		mesh.receiveShadow = true;
+
+		//
+
+		mesh.materialTexture = materialTexture;
+		mesh.materialWireframe = materialWireframe;
+
+		return mesh;
+
+	}
+
+	function checkLoadingComplete() {
+
+		scope.loadCounter -= 1;
+
+		if ( scope.loadCounter === 0 ) scope.onLoadComplete();
+
+	}
+
+};
+
+export { MD2Character };

+ 51 - 0
examples/jsm/misc/MD2CharacterComplex.d.ts

@@ -0,0 +1,51 @@
+import {
+  Object3D,
+  Mesh,
+  Texture
+} from '../../../src/Three';
+
+export class MD2CharacterComplex {
+  constructor();
+  scale: number;
+  animationFPS: number;
+  transitionFrames: number;
+  maxSpeed: number;
+  maxReverseSpeed: number;
+  frontAcceleration: number;
+  backAcceleration: number;
+  frontDecceleration: number;
+  angularSpeed: number;
+  root: Object3D;
+  meshBody: Mesh | null;
+  meshWeapon: Mesh | null;
+  controls: null;
+  skinsBody: Texture[];
+  skinsWeapon: Texture[];
+  weapons: Mesh[];
+  currentSkin: number;
+  onLoadComplete: () => void;
+
+  meshes: Mesh[];
+  animations: object[];
+  loadCounter: number;
+  speed: number;
+  bodyOrientation: number;
+  walkSpeed: number;
+  crouchSpeed: number;
+  activeAnimation: string;
+  oldAnimation: string;
+
+  enableShadows(enable: boolean): void;
+  setVisible(enable: boolean): void;
+  shareParts(original: MD2CharacterComplex): void;
+  loadParts(config: object): void;
+  setPlaybackRate(rate: number): void;
+  setWireframe(wireframeEnabled: boolean): void;
+  setSkin(index: number): void;
+  setWeapon(index: number): void;
+  setAnimation(animationName: string): void;
+  update(delta: number): void;
+  updateAnimations(delta: number): void;
+  updateBehaviors(): void;
+  updateMovementModel(delta: number): void;
+}

+ 575 - 0
examples/jsm/misc/MD2CharacterComplex.js

@@ -0,0 +1,575 @@
+/**
+ * @author alteredq / http://alteredqualia.com/
+ */
+
+import {
+	Box3,
+	Math as _Math,
+	MeshLambertMaterial,
+	Object3D,
+	TextureLoader,
+	UVMapping
+} from "../../../build/three.module.js";
+import { MD2Loader } from "../loaders/MD2Loader.js";
+import { MorphBlendMesh } from "../misc/MorphBlendMesh.js";
+
+var MD2CharacterComplex = function () {
+
+	var scope = this;
+
+	this.scale = 1;
+
+	// animation parameters
+
+	this.animationFPS = 6;
+	this.transitionFrames = 15;
+
+	// movement model parameters
+
+	this.maxSpeed = 275;
+	this.maxReverseSpeed = - 275;
+
+	this.frontAcceleration = 600;
+	this.backAcceleration = 600;
+
+	this.frontDecceleration = 600;
+
+	this.angularSpeed = 2.5;
+
+	// rig
+
+	this.root = new Object3D();
+
+	this.meshBody = null;
+	this.meshWeapon = null;
+
+	this.controls = null;
+
+	// skins
+
+	this.skinsBody = [];
+	this.skinsWeapon = [];
+
+	this.weapons = [];
+
+	this.currentSkin = undefined;
+
+	//
+
+	this.onLoadComplete = function () {};
+
+	// internals
+
+	this.meshes = [];
+	this.animations = {};
+
+	this.loadCounter = 0;
+
+	// internal movement control variables
+
+	this.speed = 0;
+	this.bodyOrientation = 0;
+
+	this.walkSpeed = this.maxSpeed;
+	this.crouchSpeed = this.maxSpeed * 0.5;
+
+	// internal animation parameters
+
+	this.activeAnimation = null;
+	this.oldAnimation = null;
+
+	// API
+
+	this.enableShadows = function ( enable ) {
+
+		for ( var i = 0; i < this.meshes.length; i ++ ) {
+
+			this.meshes[ i ].castShadow = enable;
+			this.meshes[ i ].receiveShadow = enable;
+
+		}
+
+	};
+
+	this.setVisible = function ( enable ) {
+
+		for ( var i = 0; i < this.meshes.length; i ++ ) {
+
+			this.meshes[ i ].visible = enable;
+			this.meshes[ i ].visible = enable;
+
+		}
+
+	};
+
+
+	this.shareParts = function ( original ) {
+
+		this.animations = original.animations;
+		this.walkSpeed = original.walkSpeed;
+		this.crouchSpeed = original.crouchSpeed;
+
+		this.skinsBody = original.skinsBody;
+		this.skinsWeapon = original.skinsWeapon;
+
+		// BODY
+
+		var mesh = createPart( original.meshBody.geometry, this.skinsBody[ 0 ] );
+		mesh.scale.set( this.scale, this.scale, this.scale );
+
+		this.root.position.y = original.root.position.y;
+		this.root.add( mesh );
+
+		this.meshBody = mesh;
+
+		this.meshes.push( mesh );
+
+		// WEAPONS
+
+		for ( var i = 0; i < original.weapons.length; i ++ ) {
+
+			var meshWeapon = createPart( original.weapons[ i ].geometry, this.skinsWeapon[ i ] );
+			meshWeapon.scale.set( this.scale, this.scale, this.scale );
+			meshWeapon.visible = false;
+
+			meshWeapon.name = original.weapons[ i ].name;
+
+			this.root.add( meshWeapon );
+
+			this.weapons[ i ] = meshWeapon;
+			this.meshWeapon = meshWeapon;
+
+			this.meshes.push( meshWeapon );
+
+		}
+
+	};
+
+	this.loadParts = function ( config ) {
+
+		this.animations = config.animations;
+		this.walkSpeed = config.walkSpeed;
+		this.crouchSpeed = config.crouchSpeed;
+
+		this.loadCounter = config.weapons.length * 2 + config.skins.length + 1;
+
+		var weaponsTextures = [];
+		for ( var i = 0; i < config.weapons.length; i ++ ) weaponsTextures[ i ] = config.weapons[ i ][ 1 ];
+
+		// SKINS
+
+		this.skinsBody = loadTextures( config.baseUrl + "skins/", config.skins );
+		this.skinsWeapon = loadTextures( config.baseUrl + "skins/", weaponsTextures );
+
+		// BODY
+
+		var loader = new MD2Loader();
+
+		loader.load( config.baseUrl + config.body, function ( geo ) {
+
+			var boundingBox = new Box3();
+			boundingBox.setFromBufferAttribute( geo.attributes.position );
+
+			scope.root.position.y = - scope.scale * boundingBox.min.y;
+
+			var mesh = createPart( geo, scope.skinsBody[ 0 ] );
+			mesh.scale.set( scope.scale, scope.scale, scope.scale );
+
+			scope.root.add( mesh );
+
+			scope.meshBody = mesh;
+			scope.meshes.push( mesh );
+
+			checkLoadingComplete();
+
+		} );
+
+		// WEAPONS
+
+		var generateCallback = function ( index, name ) {
+
+			return function ( geo ) {
+
+				var mesh = createPart( geo, scope.skinsWeapon[ index ] );
+				mesh.scale.set( scope.scale, scope.scale, scope.scale );
+				mesh.visible = false;
+
+				mesh.name = name;
+
+				scope.root.add( mesh );
+
+				scope.weapons[ index ] = mesh;
+				scope.meshWeapon = mesh;
+				scope.meshes.push( mesh );
+
+				checkLoadingComplete();
+
+			};
+
+		};
+
+		for ( var i = 0; i < config.weapons.length; i ++ ) {
+
+			loader.load( config.baseUrl + config.weapons[ i ][ 0 ], generateCallback( i, config.weapons[ i ][ 0 ] ) );
+
+		}
+
+	};
+
+	this.setPlaybackRate = function ( rate ) {
+
+		if ( this.meshBody ) this.meshBody.duration = this.meshBody.baseDuration / rate;
+		if ( this.meshWeapon ) this.meshWeapon.duration = this.meshWeapon.baseDuration / rate;
+
+	};
+
+	this.setWireframe = function ( wireframeEnabled ) {
+
+		if ( wireframeEnabled ) {
+
+			if ( this.meshBody ) this.meshBody.material = this.meshBody.materialWireframe;
+			if ( this.meshWeapon ) this.meshWeapon.material = this.meshWeapon.materialWireframe;
+
+		} else {
+
+			if ( this.meshBody ) this.meshBody.material = this.meshBody.materialTexture;
+			if ( this.meshWeapon ) this.meshWeapon.material = this.meshWeapon.materialTexture;
+
+		}
+
+	};
+
+	this.setSkin = function ( index ) {
+
+		if ( this.meshBody && this.meshBody.material.wireframe === false ) {
+
+			this.meshBody.material.map = this.skinsBody[ index ];
+			this.currentSkin = index;
+
+		}
+
+	};
+
+	this.setWeapon = function ( index ) {
+
+		for ( var i = 0; i < this.weapons.length; i ++ ) this.weapons[ i ].visible = false;
+
+		var activeWeapon = this.weapons[ index ];
+
+		if ( activeWeapon ) {
+
+			activeWeapon.visible = true;
+			this.meshWeapon = activeWeapon;
+
+			if ( this.activeAnimation ) {
+
+				activeWeapon.playAnimation( this.activeAnimation );
+				this.meshWeapon.setAnimationTime( this.activeAnimation, this.meshBody.getAnimationTime( this.activeAnimation ) );
+
+			}
+
+		}
+
+	};
+
+	this.setAnimation = function ( animationName ) {
+
+		if ( animationName === this.activeAnimation || ! animationName ) return;
+
+		if ( this.meshBody ) {
+
+			this.meshBody.setAnimationWeight( animationName, 0 );
+			this.meshBody.playAnimation( animationName );
+
+			this.oldAnimation = this.activeAnimation;
+			this.activeAnimation = animationName;
+
+			this.blendCounter = this.transitionFrames;
+
+		}
+
+		if ( this.meshWeapon ) {
+
+			this.meshWeapon.setAnimationWeight( animationName, 0 );
+			this.meshWeapon.playAnimation( animationName );
+
+		}
+
+
+	};
+
+	this.update = function ( delta ) {
+
+		if ( this.controls ) this.updateMovementModel( delta );
+
+		if ( this.animations ) {
+
+			this.updateBehaviors();
+			this.updateAnimations( delta );
+
+		}
+
+	};
+
+	this.updateAnimations = function ( delta ) {
+
+		var mix = 1;
+
+		if ( this.blendCounter > 0 ) {
+
+			mix = ( this.transitionFrames - this.blendCounter ) / this.transitionFrames;
+			this.blendCounter -= 1;
+
+		}
+
+		if ( this.meshBody ) {
+
+			this.meshBody.update( delta );
+
+			this.meshBody.setAnimationWeight( this.activeAnimation, mix );
+			this.meshBody.setAnimationWeight( this.oldAnimation, 1 - mix );
+
+		}
+
+		if ( this.meshWeapon ) {
+
+			this.meshWeapon.update( delta );
+
+			this.meshWeapon.setAnimationWeight( this.activeAnimation, mix );
+			this.meshWeapon.setAnimationWeight( this.oldAnimation, 1 - mix );
+
+		}
+
+	};
+
+	this.updateBehaviors = function () {
+
+		var controls = this.controls;
+		var animations = this.animations;
+
+		var moveAnimation, idleAnimation;
+
+		// crouch vs stand
+
+		if ( controls.crouch ) {
+
+			moveAnimation = animations[ "crouchMove" ];
+			idleAnimation = animations[ "crouchIdle" ];
+
+		} else {
+
+			moveAnimation = animations[ "move" ];
+			idleAnimation = animations[ "idle" ];
+
+		}
+
+		// actions
+
+		if ( controls.jump ) {
+
+			moveAnimation = animations[ "jump" ];
+			idleAnimation = animations[ "jump" ];
+
+		}
+
+		if ( controls.attack ) {
+
+			if ( controls.crouch ) {
+
+				moveAnimation = animations[ "crouchAttack" ];
+				idleAnimation = animations[ "crouchAttack" ];
+
+			} else {
+
+				moveAnimation = animations[ "attack" ];
+				idleAnimation = animations[ "attack" ];
+
+			}
+
+		}
+
+		// set animations
+
+		if ( controls.moveForward || controls.moveBackward || controls.moveLeft || controls.moveRight ) {
+
+			if ( this.activeAnimation !== moveAnimation ) {
+
+				this.setAnimation( moveAnimation );
+
+			}
+
+		}
+
+
+		if ( Math.abs( this.speed ) < 0.2 * this.maxSpeed && ! ( controls.moveLeft || controls.moveRight || controls.moveForward || controls.moveBackward ) ) {
+
+			if ( this.activeAnimation !== idleAnimation ) {
+
+				this.setAnimation( idleAnimation );
+
+			}
+
+		}
+
+		// set animation direction
+
+		if ( controls.moveForward ) {
+
+			if ( this.meshBody ) {
+
+				this.meshBody.setAnimationDirectionForward( this.activeAnimation );
+				this.meshBody.setAnimationDirectionForward( this.oldAnimation );
+
+			}
+
+			if ( this.meshWeapon ) {
+
+				this.meshWeapon.setAnimationDirectionForward( this.activeAnimation );
+				this.meshWeapon.setAnimationDirectionForward( this.oldAnimation );
+
+			}
+
+		}
+
+		if ( controls.moveBackward ) {
+
+			if ( this.meshBody ) {
+
+				this.meshBody.setAnimationDirectionBackward( this.activeAnimation );
+				this.meshBody.setAnimationDirectionBackward( this.oldAnimation );
+
+			}
+
+			if ( this.meshWeapon ) {
+
+				this.meshWeapon.setAnimationDirectionBackward( this.activeAnimation );
+				this.meshWeapon.setAnimationDirectionBackward( this.oldAnimation );
+
+			}
+
+		}
+
+	};
+
+	this.updateMovementModel = function ( delta ) {
+
+		var controls = this.controls;
+
+		// speed based on controls
+
+		if ( controls.crouch ) 	this.maxSpeed = this.crouchSpeed;
+		else this.maxSpeed = this.walkSpeed;
+
+		this.maxReverseSpeed = - this.maxSpeed;
+
+		if ( controls.moveForward ) this.speed = _Math.clamp( this.speed + delta * this.frontAcceleration, this.maxReverseSpeed, this.maxSpeed );
+		if ( controls.moveBackward ) this.speed = _Math.clamp( this.speed - delta * this.backAcceleration, this.maxReverseSpeed, this.maxSpeed );
+
+		// orientation based on controls
+		// (don't just stand while turning)
+
+		var dir = 1;
+
+		if ( controls.moveLeft ) {
+
+			this.bodyOrientation += delta * this.angularSpeed;
+			this.speed = _Math.clamp( this.speed + dir * delta * this.frontAcceleration, this.maxReverseSpeed, this.maxSpeed );
+
+		}
+
+		if ( controls.moveRight ) {
+
+			this.bodyOrientation -= delta * this.angularSpeed;
+			this.speed = _Math.clamp( this.speed + dir * delta * this.frontAcceleration, this.maxReverseSpeed, this.maxSpeed );
+
+		}
+
+		// speed decay
+
+		if ( ! ( controls.moveForward || controls.moveBackward ) ) {
+
+			if ( this.speed > 0 ) {
+
+				var k = exponentialEaseOut( this.speed / this.maxSpeed );
+				this.speed = _Math.clamp( this.speed - k * delta * this.frontDecceleration, 0, this.maxSpeed );
+
+			} else {
+
+				var k = exponentialEaseOut( this.speed / this.maxReverseSpeed );
+				this.speed = _Math.clamp( this.speed + k * delta * this.backAcceleration, this.maxReverseSpeed, 0 );
+
+			}
+
+		}
+
+		// displacement
+
+		var forwardDelta = this.speed * delta;
+
+		this.root.position.x += Math.sin( this.bodyOrientation ) * forwardDelta;
+		this.root.position.z += Math.cos( this.bodyOrientation ) * forwardDelta;
+
+		// steering
+
+		this.root.rotation.y = this.bodyOrientation;
+
+	};
+
+	// internal helpers
+
+	function loadTextures( baseUrl, textureUrls ) {
+
+		var textureLoader = new TextureLoader();
+		var textures = [];
+
+		for ( var i = 0; i < textureUrls.length; i ++ ) {
+
+			textures[ i ] = textureLoader.load( baseUrl + textureUrls[ i ], checkLoadingComplete );
+			textures[ i ].mapping = UVMapping;
+			textures[ i ].name = textureUrls[ i ];
+
+		}
+
+		return textures;
+
+	}
+
+	function createPart( geometry, skinMap ) {
+
+		var materialWireframe = new MeshLambertMaterial( { color: 0xffaa00, wireframe: true, morphTargets: true, morphNormals: true } );
+		var materialTexture = new MeshLambertMaterial( { color: 0xffffff, wireframe: false, map: skinMap, morphTargets: true, morphNormals: true } );
+
+		//
+
+		var mesh = new MorphBlendMesh( geometry, materialTexture );
+		mesh.rotation.y = - Math.PI / 2;
+
+		//
+
+		mesh.materialTexture = materialTexture;
+		mesh.materialWireframe = materialWireframe;
+
+		//
+
+		mesh.autoCreateAnimations( scope.animationFPS );
+
+		return mesh;
+
+	}
+
+	function checkLoadingComplete() {
+
+		scope.loadCounter -= 1;
+		if ( scope.loadCounter === 0 ) 	scope.onLoadComplete();
+
+	}
+
+	function exponentialEaseOut( k ) {
+
+		return k === 1 ? 1 : - Math.pow( 2, - 10 * k ) + 1;
+
+	}
+
+};
+
+export { MD2CharacterComplex };

+ 26 - 0
examples/jsm/misc/MorphBlendMesh.d.ts

@@ -0,0 +1,26 @@
+import {
+  BufferGeometry,
+  Geometry,
+  Material,
+  Mesh
+} from '../../../src/Three';
+
+export class MorphBlendMesh extends Mesh {
+  constructor(geometry: BufferGeometry | Geometry, material: Material);
+  animationsMap: object;
+  animationsList: object[];
+
+  createAnimation(name: string, start: number, end: number, fps: number): void;
+  autoCreateAnimations(fps: number): void;
+  setAnimationDirectionForward(name: string): void;
+  setAnimationDirectionBackward(name: string): void;
+  setAnimationFPS(name: string, fps: number): void;
+  setAnimationDuration(name: string, duration: number): void;
+  setAnimationWeight(name: string, weight: number): void;
+  setAnimationTime(name: string, time: number): void;
+  getAnimationTime(name: string): number;
+  getAnimationDuration(name: string): number;
+  playAnimation(name: string): void;
+  stopAnimation(name: string): void;
+  update(delta: number): void;
+}

+ 326 - 0
examples/jsm/misc/MorphBlendMesh.js

@@ -0,0 +1,326 @@
+/**
+ * @author alteredq / http://alteredqualia.com/
+ */
+
+import {
+	Math as _Math,
+	Mesh
+} from "../../../build/three.module.js";
+
+var MorphBlendMesh = function ( geometry, material ) {
+
+	Mesh.call( this, geometry, material );
+
+	this.animationsMap = {};
+	this.animationsList = [];
+
+	// prepare default animation
+	// (all frames played together in 1 second)
+
+	var numFrames = Object.keys( this.morphTargetDictionary ).length;
+
+	var name = '__default';
+
+	var startFrame = 0;
+	var endFrame = numFrames - 1;
+
+	var fps = numFrames / 1;
+
+	this.createAnimation( name, startFrame, endFrame, fps );
+	this.setAnimationWeight( name, 1 );
+
+};
+
+MorphBlendMesh.prototype = Object.assign( Object.create( Mesh.prototype ), {
+
+	constructor: MorphBlendMesh,
+
+	createAnimation: function ( name, start, end, fps ) {
+
+		var animation = {
+
+			start: start,
+			end: end,
+
+			length: end - start + 1,
+
+			fps: fps,
+			duration: ( end - start ) / fps,
+
+			lastFrame: 0,
+			currentFrame: 0,
+
+			active: false,
+
+			time: 0,
+			direction: 1,
+			weight: 1,
+
+			directionBackwards: false,
+			mirroredLoop: false
+
+		};
+
+		this.animationsMap[ name ] = animation;
+		this.animationsList.push( animation );
+
+	},
+
+	autoCreateAnimations: function ( fps ) {
+
+		var pattern = /([a-z]+)_?(\d+)/i;
+
+		var firstAnimation, frameRanges = {};
+
+		var i = 0;
+
+		for ( var key in this.morphTargetDictionary ) {
+
+			var chunks = key.match( pattern );
+
+			if ( chunks && chunks.length > 1 ) {
+
+				var name = chunks[ 1 ];
+
+				if ( ! frameRanges[ name ] ) frameRanges[ name ] = { start: Infinity, end: - Infinity };
+
+				var range = frameRanges[ name ];
+
+				if ( i < range.start ) range.start = i;
+				if ( i > range.end ) range.end = i;
+
+				if ( ! firstAnimation ) firstAnimation = name;
+
+			}
+
+			i ++;
+
+		}
+
+		for ( var name in frameRanges ) {
+
+			var range = frameRanges[ name ];
+			this.createAnimation( name, range.start, range.end, fps );
+
+		}
+
+		this.firstAnimation = firstAnimation;
+
+	},
+
+	setAnimationDirectionForward: function ( name ) {
+
+		var animation = this.animationsMap[ name ];
+
+		if ( animation ) {
+
+			animation.direction = 1;
+			animation.directionBackwards = false;
+
+		}
+
+	},
+
+	setAnimationDirectionBackward: function ( name ) {
+
+		var animation = this.animationsMap[ name ];
+
+		if ( animation ) {
+
+			animation.direction = - 1;
+			animation.directionBackwards = true;
+
+		}
+
+	},
+
+	setAnimationFPS: function ( name, fps ) {
+
+		var animation = this.animationsMap[ name ];
+
+		if ( animation ) {
+
+			animation.fps = fps;
+			animation.duration = ( animation.end - animation.start ) / animation.fps;
+
+		}
+
+	},
+
+	setAnimationDuration: function ( name, duration ) {
+
+		var animation = this.animationsMap[ name ];
+
+		if ( animation ) {
+
+			animation.duration = duration;
+			animation.fps = ( animation.end - animation.start ) / animation.duration;
+
+		}
+
+	},
+
+	setAnimationWeight: function ( name, weight ) {
+
+		var animation = this.animationsMap[ name ];
+
+		if ( animation ) {
+
+			animation.weight = weight;
+
+		}
+
+	},
+
+	setAnimationTime: function ( name, time ) {
+
+		var animation = this.animationsMap[ name ];
+
+		if ( animation ) {
+
+			animation.time = time;
+
+		}
+
+	},
+
+	getAnimationTime: function ( name ) {
+
+		var time = 0;
+
+		var animation = this.animationsMap[ name ];
+
+		if ( animation ) {
+
+			time = animation.time;
+
+		}
+
+		return time;
+
+	},
+
+	getAnimationDuration: function ( name ) {
+
+		var duration = - 1;
+
+		var animation = this.animationsMap[ name ];
+
+		if ( animation ) {
+
+			duration = animation.duration;
+
+		}
+
+		return duration;
+
+	},
+
+	playAnimation: function ( name ) {
+
+		var animation = this.animationsMap[ name ];
+
+		if ( animation ) {
+
+			animation.time = 0;
+			animation.active = true;
+
+		} else {
+
+			console.warn( "MorphBlendMesh: animation[" + name + "] undefined in .playAnimation()" );
+
+		}
+
+	},
+
+	stopAnimation: function ( name ) {
+
+		var animation = this.animationsMap[ name ];
+
+		if ( animation ) {
+
+			animation.active = false;
+
+		}
+
+	},
+
+	update: function ( delta ) {
+
+		for ( var i = 0, il = this.animationsList.length; i < il; i ++ ) {
+
+			var animation = this.animationsList[ i ];
+
+			if ( ! animation.active ) continue;
+
+			var frameTime = animation.duration / animation.length;
+
+			animation.time += animation.direction * delta;
+
+			if ( animation.mirroredLoop ) {
+
+				if ( animation.time > animation.duration || animation.time < 0 ) {
+
+					animation.direction *= - 1;
+
+					if ( animation.time > animation.duration ) {
+
+						animation.time = animation.duration;
+						animation.directionBackwards = true;
+
+					}
+
+					if ( animation.time < 0 ) {
+
+						animation.time = 0;
+						animation.directionBackwards = false;
+
+					}
+
+				}
+
+			} else {
+
+				animation.time = animation.time % animation.duration;
+
+				if ( animation.time < 0 ) animation.time += animation.duration;
+
+			}
+
+			var keyframe = animation.start + _Math.clamp( Math.floor( animation.time / frameTime ), 0, animation.length - 1 );
+			var weight = animation.weight;
+
+			if ( keyframe !== animation.currentFrame ) {
+
+				this.morphTargetInfluences[ animation.lastFrame ] = 0;
+				this.morphTargetInfluences[ animation.currentFrame ] = 1 * weight;
+
+				this.morphTargetInfluences[ keyframe ] = 0;
+
+				animation.lastFrame = animation.currentFrame;
+				animation.currentFrame = keyframe;
+
+			}
+
+			var mix = ( animation.time % frameTime ) / frameTime;
+
+			if ( animation.directionBackwards ) mix = 1 - mix;
+
+			if ( animation.currentFrame !== animation.lastFrame ) {
+
+				this.morphTargetInfluences[ animation.currentFrame ] = mix * weight;
+				this.morphTargetInfluences[ animation.lastFrame ] = ( 1 - mix ) * weight;
+
+			} else {
+
+				this.morphTargetInfluences[ animation.currentFrame ] = weight;
+
+			}
+
+		}
+
+	}
+
+} );
+
+export { MorphBlendMesh };

+ 35 - 0
examples/jsm/objects/LightningStorm.d.ts

@@ -0,0 +1,35 @@
+import {
+  Material,
+  Vector3
+} from '../../../src/Three';
+
+import { LightningStrike, RayParameters } from '../geometries/LightningStrike';
+
+export interface StormParams {
+  size?: number;
+  minHeight?: number;
+  maxHeight?: number;
+  maxSlope?: number;
+
+  maxLightnings?: number;
+
+  lightningMinPeriod?: number;
+  lightningMaxPeriod?: number;
+  lightningMinDuration?: number;
+  lightningMaxDuration?: number;
+
+  lightningParameters?: RayParameters;
+  lightningMaterial?: Material;
+
+  isEternal?: boolean;
+
+  onRayPosition?: (source: Vector3, dest: Vector3) => void;
+  onLightningDown?: (lightning: LightningStrike) => void;
+}
+
+export class LightningStorm {
+  constructor(stormParams?: StormParams);
+  update(time: number): void;
+  copy(source: LightningStorm): LightningStorm;
+  clone(): LightningStorm;
+}

+ 249 - 0
examples/jsm/objects/LightningStorm.js

@@ -0,0 +1,249 @@
+/**
+ * @author yomboprime https://github.com/yomboprime
+ *
+ * @fileoverview Lightning strike object generator
+ *
+ *
+ * Usage
+ *
+ * var myStorm = new LightningStorm( paramsObject );
+ * myStorm.position.set( ... );
+ * scene.add( myStorm );
+ * ...
+ * myStorm.update( currentTime );
+ *
+ * The "currentTime" can only go forwards or be stopped.
+ *
+ *
+ * LightningStorm parameters:
+ *
+ * @param {double} size Size of the storm. If no 'onRayPosition' parameter is defined, it means the side of the rectangle the storm covers.
+ *
+ * @param {double} minHeight Minimum height a ray can start at. If no 'onRayPosition' parameter is defined, it means the height above plane y = 0.
+ *
+ * @param {double} maxHeight Maximum height a ray can start at. If no 'onRayPosition' parameter is defined, it means the height above plane y = 0.
+ *
+ * @param {double} maxSlope The maximum inclination slope of a ray. If no 'onRayPosition' parameter is defined, it means the slope relative to plane y = 0.
+ *
+ * @param {integer} maxLightnings Greater than 0. The maximum number of simultaneous rays.
+ *
+ * @param {double} lightningMinPeriod minimum time between two consecutive rays.
+ *
+ * @param {double} lightningMaxPeriod maximum time between two consecutive rays.
+ *
+ * @param {double} lightningMinDuration The minimum time a ray can last.
+ *
+ * @param {double} lightningMaxDuration The maximum time a ray can last.
+ *
+ * @param {Object} lightningParameters The parameters for created rays. See LightningStrike (geometry)
+ *
+ * @param {Material} lightningMaterial The Material used for the created rays.
+ *
+ * @param {function} onRayPosition Optional callback with two Vector3 parameters (source, dest). You can set here the start and end points for each created ray, using the standard size, minHeight, etc parameters and other values in your algorithm.
+ *
+ * @param {function} onLightningDown This optional callback is called with one parameter (lightningStrike) when a ray ends propagating, so it has hit the ground.
+ *
+ *
+*/
+
+import {
+	Material,
+	Math as _Math,
+	Mesh,
+	MeshBasicMaterial,
+	Object3D
+} from "../../../build/three.module.js";
+import { LightningStrike } from "../geometries/LightningStrike.js";
+
+var LightningStorm = function ( stormParams ) {
+
+	Object3D.call( this );
+
+	// Parameters
+
+	stormParams = stormParams || {};
+	this.stormParams = stormParams;
+
+	stormParams.size = stormParams.size !== undefined ? stormParams.size : 1000.0;
+	stormParams.minHeight = stormParams.minHeight !== undefined ? stormParams.minHeight : 80.0;
+	stormParams.maxHeight = stormParams.maxHeight !== undefined ? stormParams.maxHeight : 100.0;
+	stormParams.maxSlope = stormParams.maxSlope !== undefined ? stormParams.maxSlope : 1.1;
+
+	stormParams.maxLightnings = stormParams.maxLightnings !== undefined ? stormParams.maxLightnings : 3;
+
+	stormParams.lightningMinPeriod = stormParams.lightningMinPeriod !== undefined ? stormParams.lightningMinPeriod : 3.0;
+	stormParams.lightningMaxPeriod = stormParams.lightningMaxPeriod !== undefined ? stormParams.lightningMaxPeriod : 7.0;
+
+	stormParams.lightningMinDuration = stormParams.lightningMinDuration !== undefined ? stormParams.lightningMinDuration : 1.0;
+	stormParams.lightningMaxDuration = stormParams.lightningMaxDuration !== undefined ? stormParams.lightningMaxDuration : 2.5;
+
+	this.lightningParameters = LightningStrike.copyParameters( stormParams.lightningParameters, stormParams.lightningParameters );
+
+	this.lightningParameters.isEternal = false;
+
+	this.lightningMaterial = stormParams.lightningMaterial !== undefined ? stormParams.lightningMaterial : new MeshBasicMaterial( { color: 0xB0FFFF } );
+
+	if ( stormParams.onRayPosition !== undefined ) {
+
+		this.onRayPosition = stormParams.onRayPosition;
+
+	} else {
+
+		this.onRayPosition = function ( source, dest ) {
+
+			dest.set( ( Math.random() - 0.5 ) * stormParams.size, 0, ( Math.random() - 0.5 ) * stormParams.size );
+
+			var height = _Math.lerp( stormParams.minHeight, stormParams.maxHeight, Math.random() );
+
+			source.set( stormParams.maxSlope * ( 2 * Math.random() - 1 ), 1, stormParams.maxSlope * ( 2 * Math.random() - 1 ) ).multiplyScalar( height ).add( dest );
+
+		};
+
+	}
+
+	this.onLightningDown = stormParams.onLightningDown;
+
+	// Internal state
+
+	this.inited = false;
+	this.nextLightningTime = 0;
+	this.lightningsMeshes = [];
+	this.deadLightningsMeshes = [];
+
+	for ( var i = 0; i < this.stormParams.maxLightnings; i ++ ) {
+
+		var lightning = new LightningStrike( LightningStrike.copyParameters( {}, this.lightningParameters ) );
+		var mesh = new Mesh( lightning, this.lightningMaterial );
+		this.deadLightningsMeshes.push( mesh );
+
+	}
+
+};
+
+LightningStorm.prototype = Object.create( Object3D.prototype );
+
+LightningStorm.prototype.constructor = LightningStorm;
+
+LightningStorm.prototype.isLightningStorm = true;
+
+LightningStorm.prototype.update = function ( time ) {
+
+	if ( ! this.inited ) {
+
+		this.nextLightningTime = this.getNextLightningTime( time ) * Math.random();
+		this.inited = true;
+
+	}
+
+	if ( time >= this.nextLightningTime ) {
+
+		// Lightning creation
+
+		var lightningMesh = this.deadLightningsMeshes.pop();
+
+		if ( lightningMesh ) {
+
+			var lightningParams1 = LightningStrike.copyParameters( lightningMesh.geometry.rayParameters, this.lightningParameters );
+
+			lightningParams1.birthTime = time;
+			lightningParams1.deathTime = time + _Math.lerp( this.stormParams.lightningMinDuration, this.stormParams.lightningMaxDuration, Math.random() );
+
+			this.onRayPosition( lightningParams1.sourceOffset, lightningParams1.destOffset );
+
+			lightningParams1.noiseSeed = Math.random();
+
+			this.add( lightningMesh );
+
+			this.lightningsMeshes.push( lightningMesh );
+
+		}
+
+		// Schedule next lightning
+		this.nextLightningTime = this.getNextLightningTime( time );
+
+	}
+
+	var i = 0, il = this.lightningsMeshes.length;
+
+	while ( i < il ) {
+
+		var mesh = this.lightningsMeshes[ i ];
+
+		var lightning = mesh.geometry;
+
+		var prevState = lightning.state;
+
+		lightning.update( time );
+
+		if ( prevState === LightningStrike.RAY_PROPAGATING && lightning.state > prevState ) {
+
+			if ( this.onLightningDown ) {
+
+				this.onLightningDown( lightning );
+
+			}
+
+		}
+
+		if ( lightning.state === LightningStrike.RAY_EXTINGUISHED ) {
+
+			// Lightning is to be destroyed
+
+			this.lightningsMeshes.splice( this.lightningsMeshes.indexOf( mesh ), 1 );
+
+			this.deadLightningsMeshes.push( mesh );
+
+			this.remove( mesh );
+
+			il --;
+
+		} else {
+
+			i ++;
+
+		}
+
+	}
+
+};
+
+LightningStorm.prototype.getNextLightningTime = function ( currentTime ) {
+
+	return currentTime + _Math.lerp( this.stormParams.lightningMinPeriod, this.stormParams.lightningMaxPeriod, Math.random() ) / ( this.stormParams.maxLightnings + 1 );
+
+};
+
+LightningStorm.prototype.copy = function ( source ) {
+
+	Object3D.prototype.copy.call( this, source );
+
+	this.stormParams.size = source.stormParams.size;
+	this.stormParams.minHeight = source.stormParams.minHeight;
+	this.stormParams.maxHeight = source.stormParams.maxHeight;
+	this.stormParams.maxSlope = source.stormParams.maxSlope;
+
+	this.stormParams.maxLightnings = source.stormParams.maxLightnings;
+
+	this.stormParams.lightningMinPeriod = source.stormParams.lightningMinPeriod;
+	this.stormParams.lightningMaxPeriod = source.stormParams.lightningMaxPeriod;
+
+	this.stormParams.lightningMinDuration = source.stormParams.lightningMinDuration;
+	this.stormParams.lightningMaxDuration = source.stormParams.lightningMaxDuration;
+
+	this.lightningParameters = LightningStrike.copyParameters( {}, source.lightningParameters );
+
+	this.lightningMaterial = source.stormParams.lightningMaterial;
+
+	this.onLightningDown = source.onLightningDown;
+
+	return this;
+
+};
+
+LightningStrike.prototype.clone = function () {
+
+	return new this.constructor( this.stormParams ).copy( this );
+
+};
+
+export { LightningStorm };

+ 73 - 0
examples/jsm/objects/MarchingCubes.d.ts

@@ -0,0 +1,73 @@
+import {
+  BufferGeometry,
+  Material,
+  ImmediateRenderObject
+} from '../../../src/Three';
+
+export class MarchingCubes extends ImmediateRenderObject {
+  constructor(resolution: number, material: Material, enableUvs?: boolean, enableColors?: boolean);
+
+  enableUvs: boolean;
+  enableColors: boolean;
+
+  resolution: number;
+
+  // parameters
+
+  isolation: number;
+
+  // size of field, 32 is pushing it in Javascript :)
+
+  size: number;
+  size2: number;
+  size3: number;
+  halfsize: number;
+
+  // deltas
+
+  delta: number;
+  yd: number;
+  zd: number;
+
+  field: Float32Array;
+  normal_cache: Float32Array;
+  palette: Float32Array;
+
+  maxCount: number;
+  count: number;
+
+  hasPositions: boolean;
+  hasNormals: boolean;
+  hasColors: boolean;
+  hasUvs: boolean;
+
+  positionArray: Float32Array;
+  normalArray: Float32Array;
+
+  uvArray: Float32Array;
+  colorArray: Float32Array;
+
+  begin(): void;
+  end(): void;
+
+  addBall( ballx: number, bally: number, ballz: number, strength: number, subtract: number, colors: any ): void;
+
+  addPlaneX( strength: number, subtract: number ): void;
+  addPlaneY( strength: number, subtract: number ): void;
+  addPlaneZ( strength: number, subtract: number ): void;
+
+  setCell ( x: number, y: number, z: number, value: number ): void;
+  getCell ( x: number, y: number, z: number ): number;
+
+  blur( intensity: number ): void;
+
+  reset(): void;
+  render( renderCallback: any ): void;
+  generateGeometry(): BufferGeometry;
+  generateBufferGeometry(): BufferGeometry;
+
+}
+
+export const edgeTable: Int32Array[];
+export const triTable: Int32Array[];
+

+ 1285 - 0
examples/jsm/objects/MarchingCubes.js

@@ -0,0 +1,1285 @@
+/**
+ * @author alteredq / http://alteredqualia.com/
+ * @author mrdoob / http://mrdoob.com
+ * @author chaht01 / http://hyuntak.com
+ * Port of http://webglsamples.org/blob/blob.html
+ */
+
+import {
+	BufferAttribute,
+	BufferGeometry,
+	Color,
+	ImmediateRenderObject,
+	NoColors
+} from "../../../build/three.module.js";
+
+var MarchingCubes = function ( resolution, material, enableUvs, enableColors ) {
+
+	ImmediateRenderObject.call( this, material );
+
+	var scope = this;
+
+	// temp buffers used in polygonize
+
+	var vlist = new Float32Array( 12 * 3 );
+	var nlist = new Float32Array( 12 * 3 );
+	var clist = new Float32Array( 12 * 3 );
+
+	this.enableUvs = enableUvs !== undefined ? enableUvs : false;
+	this.enableColors = enableColors !== undefined ? enableColors : false;
+
+	// functions have to be object properties
+	// prototype functions kill performance
+	// (tested and it was 4x slower !!!)
+
+	this.init = function ( resolution ) {
+
+		this.resolution = resolution;
+
+		// parameters
+
+		this.isolation = 80.0;
+
+		// size of field, 32 is pushing it in Javascript :)
+
+		this.size = resolution;
+		this.size2 = this.size * this.size;
+		this.size3 = this.size2 * this.size;
+		this.halfsize = this.size / 2.0;
+
+		// deltas
+
+		this.delta = 2.0 / this.size;
+		this.yd = this.size;
+		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.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 );
+
+		if ( this.enableUvs ) {
+
+			this.uvArray = new Float32Array( this.maxCount * 2 );
+
+		}
+
+		if ( this.enableColors ) {
+
+			this.colorArray = new Float32Array( this.maxCount * 3 );
+
+		}
+
+	};
+
+	///////////////////////
+	// Polygonization
+	///////////////////////
+
+	function lerp( a, b, t ) {
+
+		return a + ( b - a ) * t;
+
+	}
+
+	function VIntX( q, offset, isol, x, y, z, valp1, valp2, c_offset1, c_offset2 ) {
+
+		var mu = ( isol - valp1 ) / ( valp2 - valp1 ),
+			nc = scope.normal_cache;
+
+		vlist[ offset + 0 ] = x + mu * scope.delta;
+		vlist[ offset + 1 ] = y;
+		vlist[ offset + 2 ] = z;
+
+		nlist[ offset + 0 ] = lerp( nc[ q + 0 ], nc[ q + 3 ], mu );
+		nlist[ offset + 1 ] = lerp( nc[ q + 1 ], nc[ q + 4 ], mu );
+		nlist[ offset + 2 ] = lerp( nc[ q + 2 ], nc[ q + 5 ], mu );
+
+		clist[ offset + 0 ] = lerp( scope.palette[ c_offset1 * 3 + 0 ], scope.palette[ c_offset2 * 3 + 0 ], mu );
+		clist[ offset + 1 ] = lerp( scope.palette[ c_offset1 * 3 + 1 ], scope.palette[ c_offset2 * 3 + 1 ], mu );
+		clist[ offset + 2 ] = lerp( scope.palette[ c_offset1 * 3 + 2 ], scope.palette[ c_offset2 * 3 + 2 ], mu );
+
+	}
+
+	function VIntY( q, offset, isol, x, y, z, valp1, valp2, c_offset1, c_offset2 ) {
+
+		var mu = ( isol - valp1 ) / ( valp2 - valp1 ),
+			nc = scope.normal_cache;
+
+		vlist[ offset + 0 ] = x;
+		vlist[ offset + 1 ] = y + mu * scope.delta;
+		vlist[ offset + 2 ] = z;
+
+		var q2 = q + scope.yd * 3;
+
+		nlist[ offset + 0 ] = lerp( nc[ q + 0 ], nc[ q2 + 0 ], mu );
+		nlist[ offset + 1 ] = lerp( nc[ q + 1 ], nc[ q2 + 1 ], mu );
+		nlist[ offset + 2 ] = lerp( nc[ q + 2 ], nc[ q2 + 2 ], mu );
+
+		clist[ offset + 0 ] = lerp( scope.palette[ c_offset1 * 3 + 0 ], scope.palette[ c_offset2 * 3 + 0 ], mu );
+		clist[ offset + 1 ] = lerp( scope.palette[ c_offset1 * 3 + 1 ], scope.palette[ c_offset2 * 3 + 1 ], mu );
+		clist[ offset + 2 ] = lerp( scope.palette[ c_offset1 * 3 + 2 ], scope.palette[ c_offset2 * 3 + 2 ], mu );
+
+	}
+
+	function VIntZ( q, offset, isol, x, y, z, valp1, valp2, c_offset1, c_offset2 ) {
+
+		var mu = ( isol - valp1 ) / ( valp2 - valp1 ),
+			nc = scope.normal_cache;
+
+		vlist[ offset + 0 ] = x;
+		vlist[ offset + 1 ] = y;
+		vlist[ offset + 2 ] = z + mu * scope.delta;
+
+		var q2 = q + scope.zd * 3;
+
+		nlist[ offset + 0 ] = lerp( nc[ q + 0 ], nc[ q2 + 0 ], mu );
+		nlist[ offset + 1 ] = lerp( nc[ q + 1 ], nc[ q2 + 1 ], mu );
+		nlist[ offset + 2 ] = lerp( nc[ q + 2 ], nc[ q2 + 2 ], mu );
+
+		clist[ offset + 0 ] = lerp( scope.palette[ c_offset1 * 3 + 0 ], scope.palette[ c_offset2 * 3 + 0 ], mu );
+		clist[ offset + 1 ] = lerp( scope.palette[ c_offset1 * 3 + 1 ], scope.palette[ c_offset2 * 3 + 1 ], mu );
+		clist[ offset + 2 ] = lerp( scope.palette[ c_offset1 * 3 + 2 ], scope.palette[ c_offset2 * 3 + 2 ], mu );
+
+	}
+
+	function compNorm( q ) {
+
+		var q3 = q * 3;
+
+		if ( scope.normal_cache[ q3 ] === 0.0 ) {
+
+			scope.normal_cache[ q3 + 0 ] = scope.field[ q - 1 ] - scope.field[ q + 1 ];
+			scope.normal_cache[ q3 + 1 ] =
+				scope.field[ q - scope.yd ] - scope.field[ q + scope.yd ];
+			scope.normal_cache[ q3 + 2 ] =
+				scope.field[ q - scope.zd ] - scope.field[ q + scope.zd ];
+
+		}
+
+	}
+
+	// Returns total number of triangles. Fills triangles.
+	// (this is where most of time is spent - it's inner work of O(n3) loop )
+
+	function polygonize( fx, fy, fz, q, isol, renderCallback ) {
+
+		// cache indices
+		var q1 = q + 1,
+			qy = q + scope.yd,
+			qz = q + scope.zd,
+			q1y = q1 + scope.yd,
+			q1z = q1 + scope.zd,
+			qyz = q + scope.yd + scope.zd,
+			q1yz = q1 + scope.yd + scope.zd;
+
+		var cubeindex = 0,
+			field0 = scope.field[ q ],
+			field1 = scope.field[ q1 ],
+			field2 = scope.field[ qy ],
+			field3 = scope.field[ q1y ],
+			field4 = scope.field[ qz ],
+			field5 = scope.field[ q1z ],
+			field6 = scope.field[ qyz ],
+			field7 = scope.field[ q1yz ];
+
+		if ( field0 < isol ) cubeindex |= 1;
+		if ( field1 < isol ) cubeindex |= 2;
+		if ( field2 < isol ) cubeindex |= 8;
+		if ( field3 < isol ) cubeindex |= 4;
+		if ( field4 < isol ) cubeindex |= 16;
+		if ( field5 < isol ) cubeindex |= 32;
+		if ( field6 < isol ) cubeindex |= 128;
+		if ( field7 < isol ) cubeindex |= 64;
+
+		// if cube is entirely in/out of the surface - bail, nothing to draw
+
+		var bits = edgeTable[ cubeindex ];
+		if ( bits === 0 ) return 0;
+
+		var d = scope.delta,
+			fx2 = fx + d,
+			fy2 = fy + d,
+			fz2 = fz + d;
+
+		// top of the cube
+
+		if ( bits & 1 ) {
+
+			compNorm( q );
+			compNorm( q1 );
+			VIntX( q * 3, 0, isol, fx, fy, fz, field0, field1, q, q1 );
+
+		}
+
+		if ( bits & 2 ) {
+
+			compNorm( q1 );
+			compNorm( q1y );
+			VIntY( q1 * 3, 3, isol, fx2, fy, fz, field1, field3, q1, q1y );
+
+		}
+
+		if ( bits & 4 ) {
+
+			compNorm( qy );
+			compNorm( q1y );
+			VIntX( qy * 3, 6, isol, fx, fy2, fz, field2, field3, qy, q1y );
+
+		}
+
+		if ( bits & 8 ) {
+
+			compNorm( q );
+			compNorm( qy );
+			VIntY( q * 3, 9, isol, fx, fy, fz, field0, field2, q, qy );
+
+		}
+
+		// bottom of the cube
+
+		if ( bits & 16 ) {
+
+			compNorm( qz );
+			compNorm( q1z );
+			VIntX( qz * 3, 12, isol, fx, fy, fz2, field4, field5, qz, q1z );
+
+		}
+
+		if ( bits & 32 ) {
+
+			compNorm( q1z );
+			compNorm( q1yz );
+			VIntY(
+				q1z * 3,
+				15,
+				isol,
+				fx2,
+				fy,
+				fz2,
+				field5,
+				field7,
+				q1z,
+				q1yz
+			);
+
+		}
+
+		if ( bits & 64 ) {
+
+			compNorm( qyz );
+			compNorm( q1yz );
+			VIntX(
+				qyz * 3,
+				18,
+				isol,
+				fx,
+				fy2,
+				fz2,
+				field6,
+				field7,
+				qyz,
+				q1yz
+			);
+
+		}
+
+		if ( bits & 128 ) {
+
+			compNorm( qz );
+			compNorm( qyz );
+			VIntY( qz * 3, 21, isol, fx, fy, fz2, field4, field6, qz, qyz );
+
+		}
+
+		// vertical lines of the cube
+		if ( bits & 256 ) {
+
+			compNorm( q );
+			compNorm( qz );
+			VIntZ( q * 3, 24, isol, fx, fy, fz, field0, field4, q, qz );
+
+		}
+
+		if ( bits & 512 ) {
+
+			compNorm( q1 );
+			compNorm( q1z );
+			VIntZ( q1 * 3, 27, isol, fx2, fy, fz, field1, field5, q1, q1z );
+
+		}
+
+		if ( bits & 1024 ) {
+
+			compNorm( q1y );
+			compNorm( q1yz );
+			VIntZ(
+				q1y * 3,
+				30,
+				isol,
+				fx2,
+				fy2,
+				fz,
+				field3,
+				field7,
+				q1y,
+				q1yz
+			);
+
+		}
+
+		if ( bits & 2048 ) {
+
+			compNorm( qy );
+			compNorm( qyz );
+			VIntZ( qy * 3, 33, isol, fx, fy2, fz, field2, field6, qy, qyz );
+
+		}
+
+		cubeindex <<= 4; // re-purpose cubeindex into an offset into triTable
+
+		var o1,
+			o2,
+			o3,
+			numtris = 0,
+			i = 0;
+
+		// here is where triangles are created
+
+		while ( triTable[ cubeindex + i ] != - 1 ) {
+
+			o1 = cubeindex + i;
+			o2 = o1 + 1;
+			o3 = o1 + 2;
+
+			posnormtriv(
+				vlist,
+				nlist,
+				clist,
+				3 * triTable[ o1 ],
+				3 * triTable[ o2 ],
+				3 * triTable[ o3 ],
+				renderCallback
+			);
+
+			i += 3;
+			numtris ++;
+
+		}
+
+		return numtris;
+
+	}
+
+	/////////////////////////////////////
+	// Immediate render mode simulator
+	/////////////////////////////////////
+
+	function posnormtriv( pos, norm, colors, o1, o2, o3, renderCallback ) {
+
+		var c = scope.count * 3;
+
+		// positions
+
+		scope.positionArray[ c + 0 ] = pos[ o1 ];
+		scope.positionArray[ c + 1 ] = pos[ o1 + 1 ];
+		scope.positionArray[ c + 2 ] = pos[ o1 + 2 ];
+
+		scope.positionArray[ c + 3 ] = pos[ o2 ];
+		scope.positionArray[ c + 4 ] = pos[ o2 + 1 ];
+		scope.positionArray[ c + 5 ] = pos[ o2 + 2 ];
+
+		scope.positionArray[ c + 6 ] = pos[ o3 ];
+		scope.positionArray[ c + 7 ] = pos[ o3 + 1 ];
+		scope.positionArray[ c + 8 ] = pos[ o3 + 2 ];
+
+		// normals
+
+		if ( scope.material.flatShading === true ) {
+
+			var nx = ( norm[ o1 + 0 ] + norm[ o2 + 0 ] + norm[ o3 + 0 ] ) / 3;
+			var ny = ( norm[ o1 + 1 ] + norm[ o2 + 1 ] + norm[ o3 + 1 ] ) / 3;
+			var nz = ( norm[ o1 + 2 ] + norm[ o2 + 2 ] + norm[ o3 + 2 ] ) / 3;
+
+			scope.normalArray[ c + 0 ] = nx;
+			scope.normalArray[ c + 1 ] = ny;
+			scope.normalArray[ c + 2 ] = nz;
+
+			scope.normalArray[ c + 3 ] = nx;
+			scope.normalArray[ c + 4 ] = ny;
+			scope.normalArray[ c + 5 ] = nz;
+
+			scope.normalArray[ c + 6 ] = nx;
+			scope.normalArray[ c + 7 ] = ny;
+			scope.normalArray[ c + 8 ] = nz;
+
+		} else {
+
+			scope.normalArray[ c + 0 ] = norm[ o1 + 0 ];
+			scope.normalArray[ c + 1 ] = norm[ o1 + 1 ];
+			scope.normalArray[ c + 2 ] = norm[ o1 + 2 ];
+
+			scope.normalArray[ c + 3 ] = norm[ o2 + 0 ];
+			scope.normalArray[ c + 4 ] = norm[ o2 + 1 ];
+			scope.normalArray[ c + 5 ] = norm[ o2 + 2 ];
+
+			scope.normalArray[ c + 6 ] = norm[ o3 + 0 ];
+			scope.normalArray[ c + 7 ] = norm[ o3 + 1 ];
+			scope.normalArray[ c + 8 ] = norm[ o3 + 2 ];
+
+		}
+
+		// uvs
+
+		if ( scope.enableUvs ) {
+
+			var d = scope.count * 2;
+
+			scope.uvArray[ d + 0 ] = pos[ o1 + 0 ];
+			scope.uvArray[ d + 1 ] = pos[ o1 + 2 ];
+
+			scope.uvArray[ d + 2 ] = pos[ o2 + 0 ];
+			scope.uvArray[ d + 3 ] = pos[ o2 + 2 ];
+
+			scope.uvArray[ d + 4 ] = pos[ o3 + 0 ];
+			scope.uvArray[ d + 5 ] = pos[ o3 + 2 ];
+
+		}
+
+		// colors
+
+		if ( scope.enableColors ) {
+
+			scope.colorArray[ c + 0 ] = colors[ o1 + 0 ];
+			scope.colorArray[ c + 1 ] = colors[ o1 + 1 ];
+			scope.colorArray[ c + 2 ] = colors[ o1 + 2 ];
+
+			scope.colorArray[ c + 3 ] = colors[ o2 + 0 ];
+			scope.colorArray[ c + 4 ] = colors[ o2 + 1 ];
+			scope.colorArray[ c + 5 ] = colors[ o2 + 2 ];
+
+			scope.colorArray[ c + 6 ] = colors[ o3 + 0 ];
+			scope.colorArray[ c + 7 ] = colors[ o3 + 1 ];
+			scope.colorArray[ c + 8 ] = colors[ o3 + 2 ];
+
+		}
+
+		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 ( var 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 !== NoColors ) {
+
+			this.hasColors = true;
+
+		}
+
+		renderCallback( this );
+
+	};
+
+	/////////////////////////////////////
+	// Metaballs
+	/////////////////////////////////////
+
+	// Adds a reciprocal ball (nice and blobby) that, to be fast, fades to zero after
+	// a fixed distance, determined by strength and subtract.
+
+	this.addBall = function ( ballx, bally, ballz, strength, subtract, colors ) {
+
+		var sign = Math.sign( strength );
+		strength = Math.abs( strength );
+		var userDefineColor = ! ( colors === undefined || colors === null );
+		var ballColor = new Color( ballx, bally, ballz );
+		if ( userDefineColor ) {
+
+			try {
+
+				ballColor =
+					colors instanceof Color
+						? colors
+						: Array.isArray( colors )
+							? new Color(
+								Math.min( Math.abs( colors[ 0 ] ), 1 ),
+								Math.min( Math.abs( colors[ 1 ] ), 1 ),
+								Math.min( Math.abs( colors[ 2 ] ), 1 )
+						  )
+							: new Color( colors );
+
+			} catch ( err ) {
+
+				userDefineColor = false;
+				ballColor = new Color( ballx, bally, ballz );
+
+			}
+
+		}
+
+		// Let's solve the equation to find the radius:
+		// 1.0 / (0.000001 + radius^2) * strength - subtract = 0
+		// strength / (radius^2) = subtract
+		// strength = subtract * radius^2
+		// radius^2 = strength / subtract
+		// radius = sqrt(strength / subtract)
+
+		var radius = this.size * Math.sqrt( strength / subtract ),
+			zs = ballz * this.size,
+			ys = bally * this.size,
+			xs = ballx * this.size;
+
+		var min_z = Math.floor( zs - radius );
+		if ( min_z < 1 ) min_z = 1;
+		var max_z = Math.floor( zs + radius );
+		if ( max_z > this.size - 1 ) max_z = this.size - 1;
+		var min_y = Math.floor( ys - radius );
+		if ( min_y < 1 ) min_y = 1;
+		var max_y = Math.floor( ys + radius );
+		if ( max_y > this.size - 1 ) max_y = this.size - 1;
+		var min_x = Math.floor( xs - radius );
+		if ( min_x < 1 ) min_x = 1;
+		var max_x = Math.floor( xs + radius );
+		if ( max_x > this.size - 1 ) max_x = this.size - 1;
+
+		// Don't polygonize in the outer layer because normals aren't
+		// well-defined there.
+
+		var x, y, z, y_offset, z_offset, fx, fy, fz, fz2, fy2, val;
+		for ( z = min_z; z < max_z; z ++ ) {
+
+			z_offset = this.size2 * z;
+			fz = z / this.size - ballz;
+			fz2 = fz * fz;
+
+			for ( y = min_y; y < max_y; y ++ ) {
+
+				y_offset = z_offset + this.size * y;
+				fy = y / this.size - bally;
+				fy2 = fy * fy;
+
+				for ( x = min_x; x < max_x; x ++ ) {
+
+					fx = x / this.size - ballx;
+					val = strength / ( 0.000001 + fx * fx + fy2 + fz2 ) - subtract;
+					if ( val > 0.0 ) {
+
+						this.field[ y_offset + x ] += val * sign;
+
+						// optimization
+						// http://www.geisswerks.com/ryan/BLOBS/blobs.html
+						const ratio =
+							Math.sqrt( ( x - xs ) * ( x - xs ) + ( y - ys ) * ( y - ys ) + ( z - zs ) * ( z - zs ) ) / radius;
+						const contrib =
+							1 - ratio * ratio * ratio * ( ratio * ( ratio * 6 - 15 ) + 10 );
+						this.palette[ ( y_offset + x ) * 3 + 0 ] += ballColor.r * contrib;
+						this.palette[ ( y_offset + x ) * 3 + 1 ] += ballColor.g * contrib;
+						this.palette[ ( y_offset + x ) * 3 + 2 ] += ballColor.b * contrib;
+
+					}
+
+				}
+
+			}
+
+		}
+
+	};
+
+	this.addPlaneX = function ( strength, subtract ) {
+
+		var x,
+			y,
+			z,
+			xx,
+			val,
+			xdiv,
+			cxy,
+			// cache attribute lookups
+			size = this.size,
+			yd = this.yd,
+			zd = this.zd,
+			field = this.field,
+			dist = size * Math.sqrt( strength / subtract );
+
+		if ( dist > size ) dist = size;
+
+		for ( x = 0; x < dist; x ++ ) {
+
+			xdiv = x / size;
+			xx = xdiv * xdiv;
+			val = strength / ( 0.0001 + xx ) - subtract;
+
+			if ( val > 0.0 ) {
+
+				for ( y = 0; y < size; y ++ ) {
+
+					cxy = x + y * yd;
+
+					for ( z = 0; z < size; z ++ ) {
+
+						field[ zd * z + cxy ] += val;
+
+					}
+
+				}
+
+			}
+
+		}
+
+	};
+
+	this.addPlaneY = function ( strength, subtract ) {
+
+		var x,
+			y,
+			z,
+			yy,
+			val,
+			ydiv,
+			cy,
+			cxy,
+			// cache attribute lookups
+			size = this.size,
+			yd = this.yd,
+			zd = this.zd,
+			field = this.field,
+			dist = size * Math.sqrt( strength / subtract );
+
+		if ( dist > size ) dist = size;
+
+		for ( y = 0; y < dist; y ++ ) {
+
+			ydiv = y / size;
+			yy = ydiv * ydiv;
+			val = strength / ( 0.0001 + yy ) - subtract;
+
+			if ( val > 0.0 ) {
+
+				cy = y * yd;
+
+				for ( x = 0; x < size; x ++ ) {
+
+					cxy = cy + x;
+
+					for ( z = 0; z < size; z ++ ) field[ zd * z + cxy ] += val;
+
+				}
+
+			}
+
+		}
+
+	};
+
+	this.addPlaneZ = function ( strength, subtract ) {
+
+		var x,
+			y,
+			z,
+			zz,
+			val,
+			zdiv,
+			cz,
+			cyz,
+			// cache attribute lookups
+			size = this.size,
+			yd = this.yd,
+			zd = this.zd,
+			field = this.field,
+			dist = size * Math.sqrt( strength / subtract );
+
+		if ( dist > size ) dist = size;
+
+		for ( z = 0; z < dist; z ++ ) {
+
+			zdiv = z / size;
+			zz = zdiv * zdiv;
+			val = strength / ( 0.0001 + zz ) - subtract;
+			if ( val > 0.0 ) {
+
+				cz = zd * z;
+
+				for ( y = 0; y < size; y ++ ) {
+
+					cyz = cz + y * yd;
+
+					for ( x = 0; x < size; x ++ ) field[ cyz + x ] += val;
+
+				}
+
+			}
+
+		}
+
+	};
+
+	/////////////////////////////////////
+	// Updates
+	/////////////////////////////////////
+
+	this.setCell = function ( x, y, z, value ) {
+
+		var index = this.size2 * z + this.size * y + x;
+		this.field[ index ] = value;
+
+	};
+
+	this.getCell = function ( x, y, z ) {
+
+		var index = this.size2 * z + this.size * y + x;
+		return this.field[ index ];
+
+	};
+
+	this.blur = function ( intensity ) {
+
+		if ( intensity === undefined ) {
+
+			intensity = 1;
+
+		}
+
+		var field = this.field;
+		var fieldCopy = field.slice();
+		var size = this.size;
+		var size2 = this.size2;
+		for ( var x = 0; x < size; x ++ ) {
+
+			for ( var y = 0; y < size; y ++ ) {
+
+				for ( var z = 0; z < size; z ++ ) {
+
+					var index = size2 * z + size * y + x;
+					var val = fieldCopy[ index ];
+					var count = 1;
+
+					for ( var x2 = - 1; x2 <= 1; x2 += 2 ) {
+
+						var x3 = x2 + x;
+						if ( x3 < 0 || x3 >= size ) continue;
+
+						for ( var y2 = - 1; y2 <= 1; y2 += 2 ) {
+
+							var y3 = y2 + y;
+							if ( y3 < 0 || y3 >= size ) continue;
+
+							for ( var z2 = - 1; z2 <= 1; z2 += 2 ) {
+
+								var z3 = z2 + z;
+								if ( z3 < 0 || z3 >= size ) continue;
+
+								var index2 = size2 * z3 + size * y3 + x3;
+								var val2 = fieldCopy[ index2 ];
+
+								count ++;
+								val += intensity * ( val2 - val ) / count;
+
+							}
+
+						}
+
+					}
+
+					field[ index ] = val;
+
+				}
+
+			}
+
+		}
+
+	};
+
+	this.reset = function () {
+
+		var i;
+
+		// wipe the normal cache
+
+		for ( i = 0; i < this.size3; i ++ ) {
+
+			this.normal_cache[ i * 3 ] = 0.0;
+			this.field[ i ] = 0.0;
+			this.palette[ i * 3 ] = this.palette[ i * 3 + 1 ] = this.palette[
+				i * 3 + 2
+			] = 0.0;
+
+		}
+
+	};
+
+	this.render = function ( renderCallback ) {
+
+		this.begin();
+
+		// Triangulate. Yeah, this is slow.
+
+		var smin2 = this.size - 2;
+
+		for ( var z = 1; z < smin2; z ++ ) {
+
+			var z_offset = this.size2 * z;
+			var fz = ( z - this.halfsize ) / this.halfsize; //+ 1
+
+			for ( var y = 1; y < smin2; y ++ ) {
+
+				var y_offset = z_offset + this.size * y;
+				var fy = ( y - this.halfsize ) / this.halfsize; //+ 1
+
+				for ( var x = 1; x < smin2; x ++ ) {
+
+					var fx = ( x - this.halfsize ) / this.halfsize; //+ 1
+					var q = y_offset + x;
+
+					polygonize( fx, fy, fz, q, this.isolation, renderCallback );
+
+				}
+
+			}
+
+		}
+
+		this.end( renderCallback );
+
+	};
+
+	this.generateGeometry = function () {
+
+		console.warn(
+			"MarchingCubes: generateGeometry() now returns BufferGeometry"
+		);
+		return this.generateBufferGeometry();
+
+	};
+
+	function concatenate( a, b, length ) {
+
+		var result = new Float32Array( a.length + length );
+		result.set( a, 0 );
+		result.set( b.slice( 0, length ), a.length );
+		return result;
+
+	}
+
+	this.generateBufferGeometry = function () {
+
+		var geo = new BufferGeometry();
+		var posArray = new Float32Array();
+		var normArray = new Float32Array();
+		var colorArray = new Float32Array();
+		var uvArray = new Float32Array();
+		var scope = this;
+
+		var geo_callback = function ( object ) {
+
+			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;
+
+		};
+
+		this.render( geo_callback );
+
+		if ( this.hasPositions )
+			geo.addAttribute( "position", new BufferAttribute( posArray, 3 ) );
+		if ( this.hasNormals )
+			geo.addAttribute( "normal", new BufferAttribute( normArray, 3 ) );
+		if ( this.hasColors )
+			geo.addAttribute( "color", new BufferAttribute( colorArray, 3 ) );
+		if ( this.hasUvs )
+			geo.addAttribute( "uv", new BufferAttribute( uvArray, 2 ) );
+
+		return geo;
+
+	};
+
+	this.init( resolution );
+
+};
+
+MarchingCubes.prototype = Object.create( ImmediateRenderObject.prototype );
+MarchingCubes.prototype.constructor = MarchingCubes;
+
+/////////////////////////////////////
+// Marching cubes lookup tables
+/////////////////////////////////////
+
+// These tables are straight from Paul Bourke's page:
+// http://local.wasp.uwa.edu.au/~pbourke/geometry/polygonise/
+// who in turn got them from Cory Gene Bloyd.
+
+var 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 ] );
+
+var triTable = new Int32Array( [
+	- 1, - 1, - 1, - 1, - 1, - 1, - 1, - 1, - 1, - 1, - 1, - 1, - 1, - 1, - 1, - 1,
+	0, 8, 3, - 1, - 1, - 1, - 1, - 1, - 1, - 1, - 1, - 1, - 1, - 1, - 1, - 1,
+	0, 1, 9, - 1, - 1, - 1, - 1, - 1, - 1, - 1, - 1, - 1, - 1, - 1, - 1, - 1,
+	1, 8, 3, 9, 8, 1, - 1, - 1, - 1, - 1, - 1, - 1, - 1, - 1, - 1, - 1,
+	1, 2, 10, - 1, - 1, - 1, - 1, - 1, - 1, - 1, - 1, - 1, - 1, - 1, - 1, - 1,
+	0, 8, 3, 1, 2, 10, - 1, - 1, - 1, - 1, - 1, - 1, - 1, - 1, - 1, - 1,
+	9, 2, 10, 0, 2, 9, - 1, - 1, - 1, - 1, - 1, - 1, - 1, - 1, - 1, - 1,
+	2, 8, 3, 2, 10, 8, 10, 9, 8, - 1, - 1, - 1, - 1, - 1, - 1, - 1,
+	3, 11, 2, - 1, - 1, - 1, - 1, - 1, - 1, - 1, - 1, - 1, - 1, - 1, - 1, - 1,
+	0, 11, 2, 8, 11, 0, - 1, - 1, - 1, - 1, - 1, - 1, - 1, - 1, - 1, - 1,
+	1, 9, 0, 2, 3, 11, - 1, - 1, - 1, - 1, - 1, - 1, - 1, - 1, - 1, - 1,
+	1, 11, 2, 1, 9, 11, 9, 8, 11, - 1, - 1, - 1, - 1, - 1, - 1, - 1,
+	3, 10, 1, 11, 10, 3, - 1, - 1, - 1, - 1, - 1, - 1, - 1, - 1, - 1, - 1,
+	0, 10, 1, 0, 8, 10, 8, 11, 10, - 1, - 1, - 1, - 1, - 1, - 1, - 1,
+	3, 9, 0, 3, 11, 9, 11, 10, 9, - 1, - 1, - 1, - 1, - 1, - 1, - 1,
+	9, 8, 10, 10, 8, 11, - 1, - 1, - 1, - 1, - 1, - 1, - 1, - 1, - 1, - 1,
+	4, 7, 8, - 1, - 1, - 1, - 1, - 1, - 1, - 1, - 1, - 1, - 1, - 1, - 1, - 1,
+	4, 3, 0, 7, 3, 4, - 1, - 1, - 1, - 1, - 1, - 1, - 1, - 1, - 1, - 1,
+	0, 1, 9, 8, 4, 7, - 1, - 1, - 1, - 1, - 1, - 1, - 1, - 1, - 1, - 1,
+	4, 1, 9, 4, 7, 1, 7, 3, 1, - 1, - 1, - 1, - 1, - 1, - 1, - 1,
+	1, 2, 10, 8, 4, 7, - 1, - 1, - 1, - 1, - 1, - 1, - 1, - 1, - 1, - 1,
+	3, 4, 7, 3, 0, 4, 1, 2, 10, - 1, - 1, - 1, - 1, - 1, - 1, - 1,
+	9, 2, 10, 9, 0, 2, 8, 4, 7, - 1, - 1, - 1, - 1, - 1, - 1, - 1,
+	2, 10, 9, 2, 9, 7, 2, 7, 3, 7, 9, 4, - 1, - 1, - 1, - 1,
+	8, 4, 7, 3, 11, 2, - 1, - 1, - 1, - 1, - 1, - 1, - 1, - 1, - 1, - 1,
+	11, 4, 7, 11, 2, 4, 2, 0, 4, - 1, - 1, - 1, - 1, - 1, - 1, - 1,
+	9, 0, 1, 8, 4, 7, 2, 3, 11, - 1, - 1, - 1, - 1, - 1, - 1, - 1,
+	4, 7, 11, 9, 4, 11, 9, 11, 2, 9, 2, 1, - 1, - 1, - 1, - 1,
+	3, 10, 1, 3, 11, 10, 7, 8, 4, - 1, - 1, - 1, - 1, - 1, - 1, - 1,
+	1, 11, 10, 1, 4, 11, 1, 0, 4, 7, 11, 4, - 1, - 1, - 1, - 1,
+	4, 7, 8, 9, 0, 11, 9, 11, 10, 11, 0, 3, - 1, - 1, - 1, - 1,
+	4, 7, 11, 4, 11, 9, 9, 11, 10, - 1, - 1, - 1, - 1, - 1, - 1, - 1,
+	9, 5, 4, - 1, - 1, - 1, - 1, - 1, - 1, - 1, - 1, - 1, - 1, - 1, - 1, - 1,
+	9, 5, 4, 0, 8, 3, - 1, - 1, - 1, - 1, - 1, - 1, - 1, - 1, - 1, - 1,
+	0, 5, 4, 1, 5, 0, - 1, - 1, - 1, - 1, - 1, - 1, - 1, - 1, - 1, - 1,
+	8, 5, 4, 8, 3, 5, 3, 1, 5, - 1, - 1, - 1, - 1, - 1, - 1, - 1,
+	1, 2, 10, 9, 5, 4, - 1, - 1, - 1, - 1, - 1, - 1, - 1, - 1, - 1, - 1,
+	3, 0, 8, 1, 2, 10, 4, 9, 5, - 1, - 1, - 1, - 1, - 1, - 1, - 1,
+	5, 2, 10, 5, 4, 2, 4, 0, 2, - 1, - 1, - 1, - 1, - 1, - 1, - 1,
+	2, 10, 5, 3, 2, 5, 3, 5, 4, 3, 4, 8, - 1, - 1, - 1, - 1,
+	9, 5, 4, 2, 3, 11, - 1, - 1, - 1, - 1, - 1, - 1, - 1, - 1, - 1, - 1,
+	0, 11, 2, 0, 8, 11, 4, 9, 5, - 1, - 1, - 1, - 1, - 1, - 1, - 1,
+	0, 5, 4, 0, 1, 5, 2, 3, 11, - 1, - 1, - 1, - 1, - 1, - 1, - 1,
+	2, 1, 5, 2, 5, 8, 2, 8, 11, 4, 8, 5, - 1, - 1, - 1, - 1,
+	10, 3, 11, 10, 1, 3, 9, 5, 4, - 1, - 1, - 1, - 1, - 1, - 1, - 1,
+	4, 9, 5, 0, 8, 1, 8, 10, 1, 8, 11, 10, - 1, - 1, - 1, - 1,
+	5, 4, 0, 5, 0, 11, 5, 11, 10, 11, 0, 3, - 1, - 1, - 1, - 1,
+	5, 4, 8, 5, 8, 10, 10, 8, 11, - 1, - 1, - 1, - 1, - 1, - 1, - 1,
+	9, 7, 8, 5, 7, 9, - 1, - 1, - 1, - 1, - 1, - 1, - 1, - 1, - 1, - 1,
+	9, 3, 0, 9, 5, 3, 5, 7, 3, - 1, - 1, - 1, - 1, - 1, - 1, - 1,
+	0, 7, 8, 0, 1, 7, 1, 5, 7, - 1, - 1, - 1, - 1, - 1, - 1, - 1,
+	1, 5, 3, 3, 5, 7, - 1, - 1, - 1, - 1, - 1, - 1, - 1, - 1, - 1, - 1,
+	9, 7, 8, 9, 5, 7, 10, 1, 2, - 1, - 1, - 1, - 1, - 1, - 1, - 1,
+	10, 1, 2, 9, 5, 0, 5, 3, 0, 5, 7, 3, - 1, - 1, - 1, - 1,
+	8, 0, 2, 8, 2, 5, 8, 5, 7, 10, 5, 2, - 1, - 1, - 1, - 1,
+	2, 10, 5, 2, 5, 3, 3, 5, 7, - 1, - 1, - 1, - 1, - 1, - 1, - 1,
+	7, 9, 5, 7, 8, 9, 3, 11, 2, - 1, - 1, - 1, - 1, - 1, - 1, - 1,
+	9, 5, 7, 9, 7, 2, 9, 2, 0, 2, 7, 11, - 1, - 1, - 1, - 1,
+	2, 3, 11, 0, 1, 8, 1, 7, 8, 1, 5, 7, - 1, - 1, - 1, - 1,
+	11, 2, 1, 11, 1, 7, 7, 1, 5, - 1, - 1, - 1, - 1, - 1, - 1, - 1,
+	9, 5, 8, 8, 5, 7, 10, 1, 3, 10, 3, 11, - 1, - 1, - 1, - 1,
+	5, 7, 0, 5, 0, 9, 7, 11, 0, 1, 0, 10, 11, 10, 0, - 1,
+	11, 10, 0, 11, 0, 3, 10, 5, 0, 8, 0, 7, 5, 7, 0, - 1,
+	11, 10, 5, 7, 11, 5, - 1, - 1, - 1, - 1, - 1, - 1, - 1, - 1, - 1, - 1,
+	10, 6, 5, - 1, - 1, - 1, - 1, - 1, - 1, - 1, - 1, - 1, - 1, - 1, - 1, - 1,
+	0, 8, 3, 5, 10, 6, - 1, - 1, - 1, - 1, - 1, - 1, - 1, - 1, - 1, - 1,
+	9, 0, 1, 5, 10, 6, - 1, - 1, - 1, - 1, - 1, - 1, - 1, - 1, - 1, - 1,
+	1, 8, 3, 1, 9, 8, 5, 10, 6, - 1, - 1, - 1, - 1, - 1, - 1, - 1,
+	1, 6, 5, 2, 6, 1, - 1, - 1, - 1, - 1, - 1, - 1, - 1, - 1, - 1, - 1,
+	1, 6, 5, 1, 2, 6, 3, 0, 8, - 1, - 1, - 1, - 1, - 1, - 1, - 1,
+	9, 6, 5, 9, 0, 6, 0, 2, 6, - 1, - 1, - 1, - 1, - 1, - 1, - 1,
+	5, 9, 8, 5, 8, 2, 5, 2, 6, 3, 2, 8, - 1, - 1, - 1, - 1,
+	2, 3, 11, 10, 6, 5, - 1, - 1, - 1, - 1, - 1, - 1, - 1, - 1, - 1, - 1,
+	11, 0, 8, 11, 2, 0, 10, 6, 5, - 1, - 1, - 1, - 1, - 1, - 1, - 1,
+	0, 1, 9, 2, 3, 11, 5, 10, 6, - 1, - 1, - 1, - 1, - 1, - 1, - 1,
+	5, 10, 6, 1, 9, 2, 9, 11, 2, 9, 8, 11, - 1, - 1, - 1, - 1,
+	6, 3, 11, 6, 5, 3, 5, 1, 3, - 1, - 1, - 1, - 1, - 1, - 1, - 1,
+	0, 8, 11, 0, 11, 5, 0, 5, 1, 5, 11, 6, - 1, - 1, - 1, - 1,
+	3, 11, 6, 0, 3, 6, 0, 6, 5, 0, 5, 9, - 1, - 1, - 1, - 1,
+	6, 5, 9, 6, 9, 11, 11, 9, 8, - 1, - 1, - 1, - 1, - 1, - 1, - 1,
+	5, 10, 6, 4, 7, 8, - 1, - 1, - 1, - 1, - 1, - 1, - 1, - 1, - 1, - 1,
+	4, 3, 0, 4, 7, 3, 6, 5, 10, - 1, - 1, - 1, - 1, - 1, - 1, - 1,
+	1, 9, 0, 5, 10, 6, 8, 4, 7, - 1, - 1, - 1, - 1, - 1, - 1, - 1,
+	10, 6, 5, 1, 9, 7, 1, 7, 3, 7, 9, 4, - 1, - 1, - 1, - 1,
+	6, 1, 2, 6, 5, 1, 4, 7, 8, - 1, - 1, - 1, - 1, - 1, - 1, - 1,
+	1, 2, 5, 5, 2, 6, 3, 0, 4, 3, 4, 7, - 1, - 1, - 1, - 1,
+	8, 4, 7, 9, 0, 5, 0, 6, 5, 0, 2, 6, - 1, - 1, - 1, - 1,
+	7, 3, 9, 7, 9, 4, 3, 2, 9, 5, 9, 6, 2, 6, 9, - 1,
+	3, 11, 2, 7, 8, 4, 10, 6, 5, - 1, - 1, - 1, - 1, - 1, - 1, - 1,
+	5, 10, 6, 4, 7, 2, 4, 2, 0, 2, 7, 11, - 1, - 1, - 1, - 1,
+	0, 1, 9, 4, 7, 8, 2, 3, 11, 5, 10, 6, - 1, - 1, - 1, - 1,
+	9, 2, 1, 9, 11, 2, 9, 4, 11, 7, 11, 4, 5, 10, 6, - 1,
+	8, 4, 7, 3, 11, 5, 3, 5, 1, 5, 11, 6, - 1, - 1, - 1, - 1,
+	5, 1, 11, 5, 11, 6, 1, 0, 11, 7, 11, 4, 0, 4, 11, - 1,
+	0, 5, 9, 0, 6, 5, 0, 3, 6, 11, 6, 3, 8, 4, 7, - 1,
+	6, 5, 9, 6, 9, 11, 4, 7, 9, 7, 11, 9, - 1, - 1, - 1, - 1,
+	10, 4, 9, 6, 4, 10, - 1, - 1, - 1, - 1, - 1, - 1, - 1, - 1, - 1, - 1,
+	4, 10, 6, 4, 9, 10, 0, 8, 3, - 1, - 1, - 1, - 1, - 1, - 1, - 1,
+	10, 0, 1, 10, 6, 0, 6, 4, 0, - 1, - 1, - 1, - 1, - 1, - 1, - 1,
+	8, 3, 1, 8, 1, 6, 8, 6, 4, 6, 1, 10, - 1, - 1, - 1, - 1,
+	1, 4, 9, 1, 2, 4, 2, 6, 4, - 1, - 1, - 1, - 1, - 1, - 1, - 1,
+	3, 0, 8, 1, 2, 9, 2, 4, 9, 2, 6, 4, - 1, - 1, - 1, - 1,
+	0, 2, 4, 4, 2, 6, - 1, - 1, - 1, - 1, - 1, - 1, - 1, - 1, - 1, - 1,
+	8, 3, 2, 8, 2, 4, 4, 2, 6, - 1, - 1, - 1, - 1, - 1, - 1, - 1,
+	10, 4, 9, 10, 6, 4, 11, 2, 3, - 1, - 1, - 1, - 1, - 1, - 1, - 1,
+	0, 8, 2, 2, 8, 11, 4, 9, 10, 4, 10, 6, - 1, - 1, - 1, - 1,
+	3, 11, 2, 0, 1, 6, 0, 6, 4, 6, 1, 10, - 1, - 1, - 1, - 1,
+	6, 4, 1, 6, 1, 10, 4, 8, 1, 2, 1, 11, 8, 11, 1, - 1,
+	9, 6, 4, 9, 3, 6, 9, 1, 3, 11, 6, 3, - 1, - 1, - 1, - 1,
+	8, 11, 1, 8, 1, 0, 11, 6, 1, 9, 1, 4, 6, 4, 1, - 1,
+	3, 11, 6, 3, 6, 0, 0, 6, 4, - 1, - 1, - 1, - 1, - 1, - 1, - 1,
+	6, 4, 8, 11, 6, 8, - 1, - 1, - 1, - 1, - 1, - 1, - 1, - 1, - 1, - 1,
+	7, 10, 6, 7, 8, 10, 8, 9, 10, - 1, - 1, - 1, - 1, - 1, - 1, - 1,
+	0, 7, 3, 0, 10, 7, 0, 9, 10, 6, 7, 10, - 1, - 1, - 1, - 1,
+	10, 6, 7, 1, 10, 7, 1, 7, 8, 1, 8, 0, - 1, - 1, - 1, - 1,
+	10, 6, 7, 10, 7, 1, 1, 7, 3, - 1, - 1, - 1, - 1, - 1, - 1, - 1,
+	1, 2, 6, 1, 6, 8, 1, 8, 9, 8, 6, 7, - 1, - 1, - 1, - 1,
+	2, 6, 9, 2, 9, 1, 6, 7, 9, 0, 9, 3, 7, 3, 9, - 1,
+	7, 8, 0, 7, 0, 6, 6, 0, 2, - 1, - 1, - 1, - 1, - 1, - 1, - 1,
+	7, 3, 2, 6, 7, 2, - 1, - 1, - 1, - 1, - 1, - 1, - 1, - 1, - 1, - 1,
+	2, 3, 11, 10, 6, 8, 10, 8, 9, 8, 6, 7, - 1, - 1, - 1, - 1,
+	2, 0, 7, 2, 7, 11, 0, 9, 7, 6, 7, 10, 9, 10, 7, - 1,
+	1, 8, 0, 1, 7, 8, 1, 10, 7, 6, 7, 10, 2, 3, 11, - 1,
+	11, 2, 1, 11, 1, 7, 10, 6, 1, 6, 7, 1, - 1, - 1, - 1, - 1,
+	8, 9, 6, 8, 6, 7, 9, 1, 6, 11, 6, 3, 1, 3, 6, - 1,
+	0, 9, 1, 11, 6, 7, - 1, - 1, - 1, - 1, - 1, - 1, - 1, - 1, - 1, - 1,
+	7, 8, 0, 7, 0, 6, 3, 11, 0, 11, 6, 0, - 1, - 1, - 1, - 1,
+	7, 11, 6, - 1, - 1, - 1, - 1, - 1, - 1, - 1, - 1, - 1, - 1, - 1, - 1, - 1,
+	7, 6, 11, - 1, - 1, - 1, - 1, - 1, - 1, - 1, - 1, - 1, - 1, - 1, - 1, - 1,
+	3, 0, 8, 11, 7, 6, - 1, - 1, - 1, - 1, - 1, - 1, - 1, - 1, - 1, - 1,
+	0, 1, 9, 11, 7, 6, - 1, - 1, - 1, - 1, - 1, - 1, - 1, - 1, - 1, - 1,
+	8, 1, 9, 8, 3, 1, 11, 7, 6, - 1, - 1, - 1, - 1, - 1, - 1, - 1,
+	10, 1, 2, 6, 11, 7, - 1, - 1, - 1, - 1, - 1, - 1, - 1, - 1, - 1, - 1,
+	1, 2, 10, 3, 0, 8, 6, 11, 7, - 1, - 1, - 1, - 1, - 1, - 1, - 1,
+	2, 9, 0, 2, 10, 9, 6, 11, 7, - 1, - 1, - 1, - 1, - 1, - 1, - 1,
+	6, 11, 7, 2, 10, 3, 10, 8, 3, 10, 9, 8, - 1, - 1, - 1, - 1,
+	7, 2, 3, 6, 2, 7, - 1, - 1, - 1, - 1, - 1, - 1, - 1, - 1, - 1, - 1,
+	7, 0, 8, 7, 6, 0, 6, 2, 0, - 1, - 1, - 1, - 1, - 1, - 1, - 1,
+	2, 7, 6, 2, 3, 7, 0, 1, 9, - 1, - 1, - 1, - 1, - 1, - 1, - 1,
+	1, 6, 2, 1, 8, 6, 1, 9, 8, 8, 7, 6, - 1, - 1, - 1, - 1,
+	10, 7, 6, 10, 1, 7, 1, 3, 7, - 1, - 1, - 1, - 1, - 1, - 1, - 1,
+	10, 7, 6, 1, 7, 10, 1, 8, 7, 1, 0, 8, - 1, - 1, - 1, - 1,
+	0, 3, 7, 0, 7, 10, 0, 10, 9, 6, 10, 7, - 1, - 1, - 1, - 1,
+	7, 6, 10, 7, 10, 8, 8, 10, 9, - 1, - 1, - 1, - 1, - 1, - 1, - 1,
+	6, 8, 4, 11, 8, 6, - 1, - 1, - 1, - 1, - 1, - 1, - 1, - 1, - 1, - 1,
+	3, 6, 11, 3, 0, 6, 0, 4, 6, - 1, - 1, - 1, - 1, - 1, - 1, - 1,
+	8, 6, 11, 8, 4, 6, 9, 0, 1, - 1, - 1, - 1, - 1, - 1, - 1, - 1,
+	9, 4, 6, 9, 6, 3, 9, 3, 1, 11, 3, 6, - 1, - 1, - 1, - 1,
+	6, 8, 4, 6, 11, 8, 2, 10, 1, - 1, - 1, - 1, - 1, - 1, - 1, - 1,
+	1, 2, 10, 3, 0, 11, 0, 6, 11, 0, 4, 6, - 1, - 1, - 1, - 1,
+	4, 11, 8, 4, 6, 11, 0, 2, 9, 2, 10, 9, - 1, - 1, - 1, - 1,
+	10, 9, 3, 10, 3, 2, 9, 4, 3, 11, 3, 6, 4, 6, 3, - 1,
+	8, 2, 3, 8, 4, 2, 4, 6, 2, - 1, - 1, - 1, - 1, - 1, - 1, - 1,
+	0, 4, 2, 4, 6, 2, - 1, - 1, - 1, - 1, - 1, - 1, - 1, - 1, - 1, - 1,
+	1, 9, 0, 2, 3, 4, 2, 4, 6, 4, 3, 8, - 1, - 1, - 1, - 1,
+	1, 9, 4, 1, 4, 2, 2, 4, 6, - 1, - 1, - 1, - 1, - 1, - 1, - 1,
+	8, 1, 3, 8, 6, 1, 8, 4, 6, 6, 10, 1, - 1, - 1, - 1, - 1,
+	10, 1, 0, 10, 0, 6, 6, 0, 4, - 1, - 1, - 1, - 1, - 1, - 1, - 1,
+	4, 6, 3, 4, 3, 8, 6, 10, 3, 0, 3, 9, 10, 9, 3, - 1,
+	10, 9, 4, 6, 10, 4, - 1, - 1, - 1, - 1, - 1, - 1, - 1, - 1, - 1, - 1,
+	4, 9, 5, 7, 6, 11, - 1, - 1, - 1, - 1, - 1, - 1, - 1, - 1, - 1, - 1,
+	0, 8, 3, 4, 9, 5, 11, 7, 6, - 1, - 1, - 1, - 1, - 1, - 1, - 1,
+	5, 0, 1, 5, 4, 0, 7, 6, 11, - 1, - 1, - 1, - 1, - 1, - 1, - 1,
+	11, 7, 6, 8, 3, 4, 3, 5, 4, 3, 1, 5, - 1, - 1, - 1, - 1,
+	9, 5, 4, 10, 1, 2, 7, 6, 11, - 1, - 1, - 1, - 1, - 1, - 1, - 1,
+	6, 11, 7, 1, 2, 10, 0, 8, 3, 4, 9, 5, - 1, - 1, - 1, - 1,
+	7, 6, 11, 5, 4, 10, 4, 2, 10, 4, 0, 2, - 1, - 1, - 1, - 1,
+	3, 4, 8, 3, 5, 4, 3, 2, 5, 10, 5, 2, 11, 7, 6, - 1,
+	7, 2, 3, 7, 6, 2, 5, 4, 9, - 1, - 1, - 1, - 1, - 1, - 1, - 1,
+	9, 5, 4, 0, 8, 6, 0, 6, 2, 6, 8, 7, - 1, - 1, - 1, - 1,
+	3, 6, 2, 3, 7, 6, 1, 5, 0, 5, 4, 0, - 1, - 1, - 1, - 1,
+	6, 2, 8, 6, 8, 7, 2, 1, 8, 4, 8, 5, 1, 5, 8, - 1,
+	9, 5, 4, 10, 1, 6, 1, 7, 6, 1, 3, 7, - 1, - 1, - 1, - 1,
+	1, 6, 10, 1, 7, 6, 1, 0, 7, 8, 7, 0, 9, 5, 4, - 1,
+	4, 0, 10, 4, 10, 5, 0, 3, 10, 6, 10, 7, 3, 7, 10, - 1,
+	7, 6, 10, 7, 10, 8, 5, 4, 10, 4, 8, 10, - 1, - 1, - 1, - 1,
+	6, 9, 5, 6, 11, 9, 11, 8, 9, - 1, - 1, - 1, - 1, - 1, - 1, - 1,
+	3, 6, 11, 0, 6, 3, 0, 5, 6, 0, 9, 5, - 1, - 1, - 1, - 1,
+	0, 11, 8, 0, 5, 11, 0, 1, 5, 5, 6, 11, - 1, - 1, - 1, - 1,
+	6, 11, 3, 6, 3, 5, 5, 3, 1, - 1, - 1, - 1, - 1, - 1, - 1, - 1,
+	1, 2, 10, 9, 5, 11, 9, 11, 8, 11, 5, 6, - 1, - 1, - 1, - 1,
+	0, 11, 3, 0, 6, 11, 0, 9, 6, 5, 6, 9, 1, 2, 10, - 1,
+	11, 8, 5, 11, 5, 6, 8, 0, 5, 10, 5, 2, 0, 2, 5, - 1,
+	6, 11, 3, 6, 3, 5, 2, 10, 3, 10, 5, 3, - 1, - 1, - 1, - 1,
+	5, 8, 9, 5, 2, 8, 5, 6, 2, 3, 8, 2, - 1, - 1, - 1, - 1,
+	9, 5, 6, 9, 6, 0, 0, 6, 2, - 1, - 1, - 1, - 1, - 1, - 1, - 1,
+	1, 5, 8, 1, 8, 0, 5, 6, 8, 3, 8, 2, 6, 2, 8, - 1,
+	1, 5, 6, 2, 1, 6, - 1, - 1, - 1, - 1, - 1, - 1, - 1, - 1, - 1, - 1,
+	1, 3, 6, 1, 6, 10, 3, 8, 6, 5, 6, 9, 8, 9, 6, - 1,
+	10, 1, 0, 10, 0, 6, 9, 5, 0, 5, 6, 0, - 1, - 1, - 1, - 1,
+	0, 3, 8, 5, 6, 10, - 1, - 1, - 1, - 1, - 1, - 1, - 1, - 1, - 1, - 1,
+	10, 5, 6, - 1, - 1, - 1, - 1, - 1, - 1, - 1, - 1, - 1, - 1, - 1, - 1, - 1,
+	11, 5, 10, 7, 5, 11, - 1, - 1, - 1, - 1, - 1, - 1, - 1, - 1, - 1, - 1,
+	11, 5, 10, 11, 7, 5, 8, 3, 0, - 1, - 1, - 1, - 1, - 1, - 1, - 1,
+	5, 11, 7, 5, 10, 11, 1, 9, 0, - 1, - 1, - 1, - 1, - 1, - 1, - 1,
+	10, 7, 5, 10, 11, 7, 9, 8, 1, 8, 3, 1, - 1, - 1, - 1, - 1,
+	11, 1, 2, 11, 7, 1, 7, 5, 1, - 1, - 1, - 1, - 1, - 1, - 1, - 1,
+	0, 8, 3, 1, 2, 7, 1, 7, 5, 7, 2, 11, - 1, - 1, - 1, - 1,
+	9, 7, 5, 9, 2, 7, 9, 0, 2, 2, 11, 7, - 1, - 1, - 1, - 1,
+	7, 5, 2, 7, 2, 11, 5, 9, 2, 3, 2, 8, 9, 8, 2, - 1,
+	2, 5, 10, 2, 3, 5, 3, 7, 5, - 1, - 1, - 1, - 1, - 1, - 1, - 1,
+	8, 2, 0, 8, 5, 2, 8, 7, 5, 10, 2, 5, - 1, - 1, - 1, - 1,
+	9, 0, 1, 5, 10, 3, 5, 3, 7, 3, 10, 2, - 1, - 1, - 1, - 1,
+	9, 8, 2, 9, 2, 1, 8, 7, 2, 10, 2, 5, 7, 5, 2, - 1,
+	1, 3, 5, 3, 7, 5, - 1, - 1, - 1, - 1, - 1, - 1, - 1, - 1, - 1, - 1,
+	0, 8, 7, 0, 7, 1, 1, 7, 5, - 1, - 1, - 1, - 1, - 1, - 1, - 1,
+	9, 0, 3, 9, 3, 5, 5, 3, 7, - 1, - 1, - 1, - 1, - 1, - 1, - 1,
+	9, 8, 7, 5, 9, 7, - 1, - 1, - 1, - 1, - 1, - 1, - 1, - 1, - 1, - 1,
+	5, 8, 4, 5, 10, 8, 10, 11, 8, - 1, - 1, - 1, - 1, - 1, - 1, - 1,
+	5, 0, 4, 5, 11, 0, 5, 10, 11, 11, 3, 0, - 1, - 1, - 1, - 1,
+	0, 1, 9, 8, 4, 10, 8, 10, 11, 10, 4, 5, - 1, - 1, - 1, - 1,
+	10, 11, 4, 10, 4, 5, 11, 3, 4, 9, 4, 1, 3, 1, 4, - 1,
+	2, 5, 1, 2, 8, 5, 2, 11, 8, 4, 5, 8, - 1, - 1, - 1, - 1,
+	0, 4, 11, 0, 11, 3, 4, 5, 11, 2, 11, 1, 5, 1, 11, - 1,
+	0, 2, 5, 0, 5, 9, 2, 11, 5, 4, 5, 8, 11, 8, 5, - 1,
+	9, 4, 5, 2, 11, 3, - 1, - 1, - 1, - 1, - 1, - 1, - 1, - 1, - 1, - 1,
+	2, 5, 10, 3, 5, 2, 3, 4, 5, 3, 8, 4, - 1, - 1, - 1, - 1,
+	5, 10, 2, 5, 2, 4, 4, 2, 0, - 1, - 1, - 1, - 1, - 1, - 1, - 1,
+	3, 10, 2, 3, 5, 10, 3, 8, 5, 4, 5, 8, 0, 1, 9, - 1,
+	5, 10, 2, 5, 2, 4, 1, 9, 2, 9, 4, 2, - 1, - 1, - 1, - 1,
+	8, 4, 5, 8, 5, 3, 3, 5, 1, - 1, - 1, - 1, - 1, - 1, - 1, - 1,
+	0, 4, 5, 1, 0, 5, - 1, - 1, - 1, - 1, - 1, - 1, - 1, - 1, - 1, - 1,
+	8, 4, 5, 8, 5, 3, 9, 0, 5, 0, 3, 5, - 1, - 1, - 1, - 1,
+	9, 4, 5, - 1, - 1, - 1, - 1, - 1, - 1, - 1, - 1, - 1, - 1, - 1, - 1, - 1,
+	4, 11, 7, 4, 9, 11, 9, 10, 11, - 1, - 1, - 1, - 1, - 1, - 1, - 1,
+	0, 8, 3, 4, 9, 7, 9, 11, 7, 9, 10, 11, - 1, - 1, - 1, - 1,
+	1, 10, 11, 1, 11, 4, 1, 4, 0, 7, 4, 11, - 1, - 1, - 1, - 1,
+	3, 1, 4, 3, 4, 8, 1, 10, 4, 7, 4, 11, 10, 11, 4, - 1,
+	4, 11, 7, 9, 11, 4, 9, 2, 11, 9, 1, 2, - 1, - 1, - 1, - 1,
+	9, 7, 4, 9, 11, 7, 9, 1, 11, 2, 11, 1, 0, 8, 3, - 1,
+	11, 7, 4, 11, 4, 2, 2, 4, 0, - 1, - 1, - 1, - 1, - 1, - 1, - 1,
+	11, 7, 4, 11, 4, 2, 8, 3, 4, 3, 2, 4, - 1, - 1, - 1, - 1,
+	2, 9, 10, 2, 7, 9, 2, 3, 7, 7, 4, 9, - 1, - 1, - 1, - 1,
+	9, 10, 7, 9, 7, 4, 10, 2, 7, 8, 7, 0, 2, 0, 7, - 1,
+	3, 7, 10, 3, 10, 2, 7, 4, 10, 1, 10, 0, 4, 0, 10, - 1,
+	1, 10, 2, 8, 7, 4, - 1, - 1, - 1, - 1, - 1, - 1, - 1, - 1, - 1, - 1,
+	4, 9, 1, 4, 1, 7, 7, 1, 3, - 1, - 1, - 1, - 1, - 1, - 1, - 1,
+	4, 9, 1, 4, 1, 7, 0, 8, 1, 8, 7, 1, - 1, - 1, - 1, - 1,
+	4, 0, 3, 7, 4, 3, - 1, - 1, - 1, - 1, - 1, - 1, - 1, - 1, - 1, - 1,
+	4, 8, 7, - 1, - 1, - 1, - 1, - 1, - 1, - 1, - 1, - 1, - 1, - 1, - 1, - 1,
+	9, 10, 8, 10, 11, 8, - 1, - 1, - 1, - 1, - 1, - 1, - 1, - 1, - 1, - 1,
+	3, 0, 9, 3, 9, 11, 11, 9, 10, - 1, - 1, - 1, - 1, - 1, - 1, - 1,
+	0, 1, 10, 0, 10, 8, 8, 10, 11, - 1, - 1, - 1, - 1, - 1, - 1, - 1,
+	3, 1, 10, 11, 3, 10, - 1, - 1, - 1, - 1, - 1, - 1, - 1, - 1, - 1, - 1,
+	1, 2, 11, 1, 11, 9, 9, 11, 8, - 1, - 1, - 1, - 1, - 1, - 1, - 1,
+	3, 0, 9, 3, 9, 11, 1, 2, 9, 2, 11, 9, - 1, - 1, - 1, - 1,
+	0, 2, 11, 8, 0, 11, - 1, - 1, - 1, - 1, - 1, - 1, - 1, - 1, - 1, - 1,
+	3, 2, 11, - 1, - 1, - 1, - 1, - 1, - 1, - 1, - 1, - 1, - 1, - 1, - 1, - 1,
+	2, 3, 8, 2, 8, 10, 10, 8, 9, - 1, - 1, - 1, - 1, - 1, - 1, - 1,
+	9, 10, 2, 0, 9, 2, - 1, - 1, - 1, - 1, - 1, - 1, - 1, - 1, - 1, - 1,
+	2, 3, 8, 2, 8, 10, 0, 1, 8, 1, 10, 8, - 1, - 1, - 1, - 1,
+	1, 10, 2, - 1, - 1, - 1, - 1, - 1, - 1, - 1, - 1, - 1, - 1, - 1, - 1, - 1,
+	1, 3, 8, 9, 1, 8, - 1, - 1, - 1, - 1, - 1, - 1, - 1, - 1, - 1, - 1,
+	0, 9, 1, - 1, - 1, - 1, - 1, - 1, - 1, - 1, - 1, - 1, - 1, - 1, - 1, - 1,
+	0, 3, 8, - 1, - 1, - 1, - 1, - 1, - 1, - 1, - 1, - 1, - 1, - 1, - 1, - 1,
+	- 1, - 1, - 1, - 1, - 1, - 1, - 1, - 1, - 1, - 1, - 1, - 1, - 1, - 1, - 1, - 1 ] );
+
+export { MarchingCubes, edgeTable, triTable };

+ 1 - 1
examples/webgl_gpgpu_birds.html

@@ -516,7 +516,7 @@
 
 			function initComputeRenderer() {
 
-				gpuCompute = new GPUComputationRenderer( WIDTH, WIDTH, renderer );
+				gpuCompute = new THREE.GPUComputationRenderer( WIDTH, WIDTH, renderer );
 
 				var dtPosition = gpuCompute.createTexture();
 				var dtVelocity = gpuCompute.createTexture();

+ 1 - 1
examples/webgl_gpgpu_protoplanet.html

@@ -353,7 +353,7 @@
 
 			function initComputeRenderer() {
 
-				gpuCompute = new GPUComputationRenderer( WIDTH, WIDTH, renderer );
+				gpuCompute = new THREE.GPUComputationRenderer( WIDTH, WIDTH, renderer );
 
 				var dtPosition = gpuCompute.createTexture();
 				var dtVelocity = gpuCompute.createTexture();

+ 1 - 1
examples/webgl_gpgpu_water.html

@@ -470,7 +470,7 @@
 
 				// Creates the gpu computation class and sets it up
 
-				gpuCompute = new GPUComputationRenderer( WIDTH, WIDTH, renderer );
+				gpuCompute = new THREE.GPUComputationRenderer( WIDTH, WIDTH, renderer );
 
 				var heightmap0 = gpuCompute.createTexture();
 

+ 1 - 0
examples/webgl_lightningstrike.html

@@ -655,6 +655,7 @@
 				scene.userData.lightningMaterial =  new THREE.MeshBasicMaterial( { color: scene.userData.lightningColor } );
 
 				var rayDirection = new THREE.Vector3( 0, -1, 0 );
+				var rayLength = 0;
 				var vec1 = new THREE.Vector3();
 				var vec2 = new THREE.Vector3();
 

+ 1 - 1
examples/webgl_loader_md2.html

@@ -18,7 +18,7 @@
 		<script src="js/controls/OrbitControls.js"></script>
 
 		<script src="js/loaders/MD2Loader.js"></script>
-		<script src="js/MD2Character.js"></script>
+		<script src="js/misc/MD2Character.js"></script>
 
 		<script src="js/libs/stats.min.js"></script>
 		<script src="js/libs/dat.gui.min.js"></script>

+ 3 - 3
examples/webgl_loader_md2_control.html

@@ -28,9 +28,9 @@
 		<script src="js/controls/OrbitControls.js"></script>
 
 		<script src="js/loaders/MD2Loader.js"></script>
-		<script src="js/MorphBlendMesh.js"></script>
-		<script src="js/MD2CharacterComplex.js"></script>
-		<script src="js/Gyroscope.js"></script>
+		<script src="js/misc/MorphBlendMesh.js"></script>
+		<script src="js/misc/MD2CharacterComplex.js"></script>
+		<script src="js/misc/Gyroscope.js"></script>
 
 		<script src="js/libs/stats.min.js"></script>
 		<script src="js/WebGL.js"></script>

+ 1 - 1
examples/webgl_marchingcubes.html

@@ -20,7 +20,7 @@
 
 	<script src="js/controls/OrbitControls.js"></script>
 
-	<script src="js/MarchingCubes.js"></script>
+	<script src="js/objects/MarchingCubes.js"></script>
 	<script src="js/shaders/ToonShader.js"></script>
 
 	<script src="js/WebGL.js"></script>

+ 4 - 3
examples/webgl_materials_envmaps_hdr.html

@@ -88,9 +88,11 @@
 				scene.add( planeMesh );
 
 				var hdrUrls = [ 'px.hdr', 'nx.hdr', 'py.hdr', 'ny.hdr', 'pz.hdr', 'nz.hdr' ];
+
 				hdrCubeMap = new THREE.HDRCubeTextureLoader()
 					.setPath( './textures/cube/pisaHDR/' )
-					.load( THREE.UnsignedByteType, hdrUrls, function () {
+					.setType( THREE.UnsignedByteType )
+					.load( hdrUrls, function () {
 
 						var pmremGenerator = new THREE.PMREMGenerator( hdrCubeMap );
 						pmremGenerator.update( renderer );
@@ -113,7 +115,7 @@
 					.setPath( './textures/cube/pisa/' )
 					.load( ldrUrls, function () {
 
-						ldrCubeMap.encoding = THREE.GammaEncoding;
+						ldrCubeMap.encoding = THREE.sRGBEncoding;
 
 						var pmremGenerator = new THREE.PMREMGenerator( ldrCubeMap );
 						pmremGenerator.update( renderer );
@@ -158,7 +160,6 @@
 				container.appendChild( renderer.domElement );
 
 				//renderer.toneMapping = THREE.ReinhardToneMapping;
-				renderer.gammaInput = true; // ???
 				renderer.gammaOutput = true;
 
 				stats = new Stats();

+ 4 - 2
examples/webgl_materials_reflectivity.html

@@ -141,7 +141,10 @@
 	};
 
 				var hdrUrls = genCubeUrls( "./textures/cube/pisaHDR/", ".hdr" );
-				new THREE.HDRCubeTextureLoader().load( THREE.UnsignedByteType, hdrUrls, function ( hdrCubeMap ) {
+
+				new THREE.HDRCubeTextureLoader()
+					.setType( THREE.UnsignedByteType )
+					.load( hdrUrls, function ( hdrCubeMap ) {
 
 					var pmremGenerator = new THREE.PMREMGenerator( hdrCubeMap );
 					pmremGenerator.update( renderer );
@@ -187,7 +190,6 @@
 				renderer.shadowMap.enabled = true;
 				container.appendChild( renderer.domElement );
 
-				renderer.gammaInput = true;
 				renderer.gammaOutput = true;
 
 				stats = new Stats();

+ 3 - 2
examples/webgl_materials_variations_physical.html

@@ -70,7 +70,9 @@
 				var hdrUrls = genCubeUrls( './textures/cube/pisaHDR/', '.hdr' );
 				var hdrCubeRenderTarget = null;
 
-				new THREE.HDRCubeTextureLoader().load( THREE.UnsignedByteType, hdrUrls, function ( hdrCubeMap ) {
+				new THREE.HDRCubeTextureLoader()
+					.setType( THREE.UnsignedByteType )
+					.load( hdrUrls, function ( hdrCubeMap ) {
 
 					var pmremGenerator = new THREE.PMREMGenerator( hdrCubeMap );
 					pmremGenerator.update( renderer );
@@ -185,7 +187,6 @@
 				renderer.setSize( window.innerWidth, window.innerHeight );
 				container.appendChild( renderer.domElement );
 
-				renderer.gammaInput = true;
 				renderer.gammaOutput = true;
 				renderer.toneMapping = THREE.Uncharted2ToneMapping;
 				renderer.toneMappingExposure = 0.75;

+ 3 - 2
examples/webgl_materials_variations_standard.html

@@ -75,7 +75,9 @@
 				imgTexture.anisotropy = 16;
 				imgTexture = null;
 
-				new THREE.HDRCubeTextureLoader().load( THREE.UnsignedByteType, hdrUrls, function ( hdrCubeMap ) {
+				new THREE.HDRCubeTextureLoader()
+					.setType( THREE.UnsignedByteType )
+					.load( hdrUrls, function ( hdrCubeMap ) {
 
 					var pmremGenerator = new THREE.PMREMGenerator( hdrCubeMap );
 					pmremGenerator.update( renderer );
@@ -190,7 +192,6 @@
 				renderer.setSize( window.innerWidth, window.innerHeight );
 				container.appendChild( renderer.domElement );
 
-				renderer.gammaInput = true;
 				renderer.gammaOutput = true;
 				renderer.toneMapping = THREE.Uncharted2ToneMapping;
 				renderer.toneMappingExposure = 0.75;

+ 2 - 2
examples/webgl_raycast_sprite.html

@@ -58,11 +58,11 @@
 			sprite.scale.set( 2, 5, 1 );
 			group.add( sprite );
 
-			var sprite = new THREE.Sprite( new THREE.SpriteMaterial( { color: '#69f' } ) );
+			var sprite = new THREE.Sprite( new THREE.SpriteMaterial( { color: '#69f', sizeAttenuation: false } ) );
 			sprite.material.rotation = Math.PI / 3 * 4;
 			sprite.position.set( 8, - 2, 2 );
 			sprite.center.set( 0.5, 0 );
-			sprite.scale.set( 1, - 5, 1 );
+			sprite.scale.set( .1, .5, .1 );
 			group.add( sprite );
 
 			var group2 = new THREE.Object3D();

+ 4 - 2
examples/webgl_tonemapping.html

@@ -145,13 +145,15 @@
 				// Materials
 				var hdrpath = "textures/cube/pisaHDR/";
 				var hdrformat = '.hdr';
-				var hdrurls = [
+				var hdrUrls = [
 					hdrpath + 'px' + hdrformat, hdrpath + 'nx' + hdrformat,
 					hdrpath + 'py' + hdrformat, hdrpath + 'ny' + hdrformat,
 					hdrpath + 'pz' + hdrformat, hdrpath + 'nz' + hdrformat
 				];
 
-				new THREE.HDRCubeTextureLoader().load( THREE.UnsignedByteType, hdrurls, function ( hdrCubeMap ) {
+				new THREE.HDRCubeTextureLoader()
+					.setType( THREE.UnsignedByteType )
+					.load( hdrUrls, function ( hdrCubeMap ) {
 
 					var pmremGenerator = new THREE.PMREMGenerator( hdrCubeMap );
 					pmremGenerator.update( renderer );

+ 2 - 2
examples/webvr_sculpt.html

@@ -12,13 +12,13 @@
 			<a href="http://threejs.org" target="_blank" rel="noopener">three.js</a> webvr - sculpt
 		</div>
 
-		
+
 		<script src="js/vr/HelioWebXRPolyfill.js"></script>
 		<script src="../build/three.js"></script>
 		<script src="js/vr/WebVR.js"></script>
 
 		<script src="js/loaders/OBJLoader.js"></script>
-		<script src="js/MarchingCubes.js"></script>
+		<script src="js/objects/MarchingCubes.js"></script>
 
 		<script>
 

+ 1 - 1
examples/webvr_vive_sculpt.html

@@ -19,7 +19,7 @@
 		<script src="js/vr/WebVR.js"></script>
 
 		<script src="js/loaders/OBJLoader.js"></script>
-		<script src="js/MarchingCubes.js"></script>
+		<script src="js/objects/MarchingCubes.js"></script>
 
 		<script>
 

+ 2 - 0
src/core/Raycaster.js

@@ -79,11 +79,13 @@ Object.assign( Raycaster.prototype, {
 
 			this.ray.origin.setFromMatrixPosition( camera.matrixWorld );
 			this.ray.direction.set( coords.x, coords.y, 0.5 ).unproject( camera ).sub( this.ray.origin ).normalize();
+			this._camera = camera;
 
 		} else if ( ( camera && camera.isOrthographicCamera ) ) {
 
 			this.ray.origin.set( coords.x, coords.y, ( camera.near + camera.far ) / ( camera.near - camera.far ) ).unproject( camera ); // set origin in plane of camera
 			this.ray.direction.set( 0, 0, - 1 ).transformDirection( camera.matrixWorld );
+			this._camera = camera;
 
 		} else {
 

+ 10 - 1
src/objects/Sprite.js

@@ -101,9 +101,18 @@ Sprite.prototype = Object.assign( Object.create( Object3D.prototype ), {
 		return function raycast( raycaster, intersects ) {
 
 			worldScale.setFromMatrixScale( this.matrixWorld );
-			viewWorldMatrix.getInverse( this.modelViewMatrix ).premultiply( this.matrixWorld );
+
+			viewWorldMatrix.copy( raycaster._camera.matrixWorld );
+			this.modelViewMatrix.multiplyMatrices( raycaster._camera.matrixWorldInverse, this.matrixWorld );
+
 			mvPosition.setFromMatrixPosition( this.modelViewMatrix );
 
+			if ( raycaster._camera.isPerspectiveCamera && this.material.sizeAttenuation === false ) {
+
+				worldScale.multiplyScalar( - mvPosition.z );
+
+			}
+
 			var rotation = this.material.rotation;
 			var sin, cos;
 			if ( rotation !== 0 ) {

+ 11 - 3
utils/modularize.js

@@ -50,6 +50,7 @@ var files = [
 	{ path: 'geometries/BoxLineGeometry.js', dependencies: [], ignoreList: [] },
 	{ path: 'geometries/ConvexGeometry.js', dependencies: [ { name: 'ConvexHull', path: 'math/ConvexHull.js' } ], ignoreList: [] },
 	{ path: 'geometries/DecalGeometry.js', dependencies: [], ignoreList: [] },
+	{ path: 'geometries/LightningStrike.js', dependencies: [ { name: 'SimplexNoise', path: 'math/SimplexNoise.js' } ], ignoreList: [] },
 	{ path: 'geometries/ParametricGeometries.js', dependencies: [], ignoreList: [] },
 	{ path: 'geometries/TeapotBufferGeometry.js', dependencies: [], ignoreList: [] },
 
@@ -75,13 +76,14 @@ var files = [
 	{ path: 'loaders/DDSLoader.js', dependencies: [], ignoreList: [] },
 	{ path: 'loaders/DRACOLoader.js', dependencies: [], ignoreList: [ 'LoadingManager' ] },
 	{ path: 'loaders/EXRLoader.js', dependencies: [], ignoreList: [] },
-	{ path: 'loaders/FBXLoader.js', dependencies: [ { name: 'TGALoader', path: 'loaders/TGALoader.js' }, { name: 'NURBSCurve', path: 'curves/NURBSCurve.js' } ], ignoreList: [] },
+	{ path: 'loaders/FBXLoader.js', dependencies: [ { name: 'Zlib', path: 'libs/inflate.min.js' }, { name: 'TGALoader', path: 'loaders/TGALoader.js' }, { name: 'NURBSCurve', path: 'curves/NURBSCurve.js' } ], ignoreList: [] },
 	{ path: 'loaders/GCodeLoader.js', dependencies: [], ignoreList: [] },
-	{ path: 'loaders/GLTFLoader.js', dependencies: [], ignoreList: [ 'NoSide', 'Matrix2', 'DDSLoader' ] },
+	{ path: 'loaders/GLTFLoader.js', dependencies: [], ignoreList: [ 'NoSide', 'Matrix2', 'DDSLoader', 'Camera' ] },
 	{ path: 'loaders/HDRCubeTextureLoader.js', dependencies: [ { name: 'RGBELoader', path: 'loaders/RGBELoader.js' } ], ignoreList: [] },
 	{ path: 'loaders/KMZLoader.js', dependencies: [ { name: 'ColladaLoader', path: 'loaders/ColladaLoader.js' } ], ignoreList: [] },
 	{ path: 'loaders/LWOLoader.js', dependencies: [], ignoreList: [] },
 	{ path: 'loaders/KTXLoader.js', dependencies: [], ignoreList: [] },
+	{ path: 'loaders/MD2Loader.js', dependencies: [], ignoreList: [] },
 	{ path: 'loaders/MTLLoader.js', dependencies: [], ignoreList: [ 'BackSide', 'DoubleSide', 'ClampToEdgeWrapping', 'MirroredRepeatWrapping' ] },
 	{ path: 'loaders/OBJLoader.js', dependencies: [], ignoreList: [] },
 	{ path: 'loaders/PCDLoader.js', dependencies: [], ignoreList: [] },
@@ -97,7 +99,7 @@ var files = [
 	{ path: 'loaders/TGALoader.js', dependencies: [], ignoreList: [] },
 	{ path: 'loaders/TTFLoader.js', dependencies: [], ignoreList: [ 'Font' ] },
 	{ path: 'loaders/VRMLLoader.js', dependencies: [], ignoreList: [] },
-	{ path: 'loaders/VTKLoader.js', dependencies: [], ignoreList: [] },
+	{ path: 'loaders/VTKLoader.js', dependencies: [ { name: 'Zlib', path: 'libs/inflate.min.js' } ], ignoreList: [] },
 
 	{ path: 'math/ColorConverter.js', dependencies: [], ignoreList: [] },
 	{ path: 'math/ConvexHull.js', dependencies: [], ignoreList: [] },
@@ -107,6 +109,10 @@ var files = [
 
 	{ path: 'misc/CarControls.js', dependencies: [], ignoreList: [] },
 	{ path: 'misc/ConvexObjectBreaker.js', dependencies: [ { name: 'ConvexBufferGeometry', path: 'geometries/ConvexGeometry.js' } ], ignoreList: [ 'Matrix4' ] },
+	{ path: 'misc/Gyroscope.js', dependencies: [], ignoreList: [] },
+	{ path: 'misc/MD2Character.js', dependencies: [ { name: 'MD2Loader', path: 'loaders/MD2Loader.js' } ], ignoreList: [] },
+	{ path: 'misc/MD2CharacterComplex.js', dependencies: [ { name: 'MD2Loader', path: 'loaders/MD2Loader.js' }, { name: 'MorphBlendMesh', path: 'misc/MorphBlendMesh.js' } ], ignoreList: [] },
+	{ path: 'misc/MorphBlendMesh.js', dependencies: [], ignoreList: [] },
 	{ path: 'misc/Ocean.js', dependencies: [ { name: 'OceanShaders', path: 'shaders/OceanShaders.js' } ], ignoreList: [] },
 
 	{ path: 'modifiers/ExplodeModifier.js', dependencies: [], ignoreList: [] },
@@ -116,6 +122,8 @@ var files = [
 
 	{ path: 'objects/Fire.js', dependencies: [], ignoreList: [] },
 	{ path: 'objects/Lensflare.js', dependencies: [], ignoreList: [] },
+	{ path: 'objects/LightningStorm.js', dependencies: [ { name: 'LightningStrike', path: 'geometries/LightningStrike.js' } ], ignoreList: [] },
+	{ path: 'objects/MarchingCubes.js', dependencies: [], ignoreList: [] },
 	{ path: 'objects/Reflector.js', dependencies: [], ignoreList: [] },
 	{ path: 'objects/Refractor.js', dependencies: [], ignoreList: [] },
 	{ path: 'objects/ReflectorRTT.js', dependencies: [ { name: 'Reflector', path: 'objects/Reflector.js' } ], ignoreList: [] },