浏览代码

Build unit tests

Tristan VALCKE 7 年之前
父节点
当前提交
59111f17c3
共有 2 个文件被更改,包括 448 次插入180 次删除
  1. 50 57
      test/unit/three.editor.unit.js
  2. 398 123
      test/unit/three.source.unit.js

+ 50 - 57
test/unit/three.editor.unit.js

@@ -1167,7 +1167,7 @@
 		option.setTextContent( 'Plane' );
 		option.onClick( function () {
 
-			var geometry = new THREE.PlaneBufferGeometry( 2, 2 );
+			var geometry = new THREE.PlaneBufferGeometry( 1, 1, 1, 1 );
 			var material = new THREE.MeshStandardMaterial();
 			var mesh = new THREE.Mesh( geometry, material );
 			mesh.name = 'Plane ' + ( ++ meshCount );
@@ -1184,7 +1184,7 @@
 		option.setTextContent( 'Box' );
 		option.onClick( function () {
 
-			var geometry = new THREE.BoxBufferGeometry( 1, 1, 1 );
+			var geometry = new THREE.BoxBufferGeometry( 1, 1, 1, 1, 1, 1 );
 			var mesh = new THREE.Mesh( geometry, new THREE.MeshStandardMaterial() );
 			mesh.name = 'Box ' + ( ++ meshCount );
 
@@ -1200,10 +1200,7 @@
 		option.setTextContent( 'Circle' );
 		option.onClick( function () {
 
-			var radius = 1;
-			var segments = 32;
-
-			var geometry = new THREE.CircleBufferGeometry( radius, segments );
+			var geometry = new THREE.CircleBufferGeometry( 1, 8, 0, Math.PI * 2 );
 			var mesh = new THREE.Mesh( geometry, new THREE.MeshStandardMaterial() );
 			mesh.name = 'Circle ' + ( ++ meshCount );
 
@@ -1219,14 +1216,7 @@
 		option.setTextContent( 'Cylinder' );
 		option.onClick( function () {
 
-			var radiusTop = 1;
-			var radiusBottom = 1;
-			var height = 2;
-			var radiusSegments = 32;
-			var heightSegments = 1;
-			var openEnded = false;
-
-			var geometry = new THREE.CylinderBufferGeometry( radiusTop, radiusBottom, height, radiusSegments, heightSegments, openEnded );
+			var geometry = new THREE.CylinderBufferGeometry( 1, 1, 1, 8, 1, false, 0, Math.PI * 2 );
 			var mesh = new THREE.Mesh( geometry, new THREE.MeshStandardMaterial() );
 			mesh.name = 'Cylinder ' + ( ++ meshCount );
 
@@ -1242,15 +1232,7 @@
 		option.setTextContent( 'Sphere' );
 		option.onClick( function () {
 
-			var radius = 1;
-			var widthSegments = 32;
-			var heightSegments = 16;
-			var phiStart = 0;
-			var phiLength = Math.PI * 2;
-			var thetaStart = 0;
-			var thetaLength = Math.PI;
-
-			var geometry = new THREE.SphereBufferGeometry( radius, widthSegments, heightSegments, phiStart, phiLength, thetaStart, thetaLength );
+			var geometry = new THREE.SphereBufferGeometry( 1, 8, 6, 0, Math.PI * 2, 0, Math.PI );
 			var mesh = new THREE.Mesh( geometry, new THREE.MeshStandardMaterial() );
 			mesh.name = 'Sphere ' + ( ++ meshCount );
 
@@ -1266,10 +1248,7 @@
 		option.setTextContent( 'Icosahedron' );
 		option.onClick( function () {
 
-			var radius = 1;
-			var detail = 2;
-
-			var geometry = new THREE.IcosahedronGeometry( radius, detail );
+			var geometry = new THREE.IcosahedronGeometry( 1, 0 );
 			var mesh = new THREE.Mesh( geometry, new THREE.MeshStandardMaterial() );
 			mesh.name = 'Icosahedron ' + ( ++ meshCount );
 
@@ -1285,13 +1264,7 @@
 		option.setTextContent( 'Torus' );
 		option.onClick( function () {
 
-			var radius = 2;
-			var tube = 1;
-			var radialSegments = 32;
-			var tubularSegments = 12;
-			var arc = Math.PI * 2;
-
-			var geometry = new THREE.TorusBufferGeometry( radius, tube, radialSegments, tubularSegments, arc );
+			var geometry = new THREE.TorusBufferGeometry( 1, 0.4, 8, 6, Math.PI * 2 );
 			var mesh = new THREE.Mesh( geometry, new THREE.MeshStandardMaterial() );
 			mesh.name = 'Torus ' + ( ++ meshCount );
 
@@ -1307,14 +1280,7 @@
 		option.setTextContent( 'TorusKnot' );
 		option.onClick( function () {
 
-			var radius = 2;
-			var tube = 0.8;
-			var tubularSegments = 64;
-			var radialSegments = 12;
-			var p = 2;
-			var q = 3;
-
-			var geometry = new THREE.TorusKnotBufferGeometry( radius, tube, tubularSegments, radialSegments, p, q );
+			var geometry = new THREE.TorusKnotBufferGeometry( 1, 0.4, 64, 8, 2, 3 );
 			var mesh = new THREE.Mesh( geometry, new THREE.MeshStandardMaterial() );
 			mesh.name = 'TorusKnot ' + ( ++ meshCount );
 
@@ -1361,22 +1327,19 @@
 
 			var points = [
 				new THREE.Vector2( 0, 0 ),
-				new THREE.Vector2( 4, 0 ),
-				new THREE.Vector2( 3.5, 0.5 ),
-				new THREE.Vector2( 1, 0.75 ),
-				new THREE.Vector2( 0.8, 1 ),
-				new THREE.Vector2( 0.8, 4 ),
-				new THREE.Vector2( 1, 4.2 ),
-				new THREE.Vector2( 1.4, 4.8 ),
-				new THREE.Vector2( 2, 5 ),
-				new THREE.Vector2( 2.5, 5.4 ),
-				new THREE.Vector2( 3, 12 )
+				new THREE.Vector2( 0.4, 0 ),
+				new THREE.Vector2( 0.35, 0.05 ),
+				new THREE.Vector2( 0.1, 0.075 ),
+				new THREE.Vector2( 0.08, 0.1 ),
+				new THREE.Vector2( 0.08, 0.4 ),
+				new THREE.Vector2( 0.1, 0.42 ),
+				new THREE.Vector2( 0.14, 0.48 ),
+				new THREE.Vector2( 0.2, 0.5 ),
+				new THREE.Vector2( 0.25, 0.54 ),
+				new THREE.Vector2( 0.3, 1.2 )
 			];
-			var segments = 20;
-			var phiStart = 0;
-			var phiLength = 2 * Math.PI;
 
-			var geometry = new THREE.LatheBufferGeometry( points, segments, phiStart, phiLength );
+			var geometry = new THREE.LatheBufferGeometry( points, 12, 0, Math.PI * 2 );
 			var mesh = new THREE.Mesh( geometry, new THREE.MeshStandardMaterial( { side: THREE.DoubleSide } ) );
 			mesh.name = 'Lathe ' + ( ++ meshCount );
 
@@ -2142,6 +2105,23 @@
 
 				content = content.replace( '<!-- includes -->', includes.join( '\n\t\t' ) );
 
+				var editButton = '';
+
+				if ( editor.config.getKey( 'project/editable' ) ) {
+
+					editButton = `
+			var button = document.createElement( 'a' );
+			button.href = 'https://threejs.org/editor/#file=' + location.href.split( '/' ).slice( 0, - 1 ).join( '/' ) + '/app.json';
+			button.style.cssText = 'position: absolute; bottom: 20px; right: 20px; padding: 7px 10px 6px 10px; color: #fff; border: 1px solid #fff; text-decoration: none;';
+			button.target = '_blank';
+			button.textContent = 'EDIT';
+			document.body.appendChild( button );
+				`;
+
+				}
+
+				content = content.replace( '/* edit button */', editButton );
+
 				zip.file( 'index.html', content );
 
 			} );
@@ -6381,13 +6361,26 @@
 
 		container.add( rendererPropertiesRow );
 
+		// Editable
+
+		var editableRow = new UI.Row();
+		var editable = new UI.Checkbox( config.getKey( 'project/editable' ) ).setLeft( '100px' ).onChange( function () {
+
+			config.setKey( 'project/editable', this.getValue() );
+
+		} );
+
+		editableRow.add( new UI.Text( 'Editable' ).setWidth( '90px' ) );
+		editableRow.add( editable );
+
+		container.add( editableRow );
+
 		// VR
 
 		var vrRow = new UI.Row();
 		var vr = new UI.Checkbox( config.getKey( 'project/vr' ) ).setLeft( '100px' ).onChange( function () {
 
 			config.setKey( 'project/vr', this.getValue() );
-			// updateRenderer();
 
 		} );
 

+ 398 - 123
test/unit/three.source.unit.js

@@ -4,8 +4,6 @@
 	(factory());
 }(this, (function () { 'use strict';
 
-	console.log("TADA");
-
 	QUnit.module( "Source", () => {
 
 	var REVISION = '88dev';
@@ -384,35 +382,37 @@
 		generateUUID: function () {
 
 			// http://www.broofa.com/Tools/Math.uuid.htm
+			// Replaced .join with string concatenation (@takahirox)
 
 			var chars = '0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz'.split( '' );
-			var uuid = new Array( 36 );
 			var rnd = 0, r;
 
 			return function generateUUID() {
 
+				var uuid = '';
+
 				for ( var i = 0; i < 36; i ++ ) {
 
 					if ( i === 8 || i === 13 || i === 18 || i === 23 ) {
 
-						uuid[ i ] = '-';
+						uuid += '-';
 
 					} else if ( i === 14 ) {
 
-						uuid[ i ] = '4';
+						uuid += '4';
 
 					} else {
 
 						if ( rnd <= 0x02 ) rnd = 0x2000000 + ( Math.random() * 0x1000000 ) | 0;
 						r = rnd & 0xf;
 						rnd = rnd >> 4;
-						uuid[ i ] = chars[ ( i === 19 ) ? ( r & 0x3 ) | 0x8 : r ];
+						uuid += chars[ ( i === 19 ) ? ( r & 0x3 ) | 0x8 : r ];
 
 					}
 
 				}
 
-				return uuid.join( '' );
+				return uuid;
 
 			};
 
@@ -2594,13 +2594,7 @@
 
 			}
 
-			var x = this.x, y = this.y, z = this.z;
-
-			this.x = y * v.z - z * v.y;
-			this.y = z * v.x - x * v.z;
-			this.z = x * v.y - y * v.x;
-
-			return this;
+			return this.crossVectors( this, v );
 
 		},
 
@@ -8883,23 +8877,23 @@
 		}(),
 
 		rotateOnWorldAxis: function () {
-			
+
 			// rotate object on axis in world space
 			// axis is assumed to be normalized
 			// method assumes no rotated parent
 
 			var q1 = new Quaternion();
-			
+
 			return function rotateOnWorldAxis( axis, angle ) {
-			
+
 				q1.setFromAxisAngle( axis, angle );
-			
+
 				this.quaternion.premultiply( q1 );
-			
+
 				return this;
-			
+
 			};
-			
+
 		}(),
 
 		rotateX: function () {
@@ -12469,6 +12463,21 @@
 
 		},
 
+		setFromPoints: function ( points ) {
+
+			this.vertices = [];
+
+			for ( var i = 0, l = points.length; i < l; i ++ ) {
+
+				var point = points[ i ];
+				this.vertices.push( new Vector3( point.x, point.y, point.z || 0 ) );
+
+			}
+
+			return this;
+
+		},
+
 		sortFacesByMaterialIndex: function () {
 
 			var faces = this.faces;
@@ -14556,6 +14565,23 @@
 
 		},
 
+		setFromPoints: function ( points ) {
+
+			var position = [];
+
+			for ( var i = 0, l = points.length; i < l; i ++ ) {
+
+				var point = points[ i ];
+				position.push( point.x, point.y, point.z || 0 );
+
+			}
+
+			this.addAttribute( 'position', new Float32BufferAttribute( position, 3 ) );
+
+			return this;
+
+		},
+
 		updateFromObject: function ( object ) {
 
 			var geometry = object.geometry;
@@ -20902,7 +20928,10 @@
 
 		var scope = this;
 
-		var isLoading = false, itemsLoaded = 0, itemsTotal = 0;
+		var isLoading = false;
+		var itemsLoaded = 0;
+		var itemsTotal = 0;
+		var urlModifier = undefined;
 
 		this.onStart = undefined;
 		this.onLoad = onLoad;
@@ -20961,6 +20990,24 @@
 
 		};
 
+		this.resolveURL = function ( url ) {
+
+			if ( urlModifier ) {
+
+				return urlModifier( url );
+
+			}
+
+			return url;
+
+		};
+
+		this.setURLModifier = function ( transform ) {
+
+			urlModifier = transform;
+
+		};
+
 	}
 
 	var DefaultLoadingManager = new LoadingManager();
@@ -20969,6 +21016,8 @@
 	 * @author mrdoob / http://mrdoob.com/
 	 */
 
+	var loading = {};
+
 	function FileLoader( manager ) {
 
 		this.manager = ( manager !== undefined ) ? manager : DefaultLoadingManager;
@@ -20983,6 +21032,8 @@
 
 			if ( this.path !== undefined ) url = this.path + url;
 
+			url = this.manager.resolveURL( url );
+
 			var scope = this;
 
 			var cached = Cache.get( url );
@@ -21003,6 +21054,22 @@
 
 			}
 
+			// Check if request is duplicate
+
+			if ( loading[ url ] !== undefined ) {
+
+				loading[ url ].push( {
+
+					onLoad: onLoad,
+					onProgress: onProgress,
+					onError: onError
+
+				} );
+
+				return;
+
+			}
+
 			// Check for data: URI
 			var dataUriRegex = /^data:(.*?)(;base64)?,(.*)$/;
 			var dataUriRegexResult = url.match( dataUriRegex );
@@ -21094,7 +21161,20 @@
 
 			} else {
 
+				// Initialise array for duplicate requests
+
+				loading[ url ] = [];
+
+				loading[ url ].push( {
+
+					onLoad: onLoad,
+					onProgress: onProgress,
+					onError: onError
+
+				} );
+
 				var request = new XMLHttpRequest();
+
 				request.open( 'GET', url, true );
 
 				request.addEventListener( 'load', function ( event ) {
@@ -21103,9 +21183,18 @@
 
 					Cache.add( url, response );
 
+					var callbacks = loading[ url ];
+
+					delete loading[ url ];
+
 					if ( this.status === 200 ) {
 
-						if ( onLoad ) onLoad( response );
+						for ( var i = 0, il = callbacks.length; i < il; i ++ ) {
+
+							var callback = callbacks[ i ];
+							if ( callback.onLoad ) callback.onLoad( response );
+
+						}
 
 						scope.manager.itemEnd( url );
 
@@ -21116,13 +21205,23 @@
 
 						console.warn( 'THREE.FileLoader: HTTP Status 0 received.' );
 
-						if ( onLoad ) onLoad( response );
+						for ( var i = 0, il = callbacks.length; i < il; i ++ ) {
+
+							var callback = callbacks[ i ];
+							if ( callback.onLoad ) callback.onLoad( response );
+
+						}
 
 						scope.manager.itemEnd( url );
 
 					} else {
 
-						if ( onError ) onError( event );
+						for ( var i = 0, il = callbacks.length; i < il; i ++ ) {
+
+							var callback = callbacks[ i ];
+							if ( callback.onError ) callback.onError( event );
+
+						}
 
 						scope.manager.itemEnd( url );
 						scope.manager.itemError( url );
@@ -21131,19 +21230,31 @@
 
 				}, false );
 
-				if ( onProgress !== undefined ) {
+				request.addEventListener( 'progress', function ( event ) {
 
-					request.addEventListener( 'progress', function ( event ) {
+					var callbacks = loading[ url ];
 
-						onProgress( event );
+					for ( var i = 0, il = callbacks.length; i < il; i ++ ) {
 
-					}, false );
+						var callback = callbacks[ i ];
+						if ( callback.onProgress ) callback.onProgress( event );
 
-				}
+					}
+
+				}, false );
 
 				request.addEventListener( 'error', function ( event ) {
 
-					if ( onError ) onError( event );
+					var callbacks = loading[ url ];
+
+					delete loading[ url ];
+
+					for ( var i = 0, il = callbacks.length; i < il; i ++ ) {
+
+						var callback = callbacks[ i ];
+						if ( callback.onError ) callback.onError( event );
+
+					}
 
 					scope.manager.itemEnd( url );
 					scope.manager.itemError( url );
@@ -22629,6 +22740,8 @@
 
 			if ( this.path !== undefined ) url = this.path + url;
 
+			url = this.manager.resolveURL( url );
+
 			var scope = this;
 
 			var cached = Cache.get( url );
@@ -28010,7 +28123,7 @@
 			thetaLength: thetaLength
 		};
 
-		radius = radius || 50;
+		radius = radius || 1;
 
 		widthSegments = Math.max( 3, Math.floor( widthSegments ) || 8 );
 		heightSegments = Math.max( 2, Math.floor( heightSegments ) || 6 );
@@ -29182,6 +29295,8 @@
 
 	function Curve() {
 
+		this.type = 'Curve';
+
 		this.arcLengthDivisions = 200;
 
 	}
@@ -29519,6 +29634,20 @@
 				binormals: binormals
 			};
 
+		},
+
+		clone: function () {
+
+			return new this.constructor().copy( this );
+
+		},
+
+		copy: function ( source ) {
+
+			this.arcLengthDivisions = source.arcLengthDivisions;
+
+			return this;
+
 		}
 
 	} );
@@ -29618,8 +29747,10 @@
 
 		Curve.call( this );
 
-		this.v1 = v1;
-		this.v2 = v2;
+		this.type = 'LineCurve';
+
+		this.v1 = v1 || new Vector2();
+		this.v2 = v2 || new Vector2();
 
 	}
 
@@ -29663,6 +29794,17 @@
 
 	};
 
+	LineCurve.prototype.copy = function ( source ) {
+
+		Curve.prototype.copy.call( this, source );
+
+		this.v1.copy( source.v1 );
+		this.v2.copy( source.v2 );
+
+		return this;
+
+	};
+
 	/**
 	 * @author zz85 / http://www.lab4games.net/zz85/blog
 	 *
@@ -29677,8 +29819,9 @@
 
 		Curve.call( this );
 
-		this.curves = [];
+		this.type = 'CurvePath';
 
+		this.curves = [];
 		this.autoClose = false; // Automatically closes the path
 
 	}
@@ -29858,43 +30001,6 @@
 
 			return points;
 
-		},
-
-		/**************************************************************
-		 *	Create Geometries Helpers
-		 **************************************************************/
-
-		/// Generate geometry from path points (for Line or Points objects)
-
-		createPointsGeometry: function ( divisions ) {
-
-			var pts = this.getPoints( divisions );
-			return this.createGeometry( pts );
-
-		},
-
-		// Generate geometry from equidistant sampling along the path
-
-		createSpacedPointsGeometry: function ( divisions ) {
-
-			var pts = this.getSpacedPoints( divisions );
-			return this.createGeometry( pts );
-
-		},
-
-		createGeometry: function ( points ) {
-
-			var geometry = new Geometry();
-
-			for ( var i = 0, l = points.length; i < l; i ++ ) {
-
-				var point = points[ i ];
-				geometry.vertices.push( new Vector3( point.x, point.y, point.z || 0 ) );
-
-			}
-
-			return geometry;
-
 		}
 
 	} );
@@ -30081,16 +30187,18 @@
 
 		Curve.call( this );
 
-		this.aX = aX;
-		this.aY = aY;
+		this.type = 'EllipseCurve';
+
+		this.aX = aX || 0;
+		this.aY = aY || 0;
 
-		this.xRadius = xRadius;
-		this.yRadius = yRadius;
+		this.xRadius = xRadius || 1;
+		this.yRadius = yRadius || 1;
 
-		this.aStartAngle = aStartAngle;
-		this.aEndAngle = aEndAngle;
+		this.aStartAngle = aStartAngle || 0;
+		this.aEndAngle = aEndAngle || 2 * Math.PI;
 
-		this.aClockwise = aClockwise;
+		this.aClockwise = aClockwise || false;
 
 		this.aRotation = aRotation || 0;
 
@@ -30163,11 +30271,34 @@
 
 	};
 
+	EllipseCurve.prototype.copy = function ( source ) {
+
+		Curve.prototype.copy.call( this, source );
+
+		this.aX = source.aX;
+		this.aY = source.aY;
+
+		this.xRadius = source.xRadius;
+		this.yRadius = source.yRadius;
+
+		this.aStartAngle = source.aStartAngle;
+		this.aEndAngle = source.aEndAngle;
+
+		this.aClockwise = source.aClockwise;
+
+		this.aRotation = source.aRotation;
+
+		return this;
+
+	};
+
 	function SplineCurve( points /* array of Vector2 */ ) {
 
 		Curve.call( this );
 
-		this.points = ( points === undefined ) ? [] : points;
+		this.type = 'SplineCurve';
+
+		this.points = points || [];
 
 	}
 
@@ -30200,14 +30331,34 @@
 
 	};
 
+	SplineCurve.prototype.copy = function ( source ) {
+
+		Curve.prototype.copy.call( this, source );
+
+		this.points = [];
+
+		for ( var i = 0, l = source.points.length; i < l; i ++ ) {
+
+			var point = source.points[ i ];
+
+			this.points.push( point.clone() );
+
+		}
+
+		return this;
+
+	};
+
 	function CubicBezierCurve( v0, v1, v2, v3 ) {
 
 		Curve.call( this );
 
-		this.v0 = v0;
-		this.v1 = v1;
-		this.v2 = v2;
-		this.v3 = v3;
+		this.type = 'CubicBezierCurve';
+
+		this.v0 = v0 || new Vector2();
+		this.v1 = v1 || new Vector2();
+		this.v2 = v2 || new Vector2();
+		this.v3 = v3 || new Vector2();
 
 	}
 
@@ -30231,13 +30382,28 @@
 
 	};
 
+	CubicBezierCurve.prototype.copy = function ( source ) {
+
+		Curve.prototype.copy.call( this, source );
+
+		this.v0.copy( source.v0 );
+		this.v1.copy( source.v1 );
+		this.v2.copy( source.v2 );
+		this.v3.copy( source.v3 );
+
+		return this;
+
+	};
+
 	function QuadraticBezierCurve( v0, v1, v2 ) {
 
 		Curve.call( this );
 
-		this.v0 = v0;
-		this.v1 = v1;
-		this.v2 = v2;
+		this.type = 'QuadraticBezierCurve';
+
+		this.v0 = v0 || new Vector2();
+		this.v1 = v1 || new Vector2();
+		this.v2 = v2 || new Vector2();
 
 	}
 
@@ -30261,6 +30427,18 @@
 
 	};
 
+	QuadraticBezierCurve.prototype.copy = function ( source ) {
+
+		Curve.prototype.copy.call( this, source );
+
+		this.v0.copy( source.v0 );
+		this.v1.copy( source.v1 );
+		this.v2.copy( source.v2 );
+
+		return this;
+
+	};
+
 	var PathPrototype = Object.assign( Object.create( CurvePath.prototype ), {
 
 		fromPoints: function ( vectors ) {
@@ -30389,6 +30567,9 @@
 	function Path( points ) {
 
 		CurvePath.call( this );
+
+		this.type = 'Path';
+
 		this.currentPoint = new Vector2();
 
 		if ( points ) {
@@ -30417,6 +30598,8 @@
 
 		Path.apply( this, arguments );
 
+		this.type = 'Shape';
+
 		this.holes = [];
 
 	}
@@ -30467,6 +30650,8 @@
 
 	function ShapePath() {
 
+		this.type = 'ShapePath';
+
 		this.subPaths = [];
 		this.currentPath = null;
 
@@ -30742,6 +30927,8 @@
 
 	function Font( data ) {
 
+		this.type = 'Font';
+
 		this.data = data;
 
 	}
@@ -31329,14 +31516,16 @@
 	var py = new CubicPoly();
 	var pz = new CubicPoly();
 
-	function CatmullRomCurve3( points ) {
+	function CatmullRomCurve3( points, closed, curveType, tension ) {
 
 		Curve.call( this );
 
-		if ( points.length < 2 ) console.warn( 'THREE.CatmullRomCurve3: Points array needs at least two entries.' );
+		this.type = 'CatmullRomCurve3';
 
 		this.points = points || [];
-		this.closed = false;
+		this.closed = closed || false;
+		this.curveType = curveType || 'centripetal';
+		this.tension = tension || 0.5;
 
 	}
 
@@ -31396,10 +31585,10 @@
 
 		}
 
-		if ( this.type === undefined || this.type === 'centripetal' || this.type === 'chordal' ) {
+		if ( this.curveType === 'centripetal' || this.curveType === 'chordal' ) {
 
 			// init Centripetal / Chordal Catmull-Rom
-			var pow = this.type === 'chordal' ? 0.5 : 0.25;
+			var pow = this.curveType === 'chordal' ? 0.5 : 0.25;
 			var dt0 = Math.pow( p0.distanceToSquared( p1 ), pow );
 			var dt1 = Math.pow( p1.distanceToSquared( p2 ), pow );
 			var dt2 = Math.pow( p2.distanceToSquared( p3 ), pow );
@@ -31413,12 +31602,11 @@
 			py.initNonuniformCatmullRom( p0.y, p1.y, p2.y, p3.y, dt0, dt1, dt2 );
 			pz.initNonuniformCatmullRom( p0.z, p1.z, p2.z, p3.z, dt0, dt1, dt2 );
 
-		} else if ( this.type === 'catmullrom' ) {
+		} else if ( this.curveType === 'catmullrom' ) {
 
-			var tension = this.tension !== undefined ? this.tension : 0.5;
-			px.initCatmullRom( p0.x, p1.x, p2.x, p3.x, tension );
-			py.initCatmullRom( p0.y, p1.y, p2.y, p3.y, tension );
-			pz.initCatmullRom( p0.z, p1.z, p2.z, p3.z, tension );
+			px.initCatmullRom( p0.x, p1.x, p2.x, p3.x, this.tension );
+			py.initCatmullRom( p0.y, p1.y, p2.y, p3.y, this.tension );
+			pz.initCatmullRom( p0.z, p1.z, p2.z, p3.z, this.tension );
 
 		}
 
@@ -31432,6 +31620,28 @@
 
 	};
 
+	CatmullRomCurve3.prototype.copy = function ( source ) {
+
+		Curve.prototype.copy.call( this, source );
+
+		this.points = [];
+
+		for ( var i = 0, l = source.points.length; i < l; i ++ ) {
+
+			var point = source.points[ i ];
+
+			this.points.push( point.clone() );
+
+		}
+
+		this.closed = source.closed;
+		this.curveType = source.curveType;
+		this.tension = source.tension;
+
+		return this;
+
+	};
+
 	/**
 	 * @author zz85 / http://joshuakoo.com
 	 * @author TristanVALCKE / https://github.com/Itee
@@ -32038,10 +32248,12 @@
 
 		Curve.call( this );
 
-		this.v0 = v0;
-		this.v1 = v1;
-		this.v2 = v2;
-		this.v3 = v3;
+		this.type = 'CubicBezierCurve3';
+
+		this.v0 = v0 || new Vector3();
+		this.v1 = v1 || new Vector3();
+		this.v2 = v2 || new Vector3();
+		this.v3 = v3 || new Vector3();
 
 	}
 
@@ -32066,6 +32278,19 @@
 
 	};
 
+	CubicBezierCurve3.prototype.copy = function ( source ) {
+
+		Curve.prototype.copy.call( this, source );
+
+		this.v0.copy( source.v0 );
+		this.v1.copy( source.v1 );
+		this.v2.copy( source.v2 );
+		this.v3.copy( source.v3 );
+
+		return this;
+
+	};
+
 	/**
 	 * @author TristanVALCKE / https://github.com/Itee
 	 * @author moraxy / https://github.com/moraxy
@@ -32716,8 +32941,10 @@
 
 		Curve.call( this );
 
-		this.v1 = v1;
-		this.v2 = v2;
+		this.type = 'LineCurve3';
+
+		this.v1 = v1 || new Vector3();
+		this.v2 = v2 || new Vector3();
 
 	}
 
@@ -32753,6 +32980,17 @@
 
 	};
 
+	LineCurve3.prototype.copy = function ( source ) {
+
+		Curve.prototype.copy.call( this, source );
+
+		this.v1.copy( source.v1 );
+		this.v2.copy( source.v2 );
+
+		return this;
+
+	};
+
 	/**
 	 * @author TristanVALCKE / https://github.com/Itee
 	 */
@@ -33207,9 +33445,11 @@
 
 		Curve.call( this );
 
-		this.v0 = v0;
-		this.v1 = v1;
-		this.v2 = v2;
+		this.type = 'QuadraticBezierCurve3';
+
+		this.v0 = v0 || new Vector3();
+		this.v1 = v1 || new Vector3();
+		this.v2 = v2 || new Vector3();
 
 	}
 
@@ -33234,6 +33474,18 @@
 
 	};
 
+	QuadraticBezierCurve3.prototype.copy = function ( source ) {
+
+		Curve.prototype.copy.call( this, source );
+
+		this.v0.copy( source.v0 );
+		this.v1.copy( source.v1 );
+		this.v2.copy( source.v2 );
+
+		return this;
+
+	};
+
 	/**
 	 * @author TristanVALCKE / https://github.com/Itee
 	 */
@@ -33873,7 +34125,7 @@
 			thetaLength: thetaLength
 		};
 
-		radius = radius || 50;
+		radius = radius || 1;
 		segments = segments !== undefined ? Math.max( 3, segments ) : 8;
 
 		thetaStart = thetaStart !== undefined ? thetaStart : 0;
@@ -34095,16 +34347,16 @@
 
 		var scope = this;
 
-		radiusTop = radiusTop !== undefined ? radiusTop : 20;
-		radiusBottom = radiusBottom !== undefined ? radiusBottom : 20;
-		height = height !== undefined ? height : 100;
+		radiusTop = radiusTop !== undefined ? radiusTop : 1;
+		radiusBottom = radiusBottom !== undefined ? radiusBottom : 1;
+		height = height || 1;
 
 		radialSegments = Math.floor( radialSegments ) || 8;
 		heightSegments = Math.floor( heightSegments ) || 1;
 
 		openEnded = openEnded !== undefined ? openEnded : false;
 		thetaStart = thetaStart !== undefined ? thetaStart : 0.0;
-		thetaLength = thetaLength !== undefined ? thetaLength : 2.0 * Math.PI;
+		thetaLength = thetaLength !== undefined ? thetaLength : Math.PI * 2;
 
 		// buffers
 
@@ -35847,7 +36099,7 @@
 
 	var tonemapping_fragment = "#if defined( TONE_MAPPING )\r\n\r\n  gl_FragColor.rgb = toneMapping( gl_FragColor.rgb );\r\n\r\n#endif\r\n";
 
-	var tonemapping_pars_fragment = "#define saturate(a) clamp( a, 0.0, 1.0 )\r\n\r\nuniform float toneMappingExposure;\r\nuniform float toneMappingWhitePoint;\r\n\r\n// exposure only\r\nvec3 LinearToneMapping( vec3 color ) {\r\n\r\n\treturn toneMappingExposure * color;\r\n\r\n}\r\n\r\n// source: https://www.cs.utah.edu/~reinhard/cdrom/\r\nvec3 ReinhardToneMapping( vec3 color ) {\r\n\r\n\tcolor *= toneMappingExposure;\r\n\treturn saturate( color / ( vec3( 1.0 ) + color ) );\r\n\r\n}\r\n\r\n// source: http://filmicgames.com/archives/75\r\n#define Uncharted2Helper( x ) max( ( ( x * ( 0.15 * x + 0.10 * 0.50 ) + 0.20 * 0.02 ) / ( x * ( 0.15 * x + 0.50 ) + 0.20 * 0.30 ) ) - 0.02 / 0.30, vec3( 0.0 ) )\r\nvec3 Uncharted2ToneMapping( vec3 color ) {\r\n\r\n\t// John Hable's filmic operator from Uncharted 2 video game\r\n\tcolor *= toneMappingExposure;\r\n\treturn saturate( Uncharted2Helper( color ) / Uncharted2Helper( vec3( toneMappingWhitePoint ) ) );\r\n\r\n}\r\n\r\n// source: http://filmicgames.com/archives/75\r\nvec3 OptimizedCineonToneMapping( vec3 color ) {\r\n\r\n\t// optimized filmic operator by Jim Hejl and Richard Burgess-Dawson\r\n\tcolor *= toneMappingExposure;\r\n\tcolor = max( vec3( 0.0 ), color - 0.004 );\r\n\treturn pow( ( color * ( 6.2 * color + 0.5 ) ) / ( color * ( 6.2 * color + 1.7 ) + 0.06 ), vec3( 2.2 ) );\r\n\r\n}\r\n";
+	var tonemapping_pars_fragment = "#ifndef saturate\r\n\t#define saturate(a) clamp( a, 0.0, 1.0 )\r\n#endif\r\n\r\nuniform float toneMappingExposure;\r\nuniform float toneMappingWhitePoint;\r\n\r\n// exposure only\r\nvec3 LinearToneMapping( vec3 color ) {\r\n\r\n\treturn toneMappingExposure * color;\r\n\r\n}\r\n\r\n// source: https://www.cs.utah.edu/~reinhard/cdrom/\r\nvec3 ReinhardToneMapping( vec3 color ) {\r\n\r\n\tcolor *= toneMappingExposure;\r\n\treturn saturate( color / ( vec3( 1.0 ) + color ) );\r\n\r\n}\r\n\r\n// source: http://filmicgames.com/archives/75\r\n#define Uncharted2Helper( x ) max( ( ( x * ( 0.15 * x + 0.10 * 0.50 ) + 0.20 * 0.02 ) / ( x * ( 0.15 * x + 0.50 ) + 0.20 * 0.30 ) ) - 0.02 / 0.30, vec3( 0.0 ) )\r\nvec3 Uncharted2ToneMapping( vec3 color ) {\r\n\r\n\t// John Hable's filmic operator from Uncharted 2 video game\r\n\tcolor *= toneMappingExposure;\r\n\treturn saturate( Uncharted2Helper( color ) / Uncharted2Helper( vec3( toneMappingWhitePoint ) ) );\r\n\r\n}\r\n\r\n// source: http://filmicgames.com/archives/75\r\nvec3 OptimizedCineonToneMapping( vec3 color ) {\r\n\r\n\t// optimized filmic operator by Jim Hejl and Richard Burgess-Dawson\r\n\tcolor *= toneMappingExposure;\r\n\tcolor = max( vec3( 0.0 ), color - 0.004 );\r\n\treturn pow( ( color * ( 6.2 * color + 0.5 ) ) / ( color * ( 6.2 * color + 1.7 ) + 0.06 ), vec3( 2.2 ) );\r\n\r\n}\r\n";
 
 	var uv_pars_fragment = "#if defined( USE_MAP ) || defined( USE_BUMPMAP ) || defined( USE_NORMALMAP ) || defined( USE_SPECULARMAP ) || defined( USE_ALPHAMAP ) || defined( USE_EMISSIVEMAP ) || defined( USE_ROUGHNESSMAP ) || defined( USE_METALNESSMAP )\r\n\r\n\tvarying vec2 vUv;\r\n\r\n#endif";
 
@@ -43129,7 +43381,7 @@
 
 		// Clearing
 
-		this.getClearColor = function() {
+		this.getClearColor = function () {
 
 			return background.getClearColor();
 
@@ -43141,13 +43393,13 @@
 
 		};
 
-		this.getClearAlpha = function() {
+		this.getClearAlpha = function () {
 
 			return background.getClearAlpha();
 
 		};
 
-		this.setClearAlpha = function() {
+		this.setClearAlpha = function () {
 
 			background.setClearAlpha.apply( background, arguments );
 
@@ -43716,7 +43968,19 @@
 		function start() {
 
 			if ( isAnimating ) return;
-			( vr.getDevice() || window ).requestAnimationFrame( loop );
+
+			var device = vr.getDevice();
+			
+			if ( device && device.isPresenting ) {
+
+				device.requestAnimationFrame( loop );
+
+			} else {
+
+				window.requestAnimationFrame( loop );
+
+			}
+
 			isAnimating = true;
 
 		}
@@ -43724,7 +43988,18 @@
 		function loop( time ) {
 
 			if ( onAnimationFrame !== null ) onAnimationFrame( time );
-			( vr.getDevice() || window ).requestAnimationFrame( loop );
+
+			var device = vr.getDevice();
+			
+			if ( device && device.isPresenting ) {
+
+				device.requestAnimationFrame( loop );
+
+			} else {
+
+				window.requestAnimationFrame( loop );
+
+			}
 
 		}
 
@@ -47425,8 +47700,8 @@
 			thetaLength: thetaLength
 		};
 
-		innerRadius = innerRadius || 20;
-		outerRadius = outerRadius || 50;
+		innerRadius = innerRadius || 0.5;
+		outerRadius = outerRadius || 1;
 
 		thetaStart = thetaStart !== undefined ? thetaStart : 0;
 		thetaLength = thetaLength !== undefined ? thetaLength : Math.PI * 2;
@@ -48352,8 +48627,8 @@
 			arc: arc
 		};
 
-		radius = radius || 100;
-		tube = tube || 40;
+		radius = radius || 1;
+		tube = tube || 0.4;
 		radialSegments = Math.floor( radialSegments ) || 8;
 		tubularSegments = Math.floor( tubularSegments ) || 6;
 		arc = arc || Math.PI * 2;
@@ -48596,8 +48871,8 @@
 			q: q
 		};
 
-		radius = radius || 100;
-		tube = tube || 40;
+		radius = radius || 1;
+		tube = tube || 0.4;
 		tubularSegments = Math.floor( tubularSegments ) || 64;
 		radialSegments = Math.floor( radialSegments ) || 8;
 		p = p || 2;