Browse Source

Examples: Convert misc to ES6. (#21618)

Michael Herzog 4 years ago
parent
commit
3452a4e33c

+ 158 - 158
examples/js/misc/ConvexObjectBreaker.js

@@ -29,40 +29,42 @@
  *
  *
 */
 */
 
 
-	var ConvexObjectBreaker = function ( minSizeForBreak, smallDelta ) {
-
-		this.minSizeForBreak = minSizeForBreak || 1.4;
-		this.smallDelta = smallDelta || 0.0001;
-		this.tempLine1 = new THREE.Line3();
-		this.tempPlane1 = new THREE.Plane();
-		this.tempPlane2 = new THREE.Plane();
-		this.tempPlane_Cut = new THREE.Plane();
-		this.tempCM1 = new THREE.Vector3();
-		this.tempCM2 = new THREE.Vector3();
-		this.tempVector3 = new THREE.Vector3();
-		this.tempVector3_2 = new THREE.Vector3();
-		this.tempVector3_3 = new THREE.Vector3();
-		this.tempVector3_P0 = new THREE.Vector3();
-		this.tempVector3_P1 = new THREE.Vector3();
-		this.tempVector3_P2 = new THREE.Vector3();
-		this.tempVector3_N0 = new THREE.Vector3();
-		this.tempVector3_N1 = new THREE.Vector3();
-		this.tempVector3_AB = new THREE.Vector3();
-		this.tempVector3_CB = new THREE.Vector3();
-		this.tempResultObjects = {
-			object1: null,
-			object2: null
-		};
-		this.segments = [];
-		var n = 30 * 30;
-
-		for ( var i = 0; i < n; i ++ ) this.segments[ i ] = false;
-
-	};
-
-	ConvexObjectBreaker.prototype = {
-		constructor: ConvexObjectBreaker,
-		prepareBreakableObject: function ( object, mass, velocity, angularVelocity, breakable ) {
+	const _v1 = new THREE.Vector3();
+
+	class ConvexObjectBreaker {
+
+		constructor( minSizeForBreak = 1.4, smallDelta = 0.0001 ) {
+
+			this.minSizeForBreak = minSizeForBreak;
+			this.smallDelta = smallDelta;
+			this.tempLine1 = new THREE.Line3();
+			this.tempPlane1 = new THREE.Plane();
+			this.tempPlane2 = new THREE.Plane();
+			this.tempPlane_Cut = new THREE.Plane();
+			this.tempCM1 = new THREE.Vector3();
+			this.tempCM2 = new THREE.Vector3();
+			this.tempVector3 = new THREE.Vector3();
+			this.tempVector3_2 = new THREE.Vector3();
+			this.tempVector3_3 = new THREE.Vector3();
+			this.tempVector3_P0 = new THREE.Vector3();
+			this.tempVector3_P1 = new THREE.Vector3();
+			this.tempVector3_P2 = new THREE.Vector3();
+			this.tempVector3_N0 = new THREE.Vector3();
+			this.tempVector3_N1 = new THREE.Vector3();
+			this.tempVector3_AB = new THREE.Vector3();
+			this.tempVector3_CB = new THREE.Vector3();
+			this.tempResultObjects = {
+				object1: null,
+				object2: null
+			};
+			this.segments = [];
+			const n = 30 * 30;
+
+			for ( let i = 0; i < n; i ++ ) this.segments[ i ] = false;
+
+		}
+
+		prepareBreakableObject( object, mass, velocity, angularVelocity, breakable ) {
 
 
 			// object is a Object3d (normally a THREE.Mesh), must have a BufferGeometry, and it must be convex.
 			// object is a Object3d (normally a THREE.Mesh), must have a BufferGeometry, and it must be convex.
 			// Its material property is propagated to its children (sub-pieces)
 			// Its material property is propagated to its children (sub-pieces)
@@ -73,29 +75,30 @@
 
 
 			}
 			}
 
 
-			var userData = object.userData;
+			const userData = object.userData;
 			userData.mass = mass;
 			userData.mass = mass;
 			userData.velocity = velocity.clone();
 			userData.velocity = velocity.clone();
 			userData.angularVelocity = angularVelocity.clone();
 			userData.angularVelocity = angularVelocity.clone();
 			userData.breakable = breakable;
 			userData.breakable = breakable;
 
 
-		},
-
+		}
 		/*
 		/*
 	 * @param {int} maxRadialIterations Iterations for radial cuts.
 	 * @param {int} maxRadialIterations Iterations for radial cuts.
 	 * @param {int} maxRandomIterations Max random iterations for not-radial cuts
 	 * @param {int} maxRandomIterations Max random iterations for not-radial cuts
 	 *
 	 *
 	 * Returns the array of pieces
 	 * Returns the array of pieces
 	 */
 	 */
-		subdivideByImpact: function ( object, pointOfImpact, normal, maxRadialIterations, maxRandomIterations ) {
 
 
-			var debris = [];
-			var tempPlane1 = this.tempPlane1;
-			var tempPlane2 = this.tempPlane2;
+
+		subdivideByImpact( object, pointOfImpact, normal, maxRadialIterations, maxRandomIterations ) {
+
+			const debris = [];
+			const tempPlane1 = this.tempPlane1;
+			const tempPlane2 = this.tempPlane2;
 			this.tempVector3.addVectors( pointOfImpact, normal );
 			this.tempVector3.addVectors( pointOfImpact, normal );
 			tempPlane1.setFromCoplanarPoints( pointOfImpact, object.position, this.tempVector3 );
 			tempPlane1.setFromCoplanarPoints( pointOfImpact, object.position, this.tempVector3 );
-			var maxTotalIterations = maxRandomIterations + maxRadialIterations;
-			var scope = this;
+			const maxTotalIterations = maxRandomIterations + maxRadialIterations;
+			const scope = this;
 
 
 			function subdivideRadial( subObject, startAngle, endAngle, numIterations ) {
 			function subdivideRadial( subObject, startAngle, endAngle, numIterations ) {
 
 
@@ -106,7 +109,7 @@
 
 
 				}
 				}
 
 
-				var angle = Math.PI;
+				let angle = Math.PI;
 
 
 				if ( numIterations === 0 ) {
 				if ( numIterations === 0 ) {
 
 
@@ -136,8 +139,8 @@
 
 
 
 
 				scope.cutByPlane( subObject, tempPlane2, scope.tempResultObjects );
 				scope.cutByPlane( subObject, tempPlane2, scope.tempResultObjects );
-				var obj1 = scope.tempResultObjects.object1;
-				var obj2 = scope.tempResultObjects.object2;
+				const obj1 = scope.tempResultObjects.object1;
+				const obj2 = scope.tempResultObjects.object2;
 
 
 				if ( obj1 ) {
 				if ( obj1 ) {
 
 
@@ -156,19 +159,20 @@
 			subdivideRadial( object, 0, 2 * Math.PI, 0 );
 			subdivideRadial( object, 0, 2 * Math.PI, 0 );
 			return debris;
 			return debris;
 
 
-		},
-		cutByPlane: function ( object, plane, output ) {
+		}
+
+		cutByPlane( object, plane, output ) {
 
 
 			// Returns breakable objects in output.object1 and output.object2 members, the resulting 2 pieces of the cut.
 			// Returns breakable objects in output.object1 and output.object2 members, the resulting 2 pieces of the cut.
 			// object2 can be null if the plane doesn't cut the object.
 			// object2 can be null if the plane doesn't cut the object.
 			// object1 can be null only in case of internal error
 			// object1 can be null only in case of internal error
 			// Returned value is number of pieces, 0 for error.
 			// Returned value is number of pieces, 0 for error.
-			var geometry = object.geometry;
-			var coords = geometry.attributes.position.array;
-			var normals = geometry.attributes.normal.array;
-			var numPoints = coords.length / 3;
-			var numFaces = numPoints / 3;
-			var indices = geometry.getIndex();
+			const geometry = object.geometry;
+			const coords = geometry.attributes.position.array;
+			const normals = geometry.attributes.normal.array;
+			const numPoints = coords.length / 3;
+			let numFaces = numPoints / 3;
+			let indices = geometry.getIndex();
 
 
 			if ( indices ) {
 			if ( indices ) {
 
 
@@ -180,40 +184,40 @@
 			function getVertexIndex( faceIdx, vert ) {
 			function getVertexIndex( faceIdx, vert ) {
 
 
 				// vert = 0, 1 or 2.
 				// vert = 0, 1 or 2.
-				var idx = faceIdx * 3 + vert;
+				const idx = faceIdx * 3 + vert;
 				return indices ? indices[ idx ] : idx;
 				return indices ? indices[ idx ] : idx;
 
 
 			}
 			}
 
 
-			var points1 = [];
-			var points2 = [];
-			var delta = this.smallDelta; // Reset segments mark
+			const points1 = [];
+			const points2 = [];
+			const delta = this.smallDelta; // Reset segments mark
 
 
-			var numPointPairs = numPoints * numPoints;
+			const numPointPairs = numPoints * numPoints;
 
 
-			for ( var i = 0; i < numPointPairs; i ++ ) this.segments[ i ] = false;
+			for ( let i = 0; i < numPointPairs; i ++ ) this.segments[ i ] = false;
 
 
-			var p0 = this.tempVector3_P0;
-			var p1 = this.tempVector3_P1;
-			var n0 = this.tempVector3_N0;
-			var n1 = this.tempVector3_N1; // Iterate through the faces to mark edges shared by coplanar faces
+			const p0 = this.tempVector3_P0;
+			const p1 = this.tempVector3_P1;
+			const n0 = this.tempVector3_N0;
+			const n1 = this.tempVector3_N1; // Iterate through the faces to mark edges shared by coplanar faces
 
 
-			for ( var i = 0; i < numFaces - 1; i ++ ) {
+			for ( let i = 0; i < numFaces - 1; i ++ ) {
 
 
-				var a1 = getVertexIndex( i, 0 );
-				var b1 = getVertexIndex( i, 1 );
-				var c1 = getVertexIndex( i, 2 ); // Assuming all 3 vertices have the same normal
+				const a1 = getVertexIndex( i, 0 );
+				const b1 = getVertexIndex( i, 1 );
+				const c1 = getVertexIndex( i, 2 ); // Assuming all 3 vertices have the same normal
 
 
 				n0.set( normals[ a1 ], normals[ a1 ] + 1, normals[ a1 ] + 2 );
 				n0.set( normals[ a1 ], normals[ a1 ] + 1, normals[ a1 ] + 2 );
 
 
-				for ( var j = i + 1; j < numFaces; j ++ ) {
+				for ( let j = i + 1; j < numFaces; j ++ ) {
 
 
-					var a2 = getVertexIndex( j, 0 );
-					var b2 = getVertexIndex( j, 1 );
-					var c2 = getVertexIndex( j, 2 ); // Assuming all 3 vertices have the same normal
+					const a2 = getVertexIndex( j, 0 );
+					const b2 = getVertexIndex( j, 1 );
+					const c2 = getVertexIndex( j, 2 ); // Assuming all 3 vertices have the same normal
 
 
 					n1.set( normals[ a2 ], normals[ a2 ] + 1, normals[ a2 ] + 2 );
 					n1.set( normals[ a2 ], normals[ a2 ] + 1, normals[ a2 ] + 2 );
-					var coplanar = 1 - n0.dot( n1 ) < delta;
+					const coplanar = 1 - n0.dot( n1 ) < delta;
 
 
 					if ( coplanar ) {
 					if ( coplanar ) {
 
 
@@ -245,21 +249,21 @@
 			} // Transform the plane to object local space
 			} // Transform the plane to object local space
 
 
 
 
-			var localPlane = this.tempPlane_Cut;
+			const localPlane = this.tempPlane_Cut;
 			object.updateMatrix();
 			object.updateMatrix();
 			ConvexObjectBreaker.transformPlaneToLocalSpace( plane, object.matrix, localPlane ); // Iterate through the faces adding points to both pieces
 			ConvexObjectBreaker.transformPlaneToLocalSpace( plane, object.matrix, localPlane ); // Iterate through the faces adding points to both pieces
 
 
-			for ( var i = 0; i < numFaces; i ++ ) {
+			for ( let i = 0; i < numFaces; i ++ ) {
 
 
-				var va = getVertexIndex( i, 0 );
-				var vb = getVertexIndex( i, 1 );
-				var vc = getVertexIndex( i, 2 );
+				const va = getVertexIndex( i, 0 );
+				const vb = getVertexIndex( i, 1 );
+				const vc = getVertexIndex( i, 2 );
 
 
-				for ( var segment = 0; segment < 3; segment ++ ) {
+				for ( let segment = 0; segment < 3; segment ++ ) {
 
 
-					var i0 = segment === 0 ? va : segment === 1 ? vb : vc;
-					var i1 = segment === 0 ? vb : segment === 1 ? vc : va;
-					var segmentState = this.segments[ i0 * numPoints + i1 ];
+					const i0 = segment === 0 ? va : segment === 1 ? vb : vc;
+					const i1 = segment === 0 ? vb : segment === 1 ? vc : va;
+					const segmentState = this.segments[ i0 * numPoints + i1 ];
 					if ( segmentState ) continue; // The segment already has been processed in another face
 					if ( segmentState ) continue; // The segment already has been processed in another face
 					// Mark segment as processed (also inverted segment)
 					// Mark segment as processed (also inverted segment)
 
 
@@ -268,8 +272,8 @@
 					p0.set( coords[ 3 * i0 ], coords[ 3 * i0 + 1 ], coords[ 3 * i0 + 2 ] );
 					p0.set( coords[ 3 * i0 ], coords[ 3 * i0 + 1 ], coords[ 3 * i0 + 2 ] );
 					p1.set( coords[ 3 * i1 ], coords[ 3 * i1 + 1 ], coords[ 3 * i1 + 2 ] ); // mark: 1 for negative side, 2 for positive side, 3 for coplanar point
 					p1.set( coords[ 3 * i1 ], coords[ 3 * i1 + 1 ], coords[ 3 * i1 + 2 ] ); // mark: 1 for negative side, 2 for positive side, 3 for coplanar point
 
 
-					var mark0 = 0;
-					var d = localPlane.distanceToPoint( p0 );
+					let mark0 = 0;
+					let d = localPlane.distanceToPoint( p0 );
 
 
 					if ( d > delta ) {
 					if ( d > delta ) {
 
 
@@ -290,8 +294,8 @@
 					} // mark: 1 for negative side, 2 for positive side, 3 for coplanar point
 					} // mark: 1 for negative side, 2 for positive side, 3 for coplanar point
 
 
 
 
-					var mark1 = 0;
-					var d = localPlane.distanceToPoint( p1 );
+					let mark1 = 0;
+					d = localPlane.distanceToPoint( p1 );
 
 
 					if ( d > delta ) {
 					if ( d > delta ) {
 
 
@@ -316,7 +320,7 @@
 						// Intersection of segment with the plane
 						// Intersection of segment with the plane
 						this.tempLine1.start.copy( p0 );
 						this.tempLine1.start.copy( p0 );
 						this.tempLine1.end.copy( p1 );
 						this.tempLine1.end.copy( p1 );
-						var intersection = new THREE.Vector3();
+						let intersection = new THREE.Vector3();
 						intersection = localPlane.intersectLine( this.tempLine1, intersection );
 						intersection = localPlane.intersectLine( this.tempLine1, intersection );
 
 
 						if ( intersection === null ) {
 						if ( intersection === null ) {
@@ -339,21 +343,21 @@
 			} // Calculate debris mass (very fast and imprecise):
 			} // Calculate debris mass (very fast and imprecise):
 
 
 
 
-			var newMass = object.userData.mass * 0.5; // Calculate debris Center of Mass (again fast and imprecise)
+			const newMass = object.userData.mass * 0.5; // Calculate debris Center of Mass (again fast and imprecise)
 
 
 			this.tempCM1.set( 0, 0, 0 );
 			this.tempCM1.set( 0, 0, 0 );
-			var radius1 = 0;
-			var numPoints1 = points1.length;
+			let radius1 = 0;
+			const numPoints1 = points1.length;
 
 
 			if ( numPoints1 > 0 ) {
 			if ( numPoints1 > 0 ) {
 
 
-				for ( var i = 0; i < numPoints1; i ++ ) this.tempCM1.add( points1[ i ] );
+				for ( let i = 0; i < numPoints1; i ++ ) this.tempCM1.add( points1[ i ] );
 
 
 				this.tempCM1.divideScalar( numPoints1 );
 				this.tempCM1.divideScalar( numPoints1 );
 
 
-				for ( var i = 0; i < numPoints1; i ++ ) {
+				for ( let i = 0; i < numPoints1; i ++ ) {
 
 
-					var p = points1[ i ];
+					const p = points1[ i ];
 					p.sub( this.tempCM1 );
 					p.sub( this.tempCM1 );
 					radius1 = Math.max( radius1, p.x, p.y, p.z );
 					radius1 = Math.max( radius1, p.x, p.y, p.z );
 
 
@@ -364,18 +368,18 @@
 			}
 			}
 
 
 			this.tempCM2.set( 0, 0, 0 );
 			this.tempCM2.set( 0, 0, 0 );
-			var radius2 = 0;
-			var numPoints2 = points2.length;
+			let radius2 = 0;
+			const numPoints2 = points2.length;
 
 
 			if ( numPoints2 > 0 ) {
 			if ( numPoints2 > 0 ) {
 
 
-				for ( var i = 0; i < numPoints2; i ++ ) this.tempCM2.add( points2[ i ] );
+				for ( let i = 0; i < numPoints2; i ++ ) this.tempCM2.add( points2[ i ] );
 
 
 				this.tempCM2.divideScalar( numPoints2 );
 				this.tempCM2.divideScalar( numPoints2 );
 
 
-				for ( var i = 0; i < numPoints2; i ++ ) {
+				for ( let i = 0; i < numPoints2; i ++ ) {
 
 
-					var p = points2[ i ];
+					const p = points2[ i ];
 					p.sub( this.tempCM2 );
 					p.sub( this.tempCM2 );
 					radius2 = Math.max( radius2, p.x, p.y, p.z );
 					radius2 = Math.max( radius2, p.x, p.y, p.z );
 
 
@@ -385,9 +389,9 @@
 
 
 			}
 			}
 
 
-			var object1 = null;
-			var object2 = null;
-			var numObjects = 0;
+			let object1 = null;
+			let object2 = null;
+			let numObjects = 0;
 
 
 			if ( numPoints1 > 4 ) {
 			if ( numPoints1 > 4 ) {
 
 
@@ -414,71 +418,67 @@
 			return numObjects;
 			return numObjects;
 
 
 		}
 		}
-	};
-
-	ConvexObjectBreaker.transformFreeVector = function ( v, m ) {
-
-		// input:
-		// vector interpreted as a free vector
-		// THREE.Matrix4 orthogonal matrix (matrix without scale)
-		var x = v.x,
-			y = v.y,
-			z = v.z;
-		var e = m.elements;
-		v.x = e[ 0 ] * x + e[ 4 ] * y + e[ 8 ] * z;
-		v.y = e[ 1 ] * x + e[ 5 ] * y + e[ 9 ] * z;
-		v.z = e[ 2 ] * x + e[ 6 ] * y + e[ 10 ] * z;
-		return v;
-
-	};
-
-	ConvexObjectBreaker.transformFreeVectorInverse = function ( v, m ) {
-
-		// input:
-		// vector interpreted as a free vector
-		// THREE.Matrix4 orthogonal matrix (matrix without scale)
-		var x = v.x,
-			y = v.y,
-			z = v.z;
-		var e = m.elements;
-		v.x = e[ 0 ] * x + e[ 1 ] * y + e[ 2 ] * z;
-		v.y = e[ 4 ] * x + e[ 5 ] * y + e[ 6 ] * z;
-		v.z = e[ 8 ] * x + e[ 9 ] * y + e[ 10 ] * z;
-		return v;
-
-	};
-
-	ConvexObjectBreaker.transformTiedVectorInverse = function ( v, m ) {
-
-		// input:
-		// vector interpreted as a tied (ordinary) vector
-		// THREE.Matrix4 orthogonal matrix (matrix without scale)
-		var x = v.x,
-			y = v.y,
-			z = v.z;
-		var e = m.elements;
-		v.x = e[ 0 ] * x + e[ 1 ] * y + e[ 2 ] * z - e[ 12 ];
-		v.y = e[ 4 ] * x + e[ 5 ] * y + e[ 6 ] * z - e[ 13 ];
-		v.z = e[ 8 ] * x + e[ 9 ] * y + e[ 10 ] * z - e[ 14 ];
-		return v;
-
-	};
-
-	ConvexObjectBreaker.transformPlaneToLocalSpace = function () {
-
-		var v1 = new THREE.Vector3();
-		return function transformPlaneToLocalSpace( plane, m, resultPlane ) {
+
+		static transformFreeVector( v, m ) {
+
+			// input:
+			// vector interpreted as a free vector
+			// THREE.Matrix4 orthogonal matrix (matrix without scale)
+			const x = v.x,
+				y = v.y,
+				z = v.z;
+			const e = m.elements;
+			v.x = e[ 0 ] * x + e[ 4 ] * y + e[ 8 ] * z;
+			v.y = e[ 1 ] * x + e[ 5 ] * y + e[ 9 ] * z;
+			v.z = e[ 2 ] * x + e[ 6 ] * y + e[ 10 ] * z;
+			return v;
+
+		}
+
+		static transformFreeVectorInverse( v, m ) {
+
+			// input:
+			// vector interpreted as a free vector
+			// THREE.Matrix4 orthogonal matrix (matrix without scale)
+			const x = v.x,
+				y = v.y,
+				z = v.z;
+			const e = m.elements;
+			v.x = e[ 0 ] * x + e[ 1 ] * y + e[ 2 ] * z;
+			v.y = e[ 4 ] * x + e[ 5 ] * y + e[ 6 ] * z;
+			v.z = e[ 8 ] * x + e[ 9 ] * y + e[ 10 ] * z;
+			return v;
+
+		}
+
+		static transformTiedVectorInverse( v, m ) {
+
+			// input:
+			// vector interpreted as a tied (ordinary) vector
+			// THREE.Matrix4 orthogonal matrix (matrix without scale)
+			const x = v.x,
+				y = v.y,
+				z = v.z;
+			const e = m.elements;
+			v.x = e[ 0 ] * x + e[ 1 ] * y + e[ 2 ] * z - e[ 12 ];
+			v.y = e[ 4 ] * x + e[ 5 ] * y + e[ 6 ] * z - e[ 13 ];
+			v.z = e[ 8 ] * x + e[ 9 ] * y + e[ 10 ] * z - e[ 14 ];
+			return v;
+
+		}
+
+		static transformPlaneToLocalSpace( plane, m, resultPlane ) {
 
 
 			resultPlane.normal.copy( plane.normal );
 			resultPlane.normal.copy( plane.normal );
 			resultPlane.constant = plane.constant;
 			resultPlane.constant = plane.constant;
-			var referencePoint = ConvexObjectBreaker.transformTiedVectorInverse( plane.coplanarPoint( v1 ), m );
+			const referencePoint = ConvexObjectBreaker.transformTiedVectorInverse( plane.coplanarPoint( _v1 ), m );
 			ConvexObjectBreaker.transformFreeVectorInverse( resultPlane.normal, m ); // recalculate constant (like in setFromNormalAndCoplanarPoint)
 			ConvexObjectBreaker.transformFreeVectorInverse( resultPlane.normal, m ); // recalculate constant (like in setFromNormalAndCoplanarPoint)
 
 
 			resultPlane.constant = - referencePoint.dot( resultPlane.normal );
 			resultPlane.constant = - referencePoint.dot( resultPlane.normal );
 
 
-		};
+		}
 
 
-	}();
+	}
 
 
 	THREE.ConvexObjectBreaker = ConvexObjectBreaker;
 	THREE.ConvexObjectBreaker = ConvexObjectBreaker;
 
 

+ 178 - 174
examples/js/misc/GPUComputationRenderer.js

@@ -28,16 +28,16 @@
  * // Initialization...
  * // Initialization...
  *
  *
  * // Create computation renderer
  * // Create computation renderer
- * var gpuCompute = new GPUComputationRenderer( 1024, 1024, renderer );
+ * const gpuCompute = new GPUComputationRenderer( 1024, 1024, renderer );
  *
  *
  * // Create initial state float textures
  * // Create initial state float textures
- * var pos0 = gpuCompute.createTexture();
- * var vel0 = gpuCompute.createTexture();
+ * const pos0 = gpuCompute.createTexture();
+ * const vel0 = gpuCompute.createTexture();
  * // and fill in here the texture data...
  * // and fill in here the texture data...
  *
  *
  * // Add texture variables
  * // Add texture variables
- * var velVar = gpuCompute.addVariable( "textureVelocity", fragmentShaderVel, pos0 );
- * var posVar = gpuCompute.addVariable( "texturePosition", fragmentShaderPos, vel0 );
+ * const velVar = gpuCompute.addVariable( "textureVelocity", fragmentShaderVel, pos0 );
+ * const posVar = gpuCompute.addVariable( "texturePosition", fragmentShaderPos, vel0 );
  *
  *
  * // Add variable dependencies
  * // Add variable dependencies
  * gpuCompute.setVariableDependencies( velVar, [ velVar, posVar ] );
  * gpuCompute.setVariableDependencies( velVar, [ velVar, posVar ] );
@@ -47,7 +47,7 @@
  * velVar.material.uniforms.time = { value: 0.0 };
  * velVar.material.uniforms.time = { value: 0.0 };
  *
  *
  * // Check for completeness
  * // Check for completeness
- * var error = gpuCompute.init();
+ * const error = gpuCompute.init();
  * if ( error !== null ) {
  * if ( error !== null ) {
  *		console.error( error );
  *		console.error( error );
 	* }
 	* }
@@ -69,19 +69,19 @@
  * Also, you can use utility functions to create THREE.ShaderMaterial and perform computations (rendering between textures)
  * Also, you can use utility functions to create THREE.ShaderMaterial and perform computations (rendering between textures)
  * Note that the shaders can have multiple input 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 } } );
+ * const myFilter1 = gpuCompute.createShaderMaterial( myFilterFragmentShader1, { theTexture: { value: null } } );
+ * const myFilter2 = gpuCompute.createShaderMaterial( myFilterFragmentShader2, { theTexture: { value: null } } );
  *
  *
- * var inputTexture = gpuCompute.createTexture();
+ * const inputTexture = gpuCompute.createTexture();
  *
  *
  * // Fill in here inputTexture...
  * // Fill in here inputTexture...
  *
  *
  * myFilter1.uniforms.theTexture.value = inputTexture;
  * myFilter1.uniforms.theTexture.value = inputTexture;
  *
  *
- * var myRenderTarget = gpuCompute.createRenderTarget();
+ * const myRenderTarget = gpuCompute.createRenderTarget();
  * myFilter2.uniforms.theTexture.value = myRenderTarget.texture;
  * myFilter2.uniforms.theTexture.value = myRenderTarget.texture;
  *
  *
- * var outputRenderTarget = gpuCompute.createRenderTarget();
+ * const outputRenderTarget = gpuCompute.createRenderTarget();
  *
  *
  * // Now use the output texture where you want:
  * // Now use the output texture where you want:
  * myMaterial.uniforms.map.value = outputRenderTarget.texture;
  * myMaterial.uniforms.map.value = outputRenderTarget.texture;
@@ -97,257 +97,261 @@
  * @param {WebGLRenderer} renderer The renderer
  * @param {WebGLRenderer} renderer The renderer
 	*/
 	*/
 
 
-	var GPUComputationRenderer = function ( sizeX, sizeY, renderer ) {
-
-		this.variables = [];
-		this.currentTextureIndex = 0;
-		var dataType = THREE.FloatType;
-		var scene = new THREE.Scene();
-		var camera = new THREE.Camera();
-		camera.position.z = 1;
-		var passThruUniforms = {
-			passThruTexture: {
-				value: null
-			}
-		};
-		var passThruShader = createShaderMaterial( getPassThroughFragmentShader(), passThruUniforms );
-		var mesh = new THREE.Mesh( new THREE.PlaneGeometry( 2, 2 ), passThruShader );
-		scene.add( mesh );
-
-		this.setDataType = function ( type ) {
-
-			dataType = type;
-			return this;
-
-		};
-
-		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: THREE.NearestFilter,
-				magFilter: THREE.NearestFilter
+	class GPUComputationRenderer {
+
+		constructor( sizeX, sizeY, renderer ) {
+
+			this.variables = [];
+			this.currentTextureIndex = 0;
+			let dataType = THREE.FloatType;
+			const scene = new THREE.Scene();
+			const camera = new THREE.Camera();
+			camera.position.z = 1;
+			const passThruUniforms = {
+				passThruTexture: {
+					value: null
+				}
 			};
 			};
-			this.variables.push( variable );
-			return variable;
+			const passThruShader = createShaderMaterial( getPassThroughFragmentShader(), passThruUniforms );
+			const mesh = new THREE.Mesh( new THREE.PlaneGeometry( 2, 2 ), passThruShader );
+			scene.add( mesh );
 
 
-		};
+			this.setDataType = function ( type ) {
 
 
-		this.setVariableDependencies = function ( variable, dependencies ) {
+				dataType = type;
+				return this;
 
 
-			variable.dependencies = dependencies;
+			};
 
 
-		};
+			this.addVariable = function ( variableName, computeFragmentShader, initialValueTexture ) {
+
+				const material = this.createShaderMaterial( computeFragmentShader );
+				const variable = {
+					name: variableName,
+					initialValueTexture: initialValueTexture,
+					material: material,
+					dependencies: null,
+					renderTargets: [],
+					wrapS: null,
+					wrapT: null,
+					minFilter: THREE.NearestFilter,
+					magFilter: THREE.NearestFilter
+				};
+				this.variables.push( variable );
+				return variable;
 
 
-		this.init = function () {
+			};
 
 
-			if ( renderer.capabilities.isWebGL2 === false && renderer.extensions.has( 'OES_texture_float' ) === false ) {
+			this.setVariableDependencies = function ( variable, dependencies ) {
 
 
-				return 'No OES_texture_float support for float textures.';
+				variable.dependencies = dependencies;
 
 
-			}
+			};
 
 
-			if ( renderer.capabilities.maxVertexTextures === 0 ) {
+			this.init = function () {
 
 
-				return 'No support for vertex shader textures.';
+				if ( renderer.capabilities.isWebGL2 === false && renderer.extensions.has( 'OES_texture_float' ) === false ) {
 
 
-			}
+					return 'No OES_texture_float support for float textures.';
+
+				}
+
+				if ( renderer.capabilities.maxVertexTextures === 0 ) {
+
+					return 'No support for vertex shader textures.';
+
+				}
+
+				for ( let i = 0; i < this.variables.length; i ++ ) {
 
 
-			for ( var i = 0; i < this.variables.length; i ++ ) {
+					const variable = this.variables[ i ]; // Creates rendertargets and initialize them with input texture
 
 
-				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 THREE.ShaderMaterial
 
 
-				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 THREE.ShaderMaterial
+					const material = variable.material;
+					const uniforms = material.uniforms;
 
 
-				var material = variable.material;
-				var uniforms = material.uniforms;
+					if ( variable.dependencies !== null ) {
 
 
-				if ( variable.dependencies !== null ) {
+						for ( let d = 0; d < variable.dependencies.length; d ++ ) {
 
 
-					for ( var d = 0; d < variable.dependencies.length; d ++ ) {
+							const depVar = variable.dependencies[ d ];
 
 
-						var depVar = variable.dependencies[ d ];
+							if ( depVar.name !== variable.name ) {
 
 
-						if ( depVar.name !== variable.name ) {
+								// Checks if variable exists
+								let found = false;
 
 
-							// Checks if variable exists
-							var found = false;
+								for ( let j = 0; j < this.variables.length; j ++ ) {
 
 
-							for ( var j = 0; j < this.variables.length; j ++ ) {
+									if ( depVar.name === this.variables[ j ].name ) {
 
 
-								if ( depVar.name === this.variables[ j ].name ) {
+										found = true;
+										break;
 
 
-									found = true;
-									break;
+									}
 
 
 								}
 								}
 
 
-							}
+								if ( ! found ) {
 
 
-							if ( ! found ) {
+									return 'Variable dependency not found. Variable=' + variable.name + ', dependency=' + depVar.name;
 
 
-								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;
 
 
-						uniforms[ depVar.name ] = {
-							value: null
-						};
-						material.fragmentShader = '\nuniform sampler2D ' + depVar.name + ';\n' + material.fragmentShader;
+						}
 
 
 					}
 					}
 
 
 				}
 				}
 
 
-			}
+				this.currentTextureIndex = 0;
+				return null;
 
 
-			this.currentTextureIndex = 0;
-			return null;
-
-		};
+			};
 
 
-		this.compute = function () {
+			this.compute = function () {
 
 
-			var currentTextureIndex = this.currentTextureIndex;
-			var nextTextureIndex = this.currentTextureIndex === 0 ? 1 : 0;
+				const currentTextureIndex = this.currentTextureIndex;
+				const nextTextureIndex = this.currentTextureIndex === 0 ? 1 : 0;
 
 
-			for ( var i = 0, il = this.variables.length; i < il; i ++ ) {
+				for ( let i = 0, il = this.variables.length; i < il; i ++ ) {
 
 
-				var variable = this.variables[ i ]; // Sets texture dependencies uniforms
+					const variable = this.variables[ i ]; // Sets texture dependencies uniforms
 
 
-				if ( variable.dependencies !== null ) {
+					if ( variable.dependencies !== null ) {
 
 
-					var uniforms = variable.material.uniforms;
+						const uniforms = variable.material.uniforms;
 
 
-					for ( var d = 0, dl = variable.dependencies.length; d < dl; d ++ ) {
+						for ( let d = 0, dl = variable.dependencies.length; d < dl; d ++ ) {
 
 
-						var depVar = variable.dependencies[ d ];
-						uniforms[ depVar.name ].value = depVar.renderTargets[ currentTextureIndex ].texture;
+							const depVar = variable.dependencies[ d ];
+							uniforms[ depVar.name ].value = depVar.renderTargets[ currentTextureIndex ].texture;
 
 
-					}
+						}
 
 
-				} // Performs the computation for this variable
+					} // Performs the computation for this variable
 
 
 
 
-				this.doRenderTarget( variable.material, variable.renderTargets[ nextTextureIndex ] );
+					this.doRenderTarget( variable.material, variable.renderTargets[ nextTextureIndex ] );
 
 
-			}
+				}
 
 
-			this.currentTextureIndex = nextTextureIndex;
+				this.currentTextureIndex = nextTextureIndex;
 
 
-		};
+			};
 
 
-		this.getCurrentRenderTarget = function ( variable ) {
+			this.getCurrentRenderTarget = function ( variable ) {
 
 
-			return variable.renderTargets[ this.currentTextureIndex ];
+				return variable.renderTargets[ this.currentTextureIndex ];
 
 
-		};
+			};
 
 
-		this.getAlternateRenderTarget = function ( variable ) {
+			this.getAlternateRenderTarget = function ( variable ) {
 
 
-			return variable.renderTargets[ this.currentTextureIndex === 0 ? 1 : 0 ];
+				return variable.renderTargets[ this.currentTextureIndex === 0 ? 1 : 0 ];
 
 
-		};
+			};
 
 
-		function addResolutionDefine( materialShader ) {
+			function addResolutionDefine( materialShader ) {
 
 
-			materialShader.defines.resolution = 'vec2( ' + sizeX.toFixed( 1 ) + ', ' + sizeY.toFixed( 1 ) + ' )';
+				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 ) {
+			this.addResolutionDefine = addResolutionDefine; // The following functions can be used to compute things manually
 
 
-			uniforms = uniforms || {};
-			var material = new THREE.ShaderMaterial( {
-				uniforms: uniforms,
-				vertexShader: getPassThroughVertexShader(),
-				fragmentShader: computeFragmentShader
-			} );
-			addResolutionDefine( material );
-			return material;
+			function createShaderMaterial( computeFragmentShader, uniforms ) {
 
 
-		}
+				uniforms = uniforms || {};
+				const material = new THREE.ShaderMaterial( {
+					uniforms: uniforms,
+					vertexShader: getPassThroughVertexShader(),
+					fragmentShader: computeFragmentShader
+				} );
+				addResolutionDefine( material );
+				return material;
 
 
-		this.createShaderMaterial = createShaderMaterial;
+			}
 
 
-		this.createRenderTarget = function ( sizeXTexture, sizeYTexture, wrapS, wrapT, minFilter, magFilter ) {
+			this.createShaderMaterial = createShaderMaterial;
+
+			this.createRenderTarget = function ( sizeXTexture, sizeYTexture, wrapS, wrapT, minFilter, magFilter ) {
+
+				sizeXTexture = sizeXTexture || sizeX;
+				sizeYTexture = sizeYTexture || sizeY;
+				wrapS = wrapS || THREE.ClampToEdgeWrapping;
+				wrapT = wrapT || THREE.ClampToEdgeWrapping;
+				minFilter = minFilter || THREE.NearestFilter;
+				magFilter = magFilter || THREE.NearestFilter;
+				const renderTarget = new THREE.WebGLRenderTarget( sizeXTexture, sizeYTexture, {
+					wrapS: wrapS,
+					wrapT: wrapT,
+					minFilter: minFilter,
+					magFilter: magFilter,
+					format: THREE.RGBAFormat,
+					type: dataType,
+					depthBuffer: false
+				} );
+				return renderTarget;
 
 
-			sizeXTexture = sizeXTexture || sizeX;
-			sizeYTexture = sizeYTexture || sizeY;
-			wrapS = wrapS || THREE.ClampToEdgeWrapping;
-			wrapT = wrapT || THREE.ClampToEdgeWrapping;
-			minFilter = minFilter || THREE.NearestFilter;
-			magFilter = magFilter || THREE.NearestFilter;
-			var renderTarget = new THREE.WebGLRenderTarget( sizeXTexture, sizeYTexture, {
-				wrapS: wrapS,
-				wrapT: wrapT,
-				minFilter: minFilter,
-				magFilter: magFilter,
-				format: THREE.RGBAFormat,
-				type: dataType,
-				depthBuffer: false
-			} );
-			return renderTarget;
+			};
 
 
-		};
+			this.createTexture = function () {
 
 
-		this.createTexture = function () {
+				const data = new Float32Array( sizeX * sizeY * 4 );
+				return new THREE.DataTexture( data, sizeX, sizeY, THREE.RGBAFormat, THREE.FloatType );
 
 
-			var data = new Float32Array( sizeX * sizeY * 4 );
-			return new THREE.DataTexture( data, sizeX, sizeY, THREE.RGBAFormat, THREE.FloatType );
+			};
 
 
-		};
+			this.renderTexture = function ( input, output ) {
 
 
-		this.renderTexture = function ( input, output ) {
+				// Takes a texture, and render out in rendertarget
+				// input = Texture
+				// output = RenderTarget
+				passThruUniforms.passThruTexture.value = input;
+				this.doRenderTarget( passThruShader, output );
+				passThruUniforms.passThruTexture.value = null;
 
 
-			// Takes a texture, and render out in rendertarget
-			// input = Texture
-			// output = RenderTarget
-			passThruUniforms.passThruTexture.value = input;
-			this.doRenderTarget( passThruShader, output );
-			passThruUniforms.passThruTexture.value = null;
+			};
 
 
-		};
+			this.doRenderTarget = function ( material, output ) {
 
 
-		this.doRenderTarget = function ( material, output ) {
+				const currentRenderTarget = renderer.getRenderTarget();
+				mesh.material = material;
+				renderer.setRenderTarget( output );
+				renderer.render( scene, camera );
+				mesh.material = passThruShader;
+				renderer.setRenderTarget( currentRenderTarget );
 
 
-			var currentRenderTarget = renderer.getRenderTarget();
-			mesh.material = material;
-			renderer.setRenderTarget( output );
-			renderer.render( scene, camera );
-			mesh.material = passThruShader;
-			renderer.setRenderTarget( currentRenderTarget );
+			}; // Shaders
 
 
-		}; // Shaders
 
 
+			function getPassThroughVertexShader() {
 
 
-		function getPassThroughVertexShader() {
+				return 'void main()	{\n' + '\n' + '	gl_Position = vec4( position, 1.0 );\n' + '\n' + '}\n';
 
 
-			return 'void main()	{\n' + '\n' + '	gl_Position = vec4( position, 1.0 );\n' + '\n' + '}\n';
+			}
 
 
-		}
+			function getPassThroughFragmentShader() {
 
 
-		function getPassThroughFragmentShader() {
+				return 'uniform sampler2D passThruTexture;\n' + '\n' + 'void main() {\n' + '\n' + '	vec2 uv = gl_FragCoord.xy / resolution.xy;\n' + '\n' + '	gl_FragColor = texture2D( passThruTexture, uv );\n' + '\n' + '}\n';
 
 
-			return 'uniform sampler2D passThruTexture;\n' + '\n' + 'void main() {\n' + '\n' + '	vec2 uv = gl_FragCoord.xy / resolution.xy;\n' + '\n' + '	gl_FragColor = texture2D( passThruTexture, uv );\n' + '\n' + '}\n';
+			}
 
 
 		}
 		}
 
 
-	};
+	}
 
 
 	THREE.GPUComputationRenderer = GPUComputationRenderer;
 	THREE.GPUComputationRenderer = GPUComputationRenderer;
 
 

+ 22 - 19
examples/js/misc/Gyroscope.js

@@ -1,23 +1,26 @@
 ( function () {
 ( function () {
 
 
-	var Gyroscope = function () {
+	const _translationObject = new THREE.Vector3();
 
 
-		THREE.Object3D.call( this );
+	const _quaternionObject = new THREE.Quaternion();
 
 
-	};
+	const _scaleObject = new THREE.Vector3();
 
 
-	Gyroscope.prototype = Object.create( THREE.Object3D.prototype );
-	Gyroscope.prototype.constructor = Gyroscope;
+	const _translationWorld = new THREE.Vector3();
 
 
-	Gyroscope.prototype.updateMatrixWorld = function () {
+	const _quaternionWorld = new THREE.Quaternion();
 
 
-		var translationObject = new THREE.Vector3();
-		var quaternionObject = new THREE.Quaternion();
-		var scaleObject = new THREE.Vector3();
-		var translationWorld = new THREE.Vector3();
-		var quaternionWorld = new THREE.Quaternion();
-		var scaleWorld = new THREE.Vector3();
-		return function updateMatrixWorld( force ) {
+	const _scaleWorld = new THREE.Vector3();
+
+	class Gyroscope extends THREE.Object3D {
+
+		constructor() {
+
+			super();
+
+		}
+
+		updateMatrixWorld( force ) {
 
 
 			this.matrixAutoUpdate && this.updateMatrix(); // update matrixWorld
 			this.matrixAutoUpdate && this.updateMatrix(); // update matrixWorld
 
 
@@ -26,9 +29,9 @@
 				if ( this.parent !== null ) {
 				if ( this.parent !== null ) {
 
 
 					this.matrixWorld.multiplyMatrices( this.parent.matrixWorld, this.matrix );
 					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 );
+					this.matrixWorld.decompose( _translationWorld, _quaternionWorld, _scaleWorld );
+					this.matrix.decompose( _translationObject, _quaternionObject, _scaleObject );
+					this.matrixWorld.compose( _translationWorld, _quaternionObject, _scaleWorld );
 
 
 				} else {
 				} else {
 
 
@@ -42,15 +45,15 @@
 			} // update children
 			} // update children
 
 
 
 
-			for ( var i = 0, l = this.children.length; i < l; i ++ ) {
+			for ( let i = 0, l = this.children.length; i < l; i ++ ) {
 
 
 				this.children[ i ].updateMatrixWorld( force );
 				this.children[ i ].updateMatrixWorld( force );
 
 
 			}
 			}
 
 
-		};
+		}
 
 
-	}();
+	}
 
 
 	THREE.Gyroscope = Gyroscope;
 	THREE.Gyroscope = Gyroscope;
 
 

+ 104 - 99
examples/js/misc/MD2Character.js

@@ -1,41 +1,98 @@
 ( function () {
 ( function () {
 
 
-	var MD2Character = function () {
+	class MD2Character {
 
 
-		var scope = this;
-		this.scale = 1;
-		this.animationFPS = 6;
-		this.root = new THREE.Object3D();
-		this.meshBody = null;
-		this.meshWeapon = null;
-		this.skinsBody = [];
-		this.skinsWeapon = [];
-		this.weapons = [];
-		this.activeAnimation = null;
-		this.mixer = null;
+		constructor() {
 
 
-		this.onLoadComplete = function () {};
+			this.scale = 1;
+			this.animationFPS = 6;
+			this.root = new THREE.Object3D();
+			this.meshBody = null;
+			this.meshWeapon = null;
+			this.skinsBody = [];
+			this.skinsWeapon = [];
+			this.weapons = [];
+			this.activeAnimation = null;
+			this.mixer = null;
 
 
-		this.loadCounter = 0;
+			this.onLoadComplete = function () {};
 
 
-		this.loadParts = function ( config ) {
+			this.loadCounter = 0;
+
+		}
+
+		loadParts( config ) {
+
+			const scope = this;
+
+			function createPart( geometry, skinMap ) {
+
+				const materialWireframe = new THREE.MeshLambertMaterial( {
+					color: 0xffaa00,
+					wireframe: true,
+					morphTargets: true,
+					morphNormals: true
+				} );
+				const materialTexture = new THREE.MeshLambertMaterial( {
+					color: 0xffffff,
+					wireframe: false,
+					map: skinMap,
+					morphTargets: true,
+					morphNormals: true
+				} ); //
+
+				const mesh = new THREE.Mesh( geometry, materialTexture );
+				mesh.rotation.y = - Math.PI / 2;
+				mesh.castShadow = true;
+				mesh.receiveShadow = true; //
+
+				mesh.materialTexture = materialTexture;
+				mesh.materialWireframe = materialWireframe;
+				return mesh;
+
+			}
+
+			function loadTextures( baseUrl, textureUrls ) {
+
+				const textureLoader = new THREE.TextureLoader();
+				const textures = [];
+
+				for ( let i = 0; i < textureUrls.length; i ++ ) {
+
+					textures[ i ] = textureLoader.load( baseUrl + textureUrls[ i ], checkLoadingComplete );
+					textures[ i ].mapping = THREE.UVMapping;
+					textures[ i ].name = textureUrls[ i ];
+					textures[ i ].encoding = THREE.sRGBEncoding;
+
+				}
+
+				return textures;
+
+			}
+
+			function checkLoadingComplete() {
+
+				scope.loadCounter -= 1;
+				if ( scope.loadCounter === 0 ) scope.onLoadComplete();
+
+			}
 
 
 			this.loadCounter = config.weapons.length * 2 + config.skins.length + 1;
 			this.loadCounter = config.weapons.length * 2 + config.skins.length + 1;
-			var weaponsTextures = [];
+			const weaponsTextures = [];
 
 
-			for ( var i = 0; i < config.weapons.length; i ++ ) weaponsTextures[ i ] = config.weapons[ i ][ 1 ]; // SKINS
+			for ( let i = 0; i < config.weapons.length; i ++ ) weaponsTextures[ i ] = config.weapons[ i ][ 1 ]; // SKINS
 
 
 
 
 			this.skinsBody = loadTextures( config.baseUrl + 'skins/', config.skins );
 			this.skinsBody = loadTextures( config.baseUrl + 'skins/', config.skins );
 			this.skinsWeapon = loadTextures( config.baseUrl + 'skins/', weaponsTextures ); // BODY
 			this.skinsWeapon = loadTextures( config.baseUrl + 'skins/', weaponsTextures ); // BODY
 
 
-			var loader = new THREE.MD2Loader();
+			const 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();
+				const boundingBox = new THREE.Box3();
 				boundingBox.setFromBufferAttribute( geo.attributes.position );
 				boundingBox.setFromBufferAttribute( geo.attributes.position );
 				scope.root.position.y = - scope.scale * boundingBox.min.y;
 				scope.root.position.y = - scope.scale * boundingBox.min.y;
-				var mesh = createPart( geo, scope.skinsBody[ 0 ] );
+				const mesh = createPart( geo, scope.skinsBody[ 0 ] );
 				mesh.scale.set( scope.scale, scope.scale, scope.scale );
 				mesh.scale.set( scope.scale, scope.scale, scope.scale );
 				scope.root.add( mesh );
 				scope.root.add( mesh );
 				scope.meshBody = mesh;
 				scope.meshBody = mesh;
@@ -46,11 +103,11 @@
 
 
 			} ); // WEAPONS
 			} ); // WEAPONS
 
 
-			var generateCallback = function ( index, name ) {
+			const generateCallback = function ( index, name ) {
 
 
 				return function ( geo ) {
 				return function ( geo ) {
 
 
-					var mesh = createPart( geo, scope.skinsWeapon[ index ] );
+					const mesh = createPart( geo, scope.skinsWeapon[ index ] );
 					mesh.scale.set( scope.scale, scope.scale, scope.scale );
 					mesh.scale.set( scope.scale, scope.scale, scope.scale );
 					mesh.visible = false;
 					mesh.visible = false;
 					mesh.name = name;
 					mesh.name = name;
@@ -63,15 +120,15 @@
 
 
 			};
 			};
 
 
-			for ( var i = 0; i < config.weapons.length; i ++ ) {
+			for ( let i = 0; i < config.weapons.length; i ++ ) {
 
 
 				loader.load( config.baseUrl + config.weapons[ i ][ 0 ], generateCallback( i, config.weapons[ i ][ 0 ] ) );
 				loader.load( config.baseUrl + config.weapons[ i ][ 0 ], generateCallback( i, config.weapons[ i ][ 0 ] ) );
 
 
 			}
 			}
 
 
-		};
+		}
 
 
-		this.setPlaybackRate = function ( rate ) {
+		setPlaybackRate( rate ) {
 
 
 			if ( rate !== 0 ) {
 			if ( rate !== 0 ) {
 
 
@@ -83,9 +140,9 @@
 
 
 			}
 			}
 
 
-		};
+		}
 
 
-		this.setWireframe = function ( wireframeEnabled ) {
+		setWireframe( wireframeEnabled ) {
 
 
 			if ( wireframeEnabled ) {
 			if ( wireframeEnabled ) {
 
 
@@ -99,9 +156,9 @@
 
 
 			}
 			}
 
 
-		};
+		}
 
 
-		this.setSkin = function ( index ) {
+		setSkin( index ) {
 
 
 			if ( this.meshBody && this.meshBody.material.wireframe === false ) {
 			if ( this.meshBody && this.meshBody.material.wireframe === false ) {
 
 
@@ -109,25 +166,25 @@
 
 
 			}
 			}
 
 
-		};
+		}
 
 
-		this.setWeapon = function ( index ) {
+		setWeapon( index ) {
 
 
-			for ( var i = 0; i < this.weapons.length; i ++ ) this.weapons[ i ].visible = false;
+			for ( let i = 0; i < this.weapons.length; i ++ ) this.weapons[ i ].visible = false;
 
 
-			var activeWeapon = this.weapons[ index ];
+			const activeWeapon = this.weapons[ index ];
 
 
 			if ( activeWeapon ) {
 			if ( activeWeapon ) {
 
 
 				activeWeapon.visible = true;
 				activeWeapon.visible = true;
 				this.meshWeapon = activeWeapon;
 				this.meshWeapon = activeWeapon;
-				scope.syncWeaponAnimation();
+				this.syncWeaponAnimation();
 
 
 			}
 			}
 
 
-		};
+		}
 
 
-		this.setAnimation = function ( clipName ) {
+		setAnimation( clipName ) {
 
 
 			if ( this.meshBody ) {
 			if ( this.meshBody ) {
 
 
@@ -138,7 +195,7 @@
 
 
 				}
 				}
 
 
-				var action = this.mixer.clipAction( clipName, this.meshBody );
+				const action = this.mixer.clipAction( clipName, this.meshBody );
 
 
 				if ( action ) {
 				if ( action ) {
 
 
@@ -148,16 +205,16 @@
 
 
 			}
 			}
 
 
-			scope.activeClipName = clipName;
-			scope.syncWeaponAnimation();
+			this.activeClipName = clipName;
+			this.syncWeaponAnimation();
 
 
-		};
+		}
 
 
-		this.syncWeaponAnimation = function () {
+		syncWeaponAnimation() {
 
 
-			var clipName = scope.activeClipName;
+			const clipName = this.activeClipName;
 
 
-			if ( scope.meshWeapon ) {
+			if ( this.meshWeapon ) {
 
 
 				if ( this.meshWeapon.activeAction ) {
 				if ( this.meshWeapon.activeAction ) {
 
 
@@ -166,7 +223,7 @@
 
 
 				}
 				}
 
 
-				var action = this.mixer.clipAction( clipName, this.meshWeapon );
+				const action = this.mixer.clipAction( clipName, this.meshWeapon );
 
 
 				if ( action ) {
 				if ( action ) {
 
 
@@ -176,67 +233,15 @@
 
 
 			}
 			}
 
 
-		};
-
-		this.update = function ( delta ) {
-
-			if ( this.mixer ) this.mixer.update( delta );
-
-		};
-
-		function loadTextures( baseUrl, textureUrls ) {
-
-			var textureLoader = new THREE.TextureLoader();
-			var textures = [];
-
-			for ( var i = 0; i < textureUrls.length; i ++ ) {
-
-				textures[ i ] = textureLoader.load( baseUrl + textureUrls[ i ], checkLoadingComplete );
-				textures[ i ].mapping = THREE.UVMapping;
-				textures[ i ].name = textureUrls[ i ];
-				textures[ i ].encoding = THREE.sRGBEncoding;
-
-			}
-
-			return textures;
-
 		}
 		}
 
 
-		function createPart( geometry, skinMap ) {
-
-			var materialWireframe = new THREE.MeshLambertMaterial( {
-				color: 0xffaa00,
-				wireframe: true,
-				morphTargets: true,
-				morphNormals: true
-			} );
-			var materialTexture = new THREE.MeshLambertMaterial( {
-				color: 0xffffff,
-				wireframe: false,
-				map: skinMap,
-				morphTargets: true,
-				morphNormals: true
-			} ); //
-
-			var mesh = new THREE.Mesh( geometry, materialTexture );
-			mesh.rotation.y = - Math.PI / 2;
-			mesh.castShadow = true;
-			mesh.receiveShadow = true; //
-
-			mesh.materialTexture = materialTexture;
-			mesh.materialWireframe = materialWireframe;
-			return mesh;
-
-		}
+		update( delta ) {
 
 
-		function checkLoadingComplete() {
-
-			scope.loadCounter -= 1;
-			if ( scope.loadCounter === 0 ) scope.onLoadComplete();
+			if ( this.mixer ) this.mixer.update( delta );
 
 
 		}
 		}
 
 
-	};
+	}
 
 
 	THREE.MD2Character = MD2Character;
 	THREE.MD2Character = MD2Character;
 
 

+ 126 - 116
examples/js/misc/MD2CharacterComplex.js

@@ -1,68 +1,71 @@
 ( function () {
 ( function () {
 
 
-	var MD2CharacterComplex = function () {
+	class MD2CharacterComplex {
 
 
-		var scope = this;
-		this.scale = 1; // animation parameters
+		constructor() {
 
 
-		this.animationFPS = 6;
-		this.transitionFrames = 15; // movement model parameters
+			this.scale = 1; // animation parameters
 
 
-		this.maxSpeed = 275;
-		this.maxReverseSpeed = - 275;
-		this.frontAcceleration = 600;
-		this.backAcceleration = 600;
-		this.frontDecceleration = 600;
-		this.angularSpeed = 2.5; // rig
+			this.animationFPS = 6;
+			this.transitionFrames = 15; // movement model parameters
 
 
-		this.root = new THREE.Object3D();
-		this.meshBody = null;
-		this.meshWeapon = null;
-		this.controls = null; // skins
+			this.maxSpeed = 275;
+			this.maxReverseSpeed = - 275;
+			this.frontAcceleration = 600;
+			this.backAcceleration = 600;
+			this.frontDecceleration = 600;
+			this.angularSpeed = 2.5; // rig
 
 
-		this.skinsBody = [];
-		this.skinsWeapon = [];
-		this.weapons = [];
-		this.currentSkin = undefined; //
+			this.root = new THREE.Object3D();
+			this.meshBody = null;
+			this.meshWeapon = null;
+			this.controls = null; // skins
 
 
-		this.onLoadComplete = function () {}; // internals
+			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.meshes = [];
+			this.animations = {};
+			this.loadCounter = 0; // internal movement control variables
 
 
-		this.activeAnimation = null;
-		this.oldAnimation = null; // API
+			this.speed = 0;
+			this.bodyOrientation = 0;
+			this.walkSpeed = this.maxSpeed;
+			this.crouchSpeed = this.maxSpeed * 0.5; // internal animation parameters
 
 
-		this.enableShadows = function ( enable ) {
+			this.activeAnimation = null;
+			this.oldAnimation = null; // API
 
 
-			for ( var i = 0; i < this.meshes.length; i ++ ) {
+		}
+
+		enableShadows( enable ) {
+
+			for ( let i = 0; i < this.meshes.length; i ++ ) {
 
 
 				this.meshes[ i ].castShadow = enable;
 				this.meshes[ i ].castShadow = enable;
 				this.meshes[ i ].receiveShadow = enable;
 				this.meshes[ i ].receiveShadow = enable;
 
 
 			}
 			}
 
 
-		};
+		}
 
 
-		this.setVisible = function ( enable ) {
+		setVisible( enable ) {
 
 
-			for ( var i = 0; i < this.meshes.length; i ++ ) {
+			for ( let i = 0; i < this.meshes.length; i ++ ) {
 
 
 				this.meshes[ i ].visible = enable;
 				this.meshes[ i ].visible = enable;
 				this.meshes[ i ].visible = enable;
 				this.meshes[ i ].visible = enable;
 
 
 			}
 			}
 
 
-		};
+		}
 
 
-		this.shareParts = function ( original ) {
+		shareParts( original ) {
 
 
 			this.animations = original.animations;
 			this.animations = original.animations;
 			this.walkSpeed = original.walkSpeed;
 			this.walkSpeed = original.walkSpeed;
@@ -70,16 +73,18 @@
 			this.skinsBody = original.skinsBody;
 			this.skinsBody = original.skinsBody;
 			this.skinsWeapon = original.skinsWeapon; // BODY
 			this.skinsWeapon = original.skinsWeapon; // BODY
 
 
-			var mesh = createPart( original.meshBody.geometry, this.skinsBody[ 0 ] );
+			const mesh = this._createPart( original.meshBody.geometry, this.skinsBody[ 0 ] );
+
 			mesh.scale.set( this.scale, this.scale, this.scale );
 			mesh.scale.set( this.scale, this.scale, this.scale );
 			this.root.position.y = original.root.position.y;
 			this.root.position.y = original.root.position.y;
 			this.root.add( mesh );
 			this.root.add( mesh );
 			this.meshBody = mesh;
 			this.meshBody = mesh;
 			this.meshes.push( mesh ); // WEAPONS
 			this.meshes.push( mesh ); // WEAPONS
 
 
-			for ( var i = 0; i < original.weapons.length; i ++ ) {
+			for ( let i = 0; i < original.weapons.length; i ++ ) {
+
+				const meshWeapon = this._createPart( original.weapons[ i ].geometry, this.skinsWeapon[ i ] );
 
 
-				var meshWeapon = createPart( original.weapons[ i ].geometry, this.skinsWeapon[ i ] );
 				meshWeapon.scale.set( this.scale, this.scale, this.scale );
 				meshWeapon.scale.set( this.scale, this.scale, this.scale );
 				meshWeapon.visible = false;
 				meshWeapon.visible = false;
 				meshWeapon.name = original.weapons[ i ].name;
 				meshWeapon.name = original.weapons[ i ].name;
@@ -90,29 +95,58 @@
 
 
 			}
 			}
 
 
-		};
+		}
+
+		loadParts( config ) {
+
+			const scope = this;
+
+			function loadTextures( baseUrl, textureUrls ) {
+
+				const textureLoader = new THREE.TextureLoader();
+				const textures = [];
+
+				for ( let i = 0; i < textureUrls.length; i ++ ) {
+
+					textures[ i ] = textureLoader.load( baseUrl + textureUrls[ i ], checkLoadingComplete );
+					textures[ i ].mapping = THREE.UVMapping;
+					textures[ i ].name = textureUrls[ i ];
+					textures[ i ].encoding = THREE.sRGBEncoding;
+
+				}
+
+				return textures;
+
+			}
+
+			function checkLoadingComplete() {
+
+				scope.loadCounter -= 1;
+				if ( scope.loadCounter === 0 ) scope.onLoadComplete();
 
 
-		this.loadParts = function ( config ) {
+			}
 
 
 			this.animations = config.animations;
 			this.animations = config.animations;
 			this.walkSpeed = config.walkSpeed;
 			this.walkSpeed = config.walkSpeed;
 			this.crouchSpeed = config.crouchSpeed;
 			this.crouchSpeed = config.crouchSpeed;
 			this.loadCounter = config.weapons.length * 2 + config.skins.length + 1;
 			this.loadCounter = config.weapons.length * 2 + config.skins.length + 1;
-			var weaponsTextures = [];
+			const weaponsTextures = [];
 
 
-			for ( var i = 0; i < config.weapons.length; i ++ ) weaponsTextures[ i ] = config.weapons[ i ][ 1 ]; // SKINS
+			for ( let i = 0; i < config.weapons.length; i ++ ) weaponsTextures[ i ] = config.weapons[ i ][ 1 ]; // SKINS
 
 
 
 
 			this.skinsBody = loadTextures( config.baseUrl + 'skins/', config.skins );
 			this.skinsBody = loadTextures( config.baseUrl + 'skins/', config.skins );
 			this.skinsWeapon = loadTextures( config.baseUrl + 'skins/', weaponsTextures ); // BODY
 			this.skinsWeapon = loadTextures( config.baseUrl + 'skins/', weaponsTextures ); // BODY
 
 
-			var loader = new THREE.MD2Loader();
+			const 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();
+				const boundingBox = new THREE.Box3();
 				boundingBox.setFromBufferAttribute( geo.attributes.position );
 				boundingBox.setFromBufferAttribute( geo.attributes.position );
 				scope.root.position.y = - scope.scale * boundingBox.min.y;
 				scope.root.position.y = - scope.scale * boundingBox.min.y;
-				var mesh = createPart( geo, scope.skinsBody[ 0 ] );
+
+				const mesh = scope._createPart( geo, scope.skinsBody[ 0 ] );
+
 				mesh.scale.set( scope.scale, scope.scale, scope.scale );
 				mesh.scale.set( scope.scale, scope.scale, scope.scale );
 				scope.root.add( mesh );
 				scope.root.add( mesh );
 				scope.meshBody = mesh;
 				scope.meshBody = mesh;
@@ -121,11 +155,12 @@
 
 
 			} ); // WEAPONS
 			} ); // WEAPONS
 
 
-			var generateCallback = function ( index, name ) {
+			const generateCallback = function ( index, name ) {
 
 
 				return function ( geo ) {
 				return function ( geo ) {
 
 
-					var mesh = createPart( geo, scope.skinsWeapon[ index ] );
+					const mesh = scope._createPart( geo, scope.skinsWeapon[ index ] );
+
 					mesh.scale.set( scope.scale, scope.scale, scope.scale );
 					mesh.scale.set( scope.scale, scope.scale, scope.scale );
 					mesh.visible = false;
 					mesh.visible = false;
 					mesh.name = name;
 					mesh.name = name;
@@ -139,22 +174,22 @@
 
 
 			};
 			};
 
 
-			for ( var i = 0; i < config.weapons.length; i ++ ) {
+			for ( let i = 0; i < config.weapons.length; i ++ ) {
 
 
 				loader.load( config.baseUrl + config.weapons[ i ][ 0 ], generateCallback( i, config.weapons[ i ][ 0 ] ) );
 				loader.load( config.baseUrl + config.weapons[ i ][ 0 ], generateCallback( i, config.weapons[ i ][ 0 ] ) );
 
 
 			}
 			}
 
 
-		};
+		}
 
 
-		this.setPlaybackRate = function ( rate ) {
+		setPlaybackRate( rate ) {
 
 
 			if ( this.meshBody ) this.meshBody.duration = this.meshBody.baseDuration / rate;
 			if ( this.meshBody ) this.meshBody.duration = this.meshBody.baseDuration / rate;
 			if ( this.meshWeapon ) this.meshWeapon.duration = this.meshWeapon.baseDuration / rate;
 			if ( this.meshWeapon ) this.meshWeapon.duration = this.meshWeapon.baseDuration / rate;
 
 
-		};
+		}
 
 
-		this.setWireframe = function ( wireframeEnabled ) {
+		setWireframe( wireframeEnabled ) {
 
 
 			if ( wireframeEnabled ) {
 			if ( wireframeEnabled ) {
 
 
@@ -168,9 +203,9 @@
 
 
 			}
 			}
 
 
-		};
+		}
 
 
-		this.setSkin = function ( index ) {
+		setSkin( index ) {
 
 
 			if ( this.meshBody && this.meshBody.material.wireframe === false ) {
 			if ( this.meshBody && this.meshBody.material.wireframe === false ) {
 
 
@@ -179,13 +214,13 @@
 
 
 			}
 			}
 
 
-		};
+		}
 
 
-		this.setWeapon = function ( index ) {
+		setWeapon( index ) {
 
 
-			for ( var i = 0; i < this.weapons.length; i ++ ) this.weapons[ i ].visible = false;
+			for ( let i = 0; i < this.weapons.length; i ++ ) this.weapons[ i ].visible = false;
 
 
-			var activeWeapon = this.weapons[ index ];
+			const activeWeapon = this.weapons[ index ];
 
 
 			if ( activeWeapon ) {
 			if ( activeWeapon ) {
 
 
@@ -201,9 +236,9 @@
 
 
 			}
 			}
 
 
-		};
+		}
 
 
-		this.setAnimation = function ( animationName ) {
+		setAnimation( animationName ) {
 
 
 			if ( animationName === this.activeAnimation || ! animationName ) return;
 			if ( animationName === this.activeAnimation || ! animationName ) return;
 
 
@@ -224,9 +259,9 @@
 
 
 			}
 			}
 
 
-		};
+		}
 
 
-		this.update = function ( delta ) {
+		update( delta ) {
 
 
 			if ( this.controls ) this.updateMovementModel( delta );
 			if ( this.controls ) this.updateMovementModel( delta );
 
 
@@ -237,11 +272,11 @@
 
 
 			}
 			}
 
 
-		};
+		}
 
 
-		this.updateAnimations = function ( delta ) {
+		updateAnimations( delta ) {
 
 
-			var mix = 1;
+			let mix = 1;
 
 
 			if ( this.blendCounter > 0 ) {
 			if ( this.blendCounter > 0 ) {
 
 
@@ -266,13 +301,13 @@
 
 
 			}
 			}
 
 
-		};
+		}
 
 
-		this.updateBehaviors = function () {
+		updateBehaviors() {
 
 
-			var controls = this.controls;
-			var animations = this.animations;
-			var moveAnimation, idleAnimation; // crouch vs stand
+			const controls = this.controls;
+			const animations = this.animations;
+			let moveAnimation, idleAnimation; // crouch vs stand
 
 
 			if ( controls.crouch ) {
 			if ( controls.crouch ) {
 
 
@@ -368,11 +403,17 @@
 
 
 			}
 			}
 
 
-		};
+		}
+
+		updateMovementModel( delta ) {
 
 
-		this.updateMovementModel = function ( delta ) {
+			function exponentialEaseOut( k ) {
 
 
-			var controls = this.controls; // speed based on controls
+				return k === 1 ? 1 : - Math.pow( 2, - 10 * k ) + 1;
+
+			}
+
+			const controls = this.controls; // speed based on controls
 
 
 			if ( controls.crouch ) this.maxSpeed = this.crouchSpeed; else this.maxSpeed = this.walkSpeed;
 			if ( controls.crouch ) this.maxSpeed = this.crouchSpeed; else this.maxSpeed = this.walkSpeed;
 			this.maxReverseSpeed = - this.maxSpeed;
 			this.maxReverseSpeed = - this.maxSpeed;
@@ -380,7 +421,7 @@
 			if ( controls.moveBackward ) this.speed = THREE.MathUtils.clamp( this.speed - delta * this.backAcceleration, this.maxReverseSpeed, this.maxSpeed ); // orientation based on controls
 			if ( controls.moveBackward ) this.speed = THREE.MathUtils.clamp( this.speed - delta * this.backAcceleration, this.maxReverseSpeed, this.maxSpeed ); // orientation based on controls
 			// (don't just stand while turning)
 			// (don't just stand while turning)
 
 
-			var dir = 1;
+			const dir = 1;
 
 
 			if ( controls.moveLeft ) {
 			if ( controls.moveLeft ) {
 
 
@@ -401,12 +442,12 @@
 
 
 				if ( this.speed > 0 ) {
 				if ( this.speed > 0 ) {
 
 
-					var k = exponentialEaseOut( this.speed / this.maxSpeed );
+					const k = exponentialEaseOut( this.speed / this.maxSpeed );
 					this.speed = THREE.MathUtils.clamp( this.speed - k * delta * this.frontDecceleration, 0, this.maxSpeed );
 					this.speed = THREE.MathUtils.clamp( this.speed - k * delta * this.frontDecceleration, 0, this.maxSpeed );
 
 
 				} else {
 				} else {
 
 
-					var k = exponentialEaseOut( this.speed / this.maxReverseSpeed );
+					const k = exponentialEaseOut( this.speed / this.maxReverseSpeed );
 					this.speed = THREE.MathUtils.clamp( this.speed + k * delta * this.backAcceleration, this.maxReverseSpeed, 0 );
 					this.speed = THREE.MathUtils.clamp( this.speed + k * delta * this.backAcceleration, this.maxReverseSpeed, 0 );
 
 
 				}
 				}
@@ -414,42 +455,24 @@
 			} // displacement
 			} // displacement
 
 
 
 
-			var forwardDelta = this.speed * delta;
+			const forwardDelta = this.speed * delta;
 			this.root.position.x += Math.sin( this.bodyOrientation ) * forwardDelta;
 			this.root.position.x += Math.sin( this.bodyOrientation ) * forwardDelta;
 			this.root.position.z += Math.cos( this.bodyOrientation ) * forwardDelta; // steering
 			this.root.position.z += Math.cos( this.bodyOrientation ) * forwardDelta; // steering
 
 
 			this.root.rotation.y = this.bodyOrientation;
 			this.root.rotation.y = this.bodyOrientation;
 
 
-		}; // internal helpers
-
+		} // internal
 
 
-		function loadTextures( baseUrl, textureUrls ) {
 
 
-			var textureLoader = new THREE.TextureLoader();
-			var textures = [];
+		_createPart( geometry, skinMap ) {
 
 
-			for ( var i = 0; i < textureUrls.length; i ++ ) {
-
-				textures[ i ] = textureLoader.load( baseUrl + textureUrls[ i ], checkLoadingComplete );
-				textures[ i ].mapping = THREE.UVMapping;
-				textures[ i ].name = textureUrls[ i ];
-				textures[ i ].encoding = THREE.sRGBEncoding;
-
-			}
-
-			return textures;
-
-		}
-
-		function createPart( geometry, skinMap ) {
-
-			var materialWireframe = new THREE.MeshLambertMaterial( {
+			const materialWireframe = new THREE.MeshLambertMaterial( {
 				color: 0xffaa00,
 				color: 0xffaa00,
 				wireframe: true,
 				wireframe: true,
 				morphTargets: true,
 				morphTargets: true,
 				morphNormals: true
 				morphNormals: true
 			} );
 			} );
-			var materialTexture = new THREE.MeshLambertMaterial( {
+			const materialTexture = new THREE.MeshLambertMaterial( {
 				color: 0xffffff,
 				color: 0xffffff,
 				wireframe: false,
 				wireframe: false,
 				map: skinMap,
 				map: skinMap,
@@ -457,31 +480,18 @@
 				morphNormals: true
 				morphNormals: true
 			} ); //
 			} ); //
 
 
-			var mesh = new THREE.MorphBlendMesh( geometry, materialTexture );
+			const mesh = new THREE.MorphBlendMesh( geometry, materialTexture );
 			mesh.rotation.y = - Math.PI / 2; //
 			mesh.rotation.y = - Math.PI / 2; //
 
 
 			mesh.materialTexture = materialTexture;
 			mesh.materialTexture = materialTexture;
 			mesh.materialWireframe = materialWireframe; //
 			mesh.materialWireframe = materialWireframe; //
 
 
-			mesh.autoCreateAnimations( scope.animationFPS );
+			mesh.autoCreateAnimations( this.animationFPS );
 			return mesh;
 			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;
-
-		}
-
-	};
+	}
 
 
 	THREE.MD2CharacterComplex = MD2CharacterComplex;
 	THREE.MD2CharacterComplex = MD2CharacterComplex;
 
 

+ 36 - 35
examples/js/misc/MorphAnimMesh.js

@@ -1,67 +1,68 @@
 ( function () {
 ( function () {
 
 
-	var MorphAnimMesh = function ( geometry, material ) {
+	class MorphAnimMesh extends THREE.Mesh {
 
 
-		THREE.Mesh.call( this, geometry, material );
-		this.type = 'MorphAnimMesh';
-		this.mixer = new THREE.AnimationMixer( this );
-		this.activeAction = null;
+		constructor( geometry, material ) {
 
 
-	};
+			super( geometry, material );
+			this.type = 'MorphAnimMesh';
+			this.mixer = new THREE.AnimationMixer( this );
+			this.activeAction = null;
 
 
-	MorphAnimMesh.prototype = Object.create( THREE.Mesh.prototype );
-	MorphAnimMesh.prototype.constructor = MorphAnimMesh;
+		}
 
 
-	MorphAnimMesh.prototype.setDirectionForward = function () {
+		setDirectionForward() {
 
 
-		this.mixer.timeScale = 1.0;
+			this.mixer.timeScale = 1.0;
 
 
-	};
+		}
 
 
-	MorphAnimMesh.prototype.setDirectionBackward = function () {
+		setDirectionBackward() {
 
 
-		this.mixer.timeScale = - 1.0;
+			this.mixer.timeScale = - 1.0;
 
 
-	};
+		}
 
 
-	MorphAnimMesh.prototype.playAnimation = function ( label, fps ) {
+		playAnimation( label, fps ) {
 
 
-		if ( this.activeAction ) {
+			if ( this.activeAction ) {
 
 
-			this.activeAction.stop();
-			this.activeAction = null;
+				this.activeAction.stop();
+				this.activeAction = null;
 
 
-		}
+			}
+
+			const clip = THREE.AnimationClip.findByName( this, label );
 
 
-		var clip = THREE.AnimationClip.findByName( this, label );
+			if ( clip ) {
 
 
-		if ( clip ) {
+				const action = this.mixer.clipAction( clip );
+				action.timeScale = clip.tracks.length * fps / clip.duration;
+				this.activeAction = action.play();
 
 
-			var action = this.mixer.clipAction( clip );
-			action.timeScale = clip.tracks.length * fps / clip.duration;
-			this.activeAction = action.play();
+			} else {
 
 
-		} else {
+				throw new Error( 'THREE.MorphAnimMesh: animations[' + label + '] undefined in .playAnimation()' );
 
 
-			throw new Error( 'THREE.MorphAnimMesh: animations[' + label + '] undefined in .playAnimation()' );
+			}
 
 
 		}
 		}
 
 
-	};
+		updateAnimation( delta ) {
 
 
-	MorphAnimMesh.prototype.updateAnimation = function ( delta ) {
+			this.mixer.update( delta );
 
 
-		this.mixer.update( delta );
+		}
 
 
-	};
+		copy( source ) {
 
 
-	MorphAnimMesh.prototype.copy = function ( source ) {
+			super.copy( source );
+			this.mixer = new THREE.AnimationMixer( this );
+			return this;
 
 
-		THREE.Mesh.prototype.copy.call( this, source );
-		this.mixer = new THREE.AnimationMixer( this );
-		return this;
+		}
 
 
-	};
+	}
 
 
 	THREE.MorphAnimMesh = MorphAnimMesh;
 	THREE.MorphAnimMesh = MorphAnimMesh;
 
 

+ 83 - 70
examples/js/misc/MorphBlendMesh.js

@@ -1,27 +1,27 @@
 ( function () {
 ( function () {
 
 
-	var MorphBlendMesh = function ( geometry, material ) {
+	class MorphBlendMesh extends THREE.Mesh {
 
 
-		THREE.Mesh.call( this, geometry, material );
-		this.animationsMap = {};
-		this.animationsList = []; // prepare default animation
-		// (all frames played together in 1 second)
+		constructor( geometry, material ) {
 
 
-		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 );
+			super( geometry, material );
+			this.animationsMap = {};
+			this.animationsList = []; // prepare default animation
+			// (all frames played together in 1 second)
 
 
-	};
+			const numFrames = Object.keys( this.morphTargetDictionary ).length;
+			const name = '__default';
+			const startFrame = 0;
+			const endFrame = numFrames - 1;
+			const fps = numFrames / 1;
+			this.createAnimation( name, startFrame, endFrame, fps );
+			this.setAnimationWeight( name, 1 );
 
 
-	MorphBlendMesh.prototype = Object.assign( Object.create( THREE.Mesh.prototype ), {
-		constructor: MorphBlendMesh,
-		createAnimation: function ( name, start, end, fps ) {
+		}
+
+		createAnimation( name, start, end, fps ) {
 
 
-			var animation = {
+			const animation = {
 				start: start,
 				start: start,
 				end: end,
 				end: end,
 				length: end - start + 1,
 				length: end - start + 1,
@@ -39,26 +39,27 @@
 			this.animationsMap[ name ] = animation;
 			this.animationsMap[ name ] = animation;
 			this.animationsList.push( animation );
 			this.animationsList.push( animation );
 
 
-		},
-		autoCreateAnimations: function ( fps ) {
+		}
+
+		autoCreateAnimations( fps ) {
 
 
-			var pattern = /([a-z]+)_?(\d+)/i;
-			var firstAnimation,
-				frameRanges = {};
-			var i = 0;
+			const pattern = /([a-z]+)_?(\d+)/i;
+			let firstAnimation;
+			const frameRanges = {};
+			let i = 0;
 
 
-			for ( var key in this.morphTargetDictionary ) {
+			for ( const key in this.morphTargetDictionary ) {
 
 
-				var chunks = key.match( pattern );
+				const chunks = key.match( pattern );
 
 
 				if ( chunks && chunks.length > 1 ) {
 				if ( chunks && chunks.length > 1 ) {
 
 
-					var name = chunks[ 1 ];
+					const name = chunks[ 1 ];
 					if ( ! frameRanges[ name ] ) frameRanges[ name ] = {
 					if ( ! frameRanges[ name ] ) frameRanges[ name ] = {
 						start: Infinity,
 						start: Infinity,
 						end: - Infinity
 						end: - Infinity
 					};
 					};
-					var range = frameRanges[ name ];
+					const range = frameRanges[ name ];
 					if ( i < range.start ) range.start = i;
 					if ( i < range.start ) range.start = i;
 					if ( i > range.end ) range.end = i;
 					if ( i > range.end ) range.end = i;
 					if ( ! firstAnimation ) firstAnimation = name;
 					if ( ! firstAnimation ) firstAnimation = name;
@@ -69,19 +70,20 @@
 
 
 			}
 			}
 
 
-			for ( var name in frameRanges ) {
+			for ( const name in frameRanges ) {
 
 
-				var range = frameRanges[ name ];
+				const range = frameRanges[ name ];
 				this.createAnimation( name, range.start, range.end, fps );
 				this.createAnimation( name, range.start, range.end, fps );
 
 
 			}
 			}
 
 
 			this.firstAnimation = firstAnimation;
 			this.firstAnimation = firstAnimation;
 
 
-		},
-		setAnimationDirectionForward: function ( name ) {
+		}
+
+		setAnimationDirectionForward( name ) {
 
 
-			var animation = this.animationsMap[ name ];
+			const animation = this.animationsMap[ name ];
 
 
 			if ( animation ) {
 			if ( animation ) {
 
 
@@ -90,10 +92,11 @@
 
 
 			}
 			}
 
 
-		},
-		setAnimationDirectionBackward: function ( name ) {
+		}
+
+		setAnimationDirectionBackward( name ) {
 
 
-			var animation = this.animationsMap[ name ];
+			const animation = this.animationsMap[ name ];
 
 
 			if ( animation ) {
 			if ( animation ) {
 
 
@@ -102,10 +105,11 @@
 
 
 			}
 			}
 
 
-		},
-		setAnimationFPS: function ( name, fps ) {
+		}
+
+		setAnimationFPS( name, fps ) {
 
 
-			var animation = this.animationsMap[ name ];
+			const animation = this.animationsMap[ name ];
 
 
 			if ( animation ) {
 			if ( animation ) {
 
 
@@ -114,10 +118,11 @@
 
 
 			}
 			}
 
 
-		},
-		setAnimationDuration: function ( name, duration ) {
+		}
 
 
-			var animation = this.animationsMap[ name ];
+		setAnimationDuration( name, duration ) {
+
+			const animation = this.animationsMap[ name ];
 
 
 			if ( animation ) {
 			if ( animation ) {
 
 
@@ -126,10 +131,11 @@
 
 
 			}
 			}
 
 
-		},
-		setAnimationWeight: function ( name, weight ) {
+		}
+
+		setAnimationWeight( name, weight ) {
 
 
-			var animation = this.animationsMap[ name ];
+			const animation = this.animationsMap[ name ];
 
 
 			if ( animation ) {
 			if ( animation ) {
 
 
@@ -137,10 +143,11 @@
 
 
 			}
 			}
 
 
-		},
-		setAnimationTime: function ( name, time ) {
+		}
+
+		setAnimationTime( name, time ) {
 
 
-			var animation = this.animationsMap[ name ];
+			const animation = this.animationsMap[ name ];
 
 
 			if ( animation ) {
 			if ( animation ) {
 
 
@@ -148,11 +155,12 @@
 
 
 			}
 			}
 
 
-		},
-		getAnimationTime: function ( name ) {
+		}
+
+		getAnimationTime( name ) {
 
 
-			var time = 0;
-			var animation = this.animationsMap[ name ];
+			let time = 0;
+			const animation = this.animationsMap[ name ];
 
 
 			if ( animation ) {
 			if ( animation ) {
 
 
@@ -162,11 +170,12 @@
 
 
 			return time;
 			return time;
 
 
-		},
-		getAnimationDuration: function ( name ) {
+		}
+
+		getAnimationDuration( name ) {
 
 
-			var duration = - 1;
-			var animation = this.animationsMap[ name ];
+			let duration = - 1;
+			const animation = this.animationsMap[ name ];
 
 
 			if ( animation ) {
 			if ( animation ) {
 
 
@@ -176,10 +185,11 @@
 
 
 			return duration;
 			return duration;
 
 
-		},
-		playAnimation: function ( name ) {
+		}
 
 
-			var animation = this.animationsMap[ name ];
+		playAnimation( name ) {
+
+			const animation = this.animationsMap[ name ];
 
 
 			if ( animation ) {
 			if ( animation ) {
 
 
@@ -192,10 +202,11 @@
 
 
 			}
 			}
 
 
-		},
-		stopAnimation: function ( name ) {
+		}
+
+		stopAnimation( name ) {
 
 
-			var animation = this.animationsMap[ name ];
+			const animation = this.animationsMap[ name ];
 
 
 			if ( animation ) {
 			if ( animation ) {
 
 
@@ -203,14 +214,15 @@
 
 
 			}
 			}
 
 
-		},
-		update: function ( delta ) {
+		}
+
+		update( delta ) {
 
 
-			for ( var i = 0, il = this.animationsList.length; i < il; i ++ ) {
+			for ( let i = 0, il = this.animationsList.length; i < il; i ++ ) {
 
 
-				var animation = this.animationsList[ i ];
+				const animation = this.animationsList[ i ];
 				if ( ! animation.active ) continue;
 				if ( ! animation.active ) continue;
-				var frameTime = animation.duration / animation.length;
+				const frameTime = animation.duration / animation.length;
 				animation.time += animation.direction * delta;
 				animation.time += animation.direction * delta;
 
 
 				if ( animation.mirroredLoop ) {
 				if ( animation.mirroredLoop ) {
@@ -242,8 +254,8 @@
 
 
 				}
 				}
 
 
-				var keyframe = animation.start + THREE.MathUtils.clamp( Math.floor( animation.time / frameTime ), 0, animation.length - 1 );
-				var weight = animation.weight;
+				const keyframe = animation.start + THREE.MathUtils.clamp( Math.floor( animation.time / frameTime ), 0, animation.length - 1 );
+				const weight = animation.weight;
 
 
 				if ( keyframe !== animation.currentFrame ) {
 				if ( keyframe !== animation.currentFrame ) {
 
 
@@ -255,7 +267,7 @@
 
 
 				}
 				}
 
 
-				var mix = animation.time % frameTime / frameTime;
+				let mix = animation.time % frameTime / frameTime;
 				if ( animation.directionBackwards ) mix = 1 - mix;
 				if ( animation.directionBackwards ) mix = 1 - mix;
 
 
 				if ( animation.currentFrame !== animation.lastFrame ) {
 				if ( animation.currentFrame !== animation.lastFrame ) {
@@ -272,7 +284,8 @@
 			}
 			}
 
 
 		}
 		}
-	} );
+
+	}
 
 
 	THREE.MorphBlendMesh = MorphBlendMesh;
 	THREE.MorphBlendMesh = MorphBlendMesh;
 
 

+ 354 - 344
examples/js/misc/RollerCoaster.js

@@ -1,422 +1,432 @@
 ( function () {
 ( function () {
 
 
-	var RollerCoasterGeometry = function ( curve, divisions ) {
-
-		THREE.BufferGeometry.call( this );
-		var vertices = [];
-		var normals = [];
-		var colors = [];
-		var color1 = [ 1, 1, 1 ];
-		var color2 = [ 1, 1, 0 ];
-		var up = new THREE.Vector3( 0, 1, 0 );
-		var forward = new THREE.Vector3();
-		var right = new THREE.Vector3();
-		var quaternion = new THREE.Quaternion();
-		var prevQuaternion = new THREE.Quaternion();
-		prevQuaternion.setFromAxisAngle( up, Math.PI / 2 );
-		var point = new THREE.Vector3();
-		var prevPoint = new THREE.Vector3();
-		prevPoint.copy( curve.getPointAt( 0 ) ); // shapes
-
-		var step = [ new THREE.Vector3( - 0.225, 0, 0 ), new THREE.Vector3( 0, - 0.050, 0 ), new THREE.Vector3( 0, - 0.175, 0 ), new THREE.Vector3( 0, - 0.050, 0 ), new THREE.Vector3( 0.225, 0, 0 ), new THREE.Vector3( 0, - 0.175, 0 ) ];
-		var PI2 = Math.PI * 2;
-		var sides = 5;
-		var tube1 = [];
-
-		for ( var i = 0; i < sides; i ++ ) {
-
-			var angle = i / sides * PI2;
-			tube1.push( new THREE.Vector3( Math.sin( angle ) * 0.06, Math.cos( angle ) * 0.06, 0 ) );
+	class RollerCoasterGeometry extends THREE.BufferGeometry {
+
+		constructor( curve, divisions ) {
+
+			super();
+			const vertices = [];
+			const normals = [];
+			const colors = [];
+			const color1 = [ 1, 1, 1 ];
+			const color2 = [ 1, 1, 0 ];
+			const up = new THREE.Vector3( 0, 1, 0 );
+			const forward = new THREE.Vector3();
+			const right = new THREE.Vector3();
+			const quaternion = new THREE.Quaternion();
+			const prevQuaternion = new THREE.Quaternion();
+			prevQuaternion.setFromAxisAngle( up, Math.PI / 2 );
+			const point = new THREE.Vector3();
+			const prevPoint = new THREE.Vector3();
+			prevPoint.copy( curve.getPointAt( 0 ) ); // shapes
+
+			const step = [ new THREE.Vector3( - 0.225, 0, 0 ), new THREE.Vector3( 0, - 0.050, 0 ), new THREE.Vector3( 0, - 0.175, 0 ), new THREE.Vector3( 0, - 0.050, 0 ), new THREE.Vector3( 0.225, 0, 0 ), new THREE.Vector3( 0, - 0.175, 0 ) ];
+			const PI2 = Math.PI * 2;
+			let sides = 5;
+			const tube1 = [];
+
+			for ( let i = 0; i < sides; i ++ ) {
+
+				const angle = i / sides * PI2;
+				tube1.push( new THREE.Vector3( Math.sin( angle ) * 0.06, Math.cos( angle ) * 0.06, 0 ) );
 
 
-		}
-
-		var sides = 6;
-		var tube2 = [];
-
-		for ( var i = 0; i < sides; i ++ ) {
-
-			var angle = i / sides * PI2;
-			tube2.push( new THREE.Vector3( Math.sin( angle ) * 0.025, Math.cos( angle ) * 0.025, 0 ) );
+			}
 
 
-		}
+			sides = 6;
+			const tube2 = [];
 
 
-		var vector = new THREE.Vector3();
-		var normal = new THREE.Vector3();
+			for ( let i = 0; i < sides; i ++ ) {
 
 
-		function drawShape( shape, color ) {
+				const angle = i / sides * PI2;
+				tube2.push( new THREE.Vector3( Math.sin( angle ) * 0.025, Math.cos( angle ) * 0.025, 0 ) );
 
 
-			normal.set( 0, 0, - 1 ).applyQuaternion( quaternion );
+			}
 
 
-			for ( var j = 0; j < shape.length; j ++ ) {
+			const vector = new THREE.Vector3();
+			const normal = new THREE.Vector3();
 
 
-				vector.copy( shape[ j ] );
-				vector.applyQuaternion( quaternion );
-				vector.add( point );
-				vertices.push( vector.x, vector.y, vector.z );
-				normals.push( normal.x, normal.y, normal.z );
-				colors.push( color[ 0 ], color[ 1 ], color[ 2 ] );
+			function drawShape( shape, color ) {
 
 
-			}
+				normal.set( 0, 0, - 1 ).applyQuaternion( quaternion );
 
 
-			normal.set( 0, 0, 1 ).applyQuaternion( quaternion );
+				for ( let j = 0; j < shape.length; j ++ ) {
 
 
-			for ( var j = shape.length - 1; j >= 0; j -- ) {
+					vector.copy( shape[ j ] );
+					vector.applyQuaternion( quaternion );
+					vector.add( point );
+					vertices.push( vector.x, vector.y, vector.z );
+					normals.push( normal.x, normal.y, normal.z );
+					colors.push( color[ 0 ], color[ 1 ], color[ 2 ] );
 
 
-				vector.copy( shape[ j ] );
-				vector.applyQuaternion( quaternion );
-				vector.add( point );
-				vertices.push( vector.x, vector.y, vector.z );
-				normals.push( normal.x, normal.y, normal.z );
-				colors.push( color[ 0 ], color[ 1 ], color[ 2 ] );
+				}
 
 
-			}
+				normal.set( 0, 0, 1 ).applyQuaternion( quaternion );
 
 
-		}
+				for ( let j = shape.length - 1; j >= 0; j -- ) {
 
 
-		var vector1 = new THREE.Vector3();
-		var vector2 = new THREE.Vector3();
-		var vector3 = new THREE.Vector3();
-		var vector4 = new THREE.Vector3();
-		var normal1 = new THREE.Vector3();
-		var normal2 = new THREE.Vector3();
-		var normal3 = new THREE.Vector3();
-		var normal4 = new THREE.Vector3();
+					vector.copy( shape[ j ] );
+					vector.applyQuaternion( quaternion );
+					vector.add( point );
+					vertices.push( vector.x, vector.y, vector.z );
+					normals.push( normal.x, normal.y, normal.z );
+					colors.push( color[ 0 ], color[ 1 ], color[ 2 ] );
 
 
-		function extrudeShape( shape, offset, color ) {
+				}
 
 
-			for ( var j = 0, jl = shape.length; j < jl; j ++ ) {
+			}
 
 
-				var point1 = shape[ j ];
-				var point2 = shape[ ( j + 1 ) % jl ];
-				vector1.copy( point1 ).add( offset );
-				vector1.applyQuaternion( quaternion );
-				vector1.add( point );
-				vector2.copy( point2 ).add( offset );
-				vector2.applyQuaternion( quaternion );
-				vector2.add( point );
-				vector3.copy( point2 ).add( offset );
-				vector3.applyQuaternion( prevQuaternion );
-				vector3.add( prevPoint );
-				vector4.copy( point1 ).add( offset );
-				vector4.applyQuaternion( prevQuaternion );
-				vector4.add( prevPoint );
-				vertices.push( vector1.x, vector1.y, vector1.z );
-				vertices.push( vector2.x, vector2.y, vector2.z );
-				vertices.push( vector4.x, vector4.y, vector4.z );
-				vertices.push( vector2.x, vector2.y, vector2.z );
-				vertices.push( vector3.x, vector3.y, vector3.z );
-				vertices.push( vector4.x, vector4.y, vector4.z ); //
-
-				normal1.copy( point1 );
-				normal1.applyQuaternion( quaternion );
-				normal1.normalize();
-				normal2.copy( point2 );
-				normal2.applyQuaternion( quaternion );
-				normal2.normalize();
-				normal3.copy( point2 );
-				normal3.applyQuaternion( prevQuaternion );
-				normal3.normalize();
-				normal4.copy( point1 );
-				normal4.applyQuaternion( prevQuaternion );
-				normal4.normalize();
-				normals.push( normal1.x, normal1.y, normal1.z );
-				normals.push( normal2.x, normal2.y, normal2.z );
-				normals.push( normal4.x, normal4.y, normal4.z );
-				normals.push( normal2.x, normal2.y, normal2.z );
-				normals.push( normal3.x, normal3.y, normal3.z );
-				normals.push( normal4.x, normal4.y, normal4.z );
-				colors.push( color[ 0 ], color[ 1 ], color[ 2 ] );
-				colors.push( color[ 0 ], color[ 1 ], color[ 2 ] );
-				colors.push( color[ 0 ], color[ 1 ], color[ 2 ] );
-				colors.push( color[ 0 ], color[ 1 ], color[ 2 ] );
-				colors.push( color[ 0 ], color[ 1 ], color[ 2 ] );
-				colors.push( color[ 0 ], color[ 1 ], color[ 2 ] );
+			const vector1 = new THREE.Vector3();
+			const vector2 = new THREE.Vector3();
+			const vector3 = new THREE.Vector3();
+			const vector4 = new THREE.Vector3();
+			const normal1 = new THREE.Vector3();
+			const normal2 = new THREE.Vector3();
+			const normal3 = new THREE.Vector3();
+			const normal4 = new THREE.Vector3();
+
+			function extrudeShape( shape, offset, color ) {
+
+				for ( let j = 0, jl = shape.length; j < jl; j ++ ) {
+
+					const point1 = shape[ j ];
+					const point2 = shape[ ( j + 1 ) % jl ];
+					vector1.copy( point1 ).add( offset );
+					vector1.applyQuaternion( quaternion );
+					vector1.add( point );
+					vector2.copy( point2 ).add( offset );
+					vector2.applyQuaternion( quaternion );
+					vector2.add( point );
+					vector3.copy( point2 ).add( offset );
+					vector3.applyQuaternion( prevQuaternion );
+					vector3.add( prevPoint );
+					vector4.copy( point1 ).add( offset );
+					vector4.applyQuaternion( prevQuaternion );
+					vector4.add( prevPoint );
+					vertices.push( vector1.x, vector1.y, vector1.z );
+					vertices.push( vector2.x, vector2.y, vector2.z );
+					vertices.push( vector4.x, vector4.y, vector4.z );
+					vertices.push( vector2.x, vector2.y, vector2.z );
+					vertices.push( vector3.x, vector3.y, vector3.z );
+					vertices.push( vector4.x, vector4.y, vector4.z ); //
+
+					normal1.copy( point1 );
+					normal1.applyQuaternion( quaternion );
+					normal1.normalize();
+					normal2.copy( point2 );
+					normal2.applyQuaternion( quaternion );
+					normal2.normalize();
+					normal3.copy( point2 );
+					normal3.applyQuaternion( prevQuaternion );
+					normal3.normalize();
+					normal4.copy( point1 );
+					normal4.applyQuaternion( prevQuaternion );
+					normal4.normalize();
+					normals.push( normal1.x, normal1.y, normal1.z );
+					normals.push( normal2.x, normal2.y, normal2.z );
+					normals.push( normal4.x, normal4.y, normal4.z );
+					normals.push( normal2.x, normal2.y, normal2.z );
+					normals.push( normal3.x, normal3.y, normal3.z );
+					normals.push( normal4.x, normal4.y, normal4.z );
+					colors.push( color[ 0 ], color[ 1 ], color[ 2 ] );
+					colors.push( color[ 0 ], color[ 1 ], color[ 2 ] );
+					colors.push( color[ 0 ], color[ 1 ], color[ 2 ] );
+					colors.push( color[ 0 ], color[ 1 ], color[ 2 ] );
+					colors.push( color[ 0 ], color[ 1 ], color[ 2 ] );
+					colors.push( color[ 0 ], color[ 1 ], color[ 2 ] );
+
+				}
 
 
 			}
 			}
 
 
-		}
-
-		var offset = new THREE.Vector3();
+			const offset = new THREE.Vector3();
 
 
-		for ( var i = 1; i <= divisions; i ++ ) {
+			for ( let i = 1; i <= divisions; i ++ ) {
 
 
-			point.copy( curve.getPointAt( i / divisions ) );
-			up.set( 0, 1, 0 );
-			forward.subVectors( point, prevPoint ).normalize();
-			right.crossVectors( up, forward ).normalize();
-			up.crossVectors( forward, right );
-			var angle = Math.atan2( forward.x, forward.z );
-			quaternion.setFromAxisAngle( up, angle );
+				point.copy( curve.getPointAt( i / divisions ) );
+				up.set( 0, 1, 0 );
+				forward.subVectors( point, prevPoint ).normalize();
+				right.crossVectors( up, forward ).normalize();
+				up.crossVectors( forward, right );
+				const angle = Math.atan2( forward.x, forward.z );
+				quaternion.setFromAxisAngle( up, angle );
 
 
-			if ( i % 2 === 0 ) {
+				if ( i % 2 === 0 ) {
 
 
-				drawShape( step, color2 );
+					drawShape( step, color2 );
 
 
-			}
+				}
 
 
-			extrudeShape( tube1, offset.set( 0, - 0.125, 0 ), color2 );
-			extrudeShape( tube2, offset.set( 0.2, 0, 0 ), color1 );
-			extrudeShape( tube2, offset.set( - 0.2, 0, 0 ), color1 );
-			prevPoint.copy( point );
-			prevQuaternion.copy( quaternion );
+				extrudeShape( tube1, offset.set( 0, - 0.125, 0 ), color2 );
+				extrudeShape( tube2, offset.set( 0.2, 0, 0 ), color1 );
+				extrudeShape( tube2, offset.set( - 0.2, 0, 0 ), color1 );
+				prevPoint.copy( point );
+				prevQuaternion.copy( quaternion );
 
 
-		} // console.log( vertices.length );
+			} // console.log( vertices.length );
 
 
 
 
-		this.setAttribute( 'position', new THREE.BufferAttribute( new Float32Array( vertices ), 3 ) );
-		this.setAttribute( 'normal', new THREE.BufferAttribute( new Float32Array( normals ), 3 ) );
-		this.setAttribute( 'color', new THREE.BufferAttribute( new Float32Array( colors ), 3 ) );
+			this.setAttribute( 'position', new THREE.BufferAttribute( new Float32Array( vertices ), 3 ) );
+			this.setAttribute( 'normal', new THREE.BufferAttribute( new Float32Array( normals ), 3 ) );
+			this.setAttribute( 'color', new THREE.BufferAttribute( new Float32Array( colors ), 3 ) );
 
 
-	};
+		}
 
 
-	RollerCoasterGeometry.prototype = Object.create( THREE.BufferGeometry.prototype );
+	}
+
+	class RollerCoasterLiftersGeometry extends THREE.BufferGeometry {
+
+		constructor( curve, divisions ) {
+
+			super();
+			const vertices = [];
+			const normals = [];
+			const quaternion = new THREE.Quaternion();
+			const up = new THREE.Vector3( 0, 1, 0 );
+			const point = new THREE.Vector3();
+			const tangent = new THREE.Vector3(); // shapes
+
+			const tube1 = [ new THREE.Vector3( 0, 0.05, - 0.05 ), new THREE.Vector3( 0, 0.05, 0.05 ), new THREE.Vector3( 0, - 0.05, 0 ) ];
+			const tube2 = [ new THREE.Vector3( - 0.05, 0, 0.05 ), new THREE.Vector3( - 0.05, 0, - 0.05 ), new THREE.Vector3( 0.05, 0, 0 ) ];
+			const tube3 = [ new THREE.Vector3( 0.05, 0, - 0.05 ), new THREE.Vector3( 0.05, 0, 0.05 ), new THREE.Vector3( - 0.05, 0, 0 ) ];
+			const vector1 = new THREE.Vector3();
+			const vector2 = new THREE.Vector3();
+			const vector3 = new THREE.Vector3();
+			const vector4 = new THREE.Vector3();
+			const normal1 = new THREE.Vector3();
+			const normal2 = new THREE.Vector3();
+			const normal3 = new THREE.Vector3();
+			const normal4 = new THREE.Vector3();
+
+			function extrudeShape( shape, fromPoint, toPoint ) {
+
+				for ( let j = 0, jl = shape.length; j < jl; j ++ ) {
+
+					const point1 = shape[ j ];
+					const point2 = shape[ ( j + 1 ) % jl ];
+					vector1.copy( point1 );
+					vector1.applyQuaternion( quaternion );
+					vector1.add( fromPoint );
+					vector2.copy( point2 );
+					vector2.applyQuaternion( quaternion );
+					vector2.add( fromPoint );
+					vector3.copy( point2 );
+					vector3.applyQuaternion( quaternion );
+					vector3.add( toPoint );
+					vector4.copy( point1 );
+					vector4.applyQuaternion( quaternion );
+					vector4.add( toPoint );
+					vertices.push( vector1.x, vector1.y, vector1.z );
+					vertices.push( vector2.x, vector2.y, vector2.z );
+					vertices.push( vector4.x, vector4.y, vector4.z );
+					vertices.push( vector2.x, vector2.y, vector2.z );
+					vertices.push( vector3.x, vector3.y, vector3.z );
+					vertices.push( vector4.x, vector4.y, vector4.z ); //
+
+					normal1.copy( point1 );
+					normal1.applyQuaternion( quaternion );
+					normal1.normalize();
+					normal2.copy( point2 );
+					normal2.applyQuaternion( quaternion );
+					normal2.normalize();
+					normal3.copy( point2 );
+					normal3.applyQuaternion( quaternion );
+					normal3.normalize();
+					normal4.copy( point1 );
+					normal4.applyQuaternion( quaternion );
+					normal4.normalize();
+					normals.push( normal1.x, normal1.y, normal1.z );
+					normals.push( normal2.x, normal2.y, normal2.z );
+					normals.push( normal4.x, normal4.y, normal4.z );
+					normals.push( normal2.x, normal2.y, normal2.z );
+					normals.push( normal3.x, normal3.y, normal3.z );
+					normals.push( normal4.x, normal4.y, normal4.z );
+
+				}
 
 
-	var RollerCoasterLiftersGeometry = function ( curve, divisions ) {
+			}
 
 
-		THREE.BufferGeometry.call( this );
-		var vertices = [];
-		var normals = [];
-		var quaternion = new THREE.Quaternion();
-		var up = new THREE.Vector3( 0, 1, 0 );
-		var point = new THREE.Vector3();
-		var tangent = new THREE.Vector3(); // shapes
+			const fromPoint = new THREE.Vector3();
+			const toPoint = new THREE.Vector3();
+
+			for ( let i = 1; i <= divisions; i ++ ) {
+
+				point.copy( curve.getPointAt( i / divisions ) );
+				tangent.copy( curve.getTangentAt( i / divisions ) );
+				const angle = Math.atan2( tangent.x, tangent.z );
+				quaternion.setFromAxisAngle( up, angle ); //
+
+				if ( point.y > 10 ) {
+
+					fromPoint.set( - 0.75, - 0.35, 0 );
+					fromPoint.applyQuaternion( quaternion );
+					fromPoint.add( point );
+					toPoint.set( 0.75, - 0.35, 0 );
+					toPoint.applyQuaternion( quaternion );
+					toPoint.add( point );
+					extrudeShape( tube1, fromPoint, toPoint );
+					fromPoint.set( - 0.7, - 0.3, 0 );
+					fromPoint.applyQuaternion( quaternion );
+					fromPoint.add( point );
+					toPoint.set( - 0.7, - point.y, 0 );
+					toPoint.applyQuaternion( quaternion );
+					toPoint.add( point );
+					extrudeShape( tube2, fromPoint, toPoint );
+					fromPoint.set( 0.7, - 0.3, 0 );
+					fromPoint.applyQuaternion( quaternion );
+					fromPoint.add( point );
+					toPoint.set( 0.7, - point.y, 0 );
+					toPoint.applyQuaternion( quaternion );
+					toPoint.add( point );
+					extrudeShape( tube3, fromPoint, toPoint );
+
+				} else {
+
+					fromPoint.set( 0, - 0.2, 0 );
+					fromPoint.applyQuaternion( quaternion );
+					fromPoint.add( point );
+					toPoint.set( 0, - point.y, 0 );
+					toPoint.applyQuaternion( quaternion );
+					toPoint.add( point );
+					extrudeShape( tube3, fromPoint, toPoint );
+
+				}
 
 
-		var tube1 = [ new THREE.Vector3( 0, 0.05, - 0.05 ), new THREE.Vector3( 0, 0.05, 0.05 ), new THREE.Vector3( 0, - 0.05, 0 ) ];
-		var tube2 = [ new THREE.Vector3( - 0.05, 0, 0.05 ), new THREE.Vector3( - 0.05, 0, - 0.05 ), new THREE.Vector3( 0.05, 0, 0 ) ];
-		var tube3 = [ new THREE.Vector3( 0.05, 0, - 0.05 ), new THREE.Vector3( 0.05, 0, 0.05 ), new THREE.Vector3( - 0.05, 0, 0 ) ];
-		var vector1 = new THREE.Vector3();
-		var vector2 = new THREE.Vector3();
-		var vector3 = new THREE.Vector3();
-		var vector4 = new THREE.Vector3();
-		var normal1 = new THREE.Vector3();
-		var normal2 = new THREE.Vector3();
-		var normal3 = new THREE.Vector3();
-		var normal4 = new THREE.Vector3();
+			}
 
 
-		function extrudeShape( shape, fromPoint, toPoint ) {
+			this.setAttribute( 'position', new THREE.BufferAttribute( new Float32Array( vertices ), 3 ) );
+			this.setAttribute( 'normal', new THREE.BufferAttribute( new Float32Array( normals ), 3 ) );
 
 
-			for ( var j = 0, jl = shape.length; j < jl; j ++ ) {
+		}
 
 
-				var point1 = shape[ j ];
-				var point2 = shape[ ( j + 1 ) % jl ];
-				vector1.copy( point1 );
+	}
+
+	class RollerCoasterShadowGeometry extends THREE.BufferGeometry {
+
+		constructor( curve, divisions ) {
+
+			super();
+			const vertices = [];
+			const up = new THREE.Vector3( 0, 1, 0 );
+			const forward = new THREE.Vector3();
+			const quaternion = new THREE.Quaternion();
+			const prevQuaternion = new THREE.Quaternion();
+			prevQuaternion.setFromAxisAngle( up, Math.PI / 2 );
+			const point = new THREE.Vector3();
+			const prevPoint = new THREE.Vector3();
+			prevPoint.copy( curve.getPointAt( 0 ) );
+			prevPoint.y = 0;
+			const vector1 = new THREE.Vector3();
+			const vector2 = new THREE.Vector3();
+			const vector3 = new THREE.Vector3();
+			const vector4 = new THREE.Vector3();
+
+			for ( let i = 1; i <= divisions; i ++ ) {
+
+				point.copy( curve.getPointAt( i / divisions ) );
+				point.y = 0;
+				forward.subVectors( point, prevPoint );
+				const angle = Math.atan2( forward.x, forward.z );
+				quaternion.setFromAxisAngle( up, angle );
+				vector1.set( - 0.3, 0, 0 );
 				vector1.applyQuaternion( quaternion );
 				vector1.applyQuaternion( quaternion );
-				vector1.add( fromPoint );
-				vector2.copy( point2 );
+				vector1.add( point );
+				vector2.set( 0.3, 0, 0 );
 				vector2.applyQuaternion( quaternion );
 				vector2.applyQuaternion( quaternion );
-				vector2.add( fromPoint );
-				vector3.copy( point2 );
-				vector3.applyQuaternion( quaternion );
-				vector3.add( toPoint );
-				vector4.copy( point1 );
-				vector4.applyQuaternion( quaternion );
-				vector4.add( toPoint );
+				vector2.add( point );
+				vector3.set( 0.3, 0, 0 );
+				vector3.applyQuaternion( prevQuaternion );
+				vector3.add( prevPoint );
+				vector4.set( - 0.3, 0, 0 );
+				vector4.applyQuaternion( prevQuaternion );
+				vector4.add( prevPoint );
 				vertices.push( vector1.x, vector1.y, vector1.z );
 				vertices.push( vector1.x, vector1.y, vector1.z );
 				vertices.push( vector2.x, vector2.y, vector2.z );
 				vertices.push( vector2.x, vector2.y, vector2.z );
 				vertices.push( vector4.x, vector4.y, vector4.z );
 				vertices.push( vector4.x, vector4.y, vector4.z );
 				vertices.push( vector2.x, vector2.y, vector2.z );
 				vertices.push( vector2.x, vector2.y, vector2.z );
 				vertices.push( vector3.x, vector3.y, vector3.z );
 				vertices.push( vector3.x, vector3.y, vector3.z );
-				vertices.push( vector4.x, vector4.y, vector4.z ); //
-
-				normal1.copy( point1 );
-				normal1.applyQuaternion( quaternion );
-				normal1.normalize();
-				normal2.copy( point2 );
-				normal2.applyQuaternion( quaternion );
-				normal2.normalize();
-				normal3.copy( point2 );
-				normal3.applyQuaternion( quaternion );
-				normal3.normalize();
-				normal4.copy( point1 );
-				normal4.applyQuaternion( quaternion );
-				normal4.normalize();
-				normals.push( normal1.x, normal1.y, normal1.z );
-				normals.push( normal2.x, normal2.y, normal2.z );
-				normals.push( normal4.x, normal4.y, normal4.z );
-				normals.push( normal2.x, normal2.y, normal2.z );
-				normals.push( normal3.x, normal3.y, normal3.z );
-				normals.push( normal4.x, normal4.y, normal4.z );
+				vertices.push( vector4.x, vector4.y, vector4.z );
+				prevPoint.copy( point );
+				prevQuaternion.copy( quaternion );
 
 
 			}
 			}
 
 
-		}
-
-		var fromPoint = new THREE.Vector3();
-		var toPoint = new THREE.Vector3();
-
-		for ( var i = 1; i <= divisions; i ++ ) {
-
-			point.copy( curve.getPointAt( i / divisions ) );
-			tangent.copy( curve.getTangentAt( i / divisions ) );
-			var angle = Math.atan2( tangent.x, tangent.z );
-			quaternion.setFromAxisAngle( up, angle ); //
-
-			if ( point.y > 10 ) {
-
-				fromPoint.set( - 0.75, - 0.35, 0 );
-				fromPoint.applyQuaternion( quaternion );
-				fromPoint.add( point );
-				toPoint.set( 0.75, - 0.35, 0 );
-				toPoint.applyQuaternion( quaternion );
-				toPoint.add( point );
-				extrudeShape( tube1, fromPoint, toPoint );
-				fromPoint.set( - 0.7, - 0.3, 0 );
-				fromPoint.applyQuaternion( quaternion );
-				fromPoint.add( point );
-				toPoint.set( - 0.7, - point.y, 0 );
-				toPoint.applyQuaternion( quaternion );
-				toPoint.add( point );
-				extrudeShape( tube2, fromPoint, toPoint );
-				fromPoint.set( 0.7, - 0.3, 0 );
-				fromPoint.applyQuaternion( quaternion );
-				fromPoint.add( point );
-				toPoint.set( 0.7, - point.y, 0 );
-				toPoint.applyQuaternion( quaternion );
-				toPoint.add( point );
-				extrudeShape( tube3, fromPoint, toPoint );
-
-			} else {
-
-				fromPoint.set( 0, - 0.2, 0 );
-				fromPoint.applyQuaternion( quaternion );
-				fromPoint.add( point );
-				toPoint.set( 0, - point.y, 0 );
-				toPoint.applyQuaternion( quaternion );
-				toPoint.add( point );
-				extrudeShape( tube3, fromPoint, toPoint );
-
-			}
+			this.setAttribute( 'position', new THREE.BufferAttribute( new Float32Array( vertices ), 3 ) );
 
 
 		}
 		}
 
 
-		this.setAttribute( 'position', new THREE.BufferAttribute( new Float32Array( vertices ), 3 ) );
-		this.setAttribute( 'normal', new THREE.BufferAttribute( new Float32Array( normals ), 3 ) );
-
-	};
-
-	RollerCoasterLiftersGeometry.prototype = Object.create( THREE.BufferGeometry.prototype );
-
-	var RollerCoasterShadowGeometry = function ( curve, divisions ) {
-
-		THREE.BufferGeometry.call( this );
-		var vertices = [];
-		var up = new THREE.Vector3( 0, 1, 0 );
-		var forward = new THREE.Vector3();
-		var quaternion = new THREE.Quaternion();
-		var prevQuaternion = new THREE.Quaternion();
-		prevQuaternion.setFromAxisAngle( up, Math.PI / 2 );
-		var point = new THREE.Vector3();
-		var prevPoint = new THREE.Vector3();
-		prevPoint.copy( curve.getPointAt( 0 ) );
-		prevPoint.y = 0;
-		var vector1 = new THREE.Vector3();
-		var vector2 = new THREE.Vector3();
-		var vector3 = new THREE.Vector3();
-		var vector4 = new THREE.Vector3();
-
-		for ( var i = 1; i <= divisions; i ++ ) {
-
-			point.copy( curve.getPointAt( i / divisions ) );
-			point.y = 0;
-			forward.subVectors( point, prevPoint );
-			var angle = Math.atan2( forward.x, forward.z );
-			quaternion.setFromAxisAngle( up, angle );
-			vector1.set( - 0.3, 0, 0 );
-			vector1.applyQuaternion( quaternion );
-			vector1.add( point );
-			vector2.set( 0.3, 0, 0 );
-			vector2.applyQuaternion( quaternion );
-			vector2.add( point );
-			vector3.set( 0.3, 0, 0 );
-			vector3.applyQuaternion( prevQuaternion );
-			vector3.add( prevPoint );
-			vector4.set( - 0.3, 0, 0 );
-			vector4.applyQuaternion( prevQuaternion );
-			vector4.add( prevPoint );
-			vertices.push( vector1.x, vector1.y, vector1.z );
-			vertices.push( vector2.x, vector2.y, vector2.z );
-			vertices.push( vector4.x, vector4.y, vector4.z );
-			vertices.push( vector2.x, vector2.y, vector2.z );
-			vertices.push( vector3.x, vector3.y, vector3.z );
-			vertices.push( vector4.x, vector4.y, vector4.z );
-			prevPoint.copy( point );
-			prevQuaternion.copy( quaternion );
+	}
 
 
-		}
-
-		this.setAttribute( 'position', new THREE.BufferAttribute( new Float32Array( vertices ), 3 ) );
+	class SkyGeometry extends THREE.BufferGeometry {
 
 
-	};
+		constructor() {
 
 
-	RollerCoasterShadowGeometry.prototype = Object.create( THREE.BufferGeometry.prototype );
+			super();
+			const vertices = [];
 
 
-	var SkyGeometry = function () {
+			for ( let i = 0; i < 100; i ++ ) {
 
 
-		THREE.BufferGeometry.call( this );
-		var vertices = [];
+				const x = Math.random() * 800 - 400;
+				const y = Math.random() * 50 + 50;
+				const z = Math.random() * 800 - 400;
+				const size = Math.random() * 40 + 20;
+				vertices.push( x - size, y, z - size );
+				vertices.push( x + size, y, z - size );
+				vertices.push( x - size, y, z + size );
+				vertices.push( x + size, y, z - size );
+				vertices.push( x + size, y, z + size );
+				vertices.push( x - size, y, z + size );
 
 
-		for ( var i = 0; i < 100; i ++ ) {
+			}
 
 
-			var x = Math.random() * 800 - 400;
-			var y = Math.random() * 50 + 50;
-			var z = Math.random() * 800 - 400;
-			var size = Math.random() * 40 + 20;
-			vertices.push( x - size, y, z - size );
-			vertices.push( x + size, y, z - size );
-			vertices.push( x - size, y, z + size );
-			vertices.push( x + size, y, z - size );
-			vertices.push( x + size, y, z + size );
-			vertices.push( x - size, y, z + size );
+			this.setAttribute( 'position', new THREE.BufferAttribute( new Float32Array( vertices ), 3 ) );
 
 
 		}
 		}
 
 
-		this.setAttribute( 'position', new THREE.BufferAttribute( new Float32Array( vertices ), 3 ) );
+	}
 
 
-	};
+	class TreesGeometry extends THREE.BufferGeometry {
 
 
-	SkyGeometry.prototype = Object.create( THREE.BufferGeometry.prototype );
+		constructor( landscape ) {
 
 
-	var TreesGeometry = function ( landscape ) {
+			super();
+			const vertices = [];
+			const colors = [];
+			const raycaster = new THREE.Raycaster();
+			raycaster.ray.direction.set( 0, - 1, 0 );
 
 
-		THREE.BufferGeometry.call( this );
-		var vertices = [];
-		var colors = [];
-		var raycaster = new THREE.Raycaster();
-		raycaster.ray.direction.set( 0, - 1, 0 );
+			for ( let i = 0; i < 2000; i ++ ) {
 
 
-		for ( var i = 0; i < 2000; i ++ ) {
+				const x = Math.random() * 500 - 250;
+				const z = Math.random() * 500 - 250;
+				raycaster.ray.origin.set( x, 50, z );
+				const intersections = raycaster.intersectObject( landscape );
+				if ( intersections.length === 0 ) continue;
+				const y = intersections[ 0 ].point.y;
+				const height = Math.random() * 5 + 0.5;
+				let angle = Math.random() * Math.PI * 2;
+				vertices.push( x + Math.sin( angle ), y, z + Math.cos( angle ) );
+				vertices.push( x, y + height, z );
+				vertices.push( x + Math.sin( angle + Math.PI ), y, z + Math.cos( angle + Math.PI ) );
+				angle += Math.PI / 2;
+				vertices.push( x + Math.sin( angle ), y, z + Math.cos( angle ) );
+				vertices.push( x, y + height, z );
+				vertices.push( x + Math.sin( angle + Math.PI ), y, z + Math.cos( angle + Math.PI ) );
+				const random = Math.random() * 0.1;
 
 
-			var x = Math.random() * 500 - 250;
-			var z = Math.random() * 500 - 250;
-			raycaster.ray.origin.set( x, 50, z );
-			var intersections = raycaster.intersectObject( landscape );
-			if ( intersections.length === 0 ) continue;
-			var y = intersections[ 0 ].point.y;
-			var height = Math.random() * 5 + 0.5;
-			var angle = Math.random() * Math.PI * 2;
-			vertices.push( x + Math.sin( angle ), y, z + Math.cos( angle ) );
-			vertices.push( x, y + height, z );
-			vertices.push( x + Math.sin( angle + Math.PI ), y, z + Math.cos( angle + Math.PI ) );
-			angle += Math.PI / 2;
-			vertices.push( x + Math.sin( angle ), y, z + Math.cos( angle ) );
-			vertices.push( x, y + height, z );
-			vertices.push( x + Math.sin( angle + Math.PI ), y, z + Math.cos( angle + Math.PI ) );
-			var random = Math.random() * 0.1;
+				for ( let j = 0; j < 6; j ++ ) {
 
 
-			for ( var j = 0; j < 6; j ++ ) {
+					colors.push( 0.2 + random, 0.4 + random, 0 );
 
 
-				colors.push( 0.2 + random, 0.4 + random, 0 );
+				}
 
 
 			}
 			}
 
 
-		}
-
-		this.setAttribute( 'position', new THREE.BufferAttribute( new Float32Array( vertices ), 3 ) );
-		this.setAttribute( 'color', new THREE.BufferAttribute( new Float32Array( colors ), 3 ) );
+			this.setAttribute( 'position', new THREE.BufferAttribute( new Float32Array( vertices ), 3 ) );
+			this.setAttribute( 'color', new THREE.BufferAttribute( new Float32Array( colors ), 3 ) );
 
 
-	};
+		}
 
 
-	TreesGeometry.prototype = Object.create( THREE.BufferGeometry.prototype );
+	}
 
 
 	THREE.RollerCoasterGeometry = RollerCoasterGeometry;
 	THREE.RollerCoasterGeometry = RollerCoasterGeometry;
 	THREE.RollerCoasterLiftersGeometry = RollerCoasterLiftersGeometry;
 	THREE.RollerCoasterLiftersGeometry = RollerCoasterLiftersGeometry;

+ 135 - 142
examples/jsm/misc/ConvexObjectBreaker.js

@@ -35,40 +35,40 @@ import { ConvexGeometry } from '../geometries/ConvexGeometry.js';
  *
  *
 */
 */
 
 
-var ConvexObjectBreaker = function ( minSizeForBreak, smallDelta ) {
+const _v1 = new Vector3();
+
+class ConvexObjectBreaker {
+
+	constructor( minSizeForBreak = 1.4, smallDelta = 0.0001 ) {
+
+		this.minSizeForBreak = minSizeForBreak;
+		this.smallDelta = smallDelta;
+
+		this.tempLine1 = new Line3();
+		this.tempPlane1 = new Plane();
+		this.tempPlane2 = new Plane();
+		this.tempPlane_Cut = new Plane();
+		this.tempCM1 = new Vector3();
+		this.tempCM2 = new Vector3();
+		this.tempVector3 = new Vector3();
+		this.tempVector3_2 = new Vector3();
+		this.tempVector3_3 = new Vector3();
+		this.tempVector3_P0 = new Vector3();
+		this.tempVector3_P1 = new Vector3();
+		this.tempVector3_P2 = new Vector3();
+		this.tempVector3_N0 = new Vector3();
+		this.tempVector3_N1 = new Vector3();
+		this.tempVector3_AB = new Vector3();
+		this.tempVector3_CB = new Vector3();
+		this.tempResultObjects = { object1: null, object2: null };
+
+		this.segments = [];
+		const n = 30 * 30;
+		for ( let i = 0; i < n; i ++ ) this.segments[ i ] = false;
 
 
-	this.minSizeForBreak = minSizeForBreak || 1.4;
-	this.smallDelta = smallDelta || 0.0001;
-
-	this.tempLine1 = new Line3();
-	this.tempPlane1 = new Plane();
-	this.tempPlane2 = new Plane();
-	this.tempPlane_Cut = new Plane();
-	this.tempCM1 = new Vector3();
-	this.tempCM2 = new Vector3();
-	this.tempVector3 = new Vector3();
-	this.tempVector3_2 = new Vector3();
-	this.tempVector3_3 = new Vector3();
-	this.tempVector3_P0 = new Vector3();
-	this.tempVector3_P1 = new Vector3();
-	this.tempVector3_P2 = new Vector3();
-	this.tempVector3_N0 = new Vector3();
-	this.tempVector3_N1 = new Vector3();
-	this.tempVector3_AB = new Vector3();
-	this.tempVector3_CB = new Vector3();
-	this.tempResultObjects = { object1: null, object2: null };
-
-	this.segments = [];
-	var n = 30 * 30;
-	for ( var i = 0; i < n; i ++ ) this.segments[ i ] = false;
-
-};
-
-ConvexObjectBreaker.prototype = {
-
-	constructor: ConvexObjectBreaker,
+	}
 
 
-	prepareBreakableObject: function ( object, mass, velocity, angularVelocity, breakable ) {
+	prepareBreakableObject( object, mass, velocity, angularVelocity, breakable ) {
 
 
 		// object is a Object3d (normally a Mesh), must have a BufferGeometry, and it must be convex.
 		// object is a Object3d (normally a Mesh), must have a BufferGeometry, and it must be convex.
 		// Its material property is propagated to its children (sub-pieces)
 		// Its material property is propagated to its children (sub-pieces)
@@ -80,13 +80,13 @@ ConvexObjectBreaker.prototype = {
 
 
 		}
 		}
 
 
-		var userData = object.userData;
+		const userData = object.userData;
 		userData.mass = mass;
 		userData.mass = mass;
 		userData.velocity = velocity.clone();
 		userData.velocity = velocity.clone();
 		userData.angularVelocity = angularVelocity.clone();
 		userData.angularVelocity = angularVelocity.clone();
 		userData.breakable = breakable;
 		userData.breakable = breakable;
 
 
-	},
+	}
 
 
 	/*
 	/*
 	 * @param {int} maxRadialIterations Iterations for radial cuts.
 	 * @param {int} maxRadialIterations Iterations for radial cuts.
@@ -94,19 +94,19 @@ ConvexObjectBreaker.prototype = {
 	 *
 	 *
 	 * Returns the array of pieces
 	 * Returns the array of pieces
 	 */
 	 */
-	subdivideByImpact: function ( object, pointOfImpact, normal, maxRadialIterations, maxRandomIterations ) {
+	subdivideByImpact( object, pointOfImpact, normal, maxRadialIterations, maxRandomIterations ) {
 
 
-		var debris = [];
+		const debris = [];
 
 
-		var tempPlane1 = this.tempPlane1;
-		var tempPlane2 = this.tempPlane2;
+		const tempPlane1 = this.tempPlane1;
+		const tempPlane2 = this.tempPlane2;
 
 
 		this.tempVector3.addVectors( pointOfImpact, normal );
 		this.tempVector3.addVectors( pointOfImpact, normal );
 		tempPlane1.setFromCoplanarPoints( pointOfImpact, object.position, this.tempVector3 );
 		tempPlane1.setFromCoplanarPoints( pointOfImpact, object.position, this.tempVector3 );
 
 
-		var maxTotalIterations = maxRandomIterations + maxRadialIterations;
+		const maxTotalIterations = maxRandomIterations + maxRadialIterations;
 
 
-		var scope = this;
+		const scope = this;
 
 
 		function subdivideRadial( subObject, startAngle, endAngle, numIterations ) {
 		function subdivideRadial( subObject, startAngle, endAngle, numIterations ) {
 
 
@@ -118,7 +118,7 @@ ConvexObjectBreaker.prototype = {
 
 
 			}
 			}
 
 
-			var angle = Math.PI;
+			let angle = Math.PI;
 
 
 			if ( numIterations === 0 ) {
 			if ( numIterations === 0 ) {
 
 
@@ -151,8 +151,8 @@ ConvexObjectBreaker.prototype = {
 			// Perform the cut
 			// Perform the cut
 			scope.cutByPlane( subObject, tempPlane2, scope.tempResultObjects );
 			scope.cutByPlane( subObject, tempPlane2, scope.tempResultObjects );
 
 
-			var obj1 = scope.tempResultObjects.object1;
-			var obj2 = scope.tempResultObjects.object2;
+			const obj1 = scope.tempResultObjects.object1;
+			const obj2 = scope.tempResultObjects.object2;
 
 
 			if ( obj1 ) {
 			if ( obj1 ) {
 
 
@@ -172,23 +172,23 @@ ConvexObjectBreaker.prototype = {
 
 
 		return debris;
 		return debris;
 
 
-	},
+	}
 
 
-	cutByPlane: function ( object, plane, output ) {
+	cutByPlane( object, plane, output ) {
 
 
 		// Returns breakable objects in output.object1 and output.object2 members, the resulting 2 pieces of the cut.
 		// Returns breakable objects in output.object1 and output.object2 members, the resulting 2 pieces of the cut.
 		// object2 can be null if the plane doesn't cut the object.
 		// object2 can be null if the plane doesn't cut the object.
 		// object1 can be null only in case of internal error
 		// object1 can be null only in case of internal error
 		// Returned value is number of pieces, 0 for error.
 		// Returned value is number of pieces, 0 for error.
 
 
-		var geometry = object.geometry;
-		var coords = geometry.attributes.position.array;
-		var normals = geometry.attributes.normal.array;
+		const geometry = object.geometry;
+		const coords = geometry.attributes.position.array;
+		const normals = geometry.attributes.normal.array;
 
 
-		var numPoints = coords.length / 3;
-		var numFaces = numPoints / 3;
+		const numPoints = coords.length / 3;
+		let numFaces = numPoints / 3;
 
 
-		var indices = geometry.getIndex();
+		let indices = geometry.getIndex();
 
 
 		if ( indices ) {
 		if ( indices ) {
 
 
@@ -201,46 +201,46 @@ ConvexObjectBreaker.prototype = {
 
 
 			// vert = 0, 1 or 2.
 			// vert = 0, 1 or 2.
 
 
-			var idx = faceIdx * 3 + vert;
+			const idx = faceIdx * 3 + vert;
 
 
 			return indices ? indices[ idx ] : idx;
 			return indices ? indices[ idx ] : idx;
 
 
 		}
 		}
 
 
-		var points1 = [];
-		var points2 = [];
+		const points1 = [];
+		const points2 = [];
 
 
-		var delta = this.smallDelta;
+		const delta = this.smallDelta;
 
 
 		// Reset segments mark
 		// Reset segments mark
-		var numPointPairs = numPoints * numPoints;
-		for ( var i = 0; i < numPointPairs; i ++ ) this.segments[ i ] = false;
+		const numPointPairs = numPoints * numPoints;
+		for ( let i = 0; i < numPointPairs; i ++ ) this.segments[ i ] = false;
 
 
-		var p0 = this.tempVector3_P0;
-		var p1 = this.tempVector3_P1;
-		var n0 = this.tempVector3_N0;
-		var n1 = this.tempVector3_N1;
+		const p0 = this.tempVector3_P0;
+		const p1 = this.tempVector3_P1;
+		const n0 = this.tempVector3_N0;
+		const n1 = this.tempVector3_N1;
 
 
 		// Iterate through the faces to mark edges shared by coplanar faces
 		// Iterate through the faces to mark edges shared by coplanar faces
-		for ( var i = 0; i < numFaces - 1; i ++ ) {
+		for ( let i = 0; i < numFaces - 1; i ++ ) {
 
 
-			var a1 = getVertexIndex( i, 0 );
-			var b1 = getVertexIndex( i, 1 );
-			var c1 = getVertexIndex( i, 2 );
+			const a1 = getVertexIndex( i, 0 );
+			const b1 = getVertexIndex( i, 1 );
+			const c1 = getVertexIndex( i, 2 );
 
 
 			// Assuming all 3 vertices have the same normal
 			// Assuming all 3 vertices have the same normal
 			n0.set( normals[ a1 ], normals[ a1 ] + 1, normals[ a1 ] + 2 );
 			n0.set( normals[ a1 ], normals[ a1 ] + 1, normals[ a1 ] + 2 );
 
 
-			for ( var j = i + 1; j < numFaces; j ++ ) {
+			for ( let j = i + 1; j < numFaces; j ++ ) {
 
 
-				var a2 = getVertexIndex( j, 0 );
-				var b2 = getVertexIndex( j, 1 );
-				var c2 = getVertexIndex( j, 2 );
+				const a2 = getVertexIndex( j, 0 );
+				const b2 = getVertexIndex( j, 1 );
+				const c2 = getVertexIndex( j, 2 );
 
 
 				// Assuming all 3 vertices have the same normal
 				// Assuming all 3 vertices have the same normal
 				n1.set( normals[ a2 ], normals[ a2 ] + 1, normals[ a2 ] + 2 );
 				n1.set( normals[ a2 ], normals[ a2 ] + 1, normals[ a2 ] + 2 );
 
 
-				var coplanar = 1 - n0.dot( n1 ) < delta;
+				const coplanar = 1 - n0.dot( n1 ) < delta;
 
 
 				if ( coplanar ) {
 				if ( coplanar ) {
 
 
@@ -272,23 +272,23 @@ ConvexObjectBreaker.prototype = {
 		}
 		}
 
 
 		// Transform the plane to object local space
 		// Transform the plane to object local space
-		var localPlane = this.tempPlane_Cut;
+		const localPlane = this.tempPlane_Cut;
 		object.updateMatrix();
 		object.updateMatrix();
 		ConvexObjectBreaker.transformPlaneToLocalSpace( plane, object.matrix, localPlane );
 		ConvexObjectBreaker.transformPlaneToLocalSpace( plane, object.matrix, localPlane );
 
 
 		// Iterate through the faces adding points to both pieces
 		// Iterate through the faces adding points to both pieces
-		for ( var i = 0; i < numFaces; i ++ ) {
+		for ( let i = 0; i < numFaces; i ++ ) {
 
 
-			var va = getVertexIndex( i, 0 );
-			var vb = getVertexIndex( i, 1 );
-			var vc = getVertexIndex( i, 2 );
+			const va = getVertexIndex( i, 0 );
+			const vb = getVertexIndex( i, 1 );
+			const vc = getVertexIndex( i, 2 );
 
 
-			for ( var segment = 0; segment < 3; segment ++ ) {
+			for ( let segment = 0; segment < 3; segment ++ ) {
 
 
-				var i0 = segment === 0 ? va : ( segment === 1 ? vb : vc );
-				var i1 = segment === 0 ? vb : ( segment === 1 ? vc : va );
+				const i0 = segment === 0 ? va : ( segment === 1 ? vb : vc );
+				const i1 = segment === 0 ? vb : ( segment === 1 ? vc : va );
 
 
-				var segmentState = this.segments[ i0 * numPoints + i1 ];
+				const segmentState = this.segments[ i0 * numPoints + i1 ];
 
 
 				if ( segmentState ) continue; // The segment already has been processed in another face
 				if ( segmentState ) continue; // The segment already has been processed in another face
 
 
@@ -300,9 +300,9 @@ ConvexObjectBreaker.prototype = {
 				p1.set( coords[ 3 * i1 ], coords[ 3 * i1 + 1 ], coords[ 3 * i1 + 2 ] );
 				p1.set( coords[ 3 * i1 ], coords[ 3 * i1 + 1 ], coords[ 3 * i1 + 2 ] );
 
 
 				// mark: 1 for negative side, 2 for positive side, 3 for coplanar point
 				// mark: 1 for negative side, 2 for positive side, 3 for coplanar point
-				var mark0 = 0;
+				let mark0 = 0;
 
 
-				var d = localPlane.distanceToPoint( p0 );
+				let d = localPlane.distanceToPoint( p0 );
 
 
 				if ( d > delta ) {
 				if ( d > delta ) {
 
 
@@ -323,9 +323,9 @@ ConvexObjectBreaker.prototype = {
 				}
 				}
 
 
 				// mark: 1 for negative side, 2 for positive side, 3 for coplanar point
 				// mark: 1 for negative side, 2 for positive side, 3 for coplanar point
-				var mark1 = 0;
+				let mark1 = 0;
 
 
-				var d = localPlane.distanceToPoint( p1 );
+				d = localPlane.distanceToPoint( p1 );
 
 
 				if ( d > delta ) {
 				if ( d > delta ) {
 
 
@@ -352,7 +352,7 @@ ConvexObjectBreaker.prototype = {
 					this.tempLine1.start.copy( p0 );
 					this.tempLine1.start.copy( p0 );
 					this.tempLine1.end.copy( p1 );
 					this.tempLine1.end.copy( p1 );
 
 
-					var intersection = new Vector3();
+					let intersection = new Vector3();
 					intersection = localPlane.intersectLine( this.tempLine1, intersection );
 					intersection = localPlane.intersectLine( this.tempLine1, intersection );
 
 
 					if ( intersection === null ) {
 					if ( intersection === null ) {
@@ -375,21 +375,21 @@ ConvexObjectBreaker.prototype = {
 		}
 		}
 
 
 		// Calculate debris mass (very fast and imprecise):
 		// Calculate debris mass (very fast and imprecise):
-		var newMass = object.userData.mass * 0.5;
+		const newMass = object.userData.mass * 0.5;
 
 
 		// Calculate debris Center of Mass (again fast and imprecise)
 		// Calculate debris Center of Mass (again fast and imprecise)
 		this.tempCM1.set( 0, 0, 0 );
 		this.tempCM1.set( 0, 0, 0 );
-		var radius1 = 0;
-		var numPoints1 = points1.length;
+		let radius1 = 0;
+		const numPoints1 = points1.length;
 
 
 		if ( numPoints1 > 0 ) {
 		if ( numPoints1 > 0 ) {
 
 
-			for ( var i = 0; i < numPoints1; i ++ ) this.tempCM1.add( points1[ i ] );
+			for ( let i = 0; i < numPoints1; i ++ ) this.tempCM1.add( points1[ i ] );
 
 
 			this.tempCM1.divideScalar( numPoints1 );
 			this.tempCM1.divideScalar( numPoints1 );
-			for ( var i = 0; i < numPoints1; i ++ ) {
+			for ( let i = 0; i < numPoints1; i ++ ) {
 
 
-				var p = points1[ i ];
+				const p = points1[ i ];
 				p.sub( this.tempCM1 );
 				p.sub( this.tempCM1 );
 				radius1 = Math.max( radius1, p.x, p.y, p.z );
 				radius1 = Math.max( radius1, p.x, p.y, p.z );
 
 
@@ -400,16 +400,16 @@ ConvexObjectBreaker.prototype = {
 		}
 		}
 
 
 		this.tempCM2.set( 0, 0, 0 );
 		this.tempCM2.set( 0, 0, 0 );
-		var radius2 = 0;
-		var numPoints2 = points2.length;
+		let radius2 = 0;
+		const numPoints2 = points2.length;
 		if ( numPoints2 > 0 ) {
 		if ( numPoints2 > 0 ) {
 
 
-			for ( var i = 0; i < numPoints2; i ++ ) this.tempCM2.add( points2[ i ] );
+			for ( let i = 0; i < numPoints2; i ++ ) this.tempCM2.add( points2[ i ] );
 
 
 			this.tempCM2.divideScalar( numPoints2 );
 			this.tempCM2.divideScalar( numPoints2 );
-			for ( var i = 0; i < numPoints2; i ++ ) {
+			for ( let i = 0; i < numPoints2; i ++ ) {
 
 
-				var p = points2[ i ];
+				const p = points2[ i ];
 				p.sub( this.tempCM2 );
 				p.sub( this.tempCM2 );
 				radius2 = Math.max( radius2, p.x, p.y, p.z );
 				radius2 = Math.max( radius2, p.x, p.y, p.z );
 
 
@@ -419,10 +419,10 @@ ConvexObjectBreaker.prototype = {
 
 
 		}
 		}
 
 
-		var object1 = null;
-		var object2 = null;
+		let object1 = null;
+		let object2 = null;
 
 
-		var numObjects = 0;
+		let numObjects = 0;
 
 
 		if ( numPoints1 > 4 ) {
 		if ( numPoints1 > 4 ) {
 
 
@@ -455,78 +455,71 @@ ConvexObjectBreaker.prototype = {
 
 
 	}
 	}
 
 
-};
+	static transformFreeVector( v, m ) {
 
 
-ConvexObjectBreaker.transformFreeVector = function ( v, m ) {
+		// input:
+		// vector interpreted as a free vector
+		// THREE.Matrix4 orthogonal matrix (matrix without scale)
 
 
-	// input:
-	// vector interpreted as a free vector
-	// THREE.Matrix4 orthogonal matrix (matrix without scale)
+		const x = v.x, y = v.y, z = v.z;
+		const e = m.elements;
 
 
-	var x = v.x, y = v.y, z = v.z;
-	var e = m.elements;
+		v.x = e[ 0 ] * x + e[ 4 ] * y + e[ 8 ] * z;
+		v.y = e[ 1 ] * x + e[ 5 ] * y + e[ 9 ] * z;
+		v.z = e[ 2 ] * x + e[ 6 ] * y + e[ 10 ] * z;
 
 
-	v.x = e[ 0 ] * x + e[ 4 ] * y + e[ 8 ] * z;
-	v.y = e[ 1 ] * x + e[ 5 ] * y + e[ 9 ] * z;
-	v.z = e[ 2 ] * x + e[ 6 ] * y + e[ 10 ] * z;
+		return v;
 
 
-	return v;
-
-};
-
-ConvexObjectBreaker.transformFreeVectorInverse = function ( v, m ) {
-
-	// input:
-	// vector interpreted as a free vector
-	// THREE.Matrix4 orthogonal matrix (matrix without scale)
+	}
 
 
-	var x = v.x, y = v.y, z = v.z;
-	var e = m.elements;
+	static transformFreeVectorInverse( v, m ) {
 
 
-	v.x = e[ 0 ] * x + e[ 1 ] * y + e[ 2 ] * z;
-	v.y = e[ 4 ] * x + e[ 5 ] * y + e[ 6 ] * z;
-	v.z = e[ 8 ] * x + e[ 9 ] * y + e[ 10 ] * z;
+		// input:
+		// vector interpreted as a free vector
+		// THREE.Matrix4 orthogonal matrix (matrix without scale)
 
 
-	return v;
+		const x = v.x, y = v.y, z = v.z;
+		const e = m.elements;
 
 
-};
+		v.x = e[ 0 ] * x + e[ 1 ] * y + e[ 2 ] * z;
+		v.y = e[ 4 ] * x + e[ 5 ] * y + e[ 6 ] * z;
+		v.z = e[ 8 ] * x + e[ 9 ] * y + e[ 10 ] * z;
 
 
-ConvexObjectBreaker.transformTiedVectorInverse = function ( v, m ) {
+		return v;
 
 
-	// input:
-	// vector interpreted as a tied (ordinary) vector
-	// THREE.Matrix4 orthogonal matrix (matrix without scale)
+	}
 
 
-	var x = v.x, y = v.y, z = v.z;
-	var e = m.elements;
+	static transformTiedVectorInverse( v, m ) {
 
 
-	v.x = e[ 0 ] * x + e[ 1 ] * y + e[ 2 ] * z - e[ 12 ];
-	v.y = e[ 4 ] * x + e[ 5 ] * y + e[ 6 ] * z - e[ 13 ];
-	v.z = e[ 8 ] * x + e[ 9 ] * y + e[ 10 ] * z - e[ 14 ];
+		// input:
+		// vector interpreted as a tied (ordinary) vector
+		// THREE.Matrix4 orthogonal matrix (matrix without scale)
 
 
-	return v;
+		const x = v.x, y = v.y, z = v.z;
+		const e = m.elements;
 
 
-};
+		v.x = e[ 0 ] * x + e[ 1 ] * y + e[ 2 ] * z - e[ 12 ];
+		v.y = e[ 4 ] * x + e[ 5 ] * y + e[ 6 ] * z - e[ 13 ];
+		v.z = e[ 8 ] * x + e[ 9 ] * y + e[ 10 ] * z - e[ 14 ];
 
 
-ConvexObjectBreaker.transformPlaneToLocalSpace = function () {
+		return v;
 
 
-	var v1 = new Vector3();
+	}
 
 
-	return function transformPlaneToLocalSpace( plane, m, resultPlane ) {
+	static transformPlaneToLocalSpace( plane, m, resultPlane ) {
 
 
 		resultPlane.normal.copy( plane.normal );
 		resultPlane.normal.copy( plane.normal );
 		resultPlane.constant = plane.constant;
 		resultPlane.constant = plane.constant;
 
 
-		var referencePoint = ConvexObjectBreaker.transformTiedVectorInverse( plane.coplanarPoint( v1 ), m );
+		const referencePoint = ConvexObjectBreaker.transformTiedVectorInverse( plane.coplanarPoint( _v1 ), m );
 
 
 		ConvexObjectBreaker.transformFreeVectorInverse( resultPlane.normal, m );
 		ConvexObjectBreaker.transformFreeVectorInverse( resultPlane.normal, m );
 
 
 		// recalculate constant (like in setFromNormalAndCoplanarPoint)
 		// recalculate constant (like in setFromNormalAndCoplanarPoint)
 		resultPlane.constant = - referencePoint.dot( resultPlane.normal );
 		resultPlane.constant = - referencePoint.dot( resultPlane.normal );
 
 
+	}
 
 
-	};
-
-}();
+}
 
 
 export { ConvexObjectBreaker };
 export { ConvexObjectBreaker };

+ 186 - 180
examples/jsm/misc/GPUComputationRenderer.js

@@ -40,16 +40,16 @@ import {
  * // Initialization...
  * // Initialization...
  *
  *
  * // Create computation renderer
  * // Create computation renderer
- * var gpuCompute = new GPUComputationRenderer( 1024, 1024, renderer );
+ * const gpuCompute = new GPUComputationRenderer( 1024, 1024, renderer );
  *
  *
  * // Create initial state float textures
  * // Create initial state float textures
- * var pos0 = gpuCompute.createTexture();
- * var vel0 = gpuCompute.createTexture();
+ * const pos0 = gpuCompute.createTexture();
+ * const vel0 = gpuCompute.createTexture();
  * // and fill in here the texture data...
  * // and fill in here the texture data...
  *
  *
  * // Add texture variables
  * // Add texture variables
- * var velVar = gpuCompute.addVariable( "textureVelocity", fragmentShaderVel, pos0 );
- * var posVar = gpuCompute.addVariable( "texturePosition", fragmentShaderPos, vel0 );
+ * const velVar = gpuCompute.addVariable( "textureVelocity", fragmentShaderVel, pos0 );
+ * const posVar = gpuCompute.addVariable( "texturePosition", fragmentShaderPos, vel0 );
  *
  *
  * // Add variable dependencies
  * // Add variable dependencies
  * gpuCompute.setVariableDependencies( velVar, [ velVar, posVar ] );
  * gpuCompute.setVariableDependencies( velVar, [ velVar, posVar ] );
@@ -59,7 +59,7 @@ import {
  * velVar.material.uniforms.time = { value: 0.0 };
  * velVar.material.uniforms.time = { value: 0.0 };
  *
  *
  * // Check for completeness
  * // Check for completeness
- * var error = gpuCompute.init();
+ * const error = gpuCompute.init();
  * if ( error !== null ) {
  * if ( error !== null ) {
  *		console.error( error );
  *		console.error( error );
   * }
   * }
@@ -81,19 +81,19 @@ import {
  * Also, you can use utility functions to create ShaderMaterial and perform computations (rendering between textures)
  * Also, you can use utility functions to create ShaderMaterial and perform computations (rendering between textures)
  * Note that the shaders can have multiple input 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 } } );
+ * const myFilter1 = gpuCompute.createShaderMaterial( myFilterFragmentShader1, { theTexture: { value: null } } );
+ * const myFilter2 = gpuCompute.createShaderMaterial( myFilterFragmentShader2, { theTexture: { value: null } } );
  *
  *
- * var inputTexture = gpuCompute.createTexture();
+ * const inputTexture = gpuCompute.createTexture();
  *
  *
  * // Fill in here inputTexture...
  * // Fill in here inputTexture...
  *
  *
  * myFilter1.uniforms.theTexture.value = inputTexture;
  * myFilter1.uniforms.theTexture.value = inputTexture;
  *
  *
- * var myRenderTarget = gpuCompute.createRenderTarget();
+ * const myRenderTarget = gpuCompute.createRenderTarget();
  * myFilter2.uniforms.theTexture.value = myRenderTarget.texture;
  * myFilter2.uniforms.theTexture.value = myRenderTarget.texture;
  *
  *
- * var outputRenderTarget = gpuCompute.createRenderTarget();
+ * const outputRenderTarget = gpuCompute.createRenderTarget();
  *
  *
  * // Now use the output texture where you want:
  * // Now use the output texture where you want:
  * myMaterial.uniforms.map.value = outputRenderTarget.texture;
  * myMaterial.uniforms.map.value = outputRenderTarget.texture;
@@ -109,295 +109,301 @@ import {
  * @param {WebGLRenderer} renderer The renderer
  * @param {WebGLRenderer} renderer The renderer
   */
   */
 
 
-var GPUComputationRenderer = function ( sizeX, sizeY, renderer ) {
+class GPUComputationRenderer {
 
 
-	this.variables = [];
+	constructor( sizeX, sizeY, renderer ) {
 
 
-	this.currentTextureIndex = 0;
+		this.variables = [];
 
 
-	var dataType = FloatType;
+		this.currentTextureIndex = 0;
 
 
-	var scene = new Scene();
+		let dataType = FloatType;
 
 
-	var camera = new Camera();
-	camera.position.z = 1;
+		const scene = new Scene();
 
 
-	var passThruUniforms = {
-		passThruTexture: { value: null }
-	};
+		const camera = new Camera();
+		camera.position.z = 1;
 
 
-	var passThruShader = createShaderMaterial( getPassThroughFragmentShader(), passThruUniforms );
+		const passThruUniforms = {
+			passThruTexture: { value: null }
+		};
 
 
-	var mesh = new Mesh( new PlaneGeometry( 2, 2 ), passThruShader );
-	scene.add( mesh );
+		const passThruShader = createShaderMaterial( getPassThroughFragmentShader(), passThruUniforms );
 
 
+		const mesh = new Mesh( new PlaneGeometry( 2, 2 ), passThruShader );
+		scene.add( mesh );
 
 
-	this.setDataType = function ( type ) {
 
 
-		dataType = type;
-		return this;
+		this.setDataType = function ( type ) {
 
 
-	};
+			dataType = type;
+			return this;
 
 
-	this.addVariable = function ( variableName, computeFragmentShader, initialValueTexture ) {
+		};
 
 
-		var material = this.createShaderMaterial( computeFragmentShader );
+		this.addVariable = function ( variableName, computeFragmentShader, initialValueTexture ) {
 
 
-		var variable = {
-			name: variableName,
-			initialValueTexture: initialValueTexture,
-			material: material,
-			dependencies: null,
-			renderTargets: [],
-			wrapS: null,
-			wrapT: null,
-			minFilter: NearestFilter,
-			magFilter: NearestFilter
-		};
+			const material = this.createShaderMaterial( computeFragmentShader );
+
+			const variable = {
+				name: variableName,
+				initialValueTexture: initialValueTexture,
+				material: material,
+				dependencies: null,
+				renderTargets: [],
+				wrapS: null,
+				wrapT: null,
+				minFilter: NearestFilter,
+				magFilter: NearestFilter
+			};
 
 
-		this.variables.push( variable );
+			this.variables.push( variable );
 
 
-		return variable;
+			return variable;
 
 
-	};
+		};
 
 
-	this.setVariableDependencies = function ( variable, dependencies ) {
+		this.setVariableDependencies = function ( variable, dependencies ) {
 
 
-		variable.dependencies = dependencies;
+			variable.dependencies = dependencies;
 
 
-	};
+		};
 
 
-	this.init = function () {
+		this.init = function () {
 
 
-		if ( renderer.capabilities.isWebGL2 === false && renderer.extensions.has( 'OES_texture_float' ) === false ) {
+			if ( renderer.capabilities.isWebGL2 === false && renderer.extensions.has( 'OES_texture_float' ) === false ) {
 
 
-			return 'No OES_texture_float support for float textures.';
+				return 'No OES_texture_float support for float textures.';
 
 
-		}
+			}
 
 
-		if ( renderer.capabilities.maxVertexTextures === 0 ) {
+			if ( renderer.capabilities.maxVertexTextures === 0 ) {
 
 
-			return 'No support for vertex shader textures.';
+				return 'No support for vertex shader textures.';
 
 
-		}
+			}
+
+			for ( let i = 0; i < this.variables.length; i ++ ) {
+
+				const variable = this.variables[ i ];
 
 
-		for ( var i = 0; i < this.variables.length; 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 ] );
 
 
-			var variable = this.variables[ i ];
+				// Adds dependencies uniforms to the ShaderMaterial
+				const material = variable.material;
+				const uniforms = material.uniforms;
 
 
-			// 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 ] );
+				if ( variable.dependencies !== null ) {
 
 
-			// Adds dependencies uniforms to the ShaderMaterial
-			var material = variable.material;
-			var uniforms = material.uniforms;
+					for ( let d = 0; d < variable.dependencies.length; d ++ ) {
 
 
-			if ( variable.dependencies !== null ) {
+						const depVar = variable.dependencies[ d ];
 
 
-				for ( var d = 0; d < variable.dependencies.length; d ++ ) {
+						if ( depVar.name !== variable.name ) {
 
 
-					var depVar = variable.dependencies[ d ];
+							// Checks if variable exists
+							let found = false;
 
 
-					if ( depVar.name !== variable.name ) {
+							for ( let j = 0; j < this.variables.length; j ++ ) {
 
 
-						// Checks if variable exists
-						var found = false;
-						for ( var j = 0; j < this.variables.length; j ++ ) {
+								if ( depVar.name === this.variables[ j ].name ) {
 
 
-							if ( depVar.name === this.variables[ j ].name ) {
+									found = true;
+									break;
 
 
-								found = true;
-								break;
+								}
 
 
 							}
 							}
 
 
-						}
+							if ( ! found ) {
 
 
-						if ( ! found ) {
+								return 'Variable dependency not found. Variable=' + variable.name + ', dependency=' + depVar.name;
 
 
-							return 'Variable dependency not found. Variable=' + variable.name + ', dependency=' + depVar.name;
+							}
 
 
 						}
 						}
 
 
-					}
+						uniforms[ depVar.name ] = { value: null };
 
 
-					uniforms[ depVar.name ] = { value: null };
+						material.fragmentShader = '\nuniform sampler2D ' + depVar.name + ';\n' + material.fragmentShader;
 
 
-					material.fragmentShader = '\nuniform sampler2D ' + depVar.name + ';\n' + material.fragmentShader;
+					}
 
 
 				}
 				}
 
 
 			}
 			}
 
 
-		}
+			this.currentTextureIndex = 0;
 
 
-		this.currentTextureIndex = 0;
+			return null;
 
 
-		return null;
+		};
 
 
-	};
+		this.compute = function () {
 
 
-	this.compute = function () {
+			const currentTextureIndex = this.currentTextureIndex;
+			const nextTextureIndex = this.currentTextureIndex === 0 ? 1 : 0;
 
 
-		var currentTextureIndex = this.currentTextureIndex;
-		var nextTextureIndex = this.currentTextureIndex === 0 ? 1 : 0;
+			for ( let i = 0, il = this.variables.length; i < il; i ++ ) {
 
 
-		for ( var i = 0, il = this.variables.length; i < il; i ++ ) {
+				const variable = this.variables[ i ];
 
 
-			var variable = this.variables[ i ];
+				// Sets texture dependencies uniforms
+				if ( variable.dependencies !== null ) {
 
 
-			// Sets texture dependencies uniforms
-			if ( variable.dependencies !== null ) {
+					const uniforms = variable.material.uniforms;
 
 
-				var uniforms = variable.material.uniforms;
-				for ( var d = 0, dl = variable.dependencies.length; d < dl; d ++ ) {
+					for ( let d = 0, dl = variable.dependencies.length; d < dl; d ++ ) {
 
 
-					var depVar = variable.dependencies[ d ];
+						const depVar = variable.dependencies[ d ];
 
 
-					uniforms[ depVar.name ].value = depVar.renderTargets[ currentTextureIndex ].texture;
+						uniforms[ depVar.name ].value = depVar.renderTargets[ currentTextureIndex ].texture;
+
+					}
 
 
 				}
 				}
 
 
-			}
+				// Performs the computation for this variable
+				this.doRenderTarget( variable.material, variable.renderTargets[ nextTextureIndex ] );
 
 
-			// Performs the computation for this variable
-			this.doRenderTarget( variable.material, variable.renderTargets[ nextTextureIndex ] );
+			}
 
 
-		}
+			this.currentTextureIndex = nextTextureIndex;
 
 
-		this.currentTextureIndex = nextTextureIndex;
+		};
 
 
-	};
+		this.getCurrentRenderTarget = function ( variable ) {
 
 
-	this.getCurrentRenderTarget = function ( variable ) {
+			return variable.renderTargets[ this.currentTextureIndex ];
 
 
-		return variable.renderTargets[ this.currentTextureIndex ];
+		};
 
 
-	};
+		this.getAlternateRenderTarget = function ( variable ) {
 
 
-	this.getAlternateRenderTarget = function ( variable ) {
+			return variable.renderTargets[ this.currentTextureIndex === 0 ? 1 : 0 ];
 
 
-		return variable.renderTargets[ this.currentTextureIndex === 0 ? 1 : 0 ];
+		};
 
 
-	};
+		function addResolutionDefine( materialShader ) {
 
 
-	function addResolutionDefine( materialShader ) {
+			materialShader.defines.resolution = 'vec2( ' + sizeX.toFixed( 1 ) + ', ' + sizeY.toFixed( 1 ) + ' )';
 
 
-		materialShader.defines.resolution = 'vec2( ' + sizeX.toFixed( 1 ) + ', ' + sizeY.toFixed( 1 ) + ' )';
+		}
 
 
-	}
+		this.addResolutionDefine = addResolutionDefine;
 
 
-	this.addResolutionDefine = addResolutionDefine;
 
 
+		// The following functions can be used to compute things manually
 
 
-	// The following functions can be used to compute things manually
+		function createShaderMaterial( computeFragmentShader, uniforms ) {
 
 
-	function createShaderMaterial( computeFragmentShader, uniforms ) {
+			uniforms = uniforms || {};
 
 
-		uniforms = uniforms || {};
+			const material = new ShaderMaterial( {
+				uniforms: uniforms,
+				vertexShader: getPassThroughVertexShader(),
+				fragmentShader: computeFragmentShader
+			} );
 
 
-		var material = new ShaderMaterial( {
-			uniforms: uniforms,
-			vertexShader: getPassThroughVertexShader(),
-			fragmentShader: computeFragmentShader
-		} );
+			addResolutionDefine( material );
 
 
-		addResolutionDefine( material );
+			return material;
 
 
-		return material;
+		}
 
 
-	}
+		this.createShaderMaterial = createShaderMaterial;
 
 
-	this.createShaderMaterial = createShaderMaterial;
+		this.createRenderTarget = function ( sizeXTexture, sizeYTexture, wrapS, wrapT, minFilter, magFilter ) {
 
 
-	this.createRenderTarget = function ( sizeXTexture, sizeYTexture, wrapS, wrapT, minFilter, magFilter ) {
+			sizeXTexture = sizeXTexture || sizeX;
+			sizeYTexture = sizeYTexture || sizeY;
 
 
-		sizeXTexture = sizeXTexture || sizeX;
-		sizeYTexture = sizeYTexture || sizeY;
+			wrapS = wrapS || ClampToEdgeWrapping;
+			wrapT = wrapT || ClampToEdgeWrapping;
 
 
-		wrapS = wrapS || ClampToEdgeWrapping;
-		wrapT = wrapT || ClampToEdgeWrapping;
+			minFilter = minFilter || NearestFilter;
+			magFilter = magFilter || NearestFilter;
 
 
-		minFilter = minFilter || NearestFilter;
-		magFilter = magFilter || NearestFilter;
+			const renderTarget = new WebGLRenderTarget( sizeXTexture, sizeYTexture, {
+				wrapS: wrapS,
+				wrapT: wrapT,
+				minFilter: minFilter,
+				magFilter: magFilter,
+				format: RGBAFormat,
+				type: dataType,
+				depthBuffer: false
+			} );
 
 
-		var renderTarget = new WebGLRenderTarget( sizeXTexture, sizeYTexture, {
-			wrapS: wrapS,
-			wrapT: wrapT,
-			minFilter: minFilter,
-			magFilter: magFilter,
-			format: RGBAFormat,
-			type: dataType,
-			depthBuffer: false
-		} );
+			return renderTarget;
 
 
-		return renderTarget;
+		};
 
 
-	};
+		this.createTexture = function () {
 
 
-	this.createTexture = function () {
+			const data = new Float32Array( sizeX * sizeY * 4 );
+			return new DataTexture( data, sizeX, sizeY, RGBAFormat, FloatType );
 
 
-		var data = new Float32Array( sizeX * sizeY * 4 );
-		return new DataTexture( data, sizeX, sizeY, RGBAFormat, FloatType );
+		};
 
 
-	};
+		this.renderTexture = function ( input, output ) {
 
 
-	this.renderTexture = function ( input, output ) {
+			// Takes a texture, and render out in rendertarget
+			// input = Texture
+			// output = RenderTarget
 
 
-		// Takes a texture, and render out in rendertarget
-		// input = Texture
-		// output = RenderTarget
+			passThruUniforms.passThruTexture.value = input;
 
 
-		passThruUniforms.passThruTexture.value = input;
+			this.doRenderTarget( passThruShader, output );
 
 
-		this.doRenderTarget( passThruShader, output );
+			passThruUniforms.passThruTexture.value = null;
 
 
-		passThruUniforms.passThruTexture.value = null;
+		};
 
 
-	};
+		this.doRenderTarget = function ( material, output ) {
 
 
-	this.doRenderTarget = function ( material, output ) {
+			const currentRenderTarget = renderer.getRenderTarget();
 
 
-		var currentRenderTarget = renderer.getRenderTarget();
+			mesh.material = material;
+			renderer.setRenderTarget( output );
+			renderer.render( scene, camera );
+			mesh.material = passThruShader;
 
 
-		mesh.material = material;
-		renderer.setRenderTarget( output );
-		renderer.render( scene, camera );
-		mesh.material = passThruShader;
+			renderer.setRenderTarget( currentRenderTarget );
 
 
-		renderer.setRenderTarget( currentRenderTarget );
+		};
 
 
-	};
+		// Shaders
 
 
-	// Shaders
+		function getPassThroughVertexShader() {
 
 
-	function getPassThroughVertexShader() {
+			return	'void main()	{\n' +
+					'\n' +
+					'	gl_Position = vec4( position, 1.0 );\n' +
+					'\n' +
+					'}\n';
 
 
-		return	'void main()	{\n' +
-				'\n' +
-				'	gl_Position = vec4( position, 1.0 );\n' +
-				'\n' +
-				'}\n';
+		}
 
 
-	}
+		function getPassThroughFragmentShader() {
 
 
-	function getPassThroughFragmentShader() {
+			return	'uniform sampler2D passThruTexture;\n' +
+					'\n' +
+					'void main() {\n' +
+					'\n' +
+					'	vec2 uv = gl_FragCoord.xy / resolution.xy;\n' +
+					'\n' +
+					'	gl_FragColor = texture2D( passThruTexture, uv );\n' +
+					'\n' +
+					'}\n';
 
 
-		return	'uniform sampler2D passThruTexture;\n' +
-				'\n' +
-				'void main() {\n' +
-				'\n' +
-				'	vec2 uv = gl_FragCoord.xy / resolution.xy;\n' +
-				'\n' +
-				'	gl_FragColor = texture2D( passThruTexture, uv );\n' +
-				'\n' +
-				'}\n';
+		}
 
 
 	}
 	}
 
 
-};
+}
 
 
 export { GPUComputationRenderer };
 export { GPUComputationRenderer };

+ 17 - 20
examples/jsm/misc/Gyroscope.js

@@ -4,26 +4,23 @@ import {
 	Vector3
 	Vector3
 } from '../../../build/three.module.js';
 } from '../../../build/three.module.js';
 
 
-var Gyroscope = function () {
+const _translationObject = new Vector3();
+const _quaternionObject = new Quaternion();
+const _scaleObject = new Vector3();
 
 
-	Object3D.call( this );
+const _translationWorld = new Vector3();
+const _quaternionWorld = new Quaternion();
+const _scaleWorld = new Vector3();
 
 
-};
+class Gyroscope extends Object3D {
 
 
-Gyroscope.prototype = Object.create( Object3D.prototype );
-Gyroscope.prototype.constructor = Gyroscope;
+	constructor() {
 
 
-Gyroscope.prototype.updateMatrixWorld = ( function () {
+		super();
 
 
-	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 ) {
+	updateMatrixWorld( force ) {
 
 
 		this.matrixAutoUpdate && this.updateMatrix();
 		this.matrixAutoUpdate && this.updateMatrix();
 
 
@@ -35,10 +32,10 @@ Gyroscope.prototype.updateMatrixWorld = ( function () {
 
 
 				this.matrixWorld.multiplyMatrices( this.parent.matrixWorld, this.matrix );
 				this.matrixWorld.multiplyMatrices( this.parent.matrixWorld, this.matrix );
 
 
-				this.matrixWorld.decompose( translationWorld, quaternionWorld, scaleWorld );
-				this.matrix.decompose( translationObject, quaternionObject, scaleObject );
+				this.matrixWorld.decompose( _translationWorld, _quaternionWorld, _scaleWorld );
+				this.matrix.decompose( _translationObject, _quaternionObject, _scaleObject );
 
 
-				this.matrixWorld.compose( translationWorld, quaternionObject, scaleWorld );
+				this.matrixWorld.compose( _translationWorld, _quaternionObject, _scaleWorld );
 
 
 
 
 			} else {
 			} else {
@@ -56,14 +53,14 @@ Gyroscope.prototype.updateMatrixWorld = ( function () {
 
 
 		// update children
 		// update children
 
 
-		for ( var i = 0, l = this.children.length; i < l; i ++ ) {
+		for ( let i = 0, l = this.children.length; i < l; i ++ ) {
 
 
 			this.children[ i ].updateMatrixWorld( force );
 			this.children[ i ].updateMatrixWorld( force );
 
 
 		}
 		}
 
 
-	};
+	}
 
 
-}() );
+}
 
 
 export { Gyroscope };
 export { Gyroscope };

+ 99 - 95
examples/jsm/misc/MD2Character.js

@@ -10,37 +10,89 @@ import {
 } from '../../../build/three.module.js';
 } from '../../../build/three.module.js';
 import { MD2Loader } from '../loaders/MD2Loader.js';
 import { MD2Loader } from '../loaders/MD2Loader.js';
 
 
-var MD2Character = function () {
+class MD2Character {
 
 
-	var scope = this;
+	constructor() {
 
 
-	this.scale = 1;
-	this.animationFPS = 6;
+		this.scale = 1;
+		this.animationFPS = 6;
 
 
-	this.root = new Object3D();
+		this.root = new Object3D();
 
 
-	this.meshBody = null;
-	this.meshWeapon = null;
+		this.meshBody = null;
+		this.meshWeapon = null;
 
 
-	this.skinsBody = [];
-	this.skinsWeapon = [];
+		this.skinsBody = [];
+		this.skinsWeapon = [];
 
 
-	this.weapons = [];
+		this.weapons = [];
 
 
-	this.activeAnimation = null;
+		this.activeAnimation = null;
 
 
-	this.mixer = null;
+		this.mixer = null;
 
 
-	this.onLoadComplete = function () {};
+		this.onLoadComplete = function () {};
 
 
-	this.loadCounter = 0;
+		this.loadCounter = 0;
 
 
-	this.loadParts = function ( config ) {
+	}
+
+	loadParts( config ) {
+
+		const scope = this;
+
+		function createPart( geometry, skinMap ) {
+
+			const materialWireframe = new MeshLambertMaterial( { color: 0xffaa00, wireframe: true, morphTargets: true, morphNormals: true } );
+			const materialTexture = new MeshLambertMaterial( { color: 0xffffff, wireframe: false, map: skinMap, morphTargets: true, morphNormals: true } );
+
+			//
+
+			const 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 loadTextures( baseUrl, textureUrls ) {
+
+			const textureLoader = new TextureLoader();
+			const textures = [];
+
+			for ( let i = 0; i < textureUrls.length; i ++ ) {
+
+				textures[ i ] = textureLoader.load( baseUrl + textureUrls[ i ], checkLoadingComplete );
+				textures[ i ].mapping = UVMapping;
+				textures[ i ].name = textureUrls[ i ];
+				textures[ i ].encoding = sRGBEncoding;
+
+			}
+
+			return textures;
+
+		}
+
+		function checkLoadingComplete() {
+
+			scope.loadCounter -= 1;
+
+			if ( scope.loadCounter === 0 ) scope.onLoadComplete();
+
+		}
 
 
 		this.loadCounter = config.weapons.length * 2 + config.skins.length + 1;
 		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 ];
+		const weaponsTextures = [];
+		for ( let i = 0; i < config.weapons.length; i ++ ) weaponsTextures[ i ] = config.weapons[ i ][ 1 ];
 		// SKINS
 		// SKINS
 
 
 		this.skinsBody = loadTextures( config.baseUrl + 'skins/', config.skins );
 		this.skinsBody = loadTextures( config.baseUrl + 'skins/', config.skins );
@@ -48,16 +100,16 @@ var MD2Character = function () {
 
 
 		// BODY
 		// BODY
 
 
-		var loader = new MD2Loader();
+		const loader = new MD2Loader();
 
 
 		loader.load( config.baseUrl + config.body, function ( geo ) {
 		loader.load( config.baseUrl + config.body, function ( geo ) {
 
 
-			var boundingBox = new Box3();
+			const boundingBox = new Box3();
 			boundingBox.setFromBufferAttribute( geo.attributes.position );
 			boundingBox.setFromBufferAttribute( geo.attributes.position );
 
 
 			scope.root.position.y = - scope.scale * boundingBox.min.y;
 			scope.root.position.y = - scope.scale * boundingBox.min.y;
 
 
-			var mesh = createPart( geo, scope.skinsBody[ 0 ] );
+			const mesh = createPart( geo, scope.skinsBody[ 0 ] );
 			mesh.scale.set( scope.scale, scope.scale, scope.scale );
 			mesh.scale.set( scope.scale, scope.scale, scope.scale );
 
 
 			scope.root.add( mesh );
 			scope.root.add( mesh );
@@ -75,11 +127,11 @@ var MD2Character = function () {
 
 
 		// WEAPONS
 		// WEAPONS
 
 
-		var generateCallback = function ( index, name ) {
+		const generateCallback = function ( index, name ) {
 
 
 			return function ( geo ) {
 			return function ( geo ) {
 
 
-				var mesh = createPart( geo, scope.skinsWeapon[ index ] );
+				const mesh = createPart( geo, scope.skinsWeapon[ index ] );
 				mesh.scale.set( scope.scale, scope.scale, scope.scale );
 				mesh.scale.set( scope.scale, scope.scale, scope.scale );
 				mesh.visible = false;
 				mesh.visible = false;
 
 
@@ -96,15 +148,15 @@ var MD2Character = function () {
 
 
 		};
 		};
 
 
-		for ( var i = 0; i < config.weapons.length; i ++ ) {
+		for ( let i = 0; i < config.weapons.length; i ++ ) {
 
 
 			loader.load( config.baseUrl + config.weapons[ i ][ 0 ], generateCallback( i, config.weapons[ i ][ 0 ] ) );
 			loader.load( config.baseUrl + config.weapons[ i ][ 0 ], generateCallback( i, config.weapons[ i ][ 0 ] ) );
 
 
 		}
 		}
 
 
-	};
+	}
 
 
-	this.setPlaybackRate = function ( rate ) {
+	setPlaybackRate( rate ) {
 
 
 		if ( rate !== 0 ) {
 		if ( rate !== 0 ) {
 
 
@@ -116,9 +168,9 @@ var MD2Character = function () {
 
 
 		}
 		}
 
 
-	};
+	}
 
 
-	this.setWireframe = function ( wireframeEnabled ) {
+	setWireframe( wireframeEnabled ) {
 
 
 		if ( wireframeEnabled ) {
 		if ( wireframeEnabled ) {
 
 
@@ -132,9 +184,9 @@ var MD2Character = function () {
 
 
 		}
 		}
 
 
-	};
+	}
 
 
-	this.setSkin = function ( index ) {
+	setSkin( index ) {
 
 
 		if ( this.meshBody && this.meshBody.material.wireframe === false ) {
 		if ( this.meshBody && this.meshBody.material.wireframe === false ) {
 
 
@@ -142,26 +194,26 @@ var MD2Character = function () {
 
 
 		}
 		}
 
 
-	};
+	}
 
 
-	this.setWeapon = function ( index ) {
+	setWeapon( index ) {
 
 
-		for ( var i = 0; i < this.weapons.length; i ++ ) this.weapons[ i ].visible = false;
+		for ( let i = 0; i < this.weapons.length; i ++ ) this.weapons[ i ].visible = false;
 
 
-		var activeWeapon = this.weapons[ index ];
+		const activeWeapon = this.weapons[ index ];
 
 
 		if ( activeWeapon ) {
 		if ( activeWeapon ) {
 
 
 			activeWeapon.visible = true;
 			activeWeapon.visible = true;
 			this.meshWeapon = activeWeapon;
 			this.meshWeapon = activeWeapon;
 
 
-			scope.syncWeaponAnimation();
+			this.syncWeaponAnimation();
 
 
 		}
 		}
 
 
-	};
+	}
 
 
-	this.setAnimation = function ( clipName ) {
+	setAnimation( clipName ) {
 
 
 		if ( this.meshBody ) {
 		if ( this.meshBody ) {
 
 
@@ -172,7 +224,7 @@ var MD2Character = function () {
 
 
 			}
 			}
 
 
-			var action = this.mixer.clipAction( clipName, this.meshBody );
+			const action = this.mixer.clipAction( clipName, this.meshBody );
 
 
 			if ( action ) {
 			if ( action ) {
 
 
@@ -182,17 +234,17 @@ var MD2Character = function () {
 
 
 		}
 		}
 
 
-		scope.activeClipName = clipName;
+		this.activeClipName = clipName;
 
 
-		scope.syncWeaponAnimation();
+		this.syncWeaponAnimation();
 
 
-	};
+	}
 
 
-	this.syncWeaponAnimation = function () {
+	syncWeaponAnimation() {
 
 
-		var clipName = scope.activeClipName;
+		const clipName = this.activeClipName;
 
 
-		if ( scope.meshWeapon ) {
+		if ( this.meshWeapon ) {
 
 
 			if ( this.meshWeapon.activeAction ) {
 			if ( this.meshWeapon.activeAction ) {
 
 
@@ -201,7 +253,7 @@ var MD2Character = function () {
 
 
 			}
 			}
 
 
-			var action = this.mixer.clipAction( clipName, this.meshWeapon );
+			const action = this.mixer.clipAction( clipName, this.meshWeapon );
 
 
 			if ( action ) {
 			if ( action ) {
 
 
@@ -211,62 +263,14 @@ var MD2Character = function () {
 
 
 		}
 		}
 
 
-	};
-
-	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 ];
-			textures[ i ].encoding = sRGBEncoding;
-
-		}
-
-		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;
+	update( delta ) {
 
 
-		if ( scope.loadCounter === 0 ) scope.onLoadComplete();
+		if ( this.mixer ) this.mixer.update( delta );
 
 
 	}
 	}
 
 
-};
+}
 
 
 export { MD2Character };
 export { MD2Character };

+ 130 - 127
examples/jsm/misc/MD2CharacterComplex.js

@@ -10,97 +10,98 @@ import {
 import { MD2Loader } from '../loaders/MD2Loader.js';
 import { MD2Loader } from '../loaders/MD2Loader.js';
 import { MorphBlendMesh } from '../misc/MorphBlendMesh.js';
 import { MorphBlendMesh } from '../misc/MorphBlendMesh.js';
 
 
-var MD2CharacterComplex = function () {
+class MD2CharacterComplex {
 
 
-	var scope = this;
+	constructor() {
 
 
-	this.scale = 1;
+		this.scale = 1;
 
 
-	// animation parameters
+		// animation parameters
 
 
-	this.animationFPS = 6;
-	this.transitionFrames = 15;
+		this.animationFPS = 6;
+		this.transitionFrames = 15;
 
 
-	// movement model parameters
+		// movement model parameters
 
 
-	this.maxSpeed = 275;
-	this.maxReverseSpeed = - 275;
+		this.maxSpeed = 275;
+		this.maxReverseSpeed = - 275;
 
 
-	this.frontAcceleration = 600;
-	this.backAcceleration = 600;
+		this.frontAcceleration = 600;
+		this.backAcceleration = 600;
 
 
-	this.frontDecceleration = 600;
+		this.frontDecceleration = 600;
 
 
-	this.angularSpeed = 2.5;
+		this.angularSpeed = 2.5;
 
 
-	// rig
+		// rig
 
 
-	this.root = new Object3D();
+		this.root = new Object3D();
 
 
-	this.meshBody = null;
-	this.meshWeapon = null;
+		this.meshBody = null;
+		this.meshWeapon = null;
 
 
-	this.controls = null;
+		this.controls = null;
 
 
-	// skins
+		// skins
 
 
-	this.skinsBody = [];
-	this.skinsWeapon = [];
+		this.skinsBody = [];
+		this.skinsWeapon = [];
 
 
-	this.weapons = [];
+		this.weapons = [];
 
 
-	this.currentSkin = undefined;
+		this.currentSkin = undefined;
 
 
-	//
+		//
+
+		this.onLoadComplete = function () {};
 
 
-	this.onLoadComplete = function () {};
+		// internals
 
 
-	// internals
+		this.meshes = [];
+		this.animations = {};
 
 
-	this.meshes = [];
-	this.animations = {};
+		this.loadCounter = 0;
 
 
-	this.loadCounter = 0;
+		// internal movement control variables
 
 
-	// internal movement control variables
+		this.speed = 0;
+		this.bodyOrientation = 0;
 
 
-	this.speed = 0;
-	this.bodyOrientation = 0;
+		this.walkSpeed = this.maxSpeed;
+		this.crouchSpeed = this.maxSpeed * 0.5;
 
 
-	this.walkSpeed = this.maxSpeed;
-	this.crouchSpeed = this.maxSpeed * 0.5;
+		// internal animation parameters
 
 
-	// internal animation parameters
+		this.activeAnimation = null;
+		this.oldAnimation = null;
 
 
-	this.activeAnimation = null;
-	this.oldAnimation = null;
+		// API
 
 
-	// API
+	}
 
 
-	this.enableShadows = function ( enable ) {
+	enableShadows( enable ) {
 
 
-		for ( var i = 0; i < this.meshes.length; i ++ ) {
+		for ( let i = 0; i < this.meshes.length; i ++ ) {
 
 
 			this.meshes[ i ].castShadow = enable;
 			this.meshes[ i ].castShadow = enable;
 			this.meshes[ i ].receiveShadow = enable;
 			this.meshes[ i ].receiveShadow = enable;
 
 
 		}
 		}
 
 
-	};
+	}
 
 
-	this.setVisible = function ( enable ) {
+	setVisible( enable ) {
 
 
-		for ( var i = 0; i < this.meshes.length; i ++ ) {
+		for ( let i = 0; i < this.meshes.length; i ++ ) {
 
 
 			this.meshes[ i ].visible = enable;
 			this.meshes[ i ].visible = enable;
 			this.meshes[ i ].visible = enable;
 			this.meshes[ i ].visible = enable;
 
 
 		}
 		}
 
 
-	};
-
+	}
 
 
-	this.shareParts = function ( original ) {
+	shareParts( original ) {
 
 
 		this.animations = original.animations;
 		this.animations = original.animations;
 		this.walkSpeed = original.walkSpeed;
 		this.walkSpeed = original.walkSpeed;
@@ -111,7 +112,7 @@ var MD2CharacterComplex = function () {
 
 
 		// BODY
 		// BODY
 
 
-		var mesh = createPart( original.meshBody.geometry, this.skinsBody[ 0 ] );
+		const mesh = this._createPart( original.meshBody.geometry, this.skinsBody[ 0 ] );
 		mesh.scale.set( this.scale, this.scale, this.scale );
 		mesh.scale.set( this.scale, this.scale, this.scale );
 
 
 		this.root.position.y = original.root.position.y;
 		this.root.position.y = original.root.position.y;
@@ -123,9 +124,9 @@ var MD2CharacterComplex = function () {
 
 
 		// WEAPONS
 		// WEAPONS
 
 
-		for ( var i = 0; i < original.weapons.length; i ++ ) {
+		for ( let i = 0; i < original.weapons.length; i ++ ) {
 
 
-			var meshWeapon = createPart( original.weapons[ i ].geometry, this.skinsWeapon[ i ] );
+			const meshWeapon = this._createPart( original.weapons[ i ].geometry, this.skinsWeapon[ i ] );
 			meshWeapon.scale.set( this.scale, this.scale, this.scale );
 			meshWeapon.scale.set( this.scale, this.scale, this.scale );
 			meshWeapon.visible = false;
 			meshWeapon.visible = false;
 
 
@@ -140,9 +141,36 @@ var MD2CharacterComplex = function () {
 
 
 		}
 		}
 
 
-	};
+	}
+
+	loadParts( config ) {
+
+		const scope = this;
+
+		function loadTextures( baseUrl, textureUrls ) {
+
+			const textureLoader = new TextureLoader();
+			const textures = [];
+
+			for ( let i = 0; i < textureUrls.length; i ++ ) {
+
+				textures[ i ] = textureLoader.load( baseUrl + textureUrls[ i ], checkLoadingComplete );
+				textures[ i ].mapping = UVMapping;
+				textures[ i ].name = textureUrls[ i ];
+				textures[ i ].encoding = sRGBEncoding;
+
+			}
+
+			return textures;
+
+		}
+
+		function checkLoadingComplete() {
 
 
-	this.loadParts = function ( config ) {
+			scope.loadCounter -= 1;
+			if ( scope.loadCounter === 0 ) 	scope.onLoadComplete();
+
+		}
 
 
 		this.animations = config.animations;
 		this.animations = config.animations;
 		this.walkSpeed = config.walkSpeed;
 		this.walkSpeed = config.walkSpeed;
@@ -150,8 +178,8 @@ var MD2CharacterComplex = function () {
 
 
 		this.loadCounter = config.weapons.length * 2 + config.skins.length + 1;
 		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 ];
+		const weaponsTextures = [];
+		for ( let i = 0; i < config.weapons.length; i ++ ) weaponsTextures[ i ] = config.weapons[ i ][ 1 ];
 
 
 		// SKINS
 		// SKINS
 
 
@@ -160,16 +188,16 @@ var MD2CharacterComplex = function () {
 
 
 		// BODY
 		// BODY
 
 
-		var loader = new MD2Loader();
+		const loader = new MD2Loader();
 
 
 		loader.load( config.baseUrl + config.body, function ( geo ) {
 		loader.load( config.baseUrl + config.body, function ( geo ) {
 
 
-			var boundingBox = new Box3();
+			const boundingBox = new Box3();
 			boundingBox.setFromBufferAttribute( geo.attributes.position );
 			boundingBox.setFromBufferAttribute( geo.attributes.position );
 
 
 			scope.root.position.y = - scope.scale * boundingBox.min.y;
 			scope.root.position.y = - scope.scale * boundingBox.min.y;
 
 
-			var mesh = createPart( geo, scope.skinsBody[ 0 ] );
+			const mesh = scope._createPart( geo, scope.skinsBody[ 0 ] );
 			mesh.scale.set( scope.scale, scope.scale, scope.scale );
 			mesh.scale.set( scope.scale, scope.scale, scope.scale );
 
 
 			scope.root.add( mesh );
 			scope.root.add( mesh );
@@ -183,11 +211,11 @@ var MD2CharacterComplex = function () {
 
 
 		// WEAPONS
 		// WEAPONS
 
 
-		var generateCallback = function ( index, name ) {
+		const generateCallback = function ( index, name ) {
 
 
 			return function ( geo ) {
 			return function ( geo ) {
 
 
-				var mesh = createPart( geo, scope.skinsWeapon[ index ] );
+				const mesh = scope._createPart( geo, scope.skinsWeapon[ index ] );
 				mesh.scale.set( scope.scale, scope.scale, scope.scale );
 				mesh.scale.set( scope.scale, scope.scale, scope.scale );
 				mesh.visible = false;
 				mesh.visible = false;
 
 
@@ -205,22 +233,22 @@ var MD2CharacterComplex = function () {
 
 
 		};
 		};
 
 
-		for ( var i = 0; i < config.weapons.length; i ++ ) {
+		for ( let i = 0; i < config.weapons.length; i ++ ) {
 
 
 			loader.load( config.baseUrl + config.weapons[ i ][ 0 ], generateCallback( i, config.weapons[ i ][ 0 ] ) );
 			loader.load( config.baseUrl + config.weapons[ i ][ 0 ], generateCallback( i, config.weapons[ i ][ 0 ] ) );
 
 
 		}
 		}
 
 
-	};
+	}
 
 
-	this.setPlaybackRate = function ( rate ) {
+	setPlaybackRate( rate ) {
 
 
 		if ( this.meshBody ) this.meshBody.duration = this.meshBody.baseDuration / rate;
 		if ( this.meshBody ) this.meshBody.duration = this.meshBody.baseDuration / rate;
 		if ( this.meshWeapon ) this.meshWeapon.duration = this.meshWeapon.baseDuration / rate;
 		if ( this.meshWeapon ) this.meshWeapon.duration = this.meshWeapon.baseDuration / rate;
 
 
-	};
+	}
 
 
-	this.setWireframe = function ( wireframeEnabled ) {
+	setWireframe( wireframeEnabled ) {
 
 
 		if ( wireframeEnabled ) {
 		if ( wireframeEnabled ) {
 
 
@@ -234,9 +262,9 @@ var MD2CharacterComplex = function () {
 
 
 		}
 		}
 
 
-	};
+	}
 
 
-	this.setSkin = function ( index ) {
+	setSkin( index ) {
 
 
 		if ( this.meshBody && this.meshBody.material.wireframe === false ) {
 		if ( this.meshBody && this.meshBody.material.wireframe === false ) {
 
 
@@ -245,13 +273,13 @@ var MD2CharacterComplex = function () {
 
 
 		}
 		}
 
 
-	};
+	}
 
 
-	this.setWeapon = function ( index ) {
+	setWeapon( index ) {
 
 
-		for ( var i = 0; i < this.weapons.length; i ++ ) this.weapons[ i ].visible = false;
+		for ( let i = 0; i < this.weapons.length; i ++ ) this.weapons[ i ].visible = false;
 
 
-		var activeWeapon = this.weapons[ index ];
+		const activeWeapon = this.weapons[ index ];
 
 
 		if ( activeWeapon ) {
 		if ( activeWeapon ) {
 
 
@@ -267,9 +295,9 @@ var MD2CharacterComplex = function () {
 
 
 		}
 		}
 
 
-	};
+	}
 
 
-	this.setAnimation = function ( animationName ) {
+	setAnimation( animationName ) {
 
 
 		if ( animationName === this.activeAnimation || ! animationName ) return;
 		if ( animationName === this.activeAnimation || ! animationName ) return;
 
 
@@ -293,9 +321,9 @@ var MD2CharacterComplex = function () {
 		}
 		}
 
 
 
 
-	};
+	}
 
 
-	this.update = function ( delta ) {
+	update( delta ) {
 
 
 		if ( this.controls ) this.updateMovementModel( delta );
 		if ( this.controls ) this.updateMovementModel( delta );
 
 
@@ -306,11 +334,11 @@ var MD2CharacterComplex = function () {
 
 
 		}
 		}
 
 
-	};
+	}
 
 
-	this.updateAnimations = function ( delta ) {
+	updateAnimations( delta ) {
 
 
-		var mix = 1;
+		let mix = 1;
 
 
 		if ( this.blendCounter > 0 ) {
 		if ( this.blendCounter > 0 ) {
 
 
@@ -337,14 +365,14 @@ var MD2CharacterComplex = function () {
 
 
 		}
 		}
 
 
-	};
+	}
 
 
-	this.updateBehaviors = function () {
+	updateBehaviors() {
 
 
-		var controls = this.controls;
-		var animations = this.animations;
+		const controls = this.controls;
+		const animations = this.animations;
 
 
-		var moveAnimation, idleAnimation;
+		let moveAnimation, idleAnimation;
 
 
 		// crouch vs stand
 		// crouch vs stand
 
 
@@ -446,11 +474,17 @@ var MD2CharacterComplex = function () {
 
 
 		}
 		}
 
 
-	};
+	}
 
 
-	this.updateMovementModel = function ( delta ) {
+	updateMovementModel( delta ) {
 
 
-		var controls = this.controls;
+		function exponentialEaseOut( k ) {
+
+			return k === 1 ? 1 : - Math.pow( 2, - 10 * k ) + 1;
+
+		}
+
+		const controls = this.controls;
 
 
 		// speed based on controls
 		// speed based on controls
 
 
@@ -465,7 +499,7 @@ var MD2CharacterComplex = function () {
 		// orientation based on controls
 		// orientation based on controls
 		// (don't just stand while turning)
 		// (don't just stand while turning)
 
 
-		var dir = 1;
+		const dir = 1;
 
 
 		if ( controls.moveLeft ) {
 		if ( controls.moveLeft ) {
 
 
@@ -487,12 +521,12 @@ var MD2CharacterComplex = function () {
 
 
 			if ( this.speed > 0 ) {
 			if ( this.speed > 0 ) {
 
 
-				var k = exponentialEaseOut( this.speed / this.maxSpeed );
+				const k = exponentialEaseOut( this.speed / this.maxSpeed );
 				this.speed = MathUtils.clamp( this.speed - k * delta * this.frontDecceleration, 0, this.maxSpeed );
 				this.speed = MathUtils.clamp( this.speed - k * delta * this.frontDecceleration, 0, this.maxSpeed );
 
 
 			} else {
 			} else {
 
 
-				var k = exponentialEaseOut( this.speed / this.maxReverseSpeed );
+				const k = exponentialEaseOut( this.speed / this.maxReverseSpeed );
 				this.speed = MathUtils.clamp( this.speed + k * delta * this.backAcceleration, this.maxReverseSpeed, 0 );
 				this.speed = MathUtils.clamp( this.speed + k * delta * this.backAcceleration, this.maxReverseSpeed, 0 );
 
 
 			}
 			}
@@ -501,7 +535,7 @@ var MD2CharacterComplex = function () {
 
 
 		// displacement
 		// displacement
 
 
-		var forwardDelta = this.speed * delta;
+		const forwardDelta = this.speed * delta;
 
 
 		this.root.position.x += Math.sin( this.bodyOrientation ) * forwardDelta;
 		this.root.position.x += Math.sin( this.bodyOrientation ) * forwardDelta;
 		this.root.position.z += Math.cos( this.bodyOrientation ) * forwardDelta;
 		this.root.position.z += Math.cos( this.bodyOrientation ) * forwardDelta;
@@ -510,36 +544,18 @@ var MD2CharacterComplex = function () {
 
 
 		this.root.rotation.y = this.bodyOrientation;
 		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 ];
-			textures[ i ].encoding = sRGBEncoding;
-
-		}
-
-		return textures;
-
 	}
 	}
 
 
-	function createPart( geometry, skinMap ) {
+	// internal
 
 
-		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 } );
+	_createPart( geometry, skinMap ) {
+
+		const materialWireframe = new MeshLambertMaterial( { color: 0xffaa00, wireframe: true, morphTargets: true, morphNormals: true } );
+		const materialTexture = new MeshLambertMaterial( { color: 0xffffff, wireframe: false, map: skinMap, morphTargets: true, morphNormals: true } );
 
 
 		//
 		//
 
 
-		var mesh = new MorphBlendMesh( geometry, materialTexture );
+		const mesh = new MorphBlendMesh( geometry, materialTexture );
 		mesh.rotation.y = - Math.PI / 2;
 		mesh.rotation.y = - Math.PI / 2;
 
 
 		//
 		//
@@ -549,25 +565,12 @@ var MD2CharacterComplex = function () {
 
 
 		//
 		//
 
 
-		mesh.autoCreateAnimations( scope.animationFPS );
+		mesh.autoCreateAnimations( this.animationFPS );
 
 
 		return mesh;
 		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 };
 export { MD2CharacterComplex };

+ 36 - 35
examples/jsm/misc/MorphAnimMesh.js

@@ -4,71 +4,72 @@ import {
 	Mesh
 	Mesh
 } from '../../../build/three.module.js';
 } from '../../../build/three.module.js';
 
 
-var MorphAnimMesh = function ( geometry, material ) {
+class MorphAnimMesh extends Mesh {
 
 
-	Mesh.call( this, geometry, material );
+	constructor( geometry, material ) {
 
 
-	this.type = 'MorphAnimMesh';
+		super( geometry, material );
 
 
-	this.mixer = new AnimationMixer( this );
-	this.activeAction = null;
+		this.type = 'MorphAnimMesh';
 
 
-};
+		this.mixer = new AnimationMixer( this );
+		this.activeAction = null;
 
 
-MorphAnimMesh.prototype = Object.create( Mesh.prototype );
-MorphAnimMesh.prototype.constructor = MorphAnimMesh;
+	}
 
 
-MorphAnimMesh.prototype.setDirectionForward = function () {
+	setDirectionForward() {
 
 
-	this.mixer.timeScale = 1.0;
+		this.mixer.timeScale = 1.0;
 
 
-};
+	}
 
 
-MorphAnimMesh.prototype.setDirectionBackward = function () {
+	setDirectionBackward() {
 
 
-	this.mixer.timeScale = - 1.0;
+		this.mixer.timeScale = - 1.0;
 
 
-};
+	}
 
 
-MorphAnimMesh.prototype.playAnimation = function ( label, fps ) {
+	playAnimation( label, fps ) {
 
 
-	if ( this.activeAction ) {
+		if ( this.activeAction ) {
 
 
-		this.activeAction.stop();
-		this.activeAction = null;
+			this.activeAction.stop();
+			this.activeAction = null;
 
 
-	}
+		}
+
+		const clip = AnimationClip.findByName( this, label );
 
 
-	var clip = AnimationClip.findByName( this, label );
+		if ( clip ) {
 
 
-	if ( clip ) {
+			const action = this.mixer.clipAction( clip );
+			action.timeScale = ( clip.tracks.length * fps ) / clip.duration;
+			this.activeAction = action.play();
 
 
-		var action = this.mixer.clipAction( clip );
-		action.timeScale = ( clip.tracks.length * fps ) / clip.duration;
-		this.activeAction = action.play();
+		} else {
 
 
-	} else {
+			throw new Error( 'THREE.MorphAnimMesh: animations[' + label + '] undefined in .playAnimation()' );
 
 
-		throw new Error( 'THREE.MorphAnimMesh: animations[' + label + '] undefined in .playAnimation()' );
+		}
 
 
 	}
 	}
 
 
-};
+	updateAnimation( delta ) {
 
 
-MorphAnimMesh.prototype.updateAnimation = function ( delta ) {
+		this.mixer.update( delta );
 
 
-	this.mixer.update( delta );
+	}
 
 
-};
+	copy( source ) {
 
 
-MorphAnimMesh.prototype.copy = function ( source ) {
+		super.copy( source );
 
 
-	Mesh.prototype.copy.call( this, source );
+		this.mixer = new AnimationMixer( this );
 
 
-	this.mixer = new AnimationMixer( this );
+		return this;
 
 
-	return this;
+	}
 
 
-};
+}
 
 
 export { MorphAnimMesh };
 export { MorphAnimMesh };

+ 71 - 71
examples/jsm/misc/MorphBlendMesh.js

@@ -3,37 +3,35 @@ import {
 	Mesh
 	Mesh
 } from '../../../build/three.module.js';
 } from '../../../build/three.module.js';
 
 
-var MorphBlendMesh = function ( geometry, material ) {
+class MorphBlendMesh extends Mesh {
 
 
-	Mesh.call( this, geometry, material );
+	constructor( geometry, material ) {
 
 
-	this.animationsMap = {};
-	this.animationsList = [];
+		super( geometry, material );
 
 
-	// prepare default animation
-	// (all frames played together in 1 second)
+		this.animationsMap = {};
+		this.animationsList = [];
 
 
-	var numFrames = Object.keys( this.morphTargetDictionary ).length;
+		// prepare default animation
+		// (all frames played together in 1 second)
 
 
-	var name = '__default';
+		const numFrames = Object.keys( this.morphTargetDictionary ).length;
 
 
-	var startFrame = 0;
-	var endFrame = numFrames - 1;
+		const name = '__default';
 
 
-	var fps = numFrames / 1;
+		const startFrame = 0;
+		const endFrame = numFrames - 1;
 
 
-	this.createAnimation( name, startFrame, endFrame, fps );
-	this.setAnimationWeight( name, 1 );
+		const 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 ) {
+	createAnimation( name, start, end, fps ) {
 
 
-		var animation = {
+		const animation = {
 
 
 			start: start,
 			start: start,
 			end: end,
 			end: end,
@@ -60,27 +58,29 @@ MorphBlendMesh.prototype = Object.assign( Object.create( Mesh.prototype ), {
 		this.animationsMap[ name ] = animation;
 		this.animationsMap[ name ] = animation;
 		this.animationsList.push( animation );
 		this.animationsList.push( animation );
 
 
-	},
+	}
+
+	autoCreateAnimations( fps ) {
 
 
-	autoCreateAnimations: function ( fps ) {
+		const pattern = /([a-z]+)_?(\d+)/i;
 
 
-		var pattern = /([a-z]+)_?(\d+)/i;
+		let firstAnimation;
 
 
-		var firstAnimation, frameRanges = {};
+		const frameRanges = {};
 
 
-		var i = 0;
+		let i = 0;
 
 
-		for ( var key in this.morphTargetDictionary ) {
+		for ( const key in this.morphTargetDictionary ) {
 
 
-			var chunks = key.match( pattern );
+			const chunks = key.match( pattern );
 
 
 			if ( chunks && chunks.length > 1 ) {
 			if ( chunks && chunks.length > 1 ) {
 
 
-				var name = chunks[ 1 ];
+				const name = chunks[ 1 ];
 
 
 				if ( ! frameRanges[ name ] ) frameRanges[ name ] = { start: Infinity, end: - Infinity };
 				if ( ! frameRanges[ name ] ) frameRanges[ name ] = { start: Infinity, end: - Infinity };
 
 
-				var range = frameRanges[ name ];
+				const range = frameRanges[ name ];
 
 
 				if ( i < range.start ) range.start = i;
 				if ( i < range.start ) range.start = i;
 				if ( i > range.end ) range.end = i;
 				if ( i > range.end ) range.end = i;
@@ -93,20 +93,20 @@ MorphBlendMesh.prototype = Object.assign( Object.create( Mesh.prototype ), {
 
 
 		}
 		}
 
 
-		for ( var name in frameRanges ) {
+		for ( const name in frameRanges ) {
 
 
-			var range = frameRanges[ name ];
+			const range = frameRanges[ name ];
 			this.createAnimation( name, range.start, range.end, fps );
 			this.createAnimation( name, range.start, range.end, fps );
 
 
 		}
 		}
 
 
 		this.firstAnimation = firstAnimation;
 		this.firstAnimation = firstAnimation;
 
 
-	},
+	}
 
 
-	setAnimationDirectionForward: function ( name ) {
+	setAnimationDirectionForward( name ) {
 
 
-		var animation = this.animationsMap[ name ];
+		const animation = this.animationsMap[ name ];
 
 
 		if ( animation ) {
 		if ( animation ) {
 
 
@@ -115,11 +115,11 @@ MorphBlendMesh.prototype = Object.assign( Object.create( Mesh.prototype ), {
 
 
 		}
 		}
 
 
-	},
+	}
 
 
-	setAnimationDirectionBackward: function ( name ) {
+	setAnimationDirectionBackward( name ) {
 
 
-		var animation = this.animationsMap[ name ];
+		const animation = this.animationsMap[ name ];
 
 
 		if ( animation ) {
 		if ( animation ) {
 
 
@@ -128,11 +128,11 @@ MorphBlendMesh.prototype = Object.assign( Object.create( Mesh.prototype ), {
 
 
 		}
 		}
 
 
-	},
+	}
 
 
-	setAnimationFPS: function ( name, fps ) {
+	setAnimationFPS( name, fps ) {
 
 
-		var animation = this.animationsMap[ name ];
+		const animation = this.animationsMap[ name ];
 
 
 		if ( animation ) {
 		if ( animation ) {
 
 
@@ -141,11 +141,11 @@ MorphBlendMesh.prototype = Object.assign( Object.create( Mesh.prototype ), {
 
 
 		}
 		}
 
 
-	},
+	}
 
 
-	setAnimationDuration: function ( name, duration ) {
+	setAnimationDuration( name, duration ) {
 
 
-		var animation = this.animationsMap[ name ];
+		const animation = this.animationsMap[ name ];
 
 
 		if ( animation ) {
 		if ( animation ) {
 
 
@@ -154,11 +154,11 @@ MorphBlendMesh.prototype = Object.assign( Object.create( Mesh.prototype ), {
 
 
 		}
 		}
 
 
-	},
+	}
 
 
-	setAnimationWeight: function ( name, weight ) {
+	setAnimationWeight( name, weight ) {
 
 
-		var animation = this.animationsMap[ name ];
+		const animation = this.animationsMap[ name ];
 
 
 		if ( animation ) {
 		if ( animation ) {
 
 
@@ -166,11 +166,11 @@ MorphBlendMesh.prototype = Object.assign( Object.create( Mesh.prototype ), {
 
 
 		}
 		}
 
 
-	},
+	}
 
 
-	setAnimationTime: function ( name, time ) {
+	setAnimationTime( name, time ) {
 
 
-		var animation = this.animationsMap[ name ];
+		const animation = this.animationsMap[ name ];
 
 
 		if ( animation ) {
 		if ( animation ) {
 
 
@@ -178,13 +178,13 @@ MorphBlendMesh.prototype = Object.assign( Object.create( Mesh.prototype ), {
 
 
 		}
 		}
 
 
-	},
+	}
 
 
-	getAnimationTime: function ( name ) {
+	getAnimationTime( name ) {
 
 
-		var time = 0;
+		let time = 0;
 
 
-		var animation = this.animationsMap[ name ];
+		const animation = this.animationsMap[ name ];
 
 
 		if ( animation ) {
 		if ( animation ) {
 
 
@@ -194,13 +194,13 @@ MorphBlendMesh.prototype = Object.assign( Object.create( Mesh.prototype ), {
 
 
 		return time;
 		return time;
 
 
-	},
+	}
 
 
-	getAnimationDuration: function ( name ) {
+	getAnimationDuration( name ) {
 
 
-		var duration = - 1;
+		let duration = - 1;
 
 
-		var animation = this.animationsMap[ name ];
+		const animation = this.animationsMap[ name ];
 
 
 		if ( animation ) {
 		if ( animation ) {
 
 
@@ -210,11 +210,11 @@ MorphBlendMesh.prototype = Object.assign( Object.create( Mesh.prototype ), {
 
 
 		return duration;
 		return duration;
 
 
-	},
+	}
 
 
-	playAnimation: function ( name ) {
+	playAnimation( name ) {
 
 
-		var animation = this.animationsMap[ name ];
+		const animation = this.animationsMap[ name ];
 
 
 		if ( animation ) {
 		if ( animation ) {
 
 
@@ -227,11 +227,11 @@ MorphBlendMesh.prototype = Object.assign( Object.create( Mesh.prototype ), {
 
 
 		}
 		}
 
 
-	},
+	}
 
 
-	stopAnimation: function ( name ) {
+	stopAnimation( name ) {
 
 
-		var animation = this.animationsMap[ name ];
+		const animation = this.animationsMap[ name ];
 
 
 		if ( animation ) {
 		if ( animation ) {
 
 
@@ -239,17 +239,17 @@ MorphBlendMesh.prototype = Object.assign( Object.create( Mesh.prototype ), {
 
 
 		}
 		}
 
 
-	},
+	}
 
 
-	update: function ( delta ) {
+	update( delta ) {
 
 
-		for ( var i = 0, il = this.animationsList.length; i < il; i ++ ) {
+		for ( let i = 0, il = this.animationsList.length; i < il; i ++ ) {
 
 
-			var animation = this.animationsList[ i ];
+			const animation = this.animationsList[ i ];
 
 
 			if ( ! animation.active ) continue;
 			if ( ! animation.active ) continue;
 
 
-			var frameTime = animation.duration / animation.length;
+			const frameTime = animation.duration / animation.length;
 
 
 			animation.time += animation.direction * delta;
 			animation.time += animation.direction * delta;
 
 
@@ -283,8 +283,8 @@ MorphBlendMesh.prototype = Object.assign( Object.create( Mesh.prototype ), {
 
 
 			}
 			}
 
 
-			var keyframe = animation.start + MathUtils.clamp( Math.floor( animation.time / frameTime ), 0, animation.length - 1 );
-			var weight = animation.weight;
+			const keyframe = animation.start + MathUtils.clamp( Math.floor( animation.time / frameTime ), 0, animation.length - 1 );
+			const weight = animation.weight;
 
 
 			if ( keyframe !== animation.currentFrame ) {
 			if ( keyframe !== animation.currentFrame ) {
 
 
@@ -298,7 +298,7 @@ MorphBlendMesh.prototype = Object.assign( Object.create( Mesh.prototype ), {
 
 
 			}
 			}
 
 
-			var mix = ( animation.time % frameTime ) / frameTime;
+			let mix = ( animation.time % frameTime ) / frameTime;
 
 
 			if ( animation.directionBackwards ) mix = 1 - mix;
 			if ( animation.directionBackwards ) mix = 1 - mix;
 
 
@@ -317,6 +317,6 @@ MorphBlendMesh.prototype = Object.assign( Object.create( Mesh.prototype ), {
 
 
 	}
 	}
 
 
-} );
+}
 
 
 export { MorphBlendMesh };
 export { MorphBlendMesh };

+ 358 - 348
examples/jsm/misc/RollerCoaster.js

@@ -6,545 +6,555 @@ import {
 	Vector3
 	Vector3
 } from '../../../build/three.module.js';
 } from '../../../build/three.module.js';
 
 
-var RollerCoasterGeometry = function ( curve, divisions ) {
+class RollerCoasterGeometry extends BufferGeometry {
 
 
-	BufferGeometry.call( this );
+	constructor( curve, divisions ) {
 
 
-	var vertices = [];
-	var normals = [];
-	var colors = [];
+		super();
 
 
-	var color1 = [ 1, 1, 1 ];
-	var color2 = [ 1, 1, 0 ];
+		const vertices = [];
+		const normals = [];
+		const colors = [];
 
 
-	var up = new Vector3( 0, 1, 0 );
-	var forward = new Vector3();
-	var right = new Vector3();
+		const color1 = [ 1, 1, 1 ];
+		const color2 = [ 1, 1, 0 ];
 
 
-	var quaternion = new Quaternion();
-	var prevQuaternion = new Quaternion();
-	prevQuaternion.setFromAxisAngle( up, Math.PI / 2 );
+		const up = new Vector3( 0, 1, 0 );
+		const forward = new Vector3();
+		const right = new Vector3();
 
 
-	var point = new Vector3();
-	var prevPoint = new Vector3();
-	prevPoint.copy( curve.getPointAt( 0 ) );
+		const quaternion = new Quaternion();
+		const prevQuaternion = new Quaternion();
+		prevQuaternion.setFromAxisAngle( up, Math.PI / 2 );
 
 
-	// shapes
+		const point = new Vector3();
+		const prevPoint = new Vector3();
+		prevPoint.copy( curve.getPointAt( 0 ) );
 
 
-	var step = [
-		new Vector3( - 0.225, 0, 0 ),
-		new Vector3( 0, - 0.050, 0 ),
-		new Vector3( 0, - 0.175, 0 ),
+		// shapes
 
 
-		new Vector3( 0, - 0.050, 0 ),
-		new Vector3( 0.225, 0, 0 ),
-		new Vector3( 0, - 0.175, 0 )
-	];
+		const step = [
+			new Vector3( - 0.225, 0, 0 ),
+			new Vector3( 0, - 0.050, 0 ),
+			new Vector3( 0, - 0.175, 0 ),
 
 
-	var PI2 = Math.PI * 2;
+			new Vector3( 0, - 0.050, 0 ),
+			new Vector3( 0.225, 0, 0 ),
+			new Vector3( 0, - 0.175, 0 )
+		];
 
 
-	var sides = 5;
-	var tube1 = [];
+		const PI2 = Math.PI * 2;
 
 
-	for ( var i = 0; i < sides; i ++ ) {
+		let sides = 5;
+		const tube1 = [];
 
 
-		var angle = ( i / sides ) * PI2;
-		tube1.push( new Vector3( Math.sin( angle ) * 0.06, Math.cos( angle ) * 0.06, 0 ) );
+		for ( let i = 0; i < sides; i ++ ) {
 
 
-	}
+			const angle = ( i / sides ) * PI2;
+			tube1.push( new Vector3( Math.sin( angle ) * 0.06, Math.cos( angle ) * 0.06, 0 ) );
+
+		}
 
 
-	var sides = 6;
-	var tube2 = [];
+		sides = 6;
+		const tube2 = [];
 
 
-	for ( var i = 0; i < sides; i ++ ) {
+		for ( let i = 0; i < sides; i ++ ) {
 
 
-		var angle = ( i / sides ) * PI2;
-		tube2.push( new Vector3( Math.sin( angle ) * 0.025, Math.cos( angle ) * 0.025, 0 ) );
+			const angle = ( i / sides ) * PI2;
+			tube2.push( new Vector3( Math.sin( angle ) * 0.025, Math.cos( angle ) * 0.025, 0 ) );
 
 
-	}
+		}
 
 
-	var vector = new Vector3();
-	var normal = new Vector3();
+		const vector = new Vector3();
+		const normal = new Vector3();
 
 
-	function drawShape( shape, color ) {
+		function drawShape( shape, color ) {
 
 
-		normal.set( 0, 0, - 1 ).applyQuaternion( quaternion );
+			normal.set( 0, 0, - 1 ).applyQuaternion( quaternion );
 
 
-		for ( var j = 0; j < shape.length; j ++ ) {
+			for ( let j = 0; j < shape.length; j ++ ) {
 
 
-			vector.copy( shape[ j ] );
-			vector.applyQuaternion( quaternion );
-			vector.add( point );
+				vector.copy( shape[ j ] );
+				vector.applyQuaternion( quaternion );
+				vector.add( point );
 
 
-			vertices.push( vector.x, vector.y, vector.z );
-			normals.push( normal.x, normal.y, normal.z );
-			colors.push( color[ 0 ], color[ 1 ], color[ 2 ] );
+				vertices.push( vector.x, vector.y, vector.z );
+				normals.push( normal.x, normal.y, normal.z );
+				colors.push( color[ 0 ], color[ 1 ], color[ 2 ] );
 
 
-		}
+			}
 
 
-		normal.set( 0, 0, 1 ).applyQuaternion( quaternion );
+			normal.set( 0, 0, 1 ).applyQuaternion( quaternion );
 
 
-		for ( var j = shape.length - 1; j >= 0; j -- ) {
+			for ( let j = shape.length - 1; j >= 0; j -- ) {
 
 
-			vector.copy( shape[ j ] );
-			vector.applyQuaternion( quaternion );
-			vector.add( point );
+				vector.copy( shape[ j ] );
+				vector.applyQuaternion( quaternion );
+				vector.add( point );
 
 
-			vertices.push( vector.x, vector.y, vector.z );
-			normals.push( normal.x, normal.y, normal.z );
-			colors.push( color[ 0 ], color[ 1 ], color[ 2 ] );
+				vertices.push( vector.x, vector.y, vector.z );
+				normals.push( normal.x, normal.y, normal.z );
+				colors.push( color[ 0 ], color[ 1 ], color[ 2 ] );
+
+			}
 
 
 		}
 		}
 
 
-	}
+		const vector1 = new Vector3();
+		const vector2 = new Vector3();
+		const vector3 = new Vector3();
+		const vector4 = new Vector3();
 
 
-	var vector1 = new Vector3();
-	var vector2 = new Vector3();
-	var vector3 = new Vector3();
-	var vector4 = new Vector3();
+		const normal1 = new Vector3();
+		const normal2 = new Vector3();
+		const normal3 = new Vector3();
+		const normal4 = new Vector3();
 
 
-	var normal1 = new Vector3();
-	var normal2 = new Vector3();
-	var normal3 = new Vector3();
-	var normal4 = new Vector3();
+		function extrudeShape( shape, offset, color ) {
 
 
-	function extrudeShape( shape, offset, color ) {
+			for ( let j = 0, jl = shape.length; j < jl; j ++ ) {
 
 
-		for ( var j = 0, jl = shape.length; j < jl; j ++ ) {
+				const point1 = shape[ j ];
+				const point2 = shape[ ( j + 1 ) % jl ];
 
 
-			var point1 = shape[ j ];
-			var point2 = shape[ ( j + 1 ) % jl ];
+				vector1.copy( point1 ).add( offset );
+				vector1.applyQuaternion( quaternion );
+				vector1.add( point );
 
 
-			vector1.copy( point1 ).add( offset );
-			vector1.applyQuaternion( quaternion );
-			vector1.add( point );
+				vector2.copy( point2 ).add( offset );
+				vector2.applyQuaternion( quaternion );
+				vector2.add( point );
 
 
-			vector2.copy( point2 ).add( offset );
-			vector2.applyQuaternion( quaternion );
-			vector2.add( point );
+				vector3.copy( point2 ).add( offset );
+				vector3.applyQuaternion( prevQuaternion );
+				vector3.add( prevPoint );
 
 
-			vector3.copy( point2 ).add( offset );
-			vector3.applyQuaternion( prevQuaternion );
-			vector3.add( prevPoint );
+				vector4.copy( point1 ).add( offset );
+				vector4.applyQuaternion( prevQuaternion );
+				vector4.add( prevPoint );
 
 
-			vector4.copy( point1 ).add( offset );
-			vector4.applyQuaternion( prevQuaternion );
-			vector4.add( prevPoint );
+				vertices.push( vector1.x, vector1.y, vector1.z );
+				vertices.push( vector2.x, vector2.y, vector2.z );
+				vertices.push( vector4.x, vector4.y, vector4.z );
 
 
-			vertices.push( vector1.x, vector1.y, vector1.z );
-			vertices.push( vector2.x, vector2.y, vector2.z );
-			vertices.push( vector4.x, vector4.y, vector4.z );
+				vertices.push( vector2.x, vector2.y, vector2.z );
+				vertices.push( vector3.x, vector3.y, vector3.z );
+				vertices.push( vector4.x, vector4.y, vector4.z );
 
 
-			vertices.push( vector2.x, vector2.y, vector2.z );
-			vertices.push( vector3.x, vector3.y, vector3.z );
-			vertices.push( vector4.x, vector4.y, vector4.z );
+				//
 
 
-			//
+				normal1.copy( point1 );
+				normal1.applyQuaternion( quaternion );
+				normal1.normalize();
 
 
-			normal1.copy( point1 );
-			normal1.applyQuaternion( quaternion );
-			normal1.normalize();
+				normal2.copy( point2 );
+				normal2.applyQuaternion( quaternion );
+				normal2.normalize();
 
 
-			normal2.copy( point2 );
-			normal2.applyQuaternion( quaternion );
-			normal2.normalize();
+				normal3.copy( point2 );
+				normal3.applyQuaternion( prevQuaternion );
+				normal3.normalize();
 
 
-			normal3.copy( point2 );
-			normal3.applyQuaternion( prevQuaternion );
-			normal3.normalize();
+				normal4.copy( point1 );
+				normal4.applyQuaternion( prevQuaternion );
+				normal4.normalize();
 
 
-			normal4.copy( point1 );
-			normal4.applyQuaternion( prevQuaternion );
-			normal4.normalize();
+				normals.push( normal1.x, normal1.y, normal1.z );
+				normals.push( normal2.x, normal2.y, normal2.z );
+				normals.push( normal4.x, normal4.y, normal4.z );
 
 
-			normals.push( normal1.x, normal1.y, normal1.z );
-			normals.push( normal2.x, normal2.y, normal2.z );
-			normals.push( normal4.x, normal4.y, normal4.z );
+				normals.push( normal2.x, normal2.y, normal2.z );
+				normals.push( normal3.x, normal3.y, normal3.z );
+				normals.push( normal4.x, normal4.y, normal4.z );
 
 
-			normals.push( normal2.x, normal2.y, normal2.z );
-			normals.push( normal3.x, normal3.y, normal3.z );
-			normals.push( normal4.x, normal4.y, normal4.z );
+				colors.push( color[ 0 ], color[ 1 ], color[ 2 ] );
+				colors.push( color[ 0 ], color[ 1 ], color[ 2 ] );
+				colors.push( color[ 0 ], color[ 1 ], color[ 2 ] );
 
 
-			colors.push( color[ 0 ], color[ 1 ], color[ 2 ] );
-			colors.push( color[ 0 ], color[ 1 ], color[ 2 ] );
-			colors.push( color[ 0 ], color[ 1 ], color[ 2 ] );
+				colors.push( color[ 0 ], color[ 1 ], color[ 2 ] );
+				colors.push( color[ 0 ], color[ 1 ], color[ 2 ] );
+				colors.push( color[ 0 ], color[ 1 ], color[ 2 ] );
 
 
-			colors.push( color[ 0 ], color[ 1 ], color[ 2 ] );
-			colors.push( color[ 0 ], color[ 1 ], color[ 2 ] );
-			colors.push( color[ 0 ], color[ 1 ], color[ 2 ] );
+			}
 
 
 		}
 		}
 
 
-	}
+		const offset = new Vector3();
 
 
-	var offset = new Vector3();
+		for ( let i = 1; i <= divisions; i ++ ) {
 
 
-	for ( var i = 1; i <= divisions; i ++ ) {
+			point.copy( curve.getPointAt( i / divisions ) );
 
 
-		point.copy( curve.getPointAt( i / divisions ) );
+			up.set( 0, 1, 0 );
 
 
-		up.set( 0, 1, 0 );
+			forward.subVectors( point, prevPoint ).normalize();
+			right.crossVectors( up, forward ).normalize();
+			up.crossVectors( forward, right );
 
 
-		forward.subVectors( point, prevPoint ).normalize();
-		right.crossVectors( up, forward ).normalize();
-		up.crossVectors( forward, right );
+			const angle = Math.atan2( forward.x, forward.z );
 
 
-		var angle = Math.atan2( forward.x, forward.z );
+			quaternion.setFromAxisAngle( up, angle );
 
 
-		quaternion.setFromAxisAngle( up, angle );
+			if ( i % 2 === 0 ) {
 
 
-		if ( i % 2 === 0 ) {
+				drawShape( step, color2 );
 
 
-			drawShape( step, color2 );
+			}
+
+			extrudeShape( tube1, offset.set( 0, - 0.125, 0 ), color2 );
+			extrudeShape( tube2, offset.set( 0.2, 0, 0 ), color1 );
+			extrudeShape( tube2, offset.set( - 0.2, 0, 0 ), color1 );
+
+			prevPoint.copy( point );
+			prevQuaternion.copy( quaternion );
 
 
 		}
 		}
 
 
-		extrudeShape( tube1, offset.set( 0, - 0.125, 0 ), color2 );
-		extrudeShape( tube2, offset.set( 0.2, 0, 0 ), color1 );
-		extrudeShape( tube2, offset.set( - 0.2, 0, 0 ), color1 );
+		// console.log( vertices.length );
 
 
-		prevPoint.copy( point );
-		prevQuaternion.copy( quaternion );
+		this.setAttribute( 'position', new BufferAttribute( new Float32Array( vertices ), 3 ) );
+		this.setAttribute( 'normal', new BufferAttribute( new Float32Array( normals ), 3 ) );
+		this.setAttribute( 'color', new BufferAttribute( new Float32Array( colors ), 3 ) );
 
 
 	}
 	}
 
 
-	// console.log( vertices.length );
+}
 
 
-	this.setAttribute( 'position', new BufferAttribute( new Float32Array( vertices ), 3 ) );
-	this.setAttribute( 'normal', new BufferAttribute( new Float32Array( normals ), 3 ) );
-	this.setAttribute( 'color', new BufferAttribute( new Float32Array( colors ), 3 ) );
+class RollerCoasterLiftersGeometry extends BufferGeometry {
 
 
-};
+	constructor( curve, divisions ) {
 
 
-RollerCoasterGeometry.prototype = Object.create( BufferGeometry.prototype );
+		super();
 
 
-var RollerCoasterLiftersGeometry = function ( curve, divisions ) {
+		const vertices = [];
+		const normals = [];
 
 
-	BufferGeometry.call( this );
+		const quaternion = new Quaternion();
 
 
-	var vertices = [];
-	var normals = [];
+		const up = new Vector3( 0, 1, 0 );
 
 
-	var quaternion = new Quaternion();
+		const point = new Vector3();
+		const tangent = new Vector3();
 
 
-	var up = new Vector3( 0, 1, 0 );
+		// shapes
 
 
-	var point = new Vector3();
-	var tangent = new Vector3();
+		const tube1 = [
+			new Vector3( 0, 0.05, - 0.05 ),
+			new Vector3( 0, 0.05, 0.05 ),
+			new Vector3( 0, - 0.05, 0 )
+		];
 
 
-	// shapes
+		const tube2 = [
+			new Vector3( - 0.05, 0, 0.05 ),
+			new Vector3( - 0.05, 0, - 0.05 ),
+			new Vector3( 0.05, 0, 0 )
+		];
 
 
-	var tube1 = [
-		new Vector3( 0, 0.05, - 0.05 ),
-		new Vector3( 0, 0.05, 0.05 ),
-		new Vector3( 0, - 0.05, 0 )
-	];
+		const tube3 = [
+			new Vector3( 0.05, 0, - 0.05 ),
+			new Vector3( 0.05, 0, 0.05 ),
+			new Vector3( - 0.05, 0, 0 )
+		];
 
 
-	var tube2 = [
-		new Vector3( - 0.05, 0, 0.05 ),
-		new Vector3( - 0.05, 0, - 0.05 ),
-		new Vector3( 0.05, 0, 0 )
-	];
+		const vector1 = new Vector3();
+		const vector2 = new Vector3();
+		const vector3 = new Vector3();
+		const vector4 = new Vector3();
 
 
-	var tube3 = [
-		new Vector3( 0.05, 0, - 0.05 ),
-		new Vector3( 0.05, 0, 0.05 ),
-		new Vector3( - 0.05, 0, 0 )
-	];
+		const normal1 = new Vector3();
+		const normal2 = new Vector3();
+		const normal3 = new Vector3();
+		const normal4 = new Vector3();
 
 
-	var vector1 = new Vector3();
-	var vector2 = new Vector3();
-	var vector3 = new Vector3();
-	var vector4 = new Vector3();
+		function extrudeShape( shape, fromPoint, toPoint ) {
 
 
-	var normal1 = new Vector3();
-	var normal2 = new Vector3();
-	var normal3 = new Vector3();
-	var normal4 = new Vector3();
+			for ( let j = 0, jl = shape.length; j < jl; j ++ ) {
 
 
-	function extrudeShape( shape, fromPoint, toPoint ) {
+				const point1 = shape[ j ];
+				const point2 = shape[ ( j + 1 ) % jl ];
 
 
-		for ( var j = 0, jl = shape.length; j < jl; j ++ ) {
+				vector1.copy( point1 );
+				vector1.applyQuaternion( quaternion );
+				vector1.add( fromPoint );
 
 
-			var point1 = shape[ j ];
-			var point2 = shape[ ( j + 1 ) % jl ];
+				vector2.copy( point2 );
+				vector2.applyQuaternion( quaternion );
+				vector2.add( fromPoint );
 
 
-			vector1.copy( point1 );
-			vector1.applyQuaternion( quaternion );
-			vector1.add( fromPoint );
+				vector3.copy( point2 );
+				vector3.applyQuaternion( quaternion );
+				vector3.add( toPoint );
 
 
-			vector2.copy( point2 );
-			vector2.applyQuaternion( quaternion );
-			vector2.add( fromPoint );
+				vector4.copy( point1 );
+				vector4.applyQuaternion( quaternion );
+				vector4.add( toPoint );
 
 
-			vector3.copy( point2 );
-			vector3.applyQuaternion( quaternion );
-			vector3.add( toPoint );
+				vertices.push( vector1.x, vector1.y, vector1.z );
+				vertices.push( vector2.x, vector2.y, vector2.z );
+				vertices.push( vector4.x, vector4.y, vector4.z );
 
 
-			vector4.copy( point1 );
-			vector4.applyQuaternion( quaternion );
-			vector4.add( toPoint );
-
-			vertices.push( vector1.x, vector1.y, vector1.z );
-			vertices.push( vector2.x, vector2.y, vector2.z );
-			vertices.push( vector4.x, vector4.y, vector4.z );
+				vertices.push( vector2.x, vector2.y, vector2.z );
+				vertices.push( vector3.x, vector3.y, vector3.z );
+				vertices.push( vector4.x, vector4.y, vector4.z );
 
 
-			vertices.push( vector2.x, vector2.y, vector2.z );
-			vertices.push( vector3.x, vector3.y, vector3.z );
-			vertices.push( vector4.x, vector4.y, vector4.z );
+				//
 
 
-			//
+				normal1.copy( point1 );
+				normal1.applyQuaternion( quaternion );
+				normal1.normalize();
 
 
-			normal1.copy( point1 );
-			normal1.applyQuaternion( quaternion );
-			normal1.normalize();
+				normal2.copy( point2 );
+				normal2.applyQuaternion( quaternion );
+				normal2.normalize();
 
 
-			normal2.copy( point2 );
-			normal2.applyQuaternion( quaternion );
-			normal2.normalize();
+				normal3.copy( point2 );
+				normal3.applyQuaternion( quaternion );
+				normal3.normalize();
 
 
-			normal3.copy( point2 );
-			normal3.applyQuaternion( quaternion );
-			normal3.normalize();
+				normal4.copy( point1 );
+				normal4.applyQuaternion( quaternion );
+				normal4.normalize();
 
 
-			normal4.copy( point1 );
-			normal4.applyQuaternion( quaternion );
-			normal4.normalize();
+				normals.push( normal1.x, normal1.y, normal1.z );
+				normals.push( normal2.x, normal2.y, normal2.z );
+				normals.push( normal4.x, normal4.y, normal4.z );
 
 
-			normals.push( normal1.x, normal1.y, normal1.z );
-			normals.push( normal2.x, normal2.y, normal2.z );
-			normals.push( normal4.x, normal4.y, normal4.z );
+				normals.push( normal2.x, normal2.y, normal2.z );
+				normals.push( normal3.x, normal3.y, normal3.z );
+				normals.push( normal4.x, normal4.y, normal4.z );
 
 
-			normals.push( normal2.x, normal2.y, normal2.z );
-			normals.push( normal3.x, normal3.y, normal3.z );
-			normals.push( normal4.x, normal4.y, normal4.z );
+			}
 
 
 		}
 		}
 
 
-	}
+		const fromPoint = new Vector3();
+		const toPoint = new Vector3();
 
 
-	var fromPoint = new Vector3();
-	var toPoint = new Vector3();
+		for ( let i = 1; i <= divisions; i ++ ) {
 
 
-	for ( var i = 1; i <= divisions; i ++ ) {
+			point.copy( curve.getPointAt( i / divisions ) );
+			tangent.copy( curve.getTangentAt( i / divisions ) );
 
 
-		point.copy( curve.getPointAt( i / divisions ) );
-		tangent.copy( curve.getTangentAt( i / divisions ) );
+			const angle = Math.atan2( tangent.x, tangent.z );
 
 
-		var angle = Math.atan2( tangent.x, tangent.z );
+			quaternion.setFromAxisAngle( up, angle );
 
 
-		quaternion.setFromAxisAngle( up, angle );
+			//
 
 
-		//
+			if ( point.y > 10 ) {
 
 
-		if ( point.y > 10 ) {
+				fromPoint.set( - 0.75, - 0.35, 0 );
+				fromPoint.applyQuaternion( quaternion );
+				fromPoint.add( point );
 
 
-			fromPoint.set( - 0.75, - 0.35, 0 );
-			fromPoint.applyQuaternion( quaternion );
-			fromPoint.add( point );
+				toPoint.set( 0.75, - 0.35, 0 );
+				toPoint.applyQuaternion( quaternion );
+				toPoint.add( point );
 
 
-			toPoint.set( 0.75, - 0.35, 0 );
-			toPoint.applyQuaternion( quaternion );
-			toPoint.add( point );
+				extrudeShape( tube1, fromPoint, toPoint );
 
 
-			extrudeShape( tube1, fromPoint, toPoint );
+				fromPoint.set( - 0.7, - 0.3, 0 );
+				fromPoint.applyQuaternion( quaternion );
+				fromPoint.add( point );
 
 
-			fromPoint.set( - 0.7, - 0.3, 0 );
-			fromPoint.applyQuaternion( quaternion );
-			fromPoint.add( point );
+				toPoint.set( - 0.7, - point.y, 0 );
+				toPoint.applyQuaternion( quaternion );
+				toPoint.add( point );
 
 
-			toPoint.set( - 0.7, - point.y, 0 );
-			toPoint.applyQuaternion( quaternion );
-			toPoint.add( point );
+				extrudeShape( tube2, fromPoint, toPoint );
 
 
-			extrudeShape( tube2, fromPoint, toPoint );
+				fromPoint.set( 0.7, - 0.3, 0 );
+				fromPoint.applyQuaternion( quaternion );
+				fromPoint.add( point );
 
 
-			fromPoint.set( 0.7, - 0.3, 0 );
-			fromPoint.applyQuaternion( quaternion );
-			fromPoint.add( point );
+				toPoint.set( 0.7, - point.y, 0 );
+				toPoint.applyQuaternion( quaternion );
+				toPoint.add( point );
 
 
-			toPoint.set( 0.7, - point.y, 0 );
-			toPoint.applyQuaternion( quaternion );
-			toPoint.add( point );
+				extrudeShape( tube3, fromPoint, toPoint );
 
 
-			extrudeShape( tube3, fromPoint, toPoint );
+			} else {
 
 
-		} else {
+				fromPoint.set( 0, - 0.2, 0 );
+				fromPoint.applyQuaternion( quaternion );
+				fromPoint.add( point );
 
 
-			fromPoint.set( 0, - 0.2, 0 );
-			fromPoint.applyQuaternion( quaternion );
-			fromPoint.add( point );
+				toPoint.set( 0, - point.y, 0 );
+				toPoint.applyQuaternion( quaternion );
+				toPoint.add( point );
 
 
-			toPoint.set( 0, - point.y, 0 );
-			toPoint.applyQuaternion( quaternion );
-			toPoint.add( point );
+				extrudeShape( tube3, fromPoint, toPoint );
 
 
-			extrudeShape( tube3, fromPoint, toPoint );
+			}
 
 
 		}
 		}
 
 
+		this.setAttribute( 'position', new BufferAttribute( new Float32Array( vertices ), 3 ) );
+		this.setAttribute( 'normal', new BufferAttribute( new Float32Array( normals ), 3 ) );
+
 	}
 	}
 
 
-	this.setAttribute( 'position', new BufferAttribute( new Float32Array( vertices ), 3 ) );
-	this.setAttribute( 'normal', new BufferAttribute( new Float32Array( normals ), 3 ) );
+}
 
 
-};
+class RollerCoasterShadowGeometry extends BufferGeometry {
 
 
-RollerCoasterLiftersGeometry.prototype = Object.create( BufferGeometry.prototype );
+	constructor( curve, divisions ) {
 
 
-var RollerCoasterShadowGeometry = function ( curve, divisions ) {
+		super();
 
 
-	BufferGeometry.call( this );
+		const vertices = [];
 
 
-	var vertices = [];
+		const up = new Vector3( 0, 1, 0 );
+		const forward = new Vector3();
 
 
-	var up = new Vector3( 0, 1, 0 );
-	var forward = new Vector3();
+		const quaternion = new Quaternion();
+		const prevQuaternion = new Quaternion();
+		prevQuaternion.setFromAxisAngle( up, Math.PI / 2 );
 
 
-	var quaternion = new Quaternion();
-	var prevQuaternion = new Quaternion();
-	prevQuaternion.setFromAxisAngle( up, Math.PI / 2 );
+		const point = new Vector3();
 
 
-	var point = new Vector3();
+		const prevPoint = new Vector3();
+		prevPoint.copy( curve.getPointAt( 0 ) );
+		prevPoint.y = 0;
 
 
-	var prevPoint = new Vector3();
-	prevPoint.copy( curve.getPointAt( 0 ) );
-	prevPoint.y = 0;
+		const vector1 = new Vector3();
+		const vector2 = new Vector3();
+		const vector3 = new Vector3();
+		const vector4 = new Vector3();
 
 
-	var vector1 = new Vector3();
-	var vector2 = new Vector3();
-	var vector3 = new Vector3();
-	var vector4 = new Vector3();
+		for ( let i = 1; i <= divisions; i ++ ) {
 
 
-	for ( var i = 1; i <= divisions; i ++ ) {
+			point.copy( curve.getPointAt( i / divisions ) );
+			point.y = 0;
 
 
-		point.copy( curve.getPointAt( i / divisions ) );
-		point.y = 0;
+			forward.subVectors( point, prevPoint );
 
 
-		forward.subVectors( point, prevPoint );
+			const angle = Math.atan2( forward.x, forward.z );
 
 
-		var angle = Math.atan2( forward.x, forward.z );
+			quaternion.setFromAxisAngle( up, angle );
 
 
-		quaternion.setFromAxisAngle( up, angle );
+			vector1.set( - 0.3, 0, 0 );
+			vector1.applyQuaternion( quaternion );
+			vector1.add( point );
 
 
-		vector1.set( - 0.3, 0, 0 );
-		vector1.applyQuaternion( quaternion );
-		vector1.add( point );
+			vector2.set( 0.3, 0, 0 );
+			vector2.applyQuaternion( quaternion );
+			vector2.add( point );
 
 
-		vector2.set( 0.3, 0, 0 );
-		vector2.applyQuaternion( quaternion );
-		vector2.add( point );
+			vector3.set( 0.3, 0, 0 );
+			vector3.applyQuaternion( prevQuaternion );
+			vector3.add( prevPoint );
 
 
-		vector3.set( 0.3, 0, 0 );
-		vector3.applyQuaternion( prevQuaternion );
-		vector3.add( prevPoint );
+			vector4.set( - 0.3, 0, 0 );
+			vector4.applyQuaternion( prevQuaternion );
+			vector4.add( prevPoint );
 
 
-		vector4.set( - 0.3, 0, 0 );
-		vector4.applyQuaternion( prevQuaternion );
-		vector4.add( prevPoint );
+			vertices.push( vector1.x, vector1.y, vector1.z );
+			vertices.push( vector2.x, vector2.y, vector2.z );
+			vertices.push( vector4.x, vector4.y, vector4.z );
+
+			vertices.push( vector2.x, vector2.y, vector2.z );
+			vertices.push( vector3.x, vector3.y, vector3.z );
+			vertices.push( vector4.x, vector4.y, vector4.z );
 
 
-		vertices.push( vector1.x, vector1.y, vector1.z );
-		vertices.push( vector2.x, vector2.y, vector2.z );
-		vertices.push( vector4.x, vector4.y, vector4.z );
+			prevPoint.copy( point );
+			prevQuaternion.copy( quaternion );
 
 
-		vertices.push( vector2.x, vector2.y, vector2.z );
-		vertices.push( vector3.x, vector3.y, vector3.z );
-		vertices.push( vector4.x, vector4.y, vector4.z );
+		}
 
 
-		prevPoint.copy( point );
-		prevQuaternion.copy( quaternion );
+		this.setAttribute( 'position', new BufferAttribute( new Float32Array( vertices ), 3 ) );
 
 
 	}
 	}
 
 
-	this.setAttribute( 'position', new BufferAttribute( new Float32Array( vertices ), 3 ) );
+}
 
 
-};
+class SkyGeometry extends BufferGeometry {
 
 
-RollerCoasterShadowGeometry.prototype = Object.create( BufferGeometry.prototype );
+	constructor() {
 
 
-var SkyGeometry = function () {
+		super();
 
 
-	BufferGeometry.call( this );
+		const vertices = [];
 
 
-	var vertices = [];
+		for ( let i = 0; i < 100; i ++ ) {
 
 
-	for ( var i = 0; i < 100; i ++ ) {
+			const x = Math.random() * 800 - 400;
+			const y = Math.random() * 50 + 50;
+			const z = Math.random() * 800 - 400;
 
 
-		var x = Math.random() * 800 - 400;
-		var y = Math.random() * 50 + 50;
-		var z = Math.random() * 800 - 400;
+			const size = Math.random() * 40 + 20;
 
 
-		var size = Math.random() * 40 + 20;
+			vertices.push( x - size, y, z - size );
+			vertices.push( x + size, y, z - size );
+			vertices.push( x - size, y, z + size );
 
 
-		vertices.push( x - size, y, z - size );
-		vertices.push( x + size, y, z - size );
-		vertices.push( x - size, y, z + size );
+			vertices.push( x + size, y, z - size );
+			vertices.push( x + size, y, z + size );
+			vertices.push( x - size, y, z + size );
 
 
-		vertices.push( x + size, y, z - size );
-		vertices.push( x + size, y, z + size );
-		vertices.push( x - size, y, z + size );
+		}
 
 
-	}
 
 
+		this.setAttribute( 'position', new BufferAttribute( new Float32Array( vertices ), 3 ) );
 
 
-	this.setAttribute( 'position', new BufferAttribute( new Float32Array( vertices ), 3 ) );
+	}
 
 
-};
+}
 
 
-SkyGeometry.prototype = Object.create( BufferGeometry.prototype );
+class TreesGeometry extends BufferGeometry {
 
 
-var TreesGeometry = function ( landscape ) {
+	constructor( landscape ) {
 
 
-	BufferGeometry.call( this );
+		super();
 
 
-	var vertices = [];
-	var colors = [];
+		const vertices = [];
+		const colors = [];
 
 
-	var raycaster = new Raycaster();
-	raycaster.ray.direction.set( 0, - 1, 0 );
+		const raycaster = new Raycaster();
+		raycaster.ray.direction.set( 0, - 1, 0 );
 
 
-	for ( var i = 0; i < 2000; i ++ ) {
+		for ( let i = 0; i < 2000; i ++ ) {
 
 
-		var x = Math.random() * 500 - 250;
-		var z = Math.random() * 500 - 250;
+			const x = Math.random() * 500 - 250;
+			const z = Math.random() * 500 - 250;
 
 
-		raycaster.ray.origin.set( x, 50, z );
+			raycaster.ray.origin.set( x, 50, z );
 
 
-		var intersections = raycaster.intersectObject( landscape );
+			const intersections = raycaster.intersectObject( landscape );
 
 
-		if ( intersections.length === 0 ) continue;
+			if ( intersections.length === 0 ) continue;
 
 
-		var y = intersections[ 0 ].point.y;
+			const y = intersections[ 0 ].point.y;
 
 
-		var height = Math.random() * 5 + 0.5;
+			const height = Math.random() * 5 + 0.5;
 
 
-		var angle = Math.random() * Math.PI * 2;
+			let angle = Math.random() * Math.PI * 2;
 
 
-		vertices.push( x + Math.sin( angle ), y, z + Math.cos( angle ) );
-		vertices.push( x, y + height, z );
-		vertices.push( x + Math.sin( angle + Math.PI ), y, z + Math.cos( angle + Math.PI ) );
+			vertices.push( x + Math.sin( angle ), y, z + Math.cos( angle ) );
+			vertices.push( x, y + height, z );
+			vertices.push( x + Math.sin( angle + Math.PI ), y, z + Math.cos( angle + Math.PI ) );
 
 
-		angle += Math.PI / 2;
+			angle += Math.PI / 2;
 
 
-		vertices.push( x + Math.sin( angle ), y, z + Math.cos( angle ) );
-		vertices.push( x, y + height, z );
-		vertices.push( x + Math.sin( angle + Math.PI ), y, z + Math.cos( angle + Math.PI ) );
+			vertices.push( x + Math.sin( angle ), y, z + Math.cos( angle ) );
+			vertices.push( x, y + height, z );
+			vertices.push( x + Math.sin( angle + Math.PI ), y, z + Math.cos( angle + Math.PI ) );
 
 
-		var random = Math.random() * 0.1;
+			const random = Math.random() * 0.1;
 
 
-		for ( var j = 0; j < 6; j ++ ) {
+			for ( let j = 0; j < 6; j ++ ) {
 
 
-			colors.push( 0.2 + random, 0.4 + random, 0 );
+				colors.push( 0.2 + random, 0.4 + random, 0 );
 
 
-		}
+			}
 
 
-	}
+		}
 
 
-	this.setAttribute( 'position', new BufferAttribute( new Float32Array( vertices ), 3 ) );
-	this.setAttribute( 'color', new BufferAttribute( new Float32Array( colors ), 3 ) );
+		this.setAttribute( 'position', new BufferAttribute( new Float32Array( vertices ), 3 ) );
+		this.setAttribute( 'color', new BufferAttribute( new Float32Array( colors ), 3 ) );
 
 
-};
+	}
 
 
-TreesGeometry.prototype = Object.create( BufferGeometry.prototype );
+}
 
 
 export { RollerCoasterGeometry, RollerCoasterLiftersGeometry, RollerCoasterShadowGeometry, SkyGeometry, TreesGeometry };
 export { RollerCoasterGeometry, RollerCoasterLiftersGeometry, RollerCoasterShadowGeometry, SkyGeometry, TreesGeometry };

+ 0 - 1
examples/webgl_loader_md2_control.html

@@ -145,7 +145,6 @@
 
 
 				cameraControls = new OrbitControls( camera, renderer.domElement );
 				cameraControls = new OrbitControls( camera, renderer.domElement );
 				cameraControls.target.set( 0, 50, 0 );
 				cameraControls.target.set( 0, 50, 0 );
-				cameraControls.enableKeys = false;
 				cameraControls.update();
 				cameraControls.update();
 
 
 				// CHARACTER
 				// CHARACTER